diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/CREDITS linux-2.5/CREDITS --- linux-2.5.13/CREDITS Fri May 3 01:22:43 2002 +++ linux-2.5/CREDITS Fri May 3 12:57:29 2002 @@ -595,7 +595,7 @@ S: USA N: Kees Cook -E: cook@cpoint.net +E: kees@outflux.net W: http://outflux.net/ P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D D: Minor updates to SCSI code for the Communications type diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/Documentation/Changes linux-2.5/Documentation/Changes --- linux-2.5.13/Documentation/Changes Fri May 3 01:22:56 2002 +++ linux-2.5/Documentation/Changes Sat Apr 13 17:42:53 2002 @@ -320,7 +320,7 @@ Reiserfsprogs ------------- -o +o LVM toolset ----------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/Documentation/DocBook/Makefile linux-2.5/Documentation/DocBook/Makefile --- linux-2.5.13/Documentation/DocBook/Makefile Fri May 3 01:22:52 2002 +++ linux-2.5/Documentation/DocBook/Makefile Fri May 3 03:49:06 2002 @@ -24,6 +24,8 @@ html: $(HTML) +man: kernel-api-man + %.eps: %.fig fig2dev -Leps $< $@ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/Documentation/DocBook/kernel-api.tmpl linux-2.5/Documentation/DocBook/kernel-api.tmpl --- linux-2.5.13/Documentation/DocBook/kernel-api.tmpl Fri May 3 01:22:37 2002 +++ linux-2.5/Documentation/DocBook/kernel-api.tmpl Tue Apr 23 11:27:52 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.13/Documentation/fb/tridentfb.txt linux-2.5/Documentation/fb/tridentfb.txt --- linux-2.5.13/Documentation/fb/tridentfb.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/Documentation/fb/tridentfb.txt Fri Feb 8 03:15:29 2002 @@ -0,0 +1,49 @@ +Tridentfb is a framebuffer driver for some Trident chip based cards. + +The following list of chips is thought to be supported although not all are +tested: + +those from the Image series with Cyber in their names - accelerated +those with Blade in their names (Blade3D,CyberBlade...) - accelerated +the newer CyberBladeXP family - nonaccelerated + +Only PCI/AGP based cards are supported, none of the older Tridents. + +How to use it? +============== +Just do your usual console work :) + +When booting you can pass the following parameters +================================================== + +noaccel - turns off acceleration (when it doesn't work for your card) +accel - force text acceleration (for boards which by default are noacceled) + +fp - use flat panel related stuff +crt - assume monitor is present instead of fp + +center - for flat panels and resolutions smaller than native size center the + image, otherwise use +stretch + +memsize - integer value in Kb, use if your card's memory size is misdetected. + look at the driver output to see what it says when initializing. +memdiff - integer value in Kb,should be nonzero if your card reports + more memory than it actually has.For instance mine is 192K less than + detection says in all three BIOS selectable situations 2M, 4M, 8M. + Only use if your video memory is taken from main memory hence of + configurable size.Otherwise use memsize. + If in some modes which barely fit the memory you see garbage at the bottom + this might help by not letting change to that mode anymore. + +nativex - the width in pixels of the flat panel.If you know it (usually 1024 + 800 or 1280) and it is not what the driver seems to detect use it. + +bpp - bits per pixel (8,16 or 32) +mode - a mode name like 800x600 (as described in Documentation/fb/modedb.txt) + +Using insane values for the above parameters will probably result in driver +misbehaviour so take care(for instance memsize=12345678 or memdiff=23784 or +nativex=93) + +Contact: jani@astechnix.ro diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/Documentation/isdn/README.HiSax linux-2.5/Documentation/isdn/README.HiSax --- linux-2.5.13/Documentation/isdn/README.HiSax Fri May 3 01:22: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.13/Documentation/kernel-doc-nano-HOWTO.txt linux-2.5/Documentation/kernel-doc-nano-HOWTO.txt --- linux-2.5.13/Documentation/kernel-doc-nano-HOWTO.txt Fri May 3 01:22:52 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.13/Documentation/nbd.txt linux-2.5/Documentation/nbd.txt --- linux-2.5.13/Documentation/nbd.txt Fri May 3 01:22:45 2002 +++ linux-2.5/Documentation/nbd.txt Fri May 3 03:49:06 2002 @@ -54,4 +54,4 @@ ... in case of read operation with no error, this is immediately followed len bytes of data - For more information, look at http://atrey.karlin.mff.cuni.cz/~pavel. + For more information, look at http://nbd.sf.net/. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/Documentation/networking/pktgen.txt linux-2.5/Documentation/networking/pktgen.txt --- linux-2.5.13/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.13/Documentation/s390/Debugging390.txt linux-2.5/Documentation/s390/Debugging390.txt --- linux-2.5.13/Documentation/s390/Debugging390.txt Fri May 3 01:22:44 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.13/Documentation/sonypi.txt linux-2.5/Documentation/sonypi.txt --- linux-2.5.13/Documentation/sonypi.txt Fri May 3 01:22:38 2002 +++ linux-2.5/Documentation/sonypi.txt Wed May 1 20:41:20 2002 @@ -36,14 +36,14 @@ driver and the ACPI BIOS, because Sony doesn't agree to release any programming specs for its laptops. If someone convinces them to do so, drop me a note. -Module options: +Driver options: --------------- Several options can be passed to the sonypi driver, either by adding them to /etc/modules.conf file, when the driver is compiled as a module or by adding the following to the kernel command line (in your bootloader): - sonypi=minor[[[[[,camera],fnkeyinit],verbose],compat],nojogdial] + sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,nojogdial]]]]] where: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/Documentation/sound/rme96xx linux-2.5/Documentation/sound/rme96xx --- linux-2.5.13/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.13/Documentation/sysctl/vm.txt linux-2.5/Documentation/sysctl/vm.txt --- linux-2.5.13/Documentation/sysctl/vm.txt Fri May 3 01:22:55 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.13/Documentation/video4linux/meye.txt linux-2.5/Documentation/video4linux/meye.txt --- linux-2.5.13/Documentation/video4linux/meye.txt Fri May 3 01:22:44 2002 +++ linux-2.5/Documentation/video4linux/meye.txt Tue Apr 23 12:20:22 2002 @@ -15,8 +15,16 @@ MJPEG hardware grabbing is supported via a private API (see below). -Module options: +Driver options: --------------- + +Several options can be passed to the meye driver, either by adding them +to /etc/modules.conf file, when the driver is compiled as a module, or +by adding the following to the kernel command line (in your bootloader): + + meye=gbuffers[,gbufsize[,video_nr]] + +where: gbuffers: number of capture buffers, default is 2 (32 max) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/MAINTAINERS linux-2.5/MAINTAINERS --- linux-2.5.13/MAINTAINERS Fri May 3 01:22:39 2002 +++ linux-2.5/MAINTAINERS Fri May 3 12:57:29 2002 @@ -544,14 +544,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 @@ -1187,6 +1185,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 @@ -1257,6 +1261,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 @@ -1344,6 +1362,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 @@ -1371,6 +1395,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 @@ -1651,6 +1680,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 @@ -1719,6 +1754,13 @@ W: http://pegasus2.sourceforge.net/ 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 @@ -1821,7 +1863,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.13/Makefile linux-2.5/Makefile --- linux-2.5.13/Makefile Fri May 3 01:22:41 2002 +++ linux-2.5/Makefile Sat May 4 11:51:50 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 13 -EXTRAVERSION = +EXTRAVERSION =-dj2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -14,10 +14,10 @@ TOPDIR := $(shell /bin/pwd) 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 +HOSTCFLAGS = -Wshadow -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer CROSS_COMPILE = @@ -89,7 +89,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) # @@ -121,7 +124,7 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o NETWORKS =net/network.o -LIBS =$(TOPDIR)/lib/lib.a +LIBS =$(TOPDIR)/lib/lib.o SUBDIRS =kernel lib drivers mm fs net ipc sound DRIVERS-n := @@ -167,7 +170,7 @@ DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o -DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o +DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a @@ -196,6 +199,7 @@ kernel/ksyms.lst include/linux/compile.h \ vmlinux System.map \ .tmp* \ + scripts/mkconfigs kernel/configs.c kernel/configs.o \ drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \ drivers/char/conmakehash \ drivers/char/drm/*-mod.c \ @@ -203,10 +207,14 @@ drivers/zorro/devlist.h drivers/zorro/gen-devlist \ sound/oss/bin2hex sound/oss/hex2hex \ drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \ + drivers/scsi/aic7xxx/aicasm/aicasm \ drivers/scsi/aic7xxx/aicasm/aicasm_gram.c \ + drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.c \ + drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.h \ + drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.c \ drivers/scsi/aic7xxx/aicasm/aicasm_scan.c \ + drivers/scsi/aic7xxx/aicasm/aicdb.h \ drivers/scsi/aic7xxx/aicasm/y.tab.h \ - drivers/scsi/aic7xxx/aicasm/aicasm \ drivers/scsi/53c700_d.h \ net/khttpd/make_times_h \ net/khttpd/times.h \ @@ -235,6 +243,7 @@ include/asm \ .hdepend scripts/mkdep scripts/split-include scripts/docproc \ $(TOPDIR)/include/linux/modversions.h \ + scripts/mkconfigs kernel/configs.c kernel/configs.o \ kernel.spec # directories removed with 'make mrproper' @@ -245,6 +254,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 CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS @@ -312,8 +331,8 @@ @echo -n \#define UTS_VERSION \"\#`cat .version` > .ver @if [ -n "$(CONFIG_SMP)" ] ; then echo -n " SMP" >> .ver; fi @if [ -f .name ]; then echo -n \-`cat .name` >> .ver; fi - @echo ' '`date`'"' >> .ver - @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver + @echo ' '`LANG=C date`'"' >> .ver + @echo \#define LINUX_COMPILE_TIME \"`LANG=C date +%T`\" >> .ver @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> .ver @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> .ver @if [ -x /bin/dnsdomainname ]; then \ @@ -456,6 +475,11 @@ htmldocs: sgmldocs $(MAKE) -C Documentation/DocBook html + +mandocs: + chmod 755 $(TOPDIR)/scripts/kernel-doc + chmod 755 $(TOPDIR)/scripts/split-man + $(MAKE) -C Documentation/DocBook man sums: find . -type f -print | sort | xargs sum > .SUMS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/Rules.make linux-2.5/Rules.make --- linux-2.5.13/Rules.make Fri May 3 01:22:49 2002 +++ linux-2.5/Rules.make Fri May 3 12:57:29 2002 @@ -31,6 +31,7 @@ unexport subdir- comma := , +EXTRA_CFLAGS_nostdinc := $(EXTRA_CFLAGS) $(kbuild_2_4_nostdinc) # # When an object is listed to be built compiled-in and modular, @@ -55,15 +56,15 @@ # %.s: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -S $< -o $@ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -S $< -o $@ %.i: %.c - $(CPP) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@ + $(CPP) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@ %.o: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $< + $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $< @ ( \ - echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@))),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@))))' ; \ + echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$@))),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS_nostdinc) $$(CFLAGS_$@))))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ ) > $(dir $@)/.$(notdir $@).flags @@ -86,7 +87,7 @@ endif %.lst: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $< + $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$@) -g -c -o $*.o $< $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP) # # @@ -162,7 +163,7 @@ # This make dependencies quickly # fastdep: dummy - $(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 @@ -308,9 +309,9 @@ ifneq "$(strip $(export-objs))" "" $(export-objs): $(TOPDIR)/include/linux/modversions.h $(export-objs): %.o: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c) @ ( \ - echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))' ; \ + echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS_nostdinc) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ ) > $(dir $@)/.$(notdir $@).flags diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/alpha/Config.help linux-2.5/arch/alpha/Config.help --- linux-2.5.13/arch/alpha/Config.help Fri May 3 01:22:42 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.13/arch/alpha/config.in linux-2.5/arch/alpha/config.in --- linux-2.5.13/arch/alpha/config.in Fri May 3 01:22:45 2002 +++ linux-2.5/arch/alpha/config.in Wed May 1 20:36:25 2002 @@ -372,9 +372,7 @@ source drivers/usb/Config.in source drivers/input/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/alpha/kernel/alpha_ksyms.c linux-2.5/arch/alpha/kernel/alpha_ksyms.c --- linux-2.5.13/arch/alpha/kernel/alpha_ksyms.c Fri May 3 01:22:40 2002 +++ linux-2.5/arch/alpha/kernel/alpha_ksyms.c Sat Apr 13 17:42:54 2002 @@ -213,6 +213,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.13/arch/alpha/kernel/pci_iommu.c linux-2.5/arch/alpha/kernel/pci_iommu.c --- linux-2.5.13/arch/alpha/kernel/pci_iommu.c Fri May 3 01:22:57 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.13/arch/alpha/kernel/proto.h linux-2.5/arch/alpha/kernel/proto.h --- linux-2.5.13/arch/alpha/kernel/proto.h Fri May 3 01:22:44 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.13/arch/alpha/kernel/smc37c669.c linux-2.5/arch/alpha/kernel/smc37c669.c --- linux-2.5.13/arch/alpha/kernel/smc37c669.c Fri May 3 01:22:54 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.13/arch/alpha/kernel/smp.c linux-2.5/arch/alpha/kernel/smp.c --- linux-2.5.13/arch/alpha/kernel/smp.c Fri May 3 01:22:46 2002 +++ linux-2.5/arch/alpha/kernel/smp.c Sat Mar 23 22:44:56 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.13/arch/alpha/kernel/sys_miata.c linux-2.5/arch/alpha/kernel/sys_miata.c --- linux-2.5.13/arch/alpha/kernel/sys_miata.c Fri May 3 01:22:53 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.13/arch/arm/config.in linux-2.5/arch/arm/config.in --- linux-2.5.13/arch/arm/config.in Fri May 3 01:22:44 2002 +++ linux-2.5/arch/arm/config.in Wed May 1 20:36:25 2002 @@ -581,9 +581,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 @@ -655,9 +652,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/arm/kernel/via82c505.c linux-2.5/arch/arm/kernel/via82c505.c --- linux-2.5.13/arch/arm/kernel/via82c505.c Fri May 3 01:22:38 2002 +++ linux-2.5/arch/arm/kernel/via82c505.c Sat Apr 27 13:12:44 2002 @@ -79,8 +79,15 @@ struct pci_bus *bus; printk(KERN_DEBUG "PCI: VIA 82c505\n"); - request_region(0xA8,2,"via config"); - request_region(0xCF8,8,"pci config"); + if (!request_region(0xA8,2,"via config")) { + printk(KERN_WARNING"VIA 82c505: Unable to request region 0xA8\n"); + return; + } + if (!request_region(0xCF8,8,"pci config")) { + printk(KERN_WARNING"VIA 82c505: Unable to request region 0xCF8\n"); + release_region(0xA8, 2); + return; + } /* Enable compatible Mode */ outb(0x96,0xA8); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/arm/mach-footbridge/netwinder-hw.c linux-2.5/arch/arm/mach-footbridge/netwinder-hw.c --- linux-2.5.13/arch/arm/mach-footbridge/netwinder-hw.c Fri May 3 01:22: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.13/arch/arm/mach-pxa/idp.c linux-2.5/arch/arm/mach-pxa/idp.c --- linux-2.5.13/arch/arm/mach-pxa/idp.c Fri May 3 01:22:37 2002 +++ linux-2.5/arch/arm/mach-pxa/idp.c Sun Apr 14 23:03:05 2002 @@ -81,7 +81,7 @@ #if 0 setup_ramdisk (1, 0, 0, 8192); setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/arm/mach-pxa/lubbock.c linux-2.5/arch/arm/mach-pxa/lubbock.c --- linux-2.5.13/arch/arm/mach-pxa/lubbock.c Fri May 3 01:22:49 2002 +++ linux-2.5/arch/arm/mach-pxa/lubbock.c Sun Apr 14 23:03:17 2002 @@ -128,7 +128,7 @@ #if 0 setup_ramdisk (1, 0, 0, 8192); setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/arm/mach-shark/leds.c linux-2.5/arch/arm/mach-shark/leds.c --- linux-2.5.13/arch/arm/mach-shark/leds.c Fri May 3 01:22:52 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.13/arch/cris/boot/Makefile linux-2.5/arch/cris/boot/Makefile --- linux-2.5.13/arch/cris/boot/Makefile Fri May 3 01:22:53 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.13/arch/cris/boot/compressed/Makefile linux-2.5/arch/cris/boot/compressed/Makefile --- linux-2.5.13/arch/cris/boot/compressed/Makefile Fri May 3 01:22:38 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.13/arch/cris/boot/rescue/Makefile linux-2.5/arch/cris/boot/rescue/Makefile --- linux-2.5.13/arch/cris/boot/rescue/Makefile Fri May 3 01:22:50 2002 +++ linux-2.5/arch/cris/boot/rescue/Makefile Fri Feb 8 03:15:29 2002 @@ -3,6 +3,8 @@ # ifndef TOPDIR TOPDIR = ../../../.. +HPATH = $(TOPDIR)/include +export HPATH endif CC = gcc-cris -mlinux -I $(TOPDIR)/include CFLAGS = -O2 @@ -35,7 +37,7 @@ dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784 rm ktr.bin tmp2423 kimagerescue_tmp.bin -head.o: head.S +head.o: head.S $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o testrescue.o: testrescue.S @@ -52,3 +54,8 @@ modules: modules-install: + +depend: + $(CC) -M *.S > .depend + +-include .depend diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/cris/config.in linux-2.5/arch/cris/config.in --- linux-2.5.13/arch/cris/config.in Fri May 3 01:22:38 2002 +++ linux-2.5/arch/cris/config.in Tue Apr 23 10:31:37 2002 @@ -196,10 +196,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 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/cris/drivers/ethernet.c linux-2.5/arch/cris/drivers/ethernet.c --- linux-2.5.13/arch/cris/drivers/ethernet.c Fri May 3 01:22:52 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.13/arch/cris/drivers/serial.c linux-2.5/arch/cris/drivers/serial.c --- linux-2.5.13/arch/cris/drivers/serial.c Fri May 3 01:22:42 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.13/arch/cris/drivers/serial.h linux-2.5/arch/cris/drivers/serial.h --- linux-2.5.13/arch/cris/drivers/serial.h Fri May 3 01:22:48 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.13/arch/i386/Config.help linux-2.5/arch/i386/Config.help --- linux-2.5.13/arch/i386/Config.help Fri May 3 01:22:41 2002 +++ linux-2.5/arch/i386/Config.help Tue Apr 16 03:10:04 2002 @@ -636,6 +636,18 @@ 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 off or put into a power conserving "sleep" mode if they are not diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/config.in linux-2.5/arch/i386/config.in --- linux-2.5.13/arch/i386/config.in Fri May 3 01:22:48 2002 +++ linux-2.5/arch/i386/config.in Fri May 3 03:49:06 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/VIA-C5 CONFIG_MCYRIXIII" Pentium-Pro # # Define implied options from the CPU selection here # @@ -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 @@ -392,22 +392,23 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' 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.13/arch/i386/defconfig linux-2.5/arch/i386/defconfig --- linux-2.5.13/arch/i386/defconfig Fri May 3 01:22:42 2002 +++ linux-2.5/arch/i386/defconfig Wed May 1 17:26:06 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 @@ -504,10 +505,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 @@ -537,21 +538,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 @@ -572,15 +613,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 # @@ -613,6 +645,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 @@ -851,13 +884,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.13/arch/i386/kernel/Makefile linux-2.5/arch/i386/kernel/Makefile --- linux-2.5.13/arch/i386/kernel/Makefile Fri May 3 01:22:43 2002 +++ linux-2.5/arch/i386/kernel/Makefile Sat Mar 23 22:45:17 2002 @@ -32,6 +32,7 @@ endif 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 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/apic.c linux-2.5/arch/i386/kernel/apic.c --- linux-2.5.13/arch/i386/kernel/apic.c Fri May 3 01:22:53 2002 +++ linux-2.5/arch/i386/kernel/apic.c Fri May 3 08:42:14 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); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/apm.c linux-2.5/arch/i386/kernel/apm.c --- linux-2.5.13/arch/i386/kernel/apm.c Fri May 3 01:22:39 2002 +++ linux-2.5/arch/i386/kernel/apm.c Tue Apr 23 12:04:51 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.13/arch/i386/kernel/dmi_scan.c linux-2.5/arch/i386/kernel/dmi_scan.c --- linux-2.5.13/arch/i386/kernel/dmi_scan.c Fri May 3 01:22:49 2002 +++ linux-2.5/arch/i386/kernel/dmi_scan.c Fri May 3 03:49:06 2002 @@ -643,6 +643,12 @@ MATCH(DMI_BIOS_DATE, "08/25/00"), NO_MATCH } }, + { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */ + MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + MATCH(DMI_BIOS_VERSION, "R0209Z3"), + MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH + } }, + { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-F104K */ MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), MATCH(DMI_BIOS_VERSION, "R0204K2"), diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/eisa.c linux-2.5/arch/i386/kernel/eisa.c --- linux-2.5.13/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.13/arch/i386/kernel/entry.S linux-2.5/arch/i386/kernel/entry.S --- linux-2.5.13/arch/i386/kernel/entry.S Fri May 3 01:22:46 2002 +++ linux-2.5/arch/i386/kernel/entry.S Thu May 2 21:28:32 2002 @@ -395,6 +395,11 @@ BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) + +#ifdef CONFIG_X86_MCE_P4THERMAL +BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) +#endif + #endif ENTRY(divide_error) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/head.S linux-2.5/arch/i386/kernel/head.S --- linux-2.5.13/arch/i386/kernel/head.S Fri May 3 01:22:41 2002 +++ linux-2.5/arch/i386/kernel/head.S Tue Apr 23 12:04:51 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.13/arch/i386/kernel/i386_ksyms.c linux-2.5/arch/i386/kernel/i386_ksyms.c --- linux-2.5.13/arch/i386/kernel/i386_ksyms.c Fri May 3 01:22:52 2002 +++ linux-2.5/arch/i386/kernel/i386_ksyms.c Fri May 3 03:49:06 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); @@ -174,3 +173,7 @@ extern int is_sony_vaio_laptop; EXPORT_SYMBOL(is_sony_vaio_laptop); + +EXPORT_SYMBOL(PAGE_KERNEL); +EXPORT_SYMBOL(PAGE_KERNEL_RO); +EXPORT_SYMBOL(PAGE_KERNEL_NOCACHE); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/i8259.c linux-2.5/arch/i386/kernel/i8259.c --- linux-2.5.13/arch/i386/kernel/i8259.c Fri May 3 01:22:56 2002 +++ linux-2.5/arch/i386/kernel/i8259.c Thu May 2 21:28:32 2002 @@ -394,7 +394,7 @@ /* thermal monitor LVT interrupt */ #ifdef CONFIG_X86_MCE_P4THERMAL - set_intr_gate(THERMAL_APIC_VECTOR, smp_thermal_interrupt); + set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); #endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/io_apic.c linux-2.5/arch/i386/kernel/io_apic.c --- linux-2.5.13/arch/i386/kernel/io_apic.c Fri May 3 01:22:48 2002 +++ linux-2.5/arch/i386/kernel/io_apic.c Fri May 3 03:49:06 2002 @@ -272,15 +272,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) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/mtrr.c linux-2.5/arch/i386/kernel/mtrr.c --- linux-2.5.13/arch/i386/kernel/mtrr.c Fri May 3 01:22:39 2002 +++ linux-2.5/arch/i386/kernel/mtrr.c Mon Apr 15 02:54:27 2002 @@ -1659,7 +1659,7 @@ char *ptr; char line[LINE_SIZE]; - if ( !suser () ) return -EPERM; + if ( !capable(CAP_SYS_ADMIN)) return -EPERM; /* Can't seek (pwrite) on this device */ if (ppos != &file->f_pos) return -ESPIPE; memset (line, 0, LINE_SIZE); @@ -1727,28 +1727,28 @@ default: return -ENOIOCTLCMD; case MTRRIOC_ADD_ENTRY: - if ( !suser () ) return -EPERM; + if ( ! capable(CAP_SYS_ADMIN) ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0); if (err < 0) return err; break; case MTRRIOC_SET_ENTRY: - if ( !suser () ) return -EPERM; + 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); if (err < 0) return err; break; case MTRRIOC_DEL_ENTRY: - if ( !suser () ) return -EPERM; + 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); if (err < 0) return err; break; case MTRRIOC_KILL_ENTRY: - if ( !suser () ) return -EPERM; + 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); @@ -1773,28 +1773,28 @@ return -EFAULT; break; case MTRRIOC_ADD_PAGE_ENTRY: - if ( !suser () ) return -EPERM; + if ( !capable(CAP_SYS_ADMIN) ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1); if (err < 0) return err; break; case MTRRIOC_SET_PAGE_ENTRY: - if ( !suser () ) return -EPERM; + 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); if (err < 0) return err; break; case MTRRIOC_DEL_PAGE_ENTRY: - if ( !suser () ) return -EPERM; + 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); if (err < 0) return err; break; case MTRRIOC_KILL_PAGE_ENTRY: - if ( !suser () ) return -EPERM; + 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); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/pci-irq.c linux-2.5/arch/i386/kernel/pci-irq.c --- linux-2.5.13/arch/i386/kernel/pci-irq.c Fri May 3 01:22:57 2002 +++ linux-2.5/arch/i386/kernel/pci-irq.c Sat Apr 27 12:48:57 2002 @@ -243,6 +243,8 @@ /* * Cyrix: nibble offset 0x5C + * 0x5C bits 7:4 is INTB bits 3:0 is INTA + * 0x5D bits 7:4 is INTD bits 3:0 is INTC */ static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/pci-pc.c linux-2.5/arch/i386/kernel/pci-pc.c --- linux-2.5.13/arch/i386/kernel/pci-pc.c Fri May 3 01:22:50 2002 +++ linux-2.5/arch/i386/kernel/pci-pc.c Fri May 3 00:33:01 2002 @@ -1201,28 +1201,48 @@ /* * Addresses issues with problems in the memory write queue timer in - * certain VIA Northbridges. This bugfix is per VIA's specifications. + * certain VIA Northbridges. This bugfix is per VIA's specifications, + * except for the KL133/KM133: clearing bit 5 on those Northbridges seems + * to trigger a bug in its integrated ProSavage video card, which + * causes screen corruption. We only clear bits 6 and 7 for that chipset, + * until VIA can provide us with definitive information on why screen + * corruption occurs, and what exactly those bits do. * * VIA 8363,8622,8361 Northbridges: * - bits 5, 6, 7 at offset 0x55 need to be turned off * VIA 8367 (KT266x) Northbridges: * - bits 5, 6, 7 at offset 0x95 need to be turned off + * VIA 8363 rev 0x81/0x84 (KL133/KM133) Northbridges: + * - bits 6, 7 at offset 0x55 need to be turned off */ + +#define VIA_8363_KL133_REVISION_ID 0x81 +#define VIA_8363_KM133_REVISION_ID 0x84 + static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d) { u8 v; + u8 revision; int where = 0x55; + int mask = 0x1f; /* clear bits 5, 6, 7 by default */ + + pci_read_config_byte(d, PCI_REVISION_ID, &revision); if (d->device == PCI_DEVICE_ID_VIA_8367_0) { where = 0x95; /* the memory write queue timer register is - different for the kt266x's: 0x95 not 0x55 */ + different for the KT266x's: 0x95 not 0x55 */ + } else if (d->device == PCI_DEVICE_ID_VIA_8363_0 && + (revision == VIA_8363_KL133_REVISION_ID || + revision == VIA_8363_KM133_REVISION_ID)) { + mask = 0x3f; /* clear only bits 6 and 7; clearing bit 5 + causes screen corruption on the KL133/KM133 */ } pci_read_config_byte(d, where, &v); - if (v & 0xe0) { - printk("Disabling broken memory write queue: [%02x] %02x->%02x\n", - where, v, v & 0x1f); - v &= 0x1f; /* clear bits 5, 6, 7 */ + if (v & ~mask) { + printk("Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ + d->device, revision, where, v, mask, v & mask); + v &= mask; pci_write_config_byte(d, where, v); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/process.c linux-2.5/arch/i386/kernel/process.c --- linux-2.5.13/arch/i386/kernel/process.c Fri May 3 01:22:37 2002 +++ linux-2.5/arch/i386/kernel/process.c Tue Apr 23 12:36:19 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.13/arch/i386/kernel/semaphore.c linux-2.5/arch/i386/kernel/semaphore.c --- linux-2.5.13/arch/i386/kernel/semaphore.c Fri May 3 01:22:51 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.13/arch/i386/kernel/setup.c linux-2.5/arch/i386/kernel/setup.c --- linux-2.5.13/arch/i386/kernel/setup.c Fri May 3 01:22:52 2002 +++ linux-2.5/arch/i386/kernel/setup.c Fri May 3 08:42:14 2002 @@ -126,11 +126,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; @@ -292,6 +288,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) { @@ -593,7 +605,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); @@ -616,32 +628,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); } } /* @@ -661,7 +665,7 @@ } *to = '\0'; *cmdline_p = command_line; - if (usermem) { + if (userdef) { printk(KERN_INFO "user-defined physical RAM map:\n"); print_memory_map("user"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/signal.c linux-2.5/arch/i386/kernel/signal.c --- linux-2.5.13/arch/i386/kernel/signal.c Fri May 3 01:22:52 2002 +++ linux-2.5/arch/i386/kernel/signal.c Tue Apr 23 12:26:17 2002 @@ -657,7 +657,7 @@ continue; switch (signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: + case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/smp.c linux-2.5/arch/i386/kernel/smp.c --- linux-2.5.13/arch/i386/kernel/smp.c Fri May 3 01:22:41 2002 +++ linux-2.5/arch/i386/kernel/smp.c Fri May 3 00:35:05 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, }}; @@ -302,8 +302,7 @@ */ static void inline leave_mm (unsigned long cpu) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) - BUG(); + BUG_ON(cpu_tlbstate[cpu].state == TLBSTATE_OK); clear_bit(cpu, &cpu_tlbstate[cpu].active_mm->cpu_vm_mask); } @@ -540,7 +539,7 @@ * remote CPUs are nearly ready to execute <> or are or have executed. * * You must not call this function with disabled interrupts or from a - * hardware interrupt handler, you may call it from a bottom half handler. + * hardware interrupt handler or from a bottom half handler. */ { struct call_data_struct data; @@ -556,7 +555,7 @@ if (wait) atomic_set(&data.finished, 0); - spin_lock_bh(&call_lock); + spin_lock(&call_lock); call_data = &data; wmb(); /* Send a message to all other CPUs and wait for them to respond */ @@ -569,7 +568,7 @@ if (wait) while (atomic_read(&data.finished) != cpus) barrier(); - spin_unlock_bh(&call_lock); + spin_unlock(&call_lock); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/time.c linux-2.5/arch/i386/kernel/time.c --- linux-2.5.13/arch/i386/kernel/time.c Fri May 3 01:22:53 2002 +++ linux-2.5/arch/i386/kernel/time.c Sat Mar 23 22:48:46 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 @@ -470,6 +473,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 @@ -498,6 +505,7 @@ rdtscl(last_tsc_low); +#ifndef CONFIG_CS5520 spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -510,6 +518,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); @@ -672,6 +733,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.13/arch/i386/kernel/traps.c linux-2.5/arch/i386/kernel/traps.c --- linux-2.5.13/arch/i386/kernel/traps.c Fri May 3 01:22:43 2002 +++ linux-2.5/arch/i386/kernel/traps.c Fri May 3 03:49:06 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 @@ -968,6 +968,10 @@ if (request_resource(&ioport_resource, &eisa_id) == -EBUSY) printk ("EISA port was EBUSY :-(\n"); } +#endif + +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); #endif #ifdef CONFIG_X86_LOCAL_APIC diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/kernel/vm86.c linux-2.5/arch/i386/kernel/vm86.c --- linux-2.5.13/arch/i386/kernel/vm86.c Fri May 3 01:22:41 2002 +++ linux-2.5/arch/i386/kernel/vm86.c Sun Apr 14 16:18:05 2002 @@ -18,6 +18,7 @@ #include #include #include +#include /* * Known problems: @@ -615,6 +616,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.13/arch/i386/lib/mmx.c linux-2.5/arch/i386/lib/mmx.c --- linux-2.5.13/arch/i386/lib/mmx.c Fri May 3 01:22:54 2002 +++ linux-2.5/arch/i386/lib/mmx.c Thu May 2 23:36:38 2002 @@ -57,7 +57,7 @@ : : "r" (from) ); - for(; i>0; i--) + for(; i>5; i--) { __asm__ __volatile__ ( "1: prefetch 320(%0)\n" @@ -85,6 +85,30 @@ " .align 4\n" " .long 1b, 3b\n" ".previous" + : : "r" (from), "r" (to) : "memory"); + from+=64; + to+=64; + } + + for(; i>0; i--) + { + __asm__ __volatile__ ( + " movq (%0), %%mm0\n" + " movq 8(%0), %%mm1\n" + " movq 16(%0), %%mm2\n" + " movq 24(%0), %%mm3\n" + " movq %%mm0, (%1)\n" + " movq %%mm1, 8(%1)\n" + " movq %%mm2, 16(%1)\n" + " movq %%mm3, 24(%1)\n" + " movq 32(%0), %%mm0\n" + " movq 40(%0), %%mm1\n" + " movq 48(%0), %%mm2\n" + " movq 56(%0), %%mm3\n" + " movq %%mm0, 32(%1)\n" + " movq %%mm1, 40(%1)\n" + " movq %%mm2, 48(%1)\n" + " movq %%mm3, 56(%1)\n" : : "r" (from), "r" (to) : "memory"); from+=64; to+=64; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/i386/math-emu/fpu_system.h linux-2.5/arch/i386/math-emu/fpu_system.h --- linux-2.5.13/arch/i386/math-emu/fpu_system.h Fri May 3 01:22:48 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.13/arch/i386/math-emu/reg_add_sub.c linux-2.5/arch/i386/math-emu/reg_add_sub.c --- linux-2.5.13/arch/i386/math-emu/reg_add_sub.c Fri May 3 01:22:53 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.13/arch/i386/math-emu/reg_compare.c linux-2.5/arch/i386/math-emu/reg_compare.c --- linux-2.5.13/arch/i386/math-emu/reg_compare.c Fri May 3 01:22:47 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.13/arch/i386/math-emu/reg_divide.c linux-2.5/arch/i386/math-emu/reg_divide.c --- linux-2.5.13/arch/i386/math-emu/reg_divide.c Fri May 3 01:22:54 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.13/arch/i386/math-emu/reg_ld_str.c linux-2.5/arch/i386/math-emu/reg_ld_str.c --- linux-2.5.13/arch/i386/math-emu/reg_ld_str.c Fri May 3 01:22: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.13/arch/i386/math-emu/reg_mul.c linux-2.5/arch/i386/math-emu/reg_mul.c --- linux-2.5.13/arch/i386/math-emu/reg_mul.c Fri May 3 01:22:46 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.13/arch/i386/mm/fault.c linux-2.5/arch/i386/mm/fault.c --- linux-2.5.13/arch/i386/mm/fault.c Fri May 3 01:22:37 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.13/arch/i386/mm/init.c linux-2.5/arch/i386/mm/init.c --- linux-2.5.13/arch/i386/mm/init.c Fri May 3 01:22:44 2002 +++ linux-2.5/arch/i386/mm/init.c Wed May 1 17:26:06 2002 @@ -180,32 +180,43 @@ } } +pgprot_t PAGE_KERNEL = __pgprot(__PAGE_KERNEL); +pgprot_t PAGE_KERNEL_RO = __pgprot(__PAGE_KERNEL_RO); +pgprot_t PAGE_KERNEL_NOCACHE = __pgprot(__PAGE_KERNEL_NOCACHE); + static void __init pagetable_init (void) { - unsigned long vaddr, end; + unsigned long vaddr, pfn, prot; pgd_t *pgd, *pgd_base; int i, j, k; pmd_t *pmd; pte_t *pte, *pte_base; - /* - * This can be zero as well - no problem, in that case we exit - * the loops anyway due to the PTRS_PER_* conditions. - */ - end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); - pgd_base = swapper_pg_dir; #if CONFIG_X86_PAE for (i = 0; i < PTRS_PER_PGD; i++) set_pgd(pgd_base + i, __pgd(1 + __pa(empty_zero_page))); #endif + + prot = _KERNPG_TABLE; + if (cpu_has_pse) { + set_in_cr4(X86_CR4_PSE); + prot |= _PAGE_PSE; + boot_cpu_data.wp_works_ok = 1; + } + if (cpu_has_pge) { + set_in_cr4(X86_CR4_PGE); + prot |= _PAGE_GLOBAL; + PAGE_KERNEL.pgprot |= _PAGE_GLOBAL; + PAGE_KERNEL_RO.pgprot |= _PAGE_GLOBAL; + PAGE_KERNEL_NOCACHE.pgprot |= _PAGE_GLOBAL; + } + + pfn = 0; i = __pgd_offset(PAGE_OFFSET); pgd = pgd_base + i; - for (; i < PTRS_PER_PGD; pgd++, i++) { - vaddr = i*PGDIR_SIZE; - if (end && (vaddr >= end)) - break; + for (; i < PTRS_PER_PGD && pfn < max_low_pfn; pgd++, i++) { #if CONFIG_X86_PAE pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); @@ -214,37 +225,21 @@ #endif if (pmd != pmd_offset(pgd, 0)) BUG(); - for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { - vaddr = i*PGDIR_SIZE + j*PMD_SIZE; - if (end && (vaddr >= end)) - break; + for (j = 0; j < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, j++) { if (cpu_has_pse) { - unsigned long __pe; - - set_in_cr4(X86_CR4_PSE); - boot_cpu_data.wp_works_ok = 1; - __pe = _KERNPG_TABLE + _PAGE_PSE + __pa(vaddr); - /* Make it "global" too if supported */ - if (cpu_has_pge) { - set_in_cr4(X86_CR4_PGE); - __pe += _PAGE_GLOBAL; + set_pmd(pmd, __pmd(prot + (pfn << PAGE_SHIFT))); + pfn += PMD_SIZE >> PAGE_SHIFT; + } else { + pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + + for (k = 0; k < PTRS_PER_PTE && pfn < max_low_pfn; pte++, k++) { + *pte = __mk_pte(pfn, PAGE_KERNEL); + pfn++; } - set_pmd(pmd, __pmd(__pe)); - continue; - } - - pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - - for (k = 0; k < PTRS_PER_PTE; pte++, k++) { - vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; - if (end && (vaddr >= end)) - break; - *pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL); + set_pmd(pmd, __pmd(prot + __pa(pte_base))); + if (pte_base != pte_offset_kernel(pmd, 0)) + BUG(); } - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base))); - if (pte_base != pte_offset_kernel(pmd, 0)) - BUG(); - } } @@ -437,8 +432,9 @@ #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); @@ -480,7 +476,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, @@ -544,14 +540,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.13/arch/ia64/boot/Makefile linux-2.5/arch/ia64/boot/Makefile --- linux-2.5.13/arch/ia64/boot/Makefile Fri May 3 01:22:54 2002 +++ linux-2.5/arch/ia64/boot/Makefile Sun Feb 3 18:03:58 2002 @@ -23,7 +23,7 @@ all: $(targets-y) bootloader: $(OBJECTS) - $(LD) $(LINKFLAGS) $(OBJECTS) $(TOPDIR)/lib/lib.a $(TOPDIR)/arch/$(ARCH)/lib/lib.a \ + $(LD) $(LINKFLAGS) $(OBJECTS) $(TOPDIR)/lib/lib.o $(TOPDIR)/arch/$(ARCH)/lib/lib.a \ -o bootloader clean: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ia64/config.in linux-2.5/arch/ia64/config.in --- linux-2.5.13/arch/ia64/config.in Fri May 3 01:22:53 2002 +++ linux-2.5/arch/ia64/config.in Wed May 1 20:36:25 2002 @@ -188,10 +188,8 @@ fi # !HP_SIM -# -# 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 @@ -226,9 +224,7 @@ source lib/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in fi # !HP_SIM diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ia64/ia32/sys_ia32.c linux-2.5/arch/ia64/ia32/sys_ia32.c --- linux-2.5.13/arch/ia64/ia32/sys_ia32.c Fri May 3 01:22:54 2002 +++ linux-2.5/arch/ia64/ia32/sys_ia32.c Tue Apr 23 12:39:25 2002 @@ -3850,12 +3850,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.13/arch/m68k/amiga/config.c linux-2.5/arch/m68k/amiga/config.c --- linux-2.5.13/arch/m68k/amiga/config.c Fri May 3 01:22:38 2002 +++ linux-2.5/arch/m68k/amiga/config.c Thu Feb 14 00:58:44 2002 @@ -69,11 +69,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.13/arch/mips/Config.help linux-2.5/arch/mips/Config.help --- linux-2.5.13/arch/mips/Config.help Fri May 3 01:22:54 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.13/arch/mips/au1000/common/serial.c linux-2.5/arch/mips/au1000/common/serial.c --- linux-2.5.13/arch/mips/au1000/common/serial.c Fri May 3 01:22:47 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.13/arch/mips/baget/vacserial.c linux-2.5/arch/mips/baget/vacserial.c --- linux-2.5.13/arch/mips/baget/vacserial.c Fri May 3 01:22:55 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.13/arch/mips/config.in linux-2.5/arch/mips/config.in --- linux-2.5.13/arch/mips/config.in Fri May 3 01:22:55 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.13/arch/mips/jazz/setup.c linux-2.5/arch/mips/jazz/setup.c --- linux-2.5.13/arch/mips/jazz/setup.c Fri May 3 01:22: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.13/arch/mips64/Config.help linux-2.5/arch/mips64/Config.help --- linux-2.5.13/arch/mips64/Config.help Fri May 3 01:22:47 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.13/arch/mips64/config.in linux-2.5/arch/mips64/config.in --- linux-2.5.13/arch/mips64/config.in Fri May 3 01:22: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.13/arch/mips64/kernel/ioctl32.c linux-2.5/arch/mips64/kernel/ioctl32.c --- linux-2.5.13/arch/mips64/kernel/ioctl32.c Fri May 3 01:22:53 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.13/arch/parisc/config.in linux-2.5/arch/parisc/config.in --- linux-2.5.13/arch/parisc/config.in Fri May 3 01:22:57 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.13/arch/parisc/kernel/pdc_cons.c linux-2.5/arch/parisc/kernel/pdc_cons.c --- linux-2.5.13/arch/parisc/kernel/pdc_cons.c Fri May 3 01:22:45 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.13/arch/parisc/kernel/traps.c linux-2.5/arch/parisc/kernel/traps.c --- linux-2.5.13/arch/parisc/kernel/traps.c Fri May 3 01:22:53 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.13/arch/ppc/4xx_io/serial_sicc.c linux-2.5/arch/ppc/4xx_io/serial_sicc.c --- linux-2.5.13/arch/ppc/4xx_io/serial_sicc.c Fri May 3 01:22:38 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.13/arch/ppc/8260_io/uart.c linux-2.5/arch/ppc/8260_io/uart.c --- linux-2.5.13/arch/ppc/8260_io/uart.c Fri May 3 01:22:40 2002 +++ linux-2.5/arch/ppc/8260_io/uart.c Thu Feb 14 04:11:07 2002 @@ -2538,7 +2538,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.13/arch/ppc/8xx_io/uart.c linux-2.5/arch/ppc/8xx_io/uart.c --- linux-2.5.13/arch/ppc/8xx_io/uart.c Fri May 3 01:22:44 2002 +++ linux-2.5/arch/ppc/8xx_io/uart.c Sun Mar 3 23:50:41 2002 @@ -485,7 +485,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 @@ -2586,7 +2586,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.13/arch/ppc/Config.help linux-2.5/arch/ppc/Config.help --- linux-2.5.13/arch/ppc/Config.help Fri May 3 01:22:45 2002 +++ linux-2.5/arch/ppc/Config.help Tue Apr 23 12:07:32 2002 @@ -315,6 +315,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.13/arch/ppc/amiga/config.c linux-2.5/arch/ppc/amiga/config.c --- linux-2.5.13/arch/ppc/amiga/config.c Fri May 3 01:22:47 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.13/arch/ppc/boot/chrp/Makefile linux-2.5/arch/ppc/boot/chrp/Makefile --- linux-2.5.13/arch/ppc/boot/chrp/Makefile Fri May 3 01:22:55 2002 +++ linux-2.5/arch/ppc/boot/chrp/Makefile Thu Feb 14 02:57:57 2002 @@ -13,7 +13,7 @@ OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o \ ../common/ofcommon.o -LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a +LIBS = $(TOPDIR)/lib/lib.o ../lib/zlib.a ADDNOTE = ../utils/addnote PIGGYBACK = ../utils/piggyback diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ppc/boot/utils/offset linux-2.5/arch/ppc/boot/utils/offset --- linux-2.5.13/arch/ppc/boot/utils/offset Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/ppc/boot/utils/offset Thu Dec 27 16:32:30 2001 @@ -0,0 +1,4 @@ +#!/bin/sh + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $6}'` +echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ppc/boot/utils/sioffset linux-2.5/arch/ppc/boot/utils/sioffset --- linux-2.5.13/arch/ppc/boot/utils/sioffset Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/ppc/boot/utils/sioffset Thu Dec 27 16:32:30 2001 @@ -0,0 +1,4 @@ +#!/bin/sh + +OFFSET=`grep $1 sImage.map | awk '{print $2}'` +echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ppc/boot/utils/sisize linux-2.5/arch/ppc/boot/utils/sisize --- linux-2.5.13/arch/ppc/boot/utils/sisize Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/ppc/boot/utils/sisize Thu Dec 27 16:32:30 2001 @@ -0,0 +1,4 @@ +#!/bin/sh + +OFFSET=`grep $1 sImage.map | awk '{print $3}'` +echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ppc/boot/utils/size linux-2.5/arch/ppc/boot/utils/size --- linux-2.5.13/arch/ppc/boot/utils/size Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/ppc/boot/utils/size Thu Dec 27 16:32:30 2001 @@ -0,0 +1,4 @@ +#!/bin/sh + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` +echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ppc/config.in linux-2.5/arch/ppc/config.in --- linux-2.5.13/arch/ppc/config.in Fri May 3 01:22:37 2002 +++ linux-2.5/arch/ppc/config.in Wed May 1 20:36:25 2002 @@ -589,9 +589,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in source lib/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ppc/mm/pgtable.c linux-2.5/arch/ppc/mm/pgtable.c --- linux-2.5.13/arch/ppc/mm/pgtable.c Fri May 3 01:22:43 2002 +++ linux-2.5/arch/ppc/mm/pgtable.c Sun Apr 14 17:12:08 2002 @@ -40,10 +40,19 @@ unsigned long ioremap_bot; int io_bat_index; +/* Maximum 768Mb of lowmem. On SMP, this value will be + * trimmed down to whatever can be covered by BATs though. + */ +#define MAX_LOW_MEM 0x30000000 + #if defined(CONFIG_6xx) || defined(CONFIG_POWER3) #define HAVE_BATS 1 #endif +#ifdef HAVE_BATS +static unsigned long __bat2, __bat3; +#endif + extern char etext[], _stext[]; #ifdef HAVE_BATS @@ -245,6 +254,65 @@ return err; } +void __init +adjust_total_lowmem(void) +{ + unsigned long max_low_mem = MAX_LOW_MEM; + +#ifdef HAVE_BATS + unsigned long bat_max = 0x10000000; + unsigned long align; + unsigned long ram = total_lowmem; + int is601 = 0; + + /* 601s have smaller BATs */ + if (PVR_VER(mfspr(PVR)) == 1) { + bat_max = 0x00800000; + is601 = 1; + } + + /* Make sure we don't map a block larger than the + smallest alignment of the physical address. */ + /* alignment of ram_phys_base */ + align = ~(ram_phys_base-1) & ram_phys_base; + /* set BAT block size to MIN(max_size, align) */ + if (align && align < bat_max) + bat_max = align; + + /* Calculate BAT values */ + __bat2 = 1UL << __ilog2(ram); + if (__bat2 > bat_max) + __bat2 = bat_max; + ram -= __bat2; + if (ram) { + __bat3 = 1UL << __ilog2(ram); + if (__bat3 > bat_max) + __bat3 = bat_max; + ram -= __bat3; + } + + printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb, residual: %ldMb\n", + __bat2 >> 20, __bat3 >> 20, ram >> 20); + + /* On SMP, we limit the lowmem to the area mapped with BATs. + * We also assume nobody will do SMP with 601s + */ +#ifdef CONFIG_SMP + if (!is601) + max_low_mem = __bat2 + __bat3; +#endif /* CONFIG_SMP */ + +#endif /* HAVE_BATS */ + if (total_lowmem > max_low_mem) { + total_lowmem = max_low_mem; +#ifndef CONFIG_HIGHMEM + printk(KERN_INFO "Warning, memory limited to %ld Mb, use CONFIG_HIGHMEM" + " to reach %ld Mb\n", max_low_mem >> 20, total_lowmem >> 20); + total_memory = total_lowmem; +#endif /* CONFIG_HIGHMEM */ + } +} + /* * Map in all of physical memory starting at KERNELBASE. */ @@ -254,7 +322,7 @@ #ifdef HAVE_BATS if (!__map_without_bats) - bat_mapin_ram(); + bat_mapin_ram(__bat2, __bat3); #endif /* HAVE_BATS */ v = KERNELBASE; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/ppc/xmon/start.c linux-2.5/arch/ppc/xmon/start.c --- linux-2.5.13/arch/ppc/xmon/start.c Fri May 3 01:22:38 2002 +++ linux-2.5/arch/ppc/xmon/start.c Sat Mar 16 00:50:21 2002 @@ -96,7 +96,7 @@ #endif /* CONFIG_ALL_PPC */ 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.13/arch/ppc64/kernel/chrp_setup.c linux-2.5/arch/ppc64/kernel/chrp_setup.c --- linux-2.5.13/arch/ppc64/kernel/chrp_setup.c Fri May 3 01:22: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.13/arch/ppc64/kernel/ioctl32.c linux-2.5/arch/ppc64/kernel/ioctl32.c --- linux-2.5.13/arch/ppc64/kernel/ioctl32.c Fri May 3 01:22:57 2002 +++ linux-2.5/arch/ppc64/kernel/ioctl32.c Fri May 3 12:57:29 2002 @@ -1781,7 +1781,7 @@ * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or super-user. */ - if (current->tty == tty || suser()) + if (current->tty == tty || capable(CAP_SYS_ADMIN)) return 1; return 0; } @@ -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(); @@ -4466,6 +4474,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.13/arch/ppc64/kernel/sys_ppc32.c linux-2.5/arch/ppc64/kernel/sys_ppc32.c --- linux-2.5.13/arch/ppc64/kernel/sys_ppc32.c Fri May 3 01:22:55 2002 +++ linux-2.5/arch/ppc64/kernel/sys_ppc32.c Tue Apr 23 12:39:25 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.13/arch/ppc64/xmon/start.c linux-2.5/arch/ppc64/xmon/start.c --- linux-2.5.13/arch/ppc64/xmon/start.c Fri May 3 01:22:53 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.13/arch/s390/Config.help linux-2.5/arch/s390/Config.help --- linux-2.5.13/arch/s390/Config.help Fri May 3 01:22:43 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.13/arch/s390x/kernel/linux32.c linux-2.5/arch/s390x/kernel/linux32.c --- linux-2.5.13/arch/s390x/kernel/linux32.c Fri May 3 01:22:43 2002 +++ linux-2.5/arch/s390x/kernel/linux32.c Tue Apr 23 12:39:25 2002 @@ -1582,12 +1582,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.13/arch/sh/config.in linux-2.5/arch/sh/config.in --- linux-2.5.13/arch/sh/config.in Fri May 3 01:22:53 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.13/arch/sh/kernel/hd64465_gpio.c linux-2.5/arch/sh/kernel/hd64465_gpio.c --- linux-2.5.13/arch/sh/kernel/hd64465_gpio.c Fri May 3 01:22:55 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.13/arch/sh/kernel/pci-sh7751.c linux-2.5/arch/sh/kernel/pci-sh7751.c --- linux-2.5.13/arch/sh/kernel/pci-sh7751.c Fri May 3 01:22: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.13/arch/sparc/Makefile linux-2.5/arch/sparc/Makefile --- linux-2.5.13/arch/sparc/Makefile Fri May 3 01:22:42 2002 +++ linux-2.5/arch/sparc/Makefile Sun Feb 3 18:03:58 2002 @@ -41,7 +41,7 @@ CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES) \ arch/sparc/math-emu/math-emu.o -LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ +LIBS := $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ $(TOPDIR)/arch/sparc/lib/lib.a # This one has to come last diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/sparc/defconfig linux-2.5/arch/sparc/defconfig --- linux-2.5.13/arch/sparc/defconfig Fri May 3 01:22:55 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.13/arch/sparc/kernel/sunos_ioctl.c linux-2.5/arch/sparc/kernel/sunos_ioctl.c --- linux-2.5.13/arch/sparc/kernel/sunos_ioctl.c Fri May 3 01:22:49 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.13/arch/sparc64/Makefile linux-2.5/arch/sparc64/Makefile --- linux-2.5.13/arch/sparc64/Makefile Fri May 3 01:22:57 2002 +++ linux-2.5/arch/sparc64/Makefile Sat Mar 23 22:50:31 2002 @@ -74,7 +74,7 @@ CORE_FILES += arch/sparc64/math-emu/math-emu.o -LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ +LIBS := $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ $(TOPDIR)/arch/sparc64/lib/lib.a vmlinux.aout: vmlinux diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/sparc64/config.in linux-2.5/arch/sparc64/config.in --- linux-2.5.13/arch/sparc64/config.in Fri May 3 01:22:47 2002 +++ linux-2.5/arch/sparc64/config.in Wed May 1 20:36:25 2002 @@ -267,9 +267,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Watchdog' @@ -294,5 +292,3 @@ fi endmenu - -source lib/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/sparc64/kernel/ioctl32.c linux-2.5/arch/sparc64/kernel/ioctl32.c --- linux-2.5.13/arch/sparc64/kernel/ioctl32.c Fri May 3 01:22:48 2002 +++ linux-2.5/arch/sparc64/kernel/ioctl32.c Fri May 3 12:57:29 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) @@ -2061,7 +2064,7 @@ * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or super-user. */ - if (current->tty == tty || suser()) + if (current->tty == tty || capable(CAP_SYS_ADMIN)) return 1; return 0; } @@ -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.13/arch/sparc64/kernel/irq.c linux-2.5/arch/sparc64/kernel/irq.c --- linux-2.5.13/arch/sparc64/kernel/irq.c Fri May 3 01:22:49 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.13/arch/sparc64/kernel/pci_common.c linux-2.5/arch/sparc64/kernel/pci_common.c --- linux-2.5.13/arch/sparc64/kernel/pci_common.c Fri May 3 01:22:45 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.13/arch/sparc64/kernel/rtrap.S linux-2.5/arch/sparc64/kernel/rtrap.S --- linux-2.5.13/arch/sparc64/kernel/rtrap.S Fri May 3 01:22:52 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.13/arch/sparc64/kernel/smp.c linux-2.5/arch/sparc64/kernel/smp.c --- linux-2.5.13/arch/sparc64/kernel/smp.c Fri May 3 01:22:37 2002 +++ linux-2.5/arch/sparc64/kernel/smp.c Fri May 3 12:57:29 2002 @@ -692,14 +692,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); @@ -824,11 +824,9 @@ } } -void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, +void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - struct mm_struct *mm = vma->vm_mm; - { u32 ctx = CTX_HWBITS(mm->context); int cpu = smp_processor_id(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/sparc64/kernel/sunos_ioctl32.c linux-2.5/arch/sparc64/kernel/sunos_ioctl32.c --- linux-2.5.13/arch/sparc64/kernel/sunos_ioctl32.c Fri May 3 01:22:57 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.13/arch/sparc64/kernel/sys_sparc32.c linux-2.5/arch/sparc64/kernel/sys_sparc32.c --- linux-2.5.13/arch/sparc64/kernel/sys_sparc32.c Fri May 3 01:22:54 2002 +++ linux-2.5/arch/sparc64/kernel/sys_sparc32.c Fri May 3 12:57:30 2002 @@ -1583,6 +1583,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); @@ -1590,6 +1592,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; } @@ -3960,27 +3963,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.13/arch/sparc64/mm/init.c linux-2.5/arch/sparc64/mm/init.c --- linux-2.5.13/arch/sparc64/mm/init.c Fri May 3 01:22:49 2002 +++ linux-2.5/arch/sparc64/mm/init.c Wed May 1 17:26:07 2002 @@ -594,6 +594,10 @@ remap_func(((tte_data + 0x400000) & _PAGE_PADDR), (unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle()); + if (bigkernel) + remap_func(((tte_data + 0x400000) & _PAGE_PADDR), + (unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle()); + /* Flush out that temporary mapping. */ spitfire_flush_dtlb_nucleus_page(0x0); spitfire_flush_itlb_nucleus_page(0x0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/sparc64/solaris/timod.c linux-2.5/arch/sparc64/solaris/timod.c --- linux-2.5.13/arch/sparc64/solaris/timod.c Fri May 3 01:22:50 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.13/arch/x86_64/config.in linux-2.5/arch/x86_64/config.in --- linux-2.5.13/arch/x86_64/config.in Fri May 3 01:22:45 2002 +++ linux-2.5/arch/x86_64/config.in Wed May 1 20:36:25 2002 @@ -199,9 +199,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/arch/x86_64/ia32/ia32_ioctl.c linux-2.5/arch/x86_64/ia32/ia32_ioctl.c --- linux-2.5.13/arch/x86_64/ia32/ia32_ioctl.c Fri May 3 01:22:37 2002 +++ linux-2.5/arch/x86_64/ia32/ia32_ioctl.c Thu Apr 25 03:00:02 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) @@ -1650,7 +1651,7 @@ * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or super-user. */ - if (current->tty == tty || suser()) + if (current->tty == tty || capable(CAP_SYS_ADMIN)) return 1; return 0; } @@ -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.13/arch/x86_64/kernel/mtrr.c linux-2.5/arch/x86_64/kernel/mtrr.c --- linux-2.5.13/arch/x86_64/kernel/mtrr.c Fri May 3 01:22:47 2002 +++ linux-2.5/arch/x86_64/kernel/mtrr.c Fri Apr 19 21:01:53 2002 @@ -1,22 +1,22 @@ /* 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 @@ -122,10 +122,10 @@ #endif struct set_mtrr_context { - unsigned long flags; - unsigned long deftype_lo; - unsigned long deftype_hi; - unsigned long cr4val; + unsigned long flags; + unsigned long deftype_lo; + unsigned long deftype_hi; + unsigned long cr4val; }; @@ -138,42 +138,42 @@ __save_flags(ctxt->flags); __cli(); - /* Save value of CR4 and clear Page Global Enable (bit 7) */ + /* 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)); - } + ctxt->cr4val = read_cr4(); + write_cr4(ctxt->cr4val & (unsigned char) ~(1 << 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 */ - write_cr0(read_cr0() & 0xbfffffff); + /* Enable caches */ + write_cr0(read_cr0() & 0xffffffffbfffffff); - /* Restore value of CR4 */ + /* 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 +181,7 @@ /* This function returns the number of variable MTRRs */ static unsigned int get_num_var_ranges (void) { - unsigned long config, dummy; + unsigned long config, dummy; rdmsr (MTRRcap_MSR, config, dummy); return (config & 0xff); @@ -191,46 +191,46 @@ /* Returns non-zero if we have the write-combining memory type */ static int have_wrcomb (void) { - unsigned long config, dummy; + unsigned long 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) { - unsigned long mask_lo, mask_hi, base_lo, base_hi; + unsigned long mask_lo, mask_hi, base_lo, base_hi; 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. */ + 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; } static void set_mtrr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) + 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. @@ -241,21 +241,21 @@ [RETURNS] Nothing. */ { - 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,18 +264,18 @@ #ifdef CONFIG_SMP struct mtrr_var_range { - unsigned long base_lo; - unsigned long base_hi; - unsigned long mask_lo; - unsigned long mask_hi; + unsigned long base_lo; + unsigned long base_hi; + unsigned long mask_lo; + unsigned long 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); } @@ -284,37 +284,37 @@ static int __init set_mtrr_var_range_testing (unsigned int index, struct mtrr_var_range *vr) { - unsigned int lo, hi; - int changed = FALSE; + unsigned int lo, hi; + int changed = FALSE; rdmsr (MTRRphysBase_MSR (index), lo, hi); if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { 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)) { 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; + 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]); } @@ -322,66 +322,66 @@ 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; + int changed = FALSE; + int i; + unsigned long lo, hi; rdmsr (MTRRfix64K_00000_MSR, lo, hi); if (p[0] != lo || p[1] != hi) { - wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); - changed = TRUE; - } + wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); + changed = TRUE; + } 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; + changed = TRUE; + } } - } for (i = 0; i < 8; i++) { - rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi); + rdmsr (MTRRfix4K_C0000_MSR + 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; + 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]; + unsigned char enabled; + mtrr_type def_type; }; /* 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; + 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; + 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; } @@ -394,7 +394,7 @@ static unsigned long __init set_mtrr_state (struct mtrr_state *state, - struct set_mtrr_context *ctxt) + struct set_mtrr_context *ctxt) /* [SUMMARY] Set the MTRR state for this CPU. The MTRR state information to read. Some relevant CPU context. @@ -402,24 +402,24 @@ [RETURNS] 0 if no changes made, else a mask indication what was changed. */ { - unsigned int i; - unsigned long change_mask = 0; + unsigned int i; + unsigned long 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,10 +428,10 @@ 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; + unsigned long smp_base; + unsigned long smp_size; + unsigned int smp_reg; + mtrr_type smp_type; }; static void ipi_handler (void *info) @@ -439,68 +439,68 @@ [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) + unsigned long 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); - - /* 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"); + 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"); - /* 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); } @@ -509,44 +509,44 @@ { 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) { - 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 } @@ -559,22 +559,22 @@ [RETURNS] The index of the region on success, else -1 on error. */ { - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; + int i, max; + mtrr_type ltype; + unsigned long lbase, 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; + unsigned long size) = generic_get_free_region; /** * mtrr_add_page - Add a memory type region @@ -625,19 +625,19 @@ 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; + unsigned long lbase, lsize, last; 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,47 +646,47 @@ 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 */ + return -EINVAL; + } + /* New region is enclosed by an existing region */ if (ltype != type) { if (type == MTRR_TYPE_UNCACHABLE) continue; @@ -695,26 +695,26 @@ ("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", 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) (base, size); 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; } @@ -768,10 +768,10 @@ */ 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,7 +791,7 @@ * 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 @@ -803,53 +803,53 @@ [NOTE] This routine uses a spinlock. */ { - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; + int i, max; + mtrr_type ltype; + unsigned long lbase, 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,7 +867,7 @@ * 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 @@ -879,10 +879,10 @@ */ { 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); } @@ -890,66 +890,66 @@ #ifdef USERSPACE_INTERFACE static int mtrr_file_add (unsigned long base, unsigned long size, - unsigned int type, char increment, struct file *file, int page) + unsigned int type, char increment, 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) + 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 +965,8 @@ if (copy_to_user (buf, ascii_buffer + *ppos, len)) return -EFAULT; - *ppos += len; - return len; + *ppos += len; + return len; } @@ -977,249 +977,249 @@ "disable=%d" */ { - int i, err; - unsigned long reg; - unsigned long long base, size; - char *ptr; - char line[LINE_SIZE]; + int i, err; + unsigned long reg; + unsigned long long base, size; + char *ptr; + char line[LINE_SIZE]; if (!suser ()) 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; + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; err = mtrr_add_page ((unsigned long) base, (unsigned long) 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: + case MTRRIOC_ADD_ENTRY: if (!suser ()) 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, file, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_SET_ENTRY: + case MTRRIOC_SET_ENTRY: if (!suser ()) 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: + case MTRRIOC_DEL_ENTRY: if (!suser ()) 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: + case MTRRIOC_KILL_ENTRY: if (!suser ()) 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: + case MTRRIOC_ADD_PAGE_ENTRY: if (!suser ()) 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, file, 1); if (err < 0) return err; - break; + break; - case MTRRIOC_SET_PAGE_ENTRY: + case MTRRIOC_SET_PAGE_ENTRY: if (!suser ()) 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: + case MTRRIOC_DEL_PAGE_ENTRY: if (!suser ()) 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: + case MTRRIOC_KILL_PAGE_ENTRY: if (!suser ()) 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 +1231,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; + unsigned long base, 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]); + 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,28 +1272,24 @@ EXPORT_SYMBOL (mtrr_add); EXPORT_SYMBOL (mtrr_del); - + static void __init mtrr_setup (void) { - printk ("mtrr: v%s)\n", MTRR_VERSION); + printk ("mtrr: v%s Dave Jones (davej@suse.de)\n", MTRR_VERSION); 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_and_mask = ~size_or_mask & 0xfff0000000000000; + } printk ("mtrr: detected mtrr type: x86-64\n"); - } + } } #ifdef CONFIG_SMP @@ -1310,31 +1306,31 @@ void __init mtrr_init_secondary_cpu (void) { - unsigned long mask, count; - struct set_mtrr_context ctxt; + 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 */ + /* 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 +1339,18 @@ #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.13/arch/x86_64/kernel/pci-pc.c linux-2.5/arch/x86_64/kernel/pci-pc.c --- linux-2.5.13/arch/x86_64/kernel/pci-pc.c Fri May 3 01:22:43 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.13/arch/x86_64/kernel/setup.c linux-2.5/arch/x86_64/kernel/setup.c --- linux-2.5.13/arch/x86_64/kernel/setup.c Fri May 3 01:22:39 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.13/drivers/Makefile linux-2.5/drivers/Makefile --- linux-2.5.13/drivers/Makefile Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/Makefile Fri May 3 03:49:06 2002 @@ -26,7 +26,7 @@ subdir-$(CONFIG_TC) += tc subdir-$(CONFIG_VT) += video subdir-$(CONFIG_MAC) += macintosh -subdir-$(CONFIG_ALL_PPC) += macintosh +subdir-$(CONFIG_PPC) += macintosh subdir-$(CONFIG_USB) += usb subdir-$(CONFIG_INPUT) += input subdir-$(CONFIG_SERIO) += input/serio @@ -40,7 +40,7 @@ subdir-$(CONFIG_MD) += md subdir-$(CONFIG_IEEE1394) += ieee1394 subdir-$(CONFIG_PNP) += pnp -subdir-$(CONFIG_ISDN) += isdn +subdir-$(CONFIG_ISDN_BOOL) += isdn subdir-$(CONFIG_ATM) += atm subdir-$(CONFIG_FC4) += fc4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/acorn/block/mfmhd.c linux-2.5/drivers/acorn/block/mfmhd.c --- linux-2.5.13/drivers/acorn/block/mfmhd.c Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/acorn/block/mfmhd.c Fri May 3 12:57:30 2002 @@ -1346,9 +1346,6 @@ */ static int mfm_probecontroller (unsigned int mfm_addr) { - if (check_region (mfm_addr, 10)) - return 0; - if (inw (MFM_STATUS) & STAT_BSY) { outw (CMD_ABT, MFM_COMMAND); udelay (50); @@ -1406,14 +1403,18 @@ ecard_claim(ecs); } + printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq); + if (!request_region (mfm_addr, 10, "mfm")) { + ecard_release(ecs); + return -1; + } + if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) { printk("mfm_init: unable to get major number %d\n", MAJOR_NR); ecard_release(ecs); + release_region(mfm_addr, 10); return -1; } - - printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq); - request_region (mfm_addr, 10, "mfm"); /* Stuff for the assembler routines to get to */ hdc63463_baseaddress = ioaddr(mfm_addr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/acorn/scsi/acornscsi.c linux-2.5/drivers/acorn/scsi/acornscsi.c --- linux-2.5.13/drivers/acorn/scsi/acornscsi.c Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/acorn/scsi/acornscsi.c Mon Apr 15 01:34:04 2002 @@ -2919,13 +2919,13 @@ goto err_1; if (!request_region(host->card.io_intr, 1, "acornscsi(intr)")) goto err_2; - if (!request_region(host->card.io_page, 1, "acornscsi(page)")) + request_region(host->card.io_page, 1, "acornscsi(page)"); goto err_3; #ifdef USE_DMAC - if (!request_region(host->dma.io_port, 256, "acornscsi(dmac)")) + request_region(host->dma.io_port, 256, "acornscsi(dmac)"); goto err_4; #endif - if (!request_region(instance->io_port, 2048, "acornscsi(ram)")) + request_region(instance->io_port, 2048, "acornscsi(ram)"); goto err_5; if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) { @@ -2941,16 +2941,17 @@ return count; err_5: + release_region(instance->io_port, 2048); #ifdef USE_DMAC +err_4: release_region(host->dma.io_port, 256); #endif -err_4: - release_region(host->card.io_page, 1); err_3: - release_region(host->card.io_intr, 1); + release_region(host->card.io_page, 1); err_2: - release_region(instance->io_port + 0x800, 2); + release_region(host->card.io_intr, 1); err_1: + release_region(instance->io_port + 0x800, 2); scsi_unregister(instance); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/acorn/scsi/arxescsi.c linux-2.5/drivers/acorn/scsi/arxescsi.c --- linux-2.5.13/drivers/acorn/scsi/arxescsi.c Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/acorn/scsi/arxescsi.c Mon Apr 15 01:34:04 2002 @@ -304,8 +304,18 @@ ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(host->io_port); ecs[count]->irqmask = CSTATUS_IRQ; - request_region(host->io_port , 120, "arxescsi-fas"); - request_region(host->io_port + 128, 384, "arxescsi-dma"); + if (!request_region(host->io_port , 120, "arxescsi-fas")) { + ecard_release(ecs[count]); + scsi_unregister(host); + break; + } + + if (!request_region(host->io_port + 128, 384, "arxescsi-dma")) { + ecard_release(ecs[count]); + release_region(host->io_port, 120); + scsi_unregister(host); + break; + } printk("scsi%d: Has no interrupts - using polling mode\n", host->host_no); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/acorn/scsi/cumana_2.c linux-2.5/drivers/acorn/scsi/cumana_2.c --- linux-2.5.13/drivers/acorn/scsi/cumana_2.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/acorn/scsi/cumana_2.c Mon Apr 15 01:34:04 2002 @@ -382,8 +382,13 @@ ecs[count]->irq_data = (void *)info->alatch; ecs[count]->ops = (expansioncard_ops_t *)&cumanascsi_2_ops; - request_region(host->io_port + CUMANASCSI2_FAS216_OFFSET, - 16 << CUMANASCSI2_FAS216_SHIFT, "cumanascsi2-fas"); + if (!request_region(host->io_port + CUMANASCSI2_FAS216_OFFSET, + 16 << CUMANASCSI2_FAS216_SHIFT, "cumanascsi2-fas")) { + scsi_unregister(host); + ecard_release(ecs[count]); + break; + } + if (host->irq != NO_IRQ && request_irq(host->irq, cumanascsi_2_intr, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/acorn/scsi/oak.c linux-2.5/drivers/acorn/scsi/oak.c --- linux-2.5.13/drivers/acorn/scsi/oak.c Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/acorn/scsi/oak.c Mon Apr 15 01:34:04 2002 @@ -134,7 +134,8 @@ ecard_claim(ecs[count]); instance->n_io_port = 255; - request_region (instance->io_port, instance->n_io_port, "Oak SCSI"); + if (!request_region (instance->io_port, instance->n_io_port, "Oak SCSI")) + break; if (instance->irq != IRQ_NONE) if (request_irq(instance->irq, do_oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/acpi/acpi_processor.c linux-2.5/drivers/acpi/acpi_processor.c --- linux-2.5.13/drivers/acpi/acpi_processor.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/acpi/acpi_processor.c Tue Apr 16 23:50:56 2002 @@ -23,12 +23,16 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * TBD: * 1. Make # power/performance states dynamic. - * 2. Support duty_cycle values that span bit 4. - * 3. Optimize by having scheduler determine business instead of - * having us try to calculate it here. - * 4. Need C1 timing -- must modify kernel (IRQ handler) to get this. - * 5. Convert time values to ticks (initially) to avoid having to do - * the math (acpi_get_timer_duration). + * 2. Includes support for _real_ performance states (not just throttle). + * 3. Support duty_cycle values that span bit 4. + * 4. Optimize by having scheduler determine business instead of + * having us try to calculate it here. + * 5. Need C1 timing -- must modify kernel (IRQ handler) to get this. + * 6. Convert time values to ticks (initially) to avoid having to do + * the math (acpi_get_timer_duration). + * 7. What is a good default value for the OS busy_metric? + * 8. Support both thermal and power limits. + * 9. Resolve PIIX4 BMISX errata issue (getting an I/O port value of 0). */ #include @@ -162,7 +166,7 @@ /* Limit Interface */ struct acpi_processor_lx { - int px; /* performace state */ + int px; /* performance state */ int tx; /* throttle level */ }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/atm/Config.help linux-2.5/drivers/atm/Config.help --- linux-2.5.13/drivers/atm/Config.help Fri May 3 01:22:45 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.13/drivers/atm/horizon.c linux-2.5/drivers/atm/horizon.c --- linux-2.5.13/drivers/atm/horizon.c Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/atm/horizon.c Mon Apr 15 01:34:04 2002 @@ -2765,15 +2765,13 @@ u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 1)); u8 irq = pci_dev->irq; - // check IO region - if (check_region (iobase, HRZ_IO_EXTENT)) { - PRINTD (DBG_WARN, "IO range already in use"); - continue; - } + /* XXX DEV_LABEL is a guess */ + if (!request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL)) + continue; if (pci_enable_device (pci_dev)) continue; - + dev = kmalloc (sizeof(hrz_dev), GFP_KERNEL); if (!dev) { // perhaps we should be nice: deregister all adapters and abort? @@ -2807,9 +2805,6 @@ dev->atm_dev->dev_data = (void *) dev; dev->pci_dev = pci_dev; - /* XXX DEV_LABEL is a guess */ - request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL); - // enable bus master accesses pci_set_master (pci_dev); @@ -2901,8 +2896,10 @@ atm_dev_deregister (dev->atm_dev); } /* atm_dev_register */ free_irq (irq, dev); + } /* request_irq */ kfree (dev); + release_region(iobase, HRZ_IO_EXTENT); } /* kmalloc and while */ return devs; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/Config.in linux-2.5/drivers/block/Config.in --- linux-2.5.13/drivers/block/Config.in Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/block/Config.in Fri May 3 03:49:06 2002 @@ -37,6 +37,7 @@ dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI dep_mbool ' SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI +dep_tristate 'Micro Memory MM5415 Battery Backed RAM support' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/DAC960.c linux-2.5/drivers/block/DAC960.c --- linux-2.5.13/drivers/block/DAC960.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/block/DAC960.c Fri May 3 12:57:30 2002 @@ -1945,7 +1945,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); @@ -2262,6 +2262,7 @@ Controller->Bus = Bus; Controller->Device = Device; Controller->Function = Function; + Controller->lock = SPIN_LOCK_UNLOCKED; /* Map the Controller Register Window. */ @@ -2405,8 +2406,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); @@ -2431,8 +2436,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.13/drivers/block/DAC960.h linux-2.5/drivers/block/DAC960.h --- linux-2.5.13/drivers/block/DAC960.h Fri May 3 01:22:55 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.13/drivers/block/Makefile linux-2.5/drivers/block/Makefile --- linux-2.5.13/drivers/block/Makefile Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/block/Makefile Fri May 3 03:49:06 2002 @@ -29,7 +29,7 @@ obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o - +obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o subdir-$(CONFIG_PARIDE) += paride diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/amiflop.c linux-2.5/drivers/block/amiflop.c --- linux-2.5.13/drivers/block/amiflop.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/block/amiflop.c Fri May 3 12:57:30 2002 @@ -1399,7 +1399,7 @@ if (CURRENT->bh && !buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); - device = MINOR(CURRENT_DEVICE); + device = minor(CURRENT_DEVICE); if (device < 8) { /* manual selection */ drive = device & 3; @@ -1492,7 +1492,6 @@ { int drive = inode->i_rdev & 3; static struct floppy_struct getprm; - struct super_block * sb; switch(cmd){ case HDIO_GETGEO: @@ -1626,7 +1625,7 @@ int system; unsigned long flags; - drive = MINOR(inode->i_rdev) & 3; + drive = minor(inode->i_rdev) & 3; old_dev = fd_device[drive]; if (fd_ref[drive]) @@ -1669,7 +1668,7 @@ unit[drive].dtype=&data_types[system]; unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* data_types[system].sects*unit[drive].type->sect_mult; - floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1; + floppy_sizes[minor(inode->i_rdev)] = unit[drive].blocks >> 1; printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive, unit[drive].type->name, data_types[system].name); @@ -1679,10 +1678,7 @@ static int floppy_release(struct inode * inode, struct file * filp) { -#ifdef DEBUG - struct super_block * sb; -#endif - int drive = MINOR(inode->i_rdev) & 3; + int drive = minor(inode->i_rdev) & 3; if (unit[drive].dirty == 1) { del_timer (flush_track_timer + drive); @@ -1708,11 +1704,11 @@ */ static int amiga_floppy_change(kdev_t dev) { - int drive = MINOR(dev) & 3; + int drive = minor(dev) & 3; int changed; static int first_time = 1; - if (MAJOR(dev) != MAJOR_NR) { + if (major(dev) != MAJOR_NR) { printk(KERN_CRIT "floppy_change: not a floppy\n"); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/cpqarray.c linux-2.5/drivers/block/cpqarray.c --- linux-2.5.13/drivers/block/cpqarray.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/block/cpqarray.c Fri May 3 12:57:30 2002 @@ -769,7 +769,7 @@ if (ctlr > MAX_CTLR || hba[ctlr] == NULL) return -ENXIO; - if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) + + if (!capable(CAP_SYS_ADMIN) && ida_sizes[(ctlr << CTLR_SHIFT) + minor(inode->i_rdev)] == 0) return -ENXIO; @@ -779,7 +779,7 @@ * but I'm already using way to many device nodes to claim another one * for "raw controller". */ - if (suser() + if (capable(CAP_SYS_ADMIN) && ida_sizes[(ctlr << CTLR_SHIFT) + minor(inode->i_rdev)] == 0 && minor(inode->i_rdev) != 0) return -ENXIO; @@ -1121,7 +1121,7 @@ case BLKRRPART: return revalidate_logvol(inode->i_rdev, 1); case IDAPASSTHRU: - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = copy_from_user(&my_io, io, sizeof(my_io)); if (error) return error; error = ida_ctlr_ioctl(ctlr, dsk, &my_io); @@ -1473,9 +1473,10 @@ int ctlr, i; unsigned long flags; - ctlr = major(dev) - MAJOR_NR; if (minor(dev) != 0) return -ENXIO; + + ctlr = major(dev) - MAJOR_NR; spin_lock_irqsave(IDA_LOCK(ctlr), flags); if (hba[ctlr]->usage_count > 1) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/floppy.c linux-2.5/drivers/block/floppy.c --- linux-2.5.13/drivers/block/floppy.c Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/block/floppy.c Fri May 3 12:57:30 2002 @@ -129,6 +129,12 @@ * floppy controller (lingering task on list after module is gone... boom.) */ +/* + * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range + * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix + * requires many non-obvious changes in arch dependent code. + */ + #define FLOPPY_SANITY_CHECK #undef FLOPPY_SILENT_DCL_CLEAR @@ -4200,9 +4206,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 } @@ -4248,7 +4257,7 @@ FDCS->rawcmd = 2; if (user_reset_fdc(-1,FD_RESET_ALWAYS,0)){ /* free ioports reserved by floppy_grab_irq_and_dma() */ - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); FDCS->address = -1; FDCS->version = FDC_NONE; @@ -4258,7 +4267,7 @@ FDCS->version = get_fdc_version(); if (FDCS->version == FDC_NONE){ /* free ioports reserved by floppy_grab_irq_and_dma() */ - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); FDCS->address = -1; continue; @@ -4337,11 +4346,11 @@ for (fdc=0; fdc< N_FDC; fdc++){ if (FDCS->address != -1){ - if (!request_region(FDCS->address, 6, "floppy")) { - DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address); + if (!request_region(FDCS->address+2, 4, "floppy")) { + DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 2); goto cleanup1; } - if (!request_region(FDCS->address + 7, 1, "floppy DIR")) { + if (!request_region(FDCS->address+7, 1, "floppy DIR")) { DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 7); goto cleanup2; } @@ -4369,12 +4378,12 @@ irqdma_allocated = 1; return 0; cleanup2: - release_region(FDCS->address, 6); + release_region(FDCS->address + 2, 4); cleanup1: fd_free_irq(); fd_free_dma(); while(--fdc >= 0) { - release_region(FDCS->address, 6); + release_region(FDCS->address + 2, 4); release_region(FDCS->address + 7, 1); } MOD_DEC_USE_COUNT; @@ -4441,7 +4450,7 @@ old_fdc = fdc; for (fdc = 0; fdc < N_FDC; fdc++) if (FDCS->address != -1) { - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); } fdc = old_fdc; @@ -4501,3 +4510,5 @@ __setup ("floppy=", floppy_setup); module_init(floppy_init) #endif + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/genhd.c linux-2.5/drivers/block/genhd.c --- linux-2.5.13/drivers/block/genhd.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/block/genhd.c Fri May 3 03:49:06 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.13/drivers/block/ida_ioctl.h linux-2.5/drivers/block/ida_ioctl.h --- linux-2.5.13/drivers/block/ida_ioctl.h Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/block/ida_ioctl.h Fri May 3 03:49:06 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.13/drivers/block/ll_rw_blk.c linux-2.5/drivers/block/ll_rw_blk.c --- linux-2.5.13/drivers/block/ll_rw_blk.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/block/ll_rw_blk.c Fri May 3 12:57:30 2002 @@ -1889,9 +1889,11 @@ * Free request slots per queue. * (Half for reads, half for writes) */ - queue_nr_requests = 64; - if (total_ram > MB(32)) - queue_nr_requests = 256; + queue_nr_requests = (total_ram >> 8) & ~15; /* One per quarter-megabyte */ + if (queue_nr_requests < 32) + queue_nr_requests = 32; + if (queue_nr_requests > 512) + queue_nr_requests = 512; /* * Batch frees according to queue length @@ -1901,7 +1903,11 @@ printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests); blk_max_low_pfn = max_low_pfn; +#ifdef CONFIG_HIGHMEM blk_max_pfn = max_pfn; +#else + blk_max_pfn = max_low_pfn; +#endif #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD) hd_init(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/paride/bpck6.c linux-2.5/drivers/block/paride/bpck6.c --- linux-2.5.13/drivers/block/paride/bpck6.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/block/paride/bpck6.c Fri May 3 03:49:06 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)) /****************************************************************/ /* @@ -226,9 +228,9 @@ 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 +240,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 +248,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 +289,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 +302,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.13/drivers/block/paride/paride.c linux-2.5/drivers/block/paride/paride.c --- linux-2.5.13/drivers/block/paride/paride.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/block/paride/paride.c Wed May 1 17:26:07 2002 @@ -296,9 +296,6 @@ range = 3; if (pi->mode >= pi->proto->epp_first) range = 8; if ((range == 8) && (pi->port % 8)) return 0; -#ifndef CONFIG_PARPORT - if (check_region(pi->port,range)) return 0; -#endif /* !CONFIG_PARPORT */ pi->reserved = range; return (!pi_test_proto(pi,scratch,verbose)); } @@ -307,9 +304,6 @@ range = 3; if (pi->mode >= pi->proto->epp_first) range = 8; if ((range == 8) && (pi->port % 8)) break; -#ifndef CONFIG_PARPORT - if (check_region(pi->port,range)) break; -#endif /* !CONFIG_PARPORT */ pi->reserved = range; if (!pi_test_proto(pi,scratch,verbose)) best = pi->mode; } @@ -331,10 +325,6 @@ if (!pi_register_parport(pi,verbose)) return 0; -#ifndef CONFIG_PARPORT - if (check_region(pi->port,3)) return 0; -#endif /* !CONFIG_PARPORT */ - if (pi->proto->test_port) { pi_claim(pi); max = pi->proto->test_port(pi); @@ -424,7 +414,11 @@ } #ifndef CONFIG_PARPORT - request_region(pi->port,pi->reserved,pi->device); + if (!request_region(pi->port,pi->reserved,pi->device)) + { + printk(KERN_WARNING"paride: Unable to request region 0x%x\n", pi->port); + return 0; + } #endif /* !CONFIG_PARPORT */ if (pi->parname) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/paride/paride.h linux-2.5/drivers/block/paride/paride.h --- linux-2.5.13/drivers/block/paride/paride.h Fri May 3 01:22:47 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.13/drivers/block/paride/ppc6lnx.c linux-2.5/drivers/block/paride/ppc6lnx.c --- linux-2.5.13/drivers/block/paride/ppc6lnx.c Fri May 3 01:22:38 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.13/drivers/block/ps2esdi.c linux-2.5/drivers/block/ps2esdi.c --- linux-2.5.13/drivers/block/ps2esdi.c Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/block/ps2esdi.c Fri May 3 12:57:30 2002 @@ -364,6 +364,11 @@ else io_base = PRIMARY_IO_BASE; + if (!request_region(io_base, 4, "ed")) { + printk(KERN_WARNING"Unable to request region 0x%x\n", io_base); + free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk); + return; + } /* get the dma arbitration level */ dma_arb_level = (status >> 2) & 0xf; @@ -413,7 +418,7 @@ ps2esdi_gendisk.nr_real = ps2esdi_drives; request_dma(dma_arb_level, "ed"); - request_region(io_base, 4, "ed"); + blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128); for (i = 0; i < ps2esdi_drives; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/rd.c linux-2.5/drivers/block/rd.c --- linux-2.5.13/drivers/block/rd.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/block/rd.c Fri May 3 12:57:30 2002 @@ -85,7 +85,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 @@ -102,26 +102,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; } @@ -156,30 +178,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) { @@ -203,8 +215,7 @@ } else { SetPageDirty(page); } - if (unlock) - unlock_page(page); + unlock_page(page); __free_page(page); } while (size); @@ -295,9 +306,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.13/drivers/block/smart1,2.h linux-2.5/drivers/block/smart1,2.h --- linux-2.5.13/drivers/block/smart1,2.h Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/block/smart1,2.h Fri May 3 03:49:06 2002 @@ -156,27 +156,27 @@ */ static void smart2e_submit_command(ctlr_info_t *h, cmdlist_t *c) { - outl(c->busaddr, h->ioaddr + COMMAND_FIFO); + outl(c->busaddr, h->io_mem_addr+ COMMAND_FIFO); } static void smart2e_intr_mask(ctlr_info_t *h, unsigned long val) { - outl(val, h->ioaddr + INTR_MASK); + outl(val, h->io_mem_addr+ INTR_MASK); } static unsigned long smart2e_fifo_full(ctlr_info_t *h) { - return inl(h->ioaddr + COMMAND_FIFO); + return inl(h->io_mem_addr+ COMMAND_FIFO); } static unsigned long smart2e_completed(ctlr_info_t *h) { - return inl(h->ioaddr + COMMAND_COMPLETE_FIFO); + return inl(h->io_mem_addr+ COMMAND_COMPLETE_FIFO); } static unsigned long smart2e_intr_pending(ctlr_info_t *h) { - return inl(h->ioaddr + INTR_PENDING); + return inl(h->io_mem_addr+ INTR_PENDING); } static struct access_method smart2e_access = { @@ -212,30 +212,30 @@ */ c->hdr.size = 0; - outb(CHANNEL_CLEAR, h->ioaddr + SMART1_SYSTEM_DOORBELL); + outb(CHANNEL_CLEAR, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); - outl(c->busaddr, h->ioaddr + SMART1_LISTADDR); - outw(c->size, h->ioaddr + SMART1_LISTLEN); + outl(c->busaddr, h->io_mem_addr + SMART1_LISTADDR); + outw(c->size, h->io_mem_addr + SMART1_LISTLEN); - outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL); + outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_LOCAL_DOORBELL); } static void smart1_intr_mask(ctlr_info_t *h, unsigned long val) { if (val == 1) { - outb(0xFD, h->ioaddr + SMART1_SYSTEM_DOORBELL); - outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL); - outb(0x01, h->ioaddr + SMART1_INTR_MASK); - outb(0x01, h->ioaddr + SMART1_SYSTEM_MASK); + outb(0xFD, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); + outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_LOCAL_DOORBELL); + outb(0x01, h->io_mem_addr + SMART1_INTR_MASK); + outb(0x01, h->io_mem_addr + SMART1_SYSTEM_MASK); } else { - outb(0, h->ioaddr + 0xC8E); + outb(0, h->io_mem_addr + 0xC8E); } } static unsigned long smart1_fifo_full(ctlr_info_t *h) { unsigned char chan; - chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR; + chan = inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR; return chan; } @@ -244,15 +244,18 @@ unsigned char status; unsigned long cmd; - if (inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) { - outb(CHANNEL_BUSY, h->ioaddr + SMART1_SYSTEM_DOORBELL); + if (inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) { + outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); - cmd = inl(h->ioaddr + SMART1_COMPLETE_ADDR); - status = inb(h->ioaddr + SMART1_LISTSTATUS); + cmd = inl(h->io_mem_addr + SMART1_COMPLETE_ADDR); + status = inb(h->io_mem_addr + SMART1_LISTSTATUS); - outb(CHANNEL_CLEAR, h->ioaddr + SMART1_LOCAL_DOORBELL); + outb(CHANNEL_CLEAR, h->io_mem_addr + SMART1_LOCAL_DOORBELL); +#include // Nuke me when you nuke the ifdef. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status; } else { cmd = 0; @@ -263,7 +266,7 @@ static unsigned long smart1_intr_pending(ctlr_info_t *h) { unsigned char chan; - chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY; + chan = inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY; return chan; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/swim3.c linux-2.5/drivers/block/swim3.c --- linux-2.5.13/drivers/block/swim3.c Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/block/swim3.c Fri May 3 12:57:30 2002 @@ -29,13 +29,14 @@ #include #include #include -#include +#include +#include #define MAJOR_NR FLOPPY_MAJOR #include #include -static int floppy_sizes[2] = {2880,2880}; +static int floppy_vers/block/swim3.csizes[2] = {2880,2880}; #define MAX_FLOPPIES 2 @@ -444,9 +445,9 @@ ++cp; init_dma(cp, OUTPUT_MORE, CURRENT->buffer, 512); ++cp; - init_dma(cp, OUTPUT_MORE, write_postamble, sizeof(write_postamble)); + init_dma(cp, OUTPUT_LAST, write_postamble, sizeof(write_postamble)); } else { - init_dma(cp, INPUT_MORE, CURRENT->buffer, n * 512); + init_dma(cp, INPUT_LAST, CURRENT->buffer, n * 512); } ++cp; out_le16(&cp->command, DBDMA_STOP); @@ -678,7 +679,10 @@ break; dr = fs->dma; cp = fs->dma_cmd; - st_le32(&dr->control, RUN << 16); + /* We must wait a bit for dbdma to complete */ + for (n=0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++) + udelay(10); + DBDMA_DO_STOP(dr); out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); @@ -820,7 +824,7 @@ if (devnum >= floppy_count) return -ENODEV; - if ((cmd & 0x80) && !suser()) + if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)) return -EPERM; fs = &floppy_states[devnum]; @@ -1060,9 +1064,14 @@ return -EINVAL; } + if (!request_OF_resource(swim, 0, NULL)) { + printk(KERN_INFO "swim3: can't request IO resource !\n"); + return -EINVAL; + } + mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL; if (mediabay == NULL) - feature_set(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1); memset(fs, 0, sizeof(*fs)); fs->state = idle; @@ -1084,14 +1093,14 @@ if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr); - feature_clear(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0); return -EBUSY; } /* if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA", fs->dma_intr); - feature_clear(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0); return -EBUSY; } */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/swim_iop.c linux-2.5/drivers/block/swim_iop.c --- linux-2.5.13/drivers/block/swim_iop.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/block/swim_iop.c Fri May 3 12:57:30 2002 @@ -348,7 +348,7 @@ if (devnum >= floppy_count) return -ENODEV; - if ((cmd & 0x80) && !suser()) + if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)) return -EPERM; fs = &floppy_states[devnum]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/block/umem.c linux-2.5/drivers/block/umem.c --- linux-2.5.13/drivers/block/umem.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/block/umem.c Sat May 4 12:24:59 2002 @@ -0,0 +1,1435 @@ +/* + * mm.c - Micro Memory(tm) PCI memory board block device driver - v2.3 + * + * (C) 2001 San Mehat + * (C) 2001 Johannes Erdfelt + * (C) 2001 NeilBrown + * + * This driver for the Micro Memory PCI Memory Module with Battery Backup + * is Copyright Micro Memory Inc 2001-2002. All rights reserved. + * + * This driver is released to the public under the terms of the + * GNU GENERAL PUBLIC LICENSE version 2 + * See the file COPYING for details. + * + * This driver provides a standard block device interface for Micro Memory(tm) + * PCI based RAM boards. + * 10/05/01: Phap Nguyen - Rebuilt the driver + * 10/22/01: Phap Nguyen - v2.1 Added disk partitioning + * 29oct2001:NeilBrown - Use make_request_fn instead of request_fn + * - use stand disk partitioning (so fdisk works). + * 08nov2001:NeilBrown - change driver name from "mm" to "umem" + * - incorporate into main kernel + * 08apr2002:NeilBrown - Move some of interrupt handle to tasklet + * - use spin_lock_bh instead of _irq + * - Never block on make_request. queue + * bh's instead. + * - unregister umem from devfs at mod unload + * - Change version to 2.3 + * 07Nov2001:Phap Nguyen - Select pci read command: 06, 12, 15 (Decimal) + * 07Jan2002: P. Nguyen - Used PCI Memory Write & Invalidate for DMA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* O_ACCMODE */ +#include /* HDIO_GETGEO */ + +#include + +#include + +#define PRINTK(x...) do {} while (0) +#define dprintk(x...) do {} while (0) +/*#define dprintk(x...) printk(x) */ + +#define MM_MAXCARDS 4 +#define MM_RAHEAD 2 /* two sectors */ +#define MM_BLKSIZE 1024 /* 1k blocks */ +#define MM_HARDSECT 512 /* 512-byte hardware sectors */ +#define MM_SHIFT 6 /* max 64 partitions on 4 cards */ +#define DEVICE_NR(device) (minor(device)>>MM_SHIFT) + +/* + * Version Information + */ + +#define DRIVER_VERSION "v2.3" +#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown" +#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver" + +static int debug; +/* #define HW_TRACE(x) writeb(x,cards[0].csr_remap + MEMCTRLSTATUS_MAGIC) */ +#define HW_TRACE(x) + +#define DEBUG_LED_ON_TRANSFER 0x01 +#define DEBUG_BATTERY_POLLING 0x02 + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug bitmask"); + +static int init_mem = 0; + +MODULE_PARM(init_mem, "i"); +MODULE_PARM_DESC(init_mem, "Initialize memory"); + +static int pci_read_cmd = 0x0C; /* Read Multiple */ +MODULE_PARM(pci_read_cmd, "i"); +MODULE_PARM_DESC(pci_read_cmd, "PCI read command"); + +static int pci_write_cmd = 0x0F; /* Write and Invalidate */ +MODULE_PARM(pci_write_cmd, "i"); +MODULE_PARM_DESC(pci_write_cmd, "PCI write command"); + +static int pci_cmds; + +#define MAJOR_NR UMEM_MAJOR + +#include +#include + + +static devfs_handle_t devfs_handle; /* For the directory */ + + +struct cardinfo { + int card_number; + struct pci_dev *dev; + + int irq; + + unsigned long csr_base; + unsigned char *csr_remap; + unsigned long csr_len; +#ifdef CONFIG_MM_MAP_MEMORY + unsigned long mem_base; + unsigned char *mem_remap; + unsigned long mem_len; +#endif + + unsigned int win_size; /* PCI window size */ + unsigned int mm_size; /* size in kbytes */ + + struct buffer_head *bh, **bhtail; + + struct mm_page { + dma_addr_t page_dma; + struct mm_dma_desc *desc; + int cnt, headcnt; + struct buffer_head *bh, **bhtail; + } mm_pages[2]; +#define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc)) + + int Active, Ready; + + struct tasklet_struct tasklet; + unsigned int dma_status; + + struct tq_struct plug_tq; + + struct { + int good; + int warned; + unsigned long last_change; + } battery[2]; + + atomic_t usage; + spinlock_t lock; + int check_batteries; + +}; + +static struct cardinfo cards[MM_MAXCARDS]; +static struct block_device_operations mm_fops; +static struct timer_list battery_timer; + + +static int mm_hardsect [MM_MAXCARDS << MM_SHIFT]; +static int mm_blocksizes[MM_MAXCARDS << MM_SHIFT]; +static int mm_sizes[MM_MAXCARDS << MM_SHIFT]; +static struct hd_struct mm_partitions[MM_MAXCARDS << MM_SHIFT]; + +static int num_cards = 0; + +struct gendisk mm_gendisk = { + major: MAJOR_NR, /* Major number assigned later */ + major_name: "umem", /* Name of the major device */ + minor_shift: MM_SHIFT, /* Shift to get device number */ + max_p: 1 << MM_SHIFT, /* Number of partitions */ + fops: &mm_fops, /* Block dev operations */ +/* everything else is dynamic */ +}; + + +static void check_batteries(struct cardinfo *card); + +/* +----------------------------------------------------------------------------------- +-- get_userbit +----------------------------------------------------------------------------------- +*/ +static int get_userbit(struct cardinfo *card, int bit) +{ + unsigned char led; + + led = readb(card->csr_remap + MEMCTRLCMD_LEDCTRL); + return led & bit; +} +/* +----------------------------------------------------------------------------------- +-- set_userbit +----------------------------------------------------------------------------------- +*/ +static int set_userbit(struct cardinfo *card, int bit, unsigned char state) +{ + unsigned char led; + + led = readb(card->csr_remap + MEMCTRLCMD_LEDCTRL); + if (state) + led |= bit; + else + led &= ~bit; + writeb(led, card->csr_remap + MEMCTRLCMD_LEDCTRL); + + return 0; +} +/* +----------------------------------------------------------------------------------- +-- set_led +----------------------------------------------------------------------------------- +*/ +/* + * NOTE: For the power LED, use the LED_POWER_* macros since they differ + */ +static void set_led(struct cardinfo *card, int shift, unsigned char state) +{ + unsigned char led; + + led = readb(card->csr_remap + MEMCTRLCMD_LEDCTRL); + if (state == LED_FLIP) + led ^= (1<csr_remap + MEMCTRLCMD_LEDCTRL); + +} + +#ifdef MM_DIAG +/* +----------------------------------------------------------------------------------- +-- dump_regs +----------------------------------------------------------------------------------- +*/ +static void dump_regs(struct cardinfo *card) +{ + unsigned char *p; + int i, i1; + + p = card->csr_remap; + for (i = 0; i < 8; i++) { + printk(KERN_DEBUG "%p ", p); + + for (i1 = 0; i1 < 16; i1++) + printk("%02x ", *p++); + + printk("\n"); + } +} +#endif +/* +----------------------------------------------------------------------------------- +-- dump_dmastat +----------------------------------------------------------------------------------- +*/ +static void dump_dmastat(struct cardinfo *card, unsigned int dmastat) +{ + printk(KERN_DEBUG "MM%d*: DMAstat - ", card->card_number); + if (dmastat & DMASCR_ANY_ERR) + printk("ANY_ERR "); + if (dmastat & DMASCR_MBE_ERR) + printk("MBE_ERR "); + if (dmastat & DMASCR_PARITY_ERR_REP) + printk("PARITY_ERR_REP "); + if (dmastat & DMASCR_PARITY_ERR_DET) + printk("PARITY_ERR_DET "); + if (dmastat & DMASCR_SYSTEM_ERR_SIG) + printk("SYSTEM_ERR_SIG "); + if (dmastat & DMASCR_TARGET_ABT) + printk("TARGET_ABT "); + if (dmastat & DMASCR_MASTER_ABT) + printk("MASTER_ABT "); + if (dmastat & DMASCR_CHAIN_COMPLETE) + printk("CHAIN_COMPLETE "); + if (dmastat & DMASCR_DMA_COMPLETE) + printk("DMA_COMPLETE "); + printk("\n"); +} + +/* + * Theory of request handling + * + * Each buffer_head is assigned to one mm_dma_desc. + * We have two pages of mm_dma_desc, holding about 64 descriptors + * each. These are allocated at init time. + * One page is "Ready" and is either full, or can have request added. + * The other page might be "Active", which DMA is happening on it. + * + * Whenever IO on the active page completes, the Ready page is activated + * and the ex-Active page is clean out and made Ready. + * Otherwise the Ready page is only activated when it becomes full, or + * when mm_unplug_device is called via run_task_queue(&tq_disk). + * + * If a request arrives while both pages a full, it is queued, and b_rdev is + * overloaded to record whether it was a read or a write. + * + * The interrupt handler only polls the device to clear the interrupt. + * The processing of the result is done in a tasklet. + */ + +static void mm_start_io(struct cardinfo *card) +{ + /* we have the lock, we know there is + * no IO active, and we know that card->Active + * is set + */ + struct mm_dma_desc *desc; + struct mm_page *page; + int offset; + + /* make the last descriptor end the chain */ + page = &card->mm_pages[card->Active]; + PRINTK("start_io: %d %d->%d\n", card->Active, page->headcnt, page->cnt-1); + desc = &page->desc[page->cnt-1]; + + desc->control_bits |= cpu_to_le32(DMASCR_CHAIN_COMP_EN); + desc->control_bits &= ~cpu_to_le32(DMASCR_CHAIN_EN); + desc->sem_control_bits = desc->control_bits; + + + if (debug & DEBUG_LED_ON_TRANSFER) + set_led(card, LED_REMOVE, LED_ON); + + desc = &page->desc[page->headcnt]; + writel(0, card->csr_remap + DMA_PCI_ADDR); + writel(0, card->csr_remap + DMA_PCI_ADDR + 4); + + writel(0, card->csr_remap + DMA_LOCAL_ADDR); + writel(0, card->csr_remap + DMA_LOCAL_ADDR + 4); + + writel(0, card->csr_remap + DMA_TRANSFER_SIZE); + writel(0, card->csr_remap + DMA_TRANSFER_SIZE + 4); + + writel(0, card->csr_remap + DMA_SEMAPHORE_ADDR); + writel(0, card->csr_remap + DMA_SEMAPHORE_ADDR + 4); + + offset = ((char*)desc) - ((char*)page->desc); + writel(cpu_to_le32((page->page_dma+offset)&0xffffffff), + card->csr_remap + DMA_DESCRIPTOR_ADDR); + /* if sizeof(dma_addr_t) == 32, this will generate a warning, sorry */ + writel(cpu_to_le32((page->page_dma)>>32), + card->csr_remap + DMA_DESCRIPTOR_ADDR + 4); + + /* Go, go, go */ + writel(cpu_to_le32(DMASCR_GO | DMASCR_CHAIN_EN | pci_cmds), + card->csr_remap + DMA_STATUS_CTRL); +} + +static int add_bh(struct cardinfo *card); + +static void activate(struct cardinfo *card) +{ + /* if No page is Active, and Ready is + * not empty, then switch Ready page + * to active and start IO. + * Then add any bh's that are available to Ready + */ + + do { + while (add_bh(card)) + ; + + if (card->Active == -1 && + card->mm_pages[card->Ready].cnt > 0) { + card->Active = card->Ready; + card->Ready = 1-card->Ready; + mm_start_io(card); + } + + } while (card->Active == -1 && add_bh(card)); +} + +static inline void reset_page(struct mm_page *page) +{ + page->cnt = 0; + page->headcnt = 0; + page->bh = NULL; + page->bhtail = & page->bh; +} + +static void mm_unplug_device(void *data) +{ + struct cardinfo *card = data; + + spin_lock_bh(&card->lock); + activate(card); + spin_unlock_bh(&card->lock); +} + +/* + * If there is room on Ready page, take + * one bh off list and add it. + * return 1 if there was room, else 0. + */ +static int add_bh(struct cardinfo *card) +{ + struct mm_page *p; + struct mm_dma_desc *desc; + dma_addr_t dma_handle; + int offset; + struct buffer_head *bh; + int rw; + + bh = card->bh; + if (!bh) + return 0; + + if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE) + return 0; + + card->bh = bh->b_reqnext; + if (card->bh == NULL) + card->bhtail = &card->bh; + rw = bh->b_rdev; + + dma_handle = pci_map_page(card->dev, bh->b_page, bh_offset(bh), + bh->b_size, + (rw==READ) ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + + p = &card->mm_pages[card->Ready]; + desc = &p->desc[p->cnt]; + p->cnt++; + *(p->bhtail) = bh; + p->bhtail = &(bh->b_reqnext); + bh->b_reqnext = NULL; + + desc->data_dma_handle = dma_handle; + + desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle); + desc->local_addr= cpu_to_le64(bh->b_rsector << 9); + desc->transfer_size = cpu_to_le32(bh->b_size); + offset = ( ((char*)&desc->sem_control_bits) - ((char*)p->desc)); + desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset)); + desc->zero1 = desc->zero2 = 0; + offset = ( ((char*)(desc+1)) - ((char*)p->desc)); + desc->next_desc_addr = cpu_to_le64(p->page_dma+offset); + desc->control_bits = cpu_to_le32(DMASCR_GO|DMASCR_ERR_INT_EN| + DMASCR_PARITY_INT_EN| + DMASCR_CHAIN_EN | + DMASCR_SEM_EN | + pci_cmds); + if (rw == WRITE) + desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ); + desc->sem_control_bits = desc->control_bits; + return 1; +} + +static void process_page(unsigned long data) +{ + /* check if any of the requests in the page are DMA_COMPLETE, + * and deal with them appropriately. + * If we find a descriptor without DMA_COMPLETE in the semaphore, then + * dma must have hit an error on that descriptor, so use dma_status instead + * and assume that all following descriptors must be re-tried. + */ + struct mm_page *page; + struct buffer_head *ok=NULL, *fail=NULL; + struct cardinfo *card = (struct cardinfo *)data; + unsigned int dma_status = card->dma_status; + + spin_lock_bh(&card->lock); + if (card->Active < 0) + goto out_unlock; + page = &card->mm_pages[card->Active]; + + while (page->bh != NULL) { + struct buffer_head *bh = page->bh; + struct mm_dma_desc *desc = &page->desc[page->headcnt]; + int control = le32_to_cpu(desc->sem_control_bits); + int last=0; + + if (!(control & DMASCR_DMA_COMPLETE)) { + control = dma_status; + last=1; + } + page->headcnt++; + page->bh = bh->b_reqnext; + + pci_unmap_page(card->dev, desc->data_dma_handle, bh->b_size, + (control& DMASCR_TRANSFER_READ) ? + PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + if (!(control & DMASCR_HARD_ERROR)) { + /* it worked just fine */ + bh->b_reqnext = ok; + ok = bh; + } else { + /* error */ + bh->b_reqnext = fail; + fail = bh; + printk(KERN_WARNING "MM%d: I/O error on sector %lx/%x\n", + card->card_number, bh->b_rsector, bh->b_size); + dump_dmastat(card, control); + } + if (last) break; + } + + if (debug & DEBUG_LED_ON_TRANSFER) + set_led(card, LED_REMOVE, LED_OFF); + + if (card->check_batteries) { + card->check_batteries = 0; + check_batteries(card); + } + if (page->headcnt >= page->cnt) { + reset_page(page); + card->Active = -1; + activate(card); + } else { + /* haven't finished with this one yet */ + PRINTK("do some more\n"); + mm_start_io(card); + } + out_unlock: + spin_unlock_bh(&card->lock); + + while(ok) { + struct buffer_head *bh = ok; + ok = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, 1); + } + while(fail) { + struct buffer_head *bh = fail; + fail = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, 0); + } + +} + +/* +----------------------------------------------------------------------------------- +-- mm_make_request +----------------------------------------------------------------------------------- +*/ +static int mm_make_request(request_queue_t *q, int rw, struct buffer_head *bh) +{ + struct cardinfo *card = &cards[DEVICE_NR(bh->b_rdev)]; + PRINTK("mm_make_request %d %ld %d\n", rw, bh->b_rsector, bh->b_size); + bh->b_rsector += mm_partitions[minor(bh->b_rdev)].start_sect; + bh->b_rdev = rw; /* overloading... */ + + spin_lock_bh(&card->lock); + *card->bhtail = bh; + bh->b_reqnext = NULL; + card->bhtail = &bh->b_reqnext; + spin_unlock_bh(&card->lock); + + queue_task(&card->plug_tq, &tq_disk); + return 0; +} + +/* +----------------------------------------------------------------------------------- +-- mm_interrupt +----------------------------------------------------------------------------------- +*/ +static void mm_interrupt(int irq, void *__card, struct pt_regs *regs) +{ + struct cardinfo *card = (struct cardinfo *) __card; + unsigned int dma_status; + unsigned short cfg_status; + +HW_TRACE(0x30); + + dma_status = le32_to_cpu(readl(card->csr_remap + DMA_STATUS_CTRL)); + + if (!(dma_status & (DMASCR_ERROR_MASK | DMASCR_CHAIN_COMPLETE))) { + /* interrupt wasn't for me ... */ + return; + } + + /* clear COMPLETION interrupts */ + writel(cpu_to_le32(DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE), + card->csr_remap+ DMA_STATUS_CTRL); + + + /* log errors and clear interrupt status */ + if (dma_status & DMASCR_ANY_ERR) { + unsigned int data_log1, data_log2; + unsigned int addr_log1, addr_log2; + unsigned char stat, count, syndrome, check; + + stat = readb(card->csr_remap + MEMCTRLCMD_ERRSTATUS); + + data_log1 = le32_to_cpu(readl(card->csr_remap + ERROR_DATA_LOG)); + data_log2 = le32_to_cpu(readl(card->csr_remap + ERROR_DATA_LOG + 4)); + addr_log1 = le32_to_cpu(readl(card->csr_remap + ERROR_ADDR_LOG)); + addr_log2 = readb(card->csr_remap + ERROR_ADDR_LOG + 4); + + count = readb(card->csr_remap + ERROR_COUNT); + syndrome = readb(card->csr_remap + ERROR_SYNDROME); + check = readb(card->csr_remap + ERROR_CHECK); + + dump_dmastat(card, dma_status); + + if (stat & 0x01) + printk(KERN_ERR "MM%d*: Memory access error detected (err count %d)\n", + card->card_number, count); + if (stat & 0x02) + printk(KERN_ERR "MM%d*: Multi-bit EDC error\n", + card->card_number); + + printk(KERN_ERR "MM%d*: Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n", + card->card_number, addr_log2, addr_log1, data_log2, data_log1); + printk(KERN_ERR "MM%d*: Fault Check 0x%02x, Fault Syndrome 0x%02x\n", + card->card_number, check, syndrome); + + writeb(0, card->csr_remap + ERROR_COUNT); + } + + if (dma_status & DMASCR_PARITY_ERR_REP) { + printk(KERN_ERR "MM%d*: PARITY ERROR REPORTED\n", card->card_number); + pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); + pci_write_config_word(card->dev, PCI_STATUS, cfg_status); + } + + if (dma_status & DMASCR_PARITY_ERR_DET) { + printk(KERN_ERR "MM%d*: PARITY ERROR DETECTED\n", card->card_number); + pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); + pci_write_config_word(card->dev, PCI_STATUS, cfg_status); + } + + if (dma_status & DMASCR_SYSTEM_ERR_SIG) { + printk(KERN_ERR "MM%d*: SYSTEM ERROR\n", card->card_number); + pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); + pci_write_config_word(card->dev, PCI_STATUS, cfg_status); + } + + if (dma_status & DMASCR_TARGET_ABT) { + printk(KERN_ERR "MM%d*: TARGET ABORT\n", card->card_number); + pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); + pci_write_config_word(card->dev, PCI_STATUS, cfg_status); + } + + if (dma_status & DMASCR_MASTER_ABT) { + printk(KERN_ERR "MM%d*: MASTER ABORT\n", card->card_number); + pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); + pci_write_config_word(card->dev, PCI_STATUS, cfg_status); + } + + /* and process the DMA descriptors */ + card->dma_status = dma_status; + tasklet_schedule(&card->tasklet); + +HW_TRACE(0x36); + +} +/* +----------------------------------------------------------------------------------- +-- set_fault_to_battery_status +----------------------------------------------------------------------------------- +*/ +/* + * If both batteries are good, no LED + * If either battery has been warned, solid LED + * If both batteries are bad, flash the LED quickly + * If either battery is bad, flash the LED semi quickly + */ +static void set_fault_to_battery_status(struct cardinfo *card) +{ + if (card->battery[0].good && card->battery[1].good) + set_led(card, LED_FAULT, LED_OFF); + else if (card->battery[0].warned || card->battery[1].warned) + set_led(card, LED_FAULT, LED_ON); + else if (!card->battery[0].good && !card->battery[1].good) + set_led(card, LED_FAULT, LED_FLASH_7_0); + else + set_led(card, LED_FAULT, LED_FLASH_3_5); +} + +static void init_battery_timer(void); + + +/* +----------------------------------------------------------------------------------- +-- check_battery +----------------------------------------------------------------------------------- +*/ +static int check_battery(struct cardinfo *card, int battery, int status) +{ + if (status != card->battery[battery].good) { + card->battery[battery].good = !card->battery[battery].good; + card->battery[battery].last_change = jiffies; + + if (card->battery[battery].good) { + printk(KERN_ERR "MM%d: Battery %d now good\n", + card->card_number, battery + 1); + card->battery[battery].warned = 0; + } else + printk(KERN_ERR "MM%d: Battery %d now FAILED\n", + card->card_number, battery + 1); + + return 1; + } else if (!card->battery[battery].good && + !card->battery[battery].warned && + time_after_eq(jiffies, card->battery[battery].last_change + + (HZ * 60 * 60 * 5))) { + printk(KERN_ERR "MM%d: Battery %d still FAILED after 5 hours\n", + card->card_number, battery + 1); + card->battery[battery].warned = 1; + + return 1; + } + + return 0; +} +/* +----------------------------------------------------------------------------------- +-- check_batteries +----------------------------------------------------------------------------------- +*/ +static void check_batteries(struct cardinfo *card) +{ + /* NOTE: this must *never* be called while the card + * is doing (bus-to-card) DMA, or you will need the + * reset switch + */ + unsigned char status; + int ret1, ret2; + + status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY); + if (debug & DEBUG_BATTERY_POLLING) + printk(KERN_DEBUG "MM%d: checking battery status, 1 = %s, 2 = %s\n", + card->card_number, + (status & BATTERY_1_FAILURE) ? "FAILURE" : "OK", + (status & BATTERY_2_FAILURE) ? "FAILURE" : "OK"); + + ret1 = check_battery(card, 0, !(status & BATTERY_1_FAILURE)); + ret2 = check_battery(card, 1, !(status & BATTERY_2_FAILURE)); + + if (ret1 || ret2) + set_fault_to_battery_status(card); +} + +static void check_all_batteries(unsigned long ptr) +{ + int i; + + for (i = 0; i < num_cards; i++) { + struct cardinfo *card = &cards[i]; + spin_lock_bh(&card->lock); + if (card->Active >= 0) + card->check_batteries = 1; + else + check_batteries(card); + spin_unlock_bh(&card->lock); + } + + init_battery_timer(); +} +/* +----------------------------------------------------------------------------------- +-- init_battery_timer +----------------------------------------------------------------------------------- +*/ +static void init_battery_timer(void) +{ + init_timer(&battery_timer); + battery_timer.function = check_all_batteries; + battery_timer.expires = jiffies + (HZ * 60); + add_timer(&battery_timer); +} +/* +----------------------------------------------------------------------------------- +-- del_battery_timer +----------------------------------------------------------------------------------- +*/ +static void del_battery_timer(void) +{ + del_timer(&battery_timer); +} +/* +----------------------------------------------------------------------------------- +-- mm_revalidate +----------------------------------------------------------------------------------- +*/ +/* + * Note no locks taken out here. In a worst case scenario, we could drop + * a chunk of system memory. But that should never happen, since validation + * happens at open or mount time, when locks are held. + */ +static int mm_revalidate(kdev_t i_rdev) +{ + int i; + + int card_number = DEVICE_NR(i_rdev); + /* first partition, # of partitions */ + int part1 = (DEVICE_NR(i_rdev) << MM_SHIFT) + 1; + int npart = (1 << MM_SHIFT) -1; + + /* first clear old partition information */ + for (i=0; ii_rdev) + return -EINVAL; + + minor = minor(i->i_rdev); + card_number = (minor >> MM_SHIFT); + + + switch(cmd) { + + case BLKGETSIZE: + /* Return the device size, expressed in sectors */ + err = ! access_ok (VERIFY_WRITE, arg, sizeof(long)); + if (err) return -EFAULT; + size = mm_gendisk.part[minor].nr_sects; + if (copy_to_user((long *) arg, &size, sizeof (long))) + return -EFAULT; + return 0; + + + case BLKRAGET: /* return the readahead value */ + err = ! access_ok(VERIFY_WRITE, arg, sizeof(long)); + if (err) return -EFAULT; + copy_to_user((long *)arg, &read_ahead[MAJOR(i->i_rdev)],sizeof(long)); + return 0; + + case BLKRASET: /* set the readahead value */ + if (!capable(CAP_SYS_RAWIO)) return -EACCES; + if (arg > 0xff) return -EINVAL; /* limit it */ + read_ahead[MAJOR(i->i_rdev)] = arg; + return 0; + + case BLKRRPART: + return (mm_revalidate(i->i_rdev)); + + case HDIO_GETGEO: + /* + * get geometry: we have to fake one... trim the size to a + * multiple of 2048 (1M): tell we have 32 sectors, 64 heads, + * whatever cylinders. + */ + err = ! access_ok(VERIFY_WRITE, arg, sizeof(geo)); + if (err) return -EFAULT; + size = cards[card_number].mm_size * (1024 / MM_HARDSECT); + geo.heads = 64; + geo.sectors = 32; + geo.start = mm_gendisk.part[minor].start_sect; + geo.cylinders = size / (geo.heads * geo.sectors); + + if (copy_to_user((void *) arg, &geo, sizeof(geo))) + return -EFAULT; + return 0; + + + default: + return blk_ioctl(i->i_rdev, cmd, arg); + } + + return -ENOTTY; /* unknown command */ +} +/* +----------------------------------------------------------------------------------- +-- mm_check_change +----------------------------------------------------------------------------------- + Future support for removable devices +*/ +static int mm_check_change(kdev_t i_rdev) +{ + int card_number = DEVICE_NR(i_rdev); +/* struct cardinfo *dev = cards + card_number; */ + if (card_number >= num_cards) /* paranoid */ + return 0; + + return 0; +} + +/* +----------------------------------------------------------------------------------- +-- mm_open +----------------------------------------------------------------------------------- +*/ +static int mm_open(struct inode *i, struct file *filp) +{ + int num; + struct cardinfo *card; + + num = DEVICE_NR(i->i_rdev); + if (num >= num_cards) + return -ENXIO; + + card = cards + num; + + atomic_inc(&card->usage); + MOD_INC_USE_COUNT; + + return 0; +} +/* +----------------------------------------------------------------------------------- +-- mm_do_release +----------------------------------------------------------------------------------- +*/ +static int mm_do_release(struct inode *i, struct file *filp) +{ + int num; + struct cardinfo *card; + + num = DEVICE_NR(i->i_rdev); + + card = cards + num; + + if (atomic_dec_and_test(&card->usage)) + invalidate_device(i->i_rdev, 1); + + MOD_DEC_USE_COUNT; + return 0; +} +#define INITIALIZE_BHS 32 +/* +----------------------------------------------------------------------------------- +-- mm_init_mem +----------------------------------------------------------------------------------- +*/ +static void mm_end_buffer_io_sync(struct buffer_head *bh, int uptodate) +{ + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); +} + + +static int __devinit mm_init_mem(struct cardinfo *card) +{ + struct buffer_head *bhlist, *bhactive, *bh; + unsigned int i; + int rc = 0; + struct page *zero_page; + + /* Turn this off when we flush the contents of memory and have */ + /* the card rebuild ECC */ + writeb(EDC_NONE_DEFAULT, card->csr_remap + MEMCTRLCMD_ERRCTRL); + + printk("MM%d: initializing memory\n", card->card_number); + + zero_page = alloc_page(GFP_KERNEL); + if (!zero_page) { + printk(KERN_ERR "unable to allocate page for zeroing memory\n"); + rc = -ENOMEM; + goto out_alloc_zero_page; + } + + memset(page_address(zero_page), 0, PAGE_SIZE); + + i=0; bhlist = NULL; + while (i < INITIALIZE_BHS) { + bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL); + if (bh == NULL) + break; + bh->b_next = bhlist; + bhlist = bh; + + bh->b_size = PAGE_SIZE; + init_buffer(bh, mm_end_buffer_io_sync, NULL); + set_bh_page(bh, zero_page, 0); + bh->b_dev = bh->b_rdev = + mk_kdev(MAJOR_NR, card->card_number<b_wait); + + i++; + } + if (bhlist == NULL) { + printk(KERN_ERR "MM: count not allocate buffer heads!!\n"); + rc = -ENOMEM; + goto out_alloc_bh; + } + + bhactive = NULL; + for (i = 0; i < card->mm_size / (PAGE_SIZE / 1024);i++) { + if (bhlist == NULL) { + /* time to wait for some buffers */ + while (bhactive) { + bh = bhactive; + bhactive = bh->b_next; + wait_on_buffer(bh); + if (!test_bit(BH_Uptodate, &bh->b_state)) + rc = -EIO; + bh->b_next = bhlist; + bhlist = bh; + } + } + bh = bhlist; + bhlist = bh->b_next; + + bh->b_blocknr = i; + bh->b_rsector = i*(PAGE_SIZE/512); + set_bit(BH_Lock, &bh->b_state); + clear_bit(BH_Uptodate, &bh->b_state); + mm_make_request(NULL, WRITE, bh); + bh->b_next = bhactive; + bhactive = bh; + } + while (bhactive) { + bh = bhactive; + bhactive = bh->b_next; + wait_on_buffer(bh); + bh->b_next = bhlist; + bhlist = bh; + } + + if (!rc) + set_userbit(card, MEMORY_INITIALIZED, 1); + + while (bhlist) { + bh = bhlist; + bhlist = bh->b_next; + kmem_cache_free(bh_cachep, bh); + } + +out_alloc_bh: + + free_page((unsigned long) zero_page); +out_alloc_zero_page: + + return rc; +} +/* +----------------------------------------------------------------------------------- +-- mm_fops +----------------------------------------------------------------------------------- +*/ +static struct block_device_operations mm_fops = { + owner: THIS_MODULE, + open: mm_open, + release: mm_do_release, + ioctl: mm_ioctl, + revalidate: mm_revalidate, + check_media_change: mm_check_change, +}; +/* +----------------------------------------------------------------------------------- +-- mm_pci_probe +----------------------------------------------------------------------------------- +*/ +static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int ret = -ENODEV; + struct cardinfo *card = &cards[num_cards]; + unsigned char mem_present; + unsigned char batt_status; + unsigned int saved_bar, data; + + if (pci_enable_device(dev) < 0) + return -ENODEV; + + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF8); + pci_set_master(dev); + + card->dev = dev; + card->card_number = num_cards; + + card->csr_base = pci_resource_start(dev, 0); + card->csr_len = pci_resource_len(dev, 0); +#ifdef CONFIG_MM_MAP_MEMORY + card->mem_base = pci_resource_start(dev, 1); + card->mem_len = pci_resource_len(dev, 1); +#endif + + printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n", + card->card_number, dev->bus->number, dev->devfn); + + if (pci_set_dma_mask(dev, 0xffffffffffffffffLL) && + !pci_set_dma_mask(dev, 0xffffffffLL)) { + printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards); + return -ENOMEM; + } + if (!request_mem_region(card->csr_base, card->csr_len, "Micro Memory")) { + printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number); + ret = -ENOMEM; + + goto failed_req_csr; + } + + card->csr_remap = ioremap_nocache(card->csr_base, card->csr_len); + if (!card->csr_remap) { + printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number); + ret = -ENOMEM; + + goto failed_remap_csr; + } + + printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number, + card->csr_base, card->csr_remap, card->csr_len); + +#ifdef CONFIG_MM_MAP_MEMORY + if (!request_mem_region(card->mem_base, card->mem_len, "Micro Memory")) { + printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number); + ret = -ENOMEM; + + goto failed_req_mem; + } + + if (!(card->mem_remap = (unsigned char *)ioremap(card->mem_base, cards->mem_len))) { + printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number); + ret = -ENOMEM; + + goto failed_remap_mem; + } + + printk(KERN_INFO "MM%d: MEM 0x%8lx -> 0x%8lx (0x%lx)\n", card->card_number, + card->mem_base, card->mem_remap, card->mem_len); +#else + printk(KERN_INFO "MM%d: MEM area not remapped (CONFIG_MM_MAP_MEMORY not set)\n", + card->card_number); +#endif + if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != MM_MAGIC_VALUE) { + printk(KERN_ERR "MM%d: Magic number invalid\n", card->card_number); + ret = -ENOMEM; + + goto failed_magic; + } + card->mm_pages[0].desc = pci_alloc_consistent(card->dev, + PAGE_SIZE*2, + &card->mm_pages[0].page_dma); + card->mm_pages[1].desc = pci_alloc_consistent(card->dev, + PAGE_SIZE*2, + &card->mm_pages[1].page_dma); + if (card->mm_pages[0].desc == NULL || + card->mm_pages[1].desc == NULL) { + printk(KERN_ERR "MM%d: alloc failed\n", card->card_number); + goto failed_alloc; + } + reset_page(&card->mm_pages[0]); + reset_page(&card->mm_pages[1]); + card->Ready = 0; /* page 0 is ready */ + card->Active = -1; /* no page is active */ + card->bh = NULL; + card->bhtail = &card->bh; + + tasklet_init(&card->tasklet, process_page, (unsigned long)card); + + card->plug_tq.sync = 0; + card->plug_tq.routine = &mm_unplug_device; + card->plug_tq.data = card; + card->check_batteries = 0; + + mem_present = readb(card->csr_remap + MEMCTRLSTATUS_MEMORY); + switch (mem_present) { + case MEM_128_MB: + card->mm_size = 1024 * 128; + break; + case MEM_256_MB: + card->mm_size = 1024 * 256; + break; + case MEM_512_MB: + card->mm_size = 1024 * 512; + break; + case MEM_1_GB: + card->mm_size = 1024 * 1024; + break; + case MEM_2_GB: + card->mm_size = 1024 * 2048; + break; + default: + card->mm_size = 0; + break; + } + + /* Clear the LED's we control */ + set_led(card, LED_REMOVE, LED_OFF); + set_led(card, LED_FAULT, LED_OFF); + + batt_status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY); + + card->battery[0].good = !(batt_status & BATTERY_1_FAILURE); + card->battery[1].good = !(batt_status & BATTERY_2_FAILURE); + card->battery[0].last_change = card->battery[1].last_change = jiffies; + + printk(KERN_INFO "MM%d: Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n", + card->card_number, card->mm_size, + (batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled"), + card->battery[0].good ? "OK" : "FAILURE", + (batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled"), + card->battery[1].good ? "OK" : "FAILURE"); + + set_fault_to_battery_status(card); + + pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &saved_bar); + data = 0xffffffff; + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, data); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &data); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, saved_bar); + data &= 0xfffffff0; + data = ~data; + data += 1; + + card->win_size = data; + + + if (request_irq(dev->irq, mm_interrupt, SA_SHIRQ, "pci-umem", card)) { + printk(KERN_ERR "MM%d: Unable to allocate IRQ\n", card->card_number); + ret = -ENODEV; + + goto failed_req_irq; + } + + card->irq = dev->irq; + printk(KERN_INFO "MM%d: Window size %d bytes, IRQ %d\n", card->card_number, + card->win_size, card->irq); + + spin_lock_init(&card->lock); + + dev->driver_data = card; + + if (pci_write_cmd != 0x0F) /* If not Memory Write & Invalidate */ + pci_write_cmd = 0x07; /* then Memory Write command */ + + if (pci_write_cmd & 0x08) { /* use Memory Write and Invalidate */ + unsigned short cfg_command; + pci_read_config_word(dev, PCI_COMMAND, &cfg_command); + cfg_command |= 0x10; /* Memory Write & Invalidate Enable */ + pci_write_config_word(dev, PCI_COMMAND, cfg_command); + } + pci_cmds = (pci_read_cmd << 28) | (pci_write_cmd << 24); + + num_cards++; + + if (init_mem) + mm_init_mem(card); + else { + if (!get_userbit(card, MEMORY_INITIALIZED)) + printk(KERN_INFO "MM%d: memory NOT initialized. perhaps load with init_mem=1?\n", card->card_number); + else + printk(KERN_INFO "MM%d: memory already initialized\n", card->card_number); + } + + /* Enable ECC */ + writeb(EDC_STORE_CORRECT, card->csr_remap + MEMCTRLCMD_ERRCTRL); + + return 0; + + failed_req_irq: + failed_alloc: + if (card->mm_pages[0].desc) + pci_free_consistent(card->dev, PAGE_SIZE*2, + card->mm_pages[0].desc, + card->mm_pages[0].page_dma); + if (card->mm_pages[1].desc) + pci_free_consistent(card->dev, PAGE_SIZE*2, + card->mm_pages[1].desc, + card->mm_pages[1].page_dma); + failed_magic: +#ifdef CONFIG_MM_MAP_MEMORY + iounmap((void *) card->mem_remap); + failed_remap_mem: + release_mem_region(card->mem_base, card->mem_len); + failed_req_mem: +#endif + iounmap((void *) card->csr_base); + failed_remap_csr: + release_mem_region(card->csr_base, card->csr_len); + failed_req_csr: + + return ret; +} +/* +----------------------------------------------------------------------------------- +-- mm_pci_remove +----------------------------------------------------------------------------------- +*/ +static void mm_pci_remove(struct pci_dev *dev) +{ + struct cardinfo *card = dev->driver_data; + + tasklet_kill(&card->tasklet); + iounmap(card->csr_remap); + release_mem_region(card->csr_base, card->csr_len); +#ifdef CONFIG_MM_MAP_MEMORY + iounmap(card->mem_remap); + release_mem_region(card->mem_base, card->mem_len); +#endif + free_irq(card->irq, card); + + if (card->mm_pages[0].desc) + pci_free_consistent(card->dev, PAGE_SIZE*2, + card->mm_pages[0].desc, + card->mm_pages[0].page_dma); + if (card->mm_pages[1].desc) + pci_free_consistent(card->dev, PAGE_SIZE*2, + card->mm_pages[1].desc, + card->mm_pages[1].page_dma); +} + +static const struct pci_device_id __devinitdata mm_pci_ids[] = { { + vendor: PCI_VENDOR_ID_MICRO_MEMORY, + device: PCI_DEVICE_ID_MICRO_MEMORY_5415CN, + }, { /* end: all zeroes */ } +}; + +MODULE_DEVICE_TABLE(pci, mm_pci_ids); + +static struct pci_driver mm_pci_driver = { + name: "umem", + id_table: mm_pci_ids, + probe: mm_pci_probe, + remove: mm_pci_remove, +}; +/* +----------------------------------------------------------------------------------- +-- mm_init +----------------------------------------------------------------------------------- +*/ +int __init mm_init(void) +{ + int retval, i; + int err; + + printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); + + memset (cards, 0, MM_MAXCARDS * sizeof(struct cardinfo)); + memset (mm_sizes, 0, (MM_MAXCARDS << MM_SHIFT) * sizeof (int)); + memset (mm_partitions, 0, + (MM_MAXCARDS << MM_SHIFT) * sizeof(struct hd_struct)); + + retval = pci_module_init(&mm_pci_driver); + if (retval) + return -ENOMEM; + + err = devfs_register_blkdev(MAJOR_NR, "umem", &mm_fops); + if (err < 0) { + printk(KERN_ERR "MM: Could not register block device\n"); + return -EIO; + } + devfs_handle = devfs_mk_dir(NULL, "umem", NULL); + + read_ahead[MAJOR_NR] = MM_RAHEAD; + + + /* Initialize partition size: partion 0 of each card is the entire card */ + for (i = 0; i < num_cards; i++) { + mm_sizes[i << MM_SHIFT] = cards[i].mm_size; + } + mm_gendisk.sizes = mm_sizes; + + for (i = 0; i < num_cards; i++) { + spin_lock_init(&cards[i].lock); + mm_partitions[i << MM_SHIFT].nr_sects = + cards[i].mm_size * (1024 / MM_HARDSECT); + } + + mm_gendisk.part = mm_partitions; + mm_gendisk.nr_real = num_cards; + + mm_gendisk.next = gendisk_head; + gendisk_head = &mm_gendisk; + + blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), + mm_make_request); + + for (i = 0; i < num_cards << MM_SHIFT; i++) { + mm_hardsect[i] = MM_HARDSECT; + mm_blocksizes[i] = MM_BLKSIZE; + } + + hardsect_size[MAJOR_NR] = mm_hardsect; + blksize_size[MAJOR_NR] = mm_blocksizes; + for (i = 0; i < num_cards; i++) { + register_disk(&mm_gendisk, mk_kdev(MAJOR_NR, i< #include #include -#include + #include @@ -208,7 +208,7 @@ _PAGE_WRITETHRU); #else - vaddr = (unsigned long)ioremap(paddr, size); + vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size); #endif z2ram_map = kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]), @@ -364,7 +364,7 @@ } } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUES, &z2ram_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &z2ram_lock); blk_size[ MAJOR_NR ] = z2_sizes; return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/Config.help linux-2.5/drivers/bluetooth/Config.help --- linux-2.5.13/drivers/bluetooth/Config.help Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/bluetooth/Config.help Wed May 1 20:36:25 2002 @@ -1,11 +1,23 @@ +HCI UART driver CONFIG_BLUEZ_HCIUART Bluetooth HCI UART driver. This driver is required if you want to use Bluetooth devices with - serial port interface. + serial port interface. You will also need this driver if you have + UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card + adapter and BrainBoxes Bluetooth PC Card. Say Y here to compile support for Bluetooth UART devices into the kernel or say M to compile it as module (hci_uart.o). +HCI UART (H4) protocol support +CONFIG_BLUEZ_HCIUART_H4 + UART (H4) is serial protocol for communication between Bluetooth + device and host. This protocol is required for most UART based + Bluetooth device (including PCMCIA and CF). + + Say Y here to compile support for HCI UART (H4) protocol. + +HCI USB driver CONFIG_BLUEZ_HCIUSB Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with @@ -14,6 +26,24 @@ Say Y here to compile support for Bluetooth USB devices into the kernel or say M to compile it as module (hci_usb.o). +HCI USB firmware download support +CONFIG_BLUEZ_USB_FW_LOAD + Firmware download support for Bluetooth USB devices. + This support is required for devices like Broadcom BCM2033. + + HCI USB driver uses external firmware downloader program provided + in BlueFW package. + For more information, see . + +HCI USB zero packet support +CONFIG_BLUEZ_USB_ZERO_PACKET + Support for USB zero packets. + This option is provided only as a work around for buggy Bluetooth USB + devices. Do _not_ enable it unless you know for sure that your device + requires zero packets. + Most people should say N here. + +HCI VHCI Virtual HCI device driver CONFIG_BLUEZ_HCIVHCI Bluetooth Virtual HCI device driver. This driver is required if you want to use HCI Emulation software. @@ -21,3 +51,24 @@ Say Y here to compile support for virtual HCI devices into the kernel or say M to compile it as module (hci_vhci.o). +HCI DTL1 (PC Card) device driver +CONFIG_BLUEZ_HCIDTL1 + Bluetooth HCI DTL1 (PC Card) driver. + This driver provides support for Bluetooth PCMCIA devices with + Nokia DTL1 interface: + Nokia Bluetooth Card + Socket Bluetooth CF Card + + Say Y here to compile support for HCI DTL1 devices into the + kernel or say M to compile it as module (dtl1_cs.o). + +HCI BlueCard (PC Card) device driver +CONFIG_BLUEZ_HCIBLUECARD + Bluetooth HCI BlueCard (PC Card) driver. + This driver provides support for Bluetooth PCMCIA devices with + Anycom BlueCard interface: + Anycom Bluetooth PC Card + Anycom Bluetooth CF Card + + Say Y here to compile support for HCI BlueCard devices into the + kernel or say M to compile it as module (bluecard_cs.o). diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/Config.in linux-2.5/drivers/bluetooth/Config.in --- linux-2.5.13/drivers/bluetooth/Config.in Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/bluetooth/Config.in Wed May 1 20:36:25 2002 @@ -2,7 +2,20 @@ comment 'Bluetooth device drivers' dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB +if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then + bool ' Firmware download support' CONFIG_BLUEZ_USB_FW_LOAD + bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET +fi + dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ -dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ +if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then + bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4 +fi + +dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ + +dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ + +dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/Makefile linux-2.5/drivers/bluetooth/Makefile --- linux-2.5.13/drivers/bluetooth/Makefile Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/bluetooth/Makefile Wed May 1 20:36:25 2002 @@ -4,8 +4,19 @@ O_TARGET := bluetooth.o +list-multi := hci_uart.o + obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o -obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o +obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o +uart-y := hci_ldisc.o +uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o + +obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o +obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o + include $(TOPDIR)/Rules.make + +hci_uart.o: $(uart-y) + $(LD) -r -o $@ $(uart-y) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/bluecard_cs.c linux-2.5/drivers/bluetooth/bluecard_cs.c --- linux-2.5.13/drivers/bluetooth/bluecard_cs.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/bluecard_cs.c Thu May 2 22:18:32 2002 @@ -0,0 +1,1124 @@ +/* + * + * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041) + * + * Copyright (C) 2001-2002 Marcel Holtmann + * + * + * 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; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +/* ======================== Module parameters ======================== */ + + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0x86bc; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)"); +MODULE_LICENSE("GPL"); + + + +/* ======================== Local structures ======================== */ + + +typedef struct bluecard_info_t { + dev_link_t link; + dev_node_t node; + + struct hci_dev hdev; + + spinlock_t lock; /* For serializing operations */ + struct timer_list timer; /* For LED control */ + + struct sk_buff_head txq; + unsigned long tx_state; + + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; + + unsigned char ctrl_reg; + unsigned long hw_state; /* Status of the hardware and LED control */ +} bluecard_info_t; + + +void bluecard_config(dev_link_t * link); +void bluecard_release(u_long arg); +int bluecard_event(event_t event, int priority, event_callback_args_t * args); + +static dev_info_t dev_info = "bluecard_cs"; + +dev_link_t *bluecard_attach(void); +void bluecard_detach(dev_link_t *); + +static dev_link_t *dev_list = NULL; + + +/* Default baud rate: 57600, 115200, 230400 or 460800 */ +#define DEFAULT_BAUD_RATE 230400 + + +/* Hardware states */ +#define CARD_READY 1 +#define CARD_HAS_PCCARD_ID 4 +#define CARD_HAS_POWER_LED 5 +#define CARD_HAS_ACTIVITY_LED 6 + +/* Transmit states */ +#define XMIT_SENDING 1 +#define XMIT_WAKEUP 2 +#define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */ +#define XMIT_BUF_ONE_READY 6 +#define XMIT_BUF_TWO_READY 7 +#define XMIT_SENDING_READY 8 + +/* Receiver states */ +#define RECV_WAIT_PACKET_TYPE 0 +#define RECV_WAIT_EVENT_HEADER 1 +#define RECV_WAIT_ACL_HEADER 2 +#define RECV_WAIT_SCO_HEADER 3 +#define RECV_WAIT_DATA 4 + +/* Special packet types */ +#define PKT_BAUD_RATE_57600 0x80 +#define PKT_BAUD_RATE_115200 0x81 +#define PKT_BAUD_RATE_230400 0x82 +#define PKT_BAUD_RATE_460800 0x83 + + +/* These are the register offsets */ +#define REG_COMMAND 0x20 +#define REG_INTERRUPT 0x21 +#define REG_CONTROL 0x22 +#define REG_RX_CONTROL 0x24 +#define REG_CARD_RESET 0x30 +#define REG_LED_CTRL 0x30 + +/* REG_COMMAND */ +#define REG_COMMAND_TX_BUF_ONE 0x01 +#define REG_COMMAND_TX_BUF_TWO 0x02 +#define REG_COMMAND_RX_BUF_ONE 0x04 +#define REG_COMMAND_RX_BUF_TWO 0x08 +#define REG_COMMAND_RX_WIN_ONE 0x00 +#define REG_COMMAND_RX_WIN_TWO 0x10 + +/* REG_CONTROL */ +#define REG_CONTROL_BAUD_RATE_57600 0x00 +#define REG_CONTROL_BAUD_RATE_115200 0x01 +#define REG_CONTROL_BAUD_RATE_230400 0x02 +#define REG_CONTROL_BAUD_RATE_460800 0x03 +#define REG_CONTROL_RTS 0x04 +#define REG_CONTROL_BT_ON 0x08 +#define REG_CONTROL_BT_RESET 0x10 +#define REG_CONTROL_BT_RES_PU 0x20 +#define REG_CONTROL_INTERRUPT 0x40 +#define REG_CONTROL_CARD_RESET 0x80 + +/* REG_RX_CONTROL */ +#define RTS_LEVEL_SHIFT_BITS 0x02 + + + +/* ======================== LED handling routines ======================== */ + + +void bluecard_activity_led_timeout(u_long arg) +{ + bluecard_info_t *info = (bluecard_info_t *) arg; + unsigned int iobase = info->link.io.BasePort1; + + if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { + /* Disable activity LED */ + outb(0x08 | 0x20, iobase + 0x30); + } else { + /* Disable power LED */ + outb(0x00, iobase + 0x30); + } +} + + +static void bluecard_enable_activity_led(bluecard_info_t * info) +{ + unsigned int iobase = info->link.io.BasePort1; + + if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { + /* Enable activity LED */ + outb(0x10 | 0x40, iobase + 0x30); + + /* Stop the LED after HZ/4 */ + mod_timer(&(info->timer), jiffies + HZ / 4); + } else { + /* Enable power LED */ + outb(0x08 | 0x20, iobase + 0x30); + + /* Stop the LED after HZ/2 */ + mod_timer(&(info->timer), jiffies + HZ / 2); + } +} + + + +/* ======================== Interrupt handling ======================== */ + + +static int bluecard_write(unsigned int iobase, unsigned int offset, + __u8 * buf, int len) +{ + int i, actual; + + actual = (len > 15) ? 15 : len; + + outb_p(actual, iobase + offset); + + for (i = 0; i < actual; i++) + outb_p(buf[i], iobase + offset + i + 1); + + return actual; +} + + +static void bluecard_write_wakeup(bluecard_info_t * info) +{ + if (!info) { + printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n"); + return; + } + + if (!test_bit(XMIT_SENDING_READY, &(info->tx_state))) + return; + + if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + do { + register unsigned int iobase = info->link.io.BasePort1; + register unsigned int offset; + register unsigned char command; + register unsigned long ready_bit; + register struct sk_buff *skb; + register int len; + + clear_bit(XMIT_WAKEUP, &(info->tx_state)); + + if (!(info->link.state & DEV_PRESENT)) + return; + + if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { + if (!test_bit + (XMIT_BUF_TWO_READY, &(info->tx_state))) + break; + offset = 0x10; + command = REG_COMMAND_TX_BUF_TWO; + ready_bit = XMIT_BUF_TWO_READY; + } else { + if (!test_bit + (XMIT_BUF_ONE_READY, &(info->tx_state))) + break; + offset = 0x00; + command = REG_COMMAND_TX_BUF_ONE; + ready_bit = XMIT_BUF_ONE_READY; + } + + if (!(skb = skb_dequeue(&(info->txq)))) + break; + + if (skb->pkt_type & 0x80) { + + /* Disable RTS */ + info->ctrl_reg |= REG_CONTROL_RTS; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + } + + /* Activate LED */ + bluecard_enable_activity_led(info); + + /* Send frame */ + len = bluecard_write(iobase, offset, skb->data, skb->len); + + /* Tell the FPGA to send the data */ + outb_p(command, iobase + REG_COMMAND); + + /* Mark the buffer as dirty */ + clear_bit(ready_bit, &(info->tx_state)); + + if (skb->pkt_type & 0x80) { + + wait_queue_head_t wait; + unsigned char baud_reg; + + switch (skb->pkt_type) { + case PKT_BAUD_RATE_460800: + baud_reg = REG_CONTROL_BAUD_RATE_460800; + break; + case PKT_BAUD_RATE_230400: + baud_reg = REG_CONTROL_BAUD_RATE_230400; + break; + case PKT_BAUD_RATE_115200: + baud_reg = REG_CONTROL_BAUD_RATE_115200; + break; + case PKT_BAUD_RATE_57600: + /* Fall through... */ + default: + baud_reg = REG_CONTROL_BAUD_RATE_57600; + break; + } + + /* Wait until the command reaches the baseband */ + init_waitqueue_head(&wait); + interruptible_sleep_on_timeout(&wait, HZ / 10); + + /* Set baud on baseband */ + info->ctrl_reg &= ~0x03; + info->ctrl_reg |= baud_reg; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Enable RTS */ + info->ctrl_reg &= ~REG_CONTROL_RTS; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Wait before the next HCI packet can be send */ + interruptible_sleep_on_timeout(&wait, HZ); + + } + + if (len == skb->len) { + kfree_skb(skb); + } else { + skb_pull(skb, len); + skb_queue_head(&(info->txq), skb); + } + + info->hdev.stat.byte_tx += len; + + /* Change buffer */ + change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state)); + + } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); + + clear_bit(XMIT_SENDING, &(info->tx_state)); +} + + +static int bluecard_read(unsigned int iobase, unsigned int offset, + __u8 * buf, int size) +{ + int i, n, len; + + outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND); + + len = inb(iobase + offset); + n = 0; + i = 1; + + while (n < len) { + + if (i == 16) { + outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND); + i = 0; + } + + buf[n] = inb(iobase + offset + i); + + n++; + i++; + + } + + return len; +} + + +static void bluecard_receive(bluecard_info_t * info, unsigned int offset) +{ + unsigned int iobase; + unsigned char buf[31]; + int i, len; + + if (!info) { + printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n"); + return; + } + + iobase = info->link.io.BasePort1; + + if (test_bit(XMIT_SENDING_READY, &(info->tx_state))) + bluecard_enable_activity_led(info); + + len = bluecard_read(iobase, offset, buf, sizeof(buf)); + + for (i = 0; i < len; i++) { + + /* Allocate packet */ + if (info->rx_skb == NULL) { + info->rx_state = RECV_WAIT_PACKET_TYPE; + info->rx_count = 0; + if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); + return; + } + } + + if (info->rx_state == RECV_WAIT_PACKET_TYPE) { + + info->rx_skb->dev = (void *) &(info->hdev); + info->rx_skb->pkt_type = buf[i]; + + switch (info->rx_skb->pkt_type) { + + case 0x00: + /* init packet */ + if (offset != 0x00) { + set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); + set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); + set_bit(XMIT_SENDING_READY, &(info->tx_state)); + bluecard_write_wakeup(info); + } + + kfree_skb(info->rx_skb); + info->rx_skb = NULL; + break; + + case HCI_EVENT_PKT: + info->rx_state = RECV_WAIT_EVENT_HEADER; + info->rx_count = HCI_EVENT_HDR_SIZE; + break; + + case HCI_ACLDATA_PKT: + info->rx_state = RECV_WAIT_ACL_HEADER; + info->rx_count = HCI_ACL_HDR_SIZE; + break; + + case HCI_SCODATA_PKT: + info->rx_state = RECV_WAIT_SCO_HEADER; + info->rx_count = HCI_SCO_HDR_SIZE; + break; + + default: + /* unknown packet */ + printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); + info->hdev.stat.err_rx++; + + kfree_skb(info->rx_skb); + info->rx_skb = NULL; + break; + + } + + } else { + + *skb_put(info->rx_skb, 1) = buf[i]; + info->rx_count--; + + if (info->rx_count == 0) { + + int dlen; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + + switch (info->rx_state) { + + case RECV_WAIT_EVENT_HEADER: + eh = (hci_event_hdr *) (info->rx_skb->data); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = eh->plen; + break; + + case RECV_WAIT_ACL_HEADER: + ah = (hci_acl_hdr *) (info->rx_skb->data); + dlen = __le16_to_cpu(ah->dlen); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = dlen; + break; + + case RECV_WAIT_SCO_HEADER: + sh = (hci_sco_hdr *) (info->rx_skb->data); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = sh->dlen; + break; + + case RECV_WAIT_DATA: + hci_recv_frame(info->rx_skb); + info->rx_skb = NULL; + break; + + } + + } + + } + + + } + + info->hdev.stat.byte_rx += len; +} + + +void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +{ + bluecard_info_t *info = dev_inst; + unsigned int iobase; + unsigned char reg; + + if (!info) { + printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq); + return; + } + + if (!test_bit(CARD_READY, &(info->hw_state))) + return; + + iobase = info->link.io.BasePort1; + + spin_lock(&(info->lock)); + + /* Disable interrupt */ + info->ctrl_reg &= ~REG_CONTROL_INTERRUPT; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + reg = inb(iobase + REG_INTERRUPT); + + if ((reg != 0x00) && (reg != 0xff)) { + + if (reg & 0x04) { + bluecard_receive(info, 0x00); + outb(0x04, iobase + REG_INTERRUPT); + outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); + } + + if (reg & 0x08) { + bluecard_receive(info, 0x10); + outb(0x08, iobase + REG_INTERRUPT); + outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); + } + + if (reg & 0x01) { + set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); + outb(0x01, iobase + REG_INTERRUPT); + bluecard_write_wakeup(info); + } + + if (reg & 0x02) { + set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); + outb(0x02, iobase + REG_INTERRUPT); + bluecard_write_wakeup(info); + } + + } + + /* Enable interrupt */ + info->ctrl_reg |= REG_CONTROL_INTERRUPT; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + spin_unlock(&(info->lock)); +} + + + +/* ======================== Device specific HCI commands ======================== */ + + +static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) +{ + bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + struct sk_buff *skb; + int i; + + /* Ericsson baud rate command */ + unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; + + if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); + return -1; + } + + switch (baud) { + case 460800: + cmd[4] = 0x00; + skb->pkt_type = PKT_BAUD_RATE_460800; + break; + case 230400: + cmd[4] = 0x01; + skb->pkt_type = PKT_BAUD_RATE_230400; + break; + case 115200: + cmd[4] = 0x02; + skb->pkt_type = PKT_BAUD_RATE_115200; + break; + case 57600: + /* Fall through... */ + default: + cmd[4] = 0x03; + skb->pkt_type = PKT_BAUD_RATE_57600; + break; + } + + for (i = 0; i < sizeof(cmd); i++) + *skb_put(skb, 1) = cmd[i]; + + skb_queue_tail(&(info->txq), skb); + + bluecard_write_wakeup(info); + + return 0; +} + + + +/* ======================== HCI interface ======================== */ + + +static int bluecard_hci_flush(struct hci_dev *hdev) +{ + bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + return 0; +} + + +static int bluecard_hci_open(struct hci_dev *hdev) +{ + bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + unsigned int iobase = info->link.io.BasePort1; + + bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); + + if (test_and_set_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + /* Enable LED */ + outb(0x08 | 0x20, iobase + 0x30); + + return 0; +} + + +static int bluecard_hci_close(struct hci_dev *hdev) +{ + bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + unsigned int iobase = info->link.io.BasePort1; + + if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + bluecard_hci_flush(hdev); + + /* Disable LED */ + outb(0x00, iobase + 0x30); + + return 0; +} + + +static int bluecard_hci_send_frame(struct sk_buff *skb) +{ + bluecard_info_t *info; + struct hci_dev *hdev = (struct hci_dev *) (skb->dev); + + if (!hdev) { + printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL)."); + return -ENODEV; + } + + info = (bluecard_info_t *) (hdev->driver_data); + + 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.sco_tx++; + break; + }; + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); + skb_queue_tail(&(info->txq), skb); + + bluecard_write_wakeup(info); + + return 0; +} + + +static void bluecard_hci_destruct(struct hci_dev *hdev) +{ +} + + +static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, + unsigned long arg) +{ + return -ENOIOCTLCMD; +} + + + +/* ======================== Card services HCI interaction ======================== */ + + +int bluecard_open(bluecard_info_t * info) +{ + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev; + unsigned char id; + + spin_lock_init(&(info->lock)); + + init_timer(&(info->timer)); + info->timer.function = &bluecard_activity_led_timeout; + info->timer.data = (u_long) info; + + skb_queue_head_init(&(info->txq)); + + info->rx_state = RECV_WAIT_PACKET_TYPE; + info->rx_count = 0; + info->rx_skb = NULL; + + id = inb(iobase + 0x30); + + if ((id & 0x0f) == 0x02) + set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)); + + if (id & 0x10) + set_bit(CARD_HAS_POWER_LED, &(info->hw_state)); + + if (id & 0x20) + set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state)); + + /* Reset card */ + info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Turn FPGA off */ + outb(0x80, iobase + 0x30); + + /* Wait some time */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 100); + + /* Turn FPGA on */ + outb(0x00, iobase + 0x30); + + /* Activate card */ + info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Enable interrupt */ + outb(0xff, iobase + REG_INTERRUPT); + info->ctrl_reg |= REG_CONTROL_INTERRUPT; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Start the RX buffers */ + outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); + outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); + + /* Signal that the hardware is ready */ + set_bit(CARD_READY, &(info->hw_state)); + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + /* Control the point at which RTS is enabled */ + outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL); + + /* Timeout before it is safe to send the first HCI packet */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((HZ * 5) / 4); // or set it to 3/2 + + /* Initialize and register HCI device */ + + hdev = &(info->hdev); + + hdev->type = HCI_PCCARD; + hdev->driver_data = info; + + hdev->open = bluecard_hci_open; + hdev->close = bluecard_hci_close; + hdev->flush = bluecard_hci_flush; + hdev->send = bluecard_hci_send_frame; + hdev->destruct = bluecard_hci_destruct; + hdev->ioctl = bluecard_hci_ioctl; + + if (hci_register_dev(hdev) < 0) { + printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name); + return -ENODEV; + } + + return 0; +} + + +int bluecard_close(bluecard_info_t * info) +{ + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev = &(info->hdev); + + bluecard_hci_close(hdev); + + clear_bit(CARD_READY, &(info->hw_state)); + + /* Reset card */ + info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Turn FPGA off */ + outb(0x80, iobase + 0x30); + + if (hci_unregister_dev(hdev) < 0) + printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name); + + return 0; +} + + + +/* ======================== Card services ======================== */ + + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + + CardServices(ReportError, handle, &err); +} + + +dev_link_t *bluecard_attach(void) +{ + bluecard_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + /* Create new info device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + + link = &info->link; + link->priv = info; + + link->release.function = &bluecard_release; + link->release.data = (u_long) link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + 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 = bluecard_interrupt; + link->irq.Instance = info; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* 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 = &bluecard_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + bluecard_detach(link); + return NULL; + } + + return link; +} + + +void bluecard_detach(dev_link_t * link) +{ + bluecard_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + + if (*linkp == NULL) + return; + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + bluecard_release((u_long) link); + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + + kfree(info); +} + + +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 CS_NO_MORE_ITEMS; + + 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) + +void bluecard_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + bluecard_info_t *info = link->priv; + tuple_t tuple; + u_short buf[256]; + cisparse_t parse; + config_info_t config; + int i, n, last_ret, last_fn; + + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + i = CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + + link->conf.ConfigIndex = 0x20; + link->io.NumPorts1 = 64; + link->io.IOAddrLines = 6; + + for (n = 0; n < 0x400; n += 0x40) { + link->io.BasePort1 = n ^ 0x300; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + goto failed; + } + + + MOD_INC_USE_COUNT; + + if (bluecard_open(info) != 0) + goto failed; + + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + +failed: + bluecard_release((u_long) link); +} + + +void bluecard_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + bluecard_info_t *info = link->priv; + + if (link->state & DEV_PRESENT) + bluecard_close(info); + + MOD_DEC_USE_COUNT; + + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; +} + + +int bluecard_event(event_t event, int priority, + event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + bluecard_info_t *info = link->priv; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + bluecard_close(info); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + bluecard_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 (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, + &link->conf); + break; + } + + return 0; +} + + + +/* ======================== Module initialization ======================== */ + + +int __init init_bluecard_cs(void) +{ + servinfo_t serv; + int err; + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n"); + return -1; + } + + err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach); + + return err; +} + + +void __exit exit_bluecard_cs(void) +{ + unregister_pccard_driver(&dev_info); + + while (dev_list != NULL) + bluecard_detach(dev_list); +} + + +module_init(init_bluecard_cs); +module_exit(exit_bluecard_cs); + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/dtl1_cs.c linux-2.5/drivers/bluetooth/dtl1_cs.c --- linux-2.5.13/drivers/bluetooth/dtl1_cs.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/dtl1_cs.c Wed May 1 21:12:18 2002 @@ -0,0 +1,939 @@ +/* + * + * A driver for Nokia Connectivity Card DTL-1 devices + * + * Copyright (C) 2001-2002 Marcel Holtmann + * + * + * 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; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + */ + +#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 + + + +/* ======================== Module parameters ======================== */ + + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xffff; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1"); +MODULE_LICENSE("GPL"); + + + +/* ======================== Local structures ======================== */ + + +typedef struct dtl1_info_t { + dev_link_t link; + dev_node_t node; + + struct hci_dev hdev; + + spinlock_t lock; /* For serializing operations */ + + unsigned long flowmask; /* HCI flow mask */ + int ri_latch; + + struct sk_buff_head txq; + unsigned long tx_state; + + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; + +} dtl1_info_t; + + +void dtl1_config(dev_link_t *link); +void dtl1_release(u_long arg); +int dtl1_event(event_t event, int priority, event_callback_args_t *args); + +static dev_info_t dev_info = "dtl1_cs"; + +dev_link_t *dtl1_attach(void); +void dtl1_detach(dev_link_t *); + +dev_link_t *dev_list = NULL; + + +/* Transmit states */ +#define XMIT_SENDING 1 +#define XMIT_WAKEUP 2 +#define XMIT_WAITING 8 + +/* Receiver States */ +#define RECV_WAIT_NSH 0 +#define RECV_WAIT_DATA 1 + + +typedef struct { + u8 type; + u8 zero; + u16 len; +} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ + +#define NSHL 4 /* Nokia Specific Header Length */ + + + +/* ======================== Interrupt handling ======================== */ + + +static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) { + + int actual = 0; + + + /* Tx FIFO should be empty */ + if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) + return 0; + + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase + UART_TX); + actual++; + } + + + return actual; + +} + + +static void dtl1_write_wakeup(dtl1_info_t *info) { + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n"); + return; + } + + + if (test_bit(XMIT_WAITING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + + do { + register unsigned int iobase = info->link.io.BasePort1; + register struct sk_buff *skb; + register int len; + + clear_bit(XMIT_WAKEUP, &(info->tx_state)); + + if (!(info->link.state & DEV_PRESENT)) + return; + + + if (!(skb = skb_dequeue(&(info->txq)))) + break; + + + /* Send frame */ + len = dtl1_write(iobase, 32, skb->data, skb->len); + + if (len == skb->len) { + set_bit(XMIT_WAITING, &(info->tx_state)); + kfree_skb(skb); + } + else { + skb_pull(skb, len); + skb_queue_head(&(info->txq), skb); + } + + info->hdev.stat.byte_tx += len; + + } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); + + + clear_bit(XMIT_SENDING, &(info->tx_state)); + +} + + +static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) { + + u8 flowmask = *(u8 *)skb->data; + int i; + + + printk(KERN_INFO "dtl1_cs: Nokia control data = "); + for (i = 0; i < skb->len; i++) { + printk("%02x ", skb->data[i]); + } + printk("\n"); + + + /* transition to active state */ + if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { + clear_bit(XMIT_WAITING, &(info->tx_state)); + dtl1_write_wakeup(info); + } + + info->flowmask = flowmask; + + + kfree_skb(skb); + +} + + +static void dtl1_receive(dtl1_info_t *info) { + + unsigned int iobase; + nsh_t *nsh; + int boguscount = 0; + + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n"); + return; + } + + + iobase = info->link.io.BasePort1; + + do { + info->hdev.stat.byte_rx++; + + /* Allocate packet */ + if (info->rx_skb == NULL) + if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + return; + } + + + *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + nsh = (nsh_t *)info->rx_skb->data; + + info->rx_count--; + + + if (info->rx_count == 0) { + + switch (info->rx_state) { + case RECV_WAIT_NSH: + info->rx_state = RECV_WAIT_DATA; + info->rx_count = nsh->len + (nsh->len & 0x0001); + break; + case RECV_WAIT_DATA: + info->rx_skb->pkt_type = nsh->type; + + /* remove PAD byte if it exists */ + if (nsh->len & 0x0001) { + info->rx_skb->tail--; + info->rx_skb->len--; + } + + /* remove NSH */ + skb_pull(info->rx_skb, NSHL); + + + switch (info->rx_skb->pkt_type) { + case 0x80: + /* control data for the Nokia Card */ + dtl1_control(info, info->rx_skb); + break; + case 0x82: + case 0x83: + case 0x84: + /* send frame to the HCI layer */ + info->rx_skb->dev = (void *)&(info->hdev); + info->rx_skb->pkt_type &= 0x0f; + hci_recv_frame(info->rx_skb); + break; + default: + /* unknown packet */ + printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); + kfree_skb(info->rx_skb); + break; + } + + + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + info->rx_skb = NULL; + break; + } + + } + + + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) + break; + + } while (inb(iobase + UART_LSR) & UART_LSR_DR); + + +} + + +void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) { + + dtl1_info_t *info = dev_inst; + unsigned int iobase; + unsigned char msr; + int boguscount = 0; + int iir, lsr; + + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); + return; + } + + + iobase = info->link.io.BasePort1; + + + spin_lock(&(info->lock)); + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + while (iir) { + + /* Clear interrupt */ + lsr = inb(iobase + UART_LSR); + + switch (iir) { + case UART_IIR_RLSI: + printk(KERN_NOTICE "dtl1_cs: RLSI\n"); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + dtl1_receive(info); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) { + /* Transmitter ready for data */ + dtl1_write_wakeup(info); + } + break; + default: + printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir); + break; + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 100) + break; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + + } + + + msr = inb(iobase + UART_MSR); + + if (info->ri_latch ^ (msr & UART_MSR_RI)) { + info->ri_latch = msr & UART_MSR_RI; + clear_bit(XMIT_WAITING, &(info->tx_state)); + dtl1_write_wakeup(info); + } + + spin_unlock(&(info->lock)); + +} + + + +/* ======================== HCI interface ======================== */ + + +static int dtl1_hci_open(struct hci_dev *hdev) { + + set_bit(HCI_RUNNING, &(hdev->flags)); + + + return 0; + +} + + +static int dtl1_hci_flush(struct hci_dev *hdev) { + + dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); + + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + + return 0; + +} + + +static int dtl1_hci_close(struct hci_dev *hdev) { + + if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + + dtl1_hci_flush(hdev); + + + return 0; + +} + + +static int dtl1_hci_send_frame(struct sk_buff *skb) { + + dtl1_info_t *info; + struct hci_dev* hdev = (struct hci_dev *)(skb->dev); + struct sk_buff *s; + nsh_t nsh; + + + if (!hdev) { + printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL)."); + return -ENODEV; + } + + info = (dtl1_info_t *)(hdev->driver_data); + + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + nsh.type = 0x81; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + nsh.type = 0x82; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + nsh.type = 0x83; + break; + }; + + nsh.zero = 0; + nsh.len = skb->len; + + s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); + skb_reserve(s, NSHL); + memcpy(skb_put(s, skb->len), skb->data, skb->len); + if (skb->len & 0x0001) + *skb_put(s, 1) = 0; /* PAD */ + + /* Prepend skb with Nokia frame header and queue */ + memcpy(skb_push(s, NSHL), &nsh, NSHL); + skb_queue_tail(&(info->txq), s); + + + dtl1_write_wakeup(info); + + kfree_skb(skb); + + + return 0; + +} + + +static void dtl1_hci_destruct(struct hci_dev *hdev) { +} + + +static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) { + + return -ENOIOCTLCMD; + +} + + + +/* ======================== Card services HCI interaction ======================== */ + + +int dtl1_open(dtl1_info_t *info) { + + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev; + + + spin_lock_init(&(info->lock)); + + skb_queue_head_init(&(info->txq)); + + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + info->rx_skb = NULL; + + set_bit(XMIT_WAITING, &(info->tx_state)); + + + spin_lock_irqsave(&(info->lock), flags); + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + /* Initialize UART */ + outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); + + info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; + + /* Turn on interrupts */ + outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); + + + /* Timeout before it is safe to send the first HCI packet */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ * 2); + + + /* Initialize and register HCI device */ + + hdev = &(info->hdev); + + hdev->type = HCI_PCCARD; + hdev->driver_data = info; + + hdev->open = dtl1_hci_open; + hdev->close = dtl1_hci_close; + hdev->flush = dtl1_hci_flush; + hdev->send = dtl1_hci_send_frame; + hdev->destruct = dtl1_hci_destruct; + hdev->ioctl = dtl1_hci_ioctl; + + if (hci_register_dev(hdev) < 0) { + printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name); + return -ENODEV; + } + + + return 0; + +} + + +int dtl1_close(dtl1_info_t *info) { + + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev = &(info->hdev); + + + dtl1_hci_close(hdev); + + + spin_lock_irqsave(&(info->lock), flags); + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); + + + if (hci_unregister_dev(hdev) < 0) + printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name); + + + return 0; + +} + + + +/* ======================== Card services ======================== */ + + +static void cs_error(client_handle_t handle, int func, int ret) { + + error_info_t err = { func, ret }; + + + CardServices(ReportError, handle, &err); + +} + + +dev_link_t *dtl1_attach(void) { + + dtl1_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + + /* Create new info device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + + + link = &info->link; + link->priv = info; + + link->release.function = &dtl1_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + 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 = dtl1_interrupt; + link->irq.Instance = info; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + + /* 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 = &dtl1_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + dtl1_detach(link); + return NULL; + } + + + return link; + +} + + +void dtl1_detach(dev_link_t *link) { + + dtl1_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + + if (*linkp == NULL) + return; + + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + dtl1_release((u_long)link); + + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + + /* Unlink device structure, free bits */ + *linkp = link->next; + + kfree(info); + +} + + +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 CS_NO_MORE_ITEMS; + + 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) + +void dtl1_config(dev_link_t *link) { + + client_handle_t handle = link->handle; + dtl1_info_t *info = link->priv; + tuple_t tuple; + u_short buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + config_info_t config; + int i, last_ret, last_fn; + + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + + /* Configure card */ + link->state |= DEV_CONFIG; + i = CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + /* Look for a generic full-sized window */ + link->io.NumPorts1 = 8; + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.NumPorts1 = cf->io.win[0].len; /*yo*/ + link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + i = next_tuple(handle, &tuple, &parse); + } + + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + goto failed; + } + + + MOD_INC_USE_COUNT; + + if (dtl1_open(info) != 0) + goto failed; + + + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + + return; + + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + dtl1_release((u_long)link); + +} + + +void dtl1_release(u_long arg) { + + dev_link_t *link = (dev_link_t *)arg; + dtl1_info_t *info = link->priv; + + + if (link->state & DEV_PRESENT) + dtl1_close(info); + + MOD_DEC_USE_COUNT; + + + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + +} + + +int dtl1_event(event_t event, int priority, event_callback_args_t *args) { + + dev_link_t *link = args->client_data; + dtl1_info_t *info = link->priv; + + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dtl1_close(info); + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dtl1_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 (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + + + return 0; + +} + + + +/* ======================== Module initialization ======================== */ + + +int __init init_dtl1_cs(void) { + + servinfo_t serv; + int err; + + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n"); + return -1; + } + + + err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach); + + + return err; + +} + +void __exit exit_dtl1_cs(void) { + + unregister_pccard_driver(&dev_info); + + while (dev_list != NULL) + dtl1_detach(dev_list); + +} + + +module_init(init_dtl1_cs); +module_exit(exit_dtl1_cs); + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/hci_h4.c linux-2.5/drivers/bluetooth/hci_h4.c --- linux-2.5.13/drivers/bluetooth/hci_h4.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/hci_h4.c Wed May 1 21:12:18 2002 @@ -0,0 +1,273 @@ +/* + 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(H4) protocol. + * + * $Id: hci_h4.c,v 1.2 2002/04/17 17:37:20 maxk Exp $ + */ +#define VERSION "1.1" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "hci_uart.h" +#include "hci_h4.h" + +#ifndef HCI_UART_DEBUG +#undef BT_DBG +#define BT_DBG( A... ) +#undef BT_DMP +#define BT_DMP( A... ) +#endif + +/* Initialize protocol */ +static int h4_open(struct n_hci *n_hci) +{ + struct h4_struct *h4; + + BT_DBG("n_hci %p", n_hci); + + h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); + if (!h4) + return -ENOMEM; + memset(h4, 0, sizeof(*h4)); + + n_hci->priv = h4; + return 0; +} + +/* Flush protocol data */ +static int h4_flush(struct n_hci *n_hci) +{ + BT_DBG("n_hci %p", n_hci); + return 0; +} + +/* Close protocol */ +static int h4_close(struct n_hci *n_hci) +{ + struct h4_struct *h4 = n_hci->priv; + n_hci->priv = NULL; + + BT_DBG("n_hci %p", n_hci); + + if (h4->rx_skb) + kfree_skb(h4->rx_skb); + + kfree(h4); + return 0; +} + +/* Send data */ +static int h4_send(struct n_hci *n_hci, void *data, int len) +{ + struct tty_struct *tty = n_hci->tty; + + BT_DBG("n_hci %p len %d", n_hci, len); + + /* Send frame to TTY driver */ + tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + return tty->driver.write(tty, 0, data, len); +} + +/* Init frame before queueing (padding, crc, etc) */ +static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb) +{ + BT_DBG("n_hci %p skb %p", n_hci, skb); + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &skb->pkt_type, 1); + return skb; +} + +static inline int h4_check_data_len(struct h4_struct *h4, int len) +{ + register int room = skb_tailroom(h4->rx_skb); + + BT_DBG("len %d room %d", len, room); + if (!len) { + BT_DMP(h4->rx_skb->data, h4->rx_skb->len); + hci_recv_frame(h4->rx_skb); + } else if (len > room) { + BT_ERR("Data length is to large"); + kfree_skb(h4->rx_skb); + } else { + h4->rx_state = H4_W4_DATA; + h4->rx_count = len; + return len; + } + + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_skb = NULL; + h4->rx_count = 0; + return 0; +} + +/* Recv data */ +static int h4_recv(struct n_hci *n_hci, void *data, int count) +{ + struct h4_struct *h4 = n_hci->priv; + register char *ptr; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + register int len, type, dlen; + + BT_DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count); + + ptr = data; + while (count) { + if (h4->rx_count) { + len = MIN(h4->rx_count, count); + memcpy(skb_put(h4->rx_skb, len), ptr, len); + h4->rx_count -= len; count -= len; ptr += len; + + if (h4->rx_count) + continue; + + switch (h4->rx_state) { + case H4_W4_DATA: + BT_DBG("Complete data"); + + BT_DMP(h4->rx_skb->data, h4->rx_skb->len); + + hci_recv_frame(h4->rx_skb); + + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_skb = NULL; + continue; + + case H4_W4_EVENT_HDR: + eh = (hci_event_hdr *) h4->rx_skb->data; + + BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); + + h4_check_data_len(h4, eh->plen); + continue; + + case H4_W4_ACL_HDR: + ah = (hci_acl_hdr *) h4->rx_skb->data; + dlen = __le16_to_cpu(ah->dlen); + + BT_DBG("ACL header: dlen %d", dlen); + + h4_check_data_len(h4, dlen); + continue; + + case H4_W4_SCO_HDR: + sh = (hci_sco_hdr *) h4->rx_skb->data; + + BT_DBG("SCO header: dlen %d", sh->dlen); + + h4_check_data_len(h4, sh->dlen); + continue; + }; + } + + /* H4_W4_PACKET_TYPE */ + switch (*ptr) { + case HCI_EVENT_PKT: + BT_DBG("Event packet"); + h4->rx_state = H4_W4_EVENT_HDR; + h4->rx_count = HCI_EVENT_HDR_SIZE; + type = HCI_EVENT_PKT; + break; + + case HCI_ACLDATA_PKT: + BT_DBG("ACL packet"); + h4->rx_state = H4_W4_ACL_HDR; + h4->rx_count = HCI_ACL_HDR_SIZE; + type = HCI_ACLDATA_PKT; + break; + + case HCI_SCODATA_PKT: + BT_DBG("SCO packet"); + h4->rx_state = H4_W4_SCO_HDR; + h4->rx_count = HCI_SCO_HDR_SIZE; + type = HCI_SCODATA_PKT; + break; + + default: + BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); + n_hci->hdev.stat.err_rx++; + ptr++; count--; + continue; + }; + ptr++; count--; + + /* Allocate packet */ + h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!h4->rx_skb) { + BT_ERR("Can't allocate mem for new packet"); + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_count = 0; + return 0; + } + h4->rx_skb->dev = (void *) &n_hci->hdev; + h4->rx_skb->pkt_type = type; + } + return count; +} + +static struct hci_uart_proto h4p = { + id: HCI_UART_H4, + open: h4_open, + close: h4_close, + send: h4_send, + recv: h4_recv, + preq: h4_preq, + flush: h4_flush, +}; + +int h4_init(void) +{ + return hci_uart_register_proto(&h4p); +} + +int h4_deinit(void) +{ + return hci_uart_unregister_proto(&h4p); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/hci_h4.h linux-2.5/drivers/bluetooth/hci_h4.h --- linux-2.5.13/drivers/bluetooth/hci_h4.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/hci_h4.h Wed May 1 21:12:49 2002 @@ -0,0 +1,43 @@ +/* + 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. +*/ + +/* + * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifdef __KERNEL__ +struct h4_struct { + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; +}; + +/* H4 receiver States */ +#define H4_W4_PACKET_TYPE 0 +#define H4_W4_EVENT_HDR 1 +#define H4_W4_ACL_HDR 2 +#define H4_W4_SCO_HDR 3 +#define H4_W4_DATA 4 + +#endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/hci_ldisc.c linux-2.5/drivers/bluetooth/hci_ldisc.c --- linux-2.5.13/drivers/bluetooth/hci_ldisc.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/hci_ldisc.c Wed May 1 21:12:18 2002 @@ -0,0 +1,554 @@ +/* + 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_ldisc.c,v 1.2 2002/04/17 17:37:20 maxk Exp $ + */ +#define VERSION "2.0" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "hci_uart.h" + +#ifndef HCI_UART_DEBUG +#undef BT_DBG +#define BT_DBG( A... ) +#undef BT_DMP +#define BT_DMP( A... ) +#endif + +static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; + +int hci_uart_register_proto(struct hci_uart_proto *p) +{ + if (p->id >= HCI_UART_MAX_PROTO) + return -EINVAL; + + if (hup[p->id]) + return -EEXIST; + + hup[p->id] = p; + return 0; +} + +int hci_uart_unregister_proto(struct hci_uart_proto *p) +{ + if (p->id >= HCI_UART_MAX_PROTO) + return -EINVAL; + + if (!hup[p->id]) + return -EINVAL; + + hup[p->id] = NULL; + return 0; +} + +static struct hci_uart_proto *n_hci_get_proto(unsigned int id) +{ + if (id >= HCI_UART_MAX_PROTO) + return NULL; + return hup[id]; +} + +/* ------- Interface to HCI layer ------ */ +/* Initialize device */ +static int n_hci_open(struct hci_dev *hdev) +{ + BT_DBG("%s %p", hdev->name, hdev); + + /* Nothing to do for UART driver */ + + set_bit(HCI_RUNNING, &hdev->flags); + return 0; +} + +/* Reset device */ +static 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; + + BT_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); + + if (n_hci->proto->flush) + n_hci->proto->flush(n_hci); + + return 0; +} + +/* Close device */ +static int n_hci_close(struct hci_dev *hdev) +{ + BT_DBG("hdev %p", hdev); + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; + + n_hci_flush(hdev); + return 0; +} + +static int n_hci_tx_wakeup(struct n_hci *n_hci) +{ + struct hci_dev *hdev = &n_hci->hdev; + + if (test_and_set_bit(N_HCI_SENDING, &n_hci->tx_state)) { + set_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state); + return 0; + } + + BT_DBG(""); + do { + register struct sk_buff *skb; + register int len; + + clear_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state); + + if (!(skb = skb_dequeue(&n_hci->txq))) + break; + + len = n_hci->proto->send(n_hci, skb->data, skb->len); + n_hci->hdev.stat.byte_tx += len; + + if (len == skb->len) { + /* Complete frame was sent */ + + 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; + }; + + kfree_skb(skb); + } else { + /* Subtract sent part and requeue */ + skb_pull(skb, len); + skb_queue_head(&n_hci->txq, skb); + } + } while (test_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state)); + clear_bit(N_HCI_SENDING, &n_hci->tx_state); + return 0; +} + +/* Send frames from HCI layer */ +static 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) { + BT_ERR("Frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + + n_hci = (struct n_hci *) hdev->driver_data; + tty = n_hci->tty; + + BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); + + if (n_hci->proto->preq) { + skb = n_hci->proto->preq(n_hci, skb); + if (!skb) + return 0; + } + + skb_queue_tail(&n_hci->txq, skb); + n_hci_tx_wakeup(n_hci); + return 0; +} + +static void n_hci_destruct(struct hci_dev *hdev) +{ + struct n_hci *n_hci; + + if (!hdev) return; + + BT_DBG("%s", hdev->name); + + n_hci = (struct n_hci *) hdev->driver_data; + kfree(n_hci); + + MOD_DEC_USE_COUNT; +} + +/* ------ 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 = (void *)tty->disc_data; + + BT_DBG("tty %p", tty); + + if (n_hci) + return -EEXIST; + + if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { + BT_ERR("Can't allocate controll structure"); + return -ENFILE; + } + memset(n_hci, 0, sizeof(struct n_hci)); + + tty->disc_data = n_hci; + n_hci->tty = tty; + + spin_lock_init(&n_hci->rx_lock); + skb_queue_head_init(&n_hci->txq); + + /* Flush any pending characters in the driver and line discipline */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + MOD_INC_USE_COUNT; + 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 = (void *)tty->disc_data; + + BT_DBG("tty %p", tty); + + /* Detach from the tty */ + tty->disc_data = NULL; + + if (n_hci) { + struct hci_dev *hdev = &n_hci->hdev; + n_hci_close(hdev); + + if (test_and_clear_bit(N_HCI_PROTO_SET, &n_hci->flags)) { + n_hci->proto->close(n_hci); + hci_unregister_dev(hdev); + } + + 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 = (void *)tty->disc_data; + + BT_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; +} + +/* 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 = (void *)tty->disc_data; + + if (!n_hci || tty != n_hci->tty) + return; + + if (!test_bit(N_HCI_PROTO_SET, &n_hci->flags)) + return; + + spin_lock(&n_hci->rx_lock); + n_hci->proto->recv(n_hci, (void *) data, count); + n_hci->hdev.stat.byte_rx += count; + spin_unlock(&n_hci->rx_lock); + + if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) + tty->driver.unthrottle(tty); +} + +static int n_hci_register_dev(struct n_hci *n_hci) +{ + struct hci_dev *hdev; + + BT_DBG(""); + + /* 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; + hdev->destruct = n_hci_destruct; + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device %s", hdev->name); + return -ENODEV; + } + MOD_INC_USE_COUNT; + return 0; +} + +static int n_hci_set_proto(struct n_hci *n_hci, int id) +{ + struct hci_uart_proto *p; + int err; + + p = n_hci_get_proto(id); + if (!p) + return -EPROTONOSUPPORT; + + err = p->open(n_hci); + if (err) + return err; + + n_hci->proto = p; + + err = n_hci_register_dev(n_hci); + if (err) { + p->close(n_hci); + return err; + } + return 0; +} + +/* 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 = (void *)tty->disc_data; + int err = 0; + + BT_DBG(""); + + /* Verify the status of the device */ + if (!n_hci) + return -EBADF; + + switch (cmd) { + case HCIUARTSETPROTO: + if (!test_and_set_bit(N_HCI_PROTO_SET, &n_hci->flags)) { + err = n_hci_set_proto(n_hci, arg); + if (err) { + clear_bit(N_HCI_PROTO_SET, &n_hci->flags); + return err; + } + tty->low_latency = 1; + } else + return -EBUSY; + + case HCIUARTGETPROTO: + if (test_bit(N_HCI_PROTO_SET, &n_hci->flags)) + return n_hci->proto->id; + return -EUNATCH; + + default: + err = n_tty_ioctl(tty, file, cmd, arg); + break; + }; + + return err; +} + +/* + * 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; +} + +#ifdef CONFIG_BLUEZ_HCIUART_H4 +int h4_init(void); +int h4_deinit(void); +#endif + +int __init n_hci_init(void) +{ + static struct tty_ldisc n_hci_ldisc; + int err; + + BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); + BT_INFO("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))) { + BT_ERR("Can't register HCI line discipline (%d)", err); + return err; + } + +#ifdef CONFIG_BLUEZ_HCIUART_H4 + h4_init(); +#endif + + return 0; +} + +void n_hci_cleanup(void) +{ + int err; + +#ifdef CONFIG_BLUEZ_HCIUART_H4 + h4_deinit(); +#endif + + /* Release tty registration of line discipline */ + if ((err = tty_register_ldisc(N_HCI, NULL))) + BT_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.13/drivers/bluetooth/hci_uart.h linux-2.5/drivers/bluetooth/hci_uart.h --- linux-2.5.13/drivers/bluetooth/hci_uart.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/hci_uart.h Wed May 1 21:12:50 2002 @@ -0,0 +1,80 @@ +/* + 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. +*/ + +/* + * $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifndef N_HCI +#define N_HCI 15 +#endif + +/* Ioctls */ +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) + +/* UART protocols */ +#define HCI_UART_MAX_PROTO 3 + +#define HCI_UART_H4 0 +#define HCI_UART_BCSP 1 +#define HCI_UART_NCSP 2 + +#ifdef __KERNEL__ +struct n_hci; + +struct hci_uart_proto { + unsigned int id; + int (*open)(struct n_hci *n_hci); + int (*recv)(struct n_hci *n_hci, void *data, int len); + int (*send)(struct n_hci *n_hci, void *data, int len); + int (*close)(struct n_hci *n_hci); + int (*flush)(struct n_hci *n_hci); + struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb); +}; + +struct n_hci { + struct tty_struct *tty; + struct hci_dev hdev; + unsigned long flags; + + struct hci_uart_proto *proto; + void *priv; + + struct sk_buff_head txq; + unsigned long tx_state; + spinlock_t rx_lock; +}; + +/* N_HCI flag bits */ +#define N_HCI_PROTO_SET 0x00 + +/* TX states */ +#define N_HCI_SENDING 1 +#define N_HCI_TX_WAKEUP 2 + +int hci_uart_register_proto(struct hci_uart_proto *p); +int hci_uart_unregister_proto(struct hci_uart_proto *p); + +#endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/hci_usb.c linux-2.5/drivers/bluetooth/hci_usb.c --- linux-2.5.13/drivers/bluetooth/hci_usb.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/bluetooth/hci_usb.c Wed May 1 20:36:25 2002 @@ -28,570 +28,755 @@ * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * - * $Id: hci_usb.c,v 1.5 2001/07/05 18:42:44 maxk Exp $ + * $Id: hci_usb.c,v 1.6 2002/04/17 17:37:20 maxk Exp $ */ -#define VERSION "1.0" +#define VERSION "2.0" #include #include +#define __KERNEL_SYSCALLS__ + #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 "hci_usb.h" + +#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1) #ifndef HCI_USB_DEBUG -#undef DBG -#define DBG( A... ) -#undef DMP -#define DMP( A... ) +#undef BT_DBG +#define BT_DBG( A... ) +#undef BT_DMP +#define BT_DMP( A... ) #endif +#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET +#undef USB_ZERO_PACKET +#define USB_ZERO_PACKET 0 +#endif + +static struct usb_driver hci_usb_driver; + static struct usb_device_id usb_bluetooth_ids [] = { + /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, + + /* Ericsson with non-standard id */ + { USB_DEVICE(0x0bdb, 0x1002) }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids); -static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb); -static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb); +static void hci_usb_interrupt(struct urb *urb); +static void hci_usb_rx_complete(struct urb *urb); +static void hci_usb_tx_complete(struct urb *urb); -static void hci_usb_unlink_urbs(struct hci_usb *husb) +static struct urb *hci_usb_get_completed(struct hci_usb *husb) { - usb_unlink_urb(husb->read_urb); - usb_unlink_urb(husb->intr_urb); - usb_unlink_urb(husb->ctrl_urb); - usb_unlink_urb(husb->write_urb); + struct sk_buff *skb; + struct urb *urb = NULL; + + skb = skb_dequeue(&husb->completed_q); + if (skb) { + urb = ((struct hci_usb_scb *) skb->cb)->urb; + kfree_skb(skb); + } + + BT_DBG("%s urb %p", husb->hdev.name, urb); + return urb; } -static void hci_usb_free_bufs(struct hci_usb *husb) +static int hci_usb_enable_intr(struct hci_usb *husb) { - if (husb->read_urb) { - if (husb->read_urb->transfer_buffer) - kfree(husb->read_urb->transfer_buffer); - usb_free_urb(husb->read_urb); - } + struct urb *urb; + int pipe, size; + void *buf; - if (husb->intr_urb) { - if (husb->intr_urb->transfer_buffer) - kfree(husb->intr_urb->transfer_buffer); - usb_free_urb(husb->intr_urb); - } + BT_DBG("%s", husb->hdev.name); - if (husb->ctrl_urb) - usb_free_urb(husb->ctrl_urb); + if (!(urb = usb_alloc_urb(0, GFP_KERNEL))) + return -ENOMEM; - if (husb->write_urb) - usb_free_urb(husb->write_urb); + if (!(buf = kmalloc(HCI_MAX_EVENT_SIZE, GFP_KERNEL))) { + usb_free_urb(urb); + return -ENOMEM; + } - if (husb->intr_skb) - kfree_skb(husb->intr_skb); + husb->intr_urb = urb; + + pipe = usb_rcvintpipe(husb->udev, husb->intr_ep); + size = usb_maxpacket(husb->udev, pipe, usb_pipeout(pipe)); + FILL_INT_URB(urb, husb->udev, pipe, buf, size, + hci_usb_interrupt, husb, husb->intr_interval); + + return usb_submit_urb(urb, GFP_KERNEL); } -/* ------- Interface to HCI layer ------ */ -/* Initialize device */ -int hci_usb_open(struct hci_dev *hdev) +static int hci_usb_disable_intr(struct hci_usb *husb) { - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int status; - - DBG("%s", hdev->name); + struct urb *urb = husb->intr_urb; + struct sk_buff *skb; - husb->read_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->read_urb, GFP_KERNEL))) - DBG("read submit failed. %d", status); + BT_DBG("%s", husb->hdev.name); - husb->intr_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->intr_urb, GFP_KERNEL))) - DBG("interrupt submit failed. %d", status); + usb_unlink_urb(urb); usb_free_urb(urb); + husb->intr_urb = NULL; - hdev->flags |= HCI_RUNNING; + skb = husb->intr_skb; + if (skb) { + husb->intr_skb = NULL; + kfree_skb(skb); + } return 0; } -/* Reset device */ -int hci_usb_flush(struct hci_dev *hdev) +static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb) { - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + struct hci_usb_scb *scb; + struct sk_buff *skb; + int pipe, size, err; - DBG("%s", hdev->name); + if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) + return -ENOMEM; - /* Drop TX queues */ - skb_queue_purge(&husb->tx_ctrl_q); - skb_queue_purge(&husb->tx_write_q); + size = HCI_MAX_FRAME_SIZE; - return 0; + if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) { + usb_free_urb(urb); + return -ENOMEM; + } + + BT_DBG("%s urb %p", husb->hdev.name, urb); + + skb->dev = (void *) &husb->hdev; + skb->pkt_type = HCI_ACLDATA_PKT; + + scb = (struct hci_usb_scb *) skb->cb; + scb->urb = urb; + + pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep); + + FILL_BULK_URB(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb); + urb->transfer_flags = USB_QUEUE_BULK; + + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s bulk rx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); + } + return err; } -/* Close device */ -int hci_usb_close(struct hci_dev *hdev) +/* Initialize device */ +static int hci_usb_open(struct hci_dev *hdev) { struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + int i, err; + long flags; - DBG("%s", hdev->name); + BT_DBG("%s", hdev->name); - hdev->flags &= ~HCI_RUNNING; - hci_usb_unlink_urbs(husb); + if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) + return 0; - hci_usb_flush(hdev); + write_lock_irqsave(&husb->completion_lock, flags); - return 0; + err = hci_usb_enable_intr(husb); + if (!err) { + for (i = 0; i < HCI_MAX_BULK_TX; i++) + hci_usb_rx_submit(husb, NULL); + } else + clear_bit(HCI_RUNNING, &hdev->flags); + + write_unlock_irqrestore(&husb->completion_lock, flags); + return err; } -void hci_usb_ctrl_wakeup(struct hci_usb *husb) +/* Reset device */ +static int hci_usb_flush(struct hci_dev *hdev) { - struct sk_buff *skb; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state)) - return; + BT_DBG("%s", hdev->name); - DBG("%s", husb->hdev.name); + skb_queue_purge(&husb->cmd_q); + skb_queue_purge(&husb->acl_q); + return 0; +} - if (!(skb = skb_dequeue(&husb->tx_ctrl_q))) - goto done; +static inline void hci_usb_unlink_urbs(struct hci_usb *husb) +{ + struct sk_buff *skb; + struct urb *urb; - if (hci_usb_ctrl_msg(husb, skb)){ + BT_DBG("%s", husb->hdev.name); + + while ((skb = skb_dequeue(&husb->pending_q))) { + urb = ((struct hci_usb_scb *) skb->cb)->urb; + usb_unlink_urb(urb); kfree_skb(skb); - goto done; } - DMP(skb->data, skb->len); + while ((urb = hci_usb_get_completed(husb))) + usb_free_urb(urb); +} - husb->hdev.stat.byte_tx += skb->len; - return; +/* Close device */ +static int hci_usb_close(struct hci_dev *hdev) +{ + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + long flags; + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; -done: - clear_bit(HCI_TX_CTRL, &husb->tx_state); - return; + BT_DBG("%s", hdev->name); + + write_lock_irqsave(&husb->completion_lock, flags); + + hci_usb_disable_intr(husb); + hci_usb_unlink_urbs(husb); + hci_usb_flush(hdev); + + write_unlock_irqrestore(&husb->completion_lock, flags); + return 0; } -void hci_usb_write_wakeup(struct hci_usb *husb) +static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) { - struct sk_buff *skb; + struct hci_usb_scb *scb = (void *) skb->cb; + struct urb *urb = hci_usb_get_completed(husb); + struct usb_ctrlrequest *cr; + int pipe, err; - if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state)) - return; + if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) + return -ENOMEM; - DBG("%s", husb->hdev.name); + if (!(cr = kmalloc(sizeof(*cr), GFP_ATOMIC))) { + usb_free_urb(urb); + return -ENOMEM; + } + + pipe = usb_sndctrlpipe(husb->udev, 0); - if (!(skb = skb_dequeue(&husb->tx_write_q))) - goto done; + cr->bRequestType = HCI_CTRL_REQ; + cr->bRequest = 0; + cr->wIndex = 0; + cr->wValue = 0; + cr->wLength = __cpu_to_le16(skb->len); - if (hci_usb_write_msg(husb, skb)) { - skb_queue_head(&husb->tx_write_q, skb); - goto done; - } + FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) cr, + skb->data, skb->len, hci_usb_tx_complete, skb); - DMP(skb->data, skb->len); + BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); - husb->hdev.stat.byte_tx += skb->len; - return; + scb->urb = urb; -done: - clear_bit(HCI_TX_WRITE, &husb->tx_state); - return; + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s ctrl tx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); kfree(cr); + } + return err; } -/* Send frames from HCI layer */ -int hci_usb_send_frame(struct sk_buff *skb) +static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) { - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct hci_usb *husb; - - if (!hdev) { - ERR("frame for uknown device (hdev=NULL)"); - return -ENODEV; - } + struct hci_usb_scb *scb = (void *) skb->cb; + struct urb *urb = hci_usb_get_completed(husb); + int pipe, err; - if (!(hdev->flags & HCI_RUNNING)) - return 0; + if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) + return -ENOMEM; - husb = (struct hci_usb *) hdev->driver_data; + pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep); + + FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, + hci_usb_tx_complete, skb); + urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET; - DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); + BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); - switch (skb->pkt_type) { - case HCI_COMMAND_PKT: - skb_queue_tail(&husb->tx_ctrl_q, skb); - hci_usb_ctrl_wakeup(husb); - hdev->stat.cmd_tx++; - return 0; - - case HCI_ACLDATA_PKT: - skb_queue_tail(&husb->tx_write_q, skb); - hci_usb_write_wakeup(husb); - hdev->stat.acl_tx++; - return 0; - - case HCI_SCODATA_PKT: - return -EOPNOTSUPP; - }; + scb->urb = urb; - return 0; + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s bulk tx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); + } + return err; } -/* ---------- USB ------------- */ - -static void hci_usb_ctrl(struct urb *urb) +static void hci_usb_tx_process(struct hci_usb *husb) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev; - struct hci_usb *husb; - - if (!skb) - return; - hdev = (struct hci_dev *) skb->dev; - husb = (struct hci_usb *) hdev->driver_data; + struct sk_buff *skb; - DBG("%s", hdev->name); + BT_DBG("%s", husb->hdev.name); - if (urb->status) - DBG("%s ctrl status: %d", hdev->name, urb->status); + do { + clear_bit(HCI_USB_TX_WAKEUP, &husb->state); + + /* Process ACL queue */ + while (skb_queue_len(&husb->pending_q) < HCI_MAX_PENDING && + (skb = skb_dequeue(&husb->acl_q))) { + if (hci_usb_send_bulk(husb, skb) < 0) { + skb_queue_head(&husb->acl_q, skb); + break; + } + } - clear_bit(HCI_TX_CTRL, &husb->tx_state); - kfree_skb(skb); + /* Process command queue */ + if (!test_bit(HCI_USB_CTRL_TX, &husb->state) && + (skb = skb_dequeue(&husb->cmd_q)) != NULL) { + set_bit(HCI_USB_CTRL_TX, &husb->state); + if (hci_usb_send_ctrl(husb, skb) < 0) { + skb_queue_head(&husb->cmd_q, skb); + clear_bit(HCI_USB_CTRL_TX, &husb->state); + } + } + } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); +} - /* Wake up device */ - hci_usb_ctrl_wakeup(husb); +static inline void hci_usb_tx_wakeup(struct hci_usb *husb) +{ + /* Serialize TX queue processing to avoid data reordering */ + if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) { + hci_usb_tx_process(husb); + clear_bit(HCI_USB_TX_PROCESS, &husb->state); + } else + set_bit(HCI_USB_TX_WAKEUP, &husb->state); } -static void hci_usb_bulk_write(struct urb *urb) +/* Send frames from HCI layer */ +int hci_usb_send_frame(struct sk_buff *skb) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct hci_usb *husb; - if (!skb) - return; - hdev = (struct hci_dev *) skb->dev; + if (!hdev) { + BT_ERR("frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + husb = (struct hci_usb *) hdev->driver_data; - DBG("%s", hdev->name); + BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - if (urb->status) - DBG("%s bulk write status: %d", hdev->name, urb->status); + read_lock(&husb->completion_lock); - clear_bit(HCI_TX_WRITE, &husb->tx_state); - kfree_skb(skb); + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + skb_queue_tail(&husb->cmd_q, skb); + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + skb_queue_tail(&husb->acl_q, skb); + hdev->stat.acl_tx++; + break; - /* Wake up device */ - hci_usb_write_wakeup(husb); + case HCI_SCODATA_PKT: + default: + kfree_skb(skb); + break; + } + hci_usb_tx_wakeup(husb); - return; + read_unlock(&husb->completion_lock); + return 0; } -static void hci_usb_intr(struct urb *urb) +static void hci_usb_interrupt(struct urb *urb) { - struct hci_usb *husb = (struct hci_usb *) urb->context; - unsigned char *data = urb->transfer_buffer; - register int count = urb->actual_length; - register struct sk_buff *skb = husb->intr_skb; + struct hci_usb *husb = (void *) urb->context; + struct hci_usb_scb *scb; + struct sk_buff *skb; hci_event_hdr *eh; - register int len; + __u8 *data = urb->transfer_buffer; + int count = urb->actual_length; + int len = HCI_EVENT_HDR_SIZE; - if (!husb) - return; + BT_DBG("%s urb %p count %d", husb->hdev.name, urb, count); - DBG("%s count %d", husb->hdev.name, count); + if (!test_bit(HCI_RUNNING, &husb->hdev.flags)) + return; if (urb->status || !count) { - DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count); + BT_DBG("%s intr status %d, count %d", + husb->hdev.name, urb->status, count); return; } - /* Do we really have to handle continuations here ? */ - if (!skb) { - /* New frame */ - if (count < HCI_EVENT_HDR_SIZE) { - DBG("%s bad frame len %d", husb->hdev.name, count); - return; - } + read_lock(&husb->completion_lock); + + husb->hdev.stat.byte_rx += count; + + if (!(skb = husb->intr_skb)) { + /* Start of the frame */ + if (count < HCI_EVENT_HDR_SIZE) + goto bad_len; - eh = (hci_event_hdr *) data; + eh = (hci_event_hdr *) data; len = eh->plen + HCI_EVENT_HDR_SIZE; - if (count > len) { - DBG("%s corrupted frame, len %d", husb->hdev.name, count); - return; - } + if (count > len) + goto bad_len; - /* Allocate skb */ - if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) { - ERR("Can't allocate mem for new packet"); - return; + skb = bluez_skb_alloc(len, GFP_ATOMIC); + if (!skb) { + BT_ERR("%s no memory for event packet", husb->hdev.name); + goto done; } + scb = (void *) skb->cb; + skb->dev = (void *) &husb->hdev; skb->pkt_type = HCI_EVENT_PKT; husb->intr_skb = skb; - husb->intr_count = len; + scb->intr_len = len; } else { /* Continuation */ - if (count > husb->intr_count) { - ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count); - - kfree_skb(skb); + scb = (void *) skb->cb; + len = scb->intr_len; + if (count > len) { husb->intr_skb = NULL; - husb->intr_count = 0; - return; + kfree_skb(skb); + goto bad_len; } } memcpy(skb_put(skb, count), data, count); - husb->intr_count -= count; + scb->intr_len -= count; - DMP(data, count); + if (!scb->intr_len) { + /* Complete frame */ + husb->intr_skb = NULL; + hci_recv_frame(skb); + } - if (!husb->intr_count) { - /* Got complete frame */ +done: + read_unlock(&husb->completion_lock); + return; - husb->hdev.stat.byte_rx += skb->len; - hci_recv_frame(skb); +bad_len: + BT_ERR("%s bad frame len %d expected %d", husb->hdev.name, count, len); + husb->hdev.stat.err_rx++; + read_unlock(&husb->completion_lock); +} - husb->intr_skb = NULL; +static void hci_usb_tx_complete(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + + BT_DBG("%s urb %p status %d flags %x", husb->hdev.name, urb, + urb->status, urb->transfer_flags); + + if (urb->pipe == usb_sndctrlpipe(husb->udev, 0)) { + kfree(urb->setup_packet); + clear_bit(HCI_USB_CTRL_TX, &husb->state); } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return; + + read_lock(&husb->completion_lock); + + if (!urb->status) + husb->hdev.stat.byte_tx += skb->len; + else + husb->hdev.stat.err_tx++; + + skb_unlink(skb); + skb_queue_tail(&husb->completed_q, skb); + hci_usb_tx_wakeup(husb); + + read_unlock(&husb->completion_lock); + return; } -static void hci_usb_bulk_read(struct urb *urb) +static void hci_usb_rx_complete(struct urb *urb) { - struct hci_usb *husb = (struct hci_usb *) urb->context; - unsigned char *data = urb->transfer_buffer; - int count = urb->actual_length, status; - struct sk_buff *skb; + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + int status, count = urb->actual_length; hci_acl_hdr *ah; - register __u16 dlen; + int dlen, size; - if (!husb) + BT_DBG("%s urb %p status %d count %d flags %x", husb->hdev.name, urb, + urb->status, count, urb->transfer_flags); + + if (!test_bit(HCI_RUNNING, &hdev->flags)) return; - DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags); + read_lock(&husb->completion_lock); - if (urb->status) { - /* Do not re-submit URB on critical errors */ - switch (urb->status) { - case -ENOENT: - return; - default: - goto resubmit; - }; - } - if (!count) + if (urb->status || !count) goto resubmit; - DMP(data, count); + husb->hdev.stat.byte_rx += count; - ah = (hci_acl_hdr *) data; - dlen = le16_to_cpu(ah->dlen); + ah = (hci_acl_hdr *) skb->data; + dlen = __le16_to_cpu(ah->dlen); + size = HCI_ACL_HDR_SIZE + dlen; /* Verify frame len and completeness */ - if ((count - HCI_ACL_HDR_SIZE) != dlen) { - ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen); - goto resubmit; - } - - /* Allocate packet */ - if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) { - ERR("Can't allocate mem for new packet"); + if (count != size) { + BT_ERR("%s corrupted ACL packet: count %d, dlen %d", + husb->hdev.name, count, dlen); + bluez_dump("hci_usb", skb->data, count); + husb->hdev.stat.err_rx++; goto resubmit; } - memcpy(skb_put(skb, count), data, count); - skb->dev = (void *) &husb->hdev; - skb->pkt_type = HCI_ACLDATA_PKT; - - husb->hdev.stat.byte_rx += skb->len; - + skb_unlink(skb); + skb_put(skb, count); hci_recv_frame(skb); -resubmit: - husb->read_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->read_urb, GFP_KERNEL))) - DBG("%s read URB submit failed %d", husb->hdev.name, status); + hci_usb_rx_submit(husb, urb); - DBG("%s read URB re-submited", husb->hdev.name); + read_unlock(&husb->completion_lock); + return; + +resubmit: + urb->dev = husb->udev; + status = usb_submit_urb(urb, GFP_ATOMIC); + BT_DBG("%s URB resubmit status %d", husb->hdev.name, status); + read_unlock(&husb->completion_lock); } -static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb) +static void hci_usb_destruct(struct hci_dev *hdev) { - struct urb *urb = husb->ctrl_urb; - struct usb_ctrlrequest *dr = &husb->dev_req; - int pipe, status; + struct hci_usb *husb; - DBG("%s len %d", husb->hdev.name, skb->len); + if (!hdev) return; - pipe = usb_sndctrlpipe(husb->udev, 0); + BT_DBG("%s", hdev->name); - dr->bRequestType = HCI_CTRL_REQ; - dr->bRequest = 0; - dr->wIndex = 0; - dr->wValue = 0; - dr->wLength = cpu_to_le16(skb->len); - - FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len, - hci_usb_ctrl, skb); - - if ((status = usb_submit_urb(urb, GFP_KERNEL))) { - DBG("%s control URB submit failed %d", husb->hdev.name, status); - return status; - } + husb = (struct hci_usb *) hdev->driver_data; + kfree(husb); - return 0; + MOD_DEC_USE_COUNT; } -static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb) +#ifdef CONFIG_BLUEZ_USB_FW_LOAD + +/* Support for user mode Bluetooth USB firmware loader */ + +#define FW_LOADER "/sbin/bluefw" +static int errno; + +static int hci_usb_fw_exec(void *dev) { - struct urb *urb = husb->write_urb; - int pipe, status; + char *envp[] = { "HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + char *argv[] = { FW_LOADER, dev, NULL }; + int err; - DBG("%s len %d", husb->hdev.name, skb->len); + err = exec_usermodehelper(FW_LOADER, argv, envp); + if (err) + BT_ERR("failed to exec %s %s", FW_LOADER, (char *)dev); + return err; +} - pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr); +static int hci_usb_fw_load(struct usb_device *udev) +{ + sigset_t tmpsig; + char dev[16]; + pid_t pid; + int result; - FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, - hci_usb_bulk_write, skb); - urb->transfer_flags |= USB_QUEUE_BULK; + /* Check if root fs is mounted */ + if (!current->fs->root) { + BT_ERR("root fs not mounted"); + return -EPERM; + } - if ((status = usb_submit_urb(urb, GFP_KERNEL))) { - DBG("%s write URB submit failed %d", husb->hdev.name, status); - return status; + sprintf(dev, "%3.3d/%3.3d", udev->bus->busnum, udev->devnum); + + pid = kernel_thread(hci_usb_fw_exec, (void *)dev, 0); + if (pid < 0) { + BT_ERR("fork failed, errno %d\n", -pid); + return pid; } + /* Block signals, everything but SIGKILL/SIGSTOP */ + spin_lock_irq(¤t->sigmask_lock); + tmpsig = current->blocked; + siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); + recalc_sigpending(); + spin_unlock_irq(¤t->sigmask_lock); + + result = waitpid(pid, NULL, __WCLONE); + + /* Allow signals again */ + spin_lock_irq(¤t->sigmask_lock); + current->blocked = tmpsig; + recalc_sigpending(); + spin_unlock_irq(¤t->sigmask_lock); + + if (result != pid) { + BT_ERR("waitpid failed pid %d errno %d\n", pid, -result); + return -result; + } return 0; } +#endif /* CONFIG_BLUEZ_USB_FW_LOAD */ + static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) { - struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep; + struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM]; struct usb_interface_descriptor *uif; struct usb_endpoint_descriptor *ep; + struct usb_interface *iface, *isoc_iface; struct hci_usb *husb; struct hci_dev *hdev; - int i, size, pipe; - __u8 * buf; + int i, a, e, size, ifn, isoc_ifnum, isoc_alts; - DBG("udev %p ifnum %d", udev, ifnum); + BT_DBG("udev %p ifnum %d", udev, ifnum); - /* Check device signature */ - if ((udev->descriptor.bDeviceClass != HCI_DEV_CLASS) || - (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)|| - (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) ) + /* Check number of endpoints */ + if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3) return NULL; MOD_INC_USE_COUNT; - uif = &udev->actconfig->interface[ifnum].altsetting[0]; - - if (uif->bNumEndpoints != 3) { - DBG("Wrong number of endpoints %d", uif->bNumEndpoints); - MOD_DEC_USE_COUNT; - return NULL; - } - - bulk_out_ep = intr_in_ep = bulk_in_ep = NULL; +#ifdef CONFIG_BLUEZ_USB_FW_LOAD + hci_usb_fw_load(udev); +#endif + memset(bulk_out_ep, 0, sizeof(bulk_out_ep)); + memset(isoc_out_ep, 0, sizeof(isoc_out_ep)); + memset(bulk_in_ep, 0, sizeof(bulk_in_ep)); + memset(isoc_in_ep, 0, sizeof(isoc_in_ep)); + memset(intr_in_ep, 0, sizeof(intr_in_ep)); + + size = 0; + isoc_iface = NULL; + isoc_alts = isoc_ifnum = 0; + /* Find endpoints that we need */ - for ( i = 0; i < uif->bNumEndpoints; ++i) { - ep = &uif->endpoint[i]; - switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - if (ep->bEndpointAddress & USB_DIR_IN) - bulk_in_ep = ep; - else - bulk_out_ep = ep; - break; + ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM); + for (i = 0; i < ifn; i++) { + iface = &udev->actconfig->interface[i]; + for (a = 0; a < iface->num_altsetting; a++) { + uif = &iface->altsetting[a]; + for (e = 0; e < uif->bNumEndpoints; e++) { + ep = &uif->endpoint[e]; + + switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_INT: + if (ep->bEndpointAddress & USB_DIR_IN) + intr_in_ep[i] = ep; + break; + + case USB_ENDPOINT_XFER_BULK: + if (ep->bEndpointAddress & USB_DIR_IN) + bulk_in_ep[i] = ep; + else + bulk_out_ep[i] = ep; + break; + + case USB_ENDPOINT_XFER_ISOC: + if (ep->wMaxPacketSize < size) + break; + size = ep->wMaxPacketSize; + + isoc_iface = iface; + isoc_alts = a; + isoc_ifnum = i; + + if (ep->bEndpointAddress & USB_DIR_IN) + isoc_in_ep[i] = ep; + else + isoc_out_ep[i] = ep; + break; + } + } + } + } - case USB_ENDPOINT_XFER_INT: - intr_in_ep = ep; - break; - }; + if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) { + BT_DBG("Bulk endpoints not found"); + goto done; } - if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) { - DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep); - MOD_DEC_USE_COUNT; - return NULL; + if (!isoc_in_ep[1] || !isoc_out_ep[1]) { + BT_DBG("Isoc endpoints not found"); + isoc_iface = NULL; } if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { - ERR("Can't allocate: control structure"); - MOD_DEC_USE_COUNT; - return NULL; + BT_ERR("Can't allocate: control structure"); + goto done; } memset(husb, 0, sizeof(struct hci_usb)); husb->udev = udev; - husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress; - - if (!(husb->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL))) { - ERR("Can't allocate: control URB"); - goto probe_error; - } - - if (!(husb->write_urb = usb_alloc_urb(0, GFP_KERNEL))) { - ERR("Can't allocate: write URB"); - goto probe_error; - } - - if (!(husb->read_urb = usb_alloc_urb(0, GFP_KERNEL))) { - ERR("Can't allocate: read URB"); - goto probe_error; - } - - ep = bulk_in_ep; - pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress); - size = HCI_MAX_FRAME_SIZE; - - if (!(buf = kmalloc(size, GFP_KERNEL))) { - ERR("Can't allocate: read buffer"); - goto probe_error; - } - - FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb); - husb->read_urb->transfer_flags |= USB_QUEUE_BULK; + husb->bulk_out_ep = bulk_out_ep[0]->bEndpointAddress; + husb->bulk_in_ep = bulk_in_ep[0]->bEndpointAddress; - ep = intr_in_ep; - pipe = usb_rcvintpipe(udev, ep->bEndpointAddress); - size = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + husb->intr_ep = intr_in_ep[0]->bEndpointAddress; + husb->intr_interval = intr_in_ep[0]->bInterval; - if (!(husb->intr_urb = usb_alloc_urb(0, GFP_KERNEL))) { - ERR("Can't allocate: interrupt URB"); - goto probe_error; - } + if (isoc_iface) { + if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { + BT_ERR("Can't set isoc interface settings"); + isoc_iface = NULL; + } + usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb); + husb->isoc_iface = isoc_iface; - if (!(buf = kmalloc(size, GFP_KERNEL))) { - ERR("Can't allocate: interrupt buffer"); - goto probe_error; + husb->isoc_in_ep = isoc_in_ep[1]->bEndpointAddress; + husb->isoc_out_ep = isoc_in_ep[1]->bEndpointAddress; } - FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval); - - skb_queue_head_init(&husb->tx_ctrl_q); - skb_queue_head_init(&husb->tx_write_q); + husb->completion_lock = RW_LOCK_UNLOCKED; + + skb_queue_head_init(&husb->acl_q); + skb_queue_head_init(&husb->cmd_q); + skb_queue_head_init(&husb->pending_q); + skb_queue_head_init(&husb->completed_q); /* Initialize and register HCI device */ hdev = &husb->hdev; @@ -602,18 +787,20 @@ hdev->open = hci_usb_open; hdev->close = hci_usb_close; hdev->flush = hci_usb_flush; - hdev->send = hci_usb_send_frame; + hdev->send = hci_usb_send_frame; + hdev->destruct = hci_usb_destruct; if (hci_register_dev(hdev) < 0) { - ERR("Can't register HCI device %s", hdev->name); + BT_ERR("Can't register HCI device"); goto probe_error; } return husb; probe_error: - hci_usb_free_bufs(husb); kfree(husb); + +done: MOD_DEC_USE_COUNT; return NULL; } @@ -626,22 +813,18 @@ if (!husb) return; - DBG("%s", hdev->name); + BT_DBG("%s", hdev->name); hci_usb_close(hdev); - if (hci_unregister_dev(hdev) < 0) { - ERR("Can't unregister HCI device %s", hdev->name); - } + if (husb->isoc_iface) + usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); - hci_usb_free_bufs(husb); - kfree(husb); - - MOD_DEC_USE_COUNT; + if (hci_unregister_dev(hdev) < 0) + BT_ERR("Can't unregister HCI device %s", hdev->name); } -static struct usb_driver hci_usb_driver = -{ +static struct usb_driver hci_usb_driver = { name: "hci_usb", probe: hci_usb_probe, disconnect: hci_usb_disconnect, @@ -652,12 +835,12 @@ { int err; - INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); - INF("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); if ((err = usb_register(&hci_usb_driver)) < 0) - ERR("Failed to register HCI USB driver"); + BT_ERR("Failed to register HCI USB driver"); return err; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/hci_usb.h linux-2.5/drivers/bluetooth/hci_usb.h --- linux-2.5.13/drivers/bluetooth/hci_usb.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/hci_usb.h Wed May 1 21:12:50 2002 @@ -0,0 +1,79 @@ +/* + 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. +*/ + +/* + * $Id: hci_usb.h,v 1.2 2002/03/18 19:10:04 maxk Exp $ + */ + +#ifdef __KERNEL__ + +/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ +#define HCI_DEV_CLASS 0xe0 /* Wireless class */ +#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ +#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ + +#define HCI_CTRL_REQ 0x20 + +#define HCI_MAX_IFACE_NUM 3 + +#define HCI_MAX_BULK_TX 4 +#define HCI_MAX_BULK_RX 1 + +struct hci_usb { + struct hci_dev hdev; + + unsigned long state; + + struct usb_device *udev; + struct usb_interface *isoc_iface; + + __u8 bulk_out_ep; + __u8 bulk_in_ep; + __u8 isoc_out_ep; + __u8 isoc_in_ep; + + __u8 intr_ep; + __u8 intr_interval; + struct urb * intr_urb; + struct sk_buff * intr_skb; + + rwlock_t completion_lock; + + struct sk_buff_head cmd_q; // TX Commands + struct sk_buff_head acl_q; // TX ACLs + struct sk_buff_head pending_q; // Pending requests + struct sk_buff_head completed_q; // Completed requests +}; + +struct hci_usb_scb { + struct urb *urb; + int intr_len; +}; + +/* States */ +#define HCI_USB_TX_PROCESS 1 +#define HCI_USB_TX_WAKEUP 2 +#define HCI_USB_CTRL_TX 3 + +#endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/hci_vhci.c linux-2.5/drivers/bluetooth/hci_vhci.c --- linux-2.5.13/drivers/bluetooth/hci_vhci.c Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/bluetooth/hci_vhci.c Wed May 1 20:36:25 2002 @@ -25,9 +25,9 @@ /* * BlueZ HCI virtual device driver. * - * $Id: hci_vhci.c,v 1.3 2001/08/03 04:19:50 maxk Exp $ + * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $ */ -#define VERSION "1.0" +#define VERSION "1.1" #include #include @@ -49,43 +49,56 @@ #include #include -#include #include -#include +#include "hci_vhci.h" /* HCI device part */ -int hci_vhci_open(struct hci_dev *hdev) +static int hci_vhci_open(struct hci_dev *hdev) { - hdev->flags |= HCI_RUNNING; + set_bit(HCI_RUNNING, &hdev->flags); return 0; } -int hci_vhci_flush(struct hci_dev *hdev) +static int hci_vhci_flush(struct hci_dev *hdev) { struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; skb_queue_purge(&hci_vhci->readq); return 0; } -int hci_vhci_close(struct hci_dev *hdev) +static int hci_vhci_close(struct hci_dev *hdev) { - hdev->flags &= ~HCI_RUNNING; + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; + hci_vhci_flush(hdev); return 0; } -int hci_vhci_send_frame(struct sk_buff *skb) +static void hci_vhci_destruct(struct hci_dev *hdev) +{ + struct hci_vhci_struct *vhci; + + if (!hdev) return; + + vhci = (struct hci_vhci_struct *) hdev->driver_data; + kfree(vhci); + + MOD_DEC_USE_COUNT; +} + +static int hci_vhci_send_frame(struct sk_buff *skb) { struct hci_dev* hdev = (struct hci_dev *) skb->dev; struct hci_vhci_struct *hci_vhci; if (!hdev) { - ERR("Frame for uknown device (hdev=NULL)"); + BT_ERR("Frame for uknown device (hdev=NULL)"); return -ENODEV; } - if (!(hdev->flags & HCI_RUNNING)) + if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; @@ -188,7 +201,7 @@ add_wait_queue(&hci_vhci->read_wait, &wait); while (count) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); /* Read frames from device queue */ if (!(skb = skb_dequeue(&hci_vhci->readq))) { @@ -214,13 +227,17 @@ kfree_skb(skb); break; } - - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&hci_vhci->read_wait, &wait); return ret; } +static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin) +{ + return -ESPIPE; +} + static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { return -EINVAL; @@ -265,11 +282,13 @@ hdev->close = hci_vhci_close; hdev->flush = hci_vhci_flush; hdev->send = hci_vhci_send_frame; + hdev->destruct = hci_vhci_destruct; if (hci_register_dev(hdev) < 0) { kfree(hci_vhci); return -EBUSY; } + MOD_INC_USE_COUNT; file->private_data = hci_vhci; return 0; @@ -280,18 +299,16 @@ struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; if (hci_unregister_dev(&hci_vhci->hdev) < 0) { - ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); + BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); } - kfree(hci_vhci); file->private_data = NULL; - return 0; } static struct file_operations hci_vhci_fops = { owner: THIS_MODULE, - llseek: no_llseek, + llseek: hci_vhci_chr_lseek, read: hci_vhci_chr_read, write: hci_vhci_chr_write, poll: hci_vhci_chr_poll, @@ -310,12 +327,12 @@ int __init hci_vhci_init(void) { - INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); - INF("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); if (misc_register(&hci_vhci_miscdev)) { - ERR("Can't register misc device %d\n", VHCI_MINOR); + BT_ERR("Can't register misc device %d\n", VHCI_MINOR); return -EIO; } @@ -332,4 +349,4 @@ MODULE_AUTHOR("Maxim Krasnyansky "); MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/bluetooth/hci_vhci.h linux-2.5/drivers/bluetooth/hci_vhci.h --- linux-2.5.13/drivers/bluetooth/hci_vhci.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/hci_vhci.h Wed May 1 21:12:50 2002 @@ -0,0 +1,50 @@ +/* + 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. +*/ + +/* + * $Id: hci_vhci.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifndef __HCI_VHCI_H +#define __HCI_VHCI_H + +#ifdef __KERNEL__ + +struct hci_vhci_struct { + struct hci_dev hdev; + __u32 flags; + wait_queue_head_t read_wait; + struct sk_buff_head readq; + struct fasync_struct *fasync; +}; + +/* VHCI device flags */ +#define VHCI_FASYNC 0x0010 + +#endif /* __KERNEL__ */ + +#define VHCI_DEV "/dev/vhci" +#define VHCI_MINOR 250 + +#endif /* __HCI_VHCI_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/cdrom/cdrom.c linux-2.5/drivers/cdrom/cdrom.c --- linux-2.5.13/drivers/cdrom/cdrom.c Fri May 3 01:22:43 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.13/drivers/cdrom/cdu31a.c linux-2.5/drivers/cdrom/cdu31a.c --- linux-2.5.13/drivers/cdrom/cdu31a.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/cdrom/cdu31a.c Fri May 3 12:57:30 2002 @@ -3370,7 +3370,8 @@ if (drive_found) { int deficiency = 0; - request_region(cdu31a_port, 4, "cdu31a"); + if (!request_region(cdu31a_port, 4, "cdu31a")) + goto errout3; if (devfs_register_blkdev(MAJOR_NR, "cdu31a", &scd_bdops)) { printk("Unable to get major %d for CDU-31a\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/cdrom/sbpcd.c linux-2.5/drivers/cdrom/sbpcd.c --- linux-2.5.13/drivers/cdrom/sbpcd.c Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/cdrom/sbpcd.c Fri May 3 12:57:30 2002 @@ -348,6 +348,12 @@ */ #define DONT_MERGE_REQUESTS +/* + * 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 + */ + #ifndef SBPCD_ISSUE #define SBPCD_ISSUE 1 #endif /* SBPCD_ISSUE */ @@ -490,6 +496,8 @@ #define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) +static spinlock_t sbpcd_lock = SPIN_LOCK_UNLOCKED; + /*==========================================================================*/ /* * the external references: @@ -4880,7 +4888,6 @@ */ #undef DEBUG_GTL static inline void sbpcd_end_request(struct request *req, int uptodate) { - list_add(&req->queue, &req->q->queue_head); end_request(uptodate); } /*==========================================================================*/ @@ -4916,8 +4923,7 @@ xnr, CURRENT, CURRENT->sector, CURRENT->nr_sectors, current->pid, jiffies); #endif INIT_REQUEST; - req=CURRENT; /* take out our request so no other */ - blkdev_dequeue_request(req); /* task can fuck it up GTL */ + req=CURRENT; if (req->rq_status == RQ_INACTIVE) sbpcd_end_request(req, 0); @@ -4926,9 +4932,9 @@ 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); @@ -5679,13 +5685,13 @@ #ifdef DONT_MERGE_REQUESTS static int dont_merge_requests_fn(request_queue_t *q, struct request *req, - struct request *next, int max_segments) + struct request *next) { return 0; } static int dont_bh_merge_fn(request_queue_t *q, struct request *req, - struct buffer_head *bh, int max_segments) + struct bio *bio) { return 0; } @@ -5839,6 +5845,12 @@ 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. * The addresses are obtained from SOUND_BASE (see sbpcd.h). @@ -5865,8 +5877,7 @@ #endif read_ahead[MAJOR_NR] = buffers * (CD_FRAMESIZE / 512); - request_region(CDo_command,4,major_name); - + devfs_handle = devfs_mk_dir (NULL, "sbp", NULL); for (j=0;jdev = MKDEV(MAJOR_NR, j); + sbpcd_infop->dev = mk_kdev(MAJOR_NR, j); strncpy(sbpcd_infop->name,major_name, sizeof(sbpcd_infop->name)); sprintf (nbuff, "c%dt%d/cd", SBPCD_ISSUE - 1, D_S[j].drv_id); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/cdrom/sonycd535.c linux-2.5/drivers/cdrom/sonycd535.c --- linux-2.5.13/drivers/cdrom/sonycd535.c Fri May 3 01:22:48 2002 +++ linux-2.5/drivers/cdrom/sonycd535.c Fri May 3 12:57:30 2002 @@ -1485,6 +1485,7 @@ int got_result = 0; int tmp_irq; int i; + devfs_handle_t sony_devfs_handle; /* Setting the base I/O address to 0 will disable it. */ if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0)) @@ -1508,11 +1509,6 @@ printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n", sony535_cd_base_io); #endif - if (check_region(sony535_cd_base_io,4)) { - printk(CDU535_MESSAGE_NAME ": my base address is not free!\n"); - return -EIO; - } - /* look for the CD-ROM, follows the procedure in the DOS driver */ inb(select_unit_reg); /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ @@ -1585,14 +1581,15 @@ printk("IRQ%d, ", tmp_irq); printk("using %d byte buffer\n", sony_buffer_size); - devfs_register (NULL, CDU535_HANDLE, - DEVFS_FL_DEFAULT, - MAJOR_NR, 0, - S_IFBLK | S_IRUGO | S_IWUGO, - &cdu_fops, NULL); + sony_devfs_handle = devfs_register (NULL, CDU535_HANDLE, + DEVFS_FL_DEFAULT, + MAJOR_NR, 0, + S_IFBLK | S_IRUGO | S_IWUGO, + &cdu_fops, NULL); if (devfs_register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) { printk("Unable to get major %d for %s\n", MAJOR_NR, CDU535_MESSAGE_NAME); + devfs_unregister(sony_devfs_handle); return -EIO; } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), @@ -1603,6 +1600,8 @@ kmalloc(sizeof *sony_toc, GFP_KERNEL); if (sony_toc == NULL) { blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE); + devfs_unregister(sony_devfs_handle); return -ENOMEM; } last_sony_subcode = (struct s535_sony_subcode *) @@ -1610,6 +1609,8 @@ if (last_sony_subcode == NULL) { blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); kfree(sony_toc); + devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE); + devfs_unregister(sony_devfs_handle); return -ENOMEM; } sony_buffer = (Byte **) @@ -1618,6 +1619,8 @@ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); kfree(sony_toc); kfree(last_sony_subcode); + devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE); + devfs_unregister(sony_devfs_handle); return -ENOMEM; } for (i = 0; i < sony_buffer_sectors; i++) { @@ -1630,6 +1633,8 @@ kfree(sony_buffer); kfree(sony_toc); kfree(last_sony_subcode); + devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE); + devfs_unregister(sony_devfs_handle); return -ENOMEM; } } @@ -1642,7 +1647,22 @@ printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); return -EIO; } - request_region(sony535_cd_base_io, 4, CDU535_HANDLE); + if (request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) { + printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n", + sony535_cd_base_io); + for (i = 0; i < sony_buffer_sectors; i++) + if (sony_buffer[i]) + kfree(sony_buffer[i]); + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + kfree(sony_buffer); + kfree(sony_toc); + kfree(last_sony_subcode); + devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE); + devfs_unregister(sony_devfs_handle); + if (sony535_irq_used) + free_irq(sony535_irq_used, NULL); + } + register_disk(NULL, mk_kdev(MAJOR_NR,0), 1, &cdu_fops, 0); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/Config.help linux-2.5/drivers/char/Config.help --- linux-2.5.13/drivers/char/Config.help Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/char/Config.help Sat Apr 27 00:42:19 2002 @@ -1014,6 +1014,12 @@ The module is called machzwd.o. If you want to compile it as a module, say M here and read . +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.13/drivers/char/Config.in linux-2.5/drivers/char/Config.in --- linux-2.5.13/drivers/char/Config.in Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/char/Config.in Fri May 3 04:12:45 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 @@ -108,26 +138,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 @@ -145,18 +155,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 @@ -168,8 +171,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 @@ -182,7 +189,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 @@ -209,19 +221,29 @@ dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP if [ "$CONFIG_AGP" != "n" ]; then - bool ' Intel 440LX/BX/GX and I815/I820/I830M/I840/I845/I850/I860 support' CONFIG_AGP_INTEL + bool ' Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL bool ' Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810 bool ' VIA chipset support' CONFIG_AGP_VIA bool ' AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD bool ' Generic SiS support' CONFIG_AGP_SIS bool ' ALI chipset support' CONFIG_AGP_ALI bool ' Serverworks LE/HE support' CONFIG_AGP_SWORKS + if [ "$CONFIG_IA64" = "y" ]; then + bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 + fi fi source drivers/char/drm/Config.in 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.13/drivers/char/Makefile linux-2.5/drivers/char/Makefile --- linux-2.5.13/drivers/char/Makefile Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/char/Makefile Fri May 3 03:01:34 2002 @@ -14,22 +14,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 @@ -42,7 +40,6 @@ ifeq ($(ARCH),s390x) KEYMAP = KEYBD = - CONSOLE = SERIAL = endif @@ -50,11 +47,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 = @@ -67,28 +71,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 @@ -116,12 +115,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) @@ -139,6 +143,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 @@ -157,11 +162,10 @@ obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o +obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o subdir-$(CONFIG_RIO) += rio -obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o -obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_BUSMOUSE) += busmouse.o @@ -169,12 +173,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),) @@ -184,6 +183,11 @@ 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 @@ -213,6 +217,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 @@ -221,6 +227,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 subdir-$(CONFIG_MWAVE) += mwave diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/acquirewdt.c linux-2.5/drivers/char/acquirewdt.c --- linux-2.5.13/drivers/char/acquirewdt.c Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/char/acquirewdt.c Mon Apr 15 01:34:05 2002 @@ -221,8 +221,18 @@ spin_lock_init(&acq_lock); if (misc_register(&acq_miscdev)) return -ENODEV; - request_region(WDT_STOP, 1, "Acquire WDT"); - request_region(WDT_START, 1, "Acquire WDT"); + if (!request_region(WDT_STOP, 1, "Acquire WDT")) + { + misc_deregister(&acq_miscdev); + return -EIO; + } + if (!request_region(WDT_START, 1, "Acquire WDT")) + { + release_region(WDT_STOP, 1); + misc_deregister(&acq_miscdev); + return -EIO; + } + register_reboot_notifier(&acq_notifier); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/adbmouse.c linux-2.5/drivers/char/adbmouse.c --- linux-2.5.13/drivers/char/adbmouse.c Fri May 3 01:22:52 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.13/drivers/char/advantechwdt.c linux-2.5/drivers/char/advantechwdt.c --- linux-2.5.13/drivers/char/advantechwdt.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/char/advantechwdt.c Mon Apr 15 01:31:33 2002 @@ -241,11 +241,21 @@ advwdt_validate_timeout(); spin_lock_init(&advwdt_lock); - misc_register(&advwdt_miscdev); + if (misc_register(&advwdt_miscdev)) + return -ENODEV; #if WDT_START != WDT_STOP - request_region(WDT_STOP, 1, "Advantech WDT"); + if (!request_region(WDT_STOP, 1, "Advantech WDT")) { + misc_deregister(&advwdt_miscdev); + return -EIO; + } #endif - request_region(WDT_START, 1, "Advantech WDT"); + if (!request_region(WDT_START, 1, "Advantech WDT")) { + misc_deregister(&advwdt_miscdev); +#if WDT_START != WDT_STOP + release_region(WDT_STOP, 1); +#endif + return -EIO; + } register_reboot_notifier(&advwdt_notifier); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/agp/agp.h linux-2.5/drivers/char/agp/agp.h --- linux-2.5.13/drivers/char/agp/agp.h Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/char/agp/agp.h Fri May 3 03:49:06 2002 @@ -125,10 +125,12 @@ }; +#define OUTREG64(mmap, addr, val) __raw_writeq((val), (mmap)+(addr)) #define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) #define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr)) #define OUTREG8(mmap, addr, val) __raw_writeb((val), (mmap)+(addr)) +#define INREG64(mmap, addr) __raw_readq((mmap)+(addr)) #define INREG32(mmap, addr) __raw_readl((mmap)+(addr)) #define INREG16(mmap, addr) __raw_readw((mmap)+(addr)) #define INREG8(mmap, addr) __raw_readb((mmap)+(addr)) @@ -377,5 +379,14 @@ #define SVWRKS_TLBFLUSH 0x10 #define SVWRKS_POSTFLUSH 0x14 #define SVWRKS_DIRFLUSH 0x0c + +/* HP ZX1 SBA registers */ +#define HP_ZX1_CTRL 0x200 +#define HP_ZX1_IBASE 0x300 +#define HP_ZX1_IMASK 0x308 +#define HP_ZX1_PCOM 0x310 +#define HP_ZX1_TCNFG 0x318 +#define HP_ZX1_PDIR_BASE 0x320 +#define HP_ZX1_CACHE_FLUSH 0x428 #endif /* _AGP_BACKEND_PRIV_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/agp/agpgart_be.c linux-2.5/drivers/char/agp/agpgart_be.c --- linux-2.5.13/drivers/char/agp/agpgart_be.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/char/agp/agpgart_be.c Fri May 3 03:49:06 2002 @@ -3432,6 +3432,368 @@ #endif /* CONFIG_AGP_SWORKS */ +#ifdef CONFIG_AGP_HP_ZX1 + +#ifndef log2 +#define log2(x) ffz(~(x)) +#endif + +#define HP_ZX1_IOVA_BASE GB(1UL) +#define HP_ZX1_IOVA_SIZE GB(1UL) +#define HP_ZX1_GART_SIZE (HP_ZX1_IOVA_SIZE / 2) +#define HP_ZX1_SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL + +#define HP_ZX1_PDIR_VALID_BIT 0x8000000000000000UL +#define HP_ZX1_IOVA_TO_PDIR(va) ((va - hp_private.iova_base) >> \ + hp_private.io_tlb_shift) + +static aper_size_info_fixed hp_zx1_sizes[] = +{ + {0, 0, 0}, /* filled in by hp_zx1_fetch_size() */ +}; + +static gatt_mask hp_zx1_masks[] = +{ + {HP_ZX1_PDIR_VALID_BIT, 0} +}; + +static struct _hp_private { + struct pci_dev *ioc; + volatile u8 *registers; + u64 *io_pdir; // PDIR for entire IOVA + u64 *gatt; // PDIR just for GART (subset of above) + u64 gatt_entries; + u64 iova_base; + u64 gart_base; + u64 gart_size; + u64 io_pdir_size; + int io_pdir_owner; // do we own it, or share it with sba_iommu? + int io_page_size; + int io_tlb_shift; + int io_tlb_ps; // IOC ps config + int io_pages_per_kpage; +} hp_private; + +static int __init hp_zx1_ioc_shared(void) +{ + struct _hp_private *hp = &hp_private; + + printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n"); + + /* + * IOC already configured by sba_iommu module; just use + * its setup. We assume: + * - IOVA space is 1Gb in size + * - first 512Mb is IOMMU, second 512Mb is GART + */ + hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG); + switch (hp->io_tlb_ps) { + case 0: hp->io_tlb_shift = 12; break; + case 1: hp->io_tlb_shift = 13; break; + case 2: hp->io_tlb_shift = 14; break; + case 3: hp->io_tlb_shift = 16; break; + default: + printk(KERN_ERR PFX "Invalid IOTLB page size " + "configuration 0x%x\n", hp->io_tlb_ps); + hp->gatt = 0; + hp->gatt_entries = 0; + return -ENODEV; + } + hp->io_page_size = 1 << hp->io_tlb_shift; + hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size; + + hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1; + hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE; + + hp->gart_size = HP_ZX1_GART_SIZE; + hp->gatt_entries = hp->gart_size / hp->io_page_size; + + hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE)); + hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)]; + + if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) { + hp->gatt = 0; + hp->gatt_entries = 0; + printk(KERN_ERR PFX "No reserved IO PDIR entry found; " + "GART disabled\n"); + return -ENODEV; + } + + return 0; +} + +static int __init hp_zx1_ioc_owner(u8 ioc_rev) +{ + struct _hp_private *hp = &hp_private; + + printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n"); + + /* + * Select an IOV page size no larger than system page size. + */ + if (PAGE_SIZE >= KB(64)) { + hp->io_tlb_shift = 16; + hp->io_tlb_ps = 3; + } else if (PAGE_SIZE >= KB(16)) { + hp->io_tlb_shift = 14; + hp->io_tlb_ps = 2; + } else if (PAGE_SIZE >= KB(8)) { + hp->io_tlb_shift = 13; + hp->io_tlb_ps = 1; + } else { + hp->io_tlb_shift = 12; + hp->io_tlb_ps = 0; + } + hp->io_page_size = 1 << hp->io_tlb_shift; + hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size; + + hp->iova_base = HP_ZX1_IOVA_BASE; + hp->gart_size = HP_ZX1_GART_SIZE; + hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size; + + hp->gatt_entries = hp->gart_size / hp->io_page_size; + hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64); + + return 0; +} + +static int __init hp_zx1_ioc_init(void) +{ + struct _hp_private *hp = &hp_private; + struct pci_dev *ioc; + int i; + u8 ioc_rev; + + ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL); + if (!ioc) { + printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n"); + return -ENODEV; + } + hp->ioc = ioc; + + pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev); + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) { + hp->registers = (u8 *) ioremap(pci_resource_start(ioc, + i), + pci_resource_len(ioc, i)); + break; + } + } + if (!hp->registers) { + printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n"); + + return -ENODEV; + } + + /* + * If the IOTLB is currently disabled, we can take it over. + * Otherwise, we have to share with sba_iommu. + */ + hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0; + + if (hp->io_pdir_owner) + return hp_zx1_ioc_owner(ioc_rev); + + return hp_zx1_ioc_shared(); +} + +static int hp_zx1_fetch_size(void) +{ + int size; + + size = hp_private.gart_size / MB(1); + hp_zx1_sizes[0].size = size; + agp_bridge.current_size = (void *) &hp_zx1_sizes[0]; + return size; +} + +static int hp_zx1_configure(void) +{ + struct _hp_private *hp = &hp_private; + + agp_bridge.gart_bus_addr = hp->gart_base; + agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP); + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode); + + if (hp->io_pdir_owner) { + OUTREG64(hp->registers, HP_ZX1_PDIR_BASE, + virt_to_phys(hp->io_pdir)); + OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps); + OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1)); + OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1); + OUTREG64(hp->registers, HP_ZX1_PCOM, + hp->iova_base | log2(HP_ZX1_IOVA_SIZE)); + INREG64(hp->registers, HP_ZX1_PCOM); + } + + return 0; +} + +static void hp_zx1_cleanup(void) +{ + struct _hp_private *hp = &hp_private; + + if (hp->io_pdir_owner) + OUTREG64(hp->registers, HP_ZX1_IBASE, 0); + iounmap((void *) hp->registers); +} + +static void hp_zx1_tlbflush(agp_memory * mem) +{ + struct _hp_private *hp = &hp_private; + + OUTREG64(hp->registers, HP_ZX1_PCOM, + hp->gart_base | log2(hp->gart_size)); + INREG64(hp->registers, HP_ZX1_PCOM); +} + +static int hp_zx1_create_gatt_table(void) +{ + struct _hp_private *hp = &hp_private; + int i; + + if (hp->io_pdir_owner) { + hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL, + get_order(hp->io_pdir_size)); + if (!hp->io_pdir) { + printk(KERN_ERR PFX "Couldn't allocate contiguous " + "memory for I/O PDIR\n"); + hp->gatt = 0; + hp->gatt_entries = 0; + return -ENOMEM; + } + memset(hp->io_pdir, 0, hp->io_pdir_size); + + hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)]; + } + + for (i = 0; i < hp->gatt_entries; i++) { + hp->gatt[i] = (unsigned long) agp_bridge.scratch_page; + } + + return 0; +} + +static int hp_zx1_free_gatt_table(void) +{ + struct _hp_private *hp = &hp_private; + + if (hp->io_pdir_owner) + free_pages((unsigned long) hp->io_pdir, + get_order(hp->io_pdir_size)); + else + hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE; + return 0; +} + +static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type) +{ + struct _hp_private *hp = &hp_private; + int i, k; + off_t j, io_pg_start; + int io_pg_count; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + io_pg_start = hp->io_pages_per_kpage * pg_start; + io_pg_count = hp->io_pages_per_kpage * mem->page_count; + if ((io_pg_start + io_pg_count) > hp->gatt_entries) { + return -EINVAL; + } + + j = io_pg_start; + while (j < (io_pg_start + io_pg_count)) { + if (hp->gatt[j]) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = io_pg_start; i < mem->page_count; i++) { + unsigned long paddr; + + paddr = mem->memory[i]; + for (k = 0; + k < hp->io_pages_per_kpage; + k++, j++, paddr += hp->io_page_size) { + hp->gatt[j] = agp_bridge.mask_memory(paddr, type); + } + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type) +{ + struct _hp_private *hp = &hp_private; + int i, io_pg_start, io_pg_count; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + io_pg_start = hp->io_pages_per_kpage * pg_start; + io_pg_count = hp->io_pages_per_kpage * mem->page_count; + for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) { + hp->gatt[i] = agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static unsigned long hp_zx1_mask_memory(unsigned long addr, int type) +{ + return HP_ZX1_PDIR_VALID_BIT | addr; +} + +static unsigned long hp_zx1_unmask_memory(unsigned long addr) +{ + return addr & ~(HP_ZX1_PDIR_VALID_BIT); +} + +static int __init hp_zx1_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = hp_zx1_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.dev_private_data = NULL; + agp_bridge.size_type = FIXED_APER_SIZE; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = hp_zx1_configure; + agp_bridge.fetch_size = hp_zx1_fetch_size; + agp_bridge.cleanup = hp_zx1_cleanup; + agp_bridge.tlb_flush = hp_zx1_tlbflush; + agp_bridge.mask_memory = hp_zx1_mask_memory; + agp_bridge.unmask_memory = hp_zx1_unmask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = hp_zx1_create_gatt_table; + agp_bridge.free_gatt_table = hp_zx1_free_gatt_table; + agp_bridge.insert_memory = hp_zx1_insert_memory; + agp_bridge.remove_memory = hp_zx1_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.cant_use_aperture = 1; + + return hp_zx1_ioc_init(); + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_HP_ZX1 */ /* per-chipset initialization data. * note -- all chipsets for a single vendor MUST be grouped together @@ -3725,6 +4087,15 @@ via_generic_setup }, #endif /* CONFIG_AGP_VIA */ +#ifdef CONFIG_AGP_HP_ZX1 + { PCI_DEVICE_ID_HP_ZX1_LBA, + PCI_VENDOR_ID_HP, + HP_ZX1, + "HP", + "ZX1", + hp_zx1_setup }, +#endif + { 0, }, /* dummy final entry, always present */ }; @@ -3948,6 +4319,23 @@ } #endif /* CONFIG_AGP_SWORKS */ + +#ifdef CONFIG_AGP_HP_ZX1 + if (dev->vendor == PCI_VENDOR_ID_HP) { + do { + /* ZX1 LBAs can be either PCI or AGP bridges */ + if (pci_find_capability(dev, PCI_CAP_ID_AGP)) { + printk(KERN_INFO PFX "Detected HP ZX1 AGP " + "chipset at %s\n", dev->slot_name); + agp_bridge.type = HP_ZX1; + agp_bridge.dev = dev; + return hp_zx1_setup(dev); + } + dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev); + } while (dev); + return -ENODEV; + } +#endif /* CONFIG_AGP_HP_ZX1 */ /* find capndx */ cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/alim7101_wdt.c linux-2.5/drivers/char/alim7101_wdt.c --- linux-2.5.13/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.13/drivers/char/amd768_rng.c linux-2.5/drivers/char/amd768_rng.c --- linux-2.5.13/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.13/drivers/char/amigamouse.c linux-2.5/drivers/char/amigamouse.c --- linux-2.5.13/drivers/char/amigamouse.c Fri May 3 01:22:53 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.13/drivers/char/amiserial.c linux-2.5/drivers/char/amiserial.c --- linux-2.5.13/drivers/char/amiserial.c Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/char/amiserial.c Wed Mar 27 13:07:16 2002 @@ -89,7 +89,7 @@ #include #include -#include + #include #include @@ -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.13/drivers/char/atixlmouse.c linux-2.5/drivers/char/atixlmouse.c --- linux-2.5.13/drivers/char/atixlmouse.c Fri May 3 01:22:57 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.13/drivers/char/au1000_gpio.c linux-2.5/drivers/char/au1000_gpio.c --- linux-2.5.13/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.13/drivers/char/console.c linux-2.5/drivers/char/console.c --- linux-2.5.13/drivers/char/console.c Fri May 3 01:22:47 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.13/drivers/char/console_macros.h linux-2.5/drivers/char/console_macros.h --- linux-2.5.13/drivers/char/console_macros.h Fri May 3 01:22:44 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.13/drivers/char/consolemap.c linux-2.5/drivers/char/consolemap.c --- linux-2.5.13/drivers/char/consolemap.c Fri May 3 01:22: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.13/drivers/char/decvte.c linux-2.5/drivers/char/decvte.c --- linux-2.5.13/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.13/drivers/char/drm/Config.help linux-2.5/drivers/char/drm/Config.help --- linux-2.5.13/drivers/char/drm/Config.help Fri May 3 01:22:51 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.13/drivers/char/drm/Config.in linux-2.5/drivers/char/drm/Config.in --- linux-2.5.13/drivers/char/drm/Config.in Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/char/drm/Config.in Thu Dec 13 16:32:35 2001 @@ -13,4 +13,5 @@ dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP dep_tristate ' Intel I810' CONFIG_DRM_I810 $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.13/drivers/char/drm/Makefile linux-2.5/drivers/char/drm/Makefile --- linux-2.5.13/drivers/char/drm/Makefile Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/char/drm/Makefile Mon Apr 22 02:05:17 2002 @@ -11,6 +11,7 @@ i810-objs := i810_drv.o i810_dma.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o ffb-objs := ffb_drv.o ffb_context.o +sis-objs := sis_drv.o sis_ds.o sis_mm.o obj-$(CONFIG_DRM_GAMMA) += gamma.o obj-$(CONFIG_DRM_TDFX) += tdfx.o @@ -19,5 +20,6 @@ obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_FFB) += ffb.o +obj-$(CONFIG_DRM_SIS) += sis.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/drm.h linux-2.5/drivers/char/drm/drm.h --- linux-2.5.13/drivers/char/drm/drm.h Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/char/drm/drm.h Thu May 2 22:22:25 2002 @@ -104,7 +104,7 @@ #include "i810_drm.h" #include "r128_drm.h" #include "radeon_drm.h" -#ifdef CONFIG_DRM_SIS +#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) #include "sis_drm.h" #endif @@ -483,7 +483,7 @@ #define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(0x4d, drm_radeon_indirect_t) #define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(0x4e, drm_radeon_texture_t) -#ifdef CONFIG_DRM_SIS +#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) /* SiS specific ioctls */ #define SIS_IOCTL_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) #define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/drm_agpsupport.h linux-2.5/drivers/char/drm/drm_agpsupport.h --- linux-2.5.13/drivers/char/drm/drm_agpsupport.h Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/char/drm/drm_agpsupport.h Fri May 3 03:49:06 2002 @@ -317,6 +317,8 @@ break; #endif + case HP_ZX1: head->chipset = "HP ZX1"; break; + default: head->chipset = "Unknown"; break; } #if LINUX_VERSION_CODE <= 0x020408 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/drm_context.h linux-2.5/drivers/char/drm/drm_context.h --- linux-2.5.13/drivers/char/drm/drm_context.h Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/char/drm/drm_context.h Thu May 2 22:22:25 2002 @@ -27,6 +27,10 @@ * Authors: * Rickard E. (Rik) Faith * Gareth Hughes + * ChangeLog: + * 2001-11-16 Torsten Duwe + * added context constructor/destructor hooks, + * needed by SiS driver's memory management. */ #define __NO_VERSION__ @@ -316,6 +320,10 @@ /* Should this return -EBUSY instead? */ return -ENOMEM; } +#ifdef DRIVER_CTX_CTOR + if ( ctx.handle != DRM_KERNEL_CONTEXT ) + DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */ +#endif if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) ) return -EFAULT; @@ -390,6 +398,9 @@ priv->remove_auth_on_close = 1; } if ( ctx.handle != DRM_KERNEL_CONTEXT ) { +#ifdef DRIVER_CTX_DTOR + DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */ +#endif DRM(ctxbitmap_free)( dev, ctx.handle ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/sis.h linux-2.5/drivers/char/drm/sis.h --- linux-2.5.13/drivers/char/drm/sis.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/drm/sis.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,56 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.1 2001/05/19 18:29:22 dawes Exp $ */ + +#ifndef __SIS_H__ +#define __SIS_H__ + +/* This remains constant for all DRM template files. + * Name it sisdrv_##x as there's a conflict with sis_free/malloc in the kernel + * that's used for fb devices + */ +#define DRM(x) sisdrv_##x + +/* General customization: + */ +#define __HAVE_AGP 1 +#define __MUST_HAVE_AGP 0 +#define __HAVE_MTRR 1 +#define __HAVE_CTX_BITMAP 1 + +/* Buffer customization: + */ +#define DRIVER_AGP_BUFFERS_MAP( dev ) \ + ((drm_sis_private_t *)((dev)->dev_private))->buffers + +extern int sis_init_context(int context); +extern int sis_final_context(int context); + +#define DRIVER_CTX_CTOR sis_init_context +#define DRIVER_CTX_DTOR sis_final_context + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/sis_drm.h linux-2.5/drivers/char/drm/sis_drm.h --- linux-2.5.13/drivers/char/drm/sis_drm.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drm.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,36 @@ + +#ifndef _sis_drm_public_h_ +#define _sis_drm_public_h_ + +typedef struct { + int context; + unsigned int offset; + unsigned int size; + unsigned int free; +} drm_sis_mem_t; + +typedef struct { + unsigned int offset, size; +} drm_sis_agp_t; + +typedef struct { + unsigned int left, right; +} drm_sis_flip_t; + +#ifdef __KERNEL__ + +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +#endif + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/sis_drv.c linux-2.5/drivers/char/drm/sis_drv.c --- linux-2.5.13/drivers/char/drm/sis_drv.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drv.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,74 @@ +/* sis.c -- sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include "sis.h" +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" + +#define DRIVER_AUTHOR "SIS" +#define DRIVER_NAME "sis" +#define DRIVER_DESC "SIS 300/630/540" +#define DRIVER_DATE "20010503" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +#define DRIVER_IOCTLS \ + [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)] = { sis_fb_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)] = { sis_fb_free, 1, 0 }, \ + /* AGP Memory Management */ \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)] = { sisp_agp_init, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)] = { sisp_agp_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)] = { sisp_agp_free, 1, 0 } +#if 0 /* these don't appear to be defined */ + /* SIS Stereo */ + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { sis_control, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP)] = { sis_flip, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP_INIT)] = { sis_flip_init, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final, 1, 1 } +#endif + +#define __HAVE_COUNTERS 5 + +#include "drm_auth.h" +#include "drm_agpsupport.h" +#include "drm_bufs.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_drv.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lists.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/sis_drv.h linux-2.5/drivers/char/drm/sis_drv.h --- linux-2.5.13/drivers/char/drm/sis_drv.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drv.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,45 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _SIS_DRV_H_ +#define _SIS_DRV_H_ + +typedef struct drm_sis_private { + drm_map_t *buffers; +} drm_sis_private_t; + +/* Stereo ? - this was never committed */ + +int sis_flip(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_flip_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_flip_final(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +void flip_final(void); + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/sis_ds.c linux-2.5/drivers/char/drm/sis_ds.c --- linux-2.5.13/drivers/char/drm/sis_ds.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_ds.c Fri Feb 15 18:02:54 2002 @@ -0,0 +1,406 @@ +/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sis_ds.h" + +/* Set Data Structure, not check repeated value + * temporarily used + */ + +set_t *setInit(void) +{ + int i; + set_t *set; + + set = (set_t *)MALLOC(sizeof(set_t)); + for(i = 0; i < SET_SIZE; i++){ + set->list[i].free_next = i+1; + set->list[i].alloc_next = -1; + } + set->list[SET_SIZE-1].free_next = -1; + set->free = 0; + set->alloc = -1; + set->trace = -1; + + return set; +} + +int setAdd(set_t *set, ITEM_TYPE item) +{ + int free = set->free; + + if(free != -1){ + set->list[free].val = item; + set->free = set->list[free].free_next; + } + else{ + return 0; + } + + set->list[free].alloc_next = set->alloc; + set->alloc = free; + set->list[free].free_next = -1; + + return 1; +} + +int setDel(set_t *set, ITEM_TYPE item) +{ + int alloc = set->alloc; + int prev = -1; + + while(alloc != -1){ + if(set->list[alloc].val == item){ + if(prev != -1) + set->list[prev].alloc_next = set->list[alloc].alloc_next; + else + set->alloc = set->list[alloc].alloc_next; + break; + } + prev = alloc; + alloc = set->list[alloc].alloc_next; + } + + if(alloc == -1) + return 0; + + set->list[alloc].free_next = set->free; + set->free = alloc; + set->list[alloc].alloc_next = -1; + + return 1; +} + +/* setFirst -> setAdd -> setNext is wrong */ + +int setFirst(set_t *set, ITEM_TYPE *item) +{ + if(set->alloc == -1) + return 0; + + *item = set->list[set->alloc].val; + set->trace = set->list[set->alloc].alloc_next; + + return 1; +} + +int setNext(set_t *set, ITEM_TYPE *item) +{ + if(set->trace == -1) + return 0; + + *item = set->list[set->trace].val; + set->trace = set->list[set->trace].alloc_next; + + return 1; +} + +int setDestroy(set_t *set) +{ + FREE(set); + + return 1; +} + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define ISFREE(bptr) ((bptr)->free) + +#define PRINTF(fmt, arg...) do{}while(0) +#define fprintf(fmt, arg...) do{}while(0) + +static void *calloc(size_t nmemb, size_t size) +{ + void *addr; + addr = kmalloc(nmemb*size, GFP_KERNEL); + memset(addr, 0, nmemb*size); + return addr; +} +#define free(n) kfree(n) + +void mmDumpMemInfo( memHeap_t *heap ) +{ + TMemBlock *p; + + PRINTF ("Memory heap %p:\n", heap); + if (heap == 0) { + PRINTF (" heap == 0\n"); + } else { + p = (TMemBlock *)heap; + while (p) { + PRINTF (" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size, + p->free ? '.':'U', + p->reserved ? 'R':'.'); + p = p->next; + } + } + PRINTF ("End of memory blocks\n"); +} + +memHeap_t *mmInit(int ofs, + int size) +{ + PMemBlock blocks; + + if (size <= 0) { + return 0; + } + blocks = (TMemBlock *) calloc(1,sizeof(TMemBlock)); + if (blocks) { + blocks->ofs = ofs; + blocks->size = size; + blocks->free = 1; + return (memHeap_t *)blocks; + } else + return 0; +} + +/* Kludgey workaround for existing i810 server. Remove soon. + */ +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ) +{ + PMemBlock blocks; + blocks = (TMemBlock *) calloc(2,sizeof(TMemBlock)); + if (blocks) { + blocks[0].size = size; + blocks[0].free = 1; + blocks[0].ofs = ofs; + blocks[0].next = &blocks[1]; + + /* Discontinuity - stops JoinBlock from trying to join non-adjacent + * ranges. + */ + blocks[1].size = 0; + blocks[1].free = 0; + blocks[1].ofs = ofs+size; + blocks[1].next = (PMemBlock) heap; + return (memHeap_t *)blocks; + } + else + return heap; +} + +static TMemBlock* SliceBlock(TMemBlock *p, + int startofs, int size, + int reserved, int alignment) +{ + TMemBlock *newblock; + + /* break left */ + if (startofs > p->ofs) { + newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->next = p->next; + p->size -= newblock->size; + p->next = newblock; + p = newblock; + } + + /* break right */ + if (size < p->size) { + newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->next = p->next; + p->size = size; + p->next = newblock; + } + + /* p = middle block */ + p->align = alignment; + p->free = 0; + p->reserved = reserved; + return p; +} + +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch) +{ + int mask,startofs,endofs; + TMemBlock *p; + + if (!heap || align2 < 0 || size <= 0) + return NULL; + mask = (1 << align2)-1; + startofs = 0; + p = (TMemBlock *)heap; + while (p) { + if (ISFREE(p)) { + startofs = (p->ofs + mask) & ~mask; + if ( startofs < startSearch ) { + startofs = startSearch; + } + endofs = startofs+size; + if (endofs <= (p->ofs+p->size)) + break; + } + p = p->next; + } + if (!p) + return NULL; + p = SliceBlock(p,startofs,size,0,mask+1); + p->heap = heap; + return p; +} + +static __inline__ int Join2Blocks(TMemBlock *p) +{ + if (p->free && p->next && p->next->free) { + TMemBlock *q = p->next; + p->size += q->size; + p->next = q->next; + free(q); + return 1; + } + return 0; +} + +int mmFreeMem(PMemBlock b) +{ + TMemBlock *p,*prev; + + if (!b) + return 0; + if (!b->heap) { + fprintf(stderr, "no heap\n"); + return -1; + } + p = b->heap; + prev = NULL; + while (p && p != b) { + prev = p; + p = p->next; + } + if (!p || p->free || p->reserved) { + if (!p) + fprintf(stderr, "block not found in heap\n"); + else if (p->free) + fprintf(stderr, "block already free\n"); + else + fprintf(stderr, "block is reserved\n"); + return -1; + } + p->free = 1; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +int mmReserveMem(memHeap_t *heap, int offset,int size) +{ + int endofs; + TMemBlock *p; + + if (!heap || size <= 0) + return -1; + endofs = offset+size; + p = (TMemBlock *)heap; + while (p && p->ofs <= offset) { + if (ISFREE(p) && endofs <= (p->ofs+p->size)) { + SliceBlock(p,offset,size,1,1); + return 0; + } + p = p->next; + } + return -1; +} + +int mmFreeReserved(memHeap_t *heap, int offset) +{ + TMemBlock *p,*prev; + + if (!heap) + return -1; + p = (TMemBlock *)heap; + prev = NULL; + while (p && p->ofs != offset) { + prev = p; + p = p->next; + } + if (!p || !p->reserved) + return -1; + p->free = 1; + p->reserved = 0; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +void mmDestroy(memHeap_t *heap) +{ + TMemBlock *p,*q; + + if (!heap) + return; + p = (TMemBlock *)heap; + while (p) { + q = p->next; + free(p); + p = q; + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/sis_ds.h linux-2.5/drivers/char/drm/sis_ds.h --- linux-2.5.13/drivers/char/drm/sis_ds.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_ds.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,163 @@ +/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin + * + */ + +#ifndef _sis_ds_h_ +#define _sis_ds_h_ + +/* Set Data Structure */ + +#define SET_SIZE 5000 +#define MALLOC(s) kmalloc(s, GFP_KERNEL) +#define FREE(s) kfree(s) + +typedef unsigned int ITEM_TYPE; + +typedef struct { + ITEM_TYPE val; + int alloc_next, free_next; +} list_item_t; + +typedef struct { + int alloc; + int free; + int trace; + list_item_t list[SET_SIZE]; +} set_t; + +set_t *setInit(void); +int setAdd(set_t *set, ITEM_TYPE item); +int setDel(set_t *set, ITEM_TYPE item); +int setFirst(set_t *set, ITEM_TYPE *item); +int setNext(set_t *set, ITEM_TYPE *item); +int setDestroy(set_t *set); + +#endif + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef MM_INC +#define MM_INC + +struct mem_block_t { + struct mem_block_t *next; + struct mem_block_t *heap; + int ofs,size; + int align; + int free:1; + int reserved:1; +}; +typedef struct mem_block_t TMemBlock; +typedef struct mem_block_t *PMemBlock; + +/* a heap is just the first block in a chain */ +typedef struct mem_block_t memHeap_t; + +static __inline__ int mmBlockSize(PMemBlock b) +{ return b->size; } + +static __inline__ int mmOffset(PMemBlock b) +{ return b->ofs; } + +static __inline__ void mmMarkReserved(PMemBlock b) +{ b->reserved = 1; } + +/* + * input: total size in bytes + * return: a heap pointer if OK, NULL if error + */ +memHeap_t *mmInit( int ofs, int size ); + + + +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ); + + +/* + * Allocate 'size' bytes with 2^align2 bytes alignment, + * restrict the search to free memory after 'startSearch' + * depth and back buffers should be in different 4mb banks + * to get better page hits if possible + * input: size = size of block + * align2 = 2^align2 bytes alignment + * startSearch = linear offset from start of heap to begin search + * return: pointer to the allocated block, 0 if error + */ +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch ); + +/* + * Free block starts at offset + * input: pointer to a block + * return: 0 if OK, -1 if error + */ +int mmFreeMem( PMemBlock b ); + +/* + * Reserve 'size' bytes block start at offset + * This is used to prevent allocation of memory already used + * by the X server for the front buffer, pixmaps, and cursor + * input: size, offset + * output: 0 if OK, -1 if error + */ +int mmReserveMem( memHeap_t *heap, int offset,int size ); +int mmFreeReserved( memHeap_t *heap, int offset ); + +/* + * destroy MM + */ +void mmDestroy( memHeap_t *mmInit ); + +/* For debuging purpose. */ +void mmDumpMemInfo( memHeap_t *mmInit ); + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/drm/sis_mm.c linux-2.5/drivers/char/drm/sis_mm.c --- linux-2.5.13/drivers/char/drm/sis_mm.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_mm.c Thu Dec 13 16:32:35 2001 @@ -0,0 +1,307 @@ +/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin + * + */ + +#define __NO_VERSION__ +#include "sis.h" +#include +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" +#include "sis_ds.h" + +#define MAX_CONTEXT 100 +#define VIDEO_TYPE 0 +#define AGP_TYPE 1 + +typedef struct { + int used; + int context; + set_t *sets[2]; /* 0 for video, 1 for AGP */ +} sis_context_t; + +static sis_context_t global_ppriv[MAX_CONTEXT]; + +static int add_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + + for(i = 0; i < MAX_CONTEXT; i++) + if(global_ppriv[i].used && global_ppriv[i].context == context){ + retval = setAdd(global_ppriv[i].sets[type], val); + break; + } + return retval; +} + +static int del_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + for(i = 0; i < MAX_CONTEXT; i++) + if(global_ppriv[i].used && global_ppriv[i].context == context){ + retval = setDel(global_ppriv[i].sets[type], val); + break; + } + return retval; +} + +/* fb management via fb device */ +#if 1 +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t fb; + struct sis_memreq req; + int retval = 0; + + if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) + return -EFAULT; + + req.size = fb.size; + sis_malloc(&req); + if(req.offset){ + /* TODO */ + fb.offset = req.offset; + fb.free = req.offset; + if(!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)){ + DRM_DEBUG("adding to allocation set fails\n"); + sis_free(req.offset); + retval = -1; + } + } + else{ + fb.offset = 0; + fb.size = 0; + fb.free = 0; + } + + if (copy_to_user((drm_sis_mem_t *)arg, &fb, sizeof(fb))) return -EFAULT; + + DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); + + return retval; +} + +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t fb; + int retval = 0; + + if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) + return -EFAULT; + + if(!fb.free){ + return -1; + } + + sis_free(fb.free); + if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) + retval = -1; + + DRM_DEBUG("free fb, offset = %d\n", fb.free); + + return retval; +} + +#else + +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return -1; +} + +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +#endif + +/* agp memory management */ +#if 1 + +static memHeap_t *AgpHeap = NULL; + +int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_agp_t agp; + + if (copy_from_user(&agp, (drm_sis_agp_t *)arg, sizeof(agp))) + return -EFAULT; + + AgpHeap = mmInit(agp.offset, agp.size); + + DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); + + return 0; +} + +int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t agp; + PMemBlock block; + int retval = 0; + + if(!AgpHeap) + return -1; + + if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) + return -EFAULT; + + block = mmAllocMem(AgpHeap, agp.size, 0, 0); + if(block){ + /* TODO */ + agp.offset = block->ofs; + agp.free = (unsigned int)block; + if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){ + DRM_DEBUG("adding to allocation set fails\n"); + mmFreeMem((PMemBlock)agp.free); + retval = -1; + } + } + else{ + agp.offset = 0; + agp.size = 0; + agp.free = 0; + } + + if (copy_to_user((drm_sis_mem_t *)arg, &agp, sizeof(agp))) return -EFAULT; + + DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset); + + return retval; +} + +int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t agp; + int retval = 0; + + if(!AgpHeap) + return -1; + + if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) + return -EFAULT; + + if(!agp.free){ + return -1; + } + + mmFreeMem((PMemBlock)agp.free); + if(!del_alloc_set(agp.context, AGP_TYPE, agp.free)) + retval = -1; + + DRM_DEBUG("free agp, free = %d\n", agp.free); + + return retval; +} + +#endif + +int sis_init_context(int context) +{ + int i; + + for(i = 0; i < MAX_CONTEXT ; i++) + if(global_ppriv[i].used && (global_ppriv[i].context == context)) + break; + + if(i >= MAX_CONTEXT){ + for(i = 0; i < MAX_CONTEXT ; i++){ + if(!global_ppriv[i].used){ + global_ppriv[i].context = context; + global_ppriv[i].used = 1; + global_ppriv[i].sets[0] = setInit(); + global_ppriv[i].sets[1] = setInit(); + DRM_DEBUG("init allocation set, socket=%d, context = %d\n", + i, context); + break; + } + } + if((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || + (global_ppriv[i].sets[1] == NULL)){ + return 0; + } + } + + return 1; +} + +int sis_final_context(int context) +{ + int i; + + for(i=0; i +#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.13/drivers/char/dz.c linux-2.5/drivers/char/dz.c --- linux-2.5.13/drivers/char/dz.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/char/dz.c Sat Apr 27 13:58:47 2002 @@ -14,41 +14,30 @@ * after patches by harald to irq code. * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout * field from "current" - somewhere between 2.1.121 and 2.1.131 -Qua Jun 27 15:02:26 BRT 2001 * [27-JUN-2001] Arnaldo Carvalho de Melo - cleanups * * Parts (C) 1999 David Airlie, airlied@linux.ie * [07-SEP-99] Bugfixes */ -/* #define DEBUG_DZ 1 */ - -#include -#include +#define DEBUG_DZ 1 #include +#include #include #include -#include +#include #include #include #include +#include #include #include #include -#include -#include #include -#include /* for definition of SERIAL */ +#include -/* for definition of struct console */ -#ifdef CONFIG_SERIAL_CONSOLE -#define CONSOLE_LINE (3) -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ -#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) #include -#endif /* if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) */ - #include #include #include @@ -59,15 +48,15 @@ #include #include -#ifdef DEBUG_DZ #include #include #include -extern int (*prom_printf) (char *,...); -#endif +#define CONSOLE_LINE (3) /* for definition of struct console */ +extern int (*prom_printf) (char *,...); +struct console dz_sercons; #include "dz.h" @@ -78,13 +67,11 @@ static struct dz_serial *lines[4]; static unsigned char tmp_buffer[256]; - - #ifdef DEBUG_DZ /* * debugging code to send out chars via prom */ -static void debug_console( const char *s,int count) +static void debug_console(const char *s,int count) { unsigned i; @@ -105,17 +92,19 @@ * ------------------------------------------------------------ */ -static inline unsigned short dz_in (struct dz_serial *info, unsigned offset) +static inline unsigned short dz_in(struct dz_serial *info, unsigned offset) { - volatile u16 *addr = (volatile u16 *)(info->port + offset); - + volatile unsigned short *addr = + (volatile unsigned short *) (info->port + offset); return *addr; } -static inline void dz_out (struct dz_serial *info, unsigned offset, - unsigned short value) +static inline void dz_out(struct dz_serial *info, unsigned offset, + unsigned short value) { - volatile u16 *addr = (volatile u16 *)(info->port + offset); + + volatile unsigned short *addr = + (volatile unsigned short *) (info->port + offset); *addr = value; } @@ -129,33 +118,34 @@ * ------------------------------------------------------------ */ -static void dz_stop (struct tty_struct *tty) +static void dz_stop(struct tty_struct *tty) { - struct dz_serial *info; + struct dz_serial *info; unsigned short mask, tmp; - if (!tty) - return; - - info = (struct dz_serial *)tty->driver_data; + if (tty == 0) + return; + + info = (struct dz_serial *) tty->driver_data; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); /* read the TX flag */ + tmp = dz_in(info, DZ_TCR); /* read the TX flag */ - tmp &= ~mask; /* clear the TX flag */ - dz_out (info, DZ_TCR, tmp); + tmp &= ~mask; /* clear the TX flag */ + dz_out(info, DZ_TCR, tmp); } -static void dz_start (struct tty_struct *tty) +static void dz_start(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned short mask, tmp; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); /* read the TX flag */ + tmp = dz_in(info, DZ_TCR); /* read the TX flag */ + + tmp |= mask; /* set the TX flag */ + dz_out(info, DZ_TCR, tmp); - tmp |= mask; /* set the TX flag */ - dz_out (info, DZ_TCR, tmp); } /* @@ -186,7 +176,7 @@ * processing in the software interrupt portion of the driver. * ------------------------------------------------------------ */ -static inline void dz_sched_event (struct dz_serial *info, int event) +static inline void dz_sched_event(struct dz_serial *info, int event) { info->event |= 1 << event; queue_task(&info->tqueue, &tq_serial); @@ -200,8 +190,9 @@ * This routine deals with inputs from any lines. * ------------------------------------------------------------ */ -static inline void receive_chars (struct dz_serial *info_in) +static inline void receive_chars(struct dz_serial *info_in) { + struct dz_serial *info; struct tty_struct *tty = 0; struct async_icount *icount; @@ -235,7 +226,8 @@ if (!tty) break; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = 0; @@ -243,16 +235,15 @@ /* keep track of the statistics */ if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) { - if (status & DZ_PERR) /* parity error */ + if (status & DZ_PERR) /* parity error */ icount->parity++; else if (status & DZ_FERR) /* frame error */ icount->frame++; - if (status & DZ_OERR) /* overrun error */ + if (status & DZ_OERR) /* overrun error */ icount->overrun++; - /* - * Check to see if we should ignore the character and - * mask off conditions that should be ignored + /* check to see if we should ignore the character + and mask off conditions that should be ignored */ if (status & info->ignore_status_mask) { @@ -260,24 +251,18 @@ break; goto ignore_char; } - /* mask off the error conditions we want to ignore */ tmp = status & info->read_status_mask; if (tmp & DZ_PERR) { *tty->flip.flag_buf_ptr = TTY_PARITY; -#ifdef DEBUG_DZ - debug_console("PERR\n",5); -#endif /* DEBUG_DZ */ + debug_console("PERR\n", 5); } else if (tmp & DZ_FERR) { *tty->flip.flag_buf_ptr = TTY_FRAME; -#ifdef DEBUG_DZ - debug_console("FERR\n",5); -#endif /* DEBUG_DZ */ - } if (tmp & DZ_OERR) { -#ifdef DEBUG_DZ - debug_console("OERR\n",5); -#endif /* DEBUG_DZ */ + debug_console("FERR\n", 5); + } + if (tmp & DZ_OERR) { + debug_console("OERR\n", 5); if (tty->flip.count < TTY_FLIPBUF_SIZE) { tty->flip.count++; tty->flip.flag_buf_ptr++; @@ -286,11 +271,10 @@ } } } - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; -ignore_char: - ; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: } while (status & DZ_DVAL); if (tty) @@ -304,26 +288,25 @@ * This routine deals with outputs to any lines. * ------------------------------------------------------------ */ -static inline void transmit_chars (struct dz_serial *info) +static inline void transmit_chars(struct dz_serial *info) { unsigned char tmp; - if (info->x_char) { /* XON/XOFF chars */ + + + if (info->x_char) { /* XON/XOFF chars */ dz_out(info, DZ_TDR, info->x_char); info->icount.tx++; info->x_char = 0; return; } - /* if nothing to do or stopped or hardware stopped */ - if ((info->xmit_cnt <= 0) || info->tty->stopped || - info->tty->hw_stopped) { + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { dz_stop(info->tty); return; } - /* - * If something to do ... (rember the dz has no output fifo so we go + * if something to do ... (rember the dz has no output fifo so we go * one char at a time :-< */ tmp = (unsigned short) info->xmit_buf[info->xmit_tail++]; @@ -332,7 +315,8 @@ info->icount.tx++; if (--info->xmit_cnt < WAKEUP_CHARS) - dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP); + dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP); + /* Are we done */ if (info->xmit_cnt <= 0) @@ -346,7 +330,7 @@ * Only valid for the MODEM line duh ! * ------------------------------------------------------------ */ -static inline void check_modem_status (struct dz_serial *info) +static inline void check_modem_status(struct dz_serial *info) { unsigned short status; @@ -355,7 +339,7 @@ return; status = dz_in(info, DZ_MSR); - + /* it's easy, since DSR2 is the only bit in the register */ if (status) info->icount.dsr++; @@ -369,20 +353,20 @@ * It deals with the multiple ports. * ------------------------------------------------------------ */ -static void dz_interrupt (int irq, void *dev, struct pt_regs *regs) +static void dz_interrupt(int irq, void *dev, struct pt_regs *regs) { struct dz_serial *info; unsigned short status; - /* get the reason why we just got an irq */ - status = dz_in((struct dz_serial *)dev, DZ_CSR); - info = lines[LINE(status)]; /* re-arrange info the proper port */ + /* get the reason why we just got an irq */ + status = dz_in((struct dz_serial *) dev, DZ_CSR); + info = lines[LINE(status)]; /* re-arrange info the proper port */ - if (status & DZ_RDONE) + if (status & DZ_RDONE) receive_chars(info); /* the receive function */ - if (status & DZ_TRDY) - transmit_chars (info); + if (status & DZ_TRDY) + transmit_chars(info); } /* @@ -400,12 +384,12 @@ * 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) +static void do_serial_bh(void) { - run_task_queue (&tq_serial); + run_task_queue(&tq_serial); } -static void do_softint (void *private_data) +static void do_softint(void *private_data) { struct dz_serial *info = (struct dz_serial *) private_data; struct tty_struct *tty = info->tty; @@ -414,10 +398,9 @@ return; if (test_and_clear_bit(DZ_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible (&tty->write_wait); + wake_up_interruptible(&tty->write_wait); } } @@ -431,11 +414,11 @@ * do_serial_hangup() -> tty->hangup() -> rs_hangup() * ------------------------------------------------------------------- */ -static void do_serial_hangup (void *private_data) +static void do_serial_hangup(void *private_data) { struct dz_serial *info = (struct dz_serial *) private_data; struct tty_struct *tty = info->tty;; - + if (!tty) return; @@ -449,31 +432,31 @@ * various initialization tasks * ------------------------------------------------------------------- */ -static int startup (struct dz_serial *info) +static int startup(struct dz_serial *info) { unsigned long page, flags; unsigned short tmp; if (info->is_initialized) return 0; - - save_and_cli(flags); + + save_flags(flags); + cli(); if (!info->port) { - if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); restore_flags(flags); return -ENODEV; } - if (!info->xmit_buf) { page = get_free_page(GFP_KERNEL); if (!page) { - restore_flags (flags); - return -ENOMEM; + restore_flags(flags); + return -ENOMEM; } - info->xmit_buf = (unsigned char *)page; + info->xmit_buf = (unsigned char *) page; } - if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -484,18 +467,24 @@ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - change_speed(info); /* set up the speed */ + /* set up the speed */ + change_speed(info); - /* - * Clear the line transmitter buffer I can't figure out why I need to - * do this - but its necessary - in order for the console portion and - * the interrupt portion to live happily side by side. + /* clear the line transmitter buffer + I can't figure out why I need to do this - but + its necessary - in order for the console portion + and the interrupt portion to live happily side by side. + */ + + /* clear the line transmitter buffer + I can't figure out why I need to do this - but + its necessary - in order for the console portion + and the interrupt portion to live happily side by side. */ info->is_initialized = 1; restore_flags(flags); - return 0; } @@ -507,7 +496,7 @@ * DTR is dropped if the hangup on close termio flag is on. * ------------------------------------------------------------------- */ -static void shutdown (struct dz_serial *info) +static void shutdown(struct dz_serial *info) { unsigned long flags; unsigned short tmp; @@ -515,18 +504,20 @@ if (!info->is_initialized) return; - save_and_cli(flags); + save_flags(flags); + cli(); + + dz_stop(info->tty); + - dz_stop (info->tty); info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */ dz_out(info, DZ_LPR, info->cflags); - if (info->xmit_buf) { /* free Tx buffer */ - free_page((unsigned long)info->xmit_buf); + if (info->xmit_buf) { /* free Tx buffer */ + free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; } - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { tmp = dz_in(info, DZ_TCR); if (tmp & DZ_MODEM_DTR) { @@ -534,13 +525,11 @@ dz_out(info, DZ_TCR, tmp); } } - if (info->tty) - set_bit (TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->tty->flags); info->is_initialized = 0; - - restore_flags (flags); + restore_flags(flags); } /* @@ -550,7 +539,7 @@ * set the baud rate. * ------------------------------------------------------------------- */ -static void change_speed (struct dz_serial *info) +static void change_speed(struct dz_serial *info) { unsigned long flags; unsigned cflag; @@ -558,26 +547,27 @@ if (!info->tty || !info->tty->termios) return; - - save_and_cli(flags); - + + save_flags(flags); + cli(); + info->cflags = info->line; cflag = info->tty->termios->c_cflag; switch (cflag & CSIZE) { - case CS5: - info->cflags |= DZ_CS5; - break; - case CS6: - info->cflags |= DZ_CS6; - break; - case CS7: - info->cflags |= DZ_CS7; - break; - case CS8: - default: - info->cflags |= DZ_CS8; + case CS5: + info->cflags |= DZ_CS5; + break; + case CS6: + info->cflags |= DZ_CS6; + break; + case CS7: + info->cflags |= DZ_CS7; + break; + case CS8: + default: + info->cflags |= DZ_CS8; } if (cflag & CSTOPB) @@ -586,7 +576,7 @@ info->cflags |= DZ_PARENB; if (cflag & PARODD) info->cflags |= DZ_PARODD; - + baud = tty_get_baud_rate(info->tty); switch (baud) { case 50: @@ -600,19 +590,19 @@ break; case 134: info->cflags |= DZ_B134; - break; + break; case 150: info->cflags |= DZ_B150; break; case 300: info->cflags |= DZ_B300; - break; + break; case 600: info->cflags |= DZ_B600; break; case 1200: info->cflags |= DZ_B1200; - break; + break; case 1800: info->cflags |= DZ_B1800; break; @@ -624,16 +614,16 @@ break; case 3600: info->cflags |= DZ_B3600; - break; + break; case 4800: info->cflags |= DZ_B4800; break; case 7200: info->cflags |= DZ_B7200; - break; - case 9600: + break; + case 9600: default: - info->cflags |= DZ_B9600; + info->cflags |= DZ_B9600; } info->cflags |= DZ_RXENAB; @@ -642,8 +632,8 @@ /* setup accept flag */ info->read_status_mask = DZ_OERR; if (I_INPCK(info->tty)) - info->read_status_mask |= (DZ_FERR | DZ_PERR); - + info->read_status_mask |= (DZ_FERR | DZ_PERR); + /* characters to ignore */ info->ignore_status_mask = 0; if (I_IGNPAR(info->tty)) @@ -659,17 +649,19 @@ * Flush the buffer. * ------------------------------------------------------------------- */ -static void dz_flush_chars (struct tty_struct *tty) +static void dz_flush_chars(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf) return; - save_and_cli(flags); - dz_start (info->tty); + save_flags(flags); + cli(); + + dz_start(info->tty); + restore_flags(flags); } @@ -681,64 +673,67 @@ * main output routine. * ------------------------------------------------------------------- */ -static int dz_write (struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) +static int dz_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; int c, ret = 0; - if (!tty ) + if (!tty) return ret; if (!info->xmit_buf) return ret; if (!tmp_buf) tmp_buf = tmp_buffer; + + if (from_user) { - down (&tmp_buf_sem); + + down(&tmp_buf_sem); while (1) { - c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; - c -= copy_from_user (tmp_buf, buf, c); + c -= copy_from_user(tmp_buf, buf, c); if (!c) { if (!ret) ret = -EFAULT; break; } + save_flags(flags); + cli(); - save_and_cli(flags); - - c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - info->xmit_head = ((info->xmit_head + c) & - (DZ_XMIT_SIZE - 1)); + info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE - 1)); info->xmit_cnt += c; + restore_flags(flags); buf += c; count -= c; ret += c; } + up(&tmp_buf_sem); } else { + + while (1) { - save_and_cli(flags); + save_flags(flags); + cli(); - c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); if (c <= 0) { - restore_flags (flags); + restore_flags(flags); break; } memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = ((info->xmit_head + c) & - (DZ_XMIT_SIZE-1)); + info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE - 1)); info->xmit_cnt += c; + restore_flags(flags); buf += c; @@ -747,14 +742,14 @@ } } + if (info->xmit_cnt) { if (!tty->stopped) { if (!tty->hw_stopped) { - dz_start (info->tty); + dz_start(info->tty); } } } - return ret; } @@ -765,15 +760,14 @@ * compute the amount of space available for writing. * ------------------------------------------------------------------- */ -static int dz_write_room (struct tty_struct *tty) +static int dz_write_room(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; int ret; ret = DZ_XMIT_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0; - return ret; } @@ -784,10 +778,10 @@ * compute the amount of char left to be transmitted * ------------------------------------------------------------------- */ -static int dz_chars_in_buffer (struct tty_struct *tty) +static int dz_chars_in_buffer(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - + struct dz_serial *info = (struct dz_serial *) tty->driver_data; + return info->xmit_cnt; } @@ -798,19 +792,18 @@ * Empty the output buffer * ------------------------------------------------------------------- */ -static void dz_flush_buffer (struct tty_struct *tty) +static void dz_flush_buffer(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - + struct dz_serial *info = (struct dz_serial *) tty->driver_data; + cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible (&tty->write_wait); + wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); } /* @@ -821,17 +814,17 @@ * incoming characters should be throttled (or not). * ------------------------------------------------------------ */ -static void dz_throttle (struct tty_struct *tty) +static void dz_throttle(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (I_IXOFF(tty)) info->x_char = STOP_CHAR(tty); } -static void dz_unthrottle (struct tty_struct *tty) +static void dz_unthrottle(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (I_IXOFF(tty)) { if (info->x_char) @@ -841,9 +834,9 @@ } } -static void dz_send_xchar (struct tty_struct *tty, char ch) +static void dz_send_xchar(struct tty_struct *tty, char ch) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; info->x_char = ch; @@ -860,11 +853,11 @@ struct serial_struct *retinfo) { struct serial_struct tmp; - + if (!retinfo) return -EFAULT; - memset (&tmp, 0, sizeof(tmp)); + memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->line; @@ -878,8 +871,8 @@ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } -static int set_serial_info (struct dz_serial *info, - struct serial_struct *new_info) +static int set_serial_info(struct dz_serial *info, + struct serial_struct *new_info) { struct serial_struct new_serial; struct dz_serial old_info; @@ -910,7 +903,6 @@ info->closing_wait = new_serial.closing_wait; retval = startup(info); - return retval; } @@ -924,17 +916,17 @@ * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. */ -static int get_lsr_info (struct dz_serial *info, unsigned int *value) +static int get_lsr_info(struct dz_serial *info, unsigned int *value) { - unsigned short status = dz_in (info, DZ_LPR); + unsigned short status = dz_in(info, DZ_LPR); - return put_user (status, value); + return put_user(status, value); } /* * This routine sends a break character out the serial port. */ -static void send_break (struct dz_serial *info, int duration) +static void send_break(struct dz_serial *info, int duration) { unsigned long flags; unsigned short tmp, mask; @@ -943,33 +935,36 @@ return; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); + tmp = dz_in(info, DZ_TCR); tmp |= mask; current->state = TASK_INTERRUPTIBLE; - save_and_cli(flags); + save_flags(flags); + cli(); + dz_out(info, DZ_TCR, tmp); + schedule_timeout(duration); + tmp &= ~mask; dz_out(info, DZ_TCR, tmp); + restore_flags(flags); } static int dz_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - int error; - struct dz_serial * info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; int retval; - if (cmd != TIOCGSERIAL && cmd != TIOCSSERIAL && - cmd != TIOCSERCONFIG && cmd != TIOCSERGWILD && - cmd != TIOCSERSWILD && cmd != TIOCSERGSTRUCT) { + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } - switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); @@ -977,7 +972,7 @@ return retval; tty_wait_until_sent(tty, 0); if (!arg) - send_break(info, HZ/4); /* 1/4 second */ + send_break(info, HZ / 4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ @@ -985,41 +980,32 @@ if (retval) return retval; tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); + send_break(info, arg ? arg * (HZ / 10) : HZ / 4); return 0; case TIOCGSOFTCAR: - error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long)); - if (error) - return error; - put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); - return 0; + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); case TIOCSSOFTCAR: - if (get_user (arg, (unsigned long *)arg)) + if (get_user(arg, (unsigned long *) arg)) return -EFAULT; - - tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0); + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); return 0; case TIOCGSERIAL: - error = verify_area(VERIFY_WRITE, (void *)arg, - sizeof(struct serial_struct)); - if (error) - return error; - return get_serial_info(info, (struct serial_struct *)arg); + return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info (info, (unsigned int *)arg); + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: - return copy_to_user((struct dz_serial *)arg, info, - sizeof(struct dz_serial)) ? -EFAULT : 0; - + return copy_to_user((struct dz_serial *) arg, info, + sizeof(struct dz_serial)) ? -EFAULT : 0; + default: return -ENOIOCTLCMD; } @@ -1027,15 +1013,15 @@ return 0; } -static void dz_set_termios (struct tty_struct *tty, - struct termios *old_termios) +static void dz_set_termios(struct tty_struct *tty, + struct termios *old_termios) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (tty->termios->c_cflag == old_termios->c_cflag) return; - change_speed (info); + change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1055,37 +1041,36 @@ */ static void dz_close(struct tty_struct *tty, struct file *filp) { - struct dz_serial * info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; if (!info) return; - - save_and_cli(flags); + + save_flags(flags); + cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } - if ((tty->count == 1) && (info->count != 1)) { /* - * Uh, oh. tty->count is 1, which means that the tty structure - * will be freed. Info->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. + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->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("dz_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } - if (--info->count < 0) { printk("ds_close: bad serial port count for ttyS%02d: %d\n", info->line, info->count); info->count = 0; } - if (info->count) { restore_flags(flags); return; @@ -1100,8 +1085,8 @@ if (info->flags & DZ_CALLOUT_ACTIVE) info->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. + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; @@ -1109,26 +1094,27 @@ 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. + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts. */ + shutdown(info); if (tty->driver.flush_buffer) - tty->driver.flush_buffer (tty); + tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); + tty->ldisc.flush_buffer(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) - tty->ldisc.close(tty); + (tty->ldisc.close) (tty); tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) - tty->ldisc.open(tty); + (tty->ldisc.open) (tty); } if (info->blocked_open) { if (info->close_delay) { @@ -1137,7 +1123,6 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING); wake_up_interruptible(&info->close_wait); @@ -1147,10 +1132,10 @@ /* * dz_hangup () --- called by tty_hangup() when a hangup is signaled. */ -static void dz_hangup (struct tty_struct *tty) +static void dz_hangup(struct tty_struct *tty) { struct dz_serial *info = (struct dz_serial *) tty->driver_data; - + dz_flush_buffer(tty); shutdown(info); info->event = 0; @@ -1165,10 +1150,9 @@ * rs_open() and friends * ------------------------------------------------------------ */ -static int block_til_ready(struct tty_struct *tty, struct file *filp, - struct dz_serial *info) +static int block_til_ready(struct tty_struct *tty, struct file *filp, struct dz_serial *info) { - DECLARE_WAITQUEUE(wait, current); + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; @@ -1180,7 +1164,6 @@ interruptible_sleep_on(&info->close_wait); return -EAGAIN; } - /* * If this is a callout device, then just make sure the normal * device isn't being used. @@ -1188,47 +1171,44 @@ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & DZ_NORMAL_ACTIVE) return -EBUSY; - + if ((info->flags & DZ_CALLOUT_ACTIVE) && (info->flags & DZ_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; - + if ((info->flags & DZ_CALLOUT_ACTIVE) && (info->flags & DZ_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; - info->flags |= DZ_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 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 & DZ_CALLOUT_ACTIVE) return -EBUSY; info->flags |= DZ_NORMAL_ACTIVE; - return 0; } - if (info->flags & DZ_CALLOUT_ACTIVE) { if (info->normal_termios.c_cflag & CLOCAL) do_clocal = 1; } else { if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + 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, - * info->count is dropped by one, so that dz_close() knows when to free - * things. We restore it upon exit, either normal or abnormal. + * 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, info->count is dropped by one, so that + * dz_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait); @@ -1237,7 +1217,7 @@ info->blocked_open++; while (1) { set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p (filp) || !(info->is_initialized)) { + if (tty_hung_up_p(filp) || !(info->is_initialized)) { retval = -EAGAIN; break; } @@ -1250,9 +1230,9 @@ } schedule(); } - + current->state = TASK_RUNNING; - remove_wait_queue (&info->open_wait, &wait); + remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; @@ -1294,37 +1274,36 @@ /* * Start up serial port */ - retval = startup (info); + retval = startup(info); if (retval) return retval; - retval = block_til_ready (tty, filp, info); + retval = block_til_ready(tty, filp, info); if (retval) return retval; if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; - else + else *tty->termios = info->callout_termios; change_speed(info); - } + } info->session = current->session; info->pgrp = current->pgrp; - return 0; } -static void show_serial_version (void) +static void show_serial_version(void) { printk("%s%s\n", dz_name, dz_version); } - int __init dz_init(void) { - int i, flags; + int i, tmp; + long flags; struct dz_serial *info; /* Setup base handler, and timer table. */ @@ -1353,7 +1332,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 = &dz_sercons; +#endif serial_driver.open = dz_open; serial_driver.close = dz_close; serial_driver.write = dz_write; @@ -1371,8 +1352,8 @@ serial_driver.hangup = dz_hangup; /* - * The callout device is just like normal device except for major - * number and the subtype code. + * 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)) @@ -1383,21 +1364,22 @@ callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; - 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"); - - save_flags(flags); cli(); - for (i=0; i < DZ_NB_PORT; i++) { - info = &multi[i]; + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver"); + save_flags(flags); + cli(); + + for (i = 0; i < DZ_NB_PORT; i++) { + info = &multi[i]; lines[i] = info; info->magic = SERIAL_MAGIC; - if ((mips_machtype == MACH_DS23100) || - (mips_machtype == MACH_DS5100)) + if (mips_machtype == MACH_DS23100 || + mips_machtype == MACH_DS5100) info->port = (unsigned long) KN01_DZ11_BASE; - else + else info->port = (unsigned long) KN02_DZ11_BASE; info->line = i; @@ -1414,76 +1396,71 @@ info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); /* * If we are pointing to address zero then punt - not correctly * set up in setup.c to handle this. */ - if (! info->port) + if (!info->port) return 0; printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line, info->port, SERIAL); tty_register_devfs(&serial_driver, 0, - serial_driver.minor_start + info->line); + serial_driver.minor_start + info->line); tty_register_devfs(&callout_driver, 0, - callout_driver.minor_start + info->line); + callout_driver.minor_start + info->line); } - /* Reset the chip */ + /* reset the chip */ #ifndef CONFIG_SERIAL_CONSOLE - { - int tmp; - dz_out(info, DZ_CSR, DZ_CLR); - while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR); - wbflush(); - - /* Enable scanning */ - dz_out(info, DZ_CSR, DZ_MSE); - } + dz_out(info, DZ_CSR, DZ_CLR); + while ((tmp = dz_in(info, DZ_CSR)) & DZ_CLR); + wbflush(); + + /* enable scanning */ + dz_out(info, DZ_CSR, DZ_MSE); #endif - - /* - * Order matters here... the trick is that flags is updated... in - * request_irq - to immediatedly obliterate it is unwise. - */ + + /* order matters here... the trick is that flags + is updated... in request_irq - to immediatedly obliterate + it is unwise. */ restore_flags(flags); + if (request_irq(SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0])) - panic("Unable to register DZ interrupt\n"); - + panic("Unable to register DZ interrupt"); + return 0; } #ifdef CONFIG_SERIAL_CONSOLE -static void dz_console_put_char (unsigned char ch) +static void dz_console_put_char(unsigned char ch) { unsigned long flags; - int loops = 2500; + int loops = 2500; unsigned short tmp = ch; - /* - * this code sends stuff out to serial device - spinning its wheels and - * waiting. - */ + /* this code sends stuff out to serial device - spinning its + wheels and waiting. */ - /* force the issue - point it at lines[3]*/ + /* force the issue - point it at lines[3] */ dz_console = &multi[CONSOLE_LINE]; - save_and_cli(flags); + save_flags(flags); + cli(); + /* spin our wheels */ - while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--) - ; - + while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--); + /* Actually transmit the character. */ dz_out(dz_console, DZ_TDR, tmp); - restore_flags(flags); + restore_flags(flags); } - /* * ------------------------------------------------------------------- * dz_console_print () @@ -1492,12 +1469,12 @@ * The console must be locked when we get here. * ------------------------------------------------------------------- */ -static void dz_console_print (struct console *cons, - const char *str, - unsigned int count) +static void dz_console_print(struct console *cons, + const char *str, + unsigned int count) { #ifdef DEBUG_DZ - prom_printf((char *)str); + prom_printf((char *) str); #endif while (count--) { if (*str == '\n') @@ -1518,7 +1495,7 @@ int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s; - unsigned short mask,tmp; + unsigned short mask, tmp; if (options) { baud = simple_strtoul(options, NULL, 10); @@ -1528,11 +1505,10 @@ if (*s) parity = *s++; if (*s) - bits = *s - '0'; + bits = *s - '0'; } - /* - * Now construct a cflag setting. + * Now construct a cflag setting. */ switch (baud) { case 1200: @@ -1572,18 +1548,17 @@ /* TOFIX: force to console line */ dz_console = &multi[CONSOLE_LINE]; - if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) + if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) dz_console->port = KN01_DZ11_BASE; - else - dz_console->port = KN02_DZ11_BASE; + else + dz_console->port = KN02_DZ11_BASE; dz_console->line = CONSOLE_LINE; dz_out(dz_console, DZ_CSR, DZ_CLR); - while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR) - ; + while ((tmp = dz_in(dz_console, DZ_CSR)) & DZ_CLR); /* enable scanning */ - dz_out(dz_console, DZ_CSR, DZ_MSE); + dz_out(dz_console, DZ_CSR, DZ_MSE); /* Set up flags... */ dz_console->cflags = 0; @@ -1593,16 +1568,16 @@ dz_out(dz_console, DZ_LPR, dz_console->cflags); mask = 1 << dz_console->line; - tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */ + tmp = dz_in(dz_console, DZ_TCR); /* read the TX flag */ if (!(tmp & mask)) { - tmp |= mask; /* set the TX flag */ - dz_out (dz_console, DZ_TCR, tmp); + tmp |= mask; /* set the TX flag */ + dz_out(dz_console, DZ_TCR, tmp); } - return 0; } -static struct console dz_sercons = { +static struct console dz_sercons = +{ name: "ttyS", write: dz_console_print, device: dz_console_device, @@ -1616,6 +1591,6 @@ register_console(&dz_sercons); } -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ +#endif /* CONFIG_SERIAL_CONSOLE */ MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/dz.h linux-2.5/drivers/char/dz.h --- linux-2.5.13/drivers/char/dz.h Fri May 3 01:22:44 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.13/drivers/char/efirtc.c linux-2.5/drivers/char/efirtc.c --- linux-2.5.13/drivers/char/efirtc.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/char/efirtc.c Thu May 2 21:27:25 2002 @@ -375,9 +375,14 @@ static int __init efi_rtc_init(void) { + int ret =0; printk(KERN_INFO "EFI Time Services Driver v%s\n", EFI_RTC_VERSION); - misc_register(&efi_rtc_dev); + ret = misc_register(&efi_rtc_dev); + if (ret) { + printk(KERN_ERR "driver/efirtc: can't misc_register on minor=%d\n", EFI_RTC_MINOR); + return ret; + } create_proc_read_entry ("driver/efirtc", 0, NULL, efi_rtc_read_proc, NULL); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/epca.c linux-2.5/drivers/char/epca.c --- linux-2.5.13/drivers/char/epca.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/char/epca.c Mon Apr 15 01:34:05 2002 @@ -2020,7 +2020,8 @@ (*(ushort *)((ulong)memaddr + XEPORTS) < 3)) shrinkmem = 1; if (bd->type < PCIXEM) - request_region((int)bd->port, 4, board_desc[bd->type]); + if (!request_region((int)bd->port, 4, board_desc[bd->type])) + return; memwinon(bd, 0); @@ -2184,9 +2185,13 @@ if (!(ch->tmp_buf)) { printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i); - + release_region((int)bd->port, 4); + while(i-- > 0) + kfree((ch--)->tmp_buf); + return; } - memset((void *)ch->tmp_buf,0,ch->txbufsize); + else + memset((void *)ch->tmp_buf,0,ch->txbufsize); } /* End for each port */ printk(KERN_INFO diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/esp.c linux-2.5/drivers/char/esp.c --- linux-2.5.13/drivers/char/esp.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/char/esp.c Mon Apr 15 01:34:05 2002 @@ -2476,9 +2476,13 @@ } else *region_start = info->port; - request_region(*region_start, + if (!request_region(*region_start, info->port - *region_start + 8, - "esp serial"); + "esp serial")) + { + restore_flags(flags); + return -EIO; + } /* put card in enhanced mode */ /* this prevents access through */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/ftape/lowlevel/fdc-io.c linux-2.5/drivers/char/ftape/lowlevel/fdc-io.c --- linux-2.5.13/drivers/char/ftape/lowlevel/fdc-io.c Fri May 3 01:22:45 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.13/drivers/char/ftape/zftape/zftape-init.c linux-2.5/drivers/char/ftape/zftape/zftape-init.c --- linux-2.5.13/drivers/char/ftape/zftape/zftape-init.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/char/ftape/zftape/zftape-init.c Tue Feb 12 00:57:58 2002 @@ -28,6 +28,7 @@ #include #include #include +#include #include #ifdef CONFIG_KMOD #include @@ -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.13/drivers/char/generic_serial.c linux-2.5/drivers/char/generic_serial.c --- linux-2.5.13/drivers/char/generic_serial.c Fri May 3 01:22:53 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.13/drivers/char/h8.c linux-2.5/drivers/char/h8.c --- linux-2.5.13/drivers/char/h8.c Fri May 3 01:22:48 2002 +++ linux-2.5/drivers/char/h8.c Mon Apr 15 01:34:05 2002 @@ -299,9 +299,13 @@ } printk(KERN_INFO "H8 at 0x%x IRQ %d\n", h8_base, h8_irq); - create_proc_info_entry("driver/h8", 0, NULL, h8_get_info); + if (!request_region(h8_base, 8, "h8")) + { + free_irq(h8_irq, NULL); + return -EIO; + } - request_region(h8_base, 8, "h8"); + create_proc_info_entry("driver/h8", 0, NULL, h8_get_info); h8_alloc_queues(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/hcdp_serial.c linux-2.5/drivers/char/hcdp_serial.c --- linux-2.5.13/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.13/drivers/char/ib700wdt.c linux-2.5/drivers/char/ib700wdt.c --- linux-2.5.13/drivers/char/ib700wdt.c Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/char/ib700wdt.c Mon Apr 15 01:33:31 2002 @@ -271,11 +271,21 @@ ibwdt_validate_timeout(); spin_lock_init(&ibwdt_lock); - misc_register(&ibwdt_miscdev); + if (misc_register(&ibwdt_miscdev)) + return -ENODEV; #if WDT_START != WDT_STOP - request_region(WDT_STOP, 1, "IB700 WDT"); + if (!request_region(WDT_STOP, 1, "IB700 WDT")) { + misc_deregister(&ibwdt_miscdev); + return -EIO; + } #endif - request_region(WDT_START, 1, "IB700 WDT"); + if (!request_region(WDT_START, 1, "IB700 WDT")) { +#if WDT_START != WDT_STOP + release_region(WDT_STOP, 1); +#endif + misc_deregister(&ibwdt_miscdev); + return -EIO; + } register_reboot_notifier(&ibwdt_notifier); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/indydog.c linux-2.5/drivers/char/indydog.c --- linux-2.5.13/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.13/drivers/char/ip2/i2cmd.c linux-2.5/drivers/char/ip2/i2cmd.c --- linux-2.5.13/drivers/char/ip2/i2cmd.c Fri May 3 01:22:49 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.13/drivers/char/ip2.c linux-2.5/drivers/char/ip2.c --- linux-2.5.13/drivers/char/ip2.c Fri May 3 01:22:53 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.13/drivers/char/ip2main.c linux-2.5/drivers/char/ip2main.c --- linux-2.5.13/drivers/char/ip2main.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/char/ip2main.c Wed May 1 17:26:07 2002 @@ -1002,12 +1002,10 @@ printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1, ip2config.addr[boardnum], ip2config.irq[boardnum] ); - if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) { - printk(KERN_ERR "IP2: bad addr=0x%x rc = %d\n", - ip2config.addr[boardnum], rc ); + if (!request_region( ip2config.addr[boardnum], 8, pcName )) { + printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]); goto err_initialize; } - request_region( ip2config.addr[boardnum], 8, pcName ); if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size ) != II_DOWN_GOOD ) { @@ -2662,7 +2660,7 @@ old_flags = pCh->flags; old_baud_divisor = pCh->BaudDivisor; - if ( !suser() ) { + if ( !capable(CAP_SYS_ADMIN) ) { if ( ( ns.close_delay != pCh->ClosingDelay ) || ( (ns.flags & ~ASYNC_USR_MASK) != (pCh->flags & ~ASYNC_USR_MASK) ) ) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/isicom.c linux-2.5/drivers/char/isicom.c --- linux-2.5.13/drivers/char/isicom.c Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/char/isicom.c Mon Apr 15 01:34:05 2002 @@ -1680,20 +1680,13 @@ { int count, done=0; for (count=0; count < BOARD_COUNT; count++ ) { - if (isi_card[count].base) { - if (check_region(isi_card[count].base,16)) { + if (isi_card[count].base) + if (!request_region(isi_card[count].base,16,ISICOM_NAME)) { printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n", isi_card[count].base,isi_card[count].base+15,count+1); isi_card[count].base=0; - } - else { - request_region(isi_card[count].base,16,ISICOM_NAME); -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x requested for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1); -#endif done++; } - } } return done; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/istallion.c linux-2.5/drivers/char/istallion.c --- linux-2.5.13/drivers/char/istallion.c Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/char/istallion.c Mon Apr 15 01:34:05 2002 @@ -3971,17 +3971,16 @@ printk(KERN_DEBUG "stli_initecp(brdp=%x)\n", (int) brdp); #endif -/* - * Do a basic sanity check on the IO and memory addresses. - */ + if (!request_region(brdp->iobase, brdp->iosize, name)) + return -EIO; + if ((brdp->iobase == 0) || (brdp->memaddr == 0)) + { + release_region(brdp->iobase, brdp->iosize); return(-ENODEV); + } brdp->iosize = ECP_IOSIZE; - if (check_region(brdp->iobase, brdp->iosize)) - printk(KERN_ERR "STALLION: Warning, board %d I/O address %x " - "conflicts with another device\n", - brdp->brdnr, brdp->iobase); /* * Based on the specific board type setup the common vars to access @@ -4046,6 +4045,7 @@ break; default: + release_region(brdp->iobase, brdp->iosize); return(-EINVAL); } @@ -4059,7 +4059,10 @@ brdp->membase = ioremap(brdp->memaddr, brdp->memsize); if (brdp->membase == (void *) NULL) + { + release_region(brdp->iobase, brdp->iosize); return(-ENOMEM); + } /* * Now that all specific code is set up, enable the shared memory and @@ -4081,7 +4084,10 @@ #endif if (sig.magic != ECP_MAGIC) + { + release_region(brdp->iobase, brdp->iosize); return(-ENODEV); + } /* * Scan through the signature looking at the panels connected to the @@ -4102,7 +4108,7 @@ brdp->nrpanels++; } - request_region(brdp->iobase, brdp->iosize, name); + brdp->state |= BST_FOUND; return(0); } @@ -4132,10 +4138,9 @@ return(-ENODEV); brdp->iosize = ONB_IOSIZE; - if (check_region(brdp->iobase, brdp->iosize)) - printk(KERN_ERR "STALLION: Warning, board %d I/O address %x " - "conflicts with another device\n", - brdp->brdnr, brdp->iobase); + + if (!request_region(brdp->iobase, brdp->iosize, name)) + return -EIO; /* * Based on the specific board type setup the common vars to access @@ -4210,6 +4215,7 @@ break; default: + release_region(brdp->iobase, brdp->iosize); return(-EINVAL); } @@ -4223,7 +4229,10 @@ brdp->membase = ioremap(brdp->memaddr, brdp->memsize); if (brdp->membase == (void *) NULL) + { + release_region(brdp->iobase, brdp->iosize); return(-ENOMEM); + } /* * Now that all specific code is set up, enable the shared memory and @@ -4243,7 +4252,10 @@ if ((sig.magic0 != ONB_MAGIC0) || (sig.magic1 != ONB_MAGIC1) || (sig.magic2 != ONB_MAGIC2) || (sig.magic3 != ONB_MAGIC3)) + { + release_region(brdp->iobase, brdp->iosize); return(-ENODEV); + } /* * Scan through the signature alive mask and calculate how many ports @@ -4261,7 +4273,7 @@ } brdp->panels[0] = brdp->nrports; - request_region(brdp->iobase, brdp->iosize, name); + brdp->state |= BST_FOUND; return(0); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/ite_gpio.c linux-2.5/drivers/char/ite_gpio.c --- linux-2.5.13/drivers/char/ite_gpio.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/char/ite_gpio.c Mon Apr 15 01:34:05 2002 @@ -391,13 +391,14 @@ { int i; - misc_register(&ite_gpio_miscdev); + if (misc_register(&ite_gpio_miscdev)) + return -ENODEV; - if (check_region(ite_gpio_base, 0x1c) < 0 ) { - return -ENODEV; - } else { - request_region(ite_gpio_base, 0x1c, "ITE GPIO"); - } + if (!request_region(ite_gpio_base, 0x1c, "ITE GPIO")) + { + misc_deregister(&ite_gpio_miscdev); + return -EIO; + } /* initialize registers */ ITE_GPACR = 0xffff; @@ -407,13 +408,18 @@ ITE_GPBICR = 0x00ff; ITE_GPCICR = 0x00ff; ITE_GCR = 0; - + for (i = 0; i < MAX_GPIO_LINE; i++) { ite_gpio_irq_pending[i]=0; init_waitqueue_head(&ite_gpio_wait[i]); } - if (request_irq(ite_gpio_irq, ite_gpio_irq_handler, SA_SHIRQ, "gpio", 0) < 0) + + if (request_irq(ite_gpio_irq, ite_gpio_irq_handler, SA_SHIRQ, "gpio", 0) < 0) { + misc_deregister(&ite_gpio_miscdev); + release_region(ite_gpio_base, 0x1c); return 0; + } + printk("GPIO at 0x%x (irq = %d)\n", ite_gpio_base, ite_gpio_irq); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/keyboard.c linux-2.5/drivers/char/keyboard.c --- linux-2.5.13/drivers/char/keyboard.c Fri May 3 01:22:50 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.13/drivers/char/lcd.c linux-2.5/drivers/char/lcd.c --- linux-2.5.13/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.13/drivers/char/lcd.h linux-2.5/drivers/char/lcd.h --- linux-2.5.13/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.13/drivers/char/logibusmouse.c linux-2.5/drivers/char/logibusmouse.c --- linux-2.5.13/drivers/char/logibusmouse.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/char/logibusmouse.c Thu Jan 1 01:00:00 1970 @@ -1,166 +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"); -EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/mem.c linux-2.5/drivers/char/mem.c --- linux-2.5.13/drivers/char/mem.c Fri May 3 01:22:53 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.13/drivers/char/misc.c linux-2.5/drivers/char/misc.c --- linux-2.5.13/drivers/char/misc.c Fri May 3 01:22:50 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) @@ -170,7 +170,7 @@ int misc_register(struct miscdevice * misc) { - static devfs_handle_t devfs_handle; + static devfs_handle_t devfs_handle, dir; struct miscdevice *c; if (misc->next || misc->prev) @@ -201,11 +201,12 @@ misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); if (!devfs_handle) devfs_handle = devfs_mk_dir (NULL, "misc", NULL); + dir = strchr (misc->name, '/') ? NULL : devfs_handle; misc->devfs_handle = - devfs_register (devfs_handle, misc->name, DEVFS_FL_NONE, - MISC_MAJOR, misc->minor, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - misc->fops, NULL); + devfs_register (dir, misc->name, DEVFS_FL_NONE, + MISC_MAJOR, misc->minor, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + misc->fops, NULL); /* * Add it to the front, so that later devices can "override" @@ -276,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.13/drivers/char/mixcomwd.c linux-2.5/drivers/char/mixcomwd.c --- linux-2.5.13/drivers/char/mixcomwd.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/char/mixcomwd.c Mon Apr 15 01:34:05 2002 @@ -247,11 +247,15 @@ return -ENODEV; } - request_region(watchdog_port,1,"MixCOM watchdog"); + if (!request_region(watchdog_port,1,"MixCOM watchdog")) + return -EIO; ret = misc_register(&mixcomwd_miscdev); if (ret) + { + release_region(watchdog_port, 1); return ret; + } printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/mk712.c linux-2.5/drivers/char/mk712.c --- linux-2.5.13/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.13/drivers/char/moxa.c linux-2.5/drivers/char/moxa.c --- linux-2.5.13/drivers/char/moxa.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/char/moxa.c Mon Apr 15 02:54:27 2002 @@ -2799,7 +2799,7 @@ (new_serial.baud_base != 921600)) return (-EPERM); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if (((new_serial.flags & ~ASYNC_USR_MASK) != (info->asyncflags & ~ASYNC_USR_MASK))) return (-EPERM); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/msbusmouse.c linux-2.5/drivers/char/msbusmouse.c --- linux-2.5.13/drivers/char/msbusmouse.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/char/msbusmouse.c Thu Jan 1 01:00:00 1970 @@ -1,176 +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"); -EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/mxser.c linux-2.5/drivers/char/mxser.c --- linux-2.5.13/drivers/char/mxser.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/char/mxser.c Mon Apr 15 02:54:27 2002 @@ -2199,7 +2199,7 @@ flags = info->flags & ASYNC_SPD_MASK; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/pc110pad.c linux-2.5/drivers/char/pc110pad.c --- linux-2.5.13/drivers/char/pc110pad.c Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/char/pc110pad.c Thu Jan 1 01:00:00 1970 @@ -1,852 +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"); - -EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/pc110pad.h linux-2.5/drivers/char/pc110pad.h --- linux-2.5.13/drivers/char/pc110pad.h Fri May 3 01:22: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.13/drivers/char/pc_keyb.c linux-2.5/drivers/char/pc_keyb.c --- linux-2.5.13/drivers/char/pc_keyb.c Fri May 3 01:22:51 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,833 +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; - - /* - * 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); - } - -#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.13/drivers/char/pcmcia/serial_cs.c linux-2.5/drivers/char/pcmcia/serial_cs.c --- linux-2.5.13/drivers/char/pcmcia/serial_cs.c Fri May 3 01:22:53 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.13/drivers/char/pcmcia/synclink_cs.c linux-2.5/drivers/char/pcmcia/synclink_cs.c --- linux-2.5.13/drivers/char/pcmcia/synclink_cs.c Fri May 3 01:22:48 2002 +++ linux-2.5/drivers/char/pcmcia/synclink_cs.c Sat Apr 27 04:00:10 2002 @@ -1,5 +1,5 @@ /* - * linux/drivers/char/pcmcia/synclink_cs.c + * linux/drivers/char/synclink_cs.c * * $Id: synclink_cs.c,v 4.2 2002/04/22 14:36:43 paulkf Exp $ * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/pcwd.c linux-2.5/drivers/char/pcwd.c --- linux-2.5.13/drivers/char/pcwd.c Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/char/pcwd.c Mon Apr 15 01:34:05 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. @@ -114,12 +131,6 @@ { int card_dat, prev_card_dat, found = 0, count = 0, done = 0; - /* As suggested by Alan Cox - this is a safety measure. */ - if (check_region(current_readport, 4)) { - printk("pcwd: Port 0x%x unavailable.\n", current_readport); - return 0; - } - card_dat = 0x00; prev_card_dat = 0x00; @@ -127,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 */ @@ -456,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; } @@ -565,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; @@ -628,15 +645,31 @@ outb_p(0xA5, current_readport + 3); } - if (revision == PCWD_REVISION_A) - request_region(current_readport, 2, "PCWD Rev.A (Berkshire)"); - else - request_region(current_readport, 4, "PCWD Rev.C (Berkshire)"); + if (misc_register(&pcwd_miscdev)) + return -ENODEV; + + if (supports_temp) + if (misc_register(&temp_miscdev)) { + misc_deregister(&pcwd_miscdev); + return -ENODEV; + } - misc_register(&pcwd_miscdev); - if (supports_temp) - misc_register(&temp_miscdev); + if (revision == PCWD_REVISION_A) { + if (!request_region(current_readport, 2, "PCWD Rev.A (Berkshire)")) { + misc_deregister(&pcwd_miscdev); + if (supports_temp) + misc_deregister(&pcwd_miscdev); + return -EIO; + } + } + else + if (!request_region(current_readport, 4, "PCWD Rev.C (Berkshire)")) { + misc_deregister(&pcwd_miscdev); + if (supports_temp) + misc_deregister(&pcwd_miscdev); + return -EIO; + } return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/q40_keyb.c linux-2.5/drivers/char/q40_keyb.c --- linux-2.5.13/drivers/char/q40_keyb.c Fri May 3 01:22:53 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.13/drivers/char/qpmouse.c linux-2.5/drivers/char/qpmouse.c --- linux-2.5.13/drivers/char/qpmouse.c Fri May 3 01:22:48 2002 +++ linux-2.5/drivers/char/qpmouse.c Thu Jan 1 01:00:00 1970 @@ -1,382 +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"); -EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/qtronix.c linux-2.5/drivers/char/qtronix.c --- linux-2.5.13/drivers/char/qtronix.c Fri May 3 01:22:49 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.13/drivers/char/raw.c linux-2.5/drivers/char/raw.c --- linux-2.5.13/drivers/char/raw.c Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/char/raw.c Fri May 3 03:49:06 2002 @@ -34,6 +34,7 @@ int raw_open(struct inode *, struct file *); int raw_release(struct inode *, struct file *); int raw_ctl_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +int raw_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static struct file_operations raw_fops = { @@ -41,6 +42,7 @@ write: raw_write, open: raw_open, release: raw_release, + ioctl: raw_ioctl, }; static struct file_operations raw_ctl_fops = { @@ -142,6 +144,25 @@ } + +/* Forward ioctls to the underlying block device. */ +int raw_ioctl(struct inode *inode, + struct file *flip, + unsigned int command, + unsigned long arg) +{ + int minor = minor(inode->i_rdev), err; + struct block_device *b; + if (minor < 1 && minor > 255) + return -ENODEV; + + b = raw_devices[minor].binding; + err = -EINVAL; + if (b && b->bd_inode && b->bd_op && b->bd_op->ioctl) { + err = b->bd_op->ioctl(b->bd_inode, NULL, command, arg); + } + return err; +} /* * Deal with ioctls against the raw-device control interface, to bind diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/rio/rio_linux.c linux-2.5/drivers/char/rio/rio_linux.c --- linux-2.5.13/drivers/char/rio/rio_linux.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/char/rio/rio_linux.c Mon Apr 15 02:54:27 2002 @@ -702,7 +702,7 @@ func_enter(); /* The "dev" argument isn't used. */ - rc = -riocontrol (p, 0, cmd, (void *)arg, suser ()); + rc = -riocontrol (p, 0, cmd, (void *)arg, capable(CAP_SYS_ADMIN)); func_exit (); return rc; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/rocket.c linux-2.5/drivers/char/rocket.c --- linux-2.5.13/drivers/char/rocket.c Fri May 3 01:22: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) { @@ -1238,11 +1236,7 @@ if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT; -#ifdef CAP_SYS_ADMIN if (!capable(CAP_SYS_ADMIN)) -#else - if (!suser()) -#endif { if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) @@ -1334,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"); @@ -1798,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; @@ -1876,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); } @@ -1920,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); } @@ -2012,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 @@ -2075,6 +2083,7 @@ if (retval < 0) { printk("Couldn't install Rocketport callout driver " "(error %d)\n", -retval); + release_region(controller, 4); return -1; } @@ -2082,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.13/drivers/char/rocket_int.h linux-2.5/drivers/char/rocket_int.h --- linux-2.5.13/drivers/char/rocket_int.h Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/char/rocket_int.h Thu May 2 22:24:26 2002 @@ -185,7 +185,7 @@ /* Old clock prescale definition and baud rates associated with it */ -#define CLOCK_PRESC 0x19 /* mod 9 (divide by 10) prescale */ +#define CLOCK_PRESC 0x19 /* mod 9 (divide by 10) prescale */ #define BRD50 4607 #define BRD75 3071 #define BRD110 2094 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/rtc.c linux-2.5/drivers/char/rtc.c --- linux-2.5.13/drivers/char/rtc.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/char/rtc.c Fri May 3 03:49:06 2002 @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -140,6 +141,7 @@ static unsigned long rtc_status = 0; /* bitmapped status byte. */ static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ static unsigned long rtc_irq_data = 0; /* our output to the world */ +static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ #if RTC_IRQ static spinlock_t rtc_task_lock = SPIN_LOCK_UNLOCKED; @@ -198,6 +200,38 @@ #endif /* + * sysctl-tuning infrastructure. + */ +static ctl_table rtc_table[] = { + { 1, "max-user-freq", &rtc_max_user_freq, sizeof(int), 0644, NULL, + &proc_dointvec, NULL, }, + { 0, } +}; + +static ctl_table rtc_root[] = { + { 1, "rtc", NULL, 0, 0555, rtc_table, }, + { 0, } +}; + +static ctl_table dev_root[] = { + { CTL_DEV, "dev", NULL, 0, 0555, rtc_root, }, + { 0, } +}; + +static struct ctl_table_header *sysctl_header; + +static int __init init_sysctl(void) +{ + sysctl_header = register_sysctl_table(dev_root, 0); + return 0; +} + +static void __exit cleanup_sysctl(void) +{ + unregister_sysctl_table(sysctl_header); +} + +/* * Now all the various file operations that we export. */ @@ -305,7 +339,8 @@ * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ - if (!kernel && (rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (rtc_freq > rtc_max_user_freq) && + (!capable(CAP_SYS_RESOURCE))) return -EACCES; if (!(rtc_status & RTC_TIMER_ON)) { @@ -503,7 +538,7 @@ * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if (!kernel && (arg > 64) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; while (arg > (1<, + * 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.13/drivers/char/sc520_wdt.c linux-2.5/drivers/char/sc520_wdt.c --- linux-2.5.13/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.13/drivers/char/selection.c linux-2.5/drivers/char/selection.c --- linux-2.5.13/drivers/char/selection.c Fri May 3 01:22:51 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.13/drivers/char/serial.c linux-2.5/drivers/char/serial.c --- linux-2.5.13/drivers/char/serial.c Fri May 3 01:22:47 2002 +++ linux-2.5/drivers/char/serial.c Fri May 3 03:49:06 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, @@ -5413,6 +5420,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; @@ -5424,7 +5432,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; @@ -5638,6 +5648,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) { @@ -5945,6 +5956,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.13/drivers/char/serial167.c linux-2.5/drivers/char/serial167.c --- linux-2.5.13/drivers/char/serial167.c Fri May 3 01:22:51 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 @@ -1472,7 +1473,7 @@ return -EFAULT; old_info = *info; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.close_delay != info->close_delay) || ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) @@ -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.13/drivers/char/serial_21285.c linux-2.5/drivers/char/serial_21285.c --- linux-2.5.13/drivers/char/serial_21285.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/char/serial_21285.c Sun Jan 6 01:38:27 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.13/drivers/char/serial_amba.c linux-2.5/drivers/char/serial_amba.c --- linux-2.5.13/drivers/char/serial_amba.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/char/serial_amba.c Sun Mar 3 23:50:42 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.13/drivers/char/serial_tx3912.c linux-2.5/drivers/char/serial_tx3912.c --- linux-2.5.13/drivers/char/serial_tx3912.c Fri May 3 01:22:54 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.13/drivers/char/serial_tx3912.h linux-2.5/drivers/char/serial_tx3912.h --- linux-2.5.13/drivers/char/serial_tx3912.h Fri May 3 01:22:44 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.13/drivers/char/serial_txx927.c linux-2.5/drivers/char/serial_txx927.c --- linux-2.5.13/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.13/drivers/char/sh-sci.c linux-2.5/drivers/char/sh-sci.c --- linux-2.5.13/drivers/char/sh-sci.c Fri May 3 01:22:51 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.13/drivers/char/sonypi.c linux-2.5/drivers/char/sonypi.c --- linux-2.5.13/drivers/char/sonypi.c Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/char/sonypi.c Wed May 1 20:41:20 2002 @@ -485,12 +485,10 @@ static int sonypi_misc_open(struct inode * inode, struct file * file) { down(&sonypi_device.lock); - if (sonypi_device.open_count) - goto out; + /* Flush input queue on first open */ + if (!sonypi_device.open_count) + sonypi_initq(); sonypi_device.open_count++; - /* Flush input queue */ - sonypi_initq(); -out: up(&sonypi_device.lock); return 0; } @@ -718,9 +716,12 @@ SONYPI_DRIVER_MAJORVERSION, SONYPI_DRIVER_MINORVERSION); printk(KERN_INFO "sonypi: detected %s model, " - "camera = %s, compat = %s, nojogdial = %s\n", + "verbose = %s, fnkeyinit = %s, camera = %s, " + "compat = %s, nojogdial = %s\n", (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ? "type1" : "type2", + verbose ? "on" : "off", + fnkeyinit ? "on" : "off", camera ? "on" : "off", compat ? "on" : "off", nojogdial ? "on" : "off"); @@ -779,7 +780,7 @@ #ifndef MODULE static int __init sonypi_setup(char *str) { - int ints[6]; + int ints[7]; str = get_options(str, ARRAY_SIZE(ints), ints); if (ints[0] <= 0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/sonypi.h linux-2.5/drivers/char/sonypi.h --- linux-2.5.13/drivers/char/sonypi.h Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/char/sonypi.h Thu May 2 22:25:19 2002 @@ -35,7 +35,7 @@ #ifdef __KERNEL__ #define SONYPI_DRIVER_MAJORVERSION 1 -#define SONYPI_DRIVER_MINORVERSION 11 +#define SONYPI_DRIVER_MINORVERSION 13 #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/sx.c linux-2.5/drivers/char/sx.c --- linux-2.5.13/drivers/char/sx.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/char/sx.c Fri May 3 03:49:06 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; @@ -2181,13 +2192,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; @@ -2203,7 +2221,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"); @@ -2551,6 +2569,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.13/drivers/char/sx.h linux-2.5/drivers/char/sx.h --- linux-2.5.13/drivers/char/sx.h Fri May 3 01:22:44 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.13/drivers/char/sxboards.h linux-2.5/drivers/char/sxboards.h --- linux-2.5.13/drivers/char/sxboards.h Fri May 3 01:22: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.13/drivers/char/synclink.c linux-2.5/drivers/char/synclink.c --- linux-2.5.13/drivers/char/synclink.c Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/char/synclink.c Mon Apr 15 03:27:25 2002 @@ -64,7 +64,6 @@ #define MAX_PCI_DEVICES 10 #define MAX_TOTAL_DEVICES 20 -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/sysrq.c linux-2.5/drivers/char/sysrq.c --- linux-2.5.13/drivers/char/sysrq.c Fri May 3 01:22:47 2002 +++ linux-2.5/drivers/char/sysrq.c Sat Mar 23 22:53:20 2002 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -32,7 +32,6 @@ #include -extern void reset_vc(unsigned int); extern struct list_head super_blocks; /* Whether we react on sysrq keys or just ignore them */ @@ -43,7 +42,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; @@ -60,10 +60,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, @@ -75,9 +79,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, @@ -88,7 +95,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 = { @@ -97,8 +105,6 @@ action_msg: "Resetting", }; - - /* SYNC SYSRQ HANDLERS BLOCK */ /* do_emergency_sync helper function */ @@ -218,7 +224,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(); } @@ -229,7 +236,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(); } @@ -245,7 +253,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); } @@ -257,7 +266,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 = { @@ -266,9 +276,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 = { @@ -290,13 +300,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; } @@ -307,7 +318,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; } @@ -416,13 +428,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(); } @@ -433,7 +445,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; @@ -449,7 +462,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.13/drivers/char/tty_io.c linux-2.5/drivers/char/tty_io.c --- linux-2.5.13/drivers/char/tty_io.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/char/tty_io.c Fri May 3 03:49:06 2002 @@ -156,6 +156,8 @@ extern void sci_console_init(void); extern void tx3912_console_init(void); extern void tx3912_rs_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)) @@ -691,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(); @@ -1370,7 +1377,7 @@ retval = -ENODEV; filp->f_flags = saved_flags; - if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser()) + if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) retval = -EBUSY; if (retval) { @@ -1472,7 +1479,7 @@ { char ch, mbz = 0; - if ((current->tty != tty) && !suser()) + if ((current->tty != tty) && !capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(ch, arg)) return -EFAULT; @@ -1510,7 +1517,7 @@ { if (IS_SYSCONS_DEV(inode->i_rdev) || IS_CONSOLE_DEV(inode->i_rdev)) { - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; redirect = NULL; return 0; @@ -1552,7 +1559,7 @@ * This tty is already the controlling * tty for another session group! */ - if ((arg == 1) && suser()) { + if ((arg == 1) && capable(CAP_SYS_ADMIN)) { /* * Steal it away */ @@ -1835,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; } @@ -1848,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; } @@ -2179,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) @@ -2234,6 +2240,12 @@ #ifdef CONFIG_SERIAL_TX3912_CONSOLE tx3912_console_init(); #endif +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + txx927_console_init(); +#endif +#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE + sb1250_serial_console_init(); +#endif } static struct tty_driver dev_tty_driver, dev_syscons_driver; @@ -2241,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 /* @@ -2283,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"; @@ -2313,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.13/drivers/char/vc_screen.c linux-2.5/drivers/char/vc_screen.c --- linux-2.5.13/drivers/char/vc_screen.c Fri May 3 01:22:46 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.13/drivers/char/vme_scc.c linux-2.5/drivers/char/vme_scc.c --- linux-2.5.13/drivers/char/vme_scc.c Fri May 3 01:22:38 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.13/drivers/char/vt.c linux-2.5/drivers/char/vt.c --- linux-2.5.13/drivers/char/vt.c Fri May 3 01:22:55 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 super-user. - */ - perm = 0; - if (current->tty == tty || suser()) - 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_ADMIN)) - 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_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); +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 (!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; + 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.13/drivers/char/vt_ioctl.c linux-2.5/drivers/char/vt_ioctl.c --- linux-2.5.13/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.13/drivers/char/w83877f_wdt.c linux-2.5/drivers/char/w83877f_wdt.c --- linux-2.5.13/drivers/char/w83877f_wdt.c Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/char/w83877f_wdt.c Sun Apr 14 21:52:02 2002 @@ -13,9 +13,10 @@ * 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 + * (c) Copyright 2001 Scott Jennings * * 4/19 - 2001 [Initial revision] + * 9/27 - 2001 Added spinlocking * * * Theory of operation: @@ -88,8 +89,9 @@ static void wdt_timer_ping(unsigned long); static struct timer_list timer; static unsigned long next_heartbeat; -static int wdt_is_open; +static unsigned long wdt_is_open; static int wdt_expect_close; +static spinlock_t wdt_spinlock; /* * Whack the dog @@ -102,11 +104,18 @@ */ if(time_before(jiffies, next_heartbeat)) { + /* Ping the WDT */ + spin_lock(&wdt_spinlock); + /* Ping the WDT by reading from WDT_PING */ inb_p(WDT_PING); + /* Re-set the timer interval */ timer.expires = jiffies + WDT_INTERVAL; add_timer(&timer); + + spin_unlock(&wdt_spinlock); + } else { printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); } @@ -118,19 +127,24 @@ static void wdt_change(int writeval) { + unsigned long flags; + spin_lock_irqsave(&wdt_spinlock, flags); + /* buy some time */ inb_p(WDT_PING); /* make W83877F available */ - outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT); - outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT); + outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT); + outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT); /* enable watchdog */ - outb_p(WDT_REGISTER,ENABLE_W83877F_PORT); - outb_p(writeval,ENABLE_W83877F_PORT+1); + outb_p(WDT_REGISTER, ENABLE_W83877F_PORT); + outb_p(writeval, ENABLE_W83877F_PORT+1); /* lock the W8387FF away */ - outb_p(DISABLE_W83877F,ENABLE_W83877F_PORT); + outb_p(DISABLE_W83877F, ENABLE_W83877F_PORT); + + spin_unlock_irqrestore(&wdt_spinlock, flags); } static void wdt_startup(void) @@ -178,7 +192,7 @@ /* now scan */ for(ofs = 0; ofs != count; ofs++) - if(buf[ofs] == 'V') + if(buf[ofs] == 'V') wdt_expect_close = 1; /* someone wrote to us, we should restart timer */ @@ -200,10 +214,10 @@ { case WATCHDOG_MINOR: /* Just in case we're already talking to someone... */ - if(wdt_is_open) + if(test_and_set_bit(0, &wdt_is_open)) { return -EBUSY; + } /* Good, fire up the show */ - wdt_is_open = 1; wdt_startup(); return 0; @@ -305,6 +319,8 @@ { int rc = -EBUSY; + spin_lock_init(&wdt_spinlock); + if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) goto err_out; if (!request_region(WDT_PING, 1, "W8387FF WDT")) @@ -339,4 +355,7 @@ module_init(w83877f_wdt_init); module_exit(w83877f_wdt_unload); +MODULE_AUTHOR("Scott and Bill Jennings"); +MODULE_DESCRIPTION("Driver for watchdog timer in w83877f chip"); MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/char/wafer5823wdt.c linux-2.5/drivers/char/wafer5823wdt.c --- linux-2.5.13/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.13/drivers/char/wdt285.c linux-2.5/drivers/char/wdt285.c --- linux-2.5.13/drivers/char/wdt285.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/char/wdt285.c Sat Apr 13 17:42:55 2002 @@ -136,11 +136,9 @@ default: return -ENOTTY; case WDIOC_GETSUPPORT: - i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info)); - if (i) - return i; - else - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); + 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); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/hotplug/Makefile linux-2.5/drivers/hotplug/Makefile --- linux-2.5.13/drivers/hotplug/Makefile Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/hotplug/Makefile Mon Apr 15 00:32:41 2002 @@ -28,5 +28,5 @@ cpqphp-objs += cpqphp_nvram.o endif - include $(TOPDIR)/Rules.make + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/hotplug/cpqphp_ctrl.c linux-2.5/drivers/hotplug/cpqphp_ctrl.c --- linux-2.5.13/drivers/hotplug/cpqphp_ctrl.c Fri May 3 01:22:48 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.13/drivers/i2c/Config.help linux-2.5/drivers/i2c/Config.help --- linux-2.5.13/drivers/i2c/Config.help Fri May 3 01:22:44 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.13/drivers/i2c/Config.in linux-2.5/drivers/i2c/Config.in --- linux-2.5.13/drivers/i2c/Config.in Fri May 3 01:22:57 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.13/drivers/i2c/Makefile linux-2.5/drivers/i2c/Makefile --- linux-2.5.13/drivers/i2c/Makefile Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/i2c/Makefile Thu Dec 27 16:32:31 2001 @@ -18,6 +18,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.13/drivers/i2c/i2c-adap-ite.c linux-2.5/drivers/i2c/i2c-adap-ite.c --- linux-2.5.13/drivers/i2c/i2c-adap-ite.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/i2c/i2c-adap-ite.c Sun Mar 3 17:54:35 2002 @@ -241,7 +241,7 @@ }; /* Called when the module is loaded. This function starts the - * cascade of calls up through the heirarchy of i2c modules (i.e. up to the + * cascade of calls up through the hierarchy of i2c modules (i.e. up to the * algorithm layer and into to the core layer) */ static int __init iic_ite_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/i2c/i2c-keywest.c linux-2.5/drivers/i2c/i2c-keywest.c --- linux-2.5.13/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.13/drivers/i2c/i2c-keywest.h linux-2.5/drivers/i2c/i2c-keywest.h --- linux-2.5.13/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.13/drivers/ide/Config.help linux-2.5/drivers/ide/Config.help --- linux-2.5.13/drivers/ide/Config.help Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/ide/Config.help Fri May 3 18:06:54 2002 @@ -751,6 +751,37 @@ Generally say N here. +CONFIG_BLK_DEV_IDE_TCQ + Support for tagged command queueing on ATA disk drives. This enables + the IDE layer to have multiple in-flight requests on hardware that + supports it. For now this includes the IBM Deskstar series drives, + such as the 22GXP, 75GXP, 40GV, 60GXP, and 120GXP (ie any Deskstar made + in the last couple of years), and at least some of the Western + Digital drives in the Expert series (by nature of really being IBM + drives). + + If you have such a drive, say Y here. + +CONFIG_BLK_DEV_IDE_TCQ_DEPTH + Maximum size of commands to enable per-drive. Any value between 1 + and 32 is valid, with 32 being the maxium that the hardware supports. + + You probably just want the default of 32 here. If you enter an invalid + number, the default value will be used. + +CONFIG_BLK_DEV_IDE_TCQ_DEFAULT + Enabled tagged command queueing unconditionally on drives that report + support for it. Regardless of the chosen value here, tagging can be + controlled at run time: + + echo "using_tcq:32" > /proc/ide/hdX/settings + + where any value between 1-32 selects chosen queue depth and enables + TCQ, and 0 disables it. hdparm version 4.7 an above also support + TCQ manipulations. + + Generally say Y here. + CONFIG_BLK_DEV_IT8172 Say Y here to support the on-board IDE controller on the Integrated Technology Express, Inc. ITE8172 SBC. Vendor page at diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/Config.in linux-2.5/drivers/ide/Config.in --- linux-2.5.13/drivers/ide/Config.in Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/ide/Config.in Fri May 3 18:06:54 2002 @@ -47,6 +47,11 @@ dep_bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' ATA tagged command queueing (EXPERIMENTAL)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL + dep_bool ' TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ + if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then + int ' Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32 + fi dep_bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_EXPERIMENTAL dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/Makefile linux-2.5/drivers/ide/Makefile --- linux-2.5.13/drivers/ide/Makefile Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/ide/Makefile Fri May 3 18:06:54 2002 @@ -44,6 +44,7 @@ ide-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI) += ide-dma.o +ide-obj-$(CONFIG_BLK_DEV_IDE_TCQ) += tcq.o ide-obj-$(CONFIG_BLK_DEV_IDEPCI) += ide-pci.o ide-obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += ide-pmac.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/hd.c linux-2.5/drivers/ide/hd.c --- linux-2.5.13/drivers/ide/hd.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/ide/hd.c Fri May 3 12:57:30 2002 @@ -66,6 +66,7 @@ static int revalidate_hddisk(kdev_t, int); +#define TIMEOUT_VALUE (6*HZ) #define HD_DELAY 0 #define MAX_ERRORS 16 /* Max read/write errors/sector */ @@ -827,7 +828,7 @@ printk("hd: unable to get major %d for hard disk\n",MAJOR_NR); return -1; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &hd_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock); blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255); add_gendisk(&hd_gendisk); init_timer(&device_timer); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/hpt34x.c linux-2.5/drivers/ide/hpt34x.c --- linux-2.5.13/drivers/ide/hpt34x.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/ide/hpt34x.c Fri May 3 18:06:38 2002 @@ -249,14 +249,14 @@ ide_dma_off_quietly); } -static int config_drive_xfer_rate (ide_drive_t *drive) +static int config_drive_xfer_rate(struct ata_device *drive, struct request *rq) { struct hd_driveid *id = drive->id; ide_dma_action_t dma_func = ide_dma_on; if (id && (id->capability & 1) && drive->channel->autodma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) { + if (ide_dmaproc(ide_dma_bad_drive, drive, rq)) { dma_func = ide_dma_off; goto fast_ata_pio; } @@ -278,7 +278,7 @@ if (dma_func != ide_dma_on) goto no_dma_set; } - } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + } else if (ide_dmaproc(ide_dma_good_drive, drive, rq)) { if (id->eide_dma_time > 150) { goto no_dma_set; } @@ -301,7 +301,7 @@ dma_func = ide_dma_off; #endif /* CONFIG_HPT34X_AUTODMA */ - return drive->channel->dmaproc(dma_func, drive); + return drive->channel->udma(dma_func, drive, rq); } /* @@ -312,7 +312,7 @@ * by HighPoint|Triones Technologies, Inc. */ -int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +int hpt34x_dmaproc (ide_dma_action_t func, struct ata_device *drive, struct request *rq) { struct ata_channel *hwif = drive->channel; unsigned long dma_base = hwif->dma_base; @@ -321,7 +321,7 @@ switch (func) { case ide_dma_check: - return config_drive_xfer_rate(drive); + return config_drive_xfer_rate(drive, rq); case ide_dma_read: reading = 1 << 3; case ide_dma_write: @@ -347,7 +347,7 @@ default: break; } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ + return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ } #endif /* CONFIG_BLK_DEV_IDEDMA */ @@ -423,7 +423,7 @@ else hwif->autodma = 0; - hwif->dmaproc = &hpt34x_dmaproc; + hwif->udma = &hpt34x_dmaproc; hwif->highmem = 1; } else { hwif->drives[0].autotune = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/hpt366.c linux-2.5/drivers/ide/hpt366.c --- linux-2.5.13/drivers/ide/hpt366.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/ide/hpt366.c Fri May 3 18:06:54 2002 @@ -346,8 +346,6 @@ static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev); static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev); byte hpt366_proc = 0; -byte hpt363_shared_irq; -byte hpt363_shared_pin; extern char *ide_xfer_verbose (byte xfer_rate); #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/ide-disk.c linux-2.5/drivers/ide/ide-disk.c --- linux-2.5.13/drivers/ide/ide-disk.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/ide/ide-disk.c Fri May 3 18:06:54 2002 @@ -1,11 +1,12 @@ -/* - * Copyright (C) 1994-1998 Linus Torvalds and authors: +/***** vi:set ts=8 sts=8 sw=8:************************************************ + * + * Copyright (C) 1994-1998,2002 Linus Torvalds and authors: * - * Mark Lord - * Gadi Oxman - * Andre Hedrick - * Jens Axboe - * Marcin Dalecki + * Mark Lord + * Gadi Oxman + * Andre Hedrick + * Jens Axboe + * Marcin Dalecki * * This is the ATA disk device driver, as evolved from hd.c and ide.c. */ @@ -98,6 +99,8 @@ if (lba48bit) { if (cmd == READ) { + if (drive->using_tcq) + return WIN_READDMA_QUEUED_EXT; if (drive->using_dma) return WIN_READDMA_EXT; else if (drive->mult_count) @@ -105,6 +108,8 @@ else return WIN_READ_EXT; } else if (cmd == WRITE) { + if (drive->using_tcq) + return WIN_WRITEDMA_QUEUED_EXT; if (drive->using_dma) return WIN_WRITEDMA_EXT; else if (drive->mult_count) @@ -114,6 +119,8 @@ } } else { if (cmd == READ) { + if (drive->using_tcq) + return WIN_READDMA_QUEUED; if (drive->using_dma) return WIN_READDMA; else if (drive->mult_count) @@ -121,6 +128,8 @@ else return WIN_READ; } else if (cmd == WRITE) { + if (drive->using_tcq) + return WIN_WRITEDMA_QUEUED; if (drive->using_dma) return WIN_WRITEDMA; else if (drive->mult_count) @@ -148,7 +157,11 @@ memset(&args, 0, sizeof(args)); - args.taskfile.sector_count = sectors; + if (blk_rq_tagged(rq)) { + args.taskfile.feature = sectors; + args.taskfile.sector_count = rq->tag << 3; + } else + args.taskfile.sector_count = sectors; args.taskfile.sector_number = sect; args.taskfile.low_cylinder = cyl; @@ -184,7 +197,12 @@ memset(&args, 0, sizeof(args)); - args.taskfile.sector_count = sectors; + if (blk_rq_tagged(rq)) { + args.taskfile.feature = sectors; + args.taskfile.sector_count = rq->tag << 3; + } else + args.taskfile.sector_count = sectors; + args.taskfile.sector_number = block; args.taskfile.low_cylinder = (block >>= 8); @@ -226,8 +244,14 @@ memset(&args, 0, sizeof(args)); - args.taskfile.sector_count = sectors; - args.hobfile.sector_count = sectors >> 8; + if (blk_rq_tagged(rq)) { + args.taskfile.feature = sectors; + args.hobfile.feature = sectors >> 8; + args.taskfile.sector_count = rq->tag << 3; + } else { + args.taskfile.sector_count = sectors; + args.hobfile.sector_count = sectors >> 8; + } args.taskfile.sector_number = block; /* low lba */ args.taskfile.low_cylinder = (block >>= 8); /* mid lba */ @@ -285,6 +309,30 @@ return promise_rw_disk(drive, rq, block); } + /* + * start a tagged operation + */ + if (drive->using_tcq) { + unsigned long flags; + int ret; + + spin_lock_irqsave(&ide_lock, flags); + + ret = blk_queue_start_tag(&drive->queue, rq); + + if (ata_pending_commands(drive) > drive->max_depth) + drive->max_depth = ata_pending_commands(drive); + if (ata_pending_commands(drive) > drive->max_last_depth) + drive->max_last_depth = ata_pending_commands(drive); + + spin_unlock_irqrestore(&ide_lock, flags); + + if (ret) { + BUG_ON(!ata_pending_commands(drive)); + return ide_started; + } + } + /* 48-bit LBA */ if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) return lba48_do_request(drive, rq, block); @@ -542,11 +590,61 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +#ifdef CONFIG_BLK_DEV_IDE_TCQ +static int proc_idedisk_read_tcq + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + char *out = page; + int len, cmds, i; + unsigned long flags; + + if (!blk_queue_tagged(&drive->queue)) { + len = sprintf(out, "not configured\n"); + PROC_IDE_READ_RETURN(page, start, off, count, eof, len); + } + + spin_lock_irqsave(&ide_lock, flags); + + len = sprintf(out, "TCQ currently on:\t%s\n", drive->using_tcq ? "yes" : "no"); + len += sprintf(out+len, "Max queue depth:\t%d\n",drive->queue_depth); + len += sprintf(out+len, "Max achieved depth:\t%d\n",drive->max_depth); + len += sprintf(out+len, "Max depth since last:\t%d\n",drive->max_last_depth); + len += sprintf(out+len, "Current depth:\t\t%d\n", ata_pending_commands(drive)); + len += sprintf(out+len, "Active tags:\t\t[ "); + for (i = 0, cmds = 0; i < drive->queue_depth; i++) { + struct request *rq = blk_queue_tag_request(&drive->queue, i); + + if (!rq) + continue; + + len += sprintf(out+len, "%d, ", i); + cmds++; + } + len += sprintf(out+len, "]\n"); + + len += sprintf(out+len, "Queue:\t\t\treleased [ %lu ] - started [ %lu ]\n", drive->immed_rel, drive->immed_comp); + + if (ata_pending_commands(drive) != cmds) + len += sprintf(out+len, "pending request and queue count mismatch (counted: %d)\n", cmds); + + len += sprintf(out+len, "DMA status:\t\t%srunning\n", test_bit(IDE_DMA, &HWGROUP(drive)->flags) ? "" : "not "); + + drive->max_last_depth = 0; + + spin_unlock_irqrestore(&ide_lock, flags); + PROC_IDE_READ_RETURN(page, start, off, count, eof, len); +} +#endif + static ide_proc_entry_t idedisk_proc[] = { { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL }, { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL }, { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_smart_values, NULL }, { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_smart_thresholds, NULL }, +#ifdef CONFIG_BLK_DEV_IDE_TCQ + { "tcq", S_IFREG|S_IRUSR, proc_idedisk_read_tcq, NULL }, +#endif { NULL, 0, NULL, NULL } }; @@ -633,6 +731,32 @@ return 0; } +#ifdef CONFIG_BLK_DEV_IDE_TCQ +static int set_using_tcq(ide_drive_t *drive, int arg) +{ + if (!drive->driver) + return -EPERM; + if (!drive->channel->udma) + return -EPERM; + if (arg == drive->queue_depth && drive->using_tcq) + return 0; + + /* + * set depth, but check also id for max supported depth + */ + drive->queue_depth = arg ? arg : 1; + if (drive->id) { + if (drive->queue_depth > drive->id->queue_depth + 1) + drive->queue_depth = drive->id->queue_depth + 1; + } + + if (drive->channel->udma(arg ? ide_dma_queued_on : ide_dma_queued_off, drive, NULL)) + return -EIO; + + return 0; +} +#endif + static int probe_lba_addressing (ide_drive_t *drive, int arg) { drive->addressing = 0; @@ -664,6 +788,9 @@ ide_add_setting(drive, "acoustic", SETTING_RW, HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic); ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL); ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); +#ifdef CONFIG_BLK_DEV_IDE_TCQ + ide_add_setting(drive, "using_tcq", SETTING_RW, HDIO_GET_QDMA, HDIO_SET_QDMA, TYPE_BYTE, 0, IDE_MAX_TAG, 1, 1, &drive->using_tcq, set_using_tcq); +#endif } static int idedisk_suspend(struct device *dev, u32 state, u32 level) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/ide-dma.c linux-2.5/drivers/ide/ide-dma.c --- linux-2.5.13/drivers/ide/ide-dma.c Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/ide/ide-dma.c Fri May 3 18:06:54 2002 @@ -522,6 +522,32 @@ blk_queue_bounce_limit(&drive->queue, addr); } +int ide_start_dma(ide_dma_action_t func, struct ata_device *drive) +{ + struct ata_channel *hwif = drive->channel; + unsigned long dma_base = hwif->dma_base; + unsigned int reading = 0; + + if (rq_data_dir(HWGROUP(drive)->rq) == READ) + reading = 1 << 3; + + /* active tuning based on IO direction */ + if (hwif->rwproc) + hwif->rwproc(drive, func); + + /* + * try PIO instead of DMA + */ + if (!ide_build_dmatable(drive, func)) + return 1; + + outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */ + outb(reading, dma_base); /* specify r/w */ + outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + drive->waiting_for_dma = 1; + return 0; +} + /* * This initiates/aborts DMA read/write operations on a drive. * @@ -543,7 +569,7 @@ struct ata_channel *hwif = drive->channel; unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); - unsigned int count, reading = 0, set_high = 1; + unsigned int reading = 0, set_high = 1; byte dma_stat; switch (func) { @@ -552,27 +578,27 @@ case ide_dma_off_quietly: set_high = 0; outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); +#ifdef CONFIG_BLK_DEV_IDE_TCQ + hwif->udma(ide_dma_queued_off, drive, rq); +#endif case ide_dma_on: ide_toggle_bounce(drive, set_high); drive->using_dma = (func == ide_dma_on); - if (drive->using_dma) + if (drive->using_dma) { outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT + hwif->udma(ide_dma_queued_on, drive, rq); +#endif + } return 0; case ide_dma_check: return config_drive_for_dma (drive); case ide_dma_read: reading = 1 << 3; case ide_dma_write: - /* active tuning based on IO direction */ - if (hwif->rwproc) - hwif->rwproc(drive, func); - - if (!(count = ide_build_dmatable(drive, func))) - return 1; /* try PIO instead of DMA */ - outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */ - outb(reading, dma_base); /* specify r/w */ - outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ - drive->waiting_for_dma = 1; + if (ide_start_dma(func, drive)) + return 1; + if (drive->type != ATA_DISK) return 0; @@ -587,6 +613,14 @@ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); } return drive->channel->udma(ide_dma_begin, drive, NULL); +#ifdef CONFIG_BLK_DEV_IDE_TCQ + case ide_dma_queued_on: + case ide_dma_queued_off: + case ide_dma_read_queued: + case ide_dma_write_queued: + case ide_dma_queued_start: + return ide_tcq_dmaproc(func, drive, rq); +#endif case ide_dma_begin: /* Note that this is done *after* the cmd has * been issued to the drive, as per the BM-IDE spec. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/ide-pci.c linux-2.5/drivers/ide/ide-pci.c --- linux-2.5.13/drivers/ide/ide-pci.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/ide/ide-pci.c Fri May 3 18:06:38 2002 @@ -1,6 +1,8 @@ -/* - * Copyright (c) 1998-2000 Andre Hedrick - * Copyright (c) 1995-1998 Mark Lord +/**** vi:set ts=8 sts=8 sw=8:************************************************ + * + * Copyright (C) 2002 Marcin Dalecki + * Copyright (C) 1998-2000 Andre Hedrick + * Copyright (C) 1995-1998 Mark Lord * * May be copied or modified under the terms of the GNU General Public License */ @@ -81,17 +83,10 @@ #endif #ifdef CONFIG_BLK_DEV_HPT366 -extern byte hpt363_shared_irq; -extern byte hpt363_shared_pin; - extern unsigned int pci_init_hpt366(struct pci_dev *); extern unsigned int ata66_hpt366(struct ata_channel *); extern void ide_init_hpt366(struct ata_channel *); extern void ide_dmacapable_hpt366(struct ata_channel *, unsigned long); -#else -/* FIXME: those have to be killed */ -static byte hpt363_shared_irq; -static byte hpt363_shared_pin; #endif #ifdef CONFIG_BLK_DEV_NS87415 @@ -177,7 +172,7 @@ #define ATA_F_PHACK 0x40 /* apply PROMISE hacks */ #define ATA_F_HPTHACK 0x80 /* apply HPT366 hacks */ -typedef struct ide_pci_device_s { +struct ata_pci_device { unsigned short vendor; unsigned short device; unsigned int (*init_chipset)(struct pci_dev *dev); @@ -188,9 +183,9 @@ unsigned int bootable; unsigned int extra; unsigned int flags; -} ide_pci_device_t; +}; -static ide_pci_device_t pci_chipsets[] __initdata = { +static struct ata_pci_device pci_chipsets[] __initdata = { #ifdef CONFIG_BLK_DEV_PIIX {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, @@ -319,7 +314,7 @@ * settings of split-mirror pci-config space, place chipset into init-mode, * and/or preserve an interrupt if the card is not native ide support. */ -static unsigned int __init trust_pci_irq(ide_pci_device_t *d, struct pci_dev *dev) +static unsigned int __init trust_pci_irq(struct ata_pci_device *d, struct pci_dev *dev) { if (d->flags & ATA_F_IRQ) return dev->irq; @@ -484,7 +479,7 @@ * Setup DMA transfers on a channel. */ static void __init setup_channel_dma(struct ata_channel *hwif, struct pci_dev *dev, - ide_pci_device_t *d, + struct ata_pci_device *d, int port, u8 class_rev, int pciirq, @@ -534,7 +529,7 @@ * This gets called once for the master and for the slave interface. */ static int __init setup_host_channel(struct pci_dev *dev, - ide_pci_device_t *d, + struct ata_pci_device *d, int port, u8 class_rev, int pciirq, @@ -648,17 +643,16 @@ } /* - * Looks at the primary/secondary channels on a PCI IDE device and, if they - * are enabled, prepares the IDE driver for use with them. This generic code - * works for most PCI chipsets. + * Looks at the primary/secondary channels on a PCI IDE device and, if they are + * enabled, prepares the IDE driver for use with them. This generic code works + * for most PCI chipsets. * * One thing that is not standardized is the location of the primary/secondary * interface "enable/disable" bits. For chipsets that we "know" about, this - * information is in the ide_pci_device_t struct; for all other chipsets, we - * just assume both interfaces are enabled. + * information is in the struct ata_pci_device struct; for all other chipsets, + * we just assume both interfaces are enabled. */ - -static void __init setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) +static void __init setup_pci_device(struct pci_dev *dev, struct ata_pci_device *d) { int autodma = 0; int pciirq = 0; @@ -775,10 +769,11 @@ setup_host_channel(dev, d, ATA_SECONDARY, class_rev, pciirq, autodma, &pcicmd); } -static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) +static void __init pdc20270_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d) { - struct pci_dev *dev2 = NULL, *findev; - ide_pci_device_t *d2; + struct pci_dev *dev2 = NULL; + struct pci_dev *findev; + struct ata_pci_device *d2; if (dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_DEC && @@ -814,10 +809,10 @@ setup_pci_device(dev2, d2); } -static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) +static void __init hpt366_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d) { struct pci_dev *dev2 = NULL, *findev; - ide_pci_device_t *d2; + struct ata_pci_device *d2; unsigned char pin1 = 0, pin2 = 0; unsigned int class_rev; @@ -843,9 +838,7 @@ (PCI_FUNC(findev->devfn) & 1)) { dev2 = findev; pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); - hpt363_shared_pin = (pin1 != pin2) ? 1 : 0; - hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0; - if (hpt363_shared_pin && hpt363_shared_irq) { + if ((pin1 != pin2) && (dev->irq == dev2->irq)) { d->bootable = ON_BOARD; printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", dev->name, pin1, pin2); } @@ -869,7 +862,7 @@ { unsigned short vendor; unsigned short device; - ide_pci_device_t *d; + struct ata_pci_device *d; vendor = dev->vendor; device = dev->device; @@ -881,7 +874,7 @@ ++d; if (d->init_channel == ATA_PCI_IGNORE) - printk("%s: has been ignored by PCI bus scan\n", dev->name); + printk(KERN_INFO "ATA: %s: ignored by PCI bus scan\n", dev->name); else if ((d->vendor == PCI_VENDOR_ID_OPTI && d->device == PCI_DEVICE_ID_OPTI_82C558) && !(PCI_FUNC(dev->devfn) & 1)) return; else if ((d->vendor == PCI_VENDOR_ID_CONTAQ && d->device == PCI_DEVICE_ID_CONTAQ_82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) @@ -896,10 +889,10 @@ pdc20270_device_order_fixup(dev, d); else if (!(d->vendor == 0 && d->device == 0) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { if (d->vendor == 0 && d->device == 0) - printk("%s: unknown IDE controller on PCI slot %s, vendor=%04x, device=%04x\n", - dev->name, dev->slot_name, vendor, device); + printk(KERN_INFO "ATA: unknown ATA interface %s (%04x:%04x) on PCI slot %s\n", + dev->name, vendor, device, dev->slot_name); else - printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name); + printk(KERN_INFO "ATA: interface %s on PCI slot %s\n", dev->name, dev->slot_name); setup_pci_device(dev, d); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/ide-probe.c linux-2.5/drivers/ide/ide-probe.c --- linux-2.5.13/drivers/ide/ide-probe.c Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/ide/ide-probe.c Fri May 3 18:06:54 2002 @@ -1,4 +1,5 @@ -/* +/**** vi:set ts=8 sts=8 sw=8:************************************************ + * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) * * Mostly written by Mark Lord @@ -47,7 +48,7 @@ #include #include -static inline void do_identify (ide_drive_t *drive, byte cmd) +static inline void do_identify(struct ata_device *drive, u8 cmd) { int bswap = 1; struct hd_driveid *id; @@ -121,7 +122,7 @@ drive->present = 1; /* - * Check for an ATAPI device + * Check for an ATAPI device: */ if (cmd == WIN_PIDENTIFY) { byte type = (id->config >> 8) & 0x1f; @@ -172,7 +173,7 @@ } /* - * Not an ATAPI device: looks like a "regular" hard disk + * Not an ATAPI device: looks like a "regular" hard disk: */ if (id->config & (1<<7)) drive->removable = 1; @@ -185,7 +186,7 @@ */ if (drive_is_flashcard(drive)) { - ide_drive_t *mate = &drive->channel->drives[1 ^ drive->select.b.unit]; + struct ata_device *mate = &drive->channel->drives[1 ^ drive->select.b.unit]; if (!mate->ata_flash) { mate->present = 0; mate->noprobe = 1; @@ -198,32 +199,53 @@ if (drive->channel->quirkproc) drive->quirk_list = drive->channel->quirkproc(drive); + /* Initialize queue depth settings */ + drive->queue_depth = 1; +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEPTH + drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH; +#else + drive->queue_depth = drive->id->queue_depth + 1; +#endif + if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG) + drive->queue_depth = IDE_MAX_TAG; + return; err_misc: kfree(id); err_kmalloc: drive->present = 0; + return; } /* - * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive - * and waits for a response. It also monitors irqs while this is - * happening, in hope of automatically determining which one is - * being used by the interface. + * Sends an ATA(PI) IDENTIFY request to a drive and wait for a response. It + * also monitor irqs while this is happening, in hope of automatically + * determining which one is being used by the interface. * * Returns: 0 device was identified * 1 device timed-out (no response to identify request) * 2 device aborted the command (refused to identify itself) */ -static int actual_try_to_identify (ide_drive_t *drive, byte cmd) +static int identify(struct ata_device *drive, u8 cmd) { int rc; + int autoprobe = 0; + unsigned long cookie = 0; ide_ioreg_t hd_status; unsigned long timeout; - byte s, a; + u8 s; + u8 a; + + if (IDE_CONTROL_REG && !drive->channel->irq) { + autoprobe = 1; + cookie = probe_irq_on(); + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ + } + + rc = 1; if (IDE_CONTROL_REG) { /* take a deep breath */ ide_delay_50ms(); @@ -247,19 +269,18 @@ #if CONFIG_BLK_DEV_PDC4030 if (drive->channel->chipset == ide_pdc4030) { /* DC4030 hosted drives need their own identify... */ - extern int pdc4030_identify(ide_drive_t *); - if (pdc4030_identify(drive)) { - return 1; - } + extern int pdc4030_identify(struct ata_device *); + + if (pdc4030_identify(drive)) + goto out; } else -#endif /* CONFIG_BLK_DEV_PDC4030 */ +#endif OUT_BYTE(cmd,IDE_COMMAND_REG); /* ask drive for ID */ timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; do { - if (0 < (signed long)(jiffies - timeout)) { - return 1; /* drive timed-out */ - } + if (time_after(jiffies, timeout)) + goto out; /* drive timed-out */ ide_delay_50ms(); /* give drive a breather */ } while (IN_BYTE(hd_status) & BUSY_STAT); @@ -274,23 +295,8 @@ __restore_flags(flags); /* local CPU only */ } else rc = 2; /* drive refused ID */ - return rc; -} - -static int try_to_identify (ide_drive_t *drive, byte cmd) -{ - int retval; - int autoprobe = 0; - unsigned long cookie = 0; - - if (IDE_CONTROL_REG && !drive->channel->irq) { - autoprobe = 1; - cookie = probe_irq_on(); - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ - } - - retval = actual_try_to_identify(drive, cmd); +out: if (autoprobe) { int irq; OUT_BYTE(drive->ctl | 0x02, IDE_CONTROL_REG); /* mask device irq */ @@ -304,7 +310,8 @@ printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie); } } - return retval; + + return rc; } @@ -324,10 +331,11 @@ * 3 bad status from device (possible for ATAPI drives) * 4 probe was not attempted because failure was obvious */ -static int do_probe (ide_drive_t *drive, byte cmd) +static int do_probe(struct ata_device *drive, byte cmd) { int rc; struct ata_channel *hwif = drive->channel; + if (drive->present) { /* avoid waiting for inappropriate probes */ if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY)) return 4; @@ -348,11 +356,10 @@ return 3; /* no i/f present: mmm.. this should be a 4 -ml */ } - if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) - || drive->present || cmd == WIN_PIDENTIFY) + if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) || drive->present || cmd == WIN_PIDENTIFY) { - if ((rc = try_to_identify(drive,cmd))) /* send cmd and wait */ - rc = try_to_identify(drive,cmd); /* failed: try again */ + if ((rc = identify(drive,cmd))) /* send cmd and wait */ + rc = identify(drive,cmd); /* failed: try again */ if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) { unsigned long timeout; printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT()); @@ -363,14 +370,14 @@ timeout = jiffies; while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE)) ide_delay_50ms(); - rc = try_to_identify(drive, cmd); + rc = identify(drive, cmd); } if (rc == 1) printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT()); (void) GET_STAT(); /* ensure drive irq is clear */ - } else { + } else rc = 3; /* not present or maybe ATAPI */ - } + if (drive->select.b.unit != 0) { SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */ ide_delay_50ms(); @@ -379,10 +386,7 @@ return rc; } -/* - * - */ -static void enable_nest(ide_drive_t *drive) +static void enable_nest(struct ata_device *drive) { unsigned long timeout; @@ -392,7 +396,7 @@ OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); timeout = jiffies + WAIT_WORSTCASE; do { - if (jiffies > timeout) { + if (time_after(jiffies, timeout)) { printk("failed (timeout)\n"); return; } @@ -411,17 +415,21 @@ /* * Tests for existence of a given drive using do_probe(). */ -static inline void probe_for_drive (ide_drive_t *drive) +static inline void probe_for_drive(struct ata_device *drive) { if (drive->noprobe) /* skip probing? */ return; + if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ } + if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T")) enable_nest(drive); + if (!drive->present) return; /* drive not found */ + if (drive->id == NULL) { /* identification failed? */ if (drive->type == ATA_DISK) { printk ("%s: non-IDE drive, CHS=%d/%d/%d\n", @@ -545,7 +553,7 @@ do { ide_delay_50ms(); stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]); - } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies)); + } while ((stat & BUSY_STAT) && time_before(jiffies, timeout)); } __restore_flags(flags); /* local CPU only */ @@ -569,60 +577,6 @@ } /* - * init request queue - */ -static void init_device_queue(struct ata_device *drive) -{ - request_queue_t *q = &drive->queue; - int max_sectors = 255; - - q->queuedata = drive->channel; - blk_init_queue(q, do_ide_request, &ide_lock); - blk_queue_segment_boundary(q, 0xffff); - - /* IDE can do up to 128K per request, pdc4030 needs smaller limit */ -#ifdef CONFIG_BLK_DEV_PDC4030 - if (drive->channel->chipset == ide_pdc4030) - max_sectors = 127; -#endif - blk_queue_max_sectors(q, max_sectors); - - /* IDE DMA can do PRD_ENTRIES number of segments. */ - blk_queue_max_hw_segments(q, PRD_SEGMENTS); - - /* This is a driver limit and could be eliminated. */ - blk_queue_max_phys_segments(q, PRD_SEGMENTS); -} - -#if MAX_HWIFS > 1 - -/* - * This is used to simplify logic in init_irq() below. - * - * A loophole here is that we may not know about a particular hwif's irq until - * after that hwif is actually probed/initialized.. This could be a problem - * for the case where an hwif is on a dual interface that requires - * serialization (eg. cmd640) and another hwif using one of the same irqs is - * initialized beforehand. - * - * This routine detects and reports such situations, but does not fix them. - */ -static void save_match(struct ata_channel *hwif, struct ata_channel *new, - struct ata_channel **match) -{ - struct ata_channel *m = *match; - - if (m && m->hwgroup && m->hwgroup != new->hwgroup) { - if (!new->hwgroup) - return; - printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name); - } - if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */ - *match = new; -} -#endif - -/* * This routine sets up the irq for an ide interface, and creates a new hwgroup * for the irq/channel if none was previously assigned. * @@ -643,10 +597,8 @@ ide_hwgroup_t *new_hwgroup; struct ata_channel *match = NULL; - - /* Allocate the buffer and potentially sleep first */ - - new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL); + /* Spare allocation before sleep. */ + new_hwgroup = kmalloc(sizeof(*hwgroup), GFP_KERNEL); spin_lock_irqsave(&ide_lock, flags); ch->hwgroup = NULL; @@ -658,19 +610,22 @@ for (i = 0; i < MAX_HWIFS; ++i) { struct ata_channel *h = &ide_hwifs[i]; - if (h->hwgroup) { /* scan only initialized channels */ - if (ch->irq == h->irq) { - ch->sharing_irq = h->sharing_irq = 1; - if (ch->chipset != ide_pci || h->chipset != ide_pci) - save_match(ch, h, &match); - - /* FIXME: This is still confusing. What would - * happen if we match-ed two times? - */ - - if (ch->serialized || h->serialized) - save_match(ch, h, &match); - } + /* scan only initialized channels */ + if (!h->hwgroup) + continue; + + if (ch->irq != h->irq) + continue; + + ch->sharing_irq = h->sharing_irq = 1; + + if (ch->chipset != ide_pci || h->chipset != ide_pci || + ch->serialized || h->serialized) { + if (match && match->hwgroup && match->hwgroup != h->hwgroup) + printk("%s: potential irq problem with %s and %s\n", ch->name, h->name, match->name); + /* don't undo a prior perfect match */ + if (!match || match->irq != ch->irq) + match = h; } } #endif @@ -721,6 +676,8 @@ ch->hwgroup = hwgroup; for (i = 0; i < MAX_DRIVES; ++i) { struct ata_device *drive = &ch->drives[i]; + request_queue_t *q; + int max_sectors = 255; if (!drive->present) continue; @@ -728,7 +685,27 @@ if (!hwgroup->XXX_drive) hwgroup->XXX_drive = drive; - init_device_queue(drive); + /* + * Init the per device request queue + */ + + q = &drive->queue; + q->queuedata = drive->channel; + blk_init_queue(q, do_ide_request, &ide_lock); + blk_queue_segment_boundary(q, 0xffff); + + /* ATA can do up to 128K per request, pdc4030 needs smaller limit */ +#ifdef CONFIG_BLK_DEV_PDC4030 + if (drive->channel->chipset == ide_pdc4030) + max_sectors = 127; +#endif + blk_queue_max_sectors(q, max_sectors); + + /* IDE DMA can do PRD_ENTRIES number of segments. */ + blk_queue_max_hw_segments(q, PRD_ENTRIES); + + /* FIXME: This is a driver limit and could be eliminated. */ + blk_queue_max_phys_segments(q, PRD_ENTRIES); } spin_unlock_irqrestore(&ide_lock, flags); @@ -755,80 +732,10 @@ } /* - * init_gendisk() (as opposed to ide_geninit) is called for each major device, - * after probing for drives, to allocate partition tables and other data - * structures needed for the routines in genhd.c. ide_geninit() gets called - * somewhat later, during the partition check. - */ -static void init_gendisk(struct ata_channel *hwif) -{ - struct gendisk *gd; - unsigned int unit, minors, i; - extern devfs_handle_t ide_devfs_handle; - - minors = MAX_DRIVES * (1 << PARTN_BITS); - - gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); - if (!gd) - goto err_kmalloc_gd; - - gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); - if (!gd->sizes) - goto err_kmalloc_gd_sizes; - - gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); - if (!gd->part) - goto err_kmalloc_gd_part; - memset(gd->part, 0, minors * sizeof(struct hd_struct)); - - for (unit = 0; unit < MAX_DRIVES; ++unit) - hwif->drives[unit].part = &gd->part[unit << PARTN_BITS]; - - gd->major = hwif->major; /* our major device number */ - gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */ - gd->minor_shift = PARTN_BITS; /* num bits for partitions */ - gd->nr_real = MAX_DRIVES; /* current num real drives */ - gd->next = NULL; /* linked list of major devs */ - gd->fops = ide_fops; /* file operations */ - gd->de_arr = kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL); - gd->flags = kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL); - if (gd->de_arr) - memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES); - if (gd->flags) - memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES); - - hwif->gd = gd; - add_gendisk(gd); - - for (unit = 0; unit < MAX_DRIVES; ++unit) { - char name[80]; - - ide_add_generic_settings(hwif->drives + unit); - hwif->drives[unit].dn = ((hwif->unit ? 2 : 0) + unit); - sprintf (name, "host%d/bus%d/target%d/lun%d", - hwif->index, hwif->unit, unit, hwif->drives[unit].lun); - if (hwif->drives[unit].present) - hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL); - } - return; - -err_kmalloc_bs: - kfree(gd->part); -err_kmalloc_gd_part: - kfree(gd->sizes); -err_kmalloc_gd_sizes: - kfree(gd); -err_kmalloc_gd: - printk(KERN_CRIT "(ide::init_gendisk) Out of memory\n"); - return; -} - -/* * Returns the queue which corresponds to a given device. * * FIXME: this should take struct block_device * as argument in future. */ - static request_queue_t *ata_get_queue(kdev_t dev) { struct ata_channel *ch = (struct ata_channel *)blk_dev[major(dev)].data; @@ -837,8 +744,15 @@ return &ch->drives[DEVICE_NR(dev) & 1].queue; } +/* Number of minor numbers we consume par channel. */ +#define ATA_MINORS (MAX_DRIVES * (1 << PARTN_BITS)) + static void channel_init(struct ata_channel *ch) { + struct gendisk *gd; + unsigned int unit; + extern devfs_handle_t ide_devfs_handle; + if (!ch->present) return; @@ -888,33 +802,96 @@ printk(KERN_INFO "%s: probed IRQ %d failed, using default.\n", ch->name, ch->irq); } - init_gendisk(ch); + /* Initialize partition and global device data. ide_geninit() gets + * called somewhat later, during the partition check. + */ + + gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); + if (!gd) + goto err_kmalloc_gd; + + gd->sizes = kmalloc(ATA_MINORS * sizeof(int), GFP_KERNEL); + if (!gd->sizes) + goto err_kmalloc_gd_sizes; + + gd->part = kmalloc(ATA_MINORS * sizeof(struct hd_struct), GFP_KERNEL); + if (!gd->part) + goto err_kmalloc_gd_part; + memset(gd->part, 0, ATA_MINORS * sizeof(struct hd_struct)); + + for (unit = 0; unit < MAX_DRIVES; ++unit) + ch->drives[unit].part = &gd->part[unit << PARTN_BITS]; + + gd->major = ch->major; /* our major device number */ + gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */ + gd->minor_shift = PARTN_BITS; /* num bits for partitions */ + gd->nr_real = MAX_DRIVES; /* current num real drives */ + gd->next = NULL; /* linked list of major devs */ + gd->fops = ide_fops; /* file operations */ + + gd->de_arr = kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL); + if (gd->de_arr) + memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES); + else + goto err_kmalloc_gd_de_arr; + + gd->flags = kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL); + if (gd->flags) + memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES); + else + goto err_kmalloc_gd_flags; + + ch->gd = gd; + add_gendisk(gd); + + for (unit = 0; unit < MAX_DRIVES; ++unit) { + char name[80]; + + ide_add_generic_settings(ch->drives + unit); + ch->drives[unit].dn = ((ch->unit ? 2 : 0) + unit); + sprintf(name, "host%d/bus%d/target%d/lun%d", + ch->index, ch->unit, unit, ch->drives[unit].lun); + if (ch->drives[unit].present) + ch->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL); + } + blk_dev[ch->major].data = ch; blk_dev[ch->major].queue = ata_get_queue; - /* all went well, flag this channel entry as valid */ + /* All went well, flag this channel entry as valid again. */ ch->present = 1; return; + +err_kmalloc_gd_flags: + kfree(gd->de_arr); +err_kmalloc_gd_de_arr: + kfree(gd->part); +err_kmalloc_gd_part: + kfree(gd->sizes); +err_kmalloc_gd_sizes: + kfree(gd); +err_kmalloc_gd: + printk(KERN_CRIT "(%s) Out of memory\n", __FUNCTION__); } int ideprobe_init (void) { - unsigned int index; + unsigned int i; int probe[MAX_HWIFS]; - memset(probe, 0, MAX_HWIFS * sizeof(int)); - for (index = 0; index < MAX_HWIFS; ++index) - probe[index] = !ide_hwifs[index].present; + for (i = 0; i < MAX_HWIFS; ++i) + probe[i] = !ide_hwifs[i].present; /* * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports */ - for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) - channel_probe(&ide_hwifs[index]); - for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) - channel_init(&ide_hwifs[index]); + for (i = 0; i < MAX_HWIFS; ++i) + if (probe[i]) + channel_probe(&ide_hwifs[i]); + for (i = 0; i < MAX_HWIFS; ++i) + if (probe[i]) + channel_init(&ide_hwifs[i]); + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/ide-taskfile.c linux-2.5/drivers/ide/ide-taskfile.c --- linux-2.5.13/drivers/ide/ide-taskfile.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/ide/ide-taskfile.c Sat May 4 11:43:40 2002 @@ -202,7 +202,7 @@ ata_write_slow(drive, buffer, wcount); else #endif - ata_write_16(drive, buffer, wcount<<1); + ata_write_16(drive, buffer, wcount); } } @@ -456,11 +456,39 @@ if (args->prehandler != NULL) return args->prehandler(drive, rq); } else { - /* for dma commands we down set the handler */ - if (drive->using_dma && - !(drive->channel->udma(((args->taskfile.command == WIN_WRITEDMA) - || (args->taskfile.command == WIN_WRITEDMA_EXT)) - ? ide_dma_write : ide_dma_read, drive, rq))); + ide_dma_action_t dma_act; + int tcq = 0; + + if (!drive->using_dma) + return ide_started; + + /* for dma commands we don't set the handler */ + if (args->taskfile.command == WIN_WRITEDMA || args->taskfile.command == WIN_WRITEDMA_EXT) + dma_act = ide_dma_write; + else if (args->taskfile.command == WIN_READDMA || args->taskfile.command == WIN_READDMA_EXT) + dma_act = ide_dma_read; + else if (args->taskfile.command == WIN_WRITEDMA_QUEUED || args->taskfile.command == WIN_WRITEDMA_QUEUED_EXT) { + tcq = 1; + dma_act = ide_dma_write_queued; + } else if (args->taskfile.command == WIN_READDMA_QUEUED || args->taskfile.command == WIN_READDMA_QUEUED_EXT) { + tcq = 1; + dma_act = ide_dma_read_queued; + } else { + printk("ata_taskfile: unknown command %x\n", args->taskfile.command); + return ide_stopped; + } + + /* + * FIXME: this is a gross hack, need to unify tcq dma proc and + * regular dma proc -- basically split stuff that needs to act + * on a request from things like ide_dma_check etc. + */ + if (tcq) + return drive->channel->udma(dma_act, drive, rq); + else { + if (drive->channel->udma(dma_act, drive, rq)) + return ide_stopped; + } } return ide_started; @@ -523,7 +551,7 @@ ide__sti(); /* local CPU only */ if (!OK_STAT(stat = GET_STAT(), READY_STAT, BAD_STAT)) { - /* Keep quite for NOP becouse they are expected to fail. */ + /* Keep quiet for NOP because it is expected to fail. */ if (args && args->taskfile.command != WIN_NOP) return ide_error(drive, "task_no_data_intr", stat); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/ide.c linux-2.5/drivers/ide/ide.c --- linux-2.5.13/drivers/ide/ide.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/ide/ide.c Fri May 3 18:06:54 2002 @@ -1,15 +1,19 @@ -/* - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) +/**** vi:set ts=8 sts=8 sw=8:************************************************ + * + * Copyright (C) 1994-1998,2002 Linus Torvalds and authors: * - * Mostly written by Mark Lord - * and Gadi Oxman - * and Andre Hedrick + * Mark Lord + * Gadi Oxman + * Andre Hedrick + * Jens Axboe + * Marcin Dalecki * * See linux/MAINTAINERS for address of current maintainer. * - * This is the multiple IDE interface driver, as evolved from hd.c. - * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15). - * There can be up to two drives per interface, as per the ATA-2 spec. + * This is the basic common code of the ATA interface drivers. + * + * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 + * & 15). There can be up to two drives per interface, as per the ATA-7 spec. * * Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64 * Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64 @@ -17,102 +21,15 @@ * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64 * ... * - * From hd.c: - * | - * | It traverses the request-list, using interrupts to jump between functions. - * | As nearly all functions can be called within interrupts, we may not sleep. - * | Special care is recommended. Have Fun! - * | - * | modified by Drew Eckhardt to check nr of hd's from the CMOS. - * | - * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * | in the early extended-partition checks and added DM partitions. - * | - * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI). - * | - * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads", - * | and general streamlining by Mark Lord (mlord@pobox.com). - * - * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by: - * - * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg) - * Delman Lee (delman@ieee.org) ("Mr. atdisk2") - * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom) - * - * This was a rewrite of just about everything from hd.c, though some original - * code is still sprinkled about. Think of it as a major evolution, with - * inspiration from lots of linux users, esp. hamish@zot.apana.org.au - * - * Version 1.0 ALPHA initial code, primary i/f working okay - * Version 1.3 BETA dual i/f on shared irq tested & working! - * Version 1.4 BETA added auto probing for irq(s) - * Version 1.5 BETA added ALPHA (untested) support for IDE cd-roms, - * ... - * Version 5.50 allow values as small as 20 for idebus= - * Version 5.51 force non io_32bit in drive_cmd_intr() - * change delay_10ms() to delay_50ms() to fix problems - * Version 5.52 fix incorrect invalidation of removable devices - * add "hdx=slow" command line option - * Version 5.60 start to modularize the driver; the disk and ATAPI - * drivers can be compiled as loadable modules. - * move IDE probe code to ide-probe.c - * move IDE disk code to ide-disk.c - * add support for generic IDE device subdrivers - * add m68k code from Geert Uytterhoeven - * probe all interfaces by default - * add ioctl to (re)probe an interface - * Version 6.00 use per device request queues - * attempt to optimize shared hwgroup performance - * add ioctl to manually adjust bandwidth algorithms - * add kerneld support for the probe module - * fix bug in ide_error() - * fix bug in the first ide_get_lock() call for Atari - * don't flush leftover data for ATAPI devices - * Version 6.01 clear hwgroup->active while the hwgroup sleeps - * support HDIO_GETGEO for floppies - * Version 6.02 fix ide_ack_intr() call - * check partition table on floppies - * Version 6.03 handle bad status bit sequencing in ide_wait_stat() - * Version 6.10 deleted old entries from this list of updates - * replaced triton.c with ide-dma.c generic PCI DMA - * added support for BIOS-enabled UltraDMA - * rename all "promise" things to "pdc4030" - * fix EZ-DRIVE handling on small disks - * Version 6.11 fix probe error in ide_scan_devices() - * fix ancient "jiffies" polling bugs - * mask all hwgroup interrupts on each irq entry - * Version 6.12 integrate ioctl and proc interfaces - * fix parsing of "idex=" command line parameter - * Version 6.13 add support for ide4/ide5 courtesy rjones@orchestream.com - * Version 6.14 fixed IRQ sharing among PCI devices - * Version 6.15 added SMP awareness to IDE drivers - * Version 6.16 fixed various bugs; even more SMP friendly - * Version 6.17 fix for newest EZ-Drive problem - * Version 6.18 default unpartitioned-disk translation now "BIOS LBA" - * Version 6.19 Re-design for a UNIFORM driver for all platforms, - * model based on suggestions from Russell King and - * Geert Uytterhoeven - * Promise DC4030VL now supported. - * add support for ide6/ide7 - * delay_50ms() changed to ide_delay_50ms() and exported. - * Version 6.20 Added/Fixed Generic ATA-66 support and hwif detection. - * Added hdx=flash to allow for second flash disk - * detection w/o the hang loop. - * Added support for ide8/ide9 - * Added idex=ata66 for the quirky chipsets that are - * ATA-66 compliant, but have yet to determine a method - * of verification of the 80c cable presence. - * Specifically Promise's PDC20262 chipset. - * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old - * hat that clarified original low level driver design. - * Version 6.30 Added SMP support; fixed multmode issues. -ml - * Version 6.31 Debug Share INTR's and request queue streaming - * Native ATA-100 support - * Prep for Cascades Project - * Version 6.32 4GB highmem support for DMA, and mapping of those for - * PIO transfer (Jens Axboe) + * Contributors: * - * Some additional driver compile-time options are in ./include/linux/ide.h + * Drew Eckhardt + * Branko Lankester + * Mika Liljeberg + * Delman Lee + * Scott Snyder + * + * Some additional driver compile-time options are in */ #define VERSION "7.0.0" @@ -253,10 +170,7 @@ #endif } -/* - * Do not even *think* about calling this! - */ -static void init_hwif_data(struct ata_channel *hwif, unsigned int index) +static void init_hwif_data(struct ata_channel *ch, unsigned int index) { static const byte ide_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, @@ -266,30 +180,30 @@ unsigned int unit; hw_regs_t hw; - /* bulk initialize hwif & drive info with zeros */ - memset(hwif, 0, sizeof(struct ata_channel)); + /* bulk initialize channel & drive info with zeros */ + memset(ch, 0, sizeof(struct ata_channel)); memset(&hw, 0, sizeof(hw_regs_t)); /* fill in any non-zero initial values */ - hwif->index = index; - ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq); - memcpy(&hwif->hw, &hw, sizeof(hw)); - memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports)); - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; + ch->index = index; + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &ch->irq); + memcpy(&ch->hw, &hw, sizeof(hw)); + memcpy(ch->io_ports, hw.io_ports, sizeof(hw.io_ports)); + ch->noprobe = !ch->io_ports[IDE_DATA_OFFSET]; #ifdef CONFIG_BLK_DEV_HD - if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) - hwif->noprobe = 1; /* may be overridden by ide_setup() */ + if (ch->io_ports[IDE_DATA_OFFSET] == HD_DATA) + ch->noprobe = 1; /* may be overridden by ide_setup() */ #endif /* CONFIG_BLK_DEV_HD */ - hwif->major = ide_major[index]; - sprintf(hwif->name, "ide%d", index); - hwif->bus_state = BUSSTATE_ON; + ch->major = ide_major[index]; + sprintf(ch->name, "ide%d", index); + ch->bus_state = BUSSTATE_ON; for (unit = 0; unit < MAX_DRIVES; ++unit) { - struct ata_device *drive = &hwif->drives[unit]; + struct ata_device *drive = &ch->drives[unit]; drive->type = ATA_DISK; drive->select.all = (unit<<4)|0xa0; - drive->channel = hwif; + drive->channel = ch; drive->ctl = 0x08; drive->ready_stat = READY_STAT; drive->bad_wstat = BAD_W_STAT; @@ -397,7 +311,10 @@ if (!end_that_request_first(rq, uptodate, nr_secs)) { add_blkdev_randomness(major(rq->rq_dev)); - blkdev_dequeue_request(rq); + if (!blk_rq_tagged(rq)) + blkdev_dequeue_request(rq); + else + blk_queue_end_tag(&drive->queue, rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); ret = 0; @@ -1258,7 +1175,7 @@ /* This device still wants to remain idle. */ - if (drive->sleep && time_after(jiffies, drive->sleep)) + if (drive->sleep && time_after(drive->sleep, jiffies)) continue; /* Take this device, if there is no device choosen thus far or @@ -1285,8 +1202,8 @@ * want to hog the cpu too much. */ - if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) - sleep = jiffies + WAIT_MIN_SLEEP; + if (time_after(jiffies, sleep - WAIT_MIN_SLEEP)) + sleep = jiffies + WAIT_MIN_SLEEP; #if 1 if (timer_pending(&channel->hwgroup->timer)) printk(KERN_ERR "ide_set_handler: timer already active\n"); @@ -1305,11 +1222,6 @@ } -/* Place holders for later expansion of functionality. - */ -#define ata_pending_commands(drive) (0) -#define ata_can_queue(drive) (1) - /* * Feed commands to a drive until it barfs. Called with ide_lock/DRIVE_LOCK * held and busy channel. @@ -1349,7 +1261,7 @@ * still a severe BUG! */ if (blk_queue_plugged(&drive->queue)) { - BUG(); + BUG_ON(!drive->using_tcq); break; } @@ -1761,7 +1673,8 @@ } else { printk("%s: %s: huh? expected NULL handler on exit\n", drive->name, __FUNCTION__); } - } + } else if (startstop == ide_released) + queue_commands(drive, ch->irq); out_lock: spin_unlock_irqrestore(&ide_lock, flags); @@ -2861,7 +2774,7 @@ * "hdx=flash" : allows for more than one ata_flash disk to be * registered. In most cases, only one device * will be present. - * "hdx=scsi" : the return of the ide-scsi flag, this is useful for + * "hdx=ide-scsi" : the return of the ide-scsi flag, this is useful for * allowwing ide-floppy, ide-tape, and ide-cdrom|writers * to use ide-scsi emulation on a device specific option. * "idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz, @@ -2928,14 +2841,14 @@ strncmp(s,"hd",2)) /* hdx= & hdxlun= */ return 0; - printk("ide_setup: %s", s); + printk(KERN_INFO "ide_setup: %s", s); init_ide_data (); #ifdef CONFIG_BLK_DEV_IDEDOUBLER if (!strcmp(s, "ide=doubler")) { extern int ide_doubler; - printk(" : Enabled support for IDE doublers\n"); + printk(KERN_INFO" : Enabled support for IDE doublers\n"); ide_doubler = 1; return 1; @@ -2943,7 +2856,7 @@ #endif if (!strcmp(s, "ide=nodma")) { - printk("IDE: Prevented DMA\n"); + printk(KERN_INFO "ATA: Prevented DMA\n"); noautodma = 1; return 1; @@ -3290,6 +3203,9 @@ drive->channel->udma(ide_dma_off_quietly, drive, NULL); drive->channel->udma(ide_dma_check, drive, NULL); +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT + drive->channel->udma(ide_dma_queued_on, drive, NULL); +#endif } /* Only CD-ROMs and tape drives support DSC overlap. But only @@ -3497,7 +3413,7 @@ { int h; - printk(KERN_INFO "Uniform Multi-Platform E-IDE driver ver.:" VERSION "\n"); + printk(KERN_INFO "ATA/ATAPI driver v" VERSION "\n"); ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL); @@ -3519,7 +3435,7 @@ system_bus_speed = 33; #endif - printk("ide: system bus speed %dMHz\n", system_bus_speed); + printk(KERN_INFO "ATA: system bus speed %dMHz\n", system_bus_speed); init_ide_data (); @@ -3640,27 +3556,23 @@ MODULE_PARM(options,"s"); MODULE_LICENSE("GPL"); -static void __init parse_options (char *line) +static int __init init_ata(void) { - char *next = line; - if (line == NULL || !*line) - return; - while ((line = next) != NULL) { - if ((next = strchr(line,' ')) != NULL) - *next++ = 0; - if (!ide_setup(line)) - printk ("Unknown option '%s'\n", line); - } -} + if (options != NULL && *options) { + char *next = options; -static int __init init_ata (void) -{ - parse_options(options); + while ((options = next) != NULL) { + if ((next = strchr(options,' ')) != NULL) + *next++ = 0; + if (!ide_setup(options)) + printk(KERN_ERR "Unknown option '%s'\n", options); + } + } return ata_module_init(); } -static void __exit cleanup_ata (void) +static void __exit cleanup_ata(void) { int h; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ide/tcq.c linux-2.5/drivers/ide/tcq.c --- linux-2.5.13/drivers/ide/tcq.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/ide/tcq.c Fri May 3 18:15:34 2002 @@ -0,0 +1,643 @@ +/* + * Copyright (C) 2001, 2002 Jens Axboe + * + * 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. + * + * 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 + */ + +/* + * Support for the DMA queued protocol, which enables ATA disk drives to + * use tagged command queueing. + */ +#include +#include +#include +#include +#include +#include + +#include + +/* + * warning: it will be _very_ verbose if defined + */ +#undef IDE_TCQ_DEBUG + +#ifdef IDE_TCQ_DEBUG +#define TCQ_PRINTK printk +#else +#define TCQ_PRINTK(x...) +#endif + +/* + * use nIEN or not + */ +#undef IDE_TCQ_NIEN + +/* + * We are leaving the SERVICE interrupt alone, IBM drives have it + * on per default and it can't be turned off. Doesn't matter, this + * is the sane config. + */ +#undef IDE_TCQ_FIDDLE_SI + +static ide_startstop_t ide_dmaq_intr(struct ata_device *drive, struct request *rq); +static ide_startstop_t service(struct ata_device *drive); + +static inline void drive_ctl_nien(struct ata_device *drive, int set) +{ +#ifdef IDE_TCQ_NIEN + if (IDE_CONTROL_REG) { + int mask = set ? 0x02 : 0x00; + + OUT_BYTE(drive->ctl | mask, IDE_CONTROL_REG); + } +#endif +} + +static ide_startstop_t tcq_nop_handler(struct ata_device *drive, struct request *rq) +{ + struct ata_taskfile *args = rq->special; + + ide__sti(); + ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); + kfree(args); + return ide_stopped; +} + +/* + * If we encounter _any_ error doing I/O to one of the tags, we must + * invalidate the pending queue. Clear the software busy queue and requeue + * on the request queue for restart. Issue a WIN_NOP to clear hardware queue. + */ +static void tcq_invalidate_queue(struct ata_device *drive) +{ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + request_queue_t *q = &drive->queue; + struct ata_taskfile *args; + struct request *rq; + unsigned long flags; + + printk(KERN_INFO "ATA: %s: invalidating pending queue (%d)\n", drive->name, ata_pending_commands(drive)); + + spin_lock_irqsave(&ide_lock, flags); + + del_timer(&hwgroup->timer); + + if (test_bit(IDE_DMA, &hwgroup->flags)) + drive->channel->udma(ide_dma_end, drive, hwgroup->rq); + + blk_queue_invalidate_tags(q); + + drive->using_tcq = 0; + drive->queue_depth = 1; + clear_bit(IDE_BUSY, &hwgroup->flags); + clear_bit(IDE_DMA, &hwgroup->flags); + hwgroup->handler = NULL; + + /* + * Do some internal stuff -- we really need this command to be + * executed before any new commands are started. issue a NOP + * to clear internal queue on drive. + */ + args = kmalloc(sizeof(*args), GFP_ATOMIC); + if (!args) { + printk(KERN_ERR "ATA: %s: failed to issue NOP\n", drive->name); + goto out; + } + + rq = blk_get_request(&drive->queue, READ, GFP_ATOMIC); + if (!rq) + rq = blk_get_request(&drive->queue, WRITE, GFP_ATOMIC); + + /* + * blk_queue_invalidate_tags() just added back at least one command + * to the free list, so there _must_ be at least one free. + */ + BUG_ON(!rq); + + rq->special = args; + args->taskfile.command = WIN_NOP; + args->handler = tcq_nop_handler; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + + rq->rq_dev = mk_kdev(drive->channel->major, (drive->select.b.unit)<request_fn(q); + spin_unlock_irqrestore(&ide_lock, flags); + printk(KERN_DEBUG "ATA: tcq_invalidate_queue: done\n"); +} + +static void ata_tcq_irq_timeout(unsigned long data) +{ + struct ata_device *drive = (struct ata_device *) data; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long flags; + + printk(KERN_ERR "ATA: %s: timeout waiting for %s interrupt...\n", + __FUNCTION__, hwgroup->rq ? "completion" : "service"); + + spin_lock_irqsave(&ide_lock, flags); + + if (test_and_set_bit(IDE_BUSY, &hwgroup->flags)) + printk(KERN_ERR "ATA: %s: hwgroup not busy\n", __FUNCTION__); + if (hwgroup->handler == NULL) + printk(KERN_ERR "ATA: %s: missing isr!\n", __FUNCTION__); + + spin_unlock_irqrestore(&ide_lock, flags); + + /* + * if pending commands, try service before giving up + */ + if (ata_pending_commands(drive) && (GET_STAT() & SERVICE_STAT)) + if (service(drive) == ide_started) + return; + + if (drive) + tcq_invalidate_queue(drive); +} + +static void set_irq(struct ata_device *drive, ata_handler_t *handler) +{ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long flags; + + spin_lock_irqsave(&ide_lock, flags); + + /* + * always just bump the timer for now, the timeout handling will + * have to be changed to be per-command + */ + hwgroup->timer.function = ata_tcq_irq_timeout; + hwgroup->timer.data = (unsigned long) hwgroup->XXX_drive; + mod_timer(&hwgroup->timer, jiffies + 5 * HZ); + + hwgroup->handler = handler; + spin_unlock_irqrestore(&ide_lock, flags); +} + +/* + * wait 400ns, then poll for busy_mask to clear from alt status + */ +#define IDE_TCQ_WAIT (10000) +static int wait_altstat(struct ata_device *drive, u8 *stat, u8 busy_mask) +{ + int i = 0; + + udelay(1); + + while ((*stat = GET_ALTSTAT()) & busy_mask) { + if (unlikely(i++ > IDE_TCQ_WAIT)) + return 1; + + udelay(10); + } + + return 0; +} + +/* + * issue SERVICE command to drive -- drive must have been selected first, + * and it must have reported a need for service (status has SERVICE_STAT set) + * + * Also, nIEN must be set as not to need protection against ide_dmaq_intr + */ +static ide_startstop_t service(struct ata_device *drive) +{ + struct request *rq; + u8 feat; + u8 stat; + int tag; + + TCQ_PRINTK("%s: started service\n", drive->name); + + /* + * Could be called with IDE_DMA in-progress from invalidate + * handler, refuse to do anything. + */ + if (test_bit(IDE_DMA, &HWGROUP(drive)->flags)) + return ide_stopped; + + /* + * need to select the right drive first... + */ + if (drive != HWGROUP(drive)->XXX_drive) { + SELECT_DRIVE(drive->channel, drive); + udelay(10); + } + + drive_ctl_nien(drive, 1); + + /* + * send SERVICE, wait 400ns, wait for BUSY_STAT to clear + */ + OUT_BYTE(WIN_QUEUED_SERVICE, IDE_COMMAND_REG); + + if (wait_altstat(drive, &stat, BUSY_STAT)) { + printk(KERN_ERR"%s: BUSY clear took too long\n", __FUNCTION__); + ide_dump_status(drive, __FUNCTION__, stat); + tcq_invalidate_queue(drive); + return ide_stopped; + } + + drive_ctl_nien(drive, 0); + + /* + * FIXME, invalidate queue + */ + if (stat & ERR_STAT) { + ide_dump_status(drive, __FUNCTION__, stat); + tcq_invalidate_queue(drive); + return ide_stopped; + } + + /* + * should not happen, a buggy device could introduce loop + */ + if ((feat = GET_FEAT()) & NSEC_REL) { + HWGROUP(drive)->rq = NULL; + printk("%s: release in service\n", drive->name); + return ide_stopped; + } + + tag = feat >> 3; + + TCQ_PRINTK("%s: stat %x, feat %x\n", __FUNCTION__, stat, feat); + + rq = blk_queue_tag_request(&drive->queue, tag); + if (!rq) { + printk(KERN_ERR"%s: missing request for tag %d\n", __FUNCTION__, tag); + return ide_stopped; + } + + HWGROUP(drive)->rq = rq; + + /* + * we'll start a dma read or write, device will trigger + * interrupt to indicate end of transfer, release is not allowed + */ + TCQ_PRINTK("%s: starting command %x\n", __FUNCTION__, stat); + return drive->channel->udma(ide_dma_queued_start, drive, rq); +} + +static ide_startstop_t check_service(struct ata_device *drive) +{ + u8 stat; + + TCQ_PRINTK("%s: %s\n", drive->name, __FUNCTION__); + + if (!ata_pending_commands(drive)) + return ide_stopped; + + if ((stat = GET_STAT()) & SERVICE_STAT) + return service(drive); + + /* + * we have pending commands, wait for interrupt + */ + set_irq(drive, ide_dmaq_intr); + + return ide_started; +} + +ide_startstop_t ide_dmaq_complete(struct ata_device *drive, struct request *rq, u8 stat) +{ + u8 dma_stat; + + /* + * transfer was in progress, stop DMA engine + */ + dma_stat = drive->channel->udma(ide_dma_end, drive, rq); + + /* + * must be end of I/O, check status and complete as necessary + */ + if (unlikely(!OK_STAT(stat, READY_STAT, drive->bad_wstat | DRQ_STAT))) { + printk(KERN_ERR "%s: %s: error status %x\n", __FUNCTION__, drive->name,stat); + ide_dump_status(drive, __FUNCTION__, stat); + tcq_invalidate_queue(drive); + return ide_stopped; + } + + if (dma_stat) + printk("%s: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat); + + TCQ_PRINTK("%s: ending %p, tag %d\n", __FUNCTION__, rq, rq->tag); + __ide_end_request(drive, rq, !dma_stat, rq->nr_sectors); + + /* + * we completed this command, check if we can service a new command + */ + return check_service(drive); +} + +/* + * intr handler for queued dma operations. this can be entered for two + * reasons: + * + * 1) device has completed dma transfer + * 2) service request to start a command + * + * if the drive has an active tag, we first complete that request before + * processing any pending SERVICE. + */ +static ide_startstop_t ide_dmaq_intr(struct ata_device *drive, struct request *rq) +{ + u8 stat = GET_STAT(); + + TCQ_PRINTK("%s: stat=%x\n", __FUNCTION__, stat); + + /* + * if a command completion interrupt is pending, do that first and + * check service afterwards + */ + if (rq) + return ide_dmaq_complete(drive, rq, stat); + + /* + * service interrupt + */ + if (stat & SERVICE_STAT) { + TCQ_PRINTK("%s: SERV (stat=%x)\n", __FUNCTION__, stat); + return service(drive); + } + + printk("%s: stat=%x, not expected\n", __FUNCTION__, stat); + return check_service(drive); +} + +/* + * Check if the ata adapter this drive is attached to supports the + * NOP auto-poll for multiple tcq enabled drives on one channel. + */ +static int check_autopoll(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + struct ata_taskfile args; + int drives = 0, i; + + /* + * only need to probe if both drives on a channel support tcq + */ + for (i = 0; i < MAX_DRIVES; i++) + if (drive->channel->drives[i].present &&drive->type == ATA_DISK) + drives++; + + if (drives <= 1) + return 0; + + memset(&args, 0, sizeof(args)); + + args.taskfile.feature = 0x01; + args.taskfile.command = WIN_NOP; + ide_cmd_type_parser(&args); + + /* + * do taskfile and check ABRT bit -- intelligent adapters will not + * pass NOP with sub-code 0x01 to device, so the command will not + * fail there + */ + ide_raw_taskfile(drive, &args, NULL); + if (args.taskfile.feature & ABRT_ERR) + return 1; + + ch->auto_poll = 1; + printk("%s: NOP Auto-poll enabled\n", ch->name); + return 0; +} + +/* + * configure the drive for tcq + */ +static int configure_tcq(struct ata_device *drive) +{ + int tcq_mask = 1 << 1 | 1 << 14; + int tcq_bits = tcq_mask | 1 << 15; + struct ata_taskfile args; + + /* + * bit 14 and 1 must be set in word 83 of the device id to indicate + * support for dma queued protocol, and bit 15 must be cleared + */ + if ((drive->id->command_set_2 & tcq_bits) ^ tcq_mask) + return -EIO; + + memset(&args, 0, sizeof(args)); + args.taskfile.feature = SETFEATURES_EN_WCACHE; + args.taskfile.command = WIN_SETFEATURES; + ide_cmd_type_parser(&args); + + if (ide_raw_taskfile(drive, &args, NULL)) { + printk("%s: failed to enable write cache\n", drive->name); + return 1; + } + + /* + * disable RELease interrupt, it's quicker to poll this after + * having sent the command opcode + */ + memset(&args, 0, sizeof(args)); + args.taskfile.feature = SETFEATURES_DIS_RI; + args.taskfile.command = WIN_SETFEATURES; + ide_cmd_type_parser(&args); + + if (ide_raw_taskfile(drive, &args, NULL)) { + printk("%s: disabling release interrupt fail\n", drive->name); + return 1; + } + +#ifdef IDE_TCQ_FIDDLE_SI + /* + * enable SERVICE interrupt + */ + memset(&args, 0, sizeof(args)); + args.taskfile.feature = SETFEATURES_EN_SI; + args.taskfile.command = WIN_SETFEATURES; + ide_cmd_type_parser(&args); + + if (ide_raw_taskfile(drive, &args, NULL)) { + printk("%s: enabling service interrupt fail\n", drive->name); + return 1; + } +#endif + + return 0; +} + +/* + * for now assume that command list is always as big as we need and don't + * attempt to shrink it on tcq disable + */ +static int enable_queued(struct ata_device *drive, int on) +{ + int depth = drive->using_tcq ? drive->queue_depth : 0; + + /* + * disable or adjust queue depth + */ + if (!on) { + if (drive->using_tcq) + printk("%s: TCQ disabled\n", drive->name); + drive->using_tcq = 0; + return 0; + } + + if (configure_tcq(drive)) { + drive->using_tcq = 0; + return 1; + } + + /* + * enable block tagging + */ + if (!blk_queue_tagged(&drive->queue)) + blk_queue_init_tags(&drive->queue, IDE_MAX_TAG); + + /* + * check auto-poll support + */ + check_autopoll(drive); + + if (depth != drive->queue_depth) + printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth); + + drive->using_tcq = 1; + return 0; +} + +static int tcq_wait_dataphase(struct ata_device *drive) +{ + u8 stat; + int i; + + while ((stat = GET_STAT()) & BUSY_STAT) + udelay(10); + + if (OK_STAT(stat, READY_STAT | DRQ_STAT, drive->bad_wstat)) + return 0; + + i = 0; + udelay(1); + while (!OK_STAT(GET_STAT(), READY_STAT | DRQ_STAT, drive->bad_wstat)) { + if (unlikely(i++ > IDE_TCQ_WAIT)) + return 1; + + udelay(10); + } + + return 0; +} + +ide_startstop_t ide_tcq_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +{ + struct ata_channel *hwif = drive->channel; + unsigned int enable_tcq = 1; + u8 stat; + u8 feat; + + switch (func) { + /* + * invoked from a SERVICE interrupt, command etc already known. + * just need to start the dma engine for this tag + */ + case ide_dma_queued_start: + TCQ_PRINTK("ide_dma: setting up queued %d\n", rq->tag); + if (!test_bit(IDE_BUSY, &HWGROUP(drive)->flags)) + printk("queued_rw: IDE_BUSY not set\n"); + + if (tcq_wait_dataphase(drive)) + return ide_stopped; + + if (ide_start_dma(func, drive)) + return ide_stopped; + + set_irq(drive, ide_dmaq_intr); + if (!hwif->udma(ide_dma_begin, drive, rq)) + return ide_started; + + return ide_stopped; + + /* + * start a queued command from scratch + */ + case ide_dma_read_queued: + case ide_dma_write_queued: { + struct ata_taskfile *args = rq->special; + + TCQ_PRINTK("%s: start tag %d\n", drive->name, rq->tag); + + /* + * set nIEN, tag start operation will enable again when + * it is safe + */ + drive_ctl_nien(drive, 1); + + OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG); + + if (wait_altstat(drive, &stat, BUSY_STAT)) { + ide_dump_status(drive, "queued start", stat); + tcq_invalidate_queue(drive); + return ide_stopped; + } + + drive_ctl_nien(drive, 0); + + if (stat & ERR_STAT) { + ide_dump_status(drive, "tcq_start", stat); + return ide_stopped; + } + + /* + * drive released the bus, clear active tag and + * check for service + */ + if ((feat = GET_FEAT()) & NSEC_REL) { + drive->immed_rel++; + HWGROUP(drive)->rq = NULL; + set_irq(drive, ide_dmaq_intr); + + TCQ_PRINTK("REL in queued_start\n"); + + if ((stat = GET_STAT()) & SERVICE_STAT) + return service(drive); + + return ide_released; + } + + TCQ_PRINTK("IMMED in queued_start\n"); + drive->immed_comp++; + return hwif->udma(ide_dma_queued_start, drive, rq); + } + + case ide_dma_queued_off: + enable_tcq = 0; + case ide_dma_queued_on: + if (enable_tcq && !drive->using_dma) + return 1; + return enable_queued(drive, enable_tcq); + default: + break; + } + + return 1; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/ieee1394/ieee1394_syms.c linux-2.5/drivers/ieee1394/ieee1394_syms.c --- linux-2.5.13/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.13/drivers/input/Config.help linux-2.5/drivers/input/Config.help --- linux-2.5.13/drivers/input/Config.help Fri May 3 01:22:48 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.13/drivers/input/Config.in linux-2.5/drivers/input/Config.in --- linux-2.5.13/drivers/input/Config.in Fri May 3 01:22:52 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.13/drivers/input/Makefile linux-2.5/drivers/input/Makefile --- linux-2.5.13/drivers/input/Makefile Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/input/Makefile Thu Mar 28 00:08:14 2002 @@ -8,7 +8,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. @@ -18,11 +18,29 @@ 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 subdir-$(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 ifeq ($(CONFIG_INPUT_JOYSTICK),y) obj-y += joystick/joydrv.o +endif + +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.13/drivers/input/evbug.c linux-2.5/drivers/input/evbug.c --- linux-2.5.13/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.13/drivers/input/evdev.c linux-2.5/drivers/input/evdev.c --- linux-2.5.13/drivers/input/evdev.c Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/input/evdev.c Fri Jan 25 00:37:57 2002 @@ -117,7 +117,7 @@ } kfree(list); - + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/input/gameport/Config.help linux-2.5/drivers/input/gameport/Config.help --- linux-2.5.13/drivers/input/gameport/Config.help Fri May 3 01:22:44 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.13/drivers/input/gameport/Config.in linux-2.5/drivers/input/gameport/Config.in --- linux-2.5.13/drivers/input/gameport/Config.in Fri May 3 01:22: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.13/drivers/input/gameport/Makefile linux-2.5/drivers/input/gameport/Makefile --- linux-2.5.13/drivers/input/gameport/Makefile Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/input/gameport/Makefile Sat Mar 23 22:53:44 2002 @@ -15,9 +15,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.13/drivers/input/gameport/cs461x.c linux-2.5/drivers/input/gameport/cs461x.c --- linux-2.5.13/drivers/input/gameport/cs461x.c Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/input/gameport/cs461x.c Tue Feb 26 21:24:48 2002 @@ -159,7 +159,7 @@ static int cs461x_free(struct pci_dev *pdev) { - struct gameport *port = pci_get_drvdata(pdev); + struct gameport *port = (struct gameport *)pdev->driver_data; if(port){ gameport_unregister_port(port); kfree(port); @@ -280,7 +280,7 @@ } memset(port, 0, sizeof(struct gameport)); - pci_set_drvdata(pdev, port); + pdev->driver_data = port; port->open = cs461x_gameport_open; port->trigger = cs461x_gameport_trigger; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/input/gameport/fm801-gp.c linux-2.5/drivers/input/gameport/fm801-gp.c --- linux-2.5.13/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.13/drivers/input/gameport/ns558.c linux-2.5/drivers/input/gameport/ns558.c --- linux-2.5.13/drivers/input/gameport/ns558.c Fri May 3 01:22:46 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.13/drivers/input/gameport/pcigame.c linux-2.5/drivers/input/gameport/pcigame.c --- linux-2.5.13/drivers/input/gameport/pcigame.c Fri May 3 01:22:43 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.13/drivers/input/gameport/vortex.c linux-2.5/drivers/input/gameport/vortex.c --- linux-2.5.13/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.13/drivers/input/input.c linux-2.5/drivers/input/input.c --- linux-2.5.13/drivers/input/input.c Fri May 3 01:22:54 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.13/drivers/input/joystick/Config.help linux-2.5/drivers/input/joystick/Config.help --- linux-2.5.13/drivers/input/joystick/Config.help Fri May 3 01:22: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.13/drivers/input/joystick/Config.in linux-2.5/drivers/input/joystick/Config.in --- linux-2.5.13/drivers/input/joystick/Config.in Fri May 3 01:22:56 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.13/drivers/input/joystick/Makefile linux-2.5/drivers/input/joystick/Makefile --- linux-2.5.13/drivers/input/joystick/Makefile Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/input/joystick/Makefile Sun Jan 20 17:11:45 2002 @@ -6,24 +6,6 @@ O_TARGET := joydrv.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 - # Each configuration option enables a list of files. obj-$(CONFIG_JOYSTICK_A3D) += a3d.o @@ -35,8 +17,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 @@ -44,7 +27,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.13/drivers/input/joystick/guillemot.c linux-2.5/drivers/input/joystick/guillemot.c --- linux-2.5.13/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.13/drivers/input/joystick/iforce/Makefile linux-2.5/drivers/input/joystick/iforce/Makefile --- linux-2.5.13/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.13/drivers/input/joystick/iforce/iforce-ff.c linux-2.5/drivers/input/joystick/iforce/iforce-ff.c --- linux-2.5.13/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.13/drivers/input/joystick/iforce/iforce-main.c linux-2.5/drivers/input/joystick/iforce/iforce-main.c --- linux-2.5.13/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.13/drivers/input/joystick/iforce/iforce-packets.c linux-2.5/drivers/input/joystick/iforce/iforce-packets.c --- linux-2.5.13/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.13/drivers/input/joystick/iforce/iforce-serio.c linux-2.5/drivers/input/joystick/iforce/iforce-serio.c --- linux-2.5.13/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.13/drivers/input/joystick/iforce/iforce-usb.c linux-2.5/drivers/input/joystick/iforce/iforce-usb.c --- linux-2.5.13/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.13/drivers/input/joystick/iforce/iforce.h linux-2.5/drivers/input/joystick/iforce/iforce.h --- linux-2.5.13/drivers/input/joystick/iforce/iforce.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce.h Thu May 2 22:27:25 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.13/drivers/input/joystick/iforce.c linux-2.5/drivers/input/joystick/iforce.c --- linux-2.5.13/drivers/input/joystick/iforce.c Fri May 3 01:22:41 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.13/drivers/input/joystick/joydump.c linux-2.5/drivers/input/joystick/joydump.c --- linux-2.5.13/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.13/drivers/input/joystick/twidjoy.c linux-2.5/drivers/input/joystick/twidjoy.c --- linux-2.5.13/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.13/drivers/input/keybdev.c linux-2.5/drivers/input/keybdev.c --- linux-2.5.13/drivers/input/keybdev.c Fri May 3 01:22:45 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.13/drivers/input/keyboard/Config.help linux-2.5/drivers/input/keyboard/Config.help --- linux-2.5.13/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.13/drivers/input/keyboard/Config.in linux-2.5/drivers/input/keyboard/Config.in --- linux-2.5.13/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.13/drivers/input/keyboard/Makefile linux-2.5/drivers/input/keyboard/Makefile --- linux-2.5.13/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.13/drivers/input/keyboard/amikbd.c linux-2.5/drivers/input/keyboard/amikbd.c --- linux-2.5.13/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.13/drivers/input/keyboard/atkbd.c linux-2.5/drivers/input/keyboard/atkbd.c --- linux-2.5.13/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.13/drivers/input/keyboard/maple_keyb.c linux-2.5/drivers/input/keyboard/maple_keyb.c --- linux-2.5.13/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.13/drivers/input/keyboard/ps2serkbd.c linux-2.5/drivers/input/keyboard/ps2serkbd.c --- linux-2.5.13/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.13/drivers/input/keyboard/sunkbd.c linux-2.5/drivers/input/keyboard/sunkbd.c --- linux-2.5.13/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.13/drivers/input/keyboard/xtkbd.c linux-2.5/drivers/input/keyboard/xtkbd.c --- linux-2.5.13/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.13/drivers/input/mouse/Config.help linux-2.5/drivers/input/mouse/Config.help --- linux-2.5.13/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.13/drivers/input/mouse/Config.in linux-2.5/drivers/input/mouse/Config.in --- linux-2.5.13/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.13/drivers/input/mouse/Makefile linux-2.5/drivers/input/mouse/Makefile --- linux-2.5.13/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.13/drivers/input/mouse/amimouse.c linux-2.5/drivers/input/mouse/amimouse.c --- linux-2.5.13/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.13/drivers/input/mouse/inport.c linux-2.5/drivers/input/mouse/inport.c --- linux-2.5.13/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.13/drivers/input/mouse/logibm.c linux-2.5/drivers/input/mouse/logibm.c --- linux-2.5.13/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.13/drivers/input/mouse/maplemouse.c linux-2.5/drivers/input/mouse/maplemouse.c --- linux-2.5.13/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.13/drivers/input/mouse/pc110pad.c linux-2.5/drivers/input/mouse/pc110pad.c --- linux-2.5.13/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.13/drivers/input/mouse/psmouse.c linux-2.5/drivers/input/mouse/psmouse.c --- linux-2.5.13/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.13/drivers/input/mouse/rpcmouse.c linux-2.5/drivers/input/mouse/rpcmouse.c --- linux-2.5.13/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.13/drivers/input/mouse/sermouse.c linux-2.5/drivers/input/mouse/sermouse.c --- linux-2.5.13/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.13/drivers/input/power.c linux-2.5/drivers/input/power.c --- linux-2.5.13/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.13/drivers/input/serio/Config.help linux-2.5/drivers/input/serio/Config.help --- linux-2.5.13/drivers/input/serio/Config.help Fri May 3 01:22:38 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.13/drivers/input/serio/Config.in linux-2.5/drivers/input/serio/Config.in --- linux-2.5.13/drivers/input/serio/Config.in Fri May 3 01:22:55 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.13/drivers/input/serio/Makefile linux-2.5/drivers/input/serio/Makefile --- linux-2.5.13/drivers/input/serio/Makefile Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/input/serio/Makefile Mon Jan 21 23:54:13 2002 @@ -13,7 +13,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.13/drivers/input/serio/ct82c710.c linux-2.5/drivers/input/serio/ct82c710.c --- linux-2.5.13/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.13/drivers/input/serio/i8042.c linux-2.5/drivers/input/serio/i8042.c --- linux-2.5.13/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.13/drivers/input/serio/i8042.h linux-2.5/drivers/input/serio/i8042.h --- linux-2.5.13/drivers/input/serio/i8042.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/i8042.h Thu May 2 22:28:09 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.13/drivers/input/serio/parkbd.c linux-2.5/drivers/input/serio/parkbd.c --- linux-2.5.13/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.13/drivers/input/serio/rpckbd.c linux-2.5/drivers/input/serio/rpckbd.c --- linux-2.5.13/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.13/drivers/input/touchscreen/Config.help linux-2.5/drivers/input/touchscreen/Config.help --- linux-2.5.13/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.13/drivers/input/touchscreen/Config.in linux-2.5/drivers/input/touchscreen/Config.in --- linux-2.5.13/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.13/drivers/input/touchscreen/Makefile linux-2.5/drivers/input/touchscreen/Makefile --- linux-2.5.13/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.13/drivers/input/touchscreen/gunze.c linux-2.5/drivers/input/touchscreen/gunze.c --- linux-2.5.13/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.13/drivers/input/tsdev.c linux-2.5/drivers/input/tsdev.c --- linux-2.5.13/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.13/drivers/isdn/Config.in linux-2.5/drivers/isdn/Config.in --- linux-2.5.13/drivers/isdn/Config.in Fri May 3 01:22:54 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.13/drivers/isdn/hardware/avm/b1isa.c linux-2.5/drivers/isdn/hardware/avm/b1isa.c --- linux-2.5.13/drivers/isdn/hardware/avm/b1isa.c Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/isdn/hardware/avm/b1isa.c Fri May 3 12:57:30 2002 @@ -80,19 +80,20 @@ card->cardtype = avm_b1isa; if ( card->port != 0x150 && card->port != 0x250 - && card->port != 0x300 && card->port != 0x340) { + && card->port != 0x300 && card->port != 0x340) { printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port); retval = -EINVAL; goto err_free; } if (b1_irq_table[card->irq & 0xf] == 0) { printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq); + release_region(card->port, AVMB1_PORTLEN); retval = -EINVAL; goto err_free; } if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { printk(KERN_WARNING "b1isa: ports 0x%03x-0x%03x in use.\n", - card->port, card->port + AVMB1_PORTLEN); + card->port, card->port + AVMB1_PORTLEN); retval = -EBUSY; goto err_free; } @@ -104,7 +105,7 @@ b1_reset(card->port); if ((retval = b1_detect(card->port, card->cardtype)) != 0) { printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n", - card->port, retval); + card->port, retval); retval = -ENODEV; goto err_free_irq; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/isdn/hisax/Makefile linux-2.5/drivers/isdn/hisax/Makefile --- linux-2.5.13/drivers/isdn/hisax/Makefile Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/isdn/hisax/Makefile Wed Mar 27 13:07:16 2002 @@ -60,6 +60,7 @@ obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o +obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o obj-$(CONFIG_HISAX_FRITZ_CLASSIC) += hisax_isac.o hisax_hscx.o hisax_fcclassic.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/isdn/hisax/avm_a1.c linux-2.5/drivers/isdn/hisax/avm_a1.c --- linux-2.5.13/drivers/isdn/hisax/avm_a1.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/isdn/hisax/avm_a1.c Sat Mar 23 22:53:55 2002 @@ -196,17 +196,15 @@ cs->hw.avm.hscxfifo[0] = card->para[1]; cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800; cs->irq = card->para[0]; - if (check_region((cs->hw.avm.cfg_reg), 8)) { + if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[card->typ], cs->hw.avm.cfg_reg, cs->hw.avm.cfg_reg + 8); return (0); - } else { - request_region(cs->hw.avm.cfg_reg, 8, "avm cfg"); } - if (check_region((cs->hw.avm.isac + 32), 32)) { + if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) { printk(KERN_WARNING "HiSax: %s isac ports %x-%x already in use\n", CardType[cs->typ], @@ -214,20 +212,16 @@ cs->hw.avm.isac + 64); release_ioregs(cs, 0); return (0); - } else { - request_region(cs->hw.avm.isac + 32, 32, "HiSax isac"); } - if (check_region((cs->hw.avm.isacfifo), 1)) { + if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) { printk(KERN_WARNING "HiSax: %s isac fifo port %x already in use\n", CardType[cs->typ], cs->hw.avm.isacfifo); release_ioregs(cs, 1); return (0); - } else { - request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo"); } - if (check_region((cs->hw.avm.hscx[0]) + 32, 32)) { + if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) { printk(KERN_WARNING "HiSax: %s hscx A ports %x-%x already in use\n", CardType[cs->typ], @@ -235,20 +229,16 @@ cs->hw.avm.hscx[0] + 64); release_ioregs(cs, 3); return (0); - } else { - request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A"); } - if (check_region(cs->hw.avm.hscxfifo[0], 1)) { + if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) { printk(KERN_WARNING "HiSax: %s hscx A fifo port %x already in use\n", CardType[cs->typ], cs->hw.avm.hscxfifo[0]); release_ioregs(cs, 7); return (0); - } else { - request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo"); } - if (check_region(cs->hw.avm.hscx[1] + 32, 32)) { + if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) { printk(KERN_WARNING "HiSax: %s hscx B ports %x-%x already in use\n", CardType[cs->typ], @@ -256,18 +246,14 @@ cs->hw.avm.hscx[1] + 64); release_ioregs(cs, 0xf); return (0); - } else { - request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B"); } - if (check_region(cs->hw.avm.hscxfifo[1], 1)) { + if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) { printk(KERN_WARNING "HiSax: %s hscx B fifo port %x already in use\n", CardType[cs->typ], cs->hw.avm.hscxfifo[1]); release_ioregs(cs, 0x1f); return (0); - } else { - request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo"); } save_flags(flags); byteout(cs->hw.avm.cfg_reg, 0x0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/isdn/hisax/avma1_cs.c linux-2.5/drivers/isdn/hisax/avma1_cs.c --- linux-2.5.13/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.13/drivers/isdn/hisax/hfc_pci.c linux-2.5/drivers/isdn/hisax/hfc_pci.c --- linux-2.5.13/drivers/isdn/hisax/hfc_pci.c Fri May 3 01:22:51 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.13/drivers/isdn/hisax/hisax_fcpcipnp.c linux-2.5/drivers/isdn/hisax/hisax_fcpcipnp.c --- linux-2.5.13/drivers/isdn/hisax/hisax_fcpcipnp.c Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/isdn/hisax/hisax_fcpcipnp.c Tue Feb 26 21:24:48 2002 @@ -370,7 +370,7 @@ unsigned long flags; unsigned char *p; - DBG(0x40, ""); + DBG(0x40, "hdlc_fill_fifo"); if (skb->len == 0) BUG(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/isdn/hisax/md5sums.asc linux-2.5/drivers/isdn/hisax/md5sums.asc --- linux-2.5.13/drivers/isdn/hisax/md5sums.asc Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/isdn/hisax/md5sums.asc Fri Feb 8 03:15:29 2002 @@ -1,3 +1,6 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + # This are valid md5sums for certificated HiSax driver. # The certification is valid only if the md5sums of all files match. # The certification is valid only for ELSA Microlink PCI, @@ -6,17 +9,25 @@ # in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -d08b59f56fb9ed1fbd17713342c75081 isac.c -e81e6e96f307e55f8b9777aca2b356d9 isdnl1.c -cfd2527d9fb01885484cba74bfc67121 isdnl2.c -8c6829f11459f9d044b5768803fb646d isdnl3.c -d40f88dff4191d2660240749cbdcb688 tei.c -3bd3bd05ee4cb25ffe046200b569a83a callc.c -d518f52402ebc3f1be84e09af375313c cert.c -c425de1f8be86e84006de63c9bb3cc5f l3dss1.c -4c411e29d4103ba60e9af4e3e1234a99 l3_1tr6.c -68c6cc2784f208e3247a5a555918d014 elsa.c -8d63a85d7222cf7b40e663e543191d8f diva.c -8c8cb4ce621fb84d8e337a696e75b0df sedlbauer.c -ebe5613d535748409407568435b2be97 hfc_pci.c +cd4a9917e1147039d5dfc66440d42054 isac.c +211840e78b56c9d4753be9c85da21a50 isdnl1.c +5ce9b1fff42a02f9c2eb4fb81c701b1f isdnl2.c +6948de0c43513dd23c6706feb5fc2209 isdnl3.c +3730780b69368218d756024165efea79 tei.c +16e72710eb58da01415b877490f5d2ac callc.c +6abc55c77e0f3149ae9334f3257a1a1a cert.c +27bdb2800d4590e00da20eff241edc47 l3dss1.c +df8bb877b854c4302d396b554e4e84ef l3_1tr6.c +3d22d2f2fe9af693eb3b471beecf596d elsa.c +fd6aedade5b5bbd73683a3de878b76d2 diva.c +def8d69efd25186878dc123df73d9319 sedlbauer.c +6c5bd0fdc59f33319823fa5367357983 hfc_pci.c # end of md5sums +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +iD8DBQE8UYO9DiY0VZsg4ukRAqLzAKCKK7rFSNAWpBMtpJZ0kYvF+y+b1wCZAY8u +hf6AL732sGhUsfRpwwdENVU= +=B3yd +-----END PGP SIGNATURE----- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/isdn/hisax/w6692.c linux-2.5/drivers/isdn/hisax/w6692.c --- linux-2.5.13/drivers/isdn/hisax/w6692.c Fri May 3 01:22:56 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.13/drivers/isdn/isdn_audio.c linux-2.5/drivers/isdn/isdn_audio.c --- linux-2.5.13/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.13/drivers/isdn/isdn_audio.h linux-2.5/drivers/isdn/isdn_audio.h --- linux-2.5.13/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.13/drivers/macintosh/Makefile linux-2.5/drivers/macintosh/Makefile --- linux-2.5.13/drivers/macintosh/Makefile Fri May 3 01:22:48 2002 +++ linux-2.5/drivers/macintosh/Makefile Thu Dec 27 16:32:31 2001 @@ -32,9 +32,11 @@ obj-$(CONFIG_MAC_HID) += mac_hid.o obj-$(CONFIG_INPUT_ADBHID) += adbhid.o obj-$(CONFIG_PPC_RTC) += rtc.o +obj-$(CONFIG_ANSLCD) += ans-lcd.o obj-$(CONFIG_ADB_PMU) += via-pmu.o obj-$(CONFIG_ADB_CUDA) += via-cuda.o +obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o obj-$(CONFIG_ADB) += adb.o obj-$(CONFIG_ADB_KEYBOARD) += mac_keyb.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/adb.c linux-2.5/drivers/macintosh/adb.c --- linux-2.5.13/drivers/macintosh/adb.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/macintosh/adb.c Mon Apr 15 01:00:20 2002 @@ -34,6 +34,7 @@ #include #include #include +#include #include #ifdef CONFIG_PPC #include @@ -78,7 +79,7 @@ static int adb_inited = 0; static pid_t adb_probe_task_pid; static unsigned long adb_probe_task_flag; -static wait_queue_head_t adb_probe_task_wq; +static struct completion adb_probe_task_comp; static int sleepy_trackpad; int __adb_probe_sync; @@ -318,7 +319,7 @@ if (machine_is_compatible("AAPL,PowerBook1998") || machine_is_compatible("PowerBook1,1")) sleepy_trackpad = 1; - init_waitqueue_head(&adb_probe_task_wq); + init_completion(&adb_probe_task_comp); adbdev_init(); adb_reset_bus(); } @@ -435,7 +436,7 @@ static void adb_probe_wakeup(struct adb_request *req) { - wake_up(&adb_probe_task_wq); + complete(&adb_probe_task_comp); } static struct adb_request adb_sreq; @@ -484,20 +485,11 @@ if ((flags & ADBREQ_SYNC) && (current->pid && adb_probe_task_pid && adb_probe_task_pid == current->pid)) { - DECLARE_WAITQUEUE(wait, current); req->done = adb_probe_wakeup; - add_wait_queue(&adb_probe_task_wq, &wait); rc = adb_controller->send_request(req, 0); if (rc || req->complete) goto bail; - for (;;) { - set_current_state(TASK_UNINTERRUPTIBLE); - if (req->complete) - break; - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&adb_probe_task_wq, &wait); + wait_for_completion(&adb_probe_task_comp); rc = 0; goto bail; } @@ -705,17 +697,16 @@ return ret; req = NULL; + spin_lock_irqsave(&state->lock, flags); add_wait_queue(&state->wait_queue, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { - spin_lock_irqsave(&state->lock, flags); req = state->completed; if (req != NULL) state->completed = req->next; else if (atomic_read(&state->n_pending) == 0) ret = -EIO; - spin_unlock_irqrestore(&state->lock, flags); if (req != NULL || ret != 0) break; @@ -727,12 +718,15 @@ ret = -ERESTARTSYS; break; } + spin_unlock_irqrestore(&state->lock, flags); schedule(); + spin_lock_irqsave(&state->lock, flags); } current->state = TASK_RUNNING; remove_wait_queue(&state->wait_queue, &wait); - + spin_unlock_irqrestore(&state->lock, flags); + if (ret) return ret; @@ -755,6 +749,8 @@ if (count < 2 || count > sizeof(req->data)) return -EINVAL; + if (adb_controller == NULL) + return -ENXIO; ret = verify_area(VERIFY_READ, buf, count); if (ret) return ret; @@ -774,7 +770,10 @@ goto out; atomic_inc(&state->n_pending); - if (adb_controller == NULL) return -ENXIO; + + /* If a probe is in progress, wait for it to complete */ + while (adb_probe_task_pid != 0 || test_bit(0, &adb_probe_task_flag)) + schedule(); /* Special case for ADB_BUSRESET request, all others are sent to the controller */ @@ -782,6 +781,8 @@ &&(req->data[1] == ADB_BUSRESET)) { ret = do_adb_reset_bus(); atomic_dec(&state->n_pending); + if (ret == 0) + ret = count; goto out; } else { req->reply_expected = ((req->data[1] & 0xc) == 0xc); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/adbhid.c linux-2.5/drivers/macintosh/adbhid.c --- linux-2.5.13/drivers/macintosh/adbhid.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/macintosh/adbhid.c Sun Jan 20 17:11:46 2002 @@ -77,6 +77,7 @@ int mouse_kind; unsigned char *keycode; char name[64]; + char phys[32]; }; static struct adbhid *adbhid[16] = { 0 }; @@ -273,26 +274,39 @@ break; case 0x1f: /* Powerbook button device */ { + int down = (data[1] == (data[1] & 0xf)); #ifdef CONFIG_PMAC_BACKLIGHT int backlight = get_backlight_level(); - +#endif /* * XXX: Where is the contrast control for the passive? * -- Cort */ - switch (data[1]) { + switch (data[1] & 0x0f) { case 0x8: /* mute */ + input_report_key(&adbhid[id]->input, KEY_MUTE, + data[1] == (data[1] & 0xf)); break; - case 0x7: /* contrast decrease */ + case 0x7: /* volume decrease */ + input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, + data[1] == (data[1] & 0xf)); break; - case 0x6: /* contrast increase */ + case 0x6: /* volume increase */ + input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, + data[1] == (data[1] & 0xf)); + break; + + case 0xb: /* eject */ + input_report_key(&adbhid[id]->input, KEY_EJECTCD, + data[1] == (data[1] & 0xf)); break; +#ifdef CONFIG_PMAC_BACKLIGHT case 0xa: /* brightness decrease */ - if (backlight < 0) + if (!down || backlight < 0) break; if (backlight > BACKLIGHT_OFF) set_backlight_level(backlight-1); @@ -301,15 +315,15 @@ break; case 0x9: /* brightness increase */ - if (backlight < 0) + if (!down || backlight < 0) break; if (backlight < BACKLIGHT_MAX) set_backlight_level(backlight+1); else set_backlight_level(BACKLIGHT_MAX); break; - } #endif /* CONFIG_PMAC_BACKLIGHT */ + } } break; } @@ -420,6 +434,7 @@ return; memset(adbhid[id], 0, sizeof(struct adbhid)); + sprintf(adbhid[id]->phys, "adb%d:%d.%02x/input0", id, default_id, original_handler_id); adbhid[id]->id = default_id; adbhid[id]->original_handler_id = original_handler_id; @@ -427,6 +442,7 @@ adbhid[id]->mouse_kind = mouse_kind; adbhid[id]->input.private = adbhid[id]; adbhid[id]->input.name = adbhid[id]->name; + adbhid[id]->input.phys = adbhid[id]->phys; adbhid[id]->input.idbus = BUS_ADB; adbhid[id]->input.idvendor = 0x0001; adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id; @@ -439,8 +455,7 @@ return; } - sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x", - id, default_id, original_handler_id); + sprintf(adbhid[id]->name, "ADB keyboard"); memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); @@ -487,8 +502,7 @@ break; case ADB_MOUSE: - sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x", - id, default_id, original_handler_id); + sprintf(adbhid[id]->name, "ADB mouse"); adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); @@ -498,12 +512,15 @@ case ADB_MISC: switch (original_handler_id) { case 0x02: /* Adjustable keyboard button device */ - sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x", - id, default_id, original_handler_id); + sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons"); break; case 0x1f: /* Powerbook button device */ - sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x", - id, default_id, original_handler_id); + sprintf(adbhid[id]->name, "ADB Powerbook buttons"); + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + set_bit(KEY_MUTE, adbhid[id]->input.keybit); + set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit); + set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit); + set_bit(KEY_EJECTCD, adbhid[id]->input.keybit); break; } if (adbhid[id]->name[0]) @@ -520,8 +537,8 @@ input_register_device(&adbhid[id]->input); - printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n", - adbhid[id]->input.number, id, default_id, original_handler_id); + printk(KERN_INFO "input: %s on adb%d:%d.%02x\n", + adbhid[id]->name, id, default_id, original_handler_id); if (default_id == ADB_KEYBOARD) { /* HACK WARNING!! This should go away as soon there is an utility @@ -542,16 +559,38 @@ } +static u16 +adbhid_input_reregister(int id, int default_id, int org_handler_id, + int cur_handler_id, int mk) +{ + if (adbhid[id]) { + if (adbhid[id]->input.idproduct != + ((id << 12)|(default_id << 8)|org_handler_id)) { + adbhid_input_unregister(id); + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mk); + } + } else + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mk); + return 1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ANSLCD_ADDR 0xf301c000 +#define ANSLCD_CTRL_IX 0x00 +#define ANSLCD_DATA_IX 0x10 + +static unsigned long anslcd_short_delay = 80; +static unsigned long anslcd_long_delay = 3280; +static volatile unsigned char* anslcd_ptr; + +#undef DEBUG + +static void __pmac +anslcd_write_byte_ctrl ( unsigned char c ) +{ +#ifdef DEBUG + printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c); +#endif + out_8(anslcd_ptr + ANSLCD_CTRL_IX, c); + switch(c) { + case 1: + case 2: + case 3: + udelay(anslcd_long_delay); break; + default: udelay(anslcd_short_delay); + } +} + +static void __pmac +anslcd_write_byte_data ( unsigned char c ) +{ + out_8(anslcd_ptr + ANSLCD_DATA_IX, c); + udelay(anslcd_short_delay); +} + +static ssize_t __pmac +anslcd_write( struct file * file, const char * buf, + size_t count, loff_t *ppos ) +{ + const char * p = buf; + int i; + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: write\n"); +#endif + + if ( verify_area(VERIFY_READ, buf, count) ) + return -EFAULT; + for ( i = *ppos; count > 0; ++i, ++p, --count ) + { + char c; + __get_user(c, p); + anslcd_write_byte_data( c ); + } + *ppos = i; + return p - buf; +} + +static int __pmac +anslcd_ioctl( struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg ) +{ + char ch, *temp; + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg); +#endif + + switch ( cmd ) + { + case ANSLCD_CLEAR: + anslcd_write_byte_ctrl ( 0x38 ); + anslcd_write_byte_ctrl ( 0x0f ); + anslcd_write_byte_ctrl ( 0x06 ); + anslcd_write_byte_ctrl ( 0x01 ); + anslcd_write_byte_ctrl ( 0x02 ); + return 0; + case ANSLCD_SENDCTRL: + temp = (char *) arg; + __get_user(ch, temp); + for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */ + anslcd_write_byte_ctrl ( ch ); + __get_user(ch, temp); + } + return 0; + case ANSLCD_SETSHORTDELAY: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + anslcd_short_delay=arg; + return 0; + case ANSLCD_SETLONGDELAY: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + anslcd_long_delay=arg; + return 0; + default: + return -EINVAL; + } +} + +static int __pmac +anslcd_open( struct inode * inode, struct file * file ) +{ + return 0; +} + +struct file_operations anslcd_fops = { + write: anslcd_write, + ioctl: anslcd_ioctl, + open: anslcd_open, +}; + +static struct miscdevice anslcd_dev = { + ANSLCD_MINOR, + "anslcd", + &anslcd_fops +}; + +const char anslcd_logo[] = "********************" /* Line #1 */ + "* LINUX! *" /* Line #3 */ + "* Welcome to *" /* Line #2 */ + "********************"; /* Line #4 */ + +int __init +anslcd_init(void) +{ + int a; + struct device_node* node; + + node = find_devices("lcd"); + if (!node || !node->parent) + return -ENODEV; + if (strcmp(node->parent->name, "gc")) + return -ENODEV; + + anslcd_ptr = (volatile unsigned char*)ioremap(ANSLCD_ADDR, 0x20); + + misc_register(&anslcd_dev); + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: init\n"); +#endif + + anslcd_write_byte_ctrl ( 0x38 ); + anslcd_write_byte_ctrl ( 0x0c ); + anslcd_write_byte_ctrl ( 0x06 ); + anslcd_write_byte_ctrl ( 0x01 ); + anslcd_write_byte_ctrl ( 0x02 ); + for(a=0;a<80;a++) { + anslcd_write_byte_data(anslcd_logo[a]); + } + return 0; +} + +__initcall(anslcd_init); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/apm_emu.c linux-2.5/drivers/macintosh/apm_emu.c --- linux-2.5.13/drivers/macintosh/apm_emu.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/macintosh/apm_emu.c Wed Jan 23 01:11:51 2002 @@ -0,0 +1,546 @@ +/* APM emulation layer for PowerMac + * + * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * Lots of code inherited from apm.c, see appropriate notice in + * arch/i386/kernel/apm.c + * + * 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, 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. + * + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(KERN_DEBUG args) +//#define DBG(args...) xmon_printf(args) +#else +#define DBG(args...) do { } while (0) +#endif + +/* + * The apm_bios device is one of the misc char devices. + * This is its minor number. + */ +#define APM_MINOR_DEV 134 + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 20 + +#define FAKE_APM_BIOS_VERSION 0x0101 + +#define APM_USER_NOTIFY_TIMEOUT (5*HZ) + +/* + * The per-file APM data + */ +struct apm_user { + int magic; + struct apm_user * next; + int suser: 1; + int suspend_waiting: 1; + int suspends_pending; + int suspends_read; + int event_head; + int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The magic number in apm_user + */ +#define APM_BIOS_MAGIC 0x4101 + +/* + * Local variables + */ +static int suspends_pending; + +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +static struct apm_user * user_list; + +static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier apm_sleep_notifier = { + apm_notify_sleep, + SLEEP_LEVEL_USERLAND, +}; + +static char driver_version[] = "0.5"; /* no spaces */ + +#ifdef DEBUG +static char * apm_event_name[] = { + "system standby", + "system suspend", + "normal resume", + "critical resume", + "low battery", + "power status change", + "update time", + "critical suspend", + "user standby", + "user suspend", + "system standby resume", + "capabilities change" +}; +#define NR_APM_EVENT_NAME \ + (sizeof(apm_event_name) / sizeof(apm_event_name[0])) + +#endif + +static int queue_empty(struct apm_user *as) +{ + return as->event_head == as->event_tail; +} + +static apm_event_t get_queued_event(struct apm_user *as) +{ + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + return as->events[as->event_tail]; +} + +static void queue_event(apm_event_t event, struct apm_user *sender) +{ + struct apm_user * as; + + DBG("apm_emu: queue_event(%s)\n", apm_event_name[event-1]); + if (user_list == NULL) + return; + for (as = user_list; as != NULL; as = as->next) { + if (as == sender) + continue; + as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; + if (as->event_head == as->event_tail) { + static int notified; + + if (notified++ == 0) + printk(KERN_ERR "apm_emu: an event queue overflowed\n"); + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + } + as->events[as->event_head] = event; + if (!as->suser) + continue; + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_pending++; + suspends_pending++; + break; + case APM_NORMAL_RESUME: + as->suspend_waiting = 0; + break; + } + } + wake_up_interruptible(&apm_waitqueue); +} + +static int check_apm_user(struct apm_user *as, const char *func) +{ + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { + printk(KERN_ERR "apm_emu: %s passed bad filp\n", func); + return 1; + } + return 0; +} + +static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) +{ + struct apm_user * as; + int i; + apm_event_t event; + DECLARE_WAITQUEUE(wait, current); + + as = fp->private_data; + if (check_apm_user(as, "read")) + return -EIO; + if (count < sizeof(apm_event_t)) + return -EINVAL; + if (queue_empty(as)) { + if (fp->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&apm_waitqueue, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty(as) && !signal_pending(current)) { + schedule(); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_waitqueue, &wait); + } + i = count; + while ((i >= sizeof(event)) && !queue_empty(as)) { + event = get_queued_event(as); + DBG("apm_emu: do_read, returning: %s\n", apm_event_name[event-1]); + if (copy_to_user(buf, &event, sizeof(event))) { + if (i < count) + break; + return -EFAULT; + } + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_read++; + break; + } + buf += sizeof(event); + i -= sizeof(event); + } + if (i < count) + return count - i; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +static unsigned int do_poll(struct file *fp, poll_table * wait) +{ + struct apm_user * as; + + as = fp->private_data; + if (check_apm_user(as, "poll")) + return 0; + poll_wait(fp, &apm_waitqueue, wait); + if (!queue_empty(as)) + return POLLIN | POLLRDNORM; + return 0; +} + +static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +{ + struct apm_user * as; + DECLARE_WAITQUEUE(wait, current); + + as = filp->private_data; + if (check_apm_user(as, "ioctl")) + return -EIO; + if (!as->suser) + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: + /* If a suspend message was sent to userland, we + * consider this as a confirmation message + */ + if (as->suspends_read > 0) { + as->suspends_read--; + as->suspends_pending--; + suspends_pending--; + } else { + // Route to PMU suspend ? + break; + } + as->suspend_waiting = 1; + add_wait_queue(&apm_waitqueue, &wait); + DBG("apm_emu: ioctl waking up sleep waiter !\n"); + wake_up(&apm_suspend_waitqueue); + mb(); + while(as->suspend_waiting && !signal_pending(current)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_waitqueue, &wait); + break; + default: + return -EINVAL; + } + return 0; +} + +static int do_release(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = filp->private_data; + if (check_apm_user(as, "release")) + return 0; + filp->private_data = NULL; + lock_kernel(); + if (as->suspends_pending > 0) { + suspends_pending -= as->suspends_pending; + if (suspends_pending <= 0) + wake_up(&apm_suspend_waitqueue); + } + if (user_list == as) + user_list = as->next; + else { + struct apm_user * as1; + + for (as1 = user_list; + (as1 != NULL) && (as1->next != as); + as1 = as1->next) + ; + if (as1 == NULL) + printk(KERN_ERR "apm: filp not in user list\n"); + else + as1->next = as->next; + } + unlock_kernel(); + kfree(as); + return 0; +} + +static int do_open(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); + if (as == NULL) { + printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", + sizeof(*as)); + return -ENOMEM; + } + as->magic = APM_BIOS_MAGIC; + as->event_tail = as->event_head = 0; + as->suspends_pending = 0; + as->suspends_read = 0; + /* + * XXX - this is a tiny bit broken, when we consider BSD + * process accounting. If the device is opened by root, we + * instantly flag that we used superuser privs. Who knows, + * we might close the device immediately without doing a + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); + as->next = user_list; + user_list = as; + filp->private_data = as; + + DBG("apm_emu: opened by %s, suser: %d\n", current->comm, (int)as->suser); + + return 0; +} + +/* Wait for all clients to ack the suspend request. APM API + * doesn't provide a way to NAK, but this could be added + * here. + */ +static int wait_all_suspend(void) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&apm_suspend_waitqueue, &wait); + DBG("apm_emu: wait_all_suspend(), suspends_pending: %d\n", suspends_pending); + while(suspends_pending > 0) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_suspend_waitqueue, &wait); + + DBG("apm_emu: wait_all_suspend() - complete !\n"); + + return 1; +} + +static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when) +{ + switch(when) { + case PBOOK_SLEEP_REQUEST: + queue_event(APM_SYS_SUSPEND, NULL); + if (!wait_all_suspend()) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + case PBOOK_WAKE: + queue_event(APM_NORMAL_RESUME, NULL); + break; + } + return PBOOK_SLEEP_OK; +} + +#define APM_CRITICAL 10 +#define APM_LOW 30 + +static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length) +{ + /* Arguments, with symbols from linux/apm_bios.h. Information is + from the Get Power Status (0x0a) call unless otherwise noted. + + 0) Linux driver version (this will change if format changes) + 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. + 2) APM flags from APM Installation Check (0x00): + bit 0: APM_16_BIT_SUPPORT + bit 1: APM_32_BIT_SUPPORT + bit 2: APM_IDLE_SLOWS_CLOCK + bit 3: APM_BIOS_DISABLED + bit 4: APM_BIOS_DISENGAGED + 3) AC line status + 0x00: Off-line + 0x01: On-line + 0x02: On backup power (BIOS >= 1.1 only) + 0xff: Unknown + 4) Battery status + 0x00: High + 0x01: Low + 0x02: Critical + 0x03: Charging + 0x04: Selected battery not present (BIOS >= 1.2 only) + 0xff: Unknown + 5) Battery flag + bit 0: High + bit 1: Low + bit 2: Critical + bit 3: Charging + bit 7: No system battery + 0xff: Unknown + 6) Remaining battery life (percentage of charge): + 0-100: valid + -1: Unknown + 7) Remaining battery life (time units): + Number of remaining minutes or seconds + -1: Unknown + 8) min = minutes; sec = seconds */ + + unsigned short ac_line_status = 0xff; + unsigned short battery_status = 0xff; + unsigned short battery_flag = 0xff; + int percentage = -1; + int time_units = -1; + int real_count = 0; + int i; + char * p = buf; + + ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); + for (i=0; i> 8) & 0xff, + FAKE_APM_BIOS_VERSION & 0xff, + 0, + ac_line_status, + battery_status, + battery_flag, + percentage, + time_units, + "min"); + + return p - buf; +} + +static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, + read: do_read, + poll: do_poll, + ioctl: do_ioctl, + open: do_open, + release: do_release, +}; + +static struct miscdevice apm_device = { + APM_MINOR_DEV, + "apm_bios", + &apm_bios_fops +}; + +static int __init apm_emu_init(void) +{ + struct proc_dir_entry *apm_proc; + + if (sys_ctrler != SYS_CTRLER_PMU) { + printk(KERN_INFO "apm_emu: Requires a machine with a PMU.\n"); + return -ENODEV; + } + + apm_proc = create_proc_info_entry("apm", 0, NULL, apm_emu_get_info); + if (apm_proc) + SET_MODULE_OWNER(apm_proc); + + misc_register(&apm_device); + + pmu_register_sleep_notifier(&apm_sleep_notifier); + + printk(KERN_INFO "apm_emu: APM Emulation %s initialized.\n", driver_version); + + return 0; +} + +static void __exit apm_emu_exit(void) +{ + pmu_unregister_sleep_notifier(&apm_sleep_notifier); + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + + printk(KERN_INFO "apm_emu: APM Emulation removed.\n"); +} + +module_init(apm_emu_init); +module_exit(apm_emu_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt"); +MODULE_DESCRIPTION("APM emulation layer for PowerMac"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/mac_hid.c linux-2.5/drivers/macintosh/mac_hid.c --- linux-2.5.13/drivers/macintosh/mac_hid.c Fri May 3 01:22:47 2002 +++ linux-2.5/drivers/macintosh/mac_hid.c Thu Dec 27 16:32:31 2001 @@ -200,15 +200,15 @@ 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */ 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ - 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, KEY_VOLUMEUP, 0,/* 0x18-0x1f */ + 0, 0, 0, 0, 0, KEY_VOLUMEDOWN, KEY_MUTE, 0, /* 0x20-0x27 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */ - KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + KEY_RIGHTALT, 0, 0, KEY_EJECTCD, 0, 0, 0, 0, /* 0x38-0x3f */ 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */ KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */ KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */ - 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, KEY_POWER, 0, /* 0x58-0x5f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/macserial.c linux-2.5/drivers/macintosh/macserial.c --- linux-2.5.13/drivers/macintosh/macserial.c Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/macintosh/macserial.c Mon Feb 4 22:15:16 2002 @@ -39,7 +39,8 @@ #include #include #include -#include +#include +#include #include #include #ifdef CONFIG_KGDB @@ -58,6 +59,7 @@ #endif #define SUPPORT_SERIAL_DMA +#define MACSERIAL_VERSION "2.0" /* * It would be nice to dynamically allocate everything that @@ -1030,7 +1032,7 @@ { unsigned long flags; - OPNDBG("setting up ttys%d SCC...\n", info->line); + OPNDBG("setting up ttyS%d SCC...\n", info->line); save_flags(flags); cli(); /* Disable interrupts */ @@ -1178,7 +1180,7 @@ } memset(info->curregs, 0, sizeof(info->curregs)); - memset(info->curregs, 0, sizeof(info->pendregs)); + memset(info->pendregs, 0, sizeof(info->pendregs)); info->flags &= ~ZILOG_INITIALIZED; } @@ -1193,69 +1195,34 @@ { int delay = 0; - if (feature_test(info->dev_node, FEATURE_Serial_enable) < 0) - return 0; /* don't have serial power control */ - - /* The timings looks strange but that's the ones MacOS seems - to use for the internal modem. I think we can use a lot faster - ones, at least whe not using the modem, this should be tested. - */ if (state) { - PWRDBG("ttyS%02d: powering up hardware\n", info->line); - if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) { - feature_set(info->dev_node, FEATURE_Serial_enable); - mdelay(10); - feature_set(info->dev_node, FEATURE_Serial_reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Serial_reset); - mdelay(10); - } - if (info->zs_chan_a == info->zs_channel) - feature_set(info->dev_node, FEATURE_Serial_IO_A); - else - feature_set(info->dev_node, FEATURE_Serial_IO_B); - delay = 10; - if (info->is_cobalt_modem) { - feature_set_modem_power(info->dev_node, 1); + PWRDBG("ttyS%d: powering up hardware\n", info->line); + pmac_call_feature( + PMAC_FTR_SCC_ENABLE, + info->dev_node, info->port_type, 1); + if (info->is_internal_modem) { + pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, + info->dev_node, 0, 1); delay = 2500; /* wait for 2.5s before using */ - } -#ifdef CONFIG_PMAC_PBOOK - if (info->is_irda) - pmu_enable_irled(1); -#endif /* CONFIG_PMAC_PBOOK */ + } else if (info->is_irda) + mdelay(50); /* Do better here once the problems + * with blocking have been ironed out + */ } else { /* TODO: Make that depend on a timer, don't power down * immediately */ - PWRDBG("ttyS%02d: shutting down hardware\n", info->line); - if (info->is_cobalt_modem) { - PWRDBG("ttyS%02d: shutting down modem\n", info->line); - feature_set_modem_power(info->dev_node, 0); - } -#ifdef CONFIG_PMAC_PBOOK - if (info->is_irda) - pmu_enable_irled(0); -#endif /* CONFIG_PMAC_PBOOK */ - - if (info->zs_chan_a == info->zs_channel && !info->is_irda) { - PWRDBG("ttyS%02d: shutting down SCC channel A\n", info->line); - feature_clear(info->dev_node, FEATURE_Serial_IO_A); - } else if (!info->is_irda) { - PWRDBG("ttyS%02d: shutting down SCC channel B\n", info->line); - feature_clear(info->dev_node, FEATURE_Serial_IO_B); - } - /* XXX for now, shut down SCC core only on powerbooks */ - if (is_powerbook - && !(feature_test(info->dev_node, FEATURE_Serial_IO_A) || - feature_test(info->dev_node, FEATURE_Serial_IO_B))) { - PWRDBG("ttyS%02d: shutting down SCC core\n", info->line); - feature_set(info->dev_node, FEATURE_Serial_reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Serial_reset); - mdelay(25); - feature_clear(info->dev_node, FEATURE_Serial_enable); - mdelay(5); - } + PWRDBG("ttyS%d: shutting down hardware\n", info->line); + if (info->is_internal_modem) { + PWRDBG("ttyS%d: shutting down modem\n", info->line); + pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, + info->dev_node, 0, 0); + } + pmac_call_feature( + PMAC_FTR_SCC_ENABLE, + info->dev_node, info->port_type, 0); } return delay; } @@ -1988,7 +1955,7 @@ return; } - OPNDBG("rs_close ttys%d, count = %d\n", info->line, info->count); + OPNDBG("rs_close ttyS%d, count = %d\n", info->line, info->count); if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty @@ -2003,7 +1970,7 @@ } if (--info->count < 0) { printk(KERN_ERR "rs_close: bad serial port count for " - "ttys%d: %d\n", info->line, info->count); + "ttyS%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { @@ -2220,7 +2187,7 @@ */ retval = 0; add_wait_queue(&info->open_wait, &wait); - OPNDBG("block_til_ready before block: ttys%d, count = %d\n", + OPNDBG("block_til_ready before block: ttyS%d, count = %d\n", info->line, info->count); cli(); if (!tty_hung_up_p(filp)) @@ -2255,7 +2222,7 @@ retval = -ERESTARTSYS; break; } - OPNDBG("block_til_ready blocking: ttys%d, count = %d\n", + OPNDBG("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); schedule(); } @@ -2264,7 +2231,7 @@ if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; - OPNDBG("block_til_ready after blocking: ttys%d, count = %d\n", + OPNDBG("block_til_ready after blocking: ttyS%d, count = %d\n", info->line, info->count); if (retval) return retval; @@ -2365,7 +2332,7 @@ info->session = current->session; info->pgrp = current->pgrp; - OPNDBG("rs_open ttys%d successful...\n", info->line); + OPNDBG("rs_open ttyS%d successful...\n", info->line); return 0; } @@ -2373,14 +2340,14 @@ static void show_serial_version(void) { - printk(KERN_INFO "PowerMac Z8530 serial driver version 2.0\n"); + printk(KERN_INFO "PowerMac Z8530 serial driver version " MACSERIAL_VERSION "\n"); } /* * Initialize one channel, both the mac_serial and mac_zschannel * structs. We use the dev_node field of the mac_serial struct. */ -static void +static int chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan, struct mac_zschannel *zs_chan_a) { @@ -2410,12 +2377,15 @@ /* setup misc varariables */ zss->kgdb_channel = 0; - zss->is_cobalt_modem = device_is_compatible(ch, "cobalt"); - /* XXX tested only with wallstreet PowerBook, - should do no harm anyway */ + /* For now, we assume you either have a slot-names property + * with "Modem" in it, or your channel is compatible with + * "cobalt". Might need additional fixups + */ + zss->is_internal_modem = device_is_compatible(ch, "cobalt"); conn = get_property(ch, "AAPL,connector", &len); zss->is_irda = conn && (strcmp(conn, "infrared") == 0); + zss->port_type = PMAC_SCC_ASYNC; /* 1999 Powerbook G3 has slot-names property instead */ slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len); if (slots && slots->count > 0) { @@ -2424,8 +2394,29 @@ else if (strcmp(slots->name, "Modem") == 0) zss->is_internal_modem = 1; } + if (zss->is_irda) + zss->port_type = PMAC_SCC_IRDA; + if (zss->is_internal_modem) { + struct device_node* i2c_modem = find_devices("i2c-modem"); + if (i2c_modem) { + char* mid = get_property(i2c_modem, "modem-id", NULL); + if (mid) switch(*mid) { + case 0x04 : + case 0x05 : + case 0x07 : + case 0x08 : + case 0x0b : + case 0x0c : + zss->port_type = PMAC_SCC_I2S1; + } + printk(KERN_INFO "macserial: i2c-modem detected, id: %d\n", + mid ? (*mid) : 0); + } else { + printk(KERN_INFO "macserial: serial modem detected\n"); + } + } - if (zss->has_dma) { + while (zss->has_dma) { zss->dma_priv = NULL; /* it seems that the last two addresses are the DMA controllers */ @@ -2436,11 +2427,69 @@ zss->tx_dma_irq = ch->intrs[1].line; zss->rx_dma_irq = ch->intrs[2].line; spin_lock_init(&zss->rx_dma_lock); + break; } init_timer(&zss->powerup_timer); zss->powerup_timer.function = powerup_done; zss->powerup_timer.data = (unsigned long) zss; + return 0; +} + +/* + * /proc fs routines. TODO: Add status lines & error stats + */ +static inline int +line_info(char *buf, struct mac_serial *info) +{ + int ret=0; + unsigned char* connector; + int lenp; + + ret += sprintf(buf, "%d: port:0x%X irq:%d", info->line, info->port, info->irq); + + connector = get_property(info->dev_node, "AAPL,connector", &lenp); + if (connector) + ret+=sprintf(buf+ret," con:%s ", connector); + if (info->is_internal_modem) { + if (!connector) + ret+=sprintf(buf+ret," con:"); + ret+=sprintf(buf+ret,"%s", " (internal modem)"); + } + if (info->is_irda) { + if (!connector) + ret+=sprintf(buf+ret," con:"); + ret+=sprintf(buf+ret,"%s", " (IrDA)"); + } + ret+=sprintf(buf+ret,"\n"); + + return ret; +} + +int macserial_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int l, len = 0; + off_t begin = 0; + struct mac_serial *info; + + len += sprintf(page, "serinfo:1.0 driver:" MACSERIAL_VERSION "\n"); + for (info = zs_chain; info && len < 4000; info = info->zs_next) { + l = line_info(page + len, info); + 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 + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); } /* Ask the PROM how many Z8530s we have and initialize their zs_channels */ @@ -2495,13 +2544,15 @@ continue; /* set up A side */ - chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan); + if (chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan)) + continue; ++zs_chan; /* set up B side, if it exists */ if (nchan > 1) - chan_init(&zs_soft[chip + 1 - chan_a_index], - zs_chan, zs_chan - 1); + if (chan_init(&zs_soft[chip + 1 - chan_a_index], + zs_chan, zs_chan - 1)) + continue; ++zs_chan; } *pp = 0; @@ -2527,13 +2578,35 @@ if (zs_chain == 0) probe_sccs(); - /* XXX assume it's a powerbook if we have a via-pmu */ + /* XXX assume it's a powerbook if we have a via-pmu + * + * This is OK for core99 machines as well. + */ is_powerbook = find_devices("via-pmu") != 0; - /* Register the interrupt handler for each one */ + /* Register the interrupt handler for each one + * We also request the OF resources here as probe_sccs() + * might be called too early for that + */ save_flags(flags); cli(); for (i = 0; i < zs_channels_found; ++i) { + struct device_node* ch = zs_soft[i].dev_node; + if (!request_OF_resource(ch, 0, NULL)) { + printk(KERN_ERR "macserial: can't request IO resource !\n"); + return -ENODEV; + } if (zs_soft[i].has_dma) { + if (!request_OF_resource(ch, ch->n_addrs - 2, " (tx dma)")) { + printk(KERN_ERR "macserial: can't request TX DMA resource !\n"); + zs_soft[i].has_dma = 0; + goto no_dma; + } + if (!request_OF_resource(ch, ch->n_addrs - 1, " (rx dma)")) { + release_OF_resource(ch, ch->n_addrs - 2); + printk(KERN_ERR "macserial: can't request RX DMA resource !\n"); + zs_soft[i].has_dma = 0; + goto no_dma; + } if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0, "SCC-txdma", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", @@ -2545,6 +2618,7 @@ zs_soft[i].rx_dma_irq); disable_irq(zs_soft[i].rx_dma_irq); } +no_dma: if (request_irq(zs_soft[i].irq, rs_interrupt, 0, "SCC", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", @@ -2560,6 +2634,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "macserial"; #ifdef CONFIG_DEVFS_FS serial_driver.name = "tts/%d"; #else @@ -2579,7 +2654,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; @@ -2596,6 +2673,7 @@ serial_driver.hangup = rs_hangup; serial_driver.break_ctl = rs_break; serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = macserial_read_proc; /* * The callout device is just like normal device except for @@ -2609,6 +2687,8 @@ #endif /* CONFIG_DEVFS_FS */ 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"); @@ -2675,21 +2755,11 @@ connector = get_property(info->dev_node, "AAPL,connector", &lenp); if (connector) printk(", port = %s", connector); - if (info->is_cobalt_modem) - printk(" (cobalt modem)"); - else if (info->is_internal_modem) + if (info->is_internal_modem) printk(" (internal modem)"); if (info->is_irda) printk(" (IrDA)"); printk("\n"); - -#ifndef CONFIG_XMON -#ifdef CONFIG_KGDB - if (!info->kgdb_channel) -#endif /* CONFIG_KGDB */ - /* By default, disable the port */ - set_scc_power(info, 0); -#endif /* CONFIG_XMON */ } tmp_buf = 0; @@ -2710,6 +2780,12 @@ if (zs_soft[i].has_dma) { free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]); free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]); + } + release_OF_resource(zs_soft[i].dev_node, 0); + if (zs_soft[i].has_dma) { + struct device_node* ch = zs_soft[i].dev_node; + release_OF_resource(ch, ch->n_addrs - 2); + release_OF_resource(ch, ch->n_addrs - 1); } } restore_flags(flags); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/macserial.h linux-2.5/drivers/macintosh/macserial.h --- linux-2.5.13/drivers/macintosh/macserial.h Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/macintosh/macserial.h Thu Dec 27 16:32:31 2001 @@ -111,8 +111,8 @@ char kgdb_channel; /* Kgdb is running on this channel */ char is_cons; /* Is this our console. */ char is_internal_modem; /* is connected to an internal modem */ - char is_cobalt_modem; /* is a gatwick-based cobalt modem */ char is_irda; /* is connected to an IrDA codec */ + int port_type; /* Port type for pmac_feature */ unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ unsigned char power_wait; /* waiting for power-up delay to expire */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/mediabay.c linux-2.5/drivers/macintosh/mediabay.c --- linux-2.5.13/drivers/macintosh/mediabay.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/macintosh/mediabay.c Thu Dec 27 16:32:31 2001 @@ -25,9 +25,13 @@ #include #include #include -#include +#include +#include #include #include +#include +#include +#include #include #include @@ -40,7 +44,7 @@ #endif #undef MB_USE_INTERRUPTS -#undef MB_DEBUG +#define MB_DEBUG #define MB_IGNORE_SIGNALS #ifdef MB_DEBUG @@ -49,24 +53,46 @@ #define MBDBG(fmt, arg...) do { } while (0) #endif -struct media_bay_hw { - unsigned char b0; - unsigned char contents; - unsigned char b2; - unsigned char b3; +/* Type of media bay */ +enum { + mb_ohare, + mb_heathrow, + mb_keylargo +}; + +#define MB_FCR32(bay, r) ((bay)->base + ((r) >> 2)) +#define MB_FCR8(bay, r) (((volatile u8*)((bay)->base)) + (r)) + +#define MB_IN32(bay,r) (in_le32(MB_FCR32(bay,r))) +#define MB_OUT32(bay,r,v) (out_le32(MB_FCR32(bay,r), (v))) +#define MB_BIS(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) | (v))) +#define MB_BIC(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v))) +#define MB_IN8(bay,r) (in_8(MB_FCR8(bay,r))) +#define MB_OUT8(bay,r,v) (out_8(MB_FCR8(bay,r), (v))) + +struct media_bay_info; + +struct mb_ops { + char* name; + u8 (*content)(struct media_bay_info* bay); + void (*power)(struct media_bay_info* bay, int on_off); + int (*setup_bus)(struct media_bay_info* bay, u8 device_id); + void (*un_reset)(struct media_bay_info* bay); + void (*un_reset_ide)(struct media_bay_info* bay); }; struct media_bay_info { - volatile struct media_bay_hw* addr; - volatile u8* extint_gpio; + volatile u32* base; int content_id; int state; int last_value; int value_count; int timer; struct device_node* dev_node; - int pismo; /* New PowerBook3,1 */ - int gpio_cache; + int mb_type; + struct mb_ops* ops; + int index; + int cached_gpio; #ifdef CONFIG_BLK_DEV_IDE unsigned long cd_base; int cd_index; @@ -77,33 +103,12 @@ #define MAX_BAYS 2 -static volatile struct media_bay_info media_bays[MAX_BAYS]; +static struct media_bay_info media_bays[MAX_BAYS]; int media_bay_count = 0; -inline int mb_content(volatile struct media_bay_info *bay) -{ - if (bay->pismo) { - unsigned char new_gpio = in_8(bay->extint_gpio + 0xe) & 2; - if (new_gpio) { - bay->gpio_cache = new_gpio; - return MB_NO; - } else if (bay->gpio_cache != new_gpio) { - /* make sure content bits are set */ - feature_set(bay->dev_node, FEATURE_Mediabay_content); - udelay(5); - bay->gpio_cache = new_gpio; - } - return (in_le32((unsigned*)bay->addr) >> 4) & 0xf; - } else { - int cont = (in_8(&bay->addr->contents) >> 4) & 7; - return (cont == 7) ? MB_NO : cont; - } -} - #ifdef CONFIG_BLK_DEV_IDE /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ -//#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40) #define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0) #endif @@ -116,7 +121,7 @@ * Consider the media-bay ID value stable if it is the same for * this number of milliseconds */ -#define MB_STABLE_DELAY 40 +#define MB_STABLE_DELAY 100 /* Wait after powering up the media bay this delay in ms * timeout bumped for some powerbooks @@ -166,175 +171,259 @@ mb_powering_down /* Powering down (avoid too fast down/up) */ }; -static void poll_media_bay(int which); -static void set_media_bay(int which, int id); -static void set_mb_power(int which, int onoff); -static void media_bay_step(int i); -static int media_bay_task(void *); +#define MB_POWER_SOUND 0x08 +#define MB_POWER_FLOPPY 0x04 +#define MB_POWER_ATA 0x02 +#define MB_POWER_PCI 0x01 +#define MB_POWER_OFF 0x00 -#ifdef MB_USE_INTERRUPTS -static void media_bay_intr(int irq, void *devid, struct pt_regs *regs); -#endif +/* + * Functions for polling content of media bay + */ + +static u8 __pmac +ohare_mb_content(struct media_bay_info *bay) +{ + return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7; +} + +static u8 __pmac +heathrow_mb_content(struct media_bay_info *bay) +{ + return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7; +} + +static u8 __pmac +keylargo_mb_content(struct media_bay_info *bay) +{ + int new_gpio; + + new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA; + if (new_gpio) { + bay->cached_gpio = new_gpio; + return MB_NO; + } else if (bay->cached_gpio != new_gpio) { + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); + (void)MB_IN32(bay, KEYLARGO_MBCR); + udelay(5); + MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); + (void)MB_IN32(bay, KEYLARGO_MBCR); + udelay(5); + bay->cached_gpio = new_gpio; + } + return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7; +} /* - * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL - * register is always set when there is something in the media bay. - * This causes problems for the interrupt code if we attach an interrupt - * handler to the media-bay interrupt, because it tends to go into - * an infinite loop calling the media bay interrupt handler. - * Therefore we do it all by polling the media bay once each tick. + * Functions for powering up/down the bay, puts the bay device + * into reset state as well */ -void __pmac -media_bay_init(void) +static void __pmac +ohare_mb_power(struct media_bay_info* bay, int on_off) { - struct device_node *np; - int n,i; - - for (i=0; in_addrs == 0) - continue; - media_bays[n].addr = (volatile struct media_bay_hw *) - ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); + MB_BIC(bay, OHARE_MBCR, 0x00000F00); +} - media_bays[n].pismo = device_is_compatible(np, "keylargo-media-bay"); - if (media_bays[n].pismo) { - if (!np->parent || strcmp(np->parent->name, "mac-io")) { - printk(KERN_ERR "Pismo media-bay has no mac-io parent !\n"); - continue; - } - media_bays[n].extint_gpio = ioremap(np->parent->addrs[0].address - + 0x58, 0x10); - } +static void __pmac +heathrow_mb_power(struct media_bay_info* bay, int on_off) +{ + if (on_off) { + /* Power up device, assert it's reset line */ + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N); + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N); + } else { + /* Disable all devices */ + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK); + MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); + /* Cut power from bay, release reset line */ + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N); + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); + MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); + } + MB_BIC(bay, HEATHROW_MBCR, 0x00000F00); +} -#ifdef MB_USE_INTERRUPTS - if (np->n_intrs == 0) { - printk(KERN_ERR "media bay %d has no irq\n",n); - continue; - } +static void __pmac +keylargo_mb_power(struct media_bay_info* bay, int on_off) +{ + if (on_off) { + /* Power up device, assert it's reset line */ + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); + } else { + /* Disable all devices */ + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); + MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); + /* Cut power from bay, release reset line */ + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); + } + MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); +} - if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) { - printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", - np->intrs[0].line, n); - continue; - } -#endif - media_bay_count++; - - media_bays[n].dev_node = np; +/* + * Functions for configuring the media bay for a given type of device, + * enable the related busses + */ - /* Force an immediate detect */ - set_mb_power(n,0); - mdelay(MB_POWER_DELAY); - if(!media_bays[n].pismo) - out_8(&media_bays[n].addr->contents, 0x70); - mdelay(MB_STABLE_DELAY); - media_bays[n].content_id = MB_NO; - media_bays[n].last_value = mb_content(&media_bays[n]); - media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY); - media_bays[n].state = mb_empty; - do { - mdelay(1000/HZ); - media_bay_step(n); - } while((media_bays[n].state != mb_empty) && - (media_bays[n].state != mb_up)); +static int __pmac +ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_FD: + case MB_FD1: + MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE); + MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE); + return 0; + case MB_CD: + MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N); + MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE); + return 0; + } + return -ENODEV; +} - n++; - np=np->next; +static int __pmac +heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_FD: + case MB_FD1: + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE); + MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); + return 0; + case MB_CD: + MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE); + return 0; } + return -ENODEV; +} - if (media_bay_count) - { - printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count); +static int __pmac +keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_CD: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); + MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE); + return 0; + case MB_SOUND: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE); + return 0; + } + return -ENODEV; +} -#ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&mb_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ +/* + * Functions for tweaking resets + */ - kernel_thread(media_bay_task, NULL, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - } +static void __pmac +ohare_mb_un_reset(struct media_bay_info* bay) +{ + MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); } -#ifdef MB_USE_INTERRUPTS static void __pmac -media_bay_intr(int irq, void *devid, struct pt_regs *regs) +heathrow_mb_un_reset(struct media_bay_info* bay) { + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); +} + +static void __pmac +keylargo_mb_un_reset(struct media_bay_info* bay) +{ + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); +} + +static void __pmac +ohare_mb_un_reset_ide(struct media_bay_info* bay) +{ + MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); +} + +static void __pmac +heathrow_mb_un_reset_ide(struct media_bay_info* bay) +{ + MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); } -#endif static void __pmac -set_mb_power(int which, int onoff) +keylargo_mb_un_reset_ide(struct media_bay_info* bay) { - volatile struct media_bay_info* mb = &media_bays[which]; + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); +} +static inline void __pmac +set_mb_power(struct media_bay_info* bay, int onoff) +{ + /* Power up up and assert the bay reset line */ if (onoff) { - feature_set(mb->dev_node, FEATURE_Mediabay_power); - udelay(10); - feature_set(mb->dev_node, FEATURE_Mediabay_reset); - udelay(10); - mb->state = mb_powering_up; - MBDBG("mediabay%d: powering up\n", which); - } else { - feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable); - if (mb->pismo) - feature_clear(mb->dev_node, FEATURE_IDE0_enable); - else - feature_clear(mb->dev_node, FEATURE_IDE1_enable); - feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_switch); - feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable); - feature_clear(mb->dev_node, FEATURE_SWIM3_enable); - feature_clear(mb->dev_node, FEATURE_Mediabay_power); - mb->state = mb_powering_down; - MBDBG("mediabay%d: powering down\n", which); + bay->ops->power(bay, 1); + bay->state = mb_powering_up; + MBDBG("mediabay%d: powering up\n", bay->index); + } else { + /* Make sure everything is powered down & disabled */ + bay->ops->power(bay, 0); + bay->state = mb_powering_down; + MBDBG("mediabay%d: powering down\n", bay->index); } - mb->timer = MS_TO_HZ(MB_POWER_DELAY); + bay->timer = MS_TO_HZ(MB_POWER_DELAY); } static void __pmac -set_media_bay(int which, int id) +poll_media_bay(struct media_bay_info* bay) { - volatile struct media_bay_info* bay; + int id = bay->ops->content(bay); - bay = &media_bays[which]; - - switch (id) { - case MB_CD: - if (bay->pismo) { - feature_set(bay->dev_node, FEATURE_Mediabay_IDE_switch); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE0_enable); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE0_reset); - } else { - feature_set(bay->dev_node, FEATURE_IDE1_enable); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE1_reset); + if (id == bay->last_value) { + if (id != bay->content_id + && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) { + /* If the device type changes without going thru "MB_NO", we force + a pass by "MB_NO" to make sure things are properly reset */ + if ((id != MB_NO) && (bay->content_id != MB_NO)) { + id = MB_NO; + MBDBG("mediabay%d: forcing MB_NO\n", bay->index); } - printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which); - break; - case MB_FD: - case MB_FD1: - feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable); - feature_set(bay->dev_node, FEATURE_SWIM3_enable); - printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which); - break; - case MB_NO: - break; - default: - printk(KERN_INFO "media bay %d contains an unknown device (%d)\n", - which, id); - break; + MBDBG("mediabay%d: switching to %d\n", bay->index, id); + set_mb_power(bay, id != MB_NO); + bay->content_id = id; + if (id == MB_NO) { +#ifdef CONFIG_BLK_DEV_IDE + bay->cd_retry = 0; +#endif + printk(KERN_INFO "media bay %d is empty\n", bay->index); + } + } + } else { + bay->last_value = id; + bay->value_count = 0; } } @@ -412,11 +501,11 @@ static void __pmac media_bay_step(int i) { - volatile struct media_bay_info* bay = &media_bays[i]; + struct media_bay_info* bay = &media_bays[i]; /* We don't poll when powering down */ if (bay->state != mb_powering_down) - poll_media_bay(i); + poll_media_bay(bay); /* If timer expired or polling IDE busy, run state machine */ if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0)) @@ -424,13 +513,17 @@ switch(bay->state) { case mb_powering_up: - set_media_bay(i, bay->last_value); + if (bay->ops->setup_bus(bay, bay->last_value) < 0) { + MBDBG("mediabay%d: device not supported (kind:%d)\n", i, bay->content_id); + set_mb_power(bay, 0); + break; + } bay->timer = MS_TO_HZ(MB_RESET_DELAY); bay->state = mb_enabling_bay; MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id); break; case mb_enabling_bay: - feature_clear(bay->dev_node, FEATURE_Mediabay_reset); + bay->ops->un_reset(bay); bay->timer = MS_TO_HZ(MB_SETUP_DELAY); bay->state = mb_resetting; MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id); @@ -444,16 +537,13 @@ } #ifdef CONFIG_BLK_DEV_IDE MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id); - if (bay->pismo) - feature_clear(bay->dev_node, FEATURE_IDE0_reset); - else - feature_clear(bay->dev_node, FEATURE_IDE1_reset); + bay->ops->un_reset_ide(bay); bay->timer = MS_TO_HZ(MB_IDE_WAIT); bay->state = mb_ide_resetting; #else printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i); - set_mb_power(i, 0); -#endif // #ifdef CONFIG_BLK_DEV_IDE + set_mb_power(bay, 0); +#endif /* CONFIG_BLK_DEV_IDE */ break; #ifdef CONFIG_BLK_DEV_IDE @@ -481,7 +571,7 @@ /* We eventually do a retry */ bay->cd_retry++; printk("IDE register error\n"); - set_mb_power(i, 0); + set_mb_power(bay, 0); } else { printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index); MBDBG("mediabay %d IDE ready\n", i); @@ -491,10 +581,10 @@ if (bay->timer == 0) { printk("\nIDE Timeout in bay %d !\n", i); MBDBG("mediabay%d: nIDE Timeout !\n", i); - set_mb_power(i, 0); + set_mb_power(bay, 0); } break; -#endif // #ifdef CONFIG_BLK_DEV_IDE +#endif /* CONFIG_BLK_DEV_IDE */ case mb_powering_down: bay->state = mb_empty; @@ -514,7 +604,7 @@ bay->content_id = MB_NO; } } -#endif +#endif /* CONFIG_BLK_DEV_IDE */ MBDBG("mediabay%d: end of power down\n", i); break; } @@ -526,7 +616,7 @@ * with the IDE driver. It needs to be a thread because * ide_register can't be called from interrupt context. */ -int __pmac +static int __pmac media_bay_task(void *x) { int i; @@ -547,37 +637,12 @@ } } -void __pmac -poll_media_bay(int which) +#ifdef MB_USE_INTERRUPTS +static void __pmac +media_bay_intr(int irq, void *devid, struct pt_regs *regs) { - volatile struct media_bay_info* bay = &media_bays[which]; - int id = mb_content(bay); - - if (id == bay->last_value) { - if (id != bay->content_id - && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) { - /* If the device type changes without going thru "MB_NO", we force - a pass by "MB_NO" to make sure things are properly reset */ - if ((id != MB_NO) && (bay->content_id != MB_NO)) { - id = MB_NO; - MBDBG("mediabay%d: forcing MB_NO\n", which); - } - MBDBG("mediabay%d: switching to %d\n", which, id); - set_mb_power(which, id != MB_NO); - bay->content_id = id; - if (id == MB_NO) { -#ifdef CONFIG_BLK_DEV_IDE - bay->cd_retry = 0; -#endif - printk(KERN_INFO "media bay %d is empty\n", which); - } - } - } else { - bay->last_value = id; - bay->value_count = 0; - } } - +#endif #ifdef CONFIG_PMAC_PBOOK /* @@ -586,7 +651,7 @@ int __pmac mb_notify_sleep(struct pmu_sleep_notifier *self, int when) { - volatile struct media_bay_info* bay; + struct media_bay_info* bay; int i; switch (when) { @@ -597,7 +662,7 @@ case PBOOK_SLEEP_NOW: for (i=0; ipismo) - out_8(&bay->addr->contents, 0x70); - mdelay(MB_STABLE_DELAY); - if (mb_content(bay) != bay->content_id) + if (bay->ops->content(bay) != bay->content_id) continue; - set_mb_power(i, 1); + set_mb_power(bay, 1); bay->last_value = bay->content_id; bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); bay->timer = MS_TO_HZ(MB_POWER_DELAY); @@ -634,4 +696,135 @@ return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ + + +/* Definitions of "ops" structures. + */ +static struct mb_ops ohare_mb_ops __pmacdata = { + name: "Ohare", + content: ohare_mb_content, + power: ohare_mb_power, + setup_bus: ohare_mb_setup_bus, + un_reset: ohare_mb_un_reset, + un_reset_ide: ohare_mb_un_reset_ide, +}; + +static struct mb_ops heathrow_mb_ops __pmacdata = { + name: "Heathrow", + content: heathrow_mb_content, + power: heathrow_mb_power, + setup_bus: heathrow_mb_setup_bus, + un_reset: heathrow_mb_un_reset, + un_reset_ide: heathrow_mb_un_reset_ide, +}; + +static struct mb_ops keylargo_mb_ops __pmacdata = { + name: "KeyLargo", + content: keylargo_mb_content, + power: keylargo_mb_power, + setup_bus: keylargo_mb_setup_bus, + un_reset: keylargo_mb_un_reset, + un_reset_ide: keylargo_mb_un_reset_ide, +}; + +/* + * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL + * register is always set when there is something in the media bay. + * This causes problems for the interrupt code if we attach an interrupt + * handler to the media-bay interrupt, because it tends to go into + * an infinite loop calling the media bay interrupt handler. + * Therefore we do it all by polling the media bay once each tick. + */ + +void __pmac +media_bay_init(void) +{ + struct device_node *np; + int n,i; + + for (i=0; iparent || np->n_addrs == 0 || !request_OF_resource(np, 0, NULL)) { + np = np->next; + printk(KERN_ERR "media-bay: Can't request IO resource !\n"); + continue; + } + bay->mb_type = mb_ohare; + + if (device_is_compatible(np, "keylargo-media-bay")) { + bay->mb_type = mb_keylargo; + bay->ops = &keylargo_mb_ops; + } else if (device_is_compatible(np, "heathrow-media-bay")) { + bay->mb_type = mb_heathrow; + bay->ops = &heathrow_mb_ops; + } else if (device_is_compatible(np, "ohare-media-bay")) { + bay->mb_type = mb_ohare; + bay->ops = &ohare_mb_ops; + } else { + printk(KERN_ERR "mediabay: Unknown bay type !\n"); + np = np->next; + continue; + } + bay->base = (volatile u32*)ioremap(np->parent->addrs[0].address, 0x1000); + + /* Enable probe logic on keylargo */ + if (bay->mb_type == mb_keylargo) + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); +#ifdef MB_USE_INTERRUPTS + if (np->n_intrs == 0) { + printk(KERN_ERR "media bay %d has no irq\n",n); + np = np->next; + continue; + } + + if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) { + printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", + np->intrs[0].line, n); + np = np->next; + continue; + } +#endif + media_bay_count++; + + printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", n, bay->ops->name); + bay->dev_node = np; + bay->index = n; + + /* Force an immediate detect */ + set_mb_power(bay, 0); + mdelay(MB_POWER_DELAY); + bay->content_id = MB_NO; + bay->last_value = bay->ops->content(bay); + bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); + bay->state = mb_empty; + do { + mdelay(1000/HZ); + media_bay_step(n); + } while((bay->state != mb_empty) && + (bay->state != mb_up)); + + n++; + np=np->next; + } + + if (media_bay_count) + { +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&mb_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ + + kernel_thread(media_bay_task, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/rtc.c linux-2.5/drivers/macintosh/rtc.c --- linux-2.5.13/drivers/macintosh/rtc.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/macintosh/rtc.c Thu Dec 27 16:32:31 2001 @@ -34,14 +34,13 @@ void get_rtc_time(struct rtc_time *t) { unsigned long nowtime; - + nowtime = (ppc_md.get_rtc_time)(); to_tm(nowtime, t); t->tm_year -= 1900; - t->tm_mon -= 1; - t->tm_wday -= 1; + t->tm_mon -= 1; /* Make sure userland has a 0-based month */ } /* Set the current date and time in the real time clock. */ @@ -49,7 +48,8 @@ { unsigned long nowtime; - nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); (ppc_md.set_rtc_time)(nowtime); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/via-cuda.c linux-2.5/drivers/macintosh/via-cuda.c --- linux-2.5.13/drivers/macintosh/via-cuda.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/macintosh/via-cuda.c Thu Dec 27 16:32:31 2001 @@ -191,6 +191,8 @@ if (via == NULL) return -ENODEV; + request_OF_resource(vias, 0, NULL); + if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) { printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ); return -EAGAIN; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/macintosh/via-pmu.c linux-2.5/drivers/macintosh/via-pmu.c --- linux-2.5.13/drivers/macintosh/via-pmu.c Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/macintosh/via-pmu.c Fri Mar 1 15:07:38 2002 @@ -9,9 +9,9 @@ * and the RTC (real time clock) chip. * * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. + * Copyright (C) 2001 Benjamin Herrenschmidt * - * todo: - Check this driver for smp safety (new Core99 motherboards). - * - Cleanup synchro between VIA interrupt and GPIO-based PMU + * todo: - Cleanup synchro between VIA interrupt and GPIO-based PMU * interrupt. * * @@ -45,10 +45,12 @@ #include #include #include -#include +#include #include #include +#include #include +#include #ifdef CONFIG_PMAC_BACKLIGHT #include #endif @@ -56,9 +58,13 @@ /* Some compile options */ #undef SUSPEND_USES_PMU #define DEBUG_SLEEP +#undef HACKED_PCI_SAVE /* Misc minor number allocated for /dev/pmu */ -#define PMU_MINOR 154 +#define PMU_MINOR 154 + +/* How many iterations between battery polls */ +#define BATTERY_POLLING_COUNT 2 static volatile unsigned char *via; @@ -108,7 +114,7 @@ static struct adb_request *current_req; static struct adb_request *last_req; static struct adb_request *req_awaiting_reply; -static unsigned char interrupt_data[32]; +static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */ static unsigned char *reply_ptr; static int data_index; static int data_len; @@ -126,9 +132,26 @@ static int pmu_version; static int drop_interrupts; #ifdef CONFIG_PMAC_PBOOK +static int option_lid_wakeup = 1; static int sleep_in_progress; +static int can_sleep; +#endif /* CONFIG_PMAC_PBOOK */ + +static struct proc_dir_entry *proc_pmu_root; +static struct proc_dir_entry *proc_pmu_info; +static struct proc_dir_entry *proc_pmu_options; + +#ifdef CONFIG_PMAC_PBOOK +int pmu_battery_count; +int pmu_cur_battery; +unsigned int pmu_power_flags; +struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; +static int query_batt_timer = BATTERY_POLLING_COUNT; +static struct adb_request batt_req; +static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES]; #endif /* CONFIG_PMAC_PBOOK */ +int __fake_sleep; int asleep; struct notifier_block *sleep_notifier_list; @@ -153,15 +176,22 @@ static void pmu_done(struct adb_request *req); static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); -static void set_volume(int level); static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +static int proc_get_info(char *page, char **start, off_t off, + int count, int *eof, void *data); #ifdef CONFIG_PMAC_BACKLIGHT static int pmu_set_backlight_level(int level, void* data); static int pmu_set_backlight_enable(int on, int level, void* data); #endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); -#endif +static int proc_get_batt(char *page, char **start, off_t off, + int count, int *eof, void *data); +#endif /* CONFIG_PMAC_PBOOK */ +static int proc_read_options(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int proc_write_options(struct file *file, const char *buffer, + unsigned long count, void *data); #ifdef CONFIG_ADB struct adb_driver via_pmu_driver = { @@ -309,6 +339,10 @@ } else pmu_kind = PMU_UNKNOWN; +#ifdef CONFIG_PMAC_PBOOK + if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) + can_sleep = 1; +#endif /* CONFIG_PMAC_PBOOK */ via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ @@ -362,9 +396,14 @@ if (vias == NULL) return -ENODEV; + request_OF_resource(vias, 0, NULL); + bright_req_1.complete = 1; bright_req_2.complete = 1; bright_req_3.complete = 1; +#ifdef CONFIG_PMAC_PBOOK + batt_req.complete = 1; +#endif if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) { @@ -388,6 +427,46 @@ register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); #endif /* CONFIG_PMAC_BACKLIGHT */ +#ifdef CONFIG_PMAC_PBOOK + if (machine_is_compatible("AAPL,3400/2400") || + machine_is_compatible("AAPL,3500")) + pmu_battery_count = 1; + else if (machine_is_compatible("AAPL,PowerBook1998") || + machine_is_compatible("PowerBook1,1")) + pmu_battery_count = 2; + else { + struct device_node* prim = find_devices("power-mgt"); + u32 *prim_info = NULL; + if (prim) + prim_info = (u32 *)get_property(prim, "prim-info", NULL); + if (prim_info) { + /* Other stuffs here yet unknown */ + pmu_battery_count = (prim_info[6] >> 16) & 0xff; + } + } +#endif /* CONFIG_PMAC_PBOOK */ + /* Create /proc/pmu */ + proc_pmu_root = proc_mkdir("pmu", 0); + if (proc_pmu_root) { + int i; + proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root, + proc_get_info, NULL); +#ifdef CONFIG_PMAC_PBOOK + for (i=0; inlink = 1; + proc_pmu_options->read_proc = proc_read_options; + proc_pmu_options->write_proc = proc_write_options; + } + } + /* Make sure PMU settle down before continuing. This is _very_ important * since the IDE probe may shut interrupts down for quite a bit of time. If * a PMU communication is pending while this happens, the PMU may timeout @@ -448,8 +527,8 @@ pmu_request(&req, NULL, 1, PMU_GET_VERSION); while (!req.complete) pmu_poll(); - if (req.reply_len > 1) - pmu_version = req.reply[1]; + if (req.reply_len > 0) + pmu_version = req.reply[0]; return 1; } @@ -460,6 +539,263 @@ return pmu_kind; } +#ifdef CONFIG_PMAC_PBOOK + +/* + * WARNING ! This code probably needs some debugging... -- BenH. + */ +static void __pmac +done_battery_state_ohare(struct adb_request* req) +{ + unsigned int bat_flags = 0; + int current = 0; + unsigned int capa, max, voltage, time; + int lrange[] = { 0, 275, 850, 1680, 2325, + 2765, 3160, 3500, 3830, 4115, + 4360, 4585, 4795, 4990, 5170, + 5340, 5510, 5710, 5930, 6150, + 6370, 6500 + }; + + if (req->reply[0] & 0x01) + pmu_power_flags |= PMU_PWR_AC_PRESENT; + else + pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + if (req->reply[0] & 0x04) { + int vb, i, j, charge, pcharge; + bat_flags |= PMU_BATT_PRESENT; + vb = (req->reply[1] << 8) | req->reply[2]; + voltage = ((vb * 2650) + 726650)/100; + current = *((signed char *)&req->reply[5]); + if ((req->reply[0] & 0x01) == 0 && (current > 200)) + vb += (current - 200) * 15; + else if (req->reply[0] & 0x02) + vb = (vb - 10) * 100; + i = (33000 - vb) / 10; + j = i - (i % 100); + if (j <= 0) + charge = 0; + else if (j >= 21) + charge = 650000; + else + charge = (lrange[j + 1] - lrange[j]) * (i - j) + (lrange[j] * 100); + charge = (1000 - charge / 650) / 10; + if (req->reply[0] & 0x40) { + pcharge = (req->reply[6] << 8) + req->reply[7]; + if (pcharge > 6500) + pcharge = 6500; + pcharge *= 100; + pcharge = (1000 - pcharge / 650) / 10; + if (pcharge < charge) + charge = pcharge; + } + capa = charge; + max = 100; + time = (charge * 274) / current; + current = -current; + + } else + capa = max = current = voltage = time = 0; + + if ((req->reply[0] & 0x02) && (current > 0)) + bat_flags |= PMU_BATT_CHARGING; + if (req->reply[0] & 0x04) /* CHECK THIS ONE */ + bat_flags |= PMU_BATT_PRESENT; + + pmu_batteries[pmu_cur_battery].flags = bat_flags; + pmu_batteries[pmu_cur_battery].charge = capa; + pmu_batteries[pmu_cur_battery].max_charge = max; + pmu_batteries[pmu_cur_battery].current = current; + pmu_batteries[pmu_cur_battery].voltage = voltage; + pmu_batteries[pmu_cur_battery].time_remaining = time; +} + +static void __pmac +done_battery_state_smart(struct adb_request* req) +{ + /* format: + * [0] : format of this structure (known: 3,4,5) + * [1] : flags + * + * format 3 & 4: + * + * [2] : charge + * [3] : max charge + * [4] : current + * [5] : voltage + * + * format 5: + * + * [2][3] : charge + * [4][5] : max charge + * [6][7] : current + * [8][9] : voltage + */ + + unsigned int bat_flags = 0; + int current; + unsigned int capa, max, voltage; + + if (req->reply[1] & 0x01) + pmu_power_flags |= PMU_PWR_AC_PRESENT; + else + pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + + if (req->reply[1] & 0x04) { + bat_flags |= PMU_BATT_PRESENT; + switch(req->reply[0]) { + case 3: + case 4: capa = req->reply[2]; + max = req->reply[3]; + current = *((signed char *)&req->reply[4]); + voltage = req->reply[5]; + break; + case 5: capa = (req->reply[2] << 8) | req->reply[3]; + max = (req->reply[4] << 8) | req->reply[5]; + current = *((signed short *)&req->reply[6]); + voltage = (req->reply[8] << 8) | req->reply[9]; + break; + default: + printk(KERN_WARNING "pmu.c : unrecognized battery info, len: %d, %02x %02x %02x %02x\n", + req->reply_len, req->reply[0], req->reply[1], req->reply[2], req->reply[3]); + break; + } + } else + capa = max = current = voltage = 0; + + if ((req->reply[1] & 0x01) && (current > 0)) + bat_flags |= PMU_BATT_CHARGING; + + pmu_batteries[pmu_cur_battery].flags = bat_flags; + pmu_batteries[pmu_cur_battery].charge = capa; + pmu_batteries[pmu_cur_battery].max_charge = max; + pmu_batteries[pmu_cur_battery].current = current; + pmu_batteries[pmu_cur_battery].voltage = voltage; + if (current) { + if ((req->reply[1] & 0x01) && (current > 0)) + pmu_batteries[pmu_cur_battery].time_remaining + = ((max-capa) * 3600) / current; + else + pmu_batteries[pmu_cur_battery].time_remaining + = (capa * 3600) / (-current); + } else + pmu_batteries[pmu_cur_battery].time_remaining = 0; + + pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count; +} + +static void __pmac +query_battery_state(void) +{ + if (!batt_req.complete) + return; + if (pmu_kind == PMU_OHARE_BASED) + pmu_request(&batt_req, done_battery_state_ohare, + 1, PMU_BATTERY_STATE); + else + pmu_request(&batt_req, done_battery_state_smart, + 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1); +} + +#endif /* CONFIG_PMAC_PBOOK */ + +static int +proc_get_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char* p = page; + + p += sprintf(p, "PMU driver version : %d\n", PMU_DRIVER_VERSION); + p += sprintf(p, "PMU firmware version : %02x\n", pmu_version); +#ifdef CONFIG_PMAC_PBOOK + p += sprintf(p, "AC Power : %d\n", + ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0)); + p += sprintf(p, "Battery count : %d\n", pmu_battery_count); +#endif /* CONFIG_PMAC_PBOOK */ + + return p - page; +} + +#ifdef CONFIG_PMAC_PBOOK +static int +proc_get_batt(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int batnum = (int)data; + char *p = page; + + p += sprintf(p, "\n"); + p += sprintf(p, "flags : %08x\n", + pmu_batteries[batnum].flags); + p += sprintf(p, "charge : %d\n", + pmu_batteries[batnum].charge); + p += sprintf(p, "max_charge : %d\n", + pmu_batteries[batnum].max_charge); + p += sprintf(p, "current : %d\n", + pmu_batteries[batnum].current); + p += sprintf(p, "voltage : %d\n", + pmu_batteries[batnum].voltage); + p += sprintf(p, "time rem. : %d\n", + pmu_batteries[batnum].time_remaining); + + return p - page; +} +#endif /* CONFIG_PMAC_PBOOK */ + +static int +proc_read_options(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + +#ifdef CONFIG_PMAC_PBOOK + if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) + p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup); +#endif /* CONFIG_PMAC_PBOOK */ + + return p - page; +} + +static int +proc_write_options(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char tmp[33]; + char *label, *val; + unsigned long fcount = count; + + if (!count) + return -EINVAL; + if (count > 32) + count = 32; + if (copy_from_user(tmp, buffer, count)) + return -EFAULT; + tmp[count] = 0; + + label = tmp; + while(*label == ' ') + label++; + val = label; + while(*val && (*val != '=')) { + if (*val == ' ') + *val = 0; + val++; + } + if ((*val) == 0) + return -EINVAL; + *(val++) = 0; + while(*val == ' ') + val++; +#ifdef CONFIG_PMAC_PBOOK + if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) + if (!strcmp(label, "lid_wakeup")) + option_lid_wakeup = ((*val) == '1'); +#endif /* CONFIG_PMAC_PBOOK */ + return fcount; +} + #ifdef CONFIG_ADB /* Send an ADB command */ static int __openfirmware @@ -622,11 +958,7 @@ for (i = 0; i < nbytes; ++i) req->data[i] = va_arg(list, int); va_end(list); - if (pmu_data_len[req->data[0]][1] != 0) { - req->reply[0] = ADB_RET_OK; - req->reply_len = 1; - } else - req->reply_len = 0; + req->reply_len = 0; req->reply_expected = 0; return pmu_queue_request(req); } @@ -835,27 +1167,22 @@ spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; - while ((intr = in_8(&via[IFR])) != 0) { + for (;;) { + intr = in_8(&via[IFR]) & (SR_INT | CB1_INT); + if (intr == 0) + break; if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " - "intr=%x pmu_state=%d\n", intr, pmu_state); + "intr=%x, ier=%x pmu_state=%d\n", + intr, in_8(&via[IER]), pmu_state); break; } out_8(&via[IFR], intr); if (intr & SR_INT) pmu_sr_intr(regs); - else if (intr & CB1_INT) + if (intr & CB1_INT) adb_int_pending = 1; } - /* This is not necessary except if synchronous ADB requests are done - * with interrupts off, which should not happen. Since I'm not sure - * this "wiring" will remain, I'm commenting it out for now. Please do - * not remove. -- BenH. - */ -#if 0 - if (gpio_reg && !pmu_suspended && (in_8(gpio_reg + 0x9) & 0x02) == 0) - adb_int_pending = 1; -#endif if (pmu_state == idle) { if (adb_int_pending) { @@ -866,9 +1193,8 @@ wait_for_ack(); send_byte(PMU_INT_ACK); adb_int_pending = 0; - } else if (current_req) { + } else if (current_req) pmu_start(); - } } --disable_poll; @@ -878,8 +1204,10 @@ static void __openfirmware gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) { - adb_int_pending = 1; - via_pmu_interrupt(0, 0, 0); + if ((in_8(gpio_reg + 0x9) & 0x02) == 0) { + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + } } static void __openfirmware @@ -1040,16 +1368,25 @@ adb_input(data+1, len-1, regs, 1); #endif /* CONFIG_ADB */ } - } else if (data[0] == 0x08 && len == 3) { - /* sound/brightness buttons pressed */ + } else { + /* Sound/brightness button pressed */ + if ((data[0] & PMU_INT_SNDBRT) && len == 3) { #ifdef CONFIG_PMAC_BACKLIGHT - set_backlight_level(data[1] >> 4); + set_backlight_level(data[1] >> 4); #endif - set_volume(data[2]); - } else { + } #ifdef CONFIG_PMAC_PBOOK - pmu_pass_intr(data, len); -#endif + /* Environement or tick interrupt, query batteries */ + if (pmu_battery_count && (data[0] & PMU_INT_TICK)) { + if ((--query_batt_timer) == 0) { + query_battery_state(); + query_batt_timer = BATTERY_POLLING_COUNT; + } + } else if (pmu_battery_count && (data[0] & PMU_INT_ENVIRONMENT)) + query_battery_state(); + if (data[0]) + pmu_pass_intr(data, len); +#endif /* CONFIG_PMAC_PBOOK */ } } @@ -1116,11 +1453,6 @@ pmu_poll(); } -static void __openfirmware -set_volume(int level) -{ -} - void __openfirmware pmu_restart(void) { @@ -1266,10 +1598,14 @@ * PCI devices which may get powered off when we sleep. */ static struct pci_save { +#ifndef HACKED_PCI_SAVE u16 command; u16 cache_lat; u16 intr; u32 rom_address; +#else + u32 config[16]; +#endif } *pbook_pci_saves; static int n_pbook_pci_saves; @@ -1293,14 +1629,24 @@ return; pci_for_each_dev(pd) { +#ifndef HACKED_PCI_SAVE pci_read_config_word(pd, PCI_COMMAND, &ps->command); pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address); +#else + int i; + for (i=1;i<16;i++) + pci_read_config_dword(pd, i<<4, &ps->config[i]); +#endif ++ps; } } +/* For this to work, we must take care of a few things: If gmac was enabled + * during boot, it will be in the pci dev list. If it's disabled at this point + * (and it will probably be), then you can't access it's config space. + */ static void __openfirmware pbook_pci_restore(void) { @@ -1310,7 +1656,13 @@ int j; pci_for_each_dev(pd) { +#ifdef HACKED_PCI_SAVE + int i; ps++; + for (i=2;i<16;i++) + pci_write_config_dword(pd, i<<4, ps->config[i]); + pci_write_config_dword(pd, 4, ps->config[1]); +#else if (ps->command == 0) continue; pci_read_config_word(pd, PCI_COMMAND, &cmd); @@ -1330,8 +1682,8 @@ ps->intr); pci_write_config_word(pd, PCI_COMMAND, ps->command); break; - /* other header types not restored at present */ } +#endif } } @@ -1370,7 +1722,7 @@ } mdelay(50); } -#endif /* DEBUG_SLEEP */ +#endif /* * Put the powerbook to sleep. @@ -1403,6 +1755,15 @@ out_8(&via[IER], IER_SET | SR_INT | CB1_INT); } +static inline void wakeup_decrementer(void) +{ + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + * so use get_tbl, not native + */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); +} + #define GRACKLE_PM (1<<7) #define GRACKLE_DOZE (1<<5) #define GRACKLE_NAP (1<<4) @@ -1436,6 +1797,10 @@ * vmalloc's are done before actual sleep of block drivers */ sys_sync(); + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/2); time_before(jiffies, wait); ) + mb(); + /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { @@ -1443,13 +1808,9 @@ return -EBUSY; } - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/2); time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Turn off various things. Darwin does some retry tests here... */ @@ -1495,7 +1856,7 @@ /* The VIA is supposed not to be restored correctly*/ save_via_state(); /* We shut down some HW */ - feature_prepare_for_sleep(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); pci_read_config_word(grackle, 0x70, &pmcr1); /* Apparently, MacOS uses NAP mode for Grackle ??? */ @@ -1512,7 +1873,7 @@ pci_write_config_word(grackle, 0x70, pmcr1); /* Make sure the PMU is idle */ - feature_wake_up(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); restore_via_state(); /* Restore L2 cache */ @@ -1522,11 +1883,6 @@ /* Restore userland MMU context */ set_context(current->active_mm->context, current->active_mm->pgd); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* Power things up */ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); while (!req.complete) @@ -1558,6 +1914,10 @@ /* Leave some time for HW to settle down */ mdelay(100); + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1571,7 +1931,7 @@ struct adb_request req; int ret, timeout; - if (!feature_can_sleep()) { + if (!can_sleep) { printk(KERN_ERR "Sleep mode not supported on this machine\n"); return -ENOSYS; } @@ -1591,20 +1951,19 @@ * vmalloc's are done before actual sleep of block drivers */ sys_sync(); + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + HZ; time_before(jiffies, wait); ) + mb(); + /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { printk("pmu: sleep failed\n"); return -EBUSY; } - - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + HZ; time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Tell PMU what events will wake us up */ @@ -1614,7 +1973,8 @@ pmu_poll(); pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, - 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN); + 0, PMU_PWR_WAKEUP_KEY | + (option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0)); while (!req.complete) pmu_poll(); @@ -1651,10 +2011,12 @@ /* Save the state of PCI config space for some slots */ //pbook_pci_save(); - /* Ask the PMU to put us to sleep */ - pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!req.complete && pmu_state != idle) - pmu_poll(); + if (!__fake_sleep) { + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete && pmu_state != idle) + pmu_poll(); + } out_8(&via[B], in_8(&via[B]) | TREQ); wait_for_ack(); @@ -1666,13 +2028,16 @@ * talk to the PMU after this, so I moved it to _after_ sending the * sleep command to it. Still need to be checked. */ - feature_prepare_for_sleep(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); /* Call low-level ASM sleep handler */ - low_sleep_handler(); + if (__fake_sleep) + mdelay(5000); + else + low_sleep_handler(); /* Restore Apple core ASICs state */ - feature_wake_up(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); /* Restore VIA */ restore_via_state(); @@ -1694,11 +2059,6 @@ /* Restore userland MMU context */ set_context(current->active_mm->context, current->active_mm->pgd); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* Tell PMU we are ready */ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); while (!req.complete) @@ -1725,6 +2085,10 @@ /* Leave some time for HW to settle down */ mdelay(100); + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1766,6 +2130,10 @@ * vmalloc's are done before actual sleep of block drivers */ sys_sync(); + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + mb(); + /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { @@ -1773,13 +2141,9 @@ return -EBUSY; } - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Disable all interrupts except pmu */ @@ -1811,6 +2175,8 @@ while (!sleep_req.complete) mb(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); + /* displacement-flush the L2 cache - necessary? */ for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000) i = *(volatile int *)p; @@ -1825,20 +2191,23 @@ /* OK, we're awake again, start restoring things */ out_be32(mem_ctrl_sleep, 0x3f); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); pbook_pci_restore(); /* wait for the PMU interrupt sequence to complete */ while (asleep) mb(); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* reenable interrupts */ pmac_sleep_restore_intrs(); + /* Leave some time for HW to settle down */ + mdelay(100); + + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1877,6 +2246,7 @@ spin_lock_irqsave(&all_pvt_lock, flags); for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) { pp = list_entry(list, struct pmu_private, list); + spin_lock(&pp->lock); i = pp->rb_put + 1; if (i >= RB_SIZE) i = 0; @@ -1887,6 +2257,7 @@ pp->rb_put = i; wake_up_interruptible(&pp->wait); } + spin_unlock(&pp->lock); } spin_unlock_irqrestore(&all_pvt_lock, flags); } @@ -1914,6 +2285,7 @@ { struct pmu_private *pp = file->private_data; DECLARE_WAITQUEUE(wait, current); + unsigned long flags; int ret; if (count < 1 || pp == 0) @@ -1922,38 +2294,41 @@ if (ret) return ret; + spin_lock_irqsave(&pp->lock, flags); add_wait_queue(&pp->wait, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { ret = -EAGAIN; - spin_lock(&pp->lock); if (pp->rb_get != pp->rb_put) { int i = pp->rb_get; struct rb_entry *rp = &pp->rb_buf[i]; ret = rp->len; + spin_unlock_irqrestore(&pp->lock, flags); if (ret > count) ret = count; if (ret > 0 && copy_to_user(buf, rp->data, ret)) ret = -EFAULT; if (++i >= RB_SIZE) i = 0; + spin_lock_irqsave(&pp->lock, flags); pp->rb_get = i; } - spin_unlock(&pp->lock); if (ret >= 0) break; - if (file->f_flags & O_NONBLOCK) break; ret = -ERESTARTSYS; if (signal_pending(current)) break; + spin_unlock_irqrestore(&pp->lock, flags); schedule(); + spin_lock_irqsave(&pp->lock, flags); } current->state = TASK_RUNNING; remove_wait_queue(&pp->wait, &wait); - + spin_unlock_irqrestore(&pp->lock, flags); + return ret; } @@ -1967,14 +2342,15 @@ { struct pmu_private *pp = filp->private_data; unsigned int mask = 0; - + unsigned long flags; + if (pp == 0) return 0; poll_wait(filp, &pp->wait, wait); - spin_lock(&pp->lock); + spin_lock_irqsave(&pp->lock, flags); if (pp->rb_get != pp->rb_put) mask |= POLLIN; - spin_unlock(&pp->lock); + spin_unlock_irqrestore(&pp->lock, flags); return mask; } @@ -2023,7 +2399,7 @@ sleep_in_progress = 0; return error; case PMU_IOC_CAN_SLEEP: - return put_user(feature_can_sleep(), (__u32 *)arg); + return put_user((u32)can_sleep, (__u32 *)arg); #ifdef CONFIG_PMAC_BACKLIGHT /* Backlight should have its own device or go via @@ -2153,5 +2529,8 @@ EXPORT_SYMBOL(pmu_register_sleep_notifier); EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); +EXPORT_SYMBOL(pmu_battery_count); +EXPORT_SYMBOL(pmu_batteries); +EXPORT_SYMBOL(pmu_power_flags); #endif /* CONFIG_PMAC_PBOOK */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/md/lvm-fs.c linux-2.5/drivers/md/lvm-fs.c --- linux-2.5.13/drivers/md/lvm-fs.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/md/lvm-fs.c Fri Mar 1 19:18:06 2002 @@ -276,12 +276,12 @@ 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); - } + 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, "device: %02u:%02u\n", major(lv->u.lv_dev), minor(lv->u.lv_dev)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/md/md.c linux-2.5/drivers/md/md.c --- linux-2.5.13/drivers/md/md.c Fri May 3 01:22:46 2002 +++ linux-2.5/drivers/md/md.c Fri May 3 12:57:30 2002 @@ -1011,6 +1011,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)) @@ -1576,6 +1581,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; @@ -1732,6 +1738,7 @@ } mddev->sb->state &= ~(1 << MD_SB_CLEAN); + mddev->sb_dirty = 1; md_update_sb(mddev); /* @@ -1848,6 +1855,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) @@ -2471,7 +2479,6 @@ mddev->sb->working_disks++; mddev->sb_dirty = 1; - md_update_sb(mddev); /* @@ -3513,6 +3520,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.13/drivers/md/multipath.c linux-2.5/drivers/md/multipath.c --- linux-2.5.13/drivers/md/multipath.c Fri May 3 01:22:52 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.13/drivers/md/raid1.c linux-2.5/drivers/md/raid1.c --- linux-2.5.13/drivers/md/raid1.c Fri May 3 01:22: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.13/drivers/md/raid5.c linux-2.5/drivers/md/raid5.c --- linux-2.5.13/drivers/md/raid5.c Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/md/raid5.c Wed May 1 17:26:08 2002 @@ -1276,10 +1276,8 @@ handled = 0; - if (mddev->sb_dirty) { - mddev->sb_dirty = 0; + if (mddev->sb_dirty) md_update_sb(mddev); - } md_spin_lock_irq(&conf->device_lock); while (1) { struct list_head *first; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/media/video/Config.help linux-2.5/drivers/media/video/Config.help --- linux-2.5.13/drivers/media/video/Config.help Fri May 3 01:22:47 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.13/drivers/media/video/meye.c linux-2.5/drivers/media/video/meye.c --- linux-2.5.13/drivers/media/video/meye.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/media/video/meye.c Tue Apr 23 12:20:22 2002 @@ -1242,7 +1242,6 @@ sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1); meye.mchip_dev = pcidev; - meye.mchip_irq = pcidev->irq; memcpy(&meye.video_dev, &meye_template, sizeof(meye_template)); if (mchip_dma_alloc()) { @@ -1256,6 +1255,7 @@ goto out3; } + meye.mchip_irq = pcidev->irq; mchip_adr = pci_resource_start(meye.mchip_dev,0); if (!mchip_adr) { printk(KERN_ERR "meye: mchip has no device base address\n"); @@ -1419,6 +1419,27 @@ static void __exit meye_cleanup_module(void) { pci_unregister_driver(&meye_driver); } + +#ifndef MODULE +static int __init meye_setup(char *str) { + int ints[4]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] <= 0) + goto out; + gbuffers = ints[1]; + if (ints[0] == 1) + goto out; + gbufsize = ints[2]; + if (ints[0] == 2) + goto out; + video_nr = ints[3]; +out: + return 1; +} + +__setup("meye=", meye_setup); +#endif MODULE_AUTHOR("Stelian Pop "); MODULE_DESCRIPTION("video4linux driver for the MotionEye camera"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/media/video/meye.h linux-2.5/drivers/media/video/meye.h --- linux-2.5.13/drivers/media/video/meye.h Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/media/video/meye.h Thu May 2 23:16:53 2002 @@ -29,7 +29,7 @@ #define _MEYE_PRIV_H_ #define MEYE_DRIVER_MAJORVERSION 1 -#define MEYE_DRIVER_MINORVERSION 3 +#define MEYE_DRIVER_MINORVERSION 4 /****************************************************************************/ /* Motion JPEG chip registers */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/media/video/planb.c linux-2.5/drivers/media/video/planb.c --- linux-2.5.13/drivers/media/video/planb.c Fri May 3 01:22:45 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 *); @@ -2079,7 +2078,6 @@ #endif pb->tab_size = PLANB_MAXLINES + 40; pb->suspend = 0; - pb->lock = 0; init_MUTEX(&pb->lock); pb->ch1_cmd = 0; pb->ch2_cmd = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/media/video/stradis.c linux-2.5/drivers/media/video/stradis.c --- linux-2.5.13/drivers/media/video/stradis.c Fri May 3 01:22:49 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.13/drivers/media/video/vino.c linux-2.5/drivers/media/video/vino.c --- linux-2.5.13/drivers/media/video/vino.c Fri May 3 01:22:48 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.13/drivers/media/video/w9966.c linux-2.5/drivers/media/video/w9966.c --- linux-2.5.13/drivers/media/video/w9966.c Fri May 3 01:22:45 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.13/drivers/media/video/zr36067.c linux-2.5/drivers/media/video/zr36067.c --- linux-2.5.13/drivers/media/video/zr36067.c Fri May 3 01:22:52 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.13/drivers/media/video/zr36120.c linux-2.5/drivers/media/video/zr36120.c --- linux-2.5.13/drivers/media/video/zr36120.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/media/video/zr36120.c Mon Apr 15 02:54:49 2002 @@ -1291,11 +1291,7 @@ case VIDIOCSFBUF: { struct video_buffer v; -#if LINUX_VERSION_CODE >= 0x020100 - if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN)) -#else - if(!suser()) -#endif + if(!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/message/i2o/README linux-2.5/drivers/message/i2o/README --- linux-2.5.13/drivers/message/i2o/README Fri May 3 01:22:50 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.13/drivers/message/i2o/i2o_block.c linux-2.5/drivers/message/i2o/i2o_block.c --- linux-2.5.13/drivers/message/i2o/i2o_block.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/message/i2o/i2o_block.c Fri May 3 12:57:30 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.13/drivers/message/i2o/i2o_config.c linux-2.5/drivers/message/i2o/i2o_config.c --- linux-2.5.13/drivers/message/i2o/i2o_config.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/message/i2o/i2o_config.c Mon Feb 18 21:47:52 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.13/drivers/message/i2o/i2o_core.c linux-2.5/drivers/message/i2o/i2o_core.c --- linux-2.5.13/drivers/message/i2o/i2o_core.c Fri May 3 01:22:54 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.13/drivers/message/i2o/i2o_lan.c linux-2.5/drivers/message/i2o/i2o_lan.c --- linux-2.5.13/drivers/message/i2o/i2o_lan.c Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/message/i2o/i2o_lan.c Mon Feb 18 21:50:50 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.13/drivers/message/i2o/i2o_scsi.c linux-2.5/drivers/message/i2o/i2o_scsi.c --- linux-2.5.13/drivers/message/i2o/i2o_scsi.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/message/i2o/i2o_scsi.c Mon Feb 18 21:52:06 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.13/drivers/mtd/Config.in linux-2.5/drivers/mtd/Config.in --- linux-2.5.13/drivers/mtd/Config.in Fri May 3 01:22: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.13/drivers/mtd/Makefile linux-2.5/drivers/mtd/Makefile --- linux-2.5.13/drivers/mtd/Makefile Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/mtd/Makefile Mon Apr 22 02:07:32 2002 @@ -1,7 +1,6 @@ # # Makefile for the memory technology device drivers. # -# # $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $ @@ -13,7 +12,7 @@ O_TARGET := mtdlink.o -export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o +export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o mtdconcat.o mod-subdirs := subdir-y := chips maps devices nand @@ -37,6 +36,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.13/drivers/mtd/afs.c linux-2.5/drivers/mtd/afs.c --- linux-2.5.13/drivers/mtd/afs.c Fri May 3 01:22:56 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.13/drivers/mtd/chips/Makefile linux-2.5/drivers/mtd/chips/Makefile --- linux-2.5.13/drivers/mtd/chips/Makefile Fri May 3 01:22:46 2002 +++ linux-2.5/drivers/mtd/chips/Makefile Sat Apr 13 17:42:55 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 $ O_TARGET := chipslink.o @@ -20,7 +20,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.13/drivers/mtd/chips/amd_flash.c linux-2.5/drivers/mtd/chips/amd_flash.c --- linux-2.5.13/drivers/mtd/chips/amd_flash.c Fri May 3 01:22:46 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.13/drivers/mtd/chips/jedec.c linux-2.5/drivers/mtd/chips/jedec.c --- linux-2.5.13/drivers/mtd/chips/jedec.c Fri May 3 01:22:54 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.13/drivers/mtd/devices/doc1000.c linux-2.5/drivers/mtd/devices/doc1000.c --- linux-2.5.13/drivers/mtd/devices/doc1000.c Fri May 3 01:22:42 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.13/drivers/mtd/devices/mtdram.c linux-2.5/drivers/mtd/devices/mtdram.c --- linux-2.5.13/drivers/mtd/devices/mtdram.c Fri May 3 01:22:39 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.13/drivers/mtd/ftl.c linux-2.5/drivers/mtd/ftl.c --- linux-2.5.13/drivers/mtd/ftl.c Fri May 3 01:22:46 2002 +++ linux-2.5/drivers/mtd/ftl.c Fri May 3 12:57:30 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 */ @@ -1336,7 +1339,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.13/drivers/mtd/maps/Config.in linux-2.5/drivers/mtd/maps/Config.in --- linux-2.5.13/drivers/mtd/maps/Config.in Fri May 3 01:22:53 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.13/drivers/mtd/maps/Makefile linux-2.5/drivers/mtd/maps/Makefile --- linux-2.5.13/drivers/mtd/maps/Makefile Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/mtd/maps/Makefile Sat Apr 13 17:42:55 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 $ O_TARGET := mapslink.o @@ -11,9 +11,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 @@ -29,5 +35,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.13/drivers/mtd/maps/amd766rom.c linux-2.5/drivers/mtd/maps/amd766rom.c --- linux-2.5.13/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.13/drivers/mtd/maps/autcpu12-nvram.c linux-2.5/drivers/mtd/maps/autcpu12-nvram.c --- linux-2.5.13/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.13/drivers/mtd/maps/dc21285.c linux-2.5/drivers/mtd/maps/dc21285.c --- linux-2.5.13/drivers/mtd/maps/dc21285.c Fri May 3 01:22:50 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.13/drivers/mtd/maps/dilnetpc.c linux-2.5/drivers/mtd/maps/dilnetpc.c --- linux-2.5.13/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.13/drivers/mtd/maps/epxa10db-flash.c linux-2.5/drivers/mtd/maps/epxa10db-flash.c --- linux-2.5.13/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.13/drivers/mtd/maps/ich2rom.c linux-2.5/drivers/mtd/maps/ich2rom.c --- linux-2.5.13/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.13/drivers/mtd/maps/integrator-flash.c linux-2.5/drivers/mtd/maps/integrator-flash.c --- linux-2.5.13/drivers/mtd/maps/integrator-flash.c Fri May 3 01:22:56 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.13/drivers/mtd/maps/iq80310.c linux-2.5/drivers/mtd/maps/iq80310.c --- linux-2.5.13/drivers/mtd/maps/iq80310.c Fri May 3 01:22:49 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.13/drivers/mtd/maps/l440gx.c linux-2.5/drivers/mtd/maps/l440gx.c --- linux-2.5.13/drivers/mtd/maps/l440gx.c Fri May 3 01:22:46 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.13/drivers/mtd/maps/mbx860.c linux-2.5/drivers/mtd/maps/mbx860.c --- linux-2.5.13/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.13/drivers/mtd/maps/pb1xxx-flash.c linux-2.5/drivers/mtd/maps/pb1xxx-flash.c --- linux-2.5.13/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.13/drivers/mtd/maps/pci.c linux-2.5/drivers/mtd/maps/pci.c --- linux-2.5.13/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.13/drivers/mtd/maps/sa1100-flash.c linux-2.5/drivers/mtd/maps/sa1100-flash.c --- linux-2.5.13/drivers/mtd/maps/sa1100-flash.c Fri May 3 01:22:45 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.13/drivers/mtd/maps/sc520cdp.c linux-2.5/drivers/mtd/maps/sc520cdp.c --- linux-2.5.13/drivers/mtd/maps/sc520cdp.c Fri May 3 01:22:56 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.13/drivers/mtd/maps/solutionengine.c linux-2.5/drivers/mtd/maps/solutionengine.c --- linux-2.5.13/drivers/mtd/maps/solutionengine.c Fri May 3 01:22:57 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.13/drivers/mtd/maps/tsunami_flash.c linux-2.5/drivers/mtd/maps/tsunami_flash.c --- linux-2.5.13/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.13/drivers/mtd/mtdblock.c linux-2.5/drivers/mtd/mtdblock.c --- linux-2.5.13/drivers/mtd/mtdblock.c Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/mtd/mtdblock.c Fri May 3 12:57:30 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 */ @@ -56,6 +56,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... * @@ -282,11 +290,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; } @@ -309,6 +320,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)); @@ -324,6 +336,7 @@ if (!mtdblk->cache_data) { put_mtd_device(mtdblk->mtd); kfree(mtdblk); + BLK_DEC_USE_COUNT; return -ENOMEM; } } @@ -387,6 +400,7 @@ DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + BLK_DEC_USE_COUNT; release_return(0); } @@ -526,8 +540,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) @@ -560,7 +577,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.13/drivers/mtd/mtdblock_ro.c linux-2.5/drivers/mtd/mtdblock_ro.c --- linux-2.5.13/drivers/mtd/mtdblock_ro.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/mtd/mtdblock_ro.c Fri May 3 12:57:30 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); } @@ -214,9 +222,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; @@ -244,7 +255,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.13/drivers/mtd/mtdconcat.c linux-2.5/drivers/mtd/mtdconcat.c --- linux-2.5.13/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.13/drivers/mtd/mtdcore.c linux-2.5/drivers/mtd/mtdcore.c --- linux-2.5.13/drivers/mtd/mtdcore.c Fri May 3 01:22:52 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.13/drivers/mtd/mtdpart.c linux-2.5/drivers/mtd/mtdpart.c --- linux-2.5.13/drivers/mtd/mtdpart.c Fri May 3 01:22:44 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.13/drivers/mtd/nand/nand_ecc.c linux-2.5/drivers/mtd/nand/nand_ecc.c --- linux-2.5.13/drivers/mtd/nand/nand_ecc.c Fri May 3 01:22:46 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.13/drivers/mtd/nftlcore.c linux-2.5/drivers/mtd/nftlcore.c --- linux-2.5.13/drivers/mtd/nftlcore.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/mtd/nftlcore.c Fri May 3 12:57:30 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) @@ -954,8 +962,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; } @@ -968,11 +979,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); @@ -990,7 +1000,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 @@ -1017,7 +1029,7 @@ int i; #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.13/drivers/net/82596.c linux-2.5/drivers/net/82596.c --- linux-2.5.13/drivers/net/82596.c Fri May 3 01:22:43 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.13/drivers/net/8390.h linux-2.5/drivers/net/8390.h --- linux-2.5.13/drivers/net/8390.h Fri May 3 01:22:55 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.13/drivers/net/Config.help linux-2.5/drivers/net/Config.help --- linux-2.5.13/drivers/net/Config.help Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/net/Config.help Thu Apr 4 14:47:51 2002 @@ -875,6 +875,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 @@ -1362,6 +1366,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.13/drivers/net/Config.in linux-2.5/drivers/net/Config.in --- linux-2.5.13/drivers/net/Config.in Fri May 3 01:22: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.13/drivers/net/Space.c linux-2.5/drivers/net/Space.c --- linux-2.5.13/drivers/net/Space.c Fri May 3 01:22: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.13/drivers/net/a2065.c linux-2.5/drivers/net/a2065.c --- linux-2.5.13/drivers/net/a2065.c Fri May 3 01:22:54 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.13/drivers/net/acenic.c linux-2.5/drivers/net/acenic.c --- linux-2.5.13/drivers/net/acenic.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/net/acenic.c Thu Apr 4 05:19:51 2002 @@ -173,12 +173,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 +259,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 +273,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 +291,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 +313,7 @@ #ifndef ARCH_HAS_PREFETCHW #ifndef prefetchw -#define prefetchw(x) {do{} while(0);} +#define prefetchw(x) do { } while(0) #endif #endif @@ -1355,7 +1355,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.13/drivers/net/atarilance.c linux-2.5/drivers/net/atarilance.c --- linux-2.5.13/drivers/net/atarilance.c Fri May 3 01:22:45 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.13/drivers/net/bmac.c linux-2.5/drivers/net/bmac.c --- linux-2.5.13/drivers/net/bmac.c Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/net/bmac.c Fri May 3 03:49:06 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.13/drivers/net/bonding.c linux-2.5/drivers/net/bonding.c --- linux-2.5.13/drivers/net/bonding.c Fri May 3 01:22:50 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.13/drivers/net/declance.c linux-2.5/drivers/net/declance.c --- linux-2.5.13/drivers/net/declance.c Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/net/declance.c Wed May 1 20:30:00 2002 @@ -791,6 +791,8 @@ ib->mode = 0; ib->filter [0] = 0; ib->filter [2] = 0; + ib->filter [4] = 0; + ib->filter [6] = 0; lance_init_ring(dev); load_csrs(lp); @@ -943,9 +945,9 @@ if (!(*addrs & 1)) continue; - crc = ether_crc(6, addrs); + crc = ether_crc_le(6, addrs); crc = crc >> 26; - mcast_table[crc >> 3] |= 1 << (crc & 0xf); + mcast_table[2 * (crc >> 4)] |= 1 << (crc & 0xf); } return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/defxx.c linux-2.5/drivers/net/defxx.c --- linux-2.5.13/drivers/net/defxx.c Fri May 3 01:22: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.13/drivers/net/eepro.c linux-2.5/drivers/net/eepro.c --- linux-2.5.13/drivers/net/eepro.c Fri May 3 01:22:55 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.13/drivers/net/hamradio/dmascc.c linux-2.5/drivers/net/hamradio/dmascc.c --- linux-2.5.13/drivers/net/hamradio/dmascc.c Fri May 3 01:22:51 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.13/drivers/net/hamradio/mkiss.c linux-2.5/drivers/net/hamradio/mkiss.c --- linux-2.5.13/drivers/net/hamradio/mkiss.c Fri May 3 01:22:51 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.13/drivers/net/hamradio/mkiss.h linux-2.5/drivers/net/hamradio/mkiss.h --- linux-2.5.13/drivers/net/hamradio/mkiss.h Fri May 3 01:22: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.13/drivers/net/i82586.h linux-2.5/drivers/net/i82586.h --- linux-2.5.13/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.13/drivers/net/irda/Config.help linux-2.5/drivers/net/irda/Config.help --- linux-2.5.13/drivers/net/irda/Config.help Fri May 3 01:22:38 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.13/drivers/net/irda/Config.in linux-2.5/drivers/net/irda/Config.in --- linux-2.5.13/drivers/net/irda/Config.in Fri May 3 01:22:47 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.13/drivers/net/irda/Makefile linux-2.5/drivers/net/irda/Makefile --- linux-2.5.13/drivers/net/irda/Makefile Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/net/irda/Makefile Tue Apr 23 12:30:26 2002 @@ -29,5 +29,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.13/drivers/net/irda/ali-ircc.c linux-2.5/drivers/net/irda/ali-ircc.c --- linux-2.5.13/drivers/net/irda/ali-ircc.c Fri May 3 01:22:50 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.13/drivers/net/irda/au1k_ir.c linux-2.5/drivers/net/irda/au1k_ir.c --- linux-2.5.13/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.13/drivers/net/irda/irda-usb.c linux-2.5/drivers/net/irda/irda-usb.c --- linux-2.5.13/drivers/net/irda/irda-usb.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/net/irda/irda-usb.c Sun Apr 14 17:12:08 2002 @@ -859,7 +859,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.13/drivers/net/irda/vlsi_ir.c linux-2.5/drivers/net/irda/vlsi_ir.c --- linux-2.5.13/drivers/net/irda/vlsi_ir.c Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/net/irda/vlsi_ir.c Sun Mar 3 20:15:15 2002 @@ -636,7 +636,7 @@ idev->stats.rx_bytes += len; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); + netif_rx(skb); ndev->last_rx = jiffies; } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/macmace.c linux-2.5/drivers/net/macmace.c --- linux-2.5.13/drivers/net/macmace.c Fri May 3 01:22:49 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.13/drivers/net/macsonic.c linux-2.5/drivers/net/macsonic.c --- linux-2.5.13/drivers/net/macsonic.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/net/macsonic.c Fri May 3 03:49:07 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 @@ -616,6 +662,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.13/drivers/net/natsemi.c linux-2.5/drivers/net/natsemi.c --- linux-2.5.13/drivers/net/natsemi.c Fri May 3 01:22: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.13/drivers/net/pcmcia/Config.help linux-2.5/drivers/net/pcmcia/Config.help --- linux-2.5.13/drivers/net/pcmcia/Config.help Fri May 3 01:22:47 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.13/drivers/net/pcmcia/Config.in linux-2.5/drivers/net/pcmcia/Config.in --- linux-2.5.13/drivers/net/pcmcia/Config.in Fri May 3 01:22:55 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.13/drivers/net/pcmcia/axnet_cs.c linux-2.5/drivers/net/pcmcia/axnet_cs.c --- linux-2.5.13/drivers/net/pcmcia/axnet_cs.c Fri May 3 01:22:38 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.13/drivers/net/pcmcia/com20020_cs.c linux-2.5/drivers/net/pcmcia/com20020_cs.c --- linux-2.5.13/drivers/net/pcmcia/com20020_cs.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/net/pcmcia/com20020_cs.c Fri Feb 8 15:46:33 2002 @@ -122,6 +122,7 @@ MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); +MODULE_LICENSE("GPL"); /*====================================================================*/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/pcmcia/i82593.h linux-2.5/drivers/net/pcmcia/i82593.h --- linux-2.5.13/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.13/drivers/net/pcmcia/nmclan_cs.c linux-2.5/drivers/net/pcmcia/nmclan_cs.c --- linux-2.5.13/drivers/net/pcmcia/nmclan_cs.c Fri May 3 01:22: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.13/drivers/net/pcmcia/wavelan.h linux-2.5/drivers/net/pcmcia/wavelan.h --- linux-2.5.13/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.13/drivers/net/pcmcia/wavelan_cs.c linux-2.5/drivers/net/pcmcia/wavelan_cs.c --- linux-2.5.13/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.13/drivers/net/pcmcia/wavelan_cs.h linux-2.5/drivers/net/pcmcia/wavelan_cs.h --- linux-2.5.13/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.13/drivers/net/rclanmtl.c linux-2.5/drivers/net/rclanmtl.c --- linux-2.5.13/drivers/net/rclanmtl.c Fri May 3 01:22:55 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.13/drivers/net/rclanmtl.h linux-2.5/drivers/net/rclanmtl.h --- linux-2.5.13/drivers/net/rclanmtl.h Fri May 3 01:22:53 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.13/drivers/net/rcpci45.c linux-2.5/drivers/net/rcpci45.c --- linux-2.5.13/drivers/net/rcpci45.c Fri May 3 01:22:45 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.13/drivers/net/rrunner.c linux-2.5/drivers/net/rrunner.c --- linux-2.5.13/drivers/net/rrunner.c Fri May 3 01:22:45 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.13/drivers/net/sis900.c linux-2.5/drivers/net/sis900.c --- linux-2.5.13/drivers/net/sis900.c Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/net/sis900.c Fri May 3 03:49:07 2002 @@ -61,8 +61,8 @@ #include #include #include -#include #include +#include #include /* Processor type for cache alignment. */ #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/sonic.h linux-2.5/drivers/net/sonic.h --- linux-2.5.13/drivers/net/sonic.h Fri May 3 01:22: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.13/drivers/net/sun3_82586.c linux-2.5/drivers/net/sun3_82586.c --- linux-2.5.13/drivers/net/sun3_82586.c Fri May 3 01:22:54 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.13/drivers/net/sungem.c linux-2.5/drivers/net/sungem.c --- linux-2.5.13/drivers/net/sungem.c Fri May 3 01:22:57 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.13/drivers/net/tlan.c linux-2.5/drivers/net/tlan.c --- linux-2.5.13/drivers/net/tlan.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/net/tlan.c Sat Apr 13 17:42:56 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.13/drivers/net/tokenring/madgemc.c linux-2.5/drivers/net/tokenring/madgemc.c --- linux-2.5.13/drivers/net/tokenring/madgemc.c Fri May 3 01:22:57 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.13/drivers/net/tokenring/tmspci.c linux-2.5/drivers/net/tokenring/tmspci.c --- linux-2.5.13/drivers/net/tokenring/tmspci.c Fri May 3 01:22:56 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.13/drivers/net/tulip/ChangeLog linux-2.5/drivers/net/tulip/ChangeLog --- linux-2.5.13/drivers/net/tulip/ChangeLog Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/net/tulip/ChangeLog Tue Mar 12 20:38:40 2002 @@ -5,17 +5,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 @@ -29,8 +34,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.13/drivers/net/tulip/tulip.h linux-2.5/drivers/net/tulip/tulip.h --- linux-2.5.13/drivers/net/tulip/tulip.h Fri May 3 01:22:50 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.13/drivers/net/tulip/tulip_core.c linux-2.5/drivers/net/tulip/tulip_core.c --- linux-2.5.13/drivers/net/tulip/tulip_core.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/net/tulip/tulip_core.c Wed Mar 27 13:07:16 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; @@ -648,8 +650,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; @@ -684,7 +687,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; @@ -1486,6 +1489,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]; @@ -1523,7 +1536,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.13/drivers/net/tulip/winbond-840.c linux-2.5/drivers/net/tulip/winbond-840.c --- linux-2.5.13/drivers/net/tulip/winbond-840.c Fri May 3 01:22:44 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.13/drivers/net/via-rhine.c linux-2.5/drivers/net/via-rhine.c --- linux-2.5.13/drivers/net/via-rhine.c Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/net/via-rhine.c Sat May 4 11:42:12 2002 @@ -9,8 +9,8 @@ a complete program and may only be used when the entire operating system is licensed under the GPL. - This driver is designed for the VIA VT86c100A Rhine-II PCI Fast Ethernet - controller. It also works with the older 3043 Rhine-I chip. + This driver is designed for the VIA VT86C100A Rhine-I. + It also works with the 6102 Rhine-II, and 6105/6105M Rhine-III. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation @@ -139,9 +139,6 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* max time out delay time */ -#define W_MAX_TIMEOUT 0x0FFFU - #if !defined(__OPTIMIZE__) || !defined(__KERNEL__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. @@ -322,6 +319,7 @@ VT6102, VT3043, VT6105, + VT6105M }; struct via_rhine_chip_info { @@ -346,21 +344,23 @@ static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = { { "VIA VT86C100A Rhine", RHINE_IOTYPE, 128, - CanHaveMII | ReqTxAlign }, + CanHaveMII | ReqTxAlign | HasDavicomPhy }, { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII | ReqTxAlign }, { "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, + { "VIA VT6105M Rhine-III", RHINE_IOTYPE, 256, + CanHaveMII | HasWOL }, }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = { - {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, + {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, - {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT3043}, {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, + {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, {0,} /* terminate list */ }; MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); @@ -509,15 +509,13 @@ static int via_rhine_close(struct net_device *dev); static inline void clear_tally_counters(long ioaddr); -static void wait_for_reset(struct net_device *dev, char *name) +static void wait_for_reset(struct net_device *dev, int chip_id, char *name) { - struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - int chip_id = np->chip_id; int i; - /* 3043 may need long delay after reset (dlink) */ - if (chip_id == VT3043 || chip_id == VT86C100A) + /* VT86C100A may need long delay after reset (dlink) */ + if (chip_id == VT86C100A) udelay(100); i = 0; @@ -538,11 +536,11 @@ static void __devinit enable_mmio(long ioaddr, int chip_id) { int n; - if (chip_id == VT3043 || chip_id == VT86C100A) { + if (chip_id == VT86C100A) { /* More recent docs say that this bit is reserved ... */ n = inb(ioaddr + ConfigA) | 0x20; outb(n, ioaddr + ConfigA); - } else if (chip_id == VT6102) { + } else { n = inb(ioaddr + ConfigD) | 0x80; outb(n, ioaddr + ConfigD); } @@ -666,7 +664,7 @@ writew(CmdReset, ioaddr + ChipCmd); dev->base_addr = ioaddr; - wait_for_reset(dev, shortname); + wait_for_reset(dev, chip_id, shortname); /* Reload the station address from the EEPROM. */ #ifdef USE_IO @@ -1077,7 +1075,7 @@ return i; alloc_rbufs(dev); alloc_tbufs(dev); - wait_for_reset(dev, dev->name); + wait_for_reset(dev, np->chip_id, dev->name); init_registers(dev); if (debug > 2) printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x " @@ -1184,7 +1182,7 @@ alloc_rbufs(dev); /* Reinitialize the hardware. */ - wait_for_reset(dev, dev->name); + wait_for_reset(dev, np->chip_id, dev->name); init_registers(dev); spin_unlock(&np->lock); @@ -1254,7 +1252,7 @@ if (debug > 4) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, np->cur_tx, entry); + dev->name, np->cur_tx-1, entry); } return 0; } @@ -1505,8 +1503,8 @@ printk(KERN_INFO "%s: Transmitter underrun, increasing Tx " "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); } - if ((intr_status & ~( IntrLinkChange | IntrStatsMax | - IntrTxAbort | IntrTxAborted))) { + if (intr_status & ~( IntrLinkChange | IntrStatsMax | + IntrTxAbort | IntrTxAborted | IntrNormalSummary)) { if (debug > 1) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/8253x.h linux-2.5/drivers/net/wan/8253x/8253x.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xchr.c linux-2.5/drivers/net/wan/8253x/8253xchr.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xctl.h linux-2.5/drivers/net/wan/8253x/8253xctl.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xdbg.c linux-2.5/drivers/net/wan/8253x/8253xdbg.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xini.c linux-2.5/drivers/net/wan/8253x/8253xini.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xint.c linux-2.5/drivers/net/wan/8253x/8253xint.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xioc.h linux-2.5/drivers/net/wan/8253x/8253xioc.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xmac.c linux-2.5/drivers/net/wan/8253x/8253xmac.c --- linux-2.5.13/drivers/net/wan/8253x/8253xmac.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xmac.c Fri May 3 03:49:07 2002 @@ -0,0 +1,205 @@ +/* + * 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 "ring.h" +#include +#include + + /* This application sets a pseudo mac address that */ + /* can be used when using the synchronous port in */ + /* synchronous serial ethnernet emulation mode */ + +int main(int argc, char **argv) +{ + int fd; + struct ifreq request; + PSEUDOMAC pmac; + char buffer[200]; + int count; + unsigned int uppernib; + unsigned int lowernib; + + + if(argc != 3) + { + fprintf(stderr, "Syntax: %s {ifname} {macaddr}.\n", *argv); + fflush(stdout); + exit(-1); + } + fd = socket(AF_INET, SOCK_DGRAM, 0); + if(fd < 0) + { + perror("socket failed."); + fflush(stdout); + exit(-2); + } + + strcpy(request.ifr_ifrn.ifrn_name, argv[1]); /* requests go through the socket layer */ + + request.ifr_ifru.ifru_data = (char*) &pmac; + + if(ioctl(fd, SAB8253XGETMAC, &request) < 0) + { + perror("ioctl failed."); + fflush(stdout); + exit(-3); + } + for(count = 0; count < 6; ++count) + { + buffer[2*count] = (pmac.addr[count] >> 4); + buffer[2*count] &= 0x0F; + if(buffer[2*count] < 10) + { + buffer[2*count] += '0'; + } + else + { + buffer[2*count] += 'a'; + } + buffer[(2*count)+1] = (pmac.addr[count] & 0x0F); + if(buffer[(2*count)+1] < 10) + { + buffer[(2*count)+1] += '0'; + } + else + { + buffer[(2*count)+1] += 'a'; + } + } + buffer[12] = 0; + printf("Old mac addres is %s.\n", buffer); + if(strlen(argv[2]) != 12) + { + printf("Bad size mac address %s.\n", argv[2]); + fflush(stdout); + exit(-1); + } + for(count = 0; count < 6; ++ count) + { + uppernib = argv[2][2*count]; + lowernib = argv[2][(2*count)+1]; + + switch(uppernib) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + uppernib -= '0'; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + uppernib -= 'a'; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + uppernib -= 'A'; + break; + default: + uppernib = 0; + break; + } + switch(lowernib) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + lowernib -= '0'; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + lowernib -= 'a'; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + lowernib -= 'A'; + break; + default: + lowernib = 0; + break; + } + pmac.addr[count] = ((uppernib << 4) | lowernib); + } + + + if(ioctl(fd, SAB8253XSETMAC, &request) < 0) /* actually setting the mac address */ + { + perror("ioctl failed."); + fflush(stdout); + exit(-2); + } + + if(ioctl(fd, SAB8253XGETMAC, &request) < 0) /* getting it back so that value can be verified */ + { + perror("ioctl failed."); + exit(-3); + } + for(count = 0; count < 6; ++count) + { + buffer[2*count] = (pmac.addr[count] >> 4); + buffer[2*count] &= 0x0F; + if(buffer[2*count] < 10) + { + buffer[2*count] += '0'; + } + else + { + buffer[2*count] += 'a'; + } + buffer[(2*count)+1] = (pmac.addr[count] & 0x0F); + if(buffer[(2*count)+1] < 10) + { + buffer[(2*count)+1] += '0'; + } + else + { + buffer[(2*count)+1] += 'a'; + } + } + buffer[12] = 0; + printf("New mac addres is %s.\n", buffer); + fflush(stdout); + exit(0); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/8253xmcs.c linux-2.5/drivers/net/wan/8253x/8253xmcs.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xmcs.h linux-2.5/drivers/net/wan/8253x/8253xmcs.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xmode.c linux-2.5/drivers/net/wan/8253x/8253xmode.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xnet.c linux-2.5/drivers/net/wan/8253x/8253xnet.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xpeer.c linux-2.5/drivers/net/wan/8253x/8253xpeer.c --- linux-2.5.13/drivers/net/wan/8253x/8253xpeer.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xpeer.c Fri May 3 03:49:07 2002 @@ -0,0 +1,113 @@ +/* -*- 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" +#include + +struct pollfd pollarray[2]; + +/* This application sets up synchronous character mode and loosely + * emulates putmsg/getmsg use with read and write. */ + +char buffer[8192]; + +int main(int argc, char **argv) +{ + int fd; + int status; + int prompt = 1; + int count; + + if(argc != 2) + { + fprintf(stderr, "Syntax: %s {portname}\n", *argv); + exit(-1); + } + fd = open(argv[1], O_RDWR); + if(fd < 0) + { + perror("open failed."); + exit(-2); + } + do + { + if(prompt) + { + printf("Enter data: "); + fflush(stdout); + prompt = 0; + } + pollarray[0].fd = 0; + pollarray[0].events = POLLIN; + pollarray[0].revents = 0; + pollarray[1].fd = fd; + pollarray[1].events = POLLIN|POLLOUT; + pollarray[1].revents = 0; + status = poll(pollarray, 2, 10); + switch(status) + { + case 0: + break; + + case 1: + case 2: + if(pollarray[0].revents == POLLIN) + { + if(count = read(0, buffer, 150), count <= 0) + { + perror("unable to read stdio.\n"); + exit(0); + } + buffer[count] = '\0'; + if(count) + { + if(pollarray[1].revents & POLLOUT) + { + if(write(pollarray[1].fd, buffer, count) <= 0) + { + perror("unable to write protodevice.\n"); + exit(-1); + } + } + else + { + printf("Write of protodevice would block.\n"); + fflush(stdout); + } + } + prompt = 1; + } + if(pollarray[1].revents & POLLIN) + { + if(count = read(pollarray[1].fd, buffer, 8192), count <= 0) + { + perror("unable to read protodevice.\n"); + exit(0); + } + buffer[count] = '\0'; + printf("\nRead: %s", buffer); + fflush(stdout); + prompt = 1; + } + break; + + default: + break; + } + } + while(status >= 0); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/8253xplx.c linux-2.5/drivers/net/wan/8253x/8253xplx.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xspeed.c linux-2.5/drivers/net/wan/8253x/8253xspeed.c --- linux-2.5.13/drivers/net/wan/8253x/8253xspeed.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xspeed.c Fri May 3 03:49:07 2002 @@ -0,0 +1,91 @@ +/* -*- 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" + + +/* This application shows how to set custom speeds/baudrates */ + +int main(int argc, char **argv) +{ + int fd; + unsigned long oldspeed, newspeed; + char buffer[200]; + int count; + long value; + int noprompt = 0; + int epromindex; + + if(argc < 2) + { + fprintf(stderr, "Syntax: %s {portname} [-n] {new speed}.\n", *argv); + exit(-1); + } + fd = open(argv[1], O_RDWR); + if(fd < 0) + { + perror("open failed."); + exit(-2); + } + + if((argc > 2) && !strcmp("-n", argv[2])) + { + noprompt = 1; + } + + /* get the current values */ + if(ioctl(fd, ATIS_IOCGSPEED, &oldspeed) < 0) + { + perror("ioctl failed."); + exit(-3); + } + /* set up the existing values as defaults */ + newspeed = oldspeed; + /* gather all new values from the command line */ + /* or via tty input.*/ + if(argc == (noprompt + 3)) + { + newspeed = atoi(argv[count]); + } + + fprintf(stderr, "speed [%ld/%ld]: ", oldspeed, newspeed); + + if(!noprompt) + { + if(count = read(0, buffer, 150), count <= 0) + { + exit(0); + } + buffer[count] = '\0'; + if(buffer[0] != '\n') + { + sscanf(buffer, "%ld", &newspeed); + } + } + else + { + fprintf(stderr, "\n"); + } + + /* This ioctl does the actual register load. */ + if(ioctl(fd, ATIS_IOCSSPEED, &newspeed) < 0) + { + perror("ioctl failed."); + exit(-3); + } + + fflush(stdout); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/8253xsyn.c linux-2.5/drivers/net/wan/8253x/8253xsyn.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xtty.c linux-2.5/drivers/net/wan/8253x/8253xtty.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/8253xutl.c linux-2.5/drivers/net/wan/8253x/8253xutl.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/Makefile linux-2.5/drivers/net/wan/8253x/Makefile --- linux-2.5.13/drivers/net/wan/8253x/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/Makefile Fri May 3 03:49:07 2002 @@ -0,0 +1,44 @@ +# 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 8253xcfg 8253xmac eprom9050 8253xspeed 8253xpeer eprom9050 + +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 8253xcfg 8253xmac eprom9050 *~ + +8253xcfg: 8253xcfg.c + $(CC) -o 8253xcfg $(EXTRA_CFLAGS) -U__KERNEL__ 8253xcfg.c + +8253xmac: 8253xmac.c + $(CC) -o 8253xmac $(EXTRA_CFLAGS) -U__KERNEL__ 8253xmac.c + +8253xspeed: 8253xspeed.c + $(CC) -o 8253xspeed $(EXTRA_CFLAGS) -U__KERNEL__ 8253xspeed.c + +8253xpeer: 8253xpeer.c + $(CC) -o 8253xpeer $(EXTRA_CFLAGS) -U__KERNEL__ 8253xpeer.c + +eprom9050: eprom9050.c + $(CC) -o eprom9050 $(EXTRA_CFLAGS) -U__KERNEL__ eprom9050.c + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/PciRegs.h linux-2.5/drivers/net/wan/8253x/PciRegs.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/Reg9050.h linux-2.5/drivers/net/wan/8253x/Reg9050.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/amcc5920.c linux-2.5/drivers/net/wan/8253x/amcc5920.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/clean linux-2.5/drivers/net/wan/8253x/clean --- linux-2.5.13/drivers/net/wan/8253x/clean Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/clean Fri May 3 03:49:07 2002 @@ -0,0 +1 @@ +rm -f 8253xcfg 8253xmac eprom9050 8253xspeed 8253xpeer eprom9050 \ No newline at end of file diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/crc32.c linux-2.5/drivers/net/wan/8253x/crc32.c --- linux-2.5.13/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.13/drivers/net/wan/8253x/crc32.h linux-2.5/drivers/net/wan/8253x/crc32.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/crc32dcl.h linux-2.5/drivers/net/wan/8253x/crc32dcl.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/endian.h linux-2.5/drivers/net/wan/8253x/endian.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/eprom9050.c linux-2.5/drivers/net/wan/8253x/eprom9050.c --- linux-2.5.13/drivers/net/wan/8253x/eprom9050.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/eprom9050.c Fri May 3 03:49:07 2002 @@ -0,0 +1,100 @@ +/* -*- 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" +#include "Reg9050.h" + + +/* This application reprograms the eprom associated with the 9050 */ + +int main(int argc, char **argv) +{ + int fd; + unsigned short oldeeprom[EPROM9050_SIZE], neweeprom[EPROM9050_SIZE]; + char buffer[200]; + int count; + int value; + unsigned short *pointer; + unsigned short *pointerold; + int noprompt = 0; + int epromindex; + + if(argc < 2) + { + fprintf(stderr, "Syntax: %s {portname} [-n] {prom values}.\n", *argv); + exit(-1); + } + fd = open(argv[1], O_RDWR); + if(fd < 0) + { + perror("open failed."); + exit(-2); + } + + if((argc > 2) && !strcmp("-n", argv[2])) + { + noprompt = 1; + } + + /* get the current values */ + if(ioctl(fd, ATIS_IOCGSEP9050, &oldeeprom) < 0) + { + perror("ioctl failed."); + exit(-3); + } + /* set up the existing values as defaults */ + memcpy(neweeprom, oldeeprom, sizeof(oldeeprom)); + /* gather all new values from the command line */ + /* or via tty input.*/ + for(count = (2+noprompt), pointer = neweeprom; count < argc; ++count, ++pointer) + { + *pointer = atoi(argv[count]); + } + pointer = neweeprom; + pointerold = oldeeprom; + for(epromindex = 0; epromindex < EPROM9050_SIZE; ++epromindex) + { + fprintf(stderr, "LOCATION %i [%4.4x/%4.4x]: ", epromindex, *pointerold, *pointer); + + if(!noprompt) + { + if(count = read(0, buffer, 150), count <= 0) + { + exit(0); + } + buffer[count] = '\0'; + if(buffer[0] != '\n') + { + sscanf(buffer, "%x", &value); + *pointer = (unsigned short) value; + } + } + else + { + fprintf(stderr, "\n"); + } + ++pointerold; + ++pointer; + } + /* This ioctl does the actual register load. */ + if(ioctl(fd, ATIS_IOCSSEP9050, neweeprom) < 0) + { + perror("ioctl failed."); + exit(-3); + } + + fflush(stdout); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/readme.txt linux-2.5/drivers/net/wan/8253x/readme.txt --- linux-2.5.13/drivers/net/wan/8253x/readme.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/readme.txt Fri May 3 03:49:07 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/sab8253xfs.html + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/ring.h linux-2.5/drivers/net/wan/8253x/ring.h --- linux-2.5.13/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.13/drivers/net/wan/8253x/sab8253xds.txt linux-2.5/drivers/net/wan/8253x/sab8253xds.txt --- linux-2.5.13/drivers/net/wan/8253x/sab8253xds.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/sab8253xds.txt Fri May 3 03:49:07 2002 @@ -0,0 +1,4562 @@ +*_Design Specification of SAB8253X ASLX Driver for Linux_* + + + + + The effort to design and implement the ASLX SAB8253X Driver for Aurora + hardware with the functionality described + in *_Functional Specification of SAB8253X ASLX Driver for Linux + _* requires + solutions to seven separate problems: + + + + 1. creating a development environment for maintaining and extending + the driver, + 2. integrating the driver into the kernel sources, + 3. creating a file structure of the driver that aids understanding, + 4. crafting a reasonable and easy to use user interface, + 5. developing simple tools and example programs for the driver, and + 6. designing the driver data structures and + 7. designing the driver program logic. + + + + + _Development Environment_ + + + + + There are several possible approaches to creating a development + environment. The development environments for many drivers seem + to have consisted simply of a single machine, and the developer + used only /printk()/ in the driver code to debug. I used such an + environment to develop a driver for an IOP480 based intelligent + adapter card. + + + +For a driver that provides the functionality described in the Functional +Specification, a more sophisticated development and debugging +environment is useful. (One could even occasionally wish for an ICE, +but that level of resources was not available to me.) + + + +The development environment consisted of two 686 class machines, on +which the Linux operating system was installed. One machine ran at 800 +Mhz, the other at 1Ghz. It probably would have been worthwhile to have +dual processor machine, and one was added to the development environment +later. The 800 Mhz machine hosted the remote gdb application. It ran +Redhat Linux 7.0, but because the machine served only as an NFS and +remote gdb host, the details of the Linux distribution on this machine +are not particularly important. + + + +The target machine on which the driver was developed and debugged hosted +Suse Linux 7.1 and was later upgraded to Suse Linux 7.3. Suse Linux +seemed to provide the most complete Linux distribution with the least +hassle in installation. (As the Suse distribution comes on 7 standard +CDs or 1 DVD, there is a lot of value in having a DVD drive in the +target machine [and the gdb host if it runs a Suse distribution].) + + + +The target and remote gdb machines are connected by a 100 Mbps Ethernet +network and by a serial crossover cable between the Com1 (ttyS0) ports. + + + +When I started developing the driver, I obtained the Linux 2.4.3 sources +from The Linux Kernel Archives . Later as later +distributions became stable, I switched to the Linux 2.4.6 +distribution. The sources were installed first in +/home/martillo/kernel/linux-2.4.3 and then in +/home/martillo/kernel/linux-2.4.6 on the remote gdb host machine, which +was named frolix. + + + +The sources were imported into CVS on frolix, and the core directory +into CVS was added manually because the cvs import function ignores +it. I consider it safer to maintain the CVS repository on the remote +gdb host machine instead of the target machine because the target +machine is likely to crash frequently, and its file system may be put +into bad states. + + + +I executed the following commands on the remote gdb host machine. + + + +*ln ^Ös /home/martillo/kernel/linux-2.4.3/include/asm-i386 +/home/martillo/kernel/linux-2.4.3/include/asm* + +* * + +or + +* * + +*ln ^Ös /home/martillo/kernel/linux-2.4.6/include/asm-i386 +/home/martillo/kernel/linux-2.4.6/include/asm* + +* * + +*ln ^Ös / /frolix * + + + +I edited the /etc/exports file to contain the following. + + + +/ ylith(rw) + +/ fireball(rw) + +/ bohun(rw) + +/ indefatigable(rw) + + + +Ylith is the original 1 Ghz target machine. Fireball is a 400 Mhz +compact PCI target machine. Indefatigable is a dual 1 Ghz target +machine. Bohun is a Solaris target machine used for another project. + + + +On the frolix, I started NFS with the following commands (contained in a +shell script). + + + +*/etc/rc.d/init.d/nfs start* + +*exportfs -va* + + + +If it had been a Suse Linux machine, I would have used the yast2 control +center to start NFS service. + + + +On ylith, I created an empty directory /frolix and executed the +following command. + + + +*mount frolix:/ /frolix* + +* * + +At this point both the remote gdb host (frolix) and the target +development and debugging machine can refer to the same files by the +same paths. I could have guaranteed the same paths to the source files +on both machines if I had simply used /home/martillo as my home +directory on frolix and exported /home from frolix to all the other +machines so that there would only be one /home directory for all the +machines in my network. I was lazy about the network configuration. + + + +After making sure that the user martillo had read write access +permissions to all the kernel sources, I built the kernel on the target +machine from within xemacs with the following sequence of commands. + + + +From a shell window: + +*xemacs ^Öe shell&* + + + +Inside xemacs: + + + +*cd /frolix/home/martillo/kernel/linux-2.4.3* + + + +or + + + +*cd /frolix/home/martillo/kernel/linux-2.4.6* + + + +Then make sure that linux-2.4.x/include/asm-i386 is symbolically linked to +linux-2.4.x/include/asm. + + + +Execute the following emacs command. + + + + + M-x compile + + + +This command prompts for targets. + + + +In the development environment the most useful target string was usually +/clean xconfig dep bzImage modules./ The target /xconfig /brings up a +configuration window. In the basic development environment, it was +generally worthwhile to add SCSI CD ROM, SCSI legacy support, an +Ethernet driver and DOS file system support + + + +The target/ dep/ creates the dependencies (note that if the kernel tree +is ever removed, the .depend and .hdepend files must be regenerated). +The /bzImage /target builds the kernel. The /modules/ target generates +all the modules to be dynamically installed in the kernel via the +*insmod* command. + + + +After building the kernel, installing the modules in the /lib tree +requires the execution (as root) of + + + +make modules_install + + + +The command *make install* *INSTALL_PATH=/boot* will install the +compressed kernel image as vmlinuz along with other files in the /boot +partition. I preferred to use a shell script with commands like the +following. + + + +cp /frolix/home/martillo/kernel/linux-2.4.6/arch/i386/boot/bzImage +/boot/vmlinuz_246 + +cp /frolix/home/martillo/kernel/linux-2.4.6/System.map +/boot/System.map-2.4.6 + +cp /frolix/home/martillo/kernel/linux-2.4.6/.config /boot/vmlinuz_246.config + +cp /frolix/home/martillo/kernel/linux-2.4.6/include/linux/autoconf.h +/boot/vmlinuz_246.autoconf.h + +cp /frolix/home/martillo/kernel/linux-2.4.6/include/linux/version.h +/boot/vmlinuz_246.version.h + + + +When the kernel comes from a linux-2.4.3 tree, the obvious substitutions +of 3 for 6 are required. + + + +Once all the modules and the kernel image are installed, the next step +in giving the system the ability to boot with the new linux-2.4.3 or +linux-2.4.6 kernel image is the modification of the lilo.conf file. + + + +I added the following directives to the lilo.conf file. + + + + image = /boot/vmlinuz_243 + + label = linux_2.4.3 + + root = /dev/hde7 + + optional + + + + image = /boot/vmlinuz_246 + + label = linux_2.4.6 + + root = /dev/hde7 + + optional + + + +In this case /dev/hde7 corresponds to the /boot partition, and the +options linux_2.4.3 and linux_2.4.6 will be added to the boot menu once +the *lilo* command has been executed. In other system setups the disk +partition that corresponds to /boot might have a different name like +/dev/hda7. + + + +Once the new kernel successfully boots, the next step to creating a +driver development and debugging environment is patching the kernel for +remote gdb debugging. + + + +The necessary patch can be obtained from kgdb: Source level debugging of +linux kernel . + + + +Now the kernel can be built again with the extra step of configuring for +remote gdb support in the kernel configuration menu. + + + +The following directives should be added to lilo.conf. + + + + image = /boot/vmlinuz_243 + + label = debug243 + + append = "gdb gdbttyS=0 gdbbaud=115200" + + root = /dev/hde7 + + optional + + + + image = /boot/vmlinuz_246 + + label = debug246 + + append = "gdb gdbttyS=0 gdbbaud=115200" + + root = /dev/hde7 + + optional + + + + + Then lilo can be executed. On reboot the boot menu will include + options for debug243 and debug246. + + + +To test the patch, select one of the debug options. Then, on the remote +gdb host machine execute the following command. + + + +stty 115200 < /dev/ttyS0 + + + +Start up an *xemacs* process. Execute the following commands within +*xemacs.* + + + + + M-x shell + + + +Then within the shell window execute the following command. + + + +cd /frolix/home/martillo/kernel/linux-2.4./X/ + +/ / + +Then invoke the remote debugger. + + + + + M-x gdb + + + +Reply to the file prompt with *vmlinux.* + +* * + +In the gdb window, execute the following command. + + + +target remote /dev/ttyS0 + + + +The gdb window should break in gdbstub.c which will be displayed in the +gdb source window. + + + +At this point, all the basic gdb remote debugging capabilities are ready +to use. + + + +To access the hardware breakpoint capability of the i386 processor, the +following commands can be loaded directly or from a file with the +*script* command. + + + +#Hardware breakpoints in gdb + +# + +#Using ia-32 hardware breakpoints. + +# + +#4 hardware breakpoints are available in ia-32 processors. These breakpoints + +#do not need code modification. They are set using debug registers. + +# + +#Each hardware breakpoint can be of one of the + +#three types: execution, write, access. + +#1. An Execution breakpoint is triggered when code at the breakpoint +address is + +#executed. + +#2. A write breakpoint ( aka watchpoints ) is triggered when memory location + +#at the breakpoint address is written. + +#3. An access breakpoint is triggered when memory location at the breakpoint + +#address is either read or written. + +# + +#As hardware breakpoints are available in limited number, use software + +#breakpoints ( br command in gdb ) instead of execution hardware +breakpoints. + +# + +#Length of an access or a write breakpoint defines length of the datatype to + +#be watched. Length is 1 for char, 2 short , 3 int. + +# + +#For placing execution, write and access breakpoints, use commands + +#hwebrk, hwwbrk, hwabrk + +#To remove a breakpoint use hwrmbrk command. + +# + +#These commands take following types of arguments. For arguments associated + +#with each command, use help command. + +#1. breakpointno: 0 to 3 + +#2. length: 1 to 3 + +#3. address: Memory location in hex ( without 0x ) e.g c015e9bc + +# + +#Use the command exinfo to find which hardware breakpoint occured. + + + + + +#hwebrk breakpointno address + +define hwebrk + + maintenance packet Y$arg0,0,0,$arg1 + +end + +document hwebrk + + hwebrk breakpointno address + + Places a hardware execution breakpoint + +end + + + +#hwwbrk breakpointno length address + +define hwwbrk + + maintenance packet Y$arg0,1,$arg1,$arg2 + +end + +document hwwbrk + + hwwbrk breakpointno length address + + Places a hardware write breakpoint + +end + + + +#hwabrk breakpointno length address + +define hwabrk + + maintenance packet Y$arg0,1,$arg1,$arg2 + +end + +document hwabrk + + hwabrk breakpointno length address + + Places a hardware access breakpoint + +end + + + +#hwrmbrk breakpointno + +define hwrmbrk + + maintenance packet y$arg0 + +end + +document hwrmbrk + + hwrmbrk breakpointno + + Removes a hardware breakpoint + +end + + + +#exinfo + +define exinfo + + maintenance packet qE + +end + +document exinfo + + exinfo + + Gives information about a breakpoint. + +end + + + +Once the above macros are define, the developer can set hardware +breakpoints. + + + +The next step to creating a useful development and debugging environment +is to provide a shell script to for remote debugging of dynamically +loaded modules. The following shell script (called *loadmodule.sh*) +creates a gdb script called *load/ModuleName/* in +/frolix/home/martillo/kernel/linux-2.4.6 when it is invoked (as root) +with the following command. + +loadmodule.sh modulename + + + +In order to decrease the probability of confusion, I usually make a link +in kernel root directory, /frolix/home/martillo/kernel/linux-2.4.6, to +the location of the module to be debugged in the kernel tree. The above +command is invoked on the target machine (ylith) in the root directory. +On the remote debug machine, in the gdb command window, whose working +directory should be the kernel root directory, +/frolix/home/martillo/kernel/linux-2.4.6, the command, *script +load/ModuleName/*, is invoked. Once the script is executed the symbols +for the module are available for remote symbolic debugging. + + + +#!/bin/sh + +# This script loads a module on a target machine and generates a gdb script. + +# source generated gdb script to load the module file at appropriate +addresses + +# in gdb. + +# + +# Usage: + +# Loading the module on target machine and generating gdb script) + +# [foo]$ loadmodule.sh + +# + +# Loading the module file into gdb + +# (gdb) source + +# + +# Modify following variables according to your setup. + +# TESTMACHINE - Name of the target machine + +# GDBSCRIPTS - The directory where a gdb script will be generated + +# + +# Author: Amit S. Kale (akale@veritas.com). + +# + +# If you run into problems, please check files pointed to by following + +# variables. + +# ERRFILE - /tmp/.errs contains stderr output of insmod + +# MAPFILE - /tmp/.map contains stdout output of insmod + +# GDBSCRIPT - $GDBSCRIPTS/load gdb script. + + + +TESTMACHINE=ylith + +GDBSCRIPTS=/frolix/home/martillo/kernel/linux-2.4.6 + + + +if [ $# -lt 1 ] ; then { + + echo Usage: $0 modulefile + + exit + +} ; fi + + + +MODULEFILE=$1 + +MODULEFILEBASENAME=`basename $1` + + + +if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then { + + MODULEFILE=`pwd`/$MODULEFILE + +} fi + + + +ERRFILE=/tmp/$MODULEFILEBASENAME.errs + +MAPFILE=/tmp/$MODULEFILEBASENAME.map + +GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME + + + +function findaddr() { + + local ADDR=0x$(echo "$SEGMENTS" | \ + + grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \ + + sed 's/[ ]*[^ ]*$//') + + echo $ADDR + +} + + + +function checkerrs() { + + if [ "`cat $ERRFILE`" != "" ] ; then { + + cat $ERRFILE + + } fi + +} + + + +#load the module + +#echo Copying $MODULEFILE to $TESTMACHINE + +#*rcp $MODULEFILE root@${TESTMACHINE}: + + + +echo Loading module $MODULEFILE + +#rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \ + +# > $MAPFILE 2> $ERRFILE & + +/sbin/insmod -m ./`basename $MODULEFILE` $2 . . > $MAPFILE 2> $ERRFILE & + +sleep 5 + +checkerrs + + + +NUMLINES=`grep -n '^$' $MAPFILE | sed -e 's/:.*//g'` + +SEGMENTS=`head -n $NUMLINES $MAPFILE | tail -n $(eval expr $NUMLINES - 1)` + +TEXTADDR=$(findaddr "\\.text[^.]") + +LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR" + +SEGADDRS=`echo "$SEGMENTS" | awk '//{ + + if ($1 != ".text" && $1 != ".this" && + + $1 != ".kstrtab" && $1 != ".kmodtab") { + + print " -s " $1 " 0x" $3 " " + + } + +}'` + +LOADSTRING="$LOADSTRING $SEGADDRS" + +echo Generating script $GDBSCRIPT + +echo $LOADSTRING > $GDBSCRIPT + + + +With the addition of the above shell script, the driver development and +debugging environment is almost complete. Other useful tools for +developing and debugging this type of serial driver would include a +Wanalyzer (I used an Interview 7700 and an HP 4952A in developing this +driver), a breakout box that displays interface signal states and (for +developing the serial Ethernet-like network driver) several WAN LAN VLAN +routers as described in *Packet Switching Software and Platforms +*, *Routing in a +Bridged Network , **A +WAN SUBSYSTEM for a High Performance Packet Switch +* and *A New High +Performance Architecture for Routers, Bridges and LAN Switches (Software +Defined Internetworking) +.* + + + + + _Integration into the Kernel Sources_ + + + + +The driver has its own directory, {kernel root +directory}/drivers/net/wan/8253x, in the 2.4.* kernel source tree. + + + +To facilitate the automatic build of the 8253x driver, the following +standard kernel files were modified. + + + +1. {kernel root directory}/drivers/net/wan/Config.in to +which the line + + + +tristate ' Aurora Technology, Inc. synchronous asynchronous PCI cards +V2' CONFIG_ATI_XX20 + + + + +was added, + +2. {kernel root directory}/drivers/net/wan/Makefile to +which the following lines were added, + + + +subdir-$(CONFIG_ATI_XX20) += 8253x + + + +ifeq ($(CONFIG_ATI_XX20),y) + + obj-y += 8253x/ASLX.o + +endif + + + +When the driver is built as a dynamically loaded module, the following +macro commands in the file 8253xini.c puts the module entry points in +the special module entry point segment. + + + +module_init(auraXX20_probe); + +module_exit(auraXX20_cleanup); + + + +The sources are provided to the users in a patch file, tentatively named +8253x.patch . + + + +To install it the user sets his directory to the top level of the kernel +sources and executes the following command. + + + +patch ^Öp1 < /{directory-patch}//8253x.patch + + + + + + _File Structure of the ASLX Driver Source Code_ + + + +The following files are present in the driver directory. + + + +8253x.h + +8253xdbg.c + +8253xmac.c + +8253xsyn.c + +PciRegs.h + +crc32.h + +sp502.h + +8253xcfg.c + +8253xini.c + +8253xnet.c + +8253xtty.c + +Reg9050.h + +crc32dcl.h + +ring.h + +8253xctl.h + +8253xioc.h + +8253xplx.c + +8253xint.c + +crc32.c + +endian.h + +Makefile + +Amcc5920.c + +8253xmcs.h + +8253xmcs.c + +8253xchr.c + +8253xutl.c + + + + + + + +The source code is divided functionally among the files of the ASLX driver. + + + +8253xcfg.c is the source for a user application that configures 8253x +control registers to provide clocking. 8253xmac.c is the source for a +user application that sets a pseudo-MAC address for the network driver. + + + +8253xini.c contains the initialization/probe logic. + + + +8253xint.c contains the common interrupt logic. + + + +8253xtty.c contains the asynchronous TTY logic. + + + +8253xsyn.c contains the synchronous TTY logic. + + + +8253xnet.c contains the network driver logic. + + + +8253xchr.c contains the character driver logic. + + + + +8253xdbg.c contains some debugging functions. + + + +8253xutl.c contains most of the functions that are common among the +different driver functional subunits. + + + +8253xplx.c contains some functions specific to the PLX9050 (a PCI bridge +chip) and specifically to reading and reprogramming the associated +serial EEPROM. + + + +amcc5920.c contains some functions specific to the AMCC5920 (a PCI +bridge chip) and specifically to reading and reprogramming the +associated serial EEPROM. + + + +8253xmcs.c contains functions specific to programming the multichannel +server (mostly G-LINK related logic, programming the sp502 driver chip +and reading or programming the serial EEPROM associated with the +interface cards contained within the MCS unit). + + + +crc32.c contains logic to append a CRC32 to a pseudo MAC frame that is +generated by the network driver. + + + +8253x.h contains symbols, structures and macros that relate mostly to +the 8253x chips and ports. + + + +8253xctl.h contains symbols, structures and macros that relate mostly to +the adapter cards. + + + +8253xmcs.h contains symbols and structures that relate mostly to the +multichannel server. A lot of this file relates to G-LINK. + + + +sp502.h contains symbols and structures that relate to the programming +of the hardware interface line drivers of the 3500 adapter cards of the +multichannel server. + + + +8253xioc.h contains symbols and structures that relate to private ioctls. + + + +PciRegs.h contains symbols and structures that relate to PCI +configuration space. + + + +Reg9050.h contains symbols and structures that relate to the PLX9050 PCI +interface chip and its serial eprom + + + +crc32.h, crc32dcl.h and .endian.h contain symbols, structures and macros +that relate to generating a correct CRC32. + + + +ring.h contains symbols and structures that relate to the network driver +frame transmission ring and frame reception. + + + +The Makefile is a standard Linux kernel Makefile whose structure is +dictated by the current Linux build formalism. + + + + + _Using the ASLX Driver _ + + + + + + The ASLX driver is designed to be a ^Óplug-and-play^Ô driver as far as + possible. If it is built as a dynamically loadable module, the user + (or relevant system configuration file) invokes /insmod /to load the + ASLX.o file. + + + +The following parameters can be set on the /insmod/ command line. + + + +MODULE_PARM(xx20_minorstart, "i");/*when statically linked autodected +otherwise 128 by default*/ + +MODULE_PARM(sab8253xc_major, "i");/*major dev for character device, by +default dynamic */ + +MODULE_PARM(auraXX20n_debug, "i");/*turns on debugging messages, default +off*/ + +MODULE_PARM(auraXX20n_name, "s"); /*base network driver name = 8253x000*/ + +MODULE_PARM(sab8253xn_listsize, "i"); /*transmit ring size default 32*/ + +MODULE_PARM(sab8253xc_name, "s");/*registered name for char driver = +sab8253xc*/ + +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.] + + + +The MAKETERMS script below parses the /proc/tty/driver/auraserial file +to make the asynchronous TTY device files in the /dev directory. + + + +TTYDEV=$1 + +MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e +'/[a-zA-Z]/d' | sed -e 's/://'` + + + +for i in $MDEVS + +do + + TTYNAME=/dev/ttyS${TTYDEV} + + mknod $TTYNAME c 4 $i + + TTYDEV=$((${TTYDEV}+1)) + +done + + + +The MAKEPROTO script below provides a prototype to modify the +/etc/inittab file so that an agetty process can be spawned on every +other /dev/ttyS* at 9600 bps + + + +TTYDEV=$1 + +MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e +'/[a-zA-Z]/d' | sed -e 's/://'` + +LEADCHAR="" + + + +for i in $MDEVS + +do + + NAME=S${TTYDEV} + + TTYNAME=ttyS${TTYDEV} + + echo ${LEADCHAR}${NAME}:35:respawn:/sbin/agetty 9600 ${TTYNAME} + + TTYDEV=$((${TTYDEV}+1)) + + if [ -z "$LEADCHAR" ] + + then + + LEADCHAR="#" + + else + + LEADCHAR="" + + fi + +done + + + + + If loopback cables are connected between successive TTY ports on each + Aurora adapter card or unit, the command + + + +cu ^Öl /dev/ttyS{n} ^Ös 9600 + + + +would connect to the login that was spawned on /dev/ttyS{n-1}. + + + +The script MAKESTERMS (viz below) creates synchronous TTY dev files for +all the Aurora serial ports. + + + +TTYDEV=$1 + +MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e +'/[a-zA-Z]/d' | sed -e 's/://'` + + + +for i in $MDEVS + +do + + TTYNAME=/dev/sttyS${TTYDEV} + + mknod $TTYNAME c 5 $i + + TTYDEV=$((${TTYDEV}+1)) + +done + + + +The MAKESPROTO script below creates a prototype with which to modify the +/etc/inittab file to spawn an agetty process on every other +/dev/sttyS{N} device. + + + +TTYDEV=$1 + +MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e +'/[a-zA-Z]/d' | sed -e 's/://'` + +LEADCHAR="" + + + +for i in $MDEVS + +do + + NAME=sS${TTYDEV} + + TTYNAME=sttyS${TTYDEV} + + echo ${LEADCHAR}${NAME}:35:respawn:/sbin/agetty 9600 ${TTYNAME} + + TTYDEV=$((${TTYDEV}+1)) + + if [ -z "$LEADCHAR" ] + + then + + LEADCHAR="#" + + else + + LEADCHAR="" + + fi + +done + + + + + The simplest way to use these terminals with the agetty process that + comes with the Linux distribution is to leave externally clocked (the + default) the terminals on which agetty has been spawned. + + + +The loopback cable can be connected to a port on which agetty is not +being run. The clockside of the cable is connected to this port. The +user can run the MAKECLOCKING script below. + + + +echo 8253xcfg $1 -n 64 158 56 4 192 140 15 + +8253xcfg $1 -n 64 158 56 4 192 140 15 + + + +The numbers on the 8253xcfg command line are new (decimal) values for +the channel control, mode and baud rate registers. The file 8253xioc.h +and sab8253x manuals from Siemens/Infineon can assist in explaining the +reasoning behind these values. The 8253xcfg sets the mode, channel +control and baudrate generator registers of the port specified by +/dev/sttyS{N-1} which is the argument $1 of this script file. 8253xcfg +is a simple example program that is included with the driver sources. +It is described in the next section of this document. + + + +At this point, the user could execute the following command to connect +synchronously to the peer synchronous TTY port. + + + +cu ^Öl /dev/sttyS{n} ^Ös 9600 + + + +To turn off internal clocking use the following command. + + + +8253xcfg /dev/sttyS? ^Ön 64 152 0 4 0 140 15 + + + +To use an ASLX network device the following commands would be used. + + + +*MAKECLOCKING /dev/sttyS*/{N} [if the interface is to provide clock]/ + +*stty */{speed} /*< /dev/sttyS*/{N} [if the interface is to provide clock]/ + + + +To set the MAC address, which defaults to 00:00:00:00:00:00 and which +consequently must be changed, use the following command. + + + +*ifconfig 8253x*/{mdev} /*hw ether*/ {mac address} [as root]/ + + + +[Note that the 8253x{mdev} interface must not be running when the above +command is executed.] + + + +To set the IP address, use the command. + +/ / + +*ifconfig 8253x*/{mdev} {ipadress} [as root]/ + + + +[Note that the two ifconfig commands can be combined on one line. If +they are executed separately the MAC address command must be executed +before the IP address command.] + + + +After the completion of the above commands, assuming there is an active +network peer that uses the same serial Ethernet frame structure, it +should be possible to ping or telnet to the peer networking device. + + + +{mdev} is the minor device number (in decimal, 3 digits including +leading 0s required) associated with /dev/sttyS{N}.// + +* * + +To disable the network interface use the following command. + + + +*ifconfig 8253x*/{mdev} /*down*/ [as root]/ + + + +If there is a need to disable clocking on a serial port, the +MAKENONCLOCKING shell script is invoked with the TTY device as an +argument as follows. + + + +MAKENONCLOCKING /dev/ttyS{N} + + + +The shell script contains the following commands. + + + +echo 8253xcfg $1 -n 64 152 0 4 192 140 255 + +8253xcfg $1 -n 64 152 0 4 192 140 255 + + + +The numbers on the 8253xcfg command line are new (decimal) values for +the channel control, mode and baud rate registers. The file 8253xioc.h +and sab8253x manuals from Siemens/Infineon can assist in explaining the +reasoning behind these values. The 8253xcfg sets the mode, channel +control and baudrate generator registers of the port specified by +/dev/sttyS{N-1} which is the argument $1 of this script file. 8253xcfg +is a simple example program that is included with the driver sources. +It is described in the next section of this document. + + + + + + _Simple Tools and Example Programs_ + + + +The tools and example programs supplied with the SAB8253X ASLX driver +are the following. + +1. eprom9050 + +2. 8253xcfg + +3. 8253xspeed + +4. 8253xpeer + +5. 8253xmode + + + eprom9050 + + + +This program performs the bit-banging necessary to read and to program +the serial eprom of the PLX9050. + + + +To access the serial eprom on an adapter card the program opens up a TTY +device on the adapter card, whose serial eprom is to be modified. +This TTY device can either be synchronous, asynchronous or callout. The +TTY device is passed as an argument when the program is invoked. + + + +The program uses the ATIS_IOCGSEP9050 IOCTL to get the current serial +eprom values and the ATIS_IOCSSEP9050 IOCTL to set the new serial eprom +values. + + + +Here is the source code of the program. + + + +/* + + * 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" + +#include "Reg9050.h" + + + + + + /* This application shows how to load the */ + + /* channel control, mode and rx frame +length */ + + /* check registers via an ioctl.*/ + + + +int main(int argc, char **argv) + +{ + + int fd; + + unsigned short oldeeprom[EPROM9050_SIZE], neweeprom[EPROM9050_SIZE]; + + char buffer[200]; + + int count; + + int value; + + unsigned short *pointer; + + unsigned short *pointerold; + + int noprompt = 0; + + int epromindex; + + + + if(argc < 2) + + { + + fprintf(stderr, "Syntax: %s {portname} [-n] {prom values}.\n", *argv); + + exit(-1); + + } + + fd = open(argv[1], O_RDWR); + + if(fd < 0) + + { + + perror("open failed."); + + exit(-2); + + } + + + + if((argc > 2) && !strcmp("-n", argv[2])) + + { + + noprompt = 1; + + } + + + + /* get the current values */ + + if(ioctl(fd, ATIS_IOCGSEP9050, &oldeeprom) < 0) + + { + + perror("ioctl failed."); + + exit(-3); + + } + + /* set up the existing values as defaults */ + + memcpy(neweeprom, oldeeprom, sizeof(oldeeprom)); + + /* gather all new values from the +command line */ + + /* or via tty input.*/ + + for(count = (2+noprompt), pointer = neweeprom; count < argc; ++count, +++pointer) + + { + + *pointer = atoi(argv[count]); + + } + + pointer = neweeprom; + + pointerold = oldeeprom; + + for(epromindex = 0; epromindex < EPROM9050_SIZE; ++epromindex) + + { + + fprintf(stderr, "LOCATION %i [%4.4x/%4.4x]: ", epromindex, +*pointerold, *pointer); + + + + if(!noprompt) + + { + + if(count = read(0, buffer, 150), count <= 0) + + { + + exit(0); + + } + + buffer[count] = '\0'; + + if(buffer[0] != '\n') + + { + + sscanf(buffer, "%x", &value); + + *pointer = (unsigned short) value; + + } + + } + + else + + { + + fprintf(stderr, "\n"); + + } + + ++pointerold; + + ++pointer; + + } + + /* This ioctl does the actual register +load. */ + + if(ioctl(fd, ATIS_IOCSSEP9050, neweeprom) < 0) + + { + + perror("ioctl failed."); + + exit(-3); + + } + + + + fflush(stdout); + +} + + + +With the above program it is possible to change PCI vendor and device ID +values of the adapter card. At that point the card would no longer be +visible to the driver. To correct the vendor and device IDs use the +*lspci* Linux command to find out what new values are and recompile the +driver code after modifying the symbols that correspond to the correct +vendor and device Ids of the card to the new values. (I should make the +vendor and device IDs module parameters that can be set from the +*insmod* command line.) The eprom9050 can be invoked to write the +device and vendor IDs to the correct values. Of course, then the card +will no longer be visible to the new version of the driver, and the +original version of the driver must be used to communicate with this card. + + + + + 8253xcfg + + + +The 8253xcfg command provides access to images of the channel control, +mode and baud rate generator registers of the serial port that is +specified by the minor device number (port number = minor device number +^Ö minor_start) of the TTY device (either synchronous, asynchronous or +callout) specified on the command line by which 8253xcfg is invoked. +The next time the port is initialized (usually on the first open after +every process that currently has the port open has closed it) these +registers are set with the values of their images. The 8253xcfg command +can make a synchronous port clocking or non-clocking. Note that even +though 8253xcfg operates on a TTY device, the open that finally sets the +registers with the values from the images can be either a synchronous +TTY, a network device or a synchronous character device open. The +program uses the ATIS_IOCGPARAMS IOCTL to get the current values of the +images of the registers and employs the ATIS_IOCSPARAMS IOCTL to set the +current values of the images of the registers. Here is the source of +the 8253xcfg program. + + + +/* + + * 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" + + + +char *prompts[] = + + { + + "ccr0", + + "ccr1", + + "ccr2", + + "ccr3", + + "ccr4", + + "mode", + + "rlcr", + + 0 + + }; + + + + /* This application shows how to load the */ + + /* channel control, mode and rx frame +length */ + + /* check registers via an ioctl.*/ + + + +int main(int argc, char **argv) + +{ + + int fd; + + struct channelcontrol ccontrolold, ccontrolnew; + + char buffer[200]; + + int count; + + int value; + + unsigned char *pointer; + + unsigned char *pointerold; + + char **promptpointer = prompts; + + int noprompt = 0; + + + + if(argc < 2) + + { + + fprintf(stderr, "Syntax: %s {portname} [-n] [ccr0 [ccr1 [ccr2 +[ccr3 [ccr4 [mode [rlcr]]]]]]].\n", *argv); + + exit(-1); + + } + + fd = open(argv[1], O_RDWR); + + if(fd < 0) + + { + + perror("open failed."); + + exit(-2); + + } + + + + if((argc > 2) && !strcmp("-n", argv[2])) + + { + + noprompt = 1; + + } + + + + /* get the current values */ + + if(ioctl(fd, ATIS_IOCGPARAMS, &ccontrolold) < 0) + + { + + perror("ioctl failed."); + + exit(-3); + + } + + /* set up the existing values as defaults */ + + ccontrolnew = ccontrolold; + + + + /* gather all new values from the +command line */ + + /* or via tty input.*/ + + for(count = (2+noprompt), pointer = (unsigned char*) &ccontrolnew; +count < argc; ++count, ++pointer) + + { + + *pointer = atoi(argv[count]); + + } + + pointer = (unsigned char*) &ccontrolnew; + + pointerold = (unsigned char*) &ccontrolold; + + while(*promptpointer) + + { + + fprintf(stderr, "%s [%2.2x/%2.2x]: ",*promptpointer, *pointerold, +*pointer); + + + + if(!noprompt) + + { + + if(count = read(0, buffer, 150), count <= 0) + + { + + exit(0); + + } + + buffer[count] = '\0'; + + if(buffer[0] != '\n') + + { + + sscanf(buffer, "%x", &value); + + *pointer = (unsigned char) value; + + } + + } + + else + + { + + fprintf(stderr, "\n"); + + } + + ++pointerold; + + ++pointer; + + ++promptpointer; + + } + + /* This ioctl does the actual register +load. */ + + if(ioctl(fd, ATIS_IOCSPARAMS, &ccontrolnew) < 0) + + { + + perror("ioctl failed."); + + exit(-3); + + } + + + + fflush(stdout); + +} + + + + + + + 8253xspeed + + + +This program sets the custom baud rate of a serial port. If the custom +baud rate of a serial port is non-zero, and if the standard baud rate +has been set to 38,400 bps, the next time the port is initialized, the +port will run at the custom baud rate. If the custom baud rate were 0, +the port would run at the standard baud rate. The 8352xpeed program is +invoked with a TTY device (either asynchronous, synchronous or callout), +but the effect also applies to the network device and the synchronous +character device that correspond to the same physical serial port. + + + +Here is the source code for the 8253xspeed. + + + +/* + + * 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" + + + + + +int main(int argc, char **argv) + +{ + + int fd; + + unsigned long oldspeed, newspeed; + + char buffer[200]; + + int count; + + long value; + + int noprompt = 0; + + int epromindex; + + + + if(argc < 2) + + { + + fprintf(stderr, "Syntax: %s {portname} [-n] {new speed}.\n", *argv); + + exit(-1); + + } + + fd = open(argv[1], O_RDWR); + + if(fd < 0) + + { + + perror("open failed."); + + exit(-2); + + } + + + + if((argc > 2) && !strcmp("-n", argv[2])) + + { + + noprompt = 1; + + } + + + + +/* get the current values */ + + if(ioctl(fd, ATIS_IOCGSPEED, &oldspeed) < 0) + + { + + perror("ioctl failed."); + + exit(-3); + + } + + +/* set up the existing values as defaults */ + + newspeed = oldspeed; + + +/* gather all new values from the command line */ + + +/* or via tty input.*/ + + if(argc == (noprompt + 3)) + + { + + newspeed = atoi(argv[count]); + + } + + + + fprintf(stderr, "speed [%ld/%ld]: ", oldspeed, newspeed); + + + + if(!noprompt) + + { + + if(count = read(0, buffer, 150), count <= 0) + + +{ + + + exit(0); + + +} + + buffer[count] = '\0'; + + if(buffer[0] != '\n') + + +{ + + + sscanf(buffer, "%ld", &newspeed); + + +} + + } + + else + + { + + fprintf(stderr, "\n"); + + } + + + + +/* This ioctl does the actual register load. */ + + if(ioctl(fd, ATIS_IOCSSPEED, &newspeed) < 0) + + { + + perror("ioctl failed."); + + exit(-3); + + } + + + + fflush(stdout); + +} + + + +The ATIS_IOCGSPEED gets the value the custom baud rate for a serial port +while ATIS_IOCSSPEED sets the value of the custom baud rate for a serial +port. + + + + + + + 8253xpeer + + + +The 8253xpeer example program reads and writes packets to the serial +port in synchronous mode. The synchronous character driver to some +extent emulates the getmsg/putmsg functionality found in Solaris. This +driver returns only one packet at a time to read and returns ENOMEM if +the receive buffer is not large enough to receive the current packet. +The driver assumes that the data from a write is to be packetized into a +single packet. The driver can provide asynchronous notification that +there is no more data queued to be transmitted at the serial port. This +asynchronous notification informs the application program that a low +priority packet can now be written to the driver. Such functionality is +useful to protocols like LAPB that distinguish low priority information +frames from high priority control frames. + + + +To try out this program find the major device number associated with the +8253xc device in the /proc/devices file. Select two ports to loop +together. Connect them with a synchronous loopback cable. Then execute +the following command for each of the ports. + + + +mknod /dev//DevName1/ c /major-dev-num minor-dev-num-1/ + +/ / + +mknod /dev//DevName2/ c /major-dev-num minor-dev-num-2/ + + + +Minor-dev-num-[1/2] correspond to the selected ports. + + + +Select one of the ports to be clocking (the clocking end of the loopback +cable should connect to this port) and apply MAKECLOCKING to the +corresponding TTY. Use stty or 8253xspeed and stty to set the speed on +the corresponding TTY port. + + + +Then in one window run *8253xpeer /dev//DevName1/* and in another window +execute *8253xpeer /dev//DevName2./* It should now be possible to send +and receive data in each of the windows. + + + +Here is the program source. + + + +/* + + * 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" + +#include + + + +struct pollfd pollarray[2]; + + + + + +char buffer[8192]; + + + +int main(int argc, char **argv) + +{ + + int fd; + + int status; + + int prompt = 1; + + int count; + + + + if(argc != 2) + + { + + fprintf(stderr, "Syntax: %s {portname}\n", *argv); + + exit(-1); + + } + + fd = open(argv[1], O_RDWR); + + if(fd < 0) + + { + + perror("open failed."); + + exit(-2); + + } + + do + + { + + if(prompt) + + { + + printf("Enter data: "); + + fflush(stdout); + + prompt = 0; + + } + + pollarray[0].fd = 0; + + pollarray[0].events = POLLIN; + + pollarray[0].revents = 0; + + pollarray[1].fd = fd; + + pollarray[1].events = POLLIN|POLLOUT; + + pollarray[1].revents = 0; + + status = poll(pollarray, 2, 10); + + switch(status) + + { + + case 0: + + break; + + + + case 1: + + case 2: + + if(pollarray[0].revents == POLLIN) + + { + + if(count = read(0, buffer, 150), count <= 0) + + { + + perror("unable to read stdio.\n"); + + exit(0); + + } + + buffer[count] = '\0'; + + if(count) + + { + + if(pollarray[1].revents & POLLOUT) + + { + + if(write(pollarray[1].fd, buffer, count) <= 0) + + { + + perror("unable to write protodevice.\n"); + + exit(-1); + + } + + } + + else + + { + + printf("Write of protodevice would block.\n"); + + fflush(stdout); + + } + + } + + prompt = 1; + + } + + if(pollarray[1].revents & POLLIN) + + { + + if(count = read(pollarray[1].fd, buffer, 8192), count <= 0) + + { + + perror("unable to read protodevice.\n"); + + exit(0); + + } + + buffer[count] = '\0'; + + printf("\nRead: %s", buffer); + + fflush(stdout); + + prompt = 1; + + } + + break; + + + + default: + + break; + + } + + } + + while(status >= 0); + +} + + + + + + + 8253xmode + + + +The 8253xmode program sets the signaling mode of port on a multichannel +server 3500 extension board which has a programmable Sipex sp502 +physical driver chip for each port. + + + +The command syntax is the following + + + +*8253xmode* /dev//{dev name} {mode}/ + + + +where mode is one of the following. + + * off + * 232 + * 422 + * 485 + * 530 + * v.35 + + + +Note the minor devices associated with a multiserver increase +monotonically starting from the first connector on the upper left corner +if you are facing the connector side of the multiserver. The numbering +goes from left to right and top to bottom without gaps Thus, the +numbers on the multiserver itself may not map to the minor device number +as port number + minor device number of first port if the multiserver is +not fully populated. + + + +Here is the source for the 8253xmode program. + + + +/* -*- 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); + +} + + + +The 8253xmode program uses the ATIS_IOCSSIGMODE ioctl to set the new +physical signaling mode and employs the ATIS_IOCGSIGMODE ioctl to get +the original value and to verify the new mode. + + + + + _Logic Structure of the ASLX Driver_ + + + + + /Data Structure Summary/ + + + +The key data structures that enable the driver logic are: + + + +1. SAB_BOARD structure ^Ö driver specific + +2. SAB_CHIP structure ^Ö driver specific + +3. SAB_PORT structure ^Ö driver specific + +4. AURA_CIM structure ^Ö driver specific (actually specific to the +multichannel server) + +5. RING_DESCRIPTOR ^Ö used by all the driver functionalities in the +transmission of data. + +6. DCONTROL2 ^Ö used by all the driver functionalities in managing +the transmission of data. + +7. struct sk_buff_head ^Ö two buffer lists are associated with the +SAB_PORT structure are used to track all the sk_buffs that are currently +in use at each port. + +8. struct tty_struct ^Ö one per port, standard structure by which +the TTY driver access low level routines for either asynchronous TTY, +synchronous TTY and callout functionality. The SAB_PORT serves as the +private data structure associated with each 8253x TTY, which on a given +open can instantiate itself as a synchronous TTY, an asynchronous TTY or +as a call out device. + +9. struct net_device ^Ö one per port, standard network device +structure. The SAB_PORT serves as the private data structure associated +with each 8253x network interface. + +10. struct file_operations ^Ö one per port, standard character device +structure. The SAB_PORT serves as the private data structure associated +with each 8253x character interface. + + + +Thus the fundamental driver functionalities, the TTY device, the network +interface and the character device, share the port structure; and the +port structure contains the data is used to arbitrate driver +functionality access to a given physical port. All the above driver +specific structures are dynamically allocated at driver initialization. +They are maintained on lists (in come cases several lists, e.g., global, +per board, by interrupt+by board type and per chip lists). The global +port list is used to map minor device numbers sequentially to ports. +The per chip port list is used in interrupt processing. Likewise the by +interrupt+by board type board lists are also used in interrupt processing. + + + +The use and definition of the tty_struct (TTY and callout drivers), +net_device (network drivers) and file_operations (character drivers) +structures are found in the Linux. + + + + + + Quick Overview of Standard Linux TTY, Network and Character Devices + and Interaction with the ASLX Driver Design + + + +The basic design of TTY/callout drivers, network drivers and character +drivers is specified by the Linux interface. + + + +The TTY driver uses the standard circular transmit buffer as found in +serial.c, which handles the PC com ports) while received characters pass +into a line disciple via the standard flip buffer logic found in serial.c + + + +The network and character driver parts just follow the design described +in /Linux Device Drivers/ by Alessandro Rubini. + +All the driver functionalities use a circular transmit buffer descriptor +ring and sk_buffers for receiving and transmitting data. This uniform +approach to transception simplifies the driver logic immensely. + + + +There is no use of a transmit done interrupt equivalent (unnecessary for +a non-dma design). The driver can be compiled to free up transmitted +sk_buffs in the interrupt handler or in write routines. Investigation +shows that the driver performs better when transmitted buffers are freed +outside of the interrupt handlers. The sk_* routines are in general +fairly performance costly. As a further optimization, when sk_buffs are +freed in the write routines, if system write gets ahead of the +transmitter, the program logic will try to avoid releasing transmitted +buffers (in the TTY driver) but will try to reuse them if possible. + + + +When data is received, chains of receive buffers are passed back to the +character device read routine or to a flush-to-line-discipline function +(defined in the ASLX driver to override the default flush_to_ldisc +routine defined in tty_io.c) in the case of the TTY driver +functionalities. The network driver just invokes the /netif_rx()/ +routine at interrupt level to receive packets. Currently, the network +driver pre-allocates a receive buffer, but such pre-allocation is not +necessary, and no other driver functionalities make use of +pre-allocation of buffers. + + + From Standard Driver Architectures to the ASLX Driver + + + +The main difficulties to be overcome in the ASLX design fit into two +categories. + + + +1. No other Linux driver attempts to combine multiple TTY +functionalities with network and character driver functionalities. + +2. Even though the members of this Aurora product line all use +basically the same Siemens/Infineon interface chip, the details of +accessing this chip differ radically over the product line. The adapter +cards use the PLX 9050 PCI bridge chip while the multichannel servers +use the AMCC 5920 PCI bridge chip. In the latter case there is a +somewhat complex G-Link hardware protocol used for communication between +the host adapter card and the expansion chassis that hosts the extension +boards where the serial interface chips are located. The adapter cards +differ in detecting and causing modem signal changes. + + + + + /Creating a Uniform Device Programming Interface/ + + + +The most painful aspect of of creating a multifunction driver for the +Aurora hardware is the difference of each Aurora adapter card or unit +from every other Aurora adapter card or unit. + + + +Signals are handled differently on ESCC2 (SAB82532) versus ESCC8 +(SAB82538) based devices. Interrupt processing is different on ESCC2, +ESCC8 and multichannel server devices. The multichannel servers use an +AMCC bridge chip while the other devices use a PLX bridge chip. +Multichannel servers and all other Aurora adapter cards access device +registers completely differently. + + + +There are a set of data structures and macros that simplify access to +control registers for serial ports and that try to provide uniformity in +line control signal handling, which is complex because some signals are +defined in the serial port interface of the 8253X serial interface chip +while other signals are handled through the general parallel ports of +the 8253X chip. + + + +The bitwise definition of the line control signals differ on the +parallel ports of the 82532 and the 82538 based cards (including +multichannel server units). + + + +The macros (courtesy Francois Wautier) below provide a common interface +for raising and lowering control signals as well as for querying them. + + + + +/* + + * 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)) + + + +The inverted, cnst, and mask fields of the modem signal structure (y) +are specific to the type of serial communications controller. The +readbyte and writebyte functions are specific to the different types of +Aurora hardware. + + + +To hide the details of accessing control and data registers, the +SAB_PORT structure has a fields whose values are the functions to read a +device register, to write a device register,to read a device FIFO and +to write a device FIFO (as well as to read and to write short words, +functions that could be used in implementing the readfifo and writefifo +routines). + + + +Here is readfifo for non-multichannel server hardware. + + + +/*************************************************************************** + + * 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 + + ***************************************************************************/ + +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)); + + } + +} + + + +Here is the readfifo function for multichannel servers. + + + +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 */ + +} + + + + +Except at initialization time the driver code accesses serial +communications controller device registers only through fields in the +port structure. The details of accessing the different types of +hardware are almost completely hidden from the driver program logic. + + + +The only exception is the interrupt handler, which must understand some +of the details of the multichannel server. Nevertheless, as is made +clear in the following section, from the standpoint of processing +interrupts there are really only two types of Aurora hardware, that +which is ESCC2 based and that which is ESCC8 based. The details of the +difference of the two types of hardware is contained solely within the +8253xint.c file which also contains the logic by which an interrupt from +a multichannel server can be processed almost exactly like an interrupt +from an 8520P adapter card. + + + + + /Code Structure Summary/ + + + + + + The SAB8253X driver code has the following logic components + + + +1. a probe/initialization logic, + +a. bridge initialization/EEPROM parsing logic, + +b. structure allocation logic, + +c. interrupt request logic, + +2. the core logic, which handles all the non-interrupt processing +of the driver functionality, + +a. per port startup/shutdown logic, + +b. driver arbitration logic, + +c. skbuffer management logic, + +3. the interrupt handler logic, + +a. common interrupt port polling logic, + +b. skbuffer management logic, + +4. the termination/driver unload logic, + +a. interrupt shutdown logic, + +b. device shutdown logic, + +c. structure deallocation logic. + + + + + +/Probe/Initialization Logic/ + + + +The probe/initialization logic sets up the CRC structures for the +network driver and then the tty_struct for the synchronous and +asynchronous TTY drivers. Initializing the tty_struct involves setting +up pointers to the standard functions that the Linux TTY driver invokes +as well as some standard data and the /proc/tty/driver/auraserial +function and data. + + + + +The probe/initialization logic identifies all the multiport serial +adapters, compact PCI adapters and multiserver adapters in the system +and puts them on a list of board structures. After identifying all the +boards, initializing the bridge chips and analyzing (possibly rewriting) +the serial EEPROM, the logic sets up all the chips on the boards and all +the ports on the chips. + + + +All chips are linked together in a list. All ports are linked together +in a list. The port list is linked together so that minor device N +corresponds to the Nth element of the port list. A board structure +points to a list of chips on the board as well as a list of all ports on +the board. Likewise a chip structure points to a list of all ports on +the chip. Chip structures point back to the board structure associated +with the board on which the chip resides. Likewise port structures +point back to the board and to the chip on which they reside. This +interconnected list structure facilitates access to one type of +structure when a routine has been passed a pointer to another type of +structure. All these structures are dynamically allocated via +/kmalloc()/. When the driver is unloaded, memory is released by walking +the list. + + + +After setting up the board, chip and port structures, initialization of +the tty_struct is completed at this point because the maximum possible +number of serial TTYs is now known. The, the standard network device +structure that is associated with each port is allocated and +initialized. The network devices point to the associated port +structure. The network devices are chained via a pointer in the +associated port structure. This chaining facilitates release of the +network device structure memory when the driver is unloaded. + + + +Each network device is registered after its network device structure is +initialized. Network device initialization invokes the network device +initialization, which installs the standard network functions in the +network device structure and which sets up the sk_buff transmit ring as +well as the receive sk_buf. Unlike the Solaris driver, when a complete +frame is received with no errors, it is immediately passed into the +network layer. Thus, there is no receive ring of sk_buffs as one might +find in the driver of a device that could carry out chained DMA (e.g. a +DEC Tulip or an Hitachi SCA). + + + +All sk_buffs associated with a network device that are currently in use +by the network driver are linked together in an sk_buff list (viz core +logic). This list facilitates release of all sk_buff associated with a +network device when that network device is shut down. This list may be +a problem if it becomes possible for a single sk_buff to be used +simultaneously by multiple network devices. Currently, sk_buff headers +are not shared among network devices although sk_buff data can be +shared. Thus, for the nonce this logic works correctly. + + + +After completing of network device initialization, the +probe/initialization logic register the character driver. Next, the +probe/initialization creates three lists of boards for each interrupt +(0-31). One list contains 82532 based boards at that interrupt level. +The next list contains 82538 based adapter cards at that interrupt +level. The third list contains all multichannel server units at that +interrupt level. + + + +Next the probe/initialization logic checks the lists associated with +each interrupt level. If either list is non-null, the +probe/initialization logic requests that the general interrupt handler +be installed at this interrupt level and then it turns on PLX9050 or +AMCC5920 interrupts (as needed) into the Linux host for each card +associated with that interrupt level. Thus, the interrupt handler polls +all boards/ports at a given interrupt level when the interrupt occurs. +This approach is more efficient that installing one interrupt per board +and avoids some internal Linux limits on the number of interrupt +handlers that can be installed per interrupt. + + + +At this point probe/intialization is complete and any serial port may be +used for asynchronous TTY, synchronous TTY, call out, network device +service or synchronous character device service. + + + + +/Core Logic/ + + + +The main problem of the core logic is arbitration of access to the +serial port, when and by which part of the driver a port is started and +when the port is shut down. + + + +The asynchronous callout, asynchronous TTY, synchronous TTY devices, +synchronous character device and network device follow the following rules. + + + +1. If there is an established point-to-point +connection, only the current process or process group that owns the +serial port may open the device. + +2. If the asynchronous callout is open, opens of a +single TTY or character device type block until the connection completes. + +3. Network device opens never block, and the network +layer opens a network device only once. + +4. If a connection that belongs to a TTY device or +character device hangs up, eventually all opens of that device will close. + +5. Hangup of on a network device does not guarantee a +close of the device, but a flag bit is set that permits a call out open +to restore the connection (note that a one-to-one map of TTY devices, +callout devices, character devices and network devices is implied.) + + + +The network device open and block_til_ready* functions invoked from TTY +opens enforce this arbitration. + + + +The logic works as follows: + + + + * The cua device associated with a port may only be opened one. + * If a TTY or character device is open, the cua device may not be + opened. + * If the cua device is open, the network device cannot be opened and + the TTY or character device block (multiple opens from the same + process or process group are allowed). + * If the network device is open, the TTY or character devices cannot + be opened while the cua device blocks. + * A hangup sends an interrupt to the TTY or character device while + the network device shuts down its port and a (network blocked) cua + device proceeds. + * On the close of the cua device, blocked TTY and character devices + proceed and the network device restarts its port. + + + +When an open completes, the transmit_chars, receive_chars, check_status +functions and associated data fields are set in the port structure, +these are used in the interrupt handler that never changes until the +driver is unloaded. + + + +When a port is not in use, the asynchronous version of these fields and +functions are set in the port structure. Some values must be present, +and the asynchronous ones are probably the least dangerous. + + + +Besides the arbitration problem, the core logic addresses buffer +management for the network and character drivers. + + + +The network layer passes a transmit sk_buff to the network driver. The +buffer is inserted in the transmit ring or sets a transmit congestion +flag. In either case, transmit is initialized if not already in +progress. If the sk_buff is successfully inserted, it is also linked +into the driver sk_buff list which tracks all sk_buffs used by the +network driver. On network device close all sk_buffs on the per port +sk_buff list are released. This sk_buff list mechanism is used to avoid +memory leaks. + + + +The TTY and character drivers packetize write data in an sk_buff (each +write creates a single sk_buff) and inserts it in the transmit ring if +possible or blocks (returns a failure in the case of TTY drivers). +Transmit sk_buffs are also linked into the driver sk_buff list. This +list is a convenience to assist deallocation during driver close. + + + +The TTY and character drivers also maintains a receive sk_buff list. +When the user application invokes the read system call, the data from +one sk_buff is passed up to the user application (or an error if the +read were not invoked with sufficient buffer space). + + + +The character driver can be configured via IOCTL to send asynchronous +user notification when the transmit ring empties (a design choice for +the standard driver fasync functionality). This character driver design +emulates the Solaris putmsg/getmsg interface as far as possible and +makes it possible to implement in a user application protocols like +LAPB, which require that low priority packets only be queued to the +driver when the driver currently has no frames in the process of +transmission or queued for transmission. + + + +On character device close all sk_buffs on the per port sk_buff and per +port receive sk_buff list are released. This double sk_buff list +mechanism is used to avoid memory leaks. + + + +/Interrupt Handler Logic/ + + + + + The following code comprises the combined interrupt and board/port + polling logic. The actual handler is /sab8253x_interrupt()/. It + walks through the 82532, adapter 82538 adapter and multichannel + server lists at the interrupt level that is being processed and + invokes inline /sab82532_interrupt()/ and /sab82538_interrupt()/. + Note that it temporary modifies multichannel server lists so that + it like an 8520P adapter card to the /sab8253x_interrupt()/. This + logic works because the granularity of the PCI interrupt + associated with the Aurora hardware is basically either a list of + ESCC2s (the 4520P and 4520CP adapter cards) or a single ESCC8 (an + 8520P or one ESCC8 on a multichannel server remote card after the + interrupt status has been queried). + + + + + + The current interrupt sources are identified and processed. If + any characters are available to be received, they are received one + fifo at a time into the TTY flip buffer (a structure that is + supposed to decrease TTY latency) or into an sk_buf (something + like a Solaris mblk/dblk structure( in the case of the network or + character driver. Then if there are characters in the TTY + circular transmit buffer or in the network or character driver + sk_buff, they are loaded into the transmit fifo, one fifo at a + time. Finally, modem control status is checked. If a hang up is + detected, the serial driver hang up is scheduled at kernel + scheduler priority (a slight difference from the standard serial + driver which processes hang-ups at interrupt level) in order to + avoid certain race conditions in the TTY driver that can occur on + fast machines with many serial ports. /do_serial_hangup()/ + invokes the TTY hangup routines in the case of TTY driver. For a + network connection in the event of a line disconnection, carrier + is marked as off on the interface and the blocked cua device is + woken so that it can proceed after the network port has shut down. + + + +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); + + } + + } + + } + +} + + + +/* + + * 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; + + } + + } + + } + +} + + + +Note that if there is no transmit in process when the +write/hard_start_transmit routine is invoked, transmit is intitiated +from the core logic as if it took place in the interrupt handler. This +approach differs from the ASE driver, which used to force an interrupt, +and then start the transmission. Francois Wautier may have fixed that +logic to start the transmission either in the STREAMS put or service +routine. + + + +/Driver Unload Logic/ + + + +The driver unload logic inverts the probe intialization logic. + + + +At this point no ports should be in use and in fact every port should +have been put in the 8253x powered down state when each port underwent +its last close (or hangup which can actually complete after a close). + + + +The tty driver is cleaned up, some dynamic TTY data structures are +deallocated, the bottom half associated with this driver is removed and +all TTY ports are deregistered. + + + +The PLX or AMCC interrupts to the Linux host are disabled on each board, +and all interrupt handlers are freed. + + + +Next all board and chip structures are deallocated (including physical +memory to virtual memory mappings associated with PLX9050 or AMCC 5920 +and chip registers). Then all network device structures are +deallocated. (Note that all lingering sk_buffs were freed during the +close of the network device, which must have completed before the unload +of the driver module.) And finally the port structures are +deallocated. In deallocating the port structures, network driver +transmit rings and the receive sk_buff descriptor are deallocated if +they are present. (They were only allocated if the port had ever been +used for a network device.) At this point the driver has been +gracefully unloaded. + + + + /* cleanup module/free up virtual memory */ + + /* space*/ + +void cleanup_module(void) + +{ + + SAB_BOARD *boardptr; + + SAB_CHIP *chipptr; + + SAB_PORT *portptr; + + int intr_val; + + extern void sab8253x_cleanup_ttydriver(void); + + + + printk(KERN_ALERT "auraXX50n: unloading AURAXX50 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)) + + { + + 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)); + + } + + + + 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->virtbaseaddress0) + + { + + DEBUGPRINT((KERN_ALERT + + "auraXX50n: unmapping virtual address %p.\n", + + (void*)boardptr->virtbaseaddress0)); + + iounmap((void*)boardptr->virtbaseaddress0); + + boardptr->virtbaseaddress0 = 0; + + } + + if(boardptr->virtbaseaddress2) + + { + + DEBUGPRINT((KERN_ALERT + + "auraXX50n: unmapping virtual address %p.\n", + + (void*)boardptr->virtbaseaddress2)); + + iounmap((void*)boardptr->virtbaseaddress2); + + boardptr->virtbaseaddress2 = 0; + + } + + kfree(boardptr); + + } + + + + while(AuraChipRoot) /* free chip memory */ + + { + + chipptr = AuraChipRoot; + + AuraChipRoot = chipptr->next; + + kfree(chipptr); + + } + + + + 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); + + } + +} + + + +_Design Summary_ + + + +The 10 key data structures are shared by all the logic of the system. +The logic enforces both exclusive and cooperative access to the physical +hardware on the basis of certain rules established by the core logic at +device/port open time. While the driver is mostly self-configuring, the +data structure sharing simplifies the user interface because an ioctl to +one driver functionality (e.g., the TTY functionality) configures the +rest of the driver functionality (e.g., the network and character device +functionality). In other words, a single serial port acts virtually as +three arbitrated devices: a TTY device, which may be asynchronous, +synchronous or call out, a network device or a character device. Yet, +except at the time of initialization, time of driver unload and very +early in interrupt processing all hardware details are concealed and the +driver logic is applied to an abstract, simplified port entity. Thus, +the user application interfaces to three abstract virtual devices, which +have a single configuration interface (otherwise it might be possible to +have an inconsistent configuration) and not to a complex real single +port in the context of an equally complex adapter card or unit. This +simplification makes it possible to provide a high degree of serial +functionality across the family of Aurora synchronous/asynchronous PCI +hardware through a straightforward uniform application interface. + + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/sab8253xfs.txt linux-2.5/drivers/net/wan/8253x/sab8253xfs.txt --- linux-2.5.13/drivers/net/wan/8253x/sab8253xfs.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/sab8253xfs.txt Fri May 3 03:49:07 2002 @@ -0,0 +1,1303 @@ +*_Functional Specification of SAB8253X ASLX Driver for Linux_* + + + + +The SAB8253X serial interface chip is very flexible. It supports most +of the standard asynchronous serial transmission modes as well as +synchronous Bit Oriented Protocols (BOPs) and character oriented +protocols. The Linux ASLX Driver system provides an extremely flexible +Linux interface to the SAB8253X serial interface chips that are used on +the Aurora XX20 adapter cards and +Multichannel server units whether they are inserted directly into a host +bus or whether they are connected via a PCI extension system such as the +Aurora XP7. + + + + + Supported Hardware + + + +The Linux ASLX Driver supports Aurora SAB8253X communications adapter +cards and systems for PCI bus systems. Possible adapter card +configurations are identified as MN20 where M is 1, 2, 4, 8 and N is 0 +or 5. M is the number of ports. N = 0 means that the adapter card does +not support synchronous modes. N = 5 means the adapter card modes are +unrestricted. The multichannel server system consists of an host +adapter card that attaches to an expansion box via the G-Link connection +cable. The expansion box can host 2000, 2500 and 3500 type Expansion +Boards (EBs). The 2000 EB provides 15 asynchronous-only RS-232 ports +and 1 unrestricted RS-232 port. The 2500 EB provides 16 unrestricted +RS-232 ports. The 3500 EB provides 16 unrestricted serial ports, whose +physical signaling is under software control. The XP7 is a PCI +expansion chassis. + + + +The ASLX correctly identifies the Aurora adapter card or Multichannel +server and EBs, determines capabilities and provides a software +interface to configurable capabilities (e.g., a choice of RS-232 [= the +default], RS 422/423, RS 449, EIA 530, V.35, X.21, RS-485 and none +[=off] signaling for 3500 EBs). The use of an XP7 should be transparent +to the driver. The ASLX driver will automatically correct incorrectly +programmed adapter card or Multichannel server serial EEPROMs. +Moreover, in addition to the primary serial communications interface, +the ASLX driver provides a ^Ómaintenance^Ô interface to the serial EEPROMs +so that user intervention can correct an incorrectly programmed EEPROM. + + + + + Serial Communications Interface + + + +The ASLX driver conforms to the standard Linux driver formalism for TTY +devices, network devices and character devices. + + + +The ASLX Linux driver can like all standard Linux drivers either be +linked into the kernel or be built as a downloadable module that can +also be cleanly deloaded. + + + +The ASLX Linux driver functionality provides more than the usual serial +device driver functionality because it provides the TTY device, network +device and character device functionality in one package. Moreover, the +ASLX Linux driver TTY functionality supports asynchronous TTY devices, +asynchronous CUA devices and synchronous TTY devices. The CUA devices +can also be used in conjunction with the network device and synchronous +character device functionalities for the purpose of dynamically setting +up a dialed link via a modem device. + + + +The ASLX Linux driver has been developed for Linux on i386 hardware, but +it has no specific i386 dependence and after recompilation should be +able to run with Linux that has been compiled for other hardware. + + + +The driver is structured to minimize Linux 2.4.*-isms. While it has not +been built as a Linux 2.2.* driver, rebuilding it to work under Linux +2.2.* should not be too difficult. + + + + + Driver Initialization + + + +Drivers for physical devices usually must provide device detection and +device initialization. + + + +The initialization or probe routines of the driver detect all the Aurora +SAB8253X devices in the system (i.e., these routines look for PCI +devices that have Aurora device and manufacturer IDs) and carry out any +necessary low-level PCI initialization of the PLX9050 (XX20 adapter +cards) or AMCC5920 bridge device (Multichannel server host card). + + + +The initialization routines of the ASLX driver dynamically allocate all +structures. The number of Aurora adapter cards in a given system is +solely limited by the amount of dynamically allocatable kernel memory. + + + +Note that the performance of a system will be dependent on the number of +active SAB8253X ports, port modes and speeds, the speed of the CPU, the +number of CPUs, memory design and similar hardware related considerations. + + + +This driver currently does not initialize serial adapter cards of +similar design but with different device or manufacturer IDs, but users +will be able to access all the functionality described in this document +for serial ports on SAB8253X based Aurora adapter cards. + + + +Extending the initialization to the intrinsic SAB8253X ports of SPARC +hardware or to similar adapter cards of other manufacturers would not be +difficult. + + + +Note that the intrinsic SAB8253X ports of the SPARC hardware can serve +as boot serial consoles because they do not depend on PCI initialization +as the Aurora adapter cards and multichannel units do. Currently, the +Aurora ASLX driver does not support boot console or serial console +functionality, but extending the driver to provide such functionality +would not be difficult. + + + +Note further the ASLX driver is designed (viz the Design Specification +of SAB8253X ASLX Driver for Linux) for hardware that utilizes none of +the DMA capabilities of SAB8253X extended serial interface controllers. +Because the ASLX driver transmits data from sk_buffs and receives data +into sk_buffs extending the driver to support SAB8253X based adapter +cards that support DMA would not be particularly difficult.. + + + +In addition, the Zilog 85X30, Intel 8X530 and the AMD 85X30 serial +communication controllers are character oriented devices that could +easily be supported within the logic of the ASLX driver. These devices +do not have the same sort of visible FIFO that the SAB8253X devices +have, but a FIFO operation looks like a sequence of operations to an +output or an input register on a device that does not have a visible FIFO. + + + + + The Communications Port + + + +From the standpoint of the Linux operating system, after initialization, +the device that the operating system accesses is neither the Aurora +adapter card or Multichannel server nor the SAB8253X chip but is the +individual communications port of a SAB8253X chip. Thus a SAB82532 is +logically two devices, a SAB82538 is logically 8 devices, an Aurora 4520 +logically provides 4 devices, and an Aurora Multichannel server can +logically provide up to 64 serial communications devices. + + + +Each communications port according to board capabilities and device +configuration can provide asynchronous communications or synchronous +communications as well as access to modem signal status. On a given +port synchronous communications can either be bit-oriented or +character-oriented. Currently, the driver only supports bit-oriented +HDLC flag-framing and bit-stuffing, but the driver source can be easily +modified to support BSC character-oriented synchronous communications. + + + +There are two obvious possible ways to extend the driver to support BSC +communications. Either a configuration flag could be added to indicate +that the synchronous TTY, network and character devices were running in +BSC mode and not in BOP mode, or new BSC specific TTY, network and +character devices could be created. The latter approach would probably +minimize potential user confusion and errors of connecting BSC ports to +BOP configured lines and vice-versa. + + + +/Asynchronous Serial Communications Initialization for a Specific Port/ + + + +After probing for the hardware, the driver registers the asynchronous +device dependent routines, whose addresses are values of elements of +/struct tty_driver/ variables with the device independent TTY driver by +means of the /tty_register_driver()/ function. + + + +These functions handle the device dependent aspects of opening a TTY +port (i.e., completing initialization in asynchronous mode), closing a +physical TTY port, writing an array of characters to a physical TTY +port, putting a single character to a physical TTY port, flushing the +characters in the process of being written to a single TTY port, +determining how much buffer space is currently available to a single +physical TTY port, determining how many characters are in the buffer +space associated with a single physical TTY port, carrying out the +device dependent aspects of IOCTLs invoked by a user application, +carrying out flow control at the physical port, carrying out the device +dependent aspects of setting TERMIOs, handling asynchronous break, and +waiting for a physical TTY port to transmit all characters associated +with the port. Other elements of the /struct_tty_driver/ are +initialized with information used for proc files and other TTY driver +functionality. + + + +/Asynchronous Serial Communications Functionality/ + + + +The driver supports the standard Linux asynchronous TTY and call out +functionality, which includes all standard STTY and TERMIO IOCTLs, all +the standard speeds, all the standard flow control formalisms, etc., +that can be found in the Linux STTY and TERMIO manual pages. + + + +Note that custom IOCTLs have been added to support the configuration of +signaling on the WAN multichannel server 3500 cards. + + + +In addition, customized IOCTLs have been added to support reading and +programming the serial EEPROM associated with the various Aurora adapter +cards and units. These are of limited use for users but are helpful in +debugging cards. Changing the manufacturer or device IDs can render an +adapter card or unit unusable. + + + +The asynchronous TTY and call out functionality obey the standard Linux +block_til_ready logic than enforces arbitration between call out and +asynchronous TTY access. Current Linux design documents deprecate the +separate asynchronous call out functionality, but it is not particularly +obvious how to provide asynchronous call out functionality to set up +synchronous point-to-point links dynamically without the separate call +out devices. + + + +To wit, ckermit does not use the cua devices. The ckermit user sets a +tty line, turns off carrier watch, executes the connect command, dials +out and then continues with his terminal session using the same tty +device on which he dialed out after the modems connect. This procedure +would not work if the point-to-point connection were to be synchronous +(or in fact if the point-to-point session were to carry X.25 traffic for +a PAD session). The cua devices are useful to deal with such /mixed +mode/ dynamically connected sessions. + + + +Note that in the past Linux has required that TTY devices be named +/dev/ttyS* and that call out devices be named /dev/cua*. The devices +can still be so named, but this naming convention is not obligatory. + + + +The asynchronous TTY devices use major device 4 and the call out device +uses major device 5. This assignment is a convention and can be changed +if necessary. + + + +Ports are selected by the minor device number. Port minor device +numbers increase strictly monotonically in accord with the numbering +convention of the adapter card or adapter unit.[1] <#_ftn1> + + + +The file /proc/tty/driver/auraserial that is created by the ASLX driver +helps in mapping port to minor device number. The call out device and +TTY device of a single port have the same minor device number. To +calculate the port number of an asynchronous TTY device or of a call out +device, subtract the minor device number of the first ASLX port from the +minor device number of the TTY or CUA device of interest. + + + +/Synchronous Serial TTY Communications Initialization for a Specific Port/ + + + +After probing for the hardware, the driver registers the synchronous +device dependent routines, whose addresses are values of elements of +/struct_tty_driver/ variables with the device independent TTY driver by +means of the /tty_register_driver()/ function. + + + +Just as in the case of asynchronous TTYs, these functions handle the +device dependent aspects of opening a TTY port (i.e., completing +initialization in synchronous mode), closing a physical TTY port, +writing an array of characters to a physical TTY port, putting a single +character to a physical TTY port, flushing the characters in the process +of being written to a single TTY port, determining how much buffer space +is currently available to a single physical TTY port, determining how +many characters are in the buffer space associated with a single +physical TTY port, carrying out the device dependent aspects of IOCTLs +invoked by a user application, carrying out flow control at the physical +port, carrying out the device dependent aspects of setting TERMIOs, and +waiting for a physical TTY port to transmit all characters associated +with the port. Other elements of the /struct tty_driver/ are +initialized with information used for proc files and other TTY driver +functionality. + + + + + + Synchronous Serial TTY Communications Functionality + + + +By default synchronous serial TTY communications takes place on devices +named /dev/sttyS*, but such names are not required. The major device +number associated with these ports is dynamically allocated and can be +found in the /proc/tty/driver/auraserial file. + + + +Synchronous TTYs act just like asynchronous TTYs (e.g., getty^Òs may be +associated with them, and a user may invoke cu on them) in so far as +possible (to wit, break processing is not possible on a synchronous TTY). + + + +As one cannot generally purchase synchronous TTY hardware, synchronous +TTYs are probably most useful in porting a synchronous TTY application +from another type of Unix that made use of line disciplines in some +legacy application. + + + +Note that the synchronous TTY driver logic obeys the block_til_ready +arbitration logic so that asynchronous call out devices can be used to +set up point-to-point synchronous TTY links. + + + +The synchronous TTY devices support all the standard STTY and TERMIO +IOCTLs as well as the custom IOCTLs that are described in the previous +section. Because these IOCTLs do not deal with the issue of synchronous +clock mode, IOCTLs for setting custom bit rates as well as for +programming and reading synchronous clock modes are provided. These +IOCTLs are also accessible through the asynchronous TTY and call out +devices. Configuring a port to provide clock only affects the port when +it is used as a synchronous device. + + + +The minor device number associated with a specific port is the same +whether it is used as a synchronous TTY, an asynchronous TTY or a call +out device. To calculate the port number of a synchronous TTY device, +subtract the minor device number of the first ASLX port from the minor +device number of the TTY device of interest. + + + + + Synchronous Serial Network Device Initialization + + + + +The synchronous network device functionality is to some extent an +extension of the synchronous TTY functionality. + + + +After probing for the SAB8253X hardware, the software in addition to +invoking /tty_register_driver()/ also invokes /register_netdev()/ for +each SAB8253X port. This registration makes it possible to connect +SAB8253X ports into the Linux network layer via ifconfig commands like +the following, which opens the device. + + + +*ifconfig 8253x001 */{network address or host name}/ + +*ifconfig 8253x001* *hw ether* /{MAC address}/ + + + +Note that by default the number part of the network device name +corresponds to the serial port number (i.e., the minor device number of +the associated serial port minus the value of an internal kernel +variable called sab8253x_minor_start [equal to the minor device number +of the first TTY device listed in the /proc/tty/driver/auraserial +file]). The module parameter, sab8253x_minor_start, identifies the +minor device number at which Aurora asynchronous TTY, synchronous TTY +and call out devices start. + + + +The network driver dynamically allocates memory specifically for its use +as needed on network device open and frees up network device driver +memory on network device close. + + + + + Synchronous Serial Network Devices + + + +The network devices like all standard Linux network devices are not +visible in the /dev directory. + + + +If an 8 port adapter card is installed in a Linux system that has an +Ethernet port, the new SAB8253X Linux driver makes it possible to use +the system as an 8 WAN x 1 LAN port router. + + + +The SAB8253X network device functionality emulates an Ethernet device. +The network device functionality requires the implementation of the +following functions. As a consequence, the network portion of the ASLX +driver implements the standard Ethernet functionality as far as +possible. In addition, the network driver requires a special IOCTL to +set a pseudomac address. + + + +In addition, the network driver needs some functionality that goes +beyond the standard Ethernet functionality, for it must be possible +dynamically to establish or reestablish synchronous links by means of +the asynchronous call out device logic. + + + +Using the call out device logic in conjunction with the network device +requires an extension of the call out device arbitration logic. + + + +The standard call out device arbitration logic requires that the call +out device start first and be invoked from the same process or process +group that opens the TTY device while the TTY device blocks until the +call out succeeds. Such logic is inapplicable to the network device. +The call out device must be opened while the corresponding network +device is open. The corresponding network device never blocks but +informs the network layer of outgoing network congestion. + + + + + + + Synchronous Serial Character Device Initialization + + + + +The synchronous character device functionality is to some extent an +extension of the synchronous network functionality. + + + +After probing for the SAB8253X hardware, the software besides invoking +/tty_register_driver()/ also invokes /register_chardev()/ in addition to +/register_netdev()/ for each SAB8253X port. This registration makes it +possible to access SAB8253X port packet functionality independently of +the Linux network layer via function calls associated with a standard +character device. + + + +The major device number of the synchronous serial character device can +be found in the /proc/devices file. Note that by default the minor +device number of each synchronous serial character device file (e.g., +/dev/sab8253xC* if mknod is invoked as below) corresponds to the minor +device number of the associated serial port minus the value of an +internal kernel variable/module parameter called sab8253x_minor_start +(equal to the minor device number of the first TTY device indentified in +the /proc/tty/driver/auraserial file). The variable +sab8253x_minor_start identifies the minor device number at which Aurora +asynchronous TTY, synchronous TTY and call out devices start. + + + +*mknod /dev/sab8253xC*{number} *c* {major dev number} {minor dev number} + + + +The character driver dynamically allocates memory specifically for its +use as needed on network device open and frees up network device driver +memory on network device close. + + + +/Synchronous Serial Character Device/ + +/ +/ + +/ / + + + +The SAB8253X synchronous character device functionality implements +essentially the same functions as the SAB8253X synchronous network +device functionality with the addition of a read/receive function that +will pass received data packets to a user application and with the +addition of an fasync helper function if the driver is to support +asynchronous notification to the user application. This functionality +is provided so that users that wish to implement their own bit oriented +synchronous protocols may directly access the serial data stream without +having to work around the TTY driver or the Linux network layer. + + + +Note that while the network device is only opened once by the Linux +network layer, the character device may be opened multiple times by a +process or defined process group just like the TTY driver. + + + +In a sense, the synchronous character device implements an emulation of +Solaris putmsg/getmsg functionality for Aurora^Òs synchronous serial +device. The availability of such emulation should help the portation of +applications from Solaris to a Linux platform that uses Aurora hardware +and software. + + + +The asynchronous functionality is useful for those protocols like LAPB, +which do not work well if the physical driver buffers up low priority +packets while other packets are being transmitted. The asynchronous +notification can provide notification that there are no packets of any +sort in the process of being transmitted and that there are no high +priority packets buffered within the driver. On receiving this +notification, the user application could transmit the next low priority +packet. + + + +Note that the synchronous serial character device interacts with the +call out device almost exactly like the TTY devices. + + + +In the interest of keeping the interfaces simple and not introducing +extra foci for bugs, there are no IOCTLs implemented for this device. +If it is necessary to set a clocking mode or baud rate etc., the IOCTL +call is made via the STTY, TERMIO or extended IOCTLs associated with the +TTY driver functionalities. + + + + + Common Interrupt Handling Functionality + + + +All the above functionality shares a common interrupt handler that +invokes indirectly functionality-specific receive_chars, transmit_chars +and check_status functions to receive character data, to transmit +character data and to check signal status. + + + +In other words, the interrupt handler must support all possible +functionalities simultaneously on a group of ports associated with a +single interrupt simultaneously. + + + +Linux is not capable of registering an interrupt handler for each port +separately (when there are many ports ^Ö the specialty of Aurora +hardware), and such an approach would have lower performance than having +a single interrupt handler that polled the ports. In any case, +interrupt status registers associated with the Aurora hardware often +indicate interrupt status on several ports simultaneous. It is +preferable to read such registers once especially with the Multichannel +server hardware. + + + + + Proc Files + + + +The following traces show how the driver interacts with (or creates) +various /proc status files. + + + + +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). + + + + +martillo@ylith:/proc > cat /proc/pci + +PCI devices found: + + Bus 0, device 0, function 0: + + Host bridge: Intel Corporation 82820 820 (Camino) Chipset Host +Bridge (MCH) (rev 4). + + Prefetchable 32 bit memory at 0xf8000000 [0xfbffffff]. + + Bus 0, device 1, function 0: + + PCI bridge: Intel Corporation 82820 820 (Camino) Chipset PCI to AGP +Bridge (rev 4). + + Master Capable. Latency=64. Min Gnt=8. + + Bus 0, device 30, function 0: + + PCI bridge: Intel Corporation 82801AA PCI Bridge (rev 2). + + Master Capable. No bursts. Min Gnt=2. + + Bus 0, device 31, function 0: + + ISA bridge: Intel Corporation 82801AA ISA Bridge (LPC) (rev 2). + + Bus 0, device 31, function 1: + + IDE interface: Intel Corporation 82801AA IDE (rev 2). + + I/O at 0xffa0 [0xffaf]. + + Bus 0, device 31, function 2: + + USB Controller: Intel Corporation 82801AA USB (rev 2). + + IRQ 10. + + I/O at 0xef80 [0xef9f]. + + Bus 0, device 31, function 3: + + SMBus: Intel Corporation 82801AA SMBus (rev 2). + + IRQ 9. + + I/O at 0xefa0 [0xefaf]. + + Bus 1, device 0, function 0: + + VGA compatible controller: nVidia Corporation NV15 (Geforce2 GTS) +(rev 164). + + IRQ 11. + + Master Capable. Latency=64. Min Gnt=5.Max Lat=1. + + Non-prefetchable 32 bit memory at 0xfd000000 [0xfdffffff]. + + Prefetchable 32 bit memory at 0xe8000000 [0xefffffff]. + + Bus 2, device 8, function 0: + + Ethernet controller: 3Com Corporation 3c905C-TX [Fast Etherlink] +(rev 120). + + IRQ 11. + + Master Capable. Latency=64. Min Gnt=10.Max Lat=10. + + I/O at 0xdc00 [0xdc7f]. + + Non-prefetchable 32 bit memory at 0xfeacfc00 [0xfeacfc7f]. + + Bus 2, device 9, function 0: + + Unknown mass storage controller: Promise Technology, Inc. 20267 (rev 2). + + IRQ 9. + + Master Capable. Latency=64. + + I/O at 0xdff0 [0xdff7]. + + I/O at 0xdfe4 [0xdfe7]. + + I/O at 0xdfa8 [0xdfaf]. + + I/O at 0xdfe0 [0xdfe3]. + + I/O at 0xdf00 [0xdf3f]. + + Non-prefetchable 32 bit memory at 0xfeae0000 [0xfeafffff]. + + Bus 2, device 10, function 0: + + Communication controller: PCI device 125c:0101 (Aurora Technologies, +Inc.) (rev 1). + + IRQ 3. + + Non-prefetchable 32 bit memory at 0xfeacf800 [0xfeacf87f]. + + Non-prefetchable 32 bit memory at 0xfeacf400 [0xfeacf5ff]. + + Non-prefetchable 32 bit memory at 0xfeacf000 [0xfeacf1ff]. + + Bus 2, device 11, function 0: + + Communication controller: PCI device 125c:0101 (Aurora Technologies, +Inc.) (rev 1). + + IRQ 10. + + Non-prefetchable 32 bit memory at 0xfeacec00 [0xfeacec7f]. + + Non-prefetchable 32 bit memory at 0xfeace000 [0xfeace7ff]. + + Non-prefetchable 32 bit memory at 0xfeacd800 [0xfeacdfff]. + + + +The above file indications PCI resources that the Aurora adapter card or +unit uses. + + + + +martillo@ylith:/proc > cat /proc/devices + +Character devices: + + 1 mem + + 2 pty + + 3 ttyp + + 4 ttyS + + 5 cua + + 7 vcs + + 10 misc + + 14 sound + +128 ptm + +136 pts + +162 raw + +180 usb + +253 sab8253xc + +254 sttyS + + + +Block devices: + + 2 fd + + 22 ide1 + + 33 ide2 + + + +The above file provides the major device number associated with the +synchronous serial character device. + + + +martillo@ylith:/proc > cat /proc/modules + +ASLX 84336 5 (autoclean) + + + +The above file indicates that the ASLX module has been dynamically +linked into the kernel. If the ASLX is statically linked into the +kernel, it will not appear in this file. + + + +martillo@ylith:/proc > cat /proc/interrupts + + CPU0 + + 0: 25311 XT-PIC timer + + 1: 401 XT-PIC keyboard + + 2: 0 XT-PIC cascade + + 3: 22 XT-PIC sab8253x + + 9: 20055 XT-PIC ide2 + + 10: 27 XT-PIC usb-uhci, sab8253x + + 11: 38 XT-PIC eth0 + + 12: 2720 XT-PIC PS/2 Mouse + + 15: 7 XT-PIC ide1 + +NMI: 0 + +LOC: 0 + +ERR: 0 + +MIS: 0 + + + +The above file indicates the interrupts that are being used by Aurora +adapter cards. + + +martillo@ylith:/proc/net > cat /proc/net/dev + +Inter-| Receive | Transmit + + face |bytes packets errs drop fifo frame compressed +multicast|bytes packets errs drop fifo colls carrier compressed + + lo: 1080 16 0 0 0 0 0 0 +1080 16 0 0 0 0 0 0 + + eth0: 2316 19 0 0 0 0 0 0 + 1836 19 0 0 0 1 0 0 + +8253x000: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x001: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x002: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x003: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x004: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x005: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x006: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x007: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x008: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x009: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x010: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + +8253x011: 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 + + + +The above file provides statistics on ASLX network interfaces. + + + +martillo@ylith:/proc > cat /proc/iomem + +00000000-0009fbff : System RAM + +0009fc00-0009ffff : reserved + +000a0000-000bffff : Video RAM area + +000c0000-000c7fff : Video ROM + +000cc000-000cdfff : Extension ROM + +000ce000-000ce7ff : Extension ROM + +000f0000-000fffff : System ROM + +00100000-0ffbffff : System RAM + + 00100000-00260dfe : Kernel code + + 00260dff-002f325f : Kernel data + +0ffc0000-0fff7fff : ACPI Tables + +0fff8000-0fffffff : ACPI Non-volatile Storage + +e4600000-f46fffff : PCI Bus #01 + + e8000000-efffffff : nVidia Corporation NV15 (Geforce2 GTS) + +f4700000-f47fffff : PCI Bus #02 + +f8000000-fbffffff : Intel Corporation 82820 820 (Camino) Chipset Host +Bridge (MCH) + +fc900000-fe9fffff : PCI Bus #01 + + fd000000-fdffffff : nVidia Corporation NV15 (Geforce2 GTS) + +fea00000-feafffff : PCI Bus #02 + + feacd800-feacdfff : PCI device 125c:0101 (Aurora Technologies, Inc.) + + feace000-feace7ff : PCI device 125c:0101 (Aurora Technologies, Inc.) + + feacec00-feacec7f : PCI device 125c:0101 (Aurora Technologies, Inc.) + + feacf000-feacf1ff : PCI device 125c:0101 (Aurora Technologies, Inc.) + + feacf400-feacf5ff : PCI device 125c:0101 (Aurora Technologies, Inc.) + + feacf800-feacf87f : PCI device 125c:0101 (Aurora Technologies, Inc.) + + feacfc00-feacfc7f : 3Com Corporation 3c905C-TX [Fast Etherlink] + + feae0000-feafffff : Promise Technology, Inc. 20267 + +ffb80000-ffbfffff : reserved + +fff00000-ffffffff : reserved + + + +The above file indicate the I/O memory mapping of the Aurora devices. + + + + + ASLX IOCTL Summary + + + +The ASLX driver supports the standard TTY and Ethernet driver IOCTLs. +In addition, the following TTY driver IOCTLs are supported (on +asynchronous/synchronous TTY devices and on asynchronous CUA devices): + + + +/1. /set custom baud rate,// + +/2. /get baud rate,// + +/3. /read EEPROM,// + +/4. /set EEPROM,// + +/5. /get clocking mode,// + +/6. /set clocking mode// + +/7. /get WAN MCS signaling configuration,// + +/8. /set WAN MCS signaling configuration,// + +/9. /clear network driver statistics.// + + + +In addition, the ASLX driver supports a network IOCTL to clear interface +statistics. + + + +/Source Code Functionality/ + + + +To facilitate user modification and extension of the ASLX driver, the +code has been written as clearly as possible, and the various +functionalities (asynchronous TTY, synchronous TTY, network device and +character devices, initialization, interrupt, bridge initialization, +etc) have their own files to discourage massive unsupportable changes to +driver logic. + + + +/Summary/ + + + +The driver attempts to provide as much as possible of the functionality +of the SAB8253X communication controller and the Aurora hardware in a +form that is both useful and friendly to the Linux user with as much +self-configuration as possible and by means of the standard Linux +interfaces. The custom portion of the interface has been minimized as +much as possible, and duplication of this interface across the TTY, +network, and synchronous serial character interface has been eschewed. + + + +In this version of the driver for each type of custom configuration, +there is only one IOCTL, and this custom configuration is shared among +all the functionalities that share a given physical port. + + + +In most applications of this driver, the user will generally not have to +use any of the custom IOCTLs unless he is using a serial port as a +synchronous device that is providing clock, in which case he would have +to use an IOCTL to make the port provide clock and he might have to use +another IOCTL to set a custom baud rate. In all cases, if the network +driver is used on a given port, that port would have to be assigned a +pseudomac address by means of the standard ifconfig command. + + + +Altogether the driver provides the functionality needed for massive +asynchronous and synchronous TTY connectivity, for shake-and-bake WAN +networking and for synchronous legacy interconnect by means of a custom +application. Linux systems that host Aurora communications cards that +interface to the OS via the ASLX driver can replace a massive +point-of-sales servers, expensive WAN networking systems or custom +synchronous legacy protocol-to-standard protocol interconnect hardware. + + + + +------------------------------------------------------------------------ + +[1] <#_ftnref1> In the ASLX driver internal device lists, adapter cards +and adapter units are ordered in reverse order to the ordering on the +kernel PCI device list by type. Multiport adapter cards are ordered +last. Compact multiport adapter cards are ordered next. And +Multichannel units are ordered next, i.e., first. The ordering of +adapter cards and interface chips on internal driver lists currently +does not affect external functionality with one possible exception. +Adapter cards are also listed on per type per interrupt lists. If +there are many cards associated with a given interrupt, it is possible +that list order might cause maximum delay in loading and emptying port +FIFOs to be exceeded. As every card on the interrupt list must be +interrogated when an interrupt is received, avoiding the problem might +require moving to a faster processor based system. Multi-CPU hardware +would not help. + + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/8253x/sab8253xov.txt linux-2.5/drivers/net/wan/8253x/sab8253xov.txt --- linux-2.5.13/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.13/drivers/net/wan/8253x/sp502.h linux-2.5/drivers/net/wan/8253x/sp502.h --- linux-2.5.13/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.13/drivers/net/wan/Config.help linux-2.5/drivers/net/wan/Config.help --- linux-2.5.13/drivers/net/wan/Config.help Fri May 3 01:22: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.13/drivers/net/wan/Config.in linux-2.5/drivers/net/wan/Config.in --- linux-2.5.13/drivers/net/wan/Config.in Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/net/wan/Config.in Fri May 3 12:57:31 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.13/drivers/net/wan/Makefile linux-2.5/drivers/net/wan/Makefile --- linux-2.5.13/drivers/net/wan/Makefile Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/net/wan/Makefile Fri May 3 12:57:31 2002 @@ -56,6 +56,13 @@ ifeq ($(CONFIG_LANMEDIA),y) obj-y += lmc/lmc.o endif + +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 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/farsync.c linux-2.5/drivers/net/wan/farsync.c --- linux-2.5.13/drivers/net/wan/farsync.c Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/net/wan/farsync.c Tue Apr 16 02:29:32 2002 @@ -1469,10 +1469,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; @@ -1531,6 +1527,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 ); @@ -1570,12 +1573,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.13/drivers/net/wan/hd64572.h linux-2.5/drivers/net/wan/hd64572.h --- linux-2.5.13/drivers/net/wan/hd64572.h Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/net/wan/hd64572.h Fri May 3 18:33:49 2002 @@ -12,6 +12,9 @@ * 2 of the License, or (at your option) any later version. * * $Log: hd64572.h,v $ + * Revision 1.1 2002/05/03 17:33:49 davej + * Add new bits, kill old bits. + * * Revision 3.1 2001/06/15 12:41:10 regina * upping major version number * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/hdlc.c linux-2.5/drivers/net/wan/hdlc.c --- linux-2.5.13/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.13/drivers/net/wan/lapbether.c linux-2.5/drivers/net/wan/lapbether.c --- linux-2.5.13/drivers/net/wan/lapbether.c Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/net/wan/lapbether.c Sun Mar 3 20:15:15 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.13/drivers/net/wan/lmc/lmc_debug.c linux-2.5/drivers/net/wan/lmc/lmc_debug.c --- linux-2.5.13/drivers/net/wan/lmc/lmc_debug.c Fri May 3 01:22:47 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.13/drivers/net/wan/lmc/lmc_proto.c linux-2.5/drivers/net/wan/lmc/lmc_proto.c --- linux-2.5.13/drivers/net/wan/lmc/lmc_proto.c Fri May 3 01:22:54 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.13/drivers/net/wan/lmc/lmc_var.h linux-2.5/drivers/net/wan/lmc/lmc_var.h --- linux-2.5.13/drivers/net/wan/lmc/lmc_var.h Fri May 3 01:22:52 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.13/drivers/net/wan/pc300-falc-lh.h linux-2.5/drivers/net/wan/pc300-falc-lh.h --- linux-2.5.13/drivers/net/wan/pc300-falc-lh.h Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/net/wan/pc300-falc-lh.h Fri May 3 18:33:50 2002 @@ -10,7 +10,10 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * $Log: falc-lh.h,v $ + * $Log: pc300-falc-lh.h,v $ + * Revision 1.1 2002/05/03 17:33:50 davej + * Add new bits, kill old bits. + * * Revision 3.1 2001/06/15 12:41:10 regina * upping major version number * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/pc300.h linux-2.5/drivers/net/wan/pc300.h --- linux-2.5.13/drivers/net/wan/pc300.h Fri May 3 01:22:47 2002 +++ linux-2.5/drivers/net/wan/pc300.h Fri May 3 18:33:50 2002 @@ -11,6 +11,9 @@ * 2 of the License, or (at your option) any later version. * * $Log: pc300.h,v $ + * Revision 1.1 2002/05/03 17:33:50 davej + * Add new bits, kill old bits. + * * Revision 3.12 2002/03/07 14:17:09 henrique * License data fixed * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/pc300_drv.c linux-2.5/drivers/net/wan/pc300_drv.c --- linux-2.5.13/drivers/net/wan/pc300_drv.c Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/net/wan/pc300_drv.c Fri May 3 18:33:50 2002 @@ -18,6 +18,9 @@ * Using tabstop = 4. * * $Log: pc300_drv.c,v $ + * Revision 1.1 2002/05/03 17:33:50 davej + * Add new bits, kill old bits. + * * Revision 3.23 2002/03/20 13:58:40 henrique * Fixed ortographic mistakes * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/pc300_tty.c linux-2.5/drivers/net/wan/pc300_tty.c --- linux-2.5.13/drivers/net/wan/pc300_tty.c Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/net/wan/pc300_tty.c Fri May 3 18:33:50 2002 @@ -11,6 +11,9 @@ * 2 of the License, or (at your option) any later version. * * $Log: pc300_tty.c,v $ + * Revision 1.1 2002/05/03 17:33:50 davej + * Add new bits, kill old bits. + * * Revision 3.7 2002/03/07 14:17:09 henrique * License data fixed * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wan/sdla_chdlc.c linux-2.5/drivers/net/wan/sdla_chdlc.c --- linux-2.5.13/drivers/net/wan/sdla_chdlc.c Fri May 3 01:22:53 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.13/drivers/net/wan/sdla_fr.c linux-2.5/drivers/net/wan/sdla_fr.c --- linux-2.5.13/drivers/net/wan/sdla_fr.c Fri May 3 01:22:57 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.13/drivers/net/wan/sdla_ppp.c linux-2.5/drivers/net/wan/sdla_ppp.c --- linux-2.5.13/drivers/net/wan/sdla_ppp.c Fri May 3 01:22:44 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.13/drivers/net/wan/sealevel.c linux-2.5/drivers/net/wan/sealevel.c --- linux-2.5.13/drivers/net/wan/sealevel.c Fri May 3 01:22:54 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.13/drivers/net/wan/syncppp.c linux-2.5/drivers/net/wan/syncppp.c --- linux-2.5.13/drivers/net/wan/syncppp.c Fri May 3 01:22:46 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.13/drivers/net/wan/wanpipe_multppp.c linux-2.5/drivers/net/wan/wanpipe_multppp.c --- linux-2.5.13/drivers/net/wan/wanpipe_multppp.c Fri May 3 01:22:53 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.13/drivers/net/wan/x25_asy.c linux-2.5/drivers/net/wan/x25_asy.c --- linux-2.5.13/drivers/net/wan/x25_asy.c Fri May 3 01:22:44 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.13/drivers/net/wd.c linux-2.5/drivers/net/wd.c --- linux-2.5.13/drivers/net/wd.c Fri May 3 01:22: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.13/drivers/net/wireless/airo.c linux-2.5/drivers/net/wireless/airo.c --- linux-2.5.13/drivers/net/wireless/airo.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/net/wireless/airo.c Thu Feb 7 20:00:06 2002 @@ -46,7 +46,7 @@ #include #ifdef CONFIG_PCI -static struct pci_device_id card_ids[] = __devinitdata { +static struct pci_device_id card_ids[] __devinitdata = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wireless/airo_cs.c linux-2.5/drivers/net/wireless/airo_cs.c --- linux-2.5.13/drivers/net/wireless/airo_cs.c Fri May 3 01:22:46 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.13/drivers/net/wireless/airport.c linux-2.5/drivers/net/wireless/airport.c --- linux-2.5.13/drivers/net/wireless/airport.c Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/net/wireless/airport.c Wed May 1 20:28:50 2002 @@ -1,4 +1,4 @@ -/* airport.c 0.11a +/* airport.c 0.11b * * A driver for "Hermes" chipset based Apple Airport wireless * card. @@ -42,7 +42,7 @@ #include "hermes.h" #include "orinoco.h" -static char version[] __initdata = "airport.c 0.11a (Benjamin Herrenschmidt )"; +static char version[] __initdata = "airport.c 0.11b (Benjamin Herrenschmidt )"; MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_LICENSE("Dual MPL/GPL"); @@ -270,8 +270,8 @@ static void airport_detach(struct net_device *dev) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; - struct airport *card = (struct airport *)priv->card; + struct orinoco_private *priv = dev->priv; + struct airport *card = priv->card; /* Unregister proc entry */ orinoco_proc_dev_cleanup(priv); @@ -299,7 +299,7 @@ current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ); - kfree(card); + kfree(dev); } /* airport_detach */ static int __init diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wireless/orinoco.c linux-2.5/drivers/net/wireless/orinoco.c --- linux-2.5.13/drivers/net/wireless/orinoco.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/net/wireless/orinoco.c Wed May 1 20:28:50 2002 @@ -1,4 +1,4 @@ -/* orinoco.c 0.11a - (formerly known as dldwd_cs.c and orinoco_cs.c) +/* orinoco.c 0.11b - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for Hermes or Prism 2 chipset based PCMCIA wireless * adaptors, with Lucent/Agere, Intersil or Symbol firmware. @@ -256,7 +256,7 @@ * o Fixes for recent Symbol firmwares which lack AP density * (Pavel Roskin). * - * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson + * v0.11 -> v0.11b - 29 Apr 2002 - David Gibson * o Handle different register spacing, necessary for Prism 2.5 * PCI adaptors (Steve Hill). * o Cleaned up initialization of card structures in orinoco_cs @@ -274,15 +274,21 @@ * o Makefile changes for better integration into David Hinds * pcmcia-cs package. * + * v0.11a -> v0.11b - 1 May 2002 - David Gibson + * o Better error reporting in orinoco_plx_init_one() + * o Fixed multiple bad kfree() bugs introduced by the + * alloc_orinocodev() changes. + * * TODO - * o Re-assess our encapsulation detection strategy + * o New wireless extensions API * o Handle de-encapsulation within network layer, provide 802.11 * headers * o Fix possible races in SPY handling. * o Disconnect wireless extensions from fundamental configuration. * * o Convert /proc debugging stuff to seqfile - * o Use multiple Tx buffers */ + * o Use multiple Tx buffers + */ /* Notes on locking: * * The basic principle of operation is that everything except the @@ -351,7 +357,7 @@ #define SPY_NUMBER(priv) 0 #endif /* WIRELESS_SPY */ -static char version[] __initdata = "orinoco.c 0.11a (David Gibson and others)"; +static char version[] __initdata = "orinoco.c 0.11b (David Gibson and others)"; MODULE_AUTHOR("David Gibson "); MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); #ifdef MODULE_LICENSE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wireless/orinoco_cs.c linux-2.5/drivers/net/wireless/orinoco_cs.c --- linux-2.5.13/drivers/net/wireless/orinoco_cs.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/net/wireless/orinoco_cs.c Wed May 1 20:28:50 2002 @@ -1,4 +1,4 @@ -/* orinoco_cs.c 0.11a - (formerly known as dldwd_cs.c) +/* orinoco_cs.c 0.11b - (formerly known as dldwd_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -47,7 +47,7 @@ /*====================================================================*/ -static char version[] __initdata = "orinoco_cs.c 0.11a (David Gibson and others)"; +static char version[] __initdata = "orinoco_cs.c 0.11b (David Gibson and others)"; MODULE_AUTHOR("David Gibson "); MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); @@ -373,6 +373,7 @@ { dev_link_t **linkp; struct orinoco_private *priv = link->priv; + struct net_device *dev = priv->ndev; TRACE_ENTER("orinoco"); @@ -408,9 +409,9 @@ if (link->dev) { DEBUG(0, "orinoco_cs: About to unregister net device %p\n", priv->ndev); - unregister_netdev(priv->ndev); + unregister_netdev(dev); } - kfree(priv->card); + kfree(dev); out: TRACE_EXIT("orinoco"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wireless/orinoco_plx.c linux-2.5/drivers/net/wireless/orinoco_plx.c --- linux-2.5.13/drivers/net/wireless/orinoco_plx.c Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/net/wireless/orinoco_plx.c Wed May 1 20:28:50 2002 @@ -1,4 +1,4 @@ -/* orinoco_plx.c 0.11a +/* orinoco_plx.c 0.11b * * Driver for Prism II devices which would usually be driven by orinoco_cs, * but are connected to the PCI bus by a PLX9052. @@ -134,7 +134,7 @@ #include "hermes.h" #include "orinoco.h" -static char version[] __initdata = "orinoco_plx.c 0.11a (Daniel Barlow )"; +static char version[] __initdata = "orinoco_plx.c 0.11b (Daniel Barlow )"; MODULE_AUTHOR("Daniel Barlow "); MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); #ifdef MODULE_LICENSE @@ -284,7 +284,7 @@ hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO, HERMES_16BIT_REGSPACING); - pci_set_drvdata(pdev, priv); + pci_set_drvdata(pdev, dev); err = request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name, priv); if (err) { @@ -337,12 +337,12 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = dev->priv; TRACE_ENTER("orinoco_plx"); - if (!priv) + if (! dev) BUG(); orinoco_proc_dev_cleanup(priv); @@ -352,7 +352,7 @@ if (dev->irq) free_irq(dev->irq, priv); - kfree(priv); + kfree(dev); release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/net/wireless/wavelan.c linux-2.5/drivers/net/wireless/wavelan.c --- linux-2.5.13/drivers/net/wireless/wavelan.c Fri May 3 01:22:49 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.13/drivers/net/wireless/wavelan.p.h linux-2.5/drivers/net/wireless/wavelan.p.h --- linux-2.5.13/drivers/net/wireless/wavelan.p.h Fri May 3 01:22:55 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.13/drivers/parport/ChangeLog linux-2.5/drivers/parport/ChangeLog --- linux-2.5.13/drivers/parport/ChangeLog Fri May 3 01:22:55 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.13/drivers/parport/daisy.c linux-2.5/drivers/parport/daisy.c --- linux-2.5.13/drivers/parport/daisy.c Fri May 3 01:22:46 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.13/drivers/parport/parport_cs.c linux-2.5/drivers/parport/parport_cs.c --- linux-2.5.13/drivers/parport/parport_cs.c Fri May 3 01:22:57 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.13/drivers/parport/parport_pc.c linux-2.5/drivers/parport/parport_pc.c --- linux-2.5.13/drivers/parport/parport_pc.c Fri May 3 01:22:51 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.13/drivers/parport/parport_serial.c linux-2.5/drivers/parport/parport_serial.c --- linux-2.5.13/drivers/parport/parport_serial.c Fri May 3 01:22:56 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.13/drivers/pci/Makefile linux-2.5/drivers/pci/Makefile --- linux-2.5.13/drivers/pci/Makefile Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/pci/Makefile Sun Mar 3 17:54:35 2002 @@ -28,8 +28,8 @@ obj-$(CONFIG_PARISC) += setup-bus.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o obj-$(CONFIG_ALL_PPC) += setup-bus.o -obj-$(CONFIG_DDB5476) += 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.13/drivers/pci/gen-devlist.c linux-2.5/drivers/pci/gen-devlist.c --- linux-2.5.13/drivers/pci/gen-devlist.c Fri May 3 01:22:53 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.13/drivers/pci/setup-bus.c linux-2.5/drivers/pci/setup-bus.c --- linux-2.5.13/drivers/pci/setup-bus.c Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/pci/setup-bus.c Mon Jan 14 22:39:45 2002 @@ -201,6 +201,16 @@ b->resource[0]->end = ranges->io_end - 1; b->resource[1]->end = ranges->mem_end - 1; + /* Add bridge resources to the resource tree. */ + if (b->resource[0]->end > b->resource[0]->start && + request_resource(bus->resource[0], b->resource[0]) < 0) + printk(KERN_ERR "PCI: failed to reserve IO " + "for bus %d\n", b->number); + if (b->resource[1]->end > b->resource[1]->start && + request_resource(bus->resource[1], b->resource[1]) < 0) + printk(KERN_ERR "PCI: failed to reserve MEM " + "for bus %d\n", b->number); + pci_setup_bridge(b); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/pcmcia/Config.in linux-2.5/drivers/pcmcia/Config.in --- linux-2.5.13/drivers/pcmcia/Config.in Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/pcmcia/Config.in Fri May 3 03:12:37 2002 @@ -17,15 +17,17 @@ if [ "$CONFIG_PCI" != "n" ]; then bool ' CardBus support' CONFIG_CARDBUS fi - dep_bool ' i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI - bool ' i82365 compatible bridge support' CONFIG_I82365 bool ' Databook TCIC host bridge support' CONFIG_TCIC if [ "$CONFIG_HD64465" = "y" ]; then dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA fi + dep_bool ' i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI + bool ' i82365 compatible bridge support' CONFIG_I82365 + if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 + fi + if [ "$CONFIG_8xx" ="y" ]; then + tristate ' M8xx support' CONFIG_PCMCIA_M8XX + fi fi -if [ "$CONFIG_ARM" = "y" ]; then - dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA -fi - endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/pcmcia/Makefile linux-2.5/drivers/pcmcia/Makefile --- linux-2.5.13/drivers/pcmcia/Makefile Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/pcmcia/Makefile Fri May 3 03:49:07 2002 @@ -52,6 +52,7 @@ endif obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o +obj-$)CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o sa1100_cs-objs-y := sa1100_generic.o sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1111_generic.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/pcmcia/au1000_generic.c linux-2.5/drivers/pcmcia/au1000_generic.c --- linux-2.5.13/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.13/drivers/pcmcia/au1000_pb1000.c linux-2.5/drivers/pcmcia/au1000_pb1000.c --- linux-2.5.13/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.13/drivers/pcmcia/cistpl.c linux-2.5/drivers/pcmcia/cistpl.c --- linux-2.5.13/drivers/pcmcia/cistpl.c Fri May 3 01:22:47 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.13/drivers/pcmcia/cs.c linux-2.5/drivers/pcmcia/cs.c --- linux-2.5.13/drivers/pcmcia/cs.c Fri May 3 01:22:45 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.13/drivers/pcmcia/cs_internal.h linux-2.5/drivers/pcmcia/cs_internal.h --- linux-2.5.13/drivers/pcmcia/cs_internal.h Fri May 3 01:22:37 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.13/drivers/pcmcia/ds.c linux-2.5/drivers/pcmcia/ds.c --- linux-2.5.13/drivers/pcmcia/ds.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/pcmcia/ds.c Mon Apr 15 02:54:27 2002 @@ -830,7 +830,7 @@ err = unbind_request(i, &buf.bind_info); break; case DS_BIND_MTD: - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = bind_mtd(i, &buf.mtd_info); break; default: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/pcmcia/m8xx_pcmcia.c linux-2.5/drivers/pcmcia/m8xx_pcmcia.c --- linux-2.5.13/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.13/drivers/pcmcia/pci_socket.h linux-2.5/drivers/pcmcia/pci_socket.h --- linux-2.5.13/drivers/pcmcia/pci_socket.h Fri May 3 01:22:44 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.13/drivers/pcmcia/ricoh.h linux-2.5/drivers/pcmcia/ricoh.h --- linux-2.5.13/drivers/pcmcia/ricoh.h Fri May 3 01:22:52 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.13/drivers/pcmcia/rsrc_mgr.c linux-2.5/drivers/pcmcia/rsrc_mgr.c --- linux-2.5.13/drivers/pcmcia/rsrc_mgr.c Fri May 3 01:22:54 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.13/drivers/pcmcia/ti113x.h linux-2.5/drivers/pcmcia/ti113x.h --- linux-2.5.13/drivers/pcmcia/ti113x.h Fri May 3 01:22:49 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.13/drivers/pcmcia/yenta.c linux-2.5/drivers/pcmcia/yenta.c --- linux-2.5.13/drivers/pcmcia/yenta.c Fri May 3 01:22:54 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.13/drivers/pnp/isapnp.c linux-2.5/drivers/pnp/isapnp.c --- linux-2.5.13/drivers/pnp/isapnp.c Fri May 3 01:22:54 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.13/drivers/s390/Config.help linux-2.5/drivers/s390/Config.help --- linux-2.5.13/drivers/s390/Config.help Fri May 3 01:22: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.13/drivers/s390/ccwcache.c linux-2.5/drivers/s390/ccwcache.c --- linux-2.5.13/drivers/s390/ccwcache.c Fri May 3 01:22: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.13/drivers/s390/char/ctrlchar.c linux-2.5/drivers/s390/char/ctrlchar.c --- linux-2.5.13/drivers/s390/char/ctrlchar.c Fri May 3 01:22:57 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.13/drivers/s390/char/tubtty.c linux-2.5/drivers/s390/char/tubtty.c --- linux-2.5.13/drivers/s390/char/tubtty.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/s390/char/tubtty.c Mon Apr 15 02:54:27 2002 @@ -561,7 +561,7 @@ /* * Superuser-mode settings affect the driver overall --- */ - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { return -EPERM; } else if (strncmp(mybuf, "index=", 6) == 0) { tty3270_proc_index = simple_strtoul(mybuf + 6, 0,0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/s390/misc/chandev.c linux-2.5/drivers/s390/misc/chandev.c --- linux-2.5.13/drivers/s390/misc/chandev.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/s390/misc/chandev.c Wed Mar 27 13:07:16 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.13/drivers/sbus/char/jsflash.c linux-2.5/drivers/sbus/char/jsflash.c --- linux-2.5.13/drivers/sbus/char/jsflash.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/sbus/char/jsflash.c Fri May 3 12:57:31 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 (;;) { INIT_REQUEST; /* if (QUEUE_EMPTY) return; */ @@ -212,7 +218,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]; @@ -220,31 +226,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); } } @@ -666,7 +672,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.13/drivers/sbus/char/riowatchdog.c linux-2.5/drivers/sbus/char/riowatchdog.c --- linux-2.5.13/drivers/sbus/char/riowatchdog.c Fri May 3 01:22:53 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.13/drivers/sbus/char/sab82532.c linux-2.5/drivers/sbus/char/sab82532.c --- linux-2.5.13/drivers/sbus/char/sab82532.c Fri May 3 01:22:50 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.13/drivers/sbus/char/su.c linux-2.5/drivers/sbus/char/su.c --- linux-2.5.13/drivers/sbus/char/su.c Fri May 3 01:22:44 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.13/drivers/sbus/char/sunkbd.c linux-2.5/drivers/sbus/char/sunkbd.c --- linux-2.5.13/drivers/sbus/char/sunkbd.c Fri May 3 01:22:55 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.13/drivers/sbus/char/zs.c linux-2.5/drivers/sbus/char/zs.c --- linux-2.5.13/drivers/sbus/char/zs.c Fri May 3 01:22:58 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.13/drivers/scsi/ChangeLog.ips linux-2.5/drivers/scsi/ChangeLog.ips --- linux-2.5.13/drivers/scsi/ChangeLog.ips Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/scsi/ChangeLog.ips Fri May 3 03:49:07 2002 @@ -1,10 +1,40 @@ IBM ServeRAID driver Change Log ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 4.90.11 - Don't actually RESET unless it's physically required + - Remove unused compile options + + 4.90.08 - Data Corruption if First Scatter Gather Element is > 64K + + 4.90.08 - Increase Delays in Flashing ( Trombone Only - 4H ) + + 4.90.05 - Use New PCI Architecture to facilitate Hot Plug Development + + 4.90.01 - Add ServeRAID Version Checking + + 4.80.26 - Clean up potential code problems ( Arjan's recommendations ) + + 4.80.21 - Change memcpy() to copy_to_user() in NVRAM Page 5 IOCTL path + + 4.80.20 - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel ) + - 5 second delay needed after resetting an i960 adapter + + 4.80.14 - Take all semaphores off stack + - Clean Up New_IOCTL path + + 4.80.04 - Eliminate calls to strtok() if 2.4.x or greater + - Adjustments to Device Queue Depth + + 4.80.00 - Make ia64 Safe + + 4.72.01 - I/O Mapped Memory release ( so "insmod ips" does not Fail ) + - Don't Issue Internal FFDC Command if there are Active Commands + - Close Window for getting too many IOCTL's active + 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size 4.71.00 - Change all memory allocations to not use GFP_DMA flag - Code Clean-Up for 2.4.x kernel + - Code Clean-Up for 2.4.x kernel 4.70.15 - Fix Breakup for very large ( non-SG ) requests diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/Config.help linux-2.5/drivers/scsi/Config.help --- linux-2.5.13/drivers/scsi/Config.help Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/scsi/Config.help Mon Mar 4 00:00:02 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. @@ -977,6 +981,11 @@ inserted in and removed from the running kernel whenever you want). 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. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/Config.in linux-2.5/drivers/scsi/Config.in --- linux-2.5.13/drivers/scsi/Config.in Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/scsi/Config.in Mon Mar 4 00:00:02 2002 @@ -47,6 +47,9 @@ dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'Adaptec AACRAID support (EXPERIMENTAL)' CONFIG_SCSI_AACRAID $CONFIG_SCSI $CONFIG_PCI +fi source drivers/scsi/aic7xxx/Config.in if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI @@ -208,7 +211,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.13/drivers/scsi/Makefile linux-2.5/drivers/scsi/Makefile --- linux-2.5.13/drivers/scsi/Makefile Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/scsi/Makefile Fri May 3 03:49:07 2002 @@ -25,6 +25,7 @@ mod-subdirs := pcmcia ../acorn/scsi +subdir-$(CONFIG_SCSI_AACRAID) += aacraid subdir-$(CONFIG_SCSI_AIC7XXX) += aic7xxx subdir-$(CONFIG_PCMCIA) += pcmcia @@ -64,8 +65,11 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o +ifeq ($(CONFIG_SCSI_AACRAID),y) + obj-$(CONFIG_SCSI_AACRAID) += aacraid/aacraid.o +endif ifeq ($(CONFIG_SCSI_AIC7XXX),y) -obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o + obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx.o endif obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_IPS) += ips.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/README.st linux-2.5/drivers/scsi/README.st --- linux-2.5.13/drivers/scsi/README.st Fri May 3 01:22: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.13/drivers/scsi/a3000.c linux-2.5/drivers/scsi/a3000.c --- linux-2.5.13/drivers/scsi/a3000.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/scsi/a3000.c Wed Mar 27 13:07:16 2002 @@ -200,9 +200,7 @@ return 1; fail_irq: -#ifdef MODULE wd33c93_release(); -#endif /* MODULE */ scsi_unregister(a3000_host); fail_register: release_mem_region(0xDD0000, 256); @@ -217,11 +215,11 @@ int __exit a3000_release(struct Scsi_Host *instance) { -#ifdef MODULE wd33c93_release(); -#endif /* MODULE*/ DMA(instance)->CNTR = 0; release_mem_region(0xDD0000, 256); free_irq(IRQ_AMIGA_PORTS, a3000_intr); return 1; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/Makefile linux-2.5/drivers/scsi/aacraid/Makefile --- linux-2.5.13/drivers/scsi/aacraid/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/Makefile Fri May 3 03:49:07 2002 @@ -0,0 +1,10 @@ + +EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi + +O_TARGET := aacraid.o +obj-m := $(O_TARGET) + +obj-y := linit.o aachba.o commctrl.o comminit.o commsup.o \ + dpcsup.o rx.o sap1sup.o + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/README linux-2.5/drivers/scsi/aacraid/README --- linux-2.5.13/drivers/scsi/aacraid/README Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/README Mon Feb 4 22:15:17 2002 @@ -0,0 +1,41 @@ +AACRAID Driver for Linux (take two) + +Introduction +------------------------- +The aacraid driver adds support for Adaptec (http://www.adaptec.com) +OEM based RAID controllers. This is a major rewrite from the original +Adaptec supplied driver. It has signficantly cleaned up both the code +and the running binary size (the module is less than half the size of +the original). + +This driver is experimental. + +Supported Cards/Chipsets +------------------------- + Dell Computer Corporation PERC 2 Quad Channel + Dell Computer Corporation PERC 2/Si + Dell Computer Corporation PERC 3/Si + Dell Computer Corporation PERC 3/Di + HP NetRAID-4M + +Probably Supported Devices +------------------------- + Any and All Adaptec branded AAC964/5400 series raid controllers. + +People +------------------------- +Alan Cox +Christoph Hellwig (small cleanups/fixes) +Matt Domsch (revision ioctl, adapter messages) + +Original Driver +------------------------- +Adaptec Unix OEM Product Group + +Mailing List +------------------------- +None currently. Also note this is very different to Brian's original driver +so don't expect him to support it. + +Original by Brian Boerner February 2001 +Rewritten by Alan Cox, November 2001 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/TODO linux-2.5/drivers/scsi/aacraid/TODO --- linux-2.5.13/drivers/scsi/aacraid/TODO Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/TODO Thu Dec 13 16:32:36 2001 @@ -0,0 +1,4 @@ +o Testing +o More testing +o Feature request: display the firmware/bios/etc revisions in the + /proc info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/aachba.c linux-2.5/drivers/scsi/aacraid/aachba.c --- linux-2.5.13/drivers/scsi/aacraid/aachba.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/aachba.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,1155 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MAJOR_NR SCSI_DISK0_MAJOR /* For DEVICE_NR() */ +#include +#include "scsi.h" +#include "hosts.h" +#include "sd.h" + +#include "aacraid.h" + +/* SCSI Commands */ +#define SS_TEST 0x00 /* Test unit ready */ +#define SS_REZERO 0x01 /* Rezero unit */ +#define SS_REQSEN 0x03 /* Request Sense */ +#define SS_REASGN 0x07 /* Reassign blocks */ +#define SS_READ 0x08 /* Read 6 */ +#define SS_WRITE 0x0A /* Write 6 */ +#define SS_INQUIR 0x12 /* inquiry */ +#define SS_ST_SP 0x1B /* Start/Stop unit */ +#define SS_LOCK 0x1E /* prevent/allow medium removal */ +#define SS_RESERV 0x16 /* Reserve */ +#define SS_RELES 0x17 /* Release */ +#define SS_MODESEN 0x1A /* Mode Sense 6 */ +#define SS_RDCAP 0x25 /* Read Capacity */ +#define SM_READ 0x28 /* Read 10 */ +#define SM_WRITE 0x2A /* Write 10 */ +#define SS_SEEK 0x2B /* Seek */ + +/* values for inqd_pdt: Peripheral device type in plain English */ +#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ +#define INQD_PDT_PROC 0x03 /* Processor device */ +#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ +#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ +#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ +#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ + +#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ +#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ + +#define TARGET_LUN_TO_CONTAINER(target, lun) (((lun) << 4) | target) +#define CONTAINER_TO_TARGET(cont) ((cont) & 0xf) +#define CONTAINER_TO_LUN(cont) ((cont) >> 4) + +#define MAX_FIB_DATA (sizeof(struct hw_fib) - sizeof(FIB_HEADER)) + +#define MAX_DRIVER_SG_SEGMENT_COUNT 17 + +/* + * Sense keys + */ +#define SENKEY_NO_SENSE 0x00 +#define SENKEY_UNDEFINED 0x01 +#define SENKEY_NOT_READY 0x02 +#define SENKEY_MEDIUM_ERR 0x03 +#define SENKEY_HW_ERR 0x04 +#define SENKEY_ILLEGAL 0x05 +#define SENKEY_ATTENTION 0x06 +#define SENKEY_PROTECTED 0x07 +#define SENKEY_BLANK 0x08 +#define SENKEY_V_UNIQUE 0x09 +#define SENKEY_CPY_ABORT 0x0A +#define SENKEY_ABORT 0x0B +#define SENKEY_EQUAL 0x0C +#define SENKEY_VOL_OVERFLOW 0x0D +#define SENKEY_MISCOMP 0x0E +#define SENKEY_RESERVED 0x0F + +/* + * Sense codes + */ + +#define SENCODE_NO_SENSE 0x00 +#define SENCODE_END_OF_DATA 0x00 +#define SENCODE_BECOMING_READY 0x04 +#define SENCODE_INIT_CMD_REQUIRED 0x04 +#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A +#define SENCODE_INVALID_COMMAND 0x20 +#define SENCODE_LBA_OUT_OF_RANGE 0x21 +#define SENCODE_INVALID_CDB_FIELD 0x24 +#define SENCODE_LUN_NOT_SUPPORTED 0x25 +#define SENCODE_INVALID_PARAM_FIELD 0x26 +#define SENCODE_PARAM_NOT_SUPPORTED 0x26 +#define SENCODE_PARAM_VALUE_INVALID 0x26 +#define SENCODE_RESET_OCCURRED 0x29 +#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E +#define SENCODE_INQUIRY_DATA_CHANGED 0x3F +#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SENCODE_DIAGNOSTIC_FAILURE 0x40 +#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 +#define SENCODE_INVALID_MESSAGE_ERROR 0x49 +#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c +#define SENCODE_OVERLAPPED_COMMAND 0x4E + +/* + * Additional sense codes + */ + +#define ASENCODE_NO_SENSE 0x00 +#define ASENCODE_END_OF_DATA 0x05 +#define ASENCODE_BECOMING_READY 0x01 +#define ASENCODE_INIT_CMD_REQUIRED 0x02 +#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 +#define ASENCODE_INVALID_COMMAND 0x00 +#define ASENCODE_LBA_OUT_OF_RANGE 0x00 +#define ASENCODE_INVALID_CDB_FIELD 0x00 +#define ASENCODE_LUN_NOT_SUPPORTED 0x00 +#define ASENCODE_INVALID_PARAM_FIELD 0x00 +#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 +#define ASENCODE_PARAM_VALUE_INVALID 0x02 +#define ASENCODE_RESET_OCCURRED 0x00 +#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 +#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 +#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 +#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 +#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 +#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 +#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 +#define ASENCODE_OVERLAPPED_COMMAND 0x00 + +#define BYTE0(x) (unsigned char)(x) +#define BYTE1(x) (unsigned char)((x) >> 8) +#define BYTE2(x) (unsigned char)((x) >> 16) +#define BYTE3(x) (unsigned char)((x) >> 24) + +/*------------------------------------------------------------------------------ + * S T R U C T S / T Y P E D E F S + *----------------------------------------------------------------------------*/ +/* SCSI inquiry data */ +struct inquiry_data { + u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ + u8 inqd_dtq; /* RMB | Device Type Qualifier */ + u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ + u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ + u8 inqd_len; /* Additional length (n-4) */ + u8 inqd_pad1[2];/* Reserved - must be zero */ + u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ + u8 inqd_vid[8]; /* Vendor ID */ + u8 inqd_pid[16];/* Product ID */ + u8 inqd_prl[4]; /* Product Revision Level */ +}; + +struct sense_data { + u8 error_code; /* 70h (current errors), 71h(deferred errors) */ + u8 valid:1; /* A valid bit of one indicates that the information */ + /* field contains valid information as defined in the + * SCSI-2 Standard. + */ + u8 segment_number; /* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */ + u8 sense_key:4; /* Sense Key */ + u8 reserved:1; + u8 ILI:1; /* Incorrect Length Indicator */ + u8 EOM:1; /* End Of Medium - reserved for random access devices */ + u8 filemark:1; /* Filemark - reserved for random access devices */ + + u8 information[4]; /* for direct-access devices, contains the unsigned + * logical block address or residue associated with + * the sense key + */ + u8 add_sense_len; /* number of additional sense bytes to follow this field */ + u8 cmnd_info[4]; /* not used */ + u8 ASC; /* Additional Sense Code */ + u8 ASCQ; /* Additional Sense Code Qualifier */ + u8 FRUC; /* Field Replaceable Unit Code - not used */ + u8 bit_ptr:3; /* indicates which byte of the CDB or parameter data + * was in error + */ + u8 BPV:1; /* bit pointer valid (BPV): 1- indicates that + * the bit_ptr field has valid value + */ + u8 reserved2:2; + u8 CD:1; /* command data bit: 1- illegal parameter in CDB. + * 0- illegal parameter in data. + */ + u8 SKSV:1; + u8 field_ptr[2]; /* byte of the CDB or parameter data in error */ +}; + +/* + * M O D U L E G L O B A L S + */ + +static struct fsa_scsi_hba *fsa_dev[MAXIMUM_NUM_ADAPTERS]; /* SCSI Device Instance Pointers */ +static struct sense_data sense_data[MAXIMUM_NUM_CONTAINERS]; +static void get_sd_devname(int disknum, char *buffer); + +/** + * aac_get_containers - list containers + * @common: adapter to probe + * + * Make a list of all containers on this controller + */ +int aac_get_containers(struct aac_dev *dev) +{ + struct fsa_scsi_hba *fsa_dev_ptr; + int index, status = 0; + struct aac_query_mount *dinfo; + struct aac_mount *dresp; + struct fib * fibptr; + unsigned instance; + + fsa_dev_ptr = &(dev->fsa_dev); + instance = dev->scsi_host_ptr->unique_id; + + if (!(fibptr = fib_alloc(dev))) + return -ENOMEM; + + for (index = 0; index < MAXIMUM_NUM_CONTAINERS; index++) { + fib_init(fibptr); + dinfo = (struct aac_query_mount *) fib_data(fibptr); + + dinfo->command = cpu_to_le32(VM_NameServe); + dinfo->count = cpu_to_le32(index); + dinfo->type = cpu_to_le32(FT_FILESYS); + + status = fib_send(ContainerCommand, + fibptr, + sizeof (struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL); + if (status < 0 ) { + printk(KERN_WARNING "ProbeContainers: SendFIB failed.\n"); + break; + } + dresp = (struct aac_mount *)fib_data(fibptr); + + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { + fsa_dev_ptr->valid[index] = 1; + fsa_dev_ptr->type[index] = le32_to_cpu(dresp->mnt[0].vol); + fsa_dev_ptr->size[index] = le32_to_cpu(dresp->mnt[0].capacity); + if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) + fsa_dev_ptr->ro[index] = 1; + } + fib_complete(fibptr); + /* + * If there are no more containers, then stop asking. + */ + if ((index + 1) >= le32_to_cpu(dresp->count)) + break; + } + fib_free(fibptr); + fsa_dev[instance] = fsa_dev_ptr; + return status; +} + +/** + * probe_container - query a logical volume + * @dev: device to query + * @cid: container identifier + * + * Queries the controller about the given volume. The volume information + * is updated in the struct fsa_scsi_hba structure rather than returned. + */ + +static int probe_container(struct aac_dev *dev, int cid) +{ + struct fsa_scsi_hba *fsa_dev_ptr; + int status; + struct aac_query_mount *dinfo; + struct aac_mount *dresp; + struct fib * fibptr; + unsigned instance; + + fsa_dev_ptr = &(dev->fsa_dev); + instance = dev->scsi_host_ptr->unique_id; + + if (!(fibptr = fib_alloc(dev))) + return -ENOMEM; + + fib_init(fibptr); + + dinfo = (struct aac_query_mount *)fib_data(fibptr); + + dinfo->command = cpu_to_le32(VM_NameServe); + dinfo->count = cpu_to_le32(cid); + dinfo->type = cpu_to_le32(FT_FILESYS); + + status = fib_send(ContainerCommand, + fibptr, + sizeof(struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL); + if (status < 0) { + printk(KERN_WARNING "aacraid: probe_containers query failed.\n"); + goto error; + } + + dresp = (struct aac_mount *) fib_data(fibptr); + + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { + fsa_dev_ptr->valid[cid] = 1; + fsa_dev_ptr->type[cid] = le32_to_cpu(dresp->mnt[0].vol); + fsa_dev_ptr->size[cid] = le32_to_cpu(dresp->mnt[0].capacity); + if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) + fsa_dev_ptr->ro[cid] = 1; + } + +error: + fib_complete(fibptr); + fib_free(fibptr); + + return status; +} + +/* Local Structure to set SCSI inquiry data strings */ +struct scsi_inq { + char vid[8]; /* Vendor ID */ + char pid[16]; /* Product ID */ + char prl[4]; /* Product Revision Level */ +}; + +/** + * InqStrCopy - string merge + * @a: string to copy from + * @b: string to copy to + * + * Copy a String from one location to another + * without copying \0 + */ + +static void inqstrcpy(char *a, char *b) +{ + + while(*a != (char)0) + *b++ = *a++; +} + +static char *container_types[] = { + "None", + "Volume", + "Mirror", + "Stripe", + "RAID5", + "SSRW", + "SSRO", + "Morph", + "Legacy", + "RAID4", + "RAID10", + "RAID00", + "V-MIRRORS", + "PSEUDO R4", + "RAID50", + "Unknown" +}; + + + +/* Function: setinqstr + * + * Arguments: [1] pointer to void [1] int + * + * Purpose: Sets SCSI inquiry data strings for vendor, product + * and revision level. Allows strings to be set in platform dependant + * files instead of in OS dependant driver source. + */ + +static void setinqstr(int devtype, void *data, int tindex) +{ + struct scsi_inq *str; + char *findit; + struct aac_driver_ident *mp; + extern struct aac_driver_ident aac_drivers[]; /* HACK FIXME */ + + mp = &aac_drivers[devtype]; + + str = (struct scsi_inq *)(data); /* cast data to scsi inq block */ + + inqstrcpy (mp->vname, str->vid); + inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */ + + findit = str->pid; + + for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */ + findit++; + + if (tindex < (sizeof(container_types)/sizeof(char *))){ + inqstrcpy (container_types[tindex], findit); + } + inqstrcpy ("0001", str->prl); +} + +void set_sense(char *sense_buf, u8 sense_key, u8 sense_code, + u8 a_sense_code, u8 incorrect_length, + u8 bit_pointer, unsigned field_pointer, + unsigned long residue) +{ + sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */ + sense_buf[1] = 0; /* Segment number, always zero */ + + if (incorrect_length) { + sense_buf[2] = sense_key | 0x20; /* Set the ILI bit | sense key */ + sense_buf[3] = BYTE3(residue); + sense_buf[4] = BYTE2(residue); + sense_buf[5] = BYTE1(residue); + sense_buf[6] = BYTE0(residue); + } else + sense_buf[2] = sense_key; /* Sense key */ + + if (sense_key == SENKEY_ILLEGAL) + sense_buf[7] = 10; /* Additional sense length */ + else + sense_buf[7] = 6; /* Additional sense length */ + + sense_buf[12] = sense_code; /* Additional sense code */ + sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ + if (sense_key == SENKEY_ILLEGAL) { + sense_buf[15] = 0; + + if (sense_code == SENCODE_INVALID_PARAM_FIELD) + sense_buf[15] = 0x80; /* Std sense key specific field */ + /* Illegal parameter is in the parameter block */ + + if (sense_code == SENCODE_INVALID_CDB_FIELD) + sense_buf[15] = 0xc0; /* Std sense key specific field */ + /* Illegal parameter is in the CDB block */ + sense_buf[15] |= bit_pointer; + sense_buf[16] = field_pointer >> 8; /* MSB */ + sense_buf[17] = field_pointer; /* LSB */ + } +} + +static void aac_io_done(Scsi_Cmnd * scsicmd) +{ + unsigned long cpu_flags; + spin_lock_irqsave(&io_request_lock, cpu_flags); + scsicmd->scsi_done(scsicmd); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +} + +static void __aac_io_done(Scsi_Cmnd * scsicmd) +{ + scsicmd->scsi_done(scsicmd); +} + +static void read_callback(void *context, struct fib * fibptr) +{ + struct aac_dev *dev; + struct aac_read_reply *readreply; + Scsi_Cmnd *scsicmd; + unsigned long lba; + int cid; + + scsicmd = (Scsi_Cmnd *) context; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + cid =TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies)); + + if (fibptr == NULL) + BUG(); + + if(scsicmd->use_sg) + pci_unmap_sg(dev->pdev, + (struct scatterlist *)scsicmd->buffer, + scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + else if(scsicmd->request_bufflen) + pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + readreply = (struct aac_read_reply *)fib_data(fibptr); + if (le32_to_cpu(readreply->status) == ST_OK) + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else { + printk(KERN_WARNING "read_callback: read failed, status = %d\n", readreply->status); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_HW_ERR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); + } + fib_complete(fibptr); + fib_free(fibptr); + + aac_io_done(scsicmd); +} + +static void write_callback(void *context, struct fib * fibptr) +{ + struct aac_dev *dev; + struct aac_write_reply *writereply; + Scsi_Cmnd *scsicmd; + unsigned long lba; + int cid; + + scsicmd = (Scsi_Cmnd *) context; + dev = (struct aac_dev *)scsicmd->host->hostdata; + cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies)); + if (fibptr == NULL) + BUG(); + + if(scsicmd->use_sg) + pci_unmap_sg(dev->pdev, + (struct scatterlist *)scsicmd->buffer, + scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + else if(scsicmd->request_bufflen) + pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + writereply = (struct aac_write_reply *) fib_data(fibptr); + if (le32_to_cpu(writereply->status) == ST_OK) + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else { + printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_HW_ERR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); + } + + fib_complete(fibptr); + fib_free(fibptr); + aac_io_done(scsicmd); +} + +int aac_read(Scsi_Cmnd * scsicmd, int cid) +{ + unsigned long lba; + unsigned long count; + unsigned long byte_count = 0; + int status; + + struct aac_read *readcmd; + u16 fibsize; + struct aac_dev *dev; + struct fib * cmd_fibcontext; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + /* + * Get block address and transfer length + */ + if (scsicmd->cmnd[0] == SS_READ) /* 6 byte command */ + { + dprintk((KERN_DEBUG "aachba: received a read(6) command on target %d.\n", cid)); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + count = scsicmd->cmnd[4]; + + if (count == 0) + count = 256; + } else { + dprintk((KERN_DEBUG "aachba: received a read(10) command on target %d.\n", cid)); + + lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; + count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; + } + dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies)); + /* + * Alocate and initialize a Fib + */ + if (!(cmd_fibcontext = fib_alloc(dev))) { + scsicmd->result = DID_ERROR << 16; + aac_io_done(scsicmd); + return (-1); + } + + fib_init(cmd_fibcontext); + + readcmd = (struct aac_read *) fib_data(cmd_fibcontext); + readcmd->command = cpu_to_le32(VM_CtBlockRead); + readcmd->cid = cpu_to_le32(cid); + readcmd->block = cpu_to_le32(lba); + readcmd->count = cpu_to_le32(count * 512); + readcmd->sg.count = cpu_to_le32(1); + + if (count * 512 > (64 * 1024)) + BUG(); + /* + * Build Scatter/Gather list + */ + if (scsicmd->use_sg) /* use scatter/gather list */ + { + struct scatterlist *sg; + int i; + int sg_count; + + sg = (struct scatterlist *) scsicmd->request_buffer; + + sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + byte_count = 0; + + for (i = 0; i < sg_count; i++) { + readcmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg)); + readcmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg)); + byte_count += sg->length; + if (sg->length > (64 * 1024)) + BUG(); + sg++; + } + readcmd->sg.count = cpu_to_le32(sg_count); + + if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT) + BUG(); + } + else if(scsicmd->request_bufflen) + { + dma_addr_t addr; + addr = pci_map_single(dev->pdev, scsicmd->request_buffer, + scsicmd->request_bufflen, scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + scsicmd->SCp.ptr = (void *)(long)addr; + readcmd->sg.sg[0].addr = cpu_to_le32(addr); + readcmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen); + + byte_count = scsicmd->request_bufflen; + + if (byte_count > (64 * 1024)) + BUG(); + } + if (byte_count != readcmd->count) + BUG(); + /* + * Now send the Fib to the adapter + */ + fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry)); + status = fib_send(ContainerCommand, + cmd_fibcontext, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) read_callback, + (void *) scsicmd); + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) + return 0; + + printk(KERN_WARNING "aac_read: fib_send failed with status: %d.\n", status); + /* + * For some reason, the Fib didn't queue, return QUEUE_FULL + */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL; + aac_io_done(scsicmd); + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return -1; +} + +static int aac_write(Scsi_Cmnd * scsicmd, int cid) +{ + unsigned long lba; + unsigned long count; + unsigned long byte_count = 0; + int status; + struct aac_write *writecmd; + u16 fibsize; + struct aac_dev *dev; + struct fib * cmd_fibcontext; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + /* + * Get block address and transfer length + */ + if (scsicmd->cmnd[0] == SS_WRITE) /* 6 byte command */ + { + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + count = scsicmd->cmnd[4]; + if (count == 0) + count = 256; + } else { + dprintk((KERN_DEBUG "aachba: received a write(10) command on target %d.\n", cid)); + lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; + count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; + } + dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies)); + /* + * Allocate and initialize a Fib then setup a BlockWrite command + */ + if (!(cmd_fibcontext = fib_alloc(dev))) { + scsicmd->result = DID_ERROR << 16; + aac_io_done(scsicmd); + return -1; + } + fib_init(cmd_fibcontext); + + writecmd = (struct aac_write *) fib_data(cmd_fibcontext); + writecmd->command = cpu_to_le32(VM_CtBlockWrite); + writecmd->cid = cpu_to_le32(cid); + writecmd->block = cpu_to_le32(lba); + writecmd->count = cpu_to_le32(count * 512); + writecmd->sg.count = cpu_to_le32(1); + /* FIXME: why isnt ->stable setup */ + + if (count * 512 > (64 * 1024)) { + BUG(); + } + /* + * Build Scatter/Gather list + */ + if (scsicmd->use_sg) + { + struct scatterlist *sg; + int i; + int sg_count; + + sg = (struct scatterlist *) scsicmd->request_buffer; + + sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + byte_count = 0; + + for (i = 0; i < scsicmd->use_sg; i++) { + writecmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg)); + writecmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg)); + byte_count += sg->length; + + if (sg->length > (64 * 1024)) + BUG(); + sg++; + } + writecmd->sg.count = cpu_to_le32(sg_count); + + if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT) + BUG(); + } + else if(scsicmd->request_bufflen) + { + dma_addr_t addr; + addr = pci_map_single(dev->pdev, + scsicmd->request_buffer, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + writecmd->sg.sg[0].addr = cpu_to_le32(addr); + writecmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen); + scsicmd->SCp.ptr = (void *)(long)addr; + byte_count = scsicmd->request_bufflen; + + if (byte_count > (64 * 1024)) + BUG(); + } + if (byte_count != writecmd->count) + BUG(); + /* + * Now send the Fib to the adapter + */ + fibsize = sizeof (struct aac_write) + ((writecmd->sg.count - 1) * sizeof (struct sgentry)); + + status = fib_send(ContainerCommand, + cmd_fibcontext, + fibsize, FsaNormal, + 0, 1, + (fib_callback) write_callback, + (void *) scsicmd); + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) + return 0; + + printk(KERN_WARNING "aac_write: fib_send failed with status: %d\n", status); + /* + * For some reason, the Fib didn't queue, return QUEUE_FULL + */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL; + aac_io_done(scsicmd); + + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return -1; +} + + +/** + * aac_scsi_cmd() - Process SCSI command + * @scsicmd: SCSI command block + * @wait: 1 if the user wants to await completion + * + * Emulate a SCSI command and queue the required request for the + * aacraid firmware. + */ + +int aac_scsi_cmd(Scsi_Cmnd * scsicmd) +{ + int cid = 0; + struct fsa_scsi_hba *fsa_dev_ptr; + int cardtype; + int ret; + struct aac_dev *dev = (struct aac_dev *)scsicmd->host->hostdata; + + cardtype = dev->cardtype; + + fsa_dev_ptr = fsa_dev[scsicmd->host->unique_id]; + + /* + * If the bus, target or lun is out of range, return fail + * Test does not apply to ID 16, the pseudo id for the controller + * itself. + */ + if (scsicmd->target != scsicmd->host->this_id) { + if ((scsicmd->channel > 0) ||(scsicmd->target > 15) || (scsicmd->lun > 7)) + { + dprintk((KERN_DEBUG "The bus, target or lun is out of range = %d, %d, %d.\n", + scsicmd->channel, scsicmd->target, scsicmd->lun)); + scsicmd->result = DID_BAD_TARGET << 16; + __aac_io_done(scsicmd); + return -1; + } + cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + /* + * If the target container doesn't exist, it may have + * been newly created + */ + if (fsa_dev_ptr->valid[cid] == 0) { + switch (scsicmd->cmnd[0]) { + case SS_INQUIR: + case SS_RDCAP: + case SS_TEST: + spin_unlock_irq(&io_request_lock); + probe_container(dev, cid); + spin_lock_irq(&io_request_lock); + default: + break; + } + } + /* + * If the target container still doesn't exist, + * return failure + */ + if (fsa_dev_ptr->valid[cid] == 0) { + scsicmd->result = DID_BAD_TARGET << 16; + __aac_io_done(scsicmd); + return -1; + } + } + else if ((scsicmd->cmnd[0] != SS_INQUIR) && /* only INQUIRY & TUR cmnd supported for controller */ + (scsicmd->cmnd[0] != SS_TEST)) + { + /* + * Command aimed at the controller + */ + dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_ILLEGAL, + SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); + __aac_io_done(scsicmd); + return -1; + } + /* Handle commands here that don't really require going out to the adapter */ + switch (scsicmd->cmnd[0]) + { + case SS_INQUIR: + { + struct inquiry_data *inq_data_ptr; + + dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->target)); + inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer; + memset(inq_data_ptr, 0, sizeof (struct inquiry_data)); + + inq_data_ptr->inqd_ver = 2; /* claim compliance to SCSI-2 */ + inq_data_ptr->inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */ + inq_data_ptr->inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ + inq_data_ptr->inqd_len = 31; + + /* + * Set the Vendor, Product, and Revision Level + * see: .c i.e. aac.c + */ + setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]); + if (scsicmd->target == scsicmd->host->this_id) + inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */ + else + inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return 0; + } + case SS_RDCAP: + { + int capacity; + char *cp; + + dprintk((KERN_DEBUG "READ CAPACITY command.\n")); + capacity = fsa_dev_ptr->size[cid] - 1; + cp = scsicmd->request_buffer; + cp[0] = (capacity >> 24) & 0xff; + cp[1] = (capacity >> 16) & 0xff; + cp[2] = (capacity >> 8) & 0xff; + cp[3] = (capacity >> 0) & 0xff; + cp[4] = 0; + cp[5] = 0; + cp[6] = 2; + cp[7] = 0; + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + + return 0; + } + + case SS_MODESEN: + { + char *mode_buf; + + dprintk((KERN_DEBUG "MODE SENSE command.\n")); + mode_buf = scsicmd->request_buffer; + mode_buf[0] = 0; /* Mode data length (MSB) */ + mode_buf[1] = 6; /* Mode data length (LSB) */ + mode_buf[2] = 0; /* Medium type - default */ + mode_buf[3] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */ + mode_buf[4] = 0; /* reserved */ + mode_buf[5] = 0; /* reserved */ + mode_buf[6] = 0; /* Block descriptor length (MSB) */ + mode_buf[7] = 0; /* Block descriptor length (LSB) */ + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + + return 0; + } + case SS_REQSEN: + dprintk((KERN_DEBUG "REQUEST SENSE command.\n")); + memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof (struct sense_data)); + memset(&sense_data[cid], 0, sizeof (struct sense_data)); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return (0); + + case SS_LOCK: + dprintk((KERN_DEBUG "LOCK command.\n")); + if (scsicmd->cmnd[4]) + fsa_dev_ptr->locked[cid] = 1; + else + fsa_dev_ptr->locked[cid] = 0; + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return 0; + /* + * These commands are all No-Ops + */ + case SS_TEST: + case SS_RESERV: + case SS_RELES: + case SS_REZERO: + case SS_REASGN: + case SS_SEEK: + case SS_ST_SP: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return (0); + } + + switch (scsicmd->cmnd[0]) + { + case SS_READ: + case SM_READ: + /* + * Hack to keep track of ordinal number of the device that + * corresponds to a container. Needed to convert + * containers to /dev/sd device names + */ + + spin_unlock_irq(&io_request_lock); + fsa_dev_ptr->devno[cid] = DEVICE_NR(scsicmd->request.rq_dev); + ret = aac_read(scsicmd, cid); + spin_lock_irq(&io_request_lock); + return ret; + + case SS_WRITE: + case SM_WRITE: + spin_unlock_irq(&io_request_lock); + ret = aac_write(scsicmd, cid); + spin_lock_irq(&io_request_lock); + return ret; + default: + /* + * Unhandled commands + */ + printk(KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); + __aac_io_done(scsicmd); + return -1; + } +} + +static int query_disk(struct aac_dev *dev, void *arg) +{ + struct aac_query_disk qd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) + return -EFAULT; + if (qd.cnum == -1) + qd.cnum = TARGET_LUN_TO_CONTAINER(qd.target, qd.lun); + else if ((qd.bus == -1) && (qd.target == -1) && (qd.lun == -1)) + { + if (qd.cnum < 0 || qd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + qd.instance = dev->scsi_host_ptr->host_no; + qd.bus = 0; + qd.target = CONTAINER_TO_TARGET(qd.cnum); + qd.lun = CONTAINER_TO_LUN(qd.cnum); + } + else return -EINVAL; + + qd.valid = fsa_dev_ptr->valid[qd.cnum]; + qd.locked = fsa_dev_ptr->locked[qd.cnum]; + qd.deleted = fsa_dev_ptr->deleted[qd.cnum]; + + if (fsa_dev_ptr->devno[qd.cnum] == -1) + qd.unmapped = 1; + else + qd.unmapped = 0; + + get_sd_devname(fsa_dev_ptr->devno[qd.cnum], qd.name); + + if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) + return -EFAULT; + return 0; +} + +static void get_sd_devname(int disknum, char *buffer) +{ + if (disknum < 0) { + sprintf(buffer, "%s", ""); + return; + } + + if (disknum < 26) + sprintf(buffer, "sd%c", 'a' + disknum); + else { + unsigned int min1; + unsigned int min2; + /* + * For larger numbers of disks, we need to go to a new + * naming scheme. + */ + min1 = disknum / 26; + min2 = disknum % 26; + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); + } +} + +static int force_delete_disk(struct aac_dev *dev, void *arg) +{ + struct aac_delete_disk dd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + + if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) + return -EFAULT; + + if (dd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + /* + * Mark this container as being deleted. + */ + fsa_dev_ptr->deleted[dd.cnum] = 1; + /* + * Mark the container as no longer valid + */ + fsa_dev_ptr->valid[dd.cnum] = 0; + return 0; +} + +static int delete_disk(struct aac_dev *dev, void *arg) +{ + struct aac_delete_disk dd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + + if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) + return -EFAULT; + + if (dd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + /* + * If the container is locked, it can not be deleted by the API. + */ + if (fsa_dev_ptr->locked[dd.cnum]) + return -EBUSY; + else { + /* + * Mark the container as no longer being valid. + */ + fsa_dev_ptr->valid[dd.cnum] = 0; + fsa_dev_ptr->devno[dd.cnum] = -1; + return 0; + } +} + +int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg) +{ + switch (cmd) { + case FSACTL_QUERY_DISK: + return query_disk(dev, arg); + case FSACTL_DELETE_DISK: + return delete_disk(dev, arg); + case FSACTL_FORCE_DELETE_DISK: + return force_delete_disk(dev, arg); + case 2131: + return aac_get_containers(dev); + default: + return -ENOTTY; + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/aacraid.h linux-2.5/drivers/scsi/aacraid/aacraid.h --- linux-2.5.13/drivers/scsi/aacraid/aacraid.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/aacraid.h Sun Mar 3 17:54:35 2002 @@ -0,0 +1,1208 @@ +#define dprintk(x) + +#define AAC_NUM_FIB 128 +#define AAC_NUM_IO_FIB 116 + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ + +struct diskparm +{ + int heads; + int sectors; + int cylinders; +}; + + +/* + * DON'T CHANGE THE ORDER, this is set by the firmware + */ + +#define CT_NONE 0 +#define CT_VOLUME 1 +#define CT_MIRROR 2 +#define CT_STRIPE 3 +#define CT_RAID5 4 +#define CT_SSRW 5 +#define CT_SSRO 6 +#define CT_MORPH 7 +#define CT_PASSTHRU 8 +#define CT_RAID4 9 +#define CT_RAID10 10 /* stripe of mirror */ +#define CT_RAID00 11 /* stripe of stripe */ +#define CT_VOLUME_OF_MIRRORS 12 /* volume of mirror */ +#define CT_PSEUDO_RAID 13 /* really raid4 */ +#define CT_LAST_VOLUME_TYPE 14 + +/* + * Types of objects addressable in some fashion by the client. + * This is a superset of those objects handled just by the filesystem + * and includes "raw" objects that an administrator would use to + * configure containers and filesystems. + */ + +#define FT_REG 1 /* regular file */ +#define FT_DIR 2 /* directory */ +#define FT_BLK 3 /* "block" device - reserved */ +#define FT_CHR 4 /* "character special" device - reserved */ +#define FT_LNK 5 /* symbolic link */ +#define FT_SOCK 6 /* socket */ +#define FT_FIFO 7 /* fifo */ +#define FT_FILESYS 8 /* ADAPTEC's "FSA"(tm) filesystem */ +#define FT_DRIVE 9 /* physical disk - addressable in scsi by bus/target/lun */ +#define FT_SLICE 10 /* virtual disk - raw volume - slice */ +#define FT_PARTITION 11 /* FSA partition - carved out of a slice - building block for containers */ +#define FT_VOLUME 12 /* Container - Volume Set */ +#define FT_STRIPE 13 /* Container - Stripe Set */ +#define FT_MIRROR 14 /* Container - Mirror Set */ +#define FT_RAID5 15 /* Container - Raid 5 Set */ +#define FT_DATABASE 16 /* Storage object with "foreign" content manager */ + +/* + * Host side memory scatter gather list + * Used by the adapter for read, write, and readdirplus operations + */ + +struct sgentry { + u32 addr; /* 32-bit Base address. */ + u32 count; /* Length. */ +}; + +/* + * SGMAP + * + * This is the SGMAP structure for all commands that use + * 32-bit addressing. + * + * Note that the upper 16 bits of SgCount are used as flags. + * Only the lower 16 bits of SgCount are actually used as the + * SG element count. + */ + +struct sgmap { + u32 count; + struct sgentry sg[1]; +}; + +struct creation_info +{ + u8 buildnum; /* e.g., 588 */ + u8 usec; /* e.g., 588 */ + u8 via; /* e.g., 1 = FSU, + * 2 = API + */ + u8 year; /* e.g., 1997 = 97 */ + u32 date; /* + * unsigned Month :4; // 1 - 12 + * unsigned Day :6; // 1 - 32 + * unsigned Hour :6; // 0 - 23 + * unsigned Minute :6; // 0 - 60 + * unsigned Second :6; // 0 - 60 + */ + u64 serial; /* e.g., 0x1DEADB0BFAFAF001 */ +}; + + +/* + * Define all the constants needed for the communication interface + */ + +/* + * Define how many queue entries each queue will have and the total + * number of entries for the entire communication interface. Also define + * how many queues we support. + * + * This has to match the controller + */ + +#define NUMBER_OF_COMM_QUEUES 8 // 4 command; 4 response +#define HOST_HIGH_CMD_ENTRIES 4 +#define HOST_NORM_CMD_ENTRIES 8 +#define ADAP_HIGH_CMD_ENTRIES 4 +#define ADAP_NORM_CMD_ENTRIES 512 +#define HOST_HIGH_RESP_ENTRIES 4 +#define HOST_NORM_RESP_ENTRIES 512 +#define ADAP_HIGH_RESP_ENTRIES 4 +#define ADAP_NORM_RESP_ENTRIES 8 + +#define TOTAL_QUEUE_ENTRIES \ + (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \ + HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES) + + +/* + * Set the queues on a 16 byte alignment + */ + +#define QUEUE_ALIGNMENT 16 + +/* + * The queue headers define the Communication Region queues. These + * are physically contiguous and accessible by both the adapter and the + * host. Even though all queue headers are in the same contiguous block + * they will be represented as individual units in the data structures. + */ + +struct aac_entry { + u32 size; /* Size in bytes of the Fib which this QE points to */ + u32 addr; /* Receiver addressable address of the FIB (low 32 address bits) */ +}; + +/* + * The adapter assumes the ProducerIndex and ConsumerIndex are grouped + * adjacently and in that order. + */ + +struct aac_qhdr { + u64 header_addr; /* Address to hand the adapter to access to this queue head */ + u32 *producer; /* The producer index for this queue (host address) */ + u32 *consumer; /* The consumer index for this queue (host address) */ +}; + +/* + * Define all the events which the adapter would like to notify + * the host of. + */ + +#define HostNormCmdQue 1 /* Change in host normal priority command queue */ +#define HostHighCmdQue 2 /* Change in host high priority command queue */ +#define HostNormRespQue 3 /* Change in host normal priority response queue */ +#define HostHighRespQue 4 /* Change in host high priority response queue */ +#define AdapNormRespNotFull 5 +#define AdapHighRespNotFull 6 +#define AdapNormCmdNotFull 7 +#define AdapHighCmdNotFull 8 +#define SynchCommandComplete 9 +#define AdapInternalError 0xfe /* The adapter detected an internal error shutting down */ + +/* + * Define all the events the host wishes to notify the + * adapter of. The first four values much match the Qid the + * corresponding queue. + */ + +#define AdapNormCmdQue 2 +#define AdapHighCmdQue 3 +#define AdapNormRespQue 6 +#define AdapHighRespQue 7 +#define HostShutdown 8 +#define HostPowerFail 9 +#define FatalCommError 10 +#define HostNormRespNotFull 11 +#define HostHighRespNotFull 12 +#define HostNormCmdNotFull 13 +#define HostHighCmdNotFull 14 +#define FastIo 15 +#define AdapPrintfDone 16 + +/* + * Define all the queues that the adapter and host use to communicate + * Number them to match the physical queue layout. + */ + +enum aac_queue_types { + HostNormCmdQueue = 0, /* Adapter to host normal priority command traffic */ + HostHighCmdQueue, /* Adapter to host high priority command traffic */ + AdapNormCmdQueue, /* Host to adapter normal priority command traffic */ + AdapHighCmdQueue, /* Host to adapter high priority command traffic */ + HostNormRespQueue, /* Adapter to host normal priority response traffic */ + HostHighRespQueue, /* Adapter to host high priority response traffic */ + AdapNormRespQueue, /* Host to adapter normal priority response traffic */ + AdapHighRespQueue /* Host to adapter high priority response traffic */ +}; + +/* + * Assign type values to the FSA communication data structures + */ + +#define FIB_MAGIC 0x0001 + +/* + * Define the priority levels the FSA communication routines support. + */ + +#define FsaNormal 1 +#define FsaHigh 2 + +// +// Define the FIB. The FIB is the where all the requested data and +// command information are put to the application on the FSA adapter. +// + +struct aac_fibhdr { + u32 XferState; // Current transfer state for this CCB + u16 Command; // Routing information for the destination + u8 StructType; // Type FIB + u8 Flags; // Flags for FIB + u16 Size; // Size of this FIB in bytes + u16 SenderSize; // Size of the FIB in the sender (for response sizing) + u32 SenderFibAddress; // Host defined data in the FIB + u32 ReceiverFibAddress; // Logical address of this FIB for the adapter + u32 SenderData; // Place holder for the sender to store data + union { + struct { + u32 _ReceiverTimeStart; // Timestamp for receipt of fib + u32 _ReceiverTimeDone; // Timestamp for completion of fib + } _s; + struct list_head _FibLinks; // Used to link Adapter Initiated Fibs on the host + } _u; +}; + +#define FibLinks _u._FibLinks + +#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(struct aac_fibhdr)) + + +struct hw_fib { + struct aac_fibhdr header; + u8 data[FIB_DATA_SIZE_IN_BYTES]; // Command specific data +}; + +/* + * FIB commands + */ + +#define TestCommandResponse 1 +#define TestAdapterCommand 2 +/* + * Lowlevel and comm commands + */ +#define LastTestCommand 100 +#define ReinitHostNormCommandQueue 101 +#define ReinitHostHighCommandQueue 102 +#define ReinitHostHighRespQueue 103 +#define ReinitHostNormRespQueue 104 +#define ReinitAdapNormCommandQueue 105 +#define ReinitAdapHighCommandQueue 107 +#define ReinitAdapHighRespQueue 108 +#define ReinitAdapNormRespQueue 109 +#define InterfaceShutdown 110 +#define DmaCommandFib 120 +#define StartProfile 121 +#define TermProfile 122 +#define SpeedTest 123 +#define TakeABreakPt 124 +#define RequestPerfData 125 +#define SetInterruptDefTimer 126 +#define SetInterruptDefCount 127 +#define GetInterruptDefStatus 128 +#define LastCommCommand 129 +/* + * Filesystem commands + */ +#define NuFileSystem 300 +#define UFS 301 +#define HostFileSystem 302 +#define LastFileSystemCommand 303 +/* + * Container Commands + */ +#define ContainerCommand 500 +#define ContainerCommand64 501 +/* + * Cluster Commands + */ +#define ClusterCommand 550 +/* + * Scsi Port commands (scsi passthrough) + */ +#define ScsiPortCommand 600 +/* + * Misc house keeping and generic adapter initiated commands + */ +#define AifRequest 700 +#define CheckRevision 701 +#define FsaHostShutdown 702 +#define RequestAdapterInfo 703 +#define IsAdapterPaused 704 +#define SendHostTime 705 +#define LastMiscCommand 706 + +// +// Commands that will target the failover level on the FSA adapter +// + +enum fib_xfer_state { + HostOwned = (1<<0), + AdapterOwned = (1<<1), + FibInitialized = (1<<2), + FibEmpty = (1<<3), + AllocatedFromPool = (1<<4), + SentFromHost = (1<<5), + SentFromAdapter = (1<<6), + ResponseExpected = (1<<7), + NoResponseExpected = (1<<8), + AdapterProcessed = (1<<9), + HostProcessed = (1<<10), + HighPriority = (1<<11), + NormalPriority = (1<<12), + Async = (1<<13), + AsyncIo = (1<<13), // rpbfix: remove with new regime + PageFileIo = (1<<14), // rpbfix: remove with new regime + ShutdownRequest = (1<<15), + LazyWrite = (1<<16), // rpbfix: remove with new regime + AdapterMicroFib = (1<<17), + BIOSFibPath = (1<<18), + FastResponseCapable = (1<<19), + ApiFib = (1<<20) // Its an API Fib. +}; + +/* + * The following defines needs to be updated any time there is an + * incompatible change made to the aac_init structure. + */ + +#define ADAPTER_INIT_STRUCT_REVISION 3 + +struct aac_init +{ + u32 InitStructRevision; + u32 MiniPortRevision; + u32 fsrev; + u32 CommHeaderAddress; + u32 FastIoCommAreaAddress; + u32 AdapterFibsPhysicalAddress; + u32 AdapterFibsVirtualAddress; + u32 AdapterFibsSize; + u32 AdapterFibAlign; + u32 printfbuf; + u32 printfbufsiz; + u32 HostPhysMemPages; // number of 4k pages of host physical memory + u32 HostElapsedSeconds; // number of seconds since 1970. +}; + +enum aac_log_level { + LOG_INIT = 10, + LOG_INFORMATIONAL = 20, + LOG_WARNING = 30, + LOG_LOW_ERROR = 40, + LOG_MEDIUM_ERROR = 50, + LOG_HIGH_ERROR = 60, + LOG_PANIC = 70, + LOG_DEBUG = 80, + LOG_WINDBG_PRINT = 90 +}; + +#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT 0x030b +#define FSAFS_NTC_FIB_CONTEXT 0x030c + +struct aac_dev; + +struct adapter_ops +{ + void (*adapter_interrupt)(struct aac_dev *dev); + void (*adapter_notify)(struct aac_dev *dev, u32 event); + void (*adapter_enable_int)(struct aac_dev *dev, u32 event); + void (*adapter_disable_int)(struct aac_dev *dev, u32 event); +}; + +/* + * Define which interrupt handler needs to be installed + */ + +struct aac_driver_ident +{ + u16 vendor; + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; + int (*init)(struct aac_dev *dev, unsigned long num); + char * name; + char * vname; + char * model; +}; + +/* + * The adapter interface specs all queues to be located in the same + * physically contigous block. The host structure that defines the + * commuication queues will assume they are each a seperate physically + * contigous memory region that will support them all being one big + * contigous block. + * There is a command and response queue for each level and direction of + * commuication. These regions are accessed by both the host and adapter. + */ + +struct aac_queue { + u64 logical; /* This is the address we give the adapter */ + struct aac_entry *base; /* This is the system virtual address */ + struct aac_qhdr headers; /* A pointer to the producer and consumer queue headers for this queue */ + u32 entries; /* Number of queue entries on this queue */ + wait_queue_head_t qfull; /* Event to wait on if the queue is full */ + wait_queue_head_t cmdready; /* Indicates there is a Command ready from the adapter on this queue. */ + /* This is only valid for adapter to host command queues. */ + spinlock_t *lock; /* Spinlock for this queue must take this lock before accessing the lock */ + spinlock_t lockdata; /* Actual lock (used only on one side of the lock) */ + unsigned long SavedIrql; /* Previous IRQL when the spin lock is taken */ + u32 padding; /* Padding - FIXME - can remove I believe */ + struct list_head cmdq; /* A queue of FIBs which need to be prcessed by the FS thread. This is */ + /* only valid for command queues which receive entries from the adapter. */ + struct list_head pendingq; /* A queue of outstanding fib's to the adapter. */ + unsigned long numpending; /* Number of entries on outstanding queue. */ + struct aac_dev * dev; /* Back pointer to adapter structure */ +}; + +/* + * Message queues. The order here is important, see also the + * queue type ordering + */ + +struct aac_queue_block +{ + struct aac_queue queue[8]; +}; + +/* + * SaP1 Message Unit Registers + */ + +struct sa_drawbridge_CSR { + // Offset | Name + u32 reserved[10]; // 00h-27h | Reserved + u8 LUT_Offset; // 28h | Looup Table Offset + u8 reserved1[3]; // 29h-2bh | Reserved + u32 LUT_Data; // 2ch | Looup Table Data + u32 reserved2[26]; // 30h-97h | Reserved + u16 PRICLEARIRQ; // 98h | Primary Clear Irq + u16 SECCLEARIRQ; // 9ah | Secondary Clear Irq + u16 PRISETIRQ; // 9ch | Primary Set Irq + u16 SECSETIRQ; // 9eh | Secondary Set Irq + u16 PRICLEARIRQMASK; // a0h | Primary Clear Irq Mask + u16 SECCLEARIRQMASK; // a2h | Secondary Clear Irq Mask + u16 PRISETIRQMASK; // a4h | Primary Set Irq Mask + u16 SECSETIRQMASK; // a6h | Secondary Set Irq Mask + u32 MAILBOX0; // a8h | Scratchpad 0 + u32 MAILBOX1; // ach | Scratchpad 1 + u32 MAILBOX2; // b0h | Scratchpad 2 + u32 MAILBOX3; // b4h | Scratchpad 3 + u32 MAILBOX4; // b8h | Scratchpad 4 + u32 MAILBOX5; // bch | Scratchpad 5 + u32 MAILBOX6; // c0h | Scratchpad 6 + u32 MAILBOX7; // c4h | Scratchpad 7 + + u32 ROM_Setup_Data; // c8h | Rom Setup and Data + u32 ROM_Control_Addr; // cch | Rom Control and Address + + u32 reserved3[12]; // d0h-ffh | reserved + u32 LUT[64]; // 100h-1ffh| Lookup Table Entries + + // + // TO DO + // need to add DMA, I2O, UART, etc registers form 80h to 364h + // + +}; + +#define Mailbox0 SaDbCSR.MAILBOX0 +#define Mailbox1 SaDbCSR.MAILBOX1 +#define Mailbox2 SaDbCSR.MAILBOX2 +#define Mailbox3 SaDbCSR.MAILBOX3 +#define Mailbox4 SaDbCSR.MAILBOX4 +#define Mailbox5 SaDbCSR.MAILBOX5 +#define Mailbox7 SaDbCSR.MAILBOX7 + +#define DoorbellReg_p SaDbCSR.PRISETIRQ +#define DoorbellReg_s SaDbCSR.SECSETIRQ +#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ + + +#define DOORBELL_0 cpu_to_le16(0x0001) +#define DOORBELL_1 cpu_to_le16(0x0002) +#define DOORBELL_2 cpu_to_le16(0x0004) +#define DOORBELL_3 cpu_to_le16(0x0008) +#define DOORBELL_4 cpu_to_le16(0x0010) +#define DOORBELL_5 cpu_to_le16(0x0020) +#define DOORBELL_6 cpu_to_le16(0x0040) + + +#define PrintfReady DOORBELL_5 +#define PrintfDone DOORBELL_5 + +struct sa_registers { + struct sa_drawbridge_CSR SaDbCSR; /* 98h - c4h */ +}; + + +#define Sa_MINIPORT_REVISION 1 + +#define sa_readw(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) +#define sa_readl(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) +#define sa_writew(AEP, CSR, value) writew(value, &((AEP)->regs.sa->CSR)) +#define sa_writel(AEP, CSR, value) writel(value, &((AEP)->regs.sa->CSR)) + +/* + * Rx Message Unit Registers + */ + +struct rx_mu_registers { + // Local | PCI* | Name + // | | + u32 ARSR; // 1300h | 00h | APIC Register Select Register + u32 reserved0; // 1304h | 04h | Reserved + u32 AWR; // 1308h | 08h | APIC Window Register + u32 reserved1; // 130Ch | 0Ch | Reserved + u32 IMRx[2]; // 1310h | 10h | Inbound Message Registers + u32 OMRx[2]; // 1318h | 18h | Outbound Message Registers + u32 IDR; // 1320h | 20h | Inbound Doorbell Register + u32 IISR; // 1324h | 24h | Inbound Interrupt Status Register + u32 IIMR; // 1328h | 28h | Inbound Interrupt Mask Register + u32 ODR; // 132Ch | 2Ch | Outbound Doorbell Register + u32 OISR; // 1330h | 30h | Outbound Interrupt Status Register + u32 OIMR; // 1334h | 34h | Outbound Interrupt Mask Register + // * Must access through ATU Inbound Translation Window +}; + +struct rx_inbound { + u32 Mailbox[8]; +}; + +#define InboundMailbox0 IndexRegs.Mailbox[0] +#define InboundMailbox1 IndexRegs.Mailbox[1] +#define InboundMailbox2 IndexRegs.Mailbox[2] +#define InboundMailbox3 IndexRegs.Mailbox[3] +#define InboundMailbox4 IndexRegs.Mailbox[4] + +#define INBOUNDDOORBELL_0 cpu_to_le32(0x00000001) +#define INBOUNDDOORBELL_1 cpu_to_le32(0x00000002) +#define INBOUNDDOORBELL_2 cpu_to_le32(0x00000004) +#define INBOUNDDOORBELL_3 cpu_to_le32(0x00000008) +#define INBOUNDDOORBELL_4 cpu_to_le32(0x00000010) +#define INBOUNDDOORBELL_5 cpu_to_le32(0x00000020) +#define INBOUNDDOORBELL_6 cpu_to_le32(0x00000040) + +#define OUTBOUNDDOORBELL_0 cpu_to_le32(0x00000001) +#define OUTBOUNDDOORBELL_1 cpu_to_le32(0x00000002) +#define OUTBOUNDDOORBELL_2 cpu_to_le32(0x00000004) +#define OUTBOUNDDOORBELL_3 cpu_to_le32(0x00000008) +#define OUTBOUNDDOORBELL_4 cpu_to_le32(0x00000010) + +#define InboundDoorbellReg MUnit.IDR +#define OutboundDoorbellReg MUnit.ODR + +struct rx_registers { + struct rx_mu_registers MUnit; // 1300h - 1334h + u32 reserved1[6]; // 1338h - 134ch + struct rx_inbound IndexRegs; +}; + +#define rx_readb(AEP, CSR) readb(&((AEP)->regs.rx->CSR)) +#define rx_readl(AEP, CSR) readl(&((AEP)->regs.rx->CSR)) +#define rx_writeb(AEP, CSR, value) writeb(value, &((AEP)->regs.rx->CSR)) +#define rx_writel(AEP, CSR, value) writel(value, &((AEP)->regs.rx->CSR)) + +struct fib; + +typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); + +struct aac_fib_context { + s16 type; // used for verification of structure + s16 size; + u32 jiffies; // used for cleanup + struct list_head next; // used to link context's into a linked list + struct semaphore wait_sem; // this is used to wait for the next fib to arrive. + int wait; // Set to true when thread is in WaitForSingleObject + unsigned long count; // total number of FIBs on FibList + struct list_head fibs; +}; + +#define MAXIMUM_NUM_CONTAINERS 64 // 4 Luns * 16 Targets +#define MAXIMUM_NUM_ADAPTERS 8 + +struct fsa_scsi_hba { + unsigned long size[MAXIMUM_NUM_CONTAINERS]; + unsigned long type[MAXIMUM_NUM_CONTAINERS]; + unsigned char valid[MAXIMUM_NUM_CONTAINERS]; + unsigned char ro[MAXIMUM_NUM_CONTAINERS]; + unsigned char locked[MAXIMUM_NUM_CONTAINERS]; + unsigned char deleted[MAXIMUM_NUM_CONTAINERS]; + long devno[MAXIMUM_NUM_CONTAINERS]; +}; + +struct fib { + void *next; /* this is used by the allocator */ + s16 type; + s16 size; + /* + * The Adapter that this I/O is destined for. + */ + struct aac_dev *dev; + u64 logicaladdr; /* 64 bit */ + /* + * This is the event the sendfib routine will wait on if the + * caller did not pass one and this is synch io. + */ + struct semaphore event_wait; + spinlock_t event_lock; + + unsigned long done; /* gets set to 1 when fib is complete */ + fib_callback callback; + void *callback_data; + unsigned long flags; + /* + * The following is used to put this fib context onto the + * Outstanding I/O queue. + */ + struct list_head queue; + + void *data; + struct hw_fib *fib; /* Actual shared object */ +}; + +struct aac_dev +{ + struct aac_dev *next; + const char *name; + int id; + + u16 irq_mask; + /* + * Map for 128 fib objects (64k) + */ + dma_addr_t hw_fib_pa; + struct hw_fib *hw_fib_va; + /* + * Fib Headers + */ + struct fib fibs[AAC_NUM_FIB]; + struct fib *free_fib; + struct fib *timeout_fib; + spinlock_t fib_lock; + + struct aac_queue_block *queues; + /* + * The user API will use an IOCTL to register itself to receive + * FIBs from the adapter. The following list is used to keep + * track of all the threads that have requested these FIBs. The + * mutex is used to synchronize access to all data associated + * with the adapter fibs. + */ + struct list_head fib_list; + + struct adapter_ops a_ops; + unsigned long fsrev; /* Main driver's revision number */ + + struct aac_init *init; /* Holds initialization info to communicate with adapter */ + dma_addr_t init_pa; /* Holds physical address of the init struct */ + + struct pci_dev *pdev; /* Our PCI interface */ + void * printfbuf; /* pointer to buffer used for printf's from the adapter */ + void * comm_addr; /* Base address of Comm area */ + dma_addr_t comm_phys; /* Physical Address of Comm area */ + size_t comm_size; + + struct Scsi_Host *scsi_host_ptr; + struct fsa_scsi_hba fsa_dev; + int thread_pid; + int cardtype; + + /* + * The following is the device specific extension. + */ + union + { + struct sa_registers *sa; + struct rx_registers *rx; + } regs; + /* + * The following is the number of the individual adapter + */ + long devnum; + int aif_thread; + struct completion aif_completion; +}; + +#define AllocateAndMapFibSpace(dev, MapFibContext) \ + dev->a_ops.AllocateAndMapFibSpace(dev, MapFibContext) + +#define UnmapAndFreeFibSpace(dev, MapFibContext) \ + dev->a_ops.UnmapAndFreeFibSpace(dev, MapFibContext) + +#define aac_adapter_interrupt(dev) \ + dev->a_ops.adapter_interrupt(dev) + +#define aac_adapter_notify(dev, event) \ + dev->a_ops.adapter_notify(dev, event) + +#define aac_adapter_enable_int(dev, event) \ + dev->a_ops.adapter_enable_int(dev, event) + +#define aac_adapter_disable_int(dev, event) \ + dev->a_ops.adapter_disable_int(dev, event) + + + +#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001) + +/* + * Define the command values + */ + +#define Null 0 +#define GetAttributes 1 +#define SetAttributes 2 +#define Lookup 3 +#define ReadLink 4 +#define Read 5 +#define Write 6 +#define Create 7 +#define MakeDirectory 8 +#define SymbolicLink 9 +#define MakeNode 10 +#define Removex 11 +#define RemoveDirectoryx 12 +#define Rename 13 +#define Link 14 +#define ReadDirectory 15 +#define ReadDirectoryPlus 16 +#define FileSystemStatus 17 +#define FileSystemInfo 18 +#define PathConfigure 19 +#define Commit 20 +#define Mount 21 +#define UnMount 22 +#define Newfs 23 +#define FsCheck 24 +#define FsSync 25 +#define SimReadWrite 26 +#define SetFileSystemStatus 27 +#define BlockRead 28 +#define BlockWrite 29 +#define NvramIoctl 30 +#define FsSyncWait 31 +#define ClearArchiveBit 32 +#define SetAcl 33 +#define GetAcl 34 +#define AssignAcl 35 +#define FaultInsertion 36 /* Fault Insertion Command */ +#define CrazyCache 37 /* Crazycache */ + +#define MAX_FSACOMMAND_NUM 38 + + +/* + * Define the status returns. These are very unixlike although + * most are not in fact used + */ + +#define ST_OK 0 +#define ST_PERM 1 +#define ST_NOENT 2 +#define ST_IO 5 +#define ST_NXIO 6 +#define ST_E2BIG 7 +#define ST_ACCES 13 +#define ST_EXIST 17 +#define ST_XDEV 18 +#define ST_NODEV 19 +#define ST_NOTDIR 20 +#define ST_ISDIR 21 +#define ST_INVAL 22 +#define ST_FBIG 27 +#define ST_NOSPC 28 +#define ST_ROFS 30 +#define ST_MLINK 31 +#define ST_WOULDBLOCK 35 +#define ST_NAMETOOLONG 63 +#define ST_NOTEMPTY 66 +#define ST_DQUOT 69 +#define ST_STALE 70 +#define ST_REMOTE 71 +#define ST_BADHANDLE 10001 +#define ST_NOT_SYNC 10002 +#define ST_BAD_COOKIE 10003 +#define ST_NOTSUPP 10004 +#define ST_TOOSMALL 10005 +#define ST_SERVERFAULT 10006 +#define ST_BADTYPE 10007 +#define ST_JUKEBOX 10008 +#define ST_NOTMOUNTED 10009 +#define ST_MAINTMODE 10010 +#define ST_STALEACL 10011 + +/* + * On writes how does the client want the data written. + */ + +#define CACHE_CSTABLE 1 +#define CACHE_UNSTABLE 2 + +/* + * Lets the client know at which level the data was commited on + * a write request + */ + +#define CMFILE_SYNCH_NVRAM 1 +#define CMDATA_SYNCH_NVRAM 2 +#define CMFILE_SYNCH 3 +#define CMDATA_SYNCH 4 +#define CMUNSTABLE 5 + +struct aac_read +{ + u32 command; + u32 cid; + u32 block; + u32 count; + struct sgmap sg; // Must be last in struct because it is variable +}; + +struct aac_read_reply +{ + u32 status; + u32 count; +}; + +struct aac_write +{ + u32 command; + u32 cid; + u32 block; + u32 count; + u32 stable; + struct sgmap sg; // Must be last in struct because it is variable +}; + +struct aac_write_reply +{ + u32 status; + u32 count; + u32 committed; +}; + + +/* + * Object-Server / Volume-Manager Dispatch Classes + */ + +#define VM_Null 0 +#define VM_NameServe 1 +#define VM_ContainerConfig 2 +#define VM_Ioctl 3 +#define VM_FilesystemIoctl 4 +#define VM_CloseAll 5 +#define VM_CtBlockRead 6 +#define VM_CtBlockWrite 7 +#define VM_SliceBlockRead 8 /* raw access to configured "storage objects" */ +#define VM_SliceBlockWrite 9 +#define VM_DriveBlockRead 10 /* raw access to physical devices */ +#define VM_DriveBlockWrite 11 +#define VM_EnclosureMgt 12 /* enclosure management */ +#define VM_Unused 13 /* used to be diskset management */ +#define VM_CtBlockVerify 14 +#define VM_CtPerf 15 /* performance test */ +#define VM_CtBlockRead64 16 +#define VM_CtBlockWrite64 17 +#define VM_CtBlockVerify64 18 + +#define MAX_VMCOMMAND_NUM 19 /* used for sizing stats array - leave last */ + +/* + * Descriptive information (eg, vital stats) + * that a content manager might report. The + * FileArray filesystem component is one example + * of a content manager. Raw mode might be + * another. + */ + +struct aac_fsinfo { + u32 fsTotalSize; /* Consumed by fs, incl. metadata */ + u32 fsBlockSize; + u32 fsFragSize; + u32 fsMaxExtendSize; + u32 fsSpaceUnits; + u32 fsMaxNumFiles; + u32 fsNumFreeFiles; + u32 fsInodeDensity; +}; /* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */ + +union aac_contentinfo { + struct aac_fsinfo filesys; /* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */ +}; + +/* + * Query for "mountable" objects, ie, objects that are typically + * associated with a drive letter on the client (host) side. + */ + +struct aac_mntent { + u32 oid; + char name[16]; // if applicable + struct creation_info create_info; // if applicable + u32 capacity; + u32 vol; // substrate structure + u32 obj; // FT_FILESYS, FT_DATABASE, etc. + u32 state; // unready for mounting, readonly, etc. + union aac_contentinfo fileinfo; // Info specific to content manager (eg, filesystem) + u32 altoid; // != oid <==> snapshot or broken mirror exists +}; + +#define FSCS_READONLY 0x0002 /* possible result of broken mirror */ + +struct aac_query_mount { + u32 command; + u32 type; + u32 count; +}; + +struct aac_mount { + u32 status; + u32 type; /* should be same as that requested */ + u32 count; + struct aac_mntent mnt[1]; +}; + +/* + * The following command is sent to shut down each container. + */ + +struct aac_close { + u32 command; + u32 cid; +}; + +struct aac_query_disk +{ + s32 cnum; + s32 bus; + s32 target; + s32 lun; + u32 valid; + u32 locked; + u32 deleted; + s32 instance; + s8 name[10]; + u32 unmapped; +}; + +struct aac_delete_disk { + u32 disknum; + u32 cnum; +}; + +struct fib_ioctl +{ + char *fibctx; + int wait; + char *fib; +}; + +struct revision +{ + int compat; + unsigned long version; + unsigned long build; +}; + +/* + * Ugly - non Linux like ioctl coding for back compat. + */ + +#define CTL_CODE(function, method) ( \ + (4<< 16) | ((function) << 2) | (method) \ +) + +/* + * Define the method codes for how buffers are passed for I/O and FS + * controls + */ + +#define METHOD_BUFFERED 0 +#define METHOD_NEITHER 3 + +/* + * Filesystem ioctls + */ + +#define FSACTL_SENDFIB CTL_CODE(2050, METHOD_BUFFERED) +#define FSACTL_DELETE_DISK 0x163 +#define FSACTL_QUERY_DISK 0x173 +#define FSACTL_OPEN_GET_ADAPTER_FIB CTL_CODE(2100, METHOD_BUFFERED) +#define FSACTL_GET_NEXT_ADAPTER_FIB CTL_CODE(2101, METHOD_BUFFERED) +#define FSACTL_CLOSE_GET_ADAPTER_FIB CTL_CODE(2102, METHOD_BUFFERED) +#define FSACTL_MINIPORT_REV_CHECK CTL_CODE(2107, METHOD_BUFFERED) +#define FSACTL_FORCE_DELETE_DISK CTL_CODE(2120, METHOD_NEITHER) + +struct aac_common +{ + /* + * If this value is set to 1 then interrupt moderation will occur + * in the base commuication support. + */ + unsigned long irq_mod; + int peak_fibs; + int zero_fibs; + unsigned long fib_timeouts; + /* + * Statistical counters in debug mode + */ +#ifdef DBG + unsigned long FibsSent; + unsigned long FibRecved; + unsigned long NoResponseSent; + unsigned long NoResponseRecved; + unsigned long AsyncSent; + unsigned long AsyncRecved; + unsigned long NormalSent; + unsigned long NormalRecved; +#endif +}; + +extern struct aac_common aac_config; + + +/* + * The following macro is used when sending and receiving FIBs. It is + * only used for debugging. + */ + +#if DBG +#define FIB_COUNTER_INCREMENT(counter) (counter)++ +#else +#define FIB_COUNTER_INCREMENT(counter) +#endif + +/* + * Adapter direct commands + */ + +#define BREAKPOINT_REQUEST 0x00000004 +#define INIT_STRUCT_BASE_ADDRESS 0x00000005 +#define SEND_SYNCHRONOUS_FIB 0x0000000c + +/* + * Adapter Status Register + * + * Phase Staus mailbox is 32bits: + * <31:16> = Phase Status + * <15:0> = Phase + * + * The adapter reports is present state through the phase. Only + * a single phase should be ever be set. Each phase can have multiple + * phase status bits to provide more detailed information about the + * state of the board. Care should be taken to ensure that any phase + * status bits that are set when changing the phase are also valid + * for the new phase or be cleared out. Adapter software (monitor, + * iflash, kernel) is responsible for properly maintining the phase + * status mailbox when it is running. + * + * MONKER_API Phases + * + * Phases are bit oriented. It is NOT valid to have multiple bits set + */ + +#define SELF_TEST_FAILED cpu_to_le32(0x00000004) +#define KERNEL_UP_AND_RUNNING cpu_to_le32(0x00000080) +#define KERNEL_PANIC cpu_to_le32(0x00000100) + +/* + * Doorbell bit defines + */ + +#define DoorBellPrintfDone cpu_to_le32(1<<5) // Host -> Adapter +#define DoorBellAdapterNormCmdReady cpu_to_le32(1<<1) // Adapter -> Host +#define DoorBellAdapterNormRespReady cpu_to_le32(1<<2) // Adapter -> Host +#define DoorBellAdapterNormCmdNotFull cpu_to_le32(1<<3) // Adapter -> Host +#define DoorBellAdapterNormRespNotFull cpu_to_le32(1<<4) // Adapter -> Host +#define DoorBellPrintfReady cpu_to_le32(1<<5) // Adapter -> Host + +/* + * For FIB communication, we need all of the following things + * to send back to the user. + */ + +#define AifCmdEventNotify 1 /* Notify of event */ +#define AifCmdJobProgress 2 /* Progress report */ +#define AifCmdAPIReport 3 /* Report from other user of API */ +#define AifCmdDriverNotify 4 /* Notify host driver of event */ +#define AifReqJobList 100 /* Gets back complete job list */ +#define AifReqJobsForCtr 101 /* Gets back jobs for specific container */ +#define AifReqJobsForScsi 102 /* Gets back jobs for specific SCSI device */ +#define AifReqJobReport 103 /* Gets back a specific job report or list of them */ +#define AifReqTerminateJob 104 /* Terminates job */ +#define AifReqSuspendJob 105 /* Suspends a job */ +#define AifReqResumeJob 106 /* Resumes a job */ +#define AifReqSendAPIReport 107 /* API generic report requests */ +#define AifReqAPIJobStart 108 /* Start a job from the API */ +#define AifReqAPIJobUpdate 109 /* Update a job report from the API */ +#define AifReqAPIJobFinish 110 /* Finish a job from the API */ + +/* + * Adapter Initiated FIB command structures. Start with the adapter + * initiated FIBs that really come from the adapter, and get responded + * to by the host. + */ + +struct aac_aifcmd { + u32 command; /* Tell host what type of notify this is */ + u32 seqnum; /* To allow ordering of reports (if necessary) */ + u8 data[1]; /* Undefined length (from kernel viewpoint) */ +}; + +/* + * Adapter Information Block + * + * This is returned by the RequestAdapterInfo block + */ + +struct aac_adapter_info +{ + u32 platform; + u32 cpu; + u32 subcpu; + u32 clock; + u32 execmem; + u32 buffermem; + u32 totalmem; + u32 kernelrev; + u32 kernelbuild; + u32 monitorrev; + u32 monitorbuild; + u32 hwrev; + u32 hwbuild; + u32 biosrev; + u32 biosbuild; + u32 clustering; + u32 clustermask; + u64 serial; + u32 battery; + u32 options; + u32 OEM; +}; + +static inline u32 fib2addr(struct hw_fib *hw) +{ + return (u32)hw; +} + +static inline struct hw_fib *addr2fib(u32 addr) +{ + return (struct hw_fib *)addr; +} + +const char *aac_driverinfo(struct Scsi_Host *); +struct fib *fib_alloc(struct aac_dev *dev); +int fib_setup(struct aac_dev *dev); +void fib_map_free(struct aac_dev *dev); +void fib_free(struct fib * context); +void fib_init(struct fib * context); +void fib_dealloc(struct fib * context); +void aac_printf(struct aac_dev *dev, u32 val); +int fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt); +int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry); +int aac_consumer_avail(struct aac_dev * dev, struct aac_queue * q); +void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum); +int fib_complete(struct fib * context); +#define fib_data(fibctx) ((void *)(fibctx)->fib->data) +int aac_detach(struct aac_dev *dev); +struct aac_dev *aac_init_adapter(struct aac_dev *dev); +int aac_get_containers(struct aac_dev *dev); +int aac_scsi_cmd(Scsi_Cmnd *scsi_cmnd_ptr); +int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg); +int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg); +int aac_rx_init(struct aac_dev *dev, unsigned long devNumber); +int aac_sa_init(struct aac_dev *dev, unsigned long devNumber); +unsigned int aac_response_normal(struct aac_queue * q); +unsigned int aac_command_normal(struct aac_queue * q); +int aac_command_thread(struct aac_dev * dev); +int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); +int fib_adapter_complete(struct fib * fibptr, unsigned short size); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/commctrl.c linux-2.5/drivers/scsi/aacraid/commctrl.c --- linux-2.5.13/drivers/scsi/aacraid/commctrl.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/commctrl.c Thu Dec 13 16:32:36 2001 @@ -0,0 +1,410 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commctrl.c + * + * Abstract: Contains all routines for control of the AFA comm layer + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * ioctl_send_fib - send a FIB from userspace + * @dev: adapter is being processed + * @arg: arguments to the ioctl call + * + * This routine sends a fib to the adapter on behalf of a user level + * program. + */ + +static int ioctl_send_fib(struct aac_dev * dev, void *arg) +{ + struct hw_fib * kfib; + struct fib *fibptr; + + fibptr = fib_alloc(dev); + if(fibptr == NULL) + return -ENOMEM; + + kfib = fibptr->fib; + /* + * First copy in the header so that we can check the size field. + */ + if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { + fib_free(fibptr); + return -EFAULT; + } + /* + * Since we copy based on the fib header size, make sure that we + * will not overrun the buffer when we copy the memory. Return + * an error if we would. + */ + if(le32_to_cpu(kfib->header.Size) > sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) { + fib_free(fibptr); + return -EINVAL; + } + + if (copy_from_user((void *) kfib, arg, le32_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr))) { + fib_free(fibptr); + return -EFAULT; + } + + if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) { + aac_adapter_interrupt(dev); + /* + * Since we didn't really send a fib, zero out the state to allow + * cleanup code not to assert. + */ + kfib->header.XferState = 0; + } else { + if (fib_send(kfib->header.Command, fibptr, le32_to_cpu(kfib->header.Size) , FsaNormal, + 1, 1, NULL, NULL) != 0) + { + fib_free(fibptr); + return -EINVAL; + } + if (fib_complete(fibptr) != 0) { + fib_free(fibptr); + return -EINVAL; + } + } + /* + * Make sure that the size returned by the adapter (which includes + * the header) is less than or equal to the size of a fib, so we + * don't corrupt application data. Then copy that size to the user + * buffer. (Don't try to add the header information again, since it + * was already included by the adapter.) + */ + + if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) { + fib_free(fibptr); + return -EFAULT; + } + fib_free(fibptr); + return 0; +} + +/** + * open_getadapter_fib - Get the next fib + * + * This routine will get the next Fib, if available, from the AdapterFibContext + * passed in from the user. + */ + +static int open_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct aac_fib_context * fibctx; + int status; + unsigned long flags; + + fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); + if (fibctx == NULL) { + status = -ENOMEM; + } else { + fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; + fibctx->size = sizeof(struct aac_fib_context); + /* + * Initialize the mutex used to wait for the next AIF. + */ + init_MUTEX_LOCKED(&fibctx->wait_sem); + fibctx->wait = 0; + /* + * Initialize the fibs and set the count of fibs on + * the list to 0. + */ + fibctx->count = 0; + INIT_LIST_HEAD(&fibctx->fibs); + fibctx->jiffies = jiffies/HZ; + /* + * Now add this context onto the adapter's + * AdapterFibContext list. + */ + spin_lock_irqsave(&dev->fib_lock, flags); + list_add_tail(&fibctx->next, &dev->fib_list); + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (copy_to_user(arg, &fibctx, sizeof(struct aac_fib_context *))) { + status = -EFAULT; + } else { + status = 0; + } + } + return status; +} + +/** + * next_getadapter_fib - get the next fib + * @dev: adapter to use + * @arg: ioctl argument + * + * This routine will get the next Fib, if available, from the AdapterFibContext + * passed in from the user. + */ + +static int next_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct fib_ioctl f; + struct aac_fib_context *fibctx, *aifcp; + struct hw_fib * fib; + int status; + struct list_head * entry; + int found; + unsigned long flags; + + if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) + return -EFAULT; + /* + * Extract the AdapterFibContext from the Input parameters. + */ + fibctx = (struct aac_fib_context *) f.fibctx; + + /* + * Verify that the HANDLE passed in was a valid AdapterFibContext + * + * Search the list of AdapterFibContext addresses on the adapter + * to be sure this is a valid address + */ + found = 0; + entry = dev->fib_list.next; + + while(entry != &dev->fib_list) { + aifcp = list_entry(entry, struct aac_fib_context, next); + if(fibctx == aifcp) { /* We found a winner */ + found = 1; + break; + } + entry = entry->next; + } + if (found == 0) + return -EINVAL; + + if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (fibctx->size != sizeof(struct aac_fib_context))) + return -EINVAL; + status = 0; + spin_lock_irqsave(&dev->fib_lock, flags); + /* + * If there are no fibs to send back, then either wait or return + * -EAGAIN + */ +return_fib: + if (!list_empty(&fibctx->fibs)) { + struct list_head * entry; + /* + * Pull the next fib from the fibs + */ + entry = fibctx->fibs.next; + list_del(entry); + + fib = list_entry(entry, struct hw_fib, header.FibLinks); + fibctx->count--; + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (copy_to_user(f.fib, fib, sizeof(struct hw_fib))) { + kfree(fib); + return -EFAULT; + } + /* + * Free the space occupied by this copy of the fib. + */ + kfree(fib); + status = 0; + fibctx->jiffies = jiffies/HZ; + } else { + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (f.wait) { + if(down_interruptible(&fibctx->wait_sem) < 0) { + status = -EINTR; + } else { + /* Lock again and retry */ + spin_lock_irqsave(&dev->fib_lock, flags); + goto return_fib; + } + } else { + status = -EAGAIN; + } + } + return status; +} + +int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) +{ + struct hw_fib *fib; + + /* + * First free any FIBs that have not been consumed. + */ + while (!list_empty(&fibctx->fibs)) { + struct list_head * entry; + /* + * Pull the next fib from the fibs + */ + entry = fibctx->fibs.next; + list_del(entry); + fib = list_entry(entry, struct hw_fib, header.FibLinks); + fibctx->count--; + /* + * Free the space occupied by this copy of the fib. + */ + kfree(fib); + } + /* + * Remove the Context from the AdapterFibContext List + */ + list_del(&fibctx->next); + /* + * Invalidate context + */ + fibctx->type = 0; + /* + * Free the space occupied by the Context + */ + kfree(fibctx); + return 0; +} + +/** + * close_getadapter_fib - close down user fib context + * @dev: adapter + * @arg: ioctl arguments + * + * This routine will close down the fibctx passed in from the user. + */ + +static int close_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct aac_fib_context *fibctx, *aifcp; + int status; + unsigned long flags; + struct list_head * entry; + int found; + + /* + * Extract the fibctx from the input parameters + */ + fibctx = arg; + + /* + * Verify that the HANDLE passed in was a valid AdapterFibContext + * + * Search the list of AdapterFibContext addresses on the adapter + * to be sure this is a valid address + */ + + found = 0; + entry = dev->fib_list.next; + + while(entry != &dev->fib_list) { + aifcp = list_entry(entry, struct aac_fib_context, next); + if(fibctx == aifcp) { /* We found a winner */ + found = 1; + break; + } + entry = entry->next; + } + + if(found == 0) + return 0; /* Already gone */ + + if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (fibctx->size != sizeof(struct aac_fib_context))) + return -EINVAL; + spin_lock_irqsave(&dev->fib_lock, flags); + status = aac_close_fib_context(dev, fibctx); + spin_unlock_irqrestore(&dev->fib_lock, flags); + return status; +} + +/** + * check_revision - close down user fib context + * @dev: adapter + * @arg: ioctl arguments + * + * This routine returns the firmware version. + * Under Linux, there have been no version incompatibilities, so this is simple! + */ + +static int check_revision(struct aac_dev *dev, void *arg) +{ + struct revision response; + + response.compat = 1; + response.version = 0x03000400; + response.build = 0x5125; + + if (copy_to_user(arg, &response, sizeof(response))) + return -EFAULT; + return 0; +} + + +int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg) +{ + int status; + + /* + * HBA gets first crack + */ + + status = aac_dev_ioctl(dev, cmd, arg); + if(status != -ENOTTY) + return status; + + switch (cmd) { + case FSACTL_MINIPORT_REV_CHECK: + status = check_revision(dev, arg); + break; + case FSACTL_SENDFIB: + status = ioctl_send_fib(dev, arg); + break; + case FSACTL_OPEN_GET_ADAPTER_FIB: + status = open_getadapter_fib(dev, arg); + break; + case FSACTL_GET_NEXT_ADAPTER_FIB: + status = next_getadapter_fib(dev, arg); + break; + case FSACTL_CLOSE_GET_ADAPTER_FIB: + status = close_getadapter_fib(dev, arg); + break; + default: + status = -ENOTTY; + break; + } + return status; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/comminit.c linux-2.5/drivers/scsi/aacraid/comminit.c --- linux-2.5.13/drivers/scsi/aacraid/comminit.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/comminit.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,332 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comminit.c + * + * Abstract: This supports the initialization of the host adapter commuication interface. + * This is a platform dependent module for the pci cyclone board. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +struct aac_common aac_config; + +static struct aac_dev *devices; + +static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign) +{ + unsigned char *base; + unsigned long size, align; + unsigned long fibsize = 4096; + unsigned long printfbufsiz = 256; + struct aac_init *init; + dma_addr_t phys; + + size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz; + + base = pci_alloc_consistent(dev->pdev, size, &phys); + if(base == NULL) + { + printk(KERN_ERR "aacraid: unable to create mapping.\n"); + return 0; + } + dev->comm_addr = (void *)base; + dev->comm_phys = phys; + dev->comm_size = size; + + dev->init = (struct aac_init *)(base + fibsize); + dev->init_pa = phys + fibsize; + + init = dev->init; + + init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION); + init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION); + init->fsrev = cpu_to_le32(dev->fsrev); + + /* + * Adapter Fibs are the first thing allocated so that they + * start page aligned + */ + init->AdapterFibsVirtualAddress = cpu_to_le32((long)base); + init->AdapterFibsPhysicalAddress = cpu_to_le32(phys); + init->AdapterFibsSize = cpu_to_le32(fibsize); + init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); + + /* + * Increment the base address by the amount already used + */ + base = base + fibsize + sizeof(struct aac_init); + phys = phys + fibsize + sizeof(struct aac_init); + /* + * Align the beginning of Headers to commalign + */ + align = (commalign - ((unsigned long)(base) & (commalign - 1))); + base = base + align; + phys = phys + align; + /* + * Fill in addresses of the Comm Area Headers and Queues + */ + *commaddr = (unsigned long *)base; + init->CommHeaderAddress = cpu_to_le32(phys); + /* + * Increment the base address by the size of the CommArea + */ + base = base + commsize; + phys = phys + commsize; + /* + * Place the Printf buffer area after the Fast I/O comm area. + */ + dev->printfbuf = (void *)base; + init->printfbuf = cpu_to_le32(phys); + init->printfbufsiz = cpu_to_le32(printfbufsiz); + memset(base, 0, printfbufsiz); + return 1; +} + +static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize) +{ + q->numpending = 0; + q->dev = dev; + INIT_LIST_HEAD(&q->pendingq); + init_waitqueue_head(&q->cmdready); + INIT_LIST_HEAD(&q->cmdq); + init_waitqueue_head(&q->qfull); + spin_lock_init(&q->lockdata); + q->lock = &q->lockdata; + q->headers.producer = mem; + q->headers.consumer = mem+1; + *q->headers.producer = cpu_to_le32(qsize); + *q->headers.consumer = cpu_to_le32(qsize); + q->entries = qsize; +} + +/** + * aac_send_shutdown - shutdown an adapter + * @dev: Adapter to shutdown + * + * This routine will send a VM_CloseAll (shutdown) request to the adapter. + */ + +static int aac_send_shutdown(struct aac_dev * dev) +{ + struct fib * fibctx; + struct aac_close *cmd; + int status; + + fibctx = fib_alloc(dev); + fib_init(fibctx); + + cmd = (struct aac_close *) fib_data(fibctx); + + cmd->command = cpu_to_le32(VM_CloseAll); + cmd->cid = cpu_to_le32(0xffffffff); + + status = fib_send(ContainerCommand, + fibctx, + sizeof(struct aac_close), + FsaNormal, + 1, 1, + NULL, NULL); + + if (status == 0) + fib_complete(fibctx); + fib_free(fibctx); + return status; +} + +/** + * aac_detach - detach adapter + * @detach: adapter to disconnect + * + * Disconnect and shutdown an AAC based adapter, freeing resources + * as we go. + */ + +int aac_detach(struct aac_dev *detach) +{ + struct aac_dev **dev = &devices; + + while(*dev) + { + if(*dev == detach) + { + *dev = detach->next; + aac_send_shutdown(detach); + fib_map_free(detach); + pci_free_consistent(detach->pdev, detach->comm_size, detach->comm_addr, detach->comm_phys); + kfree(detach->queues); + return 1; + } + dev=&((*dev)->next); + } + BUG(); + return 0; +} + +/** + * aac_comm_init - Initialise FSA data structures + * @dev: Adapter to intialise + * + * Initializes the data structures that are required for the FSA commuication + * interface to operate. + * Returns + * 1 - if we were able to init the commuication interface. + * 0 - If there were errors initing. This is a fatal error. + */ + +int aac_comm_init(struct aac_dev * dev) +{ + unsigned long hdrsize = (sizeof(u32) * NUMBER_OF_COMM_QUEUES) * 2; + unsigned long queuesize = sizeof(struct aac_entry) * TOTAL_QUEUE_ENTRIES; + u32 *headers; + struct aac_entry * queues; + unsigned long size; + struct aac_queue_block * comm = dev->queues; + + /* + * Now allocate and initialize the zone structures used as our + * pool of FIB context records. The size of the zone is based + * on the system memory size. We also initialize the mutex used + * to protect the zone. + */ + spin_lock_init(&dev->fib_lock); + + /* + * Allocate the physically contigous space for the commuication + * queue headers. + */ + + size = hdrsize + queuesize; + + if (!aac_alloc_comm(dev, (void * *)&headers, size, QUEUE_ALIGNMENT)) + return -ENOMEM; + + queues = (struct aac_entry *)((unsigned char *)headers + hdrsize); + + /* Adapter to Host normal priority Command queue */ + comm->queue[HostNormCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES); + queues += HOST_NORM_CMD_ENTRIES; + headers += 2; + + /* Adapter to Host high priority command queue */ + comm->queue[HostHighCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostHighCmdQueue], headers, HOST_HIGH_CMD_ENTRIES); + + queues += HOST_HIGH_CMD_ENTRIES; + headers +=2; + + /* Host to adapter normal priority command queue */ + comm->queue[AdapNormCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapNormCmdQueue], headers, ADAP_NORM_CMD_ENTRIES); + + queues += ADAP_NORM_CMD_ENTRIES; + headers += 2; + + /* host to adapter high priority command queue */ + comm->queue[AdapHighCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapHighCmdQueue], headers, ADAP_HIGH_CMD_ENTRIES); + + queues += ADAP_HIGH_CMD_ENTRIES; + headers += 2; + + /* adapter to host normal priority response queue */ + comm->queue[HostNormRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES); + + queues += HOST_NORM_RESP_ENTRIES; + headers += 2; + + /* adapter to host high priority response queue */ + comm->queue[HostHighRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostHighRespQueue], headers, HOST_HIGH_RESP_ENTRIES); + + queues += HOST_HIGH_RESP_ENTRIES; + headers += 2; + + /* host to adapter normal priority response queue */ + comm->queue[AdapNormRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapNormRespQueue], headers, ADAP_NORM_RESP_ENTRIES); + + queues += ADAP_NORM_RESP_ENTRIES; + headers += 2; + + /* host to adapter high priority response queue */ + comm->queue[AdapHighRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapHighRespQueue], headers, ADAP_HIGH_RESP_ENTRIES); + + comm->queue[AdapNormCmdQueue].lock = comm->queue[HostNormRespQueue].lock; + comm->queue[AdapHighCmdQueue].lock = comm->queue[HostHighRespQueue].lock; + comm->queue[AdapNormRespQueue].lock = comm->queue[HostNormCmdQueue].lock; + comm->queue[AdapHighRespQueue].lock = comm->queue[HostHighCmdQueue].lock; + + return 0; +} + +struct aac_dev *aac_init_adapter(struct aac_dev *dev) +{ + /* + * Ok now init the communication subsystem + */ + dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL); + if (dev->queues == NULL) { + printk(KERN_ERR "Error could not allocate comm region.\n"); + return NULL; + } + memset(dev->queues, 0, sizeof(struct aac_queue_block)); + + if (aac_comm_init(dev)<0) + return NULL; + /* + * Initialize the list of fibs + */ + if(fib_setup(dev)<0) + return NULL; + + INIT_LIST_HEAD(&dev->fib_list); + spin_lock_init(&dev->fib_lock); + init_completion(&dev->aif_completion); + /* + * Add this adapter in to our dev List. + */ + dev->next = devices; + devices = dev; + return dev; +} + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/commsup.c linux-2.5/drivers/scsi/aacraid/commsup.c --- linux-2.5.13/drivers/scsi/aacraid/commsup.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/commsup.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,949 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commsup.c + * + * Abstract: Contain all routines that are required for FSA host/adapter + * commuication. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * fib_map_alloc - allocate the fib objects + * @dev: Adapter to allocate for + * + * Allocate and map the shared PCI space for the FIB blocks used to + * talk to the Adaptec firmware. + */ + +static int fib_map_alloc(struct aac_dev *dev) +{ + if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, &dev->hw_fib_pa))==NULL) + return -ENOMEM; + return 0; +} + +/** + * fib_map_free - free the fib objects + * @dev: Adapter to free + * + * Free the PCI mappings and the memory allocated for FIB blocks + * on this adapter. + */ + +void fib_map_free(struct aac_dev *dev) +{ + pci_free_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, dev->hw_fib_va, dev->hw_fib_pa); +} + +/** + * fib_setup - setup the fibs + * @dev: Adapter to set up + * + * Allocate the PCI space for the fibs, map it and then intialise the + * fib area, the unmapped fib data and also the free list + */ + +int fib_setup(struct aac_dev * dev) +{ + struct fib *fibptr; + struct hw_fib *fib; + dma_addr_t fibpa; + int i; + + if(fib_map_alloc(dev)<0) + return -ENOMEM; + + fib = dev->hw_fib_va; + fibpa = dev->hw_fib_pa; + memset(fib, 0, sizeof(struct hw_fib) * AAC_NUM_FIB); + /* + * Initialise the fibs + */ + for (i = 0, fibptr = &dev->fibs[i]; i < AAC_NUM_FIB; i++, fibptr++) + { + fibptr->dev = dev; + fibptr->fib = fib; + fibptr->data = (void *) fibptr->fib->data; + fibptr->next = fibptr+1; /* Forward chain the fibs */ + init_MUTEX_LOCKED(&fibptr->event_wait); + spin_lock_init(&fibptr->event_lock); + fib->header.XferState = cpu_to_le32(0xffffffff); + fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib)); + fibptr->logicaladdr = (unsigned long) fibpa; + fib = (struct hw_fib *)((unsigned char *)fib + sizeof(struct hw_fib)); + fibpa = fibpa + sizeof(struct hw_fib); + } + /* + * Add the fib chain to the free list + */ + dev->fibs[AAC_NUM_FIB-1].next = NULL; + /* + * Enable this to debug out of queue space + */ + dev->free_fib = &dev->fibs[0]; + return 0; +} + +/** + * fib_alloc - allocate a fib + * @dev: Adapter to allocate the fib for + * + * Allocate a fib from the adapter fib pool. If the pool is empty we + * wait for fibs to become free. + */ + +struct fib * fib_alloc(struct aac_dev *dev) +{ + struct fib * fibptr; + unsigned long flags; + + spin_lock_irqsave(&dev->fib_lock, flags); + fibptr = dev->free_fib; + if(!fibptr) + BUG(); + dev->free_fib = fibptr->next; + spin_unlock_irqrestore(&dev->fib_lock, flags); + /* + * Set the proper node type code and node byte size + */ + fibptr->type = FSAFS_NTC_FIB_CONTEXT; + fibptr->size = sizeof(struct fib); + /* + * Null out fields that depend on being zero at the start of + * each I/O + */ + fibptr->fib->header.XferState = cpu_to_le32(0); + fibptr->callback = NULL; + fibptr->callback_data = NULL; + + return fibptr; +} + +/** + * fib_free - free a fib + * @fibptr: fib to free up + * + * Frees up a fib and places it on the appropriate queue + * (either free or timed out) + */ + +void fib_free(struct fib * fibptr) +{ + unsigned long flags; + + spin_lock_irqsave(&fibptr->dev->fib_lock, flags); + + if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) { + aac_config.fib_timeouts++; + fibptr->next = fibptr->dev->timeout_fib; + fibptr->dev->timeout_fib = fibptr; + } else { + if (fibptr->fib->header.XferState != 0) { + printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", + fibptr, fibptr->fib->header.XferState); + } + fibptr->next = fibptr->dev->free_fib; + fibptr->dev->free_fib = fibptr; + } + spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags); +} + +/** + * fib_init - initialise a fib + * @fibptr: The fib to initialize + * + * Set up the generic fib fields ready for use + */ + +void fib_init(struct fib *fibptr) +{ + struct hw_fib *fib = fibptr->fib; + + fib->header.StructType = FIB_MAGIC; + fib->header.Size = cpu_to_le16(sizeof(struct hw_fib)); + fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable); + fib->header.SenderFibAddress = cpu_to_le32(0); + fib->header.ReceiverFibAddress = cpu_to_le32(0); + fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib)); +} + +/** + * fib_deallocate - deallocate a fib + * @fibptr: fib to deallocate + * + * Will deallocate and return to the free pool the FIB pointed to by the + * caller. + */ + +void fib_dealloc(struct fib * fibptr) +{ + struct hw_fib *fib = fibptr->fib; + if(fib->header.StructType != FIB_MAGIC) + BUG(); + fib->header.XferState = cpu_to_le32(0); +} + +/* + * Commuication primitives define and support the queuing method we use to + * support host to adapter commuication. All queue accesses happen through + * these routines and are the only routines which have a knowledge of the + * how these queues are implemented. + */ + +/** + * aac_get_entry - get a queue entry + * @dev: Adapter + * @qid: Queue Number + * @entry: Entry return + * @index: Index return + * @nonotify: notification control + * + * With a priority the routine returns a queue entry if the queue has free entries. If the queue + * is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is + * returned. + */ + +static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) +{ + struct aac_queue * q; + + /* + * All of the queues wrap when they reach the end, so we check + * to see if they have reached the end and if they have we just + * set the index back to zero. This is a wrap. You could or off + * the high bits in all updates but this is a bit faster I think. + */ + + q = &dev->queues->queue[qid]; + + *index = le32_to_cpu(*(q->headers.producer)); + if (*index - 2 == le32_to_cpu(*(q->headers.consumer))) + *nonotify = 1; + + if (qid == AdapHighCmdQueue) { + if (*index >= ADAP_HIGH_CMD_ENTRIES) + *index = 0; + } else if (qid == AdapNormCmdQueue) { + if (*index >= ADAP_NORM_CMD_ENTRIES) + *index = 0; /* Wrap to front of the Producer Queue. */ + } + else if (qid == AdapHighRespQueue) + { + if (*index >= ADAP_HIGH_RESP_ENTRIES) + *index = 0; + } + else if (qid == AdapNormRespQueue) + { + if (*index >= ADAP_NORM_RESP_ENTRIES) + *index = 0; /* Wrap to front of the Producer Queue. */ + } + else BUG(); + + if (*index + 1 == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */ + printk(KERN_WARNING "Queue %d full, %ld outstanding.\n", + qid, q->numpending); + return 0; + } else { + *entry = q->base + *index; + return 1; + } +} + +/** + * aac_queue_get - get the next free QE + * @dev: Adapter + * @index: Returned index + * @priority: Priority of fib + * @fib: Fib to associate with the queue entry + * @wait: Wait if queue full + * @fibptr: Driver fib object to go with fib + * @nonotify: Don't notify the adapter + * + * Gets the next free QE off the requested priorty adapter command + * queue and associates the Fib with the QE. The QE represented by + * index is ready to insert on the queue when this routine returns + * success. + */ + +static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * fib, int wait, struct fib * fibptr, unsigned long *nonotify) +{ + struct aac_entry * entry = NULL; + int map = 0; + struct aac_queue * q = &dev->queues->queue[qid]; + + spin_lock_irqsave(q->lock, q->SavedIrql); + + if (qid == AdapHighCmdQueue || qid == AdapNormCmdQueue) + { + /* if no entries wait for some if caller wants to */ + while (!aac_get_entry(dev, qid, &entry, index, nonotify)) + { + printk(KERN_ERR "GetEntries failed\n"); + } + /* + * Setup queue entry with a command, status and fib mapped + */ + entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size)); + map = 1; + } + else if (qid == AdapHighRespQueue || qid == AdapNormRespQueue) + { + while(!aac_get_entry(dev, qid, &entry, index, nonotify)) + { + /* if no entries wait for some if caller wants to */ + } + /* + * Setup queue entry with command, status and fib mapped + */ + entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size)); + entry->addr = cpu_to_le32(fib->header.SenderFibAddress); /* Restore adapters pointer to the FIB */ + fib->header.ReceiverFibAddress = fib->header.SenderFibAddress; /* Let the adapter now where to find its data */ + map = 0; + } + /* + * If MapFib is true than we need to map the Fib and put pointers + * in the queue entry. + */ + if (map) + entry->addr = cpu_to_le32((unsigned long)(fibptr->logicaladdr)); + return 0; +} + + +/** + * aac_insert_entry - insert a queue entry + * @dev: Adapter + * @index: Index of entry to insert + * @qid: Queue number + * @nonotify: Suppress adapter notification + * + * Gets the next free QE off the requested priorty adapter command + * queue and associates the Fib with the QE. The QE represented by + * index is ready to insert on the queue when this routine returns + * success. + */ + +static int aac_insert_entry(struct aac_dev * dev, u32 index, u32 qid, unsigned long nonotify) +{ + struct aac_queue * q = &dev->queues->queue[qid]; + + if(q == NULL) + BUG(); + *(q->headers.producer) = cpu_to_le32(index + 1); + spin_unlock_irqrestore(q->lock, q->SavedIrql); + + if (qid == AdapHighCmdQueue || + qid == AdapNormCmdQueue || + qid == AdapHighRespQueue || + qid == AdapNormRespQueue) + { + if (!nonotify) + aac_adapter_notify(dev, qid); + } + else + printk("Suprise insert!\n"); + return 0; +} + +/* + * Define the highest level of host to adapter communication routines. + * These routines will support host to adapter FS commuication. These + * routines have no knowledge of the commuication method used. This level + * sends and receives FIBs. This level has no knowledge of how these FIBs + * get passed back and forth. + */ + +/** + * fib_send - send a fib to the adapter + * @command: Command to send + * @fibptr: The fib + * @size: Size of fib data area + * @priority: Priority of Fib + * @wait: Async/sync select + * @reply: True if a reply is wanted + * @callback: Called with reply + * @callback_data: Passed to callback + * + * Sends the requested FIB to the adapter and optionally will wait for a + * response FIB. If the caller does not wish to wait for a response than + * an event to wait on must be supplied. This event will be set when a + * response FIB is received from the adapter. + */ + +int fib_send(u16 command, struct fib * fibptr, unsigned long size, int priority, int wait, int reply, fib_callback callback, void * callback_data) +{ + u32 index; + u32 qid; + struct aac_dev * dev = fibptr->dev; + unsigned long nointr = 0; + struct hw_fib * fib = fibptr->fib; + struct aac_queue * q; + unsigned long flags = 0; + + if (!(le32_to_cpu(fib->header.XferState) & HostOwned)) + return -EBUSY; + /* + * There are 5 cases with the wait and reponse requested flags. + * The only invalid cases are if the caller requests to wait and + * does not request a response and if the caller does not want a + * response and the Fibis not allocated from pool. If a response + * is not requesed the Fib will just be deallocaed by the DPC + * routine when the response comes back from the adapter. No + * further processing will be done besides deleting the Fib. We + * will have a debug mode where the adapter can notify the host + * it had a problem and the host can log that fact. + */ + if (wait && !reply) { + return -EINVAL; + } else if (!wait && reply) { + fib->header.XferState |= cpu_to_le32(Async | ResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.AsyncSent); + } else if (!wait && !reply) { + fib->header.XferState |= cpu_to_le32(NoResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.NoResponseSent); + } else if (wait && reply) { + fib->header.XferState |= cpu_to_le32(ResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.NormalSent); + } + /* + * Map the fib into 32bits by using the fib number + */ + fib->header.SenderData = fibptr-&dev->fibs[0]; /* for callback */ + /* + * Set FIB state to indicate where it came from and if we want a + * response from the adapter. Also load the command from the + * caller. + * + * Map the hw fib pointer as a 32bit value + */ + fib->header.SenderFibAddress = fib2addr(fib); + fib->header.Command = cpu_to_le16(command); + fib->header.XferState |= cpu_to_le32(SentFromHost); + fibptr->fib->header.Flags = 0; /* Zero the flags field - its internal only... */ + /* + * Set the size of the Fib we want to send to the adapter + */ + fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size); + if (le16_to_cpu(fib->header.Size) > le16_to_cpu(fib->header.SenderSize)) { + return -EMSGSIZE; + } + /* + * Get a queue entry connect the FIB to it and send an notify + * the adapter a command is ready. + */ + if (priority == FsaHigh) { + fib->header.XferState |= cpu_to_le32(HighPriority); + qid = AdapHighCmdQueue; + } else { + fib->header.XferState |= cpu_to_le32(NormalPriority); + qid = AdapNormCmdQueue; + } + q = &dev->queues->queue[qid]; + + if(wait) + spin_lock_irqsave(&fibptr->event_lock, flags); + if(aac_queue_get( dev, &index, qid, fib, 1, fibptr, &nointr)<0) + return -EWOULDBLOCK; + dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index)); + dprintk((KERN_DEBUG "Fib contents:.\n")); + dprintk((KERN_DEBUG " Command = %d.\n", fib->header.Command)); + dprintk((KERN_DEBUG " XferState = %x.\n", fib->header.XferState)); + /* + * Fill in the Callback and CallbackContext if we are not + * going to wait. + */ + if (!wait) { + fibptr->callback = callback; + fibptr->callback_data = callback_data; + } + FIB_COUNTER_INCREMENT(aac_config.FibsSent); + list_add_tail(&fibptr->queue, &q->pendingq); + q->numpending++; + + fibptr->done = 0; + + if(aac_insert_entry(dev, index, qid, (nointr & aac_config.irq_mod)) < 0) + return -EWOULDBLOCK; + /* + * If the caller wanted us to wait for response wait now. + */ + + if (wait) { + spin_unlock_irqrestore(&fibptr->event_lock, flags); + down(&fibptr->event_wait); + if(fibptr->done == 0) + BUG(); + + if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) + return -ETIMEDOUT; + else + return 0; + } + /* + * If the user does not want a response than return success otherwise + * return pending + */ + if (reply) + return -EINPROGRESS; + else + return 0; +} + +/** + * aac_consumer_get - get the top of the queue + * @dev: Adapter + * @q: Queue + * @entry: Return entry + * + * Will return a pointer to the entry on the top of the queue requested that + * we are a consumer of, and return the address of the queue entry. It does + * not change the state of the queue. + */ + +int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry) +{ + u32 index; + int status; + + if (*q->headers.producer == *q->headers.consumer) { + status = 0; + } else { + /* + * The consumer index must be wrapped if we have reached + * the end of the queue, else we just use the entry + * pointed to by the header index + */ + if (le32_to_cpu(*q->headers.consumer) >= q->entries) + index = 0; + else + index = le32_to_cpu(*q->headers.consumer); + *entry = q->base + index; + status = 1; + } + return(status); +} + +int aac_consumer_avail(struct aac_dev *dev, struct aac_queue * q) +{ + return (*q->headers.producer != *q->headers.consumer); +} + + +/** + * aac_consumer_free - free consumer entry + * @dev: Adapter + * @q: Queue + * @qid: Queue ident + * + * Frees up the current top of the queue we are a consumer of. If the + * queue was full notify the producer that the queue is no longer full. + */ + +void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) +{ + int wasfull = 0; + u32 notify; + + if (*q->headers.producer+1 == *q->headers.consumer) + wasfull = 1; + + if (le32_to_cpu(*q->headers.consumer) >= q->entries) + *q->headers.consumer = cpu_to_le32(1); + else + *q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1); + + if (wasfull) { + switch (qid) { + + case HostNormCmdQueue: + notify = HostNormCmdNotFull; + break; + case HostHighCmdQueue: + notify = HostHighCmdNotFull; + break; + case HostNormRespQueue: + notify = HostNormRespNotFull; + break; + case HostHighRespQueue: + notify = HostHighRespNotFull; + break; + default: + BUG(); + return; + } + aac_adapter_notify(dev, notify); + } +} + +/** + * fib_adapter_complete - complete adapter issued fib + * @fibptr: fib to complete + * @size: size of fib + * + * Will do all necessary work to complete a FIB that was sent from + * the adapter. + */ + +int fib_adapter_complete(struct fib * fibptr, unsigned short size) +{ + struct hw_fib * fib = fibptr->fib; + struct aac_dev * dev = fibptr->dev; + unsigned long nointr = 0; + + if (le32_to_cpu(fib->header.XferState) == 0) + return 0; + /* + * If we plan to do anything check the structure type first. + */ + if ( fib->header.StructType != FIB_MAGIC ) { + return -EINVAL; + } + /* + * This block handles the case where the adapter had sent us a + * command and we have finished processing the command. We + * call completeFib when we are done processing the command + * and want to send a response back to the adapter. This will + * send the completed cdb to the adapter. + */ + if (fib->header.XferState & cpu_to_le32(SentFromAdapter)) { + fib->header.XferState |= cpu_to_le32(HostProcessed); + if (fib->header.XferState & cpu_to_le32(HighPriority)) { + u32 index; + if (size) + { + size += sizeof(struct aac_fibhdr); + if (size > le16_to_cpu(fib->header.SenderSize)) + return -EMSGSIZE; + fib->header.Size = cpu_to_le16(size); + } + if(aac_queue_get(dev, &index, AdapHighRespQueue, fib, 1, NULL, &nointr) < 0) { + return -EWOULDBLOCK; + } + if (aac_insert_entry(dev, index, AdapHighRespQueue, (nointr & (int)aac_config.irq_mod)) != 0) { + } + } + else if (fib->header.XferState & NormalPriority) + { + u32 index; + + if (size) { + size += sizeof(struct aac_fibhdr); + if (size > le16_to_cpu(fib->header.SenderSize)) + return -EMSGSIZE; + fib->header.Size = cpu_to_le16(size); + } + if (aac_queue_get(dev, &index, AdapNormRespQueue, fib, 1, NULL, &nointr) < 0) + return -EWOULDBLOCK; + if (aac_insert_entry(dev, index, AdapNormRespQueue, + (nointr & (int)aac_config.irq_mod)) != 0) + { + } + } + } + else + { + printk(KERN_WARNING "fib_complete: Unknown xferstate detected.\n"); + BUG(); + } + return 0; +} + +/** + * fib_complete - fib completion handler + * @fib: FIB to complete + * + * Will do all necessary work to complete a FIB. + */ + +int fib_complete(struct fib * fibptr) +{ + struct hw_fib * fib = fibptr->fib; + + /* + * Check for a fib which has already been completed + */ + + if (fib->header.XferState == cpu_to_le32(0)) + return 0; + /* + * If we plan to do anything check the structure type first. + */ + + if (fib->header.StructType != FIB_MAGIC) + return -EINVAL; + /* + * This block completes a cdb which orginated on the host and we + * just need to deallocate the cdb or reinit it. At this point the + * command is complete that we had sent to the adapter and this + * cdb could be reused. + */ + if((fib->header.XferState & cpu_to_le32(SentFromHost)) && + (fib->header.XferState & cpu_to_le32(AdapterProcessed))) + { + fib_dealloc(fibptr); + } + else if(fib->header.XferState & cpu_to_le32(SentFromHost)) + { + /* + * This handles the case when the host has aborted the I/O + * to the adapter because the adapter is not responding + */ + fib_dealloc(fibptr); + } else if(fib->header.XferState & cpu_to_le32(HostOwned)) { + fib_dealloc(fibptr); + } else { + BUG(); + } + return 0; +} + +/** + * aac_printf - handle printf from firmware + * @dev: Adapter + * @val: Message info + * + * Print a message passed to us by the controller firmware on the + * Adaptec board + */ + +void aac_printf(struct aac_dev *dev, u32 val) +{ + int length = val & 0xffff; + int level = (val >> 16) & 0xffff; + char *cp = dev->printfbuf; + + /* + * The size of the printfbuf is set in port.c + * There is no variable or define for it + */ + if (length > 255) + length = 255; + if (cp[length] != 0) + cp[length] = 0; + if (level == LOG_HIGH_ERROR) + printk(KERN_WARNING "aacraid:%s", cp); + else + printk(KERN_INFO "aacraid:%s", cp); + memset(cp, 0, 256); +} + + +/** + * aac_handle_aif - Handle a message from the firmware + * @dev: Which adapter this fib is from + * @fibptr: Pointer to fibptr from adapter + * + * This routine handles a driver notify fib from the adapter and + * dispatches it to the appropriate routine for handling. + */ + +static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) +{ + struct hw_fib * fib = fibptr->fib; + /* + * Set the status of this FIB to be Invalid parameter. + * + * *(u32 *)fib->data = ST_INVAL; + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(fibptr, sizeof(u32)); +} + +/** + * aac_command_thread - command processing thread + * @dev: Adapter to monitor + * + * Waits on the commandready event in it's queue. When the event gets set + * it will pull FIBs off it's queue. It will continue to pull FIBs off + * until the queue is empty. When the queue is empty it will wait for + * more FIBs. + */ + +int aac_command_thread(struct aac_dev * dev) +{ + struct hw_fib *fib, *newfib; + struct fib fibptr; /* for error logging */ + struct aac_queue_block *queues = dev->queues; + struct aac_fib_context *fibctx; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + + /* + * We can only have one thread per adapter for AIF's. + */ + if (dev->aif_thread) + return -EINVAL; + /* + * Set up the name that will appear in 'ps' + * stored in task_struct.comm[16]. + */ + sprintf(current->comm, "aacraid"); + daemonize(); + /* + * Let the DPC know it has a place to send the AIF's to. + */ + dev->aif_thread = 1; + memset(&fibptr, 0, sizeof(struct fib)); + add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait); + set_current_state(TASK_INTERRUPTIBLE); + while(1) + { + spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags); + while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) { + struct list_head *entry; + struct aac_aifcmd * aifcmd; + + set_current_state(TASK_RUNNING); + + entry = queues->queue[HostNormCmdQueue].cmdq.next; + list_del(entry); + + spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags); + fib = list_entry(entry, struct hw_fib, header.FibLinks); + /* + * We will process the FIB here or pass it to a + * worker thread that is TBD. We Really can't + * do anything at this point since we don't have + * anything defined for this thread to do. + */ + memset(&fibptr, 0, sizeof(struct fib)); + fibptr.type = FSAFS_NTC_FIB_CONTEXT; + fibptr.size = sizeof( struct fib ); + fibptr.fib = fib; + fibptr.data = fib->data; + fibptr.dev = dev; + /* + * We only handle AifRequest fibs from the adapter. + */ + aifcmd = (struct aac_aifcmd *) fib->data; + if (aifcmd->command == le16_to_cpu(AifCmdDriverNotify)) { + aac_handle_aif(dev, &fibptr); + } else { + /* The u32 here is important and intended. We are using + 32bit wrapping time to fit the adapter field */ + + u32 time_now, time_last; + unsigned long flagv; + + time_now = jiffies/HZ; + + spin_lock_irqsave(&dev->fib_lock, flagv); + entry = dev->fib_list.next; + /* + * For each Context that is on the + * fibctxList, make a copy of the + * fib, and then set the event to wake up the + * thread that is waiting for it. + */ + while (entry != &dev->fib_list) { + /* + * Extract the fibctx + */ + fibctx = list_entry(entry, struct aac_fib_context, next); + /* + * Check if the queue is getting + * backlogged + */ + if (fibctx->count > 20) + { + time_last = fibctx->jiffies; + /* + * Has it been > 2 minutes + * since the last read off + * the queue? + */ + if ((time_now - time_last) > 120) { + entry = entry->next; + aac_close_fib_context(dev, fibctx); + continue; + } + } + /* + * Warning: no sleep allowed while + * holding spinlock + */ + newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC); + if (newfib) { + /* + * Make the copy of the FIB + */ + memcpy(newfib, fib, sizeof(struct hw_fib)); + /* + * Put the FIB onto the + * fibctx's fibs + */ + list_add_tail(&newfib->header.FibLinks, &fibctx->fibs); + fibctx->count++; + /* + * Set the event to wake up the + * thread that will waiting. + */ + up(&fibctx->wait_sem); + } else { + printk(KERN_WARNING "aifd: didn't allocate NewFib.\n"); + } + entry = entry->next; + } + /* + * Set the status of this FIB + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(&fibptr, sizeof(u32)); + spin_unlock_irqrestore(&dev->fib_lock, flagv); + } + spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags); + } + /* + * There are no more AIF's + */ + spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags); + schedule(); + + if(signal_pending(current)) + break; + set_current_state(TASK_INTERRUPTIBLE); + } + remove_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait); + dev->aif_thread = 0; + complete_and_exit(&dev->aif_completion, 0); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/dpcsup.c linux-2.5/drivers/scsi/aacraid/dpcsup.c --- linux-2.5.13/drivers/scsi/aacraid/dpcsup.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/dpcsup.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,201 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * dpcsup.c + * + * Abstract: All DPC processing routines for the cyclone board occur here. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * aac_response_normal - Handle command replies + * @q: Queue to read from + * + * This DPC routine will be run when the adapter interrupts us to let us + * know there is a response on our normal priority queue. We will pull off + * all QE there are and wake up all the waiters before exiting. We will + * take a spinlock out on the queue before operating on it. + */ + +unsigned int aac_response_normal(struct aac_queue * q) +{ + struct aac_dev * dev = q->dev; + struct aac_entry *entry; + struct hw_fib * fib; + struct fib * fibctx; + int consumed = 0; + unsigned long flags; + + spin_lock_irqsave(q->lock, flags); + + /* + * Keep pulling response QEs off the response queue and waking + * up the waiters until there are no more QEs. We then return + * back to the system. If no response was requesed we just + * deallocate the Fib here and continue. + */ + while(aac_consumer_get(dev, q, &entry)) + { + int fast; + + fast = (int) (entry->addr & 0x01); + fib = addr2fib(entry->addr & ~0x01); + aac_consumer_free(dev, q, HostNormRespQueue); + fibctx = &dev->fibs[fib->header.SenderData]; + /* + * Remove this fibctx from the Outstanding I/O queue. + * But only if it has not already been timed out. + * + * If the fib has been timed out already, then just + * continue. The caller has already been notified that + * the fib timed out. + */ + if (!(fibctx->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { + list_del(&fibctx->queue); + dev->queues->queue[AdapNormCmdQueue].numpending--; + } else { + printk(KERN_WARNING "aacraid: FIB timeout.\n"); + continue; + } + spin_unlock_irqrestore(q->lock, flags); + + if (fast) { + /* + * Doctor the fib + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib->header.XferState |= cpu_to_le32(AdapterProcessed); + } + + FIB_COUNTER_INCREMENT(aac_config.FibRecved); + + if (fib->header.Command == cpu_to_le16(NuFileSystem)) + { + u32 *pstatus = (u32 *)fib->data; + if (*pstatus & cpu_to_le32(0xffff0000)) + *pstatus = cpu_to_le32(ST_OK); + } + if (fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) + { + if (fib->header.XferState & cpu_to_le32(NoResponseExpected)) + FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved); + else + FIB_COUNTER_INCREMENT(aac_config.AsyncRecved); + /* + * NOTE: we cannot touch the fibctx after this + * call, because it may have been deallocated. + */ + fibctx->callback(fibctx->callback_data, fibctx); + } else { + unsigned long flagv; + spin_lock_irqsave(&fibctx->event_lock, flagv); + fibctx->done = 1; + up(&fibctx->event_wait); + spin_unlock_irqrestore(&fibctx->event_lock, flagv); + FIB_COUNTER_INCREMENT(aac_config.NormalRecved); + } + consumed++; + spin_lock_irqsave(q->lock, flags); + } + + if (consumed > aac_config.peak_fibs) + aac_config.peak_fibs = consumed; + if (consumed == 0) + aac_config.zero_fibs++; + + spin_unlock_irqrestore(q->lock, flags); + return 0; +} + + +/** + * aac_command_normal - handle commands + * @q: queue to process + * + * This DPC routine will be queued when the adapter interrupts us to + * let us know there is a command on our normal priority queue. We will + * pull off all QE there are and wake up all the waiters before exiting. + * We will take a spinlock out on the queue before operating on it. + */ + +unsigned int aac_command_normal(struct aac_queue *q) +{ + struct aac_dev * dev = q->dev; + struct aac_entry *entry; + unsigned long flags; + + spin_lock_irqsave(q->lock, flags); + + /* + * Keep pulling response QEs off the response queue and waking + * up the waiters until there are no more QEs. We then return + * back to the system. + */ + while(aac_consumer_get(dev, q, &entry)) + { + struct hw_fib * fib; + fib = addr2fib(entry->addr); + + if (dev->aif_thread) { + list_add_tail(&fib->header.FibLinks, &q->cmdq); + aac_consumer_free(dev, q, HostNormCmdQueue); + wake_up_interruptible(&q->cmdready); + } else { + struct fib fibctx; + aac_consumer_free(dev, q, HostNormCmdQueue); + spin_unlock_irqrestore(q->lock, flags); + memset(&fibctx, 0, sizeof(struct fib)); + fibctx.type = FSAFS_NTC_FIB_CONTEXT; + fibctx.size = sizeof(struct fib); + fibctx.fib = fib; + fibctx.data = fib->data; + fibctx.dev = dev; + /* + * Set the status of this FIB + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(&fibctx, sizeof(u32)); + spin_lock_irqsave(q->lock, flags); + } + } + spin_unlock_irqrestore(q->lock, flags); + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/linit.c linux-2.5/drivers/scsi/aacraid/linit.c --- linux-2.5.13/drivers/scsi/aacraid/linit.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/linit.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,691 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * linit.c + * + * Abstract: Linux Driver entry module for Adaptec RAID Array Controller + * + * Provides the following driver entry points: + * aac_detect() + * aac_release() + * aac_queuecommand() + * aac_resetcommand() + * aac_biosparm() + * + */ + +#define AAC_DRIVER_VERSION "0.9.9ac4-rel" +#define AAC_DRIVER_BUILD_DATE __DATE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" +#include "sd.h" + +#define AAC_DRIVERNAME "aacraid" + +MODULE_AUTHOR("Red Hat Inc and Adaptec OEM RAID Solutions"); +MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, and HP NetRAID-4M devices. http://domsch.com/linux/"); +MODULE_LICENSE("GPL"); + +struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS]; + +static unsigned aac_count = 0; +static int aac_cfg_major = -1; +static int single_command_done = 0; + +/* + * Because of the way Linux names scsi devices, the order in this table has + * become important. Check for on-board Raid first, add-in cards second. + */ + +/* FIXME static */struct aac_driver_ident aac_drivers[] = { + { 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 2/Si */ + { 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x0003, 0x1028, 0x0003, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0004, 0x1028, 0x00d0, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0002, 0x1028, 0x00d1, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x0002, 0x1028, 0x00d9, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x0106, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x011b, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x0121, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL ", "PERCRAID " }, /* Dell PERC2 "Quad Channel" */ + { 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S " }, /* Adaptec 5400S */ + { 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid", "HP ", "NetRAID-4M " } /* HP NetRAID-4M */ +}; + +#define NUM_AACTYPES (sizeof(aac_drivers) / sizeof(struct aac_driver_ident)) +static int num_aacdrivers = NUM_AACTYPES; + +static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); +static int aac_cfg_open(struct inode * inode, struct file * file); +static int aac_cfg_release(struct inode * inode,struct file * file); + +static struct file_operations aac_cfg_fops = { + owner: THIS_MODULE, + ioctl: aac_cfg_ioctl, + open: aac_cfg_open, + release: aac_cfg_release +}; + +static int aac_detect(Scsi_Host_Template *); +static int aac_release(struct Scsi_Host *); +static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *)); +static int aac_command(Scsi_Cmnd *); +static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr); +static int aac_resetcommand(Scsi_Cmnd *, unsigned int); +static int aac_biosparm(Scsi_Disk *, kdev_t, int *); +static int aac_procinfo(char *, char **, off_t, int, int, int); +static int aac_ioctl(Scsi_Device *, int, void *); + +static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *); + +/** + * aac_detect - Probe for aacraid cards + * @template: SCSI driver template + * + * Probe for AAC Host Adapters initialize, register, and report the + * configuration of each AAC Host Adapter found. + * Returns the number of adapters successfully initialized and + * registered. + * Initializes all data necessary for this particular SCSI driver. + * Notes: + * The detect routine must not call any of the mid level functions + * to queue commands because things are not guaranteed to be set + * up yet. The detect routine can send commands to the host adapter + * as long as the program control will not be passed to scsi.c in + * the processing of the command. Note especially that + * scsi_malloc/scsi_free must not be called. + * + */ + +static int aac_detect(Scsi_Host_Template *template) +{ + int index; + int container; + u16 vendor_id, device_id; + struct Scsi_Host *host_ptr; + struct pci_dev *dev = NULL; + struct aac_dev *aac; + struct fsa_scsi_hba *fsa_dev_ptr; + char *name = NULL; + + printk(KERN_INFO "Red Hat/Adaptec aacraid driver, %s\n", AAC_DRIVER_BUILD_DATE); + + /* setting up the proc directory structure */ + template->proc_name = "aacraid"; + + for( index = 0; index != num_aacdrivers; index++ ) + { + device_id = aac_drivers[index].device; + vendor_id = aac_drivers[index].vendor; + name = aac_drivers[index].name; + dprintk((KERN_DEBUG "Checking %s %x/%x/%x/%x.\n", + name, vendor_id, device_id, + aac_drivers[index].subsystem_vendor, + aac_drivers[index].subsystem_device)); + + dev = NULL; + while((dev = pci_find_device(vendor_id, device_id, dev))) + { + if (pci_enable_device(dev)) + continue; + pci_set_master(dev); + pci_set_dma_mask(dev, 0xFFFFFFFFULL); + + if((dev->subsystem_vendor != aac_drivers[index].subsystem_vendor) || + (dev->subsystem_device != aac_drivers[index].subsystem_device)) + continue; + + dprintk((KERN_DEBUG "%s device detected.\n", name)); + dprintk((KERN_DEBUG "%x/%x/%x/%x.\n", vendor_id, device_id, + aac_drivers[index].subsystem_vendor, aac_drivers[index].subsystem_device)); + /* Increment the host adapter count */ + aac_count++; + /* + * scsi_register() allocates memory for a Scsi_Hosts structure and + * links it into the linked list of host adapters. This linked list + * contains the data for all possible scsi hosts. + * This is similar to the Scsi_Host_Template, except that we have + * one entry for each actual physical host adapter on the system, + * stored as a linked list. If there are two AAC boards, then we + * will need to make two Scsi_Host entries, but there will be only + * one Scsi_Host_Template entry. The second argument to scsi_register() + * specifies the size of the extra memory we want to hold any device + * specific information. + */ + host_ptr = scsi_register( template, sizeof(struct aac_dev) ); + /* + * These three parameters can be used to allow for wide SCSI + * and for host adapters that support multiple buses. + */ + host_ptr->max_id = 17; + host_ptr->max_lun = 8; + host_ptr->max_channel = 1; + host_ptr->irq = dev->irq; /* Adapter IRQ number */ + /* host_ptr->base = ( char * )(dev->resource[0].start & ~0xff); */ + host_ptr->base = dev->resource[0].start; + scsi_set_pci_device(host_ptr, dev); + dprintk((KERN_DEBUG "Device base address = 0x%lx [0x%lx].\n", host_ptr->base, dev->resource[0].start)); + dprintk((KERN_DEBUG "Device irq = 0x%x.\n", dev->irq)); + /* + * The unique_id field is a unique identifier that must + * be assigned so that we have some way of identifying + * each host adapter properly and uniquely. For hosts + * that do not support more than one card in the + * system, this does not need to be set. It is + * initialized to zero in scsi_register(). This is the + * value returned as aac->id. + */ + host_ptr->unique_id = aac_count - 1; + /* + * This function is called after the device list has + * been built to find the tagged queueing depth + * supported for each device. + */ + host_ptr->select_queue_depths = aac_queuedepth; + aac = (struct aac_dev *)host_ptr->hostdata; + /* attach a pointer back to Scsi_Host */ + aac->scsi_host_ptr = host_ptr; + aac->pdev = dev; + aac->cardtype = index; + aac->name = aac->scsi_host_ptr->hostt->name; + aac->id = aac->scsi_host_ptr->unique_id; + /* Initialize the ordinal number of the device to -1 */ + fsa_dev_ptr = &(aac->fsa_dev); + for( container = 0; container < MAXIMUM_NUM_CONTAINERS; container++ ) + fsa_dev_ptr->devno[container] = -1; + + dprintk((KERN_DEBUG "Initializing Hardware...\n")); + if((*aac_drivers[index].init)(aac , host_ptr->unique_id) != 0) + { + /* device initialization failed */ + printk(KERN_WARNING "aacraid: device initialization failed.\n"); + scsi_unregister(host_ptr); + aac_count--; + } + else + { + dprintk((KERN_DEBUG "%s:%d device initialization successful.\n", name, host_ptr->unique_id)); + aac_get_containers(aac); + aac_devices[aac_count-1] = aac; + } + } + } + + if( aac_count ){ + if((aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops))<0) + printk(KERN_WARNING "aacraid: unable to register \"aac\" device.\n"); + } + + template->present = aac_count; /* # of cards of this type found */ + return aac_count; +} + +/** + * aac_release - release SCSI host resources + * @host_ptr: SCSI host to clean up + * + * Release all resources previously acquired to support a specific Host + * Adapter and unregister the AAC Host Adapter. + * + * BUGS: Does not wait for the thread it kills to die. + */ + +static int aac_release(struct Scsi_Host *host_ptr) +{ + struct aac_dev *dev; + dprintk((KERN_DEBUG "aac_release.\n")); + dev = (struct aac_dev *)host_ptr->hostdata; + /* + * kill any threads we started + */ + kill_proc(dev->thread_pid, SIGKILL, 0); + wait_for_completion(&dev->aif_completion); + /* + * Call the comm layer to detach from this adapter + */ + aac_detach(dev); + /* Check free orderings... */ + /* remove interrupt binding */ + free_irq(host_ptr->irq, dev); + iounmap((void * )dev->regs.sa); + /* unregister adapter */ + scsi_unregister(host_ptr); + /* + * FIXME: This assumes no hot plugging is going on... + */ + if( aac_cfg_major >= 0 ) + { + unregister_chrdev(aac_cfg_major, "aac"); + aac_cfg_major = -1; + } + return 0; +} + +/** + * aac_queuecommand - queue a SCSI command + * @scsi_cmnd_ptr: SCSI command to queue + * @CompletionRoutine: Function to call on command completion + * + * Queues a command for execution by the associated Host Adapter. + */ + +static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*CompletionRoutine)(Scsi_Cmnd *)) +{ + int ret; + + scsi_cmnd_ptr->scsi_done = CompletionRoutine; + /* + * aac_scsi_cmd() handles command processing, setting the + * result code and calling completion routine. + */ + if((ret = aac_scsi_cmd(scsi_cmnd_ptr)) != 0) + dprintk((KERN_DEBUG "aac_scsi_cmd failed.\n")); + return ret; +} + + +/** + * aac_done - Callback function for a non-queued command. + * @scsi_cmnd_ptr: SCSI command block to wait for + * + * Sets single_command done to 1. This lets aac_command complete. + * This function is obsolete. + * + * Bugs: Doesn't actually work properly with multiple controllers + */ + +static void aac_done(Scsi_Cmnd * scsi_cmnd_ptr) +{ + single_command_done = 1; +} + +/** + * aac_command - synchronous SCSI command execution + * @scsi_cmnd_ptr: SCSI command to issue + * + * Accepts a single command for execution by the associated Host Adapter. + * Waits until it completes an then returns an int where: + * Byte 0 = SCSI status code + * Byte 1 = SCSI 1 byte message + * Byte 2 = host error return + * Byte 3 = mid level error return + */ + +static int aac_command(Scsi_Cmnd *scsi_cmnd_ptr ) +{ + scsi_cmnd_ptr->scsi_done = aac_done; + dprintk((KERN_DEBUG "aac_command.\n")); + + /* + * aac_scsi_cmd() handles command processing, setting the + * result code and calling completion routine. + */ + single_command_done = 0; + aac_scsi_cmd(scsi_cmnd_ptr); + while(!single_command_done) + rmb(); + return scsi_cmnd_ptr->result; +} + +/** + * aac_abortcommand - Abort command if possible. + * @scsi_cmnd_ptr: SCSI command block to abort + * + * Called when the midlayer wishes to abort a command. We don't support + * this facility, and our firmware looks after life for us. We just + * report the command as busy. + */ + +static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr ) +{ + return SCSI_ABORT_BUSY; +} + +/** + * aac_resetcommand - Reset command handling + * @scsi_cmnd_ptr: SCSI command block causing the reset + * @reset_flags: Reset hints from the midlayer code + * + * Issue a reset of a SCSI command. We are ourselves not truely a SCSI + * controller and our firmware will do the work for us anyway. Thus this + * is a no-op. We just return SCSI_RESET_PUNT + */ + +static int aac_resetcommand(struct scsi_cmnd *scsi_cmnd_ptr, unsigned int reset_flags ) +{ + return SCSI_RESET_PUNT; +} + +/** + * aac_driverinfo - Returns the host adapter name + * @host_ptr: Scsi host to report on + * + * Returns a static string describing the device in question + */ + +const char *aac_driverinfo(struct Scsi_Host *host_ptr) +{ + struct aac_dev *dev = (struct aac_dev *)host_ptr->hostdata; + return aac_drivers[dev->cardtype].name; +} + +/** + * aac_biosparm - return BIOS parameters for disk + * @disk: SCSI disk object to process + * @device: kdev_t of the disk in question + * @geom: geometry block to fill in + * + * Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk. + * The default disk geometry is 64 heads, 32 sectors, and the appropriate + * number of cylinders so as not to exceed drive capacity. In order for + * disks equal to or larger than 1 GB to be addressable by the BIOS + * without exceeding the BIOS limitation of 1024 cylinders, Extended + * Translation should be enabled. With Extended Translation enabled, + * drives between 1 GB inclusive and 2 GB exclusive are given a disk + * geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive + * are given a disk geometry of 255 heads and 63 sectors. However, if + * the BIOS detects that the Extended Translation setting does not match + * the geometry in the partition table, then the translation inferred + * from the partition table will be used by the BIOS, and a warning may + * be displayed. + */ + +static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom) +{ + struct diskparm *param = (struct diskparm *)geom; + struct buffer_head * buf; + + dprintk((KERN_DEBUG "aac_biosparm.\n")); + + /* + * Assuming extended translation is enabled - #REVISIT# + */ + if( disk->capacity >= 2 * 1024 * 1024 ) /* 1 GB in 512 byte sectors */ + { + if( disk->capacity >= 4 * 1024 * 1024 ) /* 2 GB in 512 byte sectors */ + { + param->heads = 255; + param->sectors = 63; + } + else + { + param->heads = 128; + param->sectors = 32; + } + } + else + { + param->heads = 64; + param->sectors = 32; + } + + param->cylinders = disk->capacity/(param->heads * param->sectors); + + /* + * Read the first 1024 bytes from the disk device + */ + + buf = bread(mk_kdev(major(dev), minor(dev)&~0xf), 0, block_size(dev)); + if(buf == NULL) + return 0; + /* + * If the boot sector partition table is valid, search for a partition + * table entry whose end_head matches one of the standard geometry + * translations ( 64/32, 128/32, 255/63 ). + */ + + if(*(unsigned short *)(buf->b_data + 0x1fe) == cpu_to_le16(0xaa55)) + { + struct partition *first = (struct partition * )(buf->b_data + 0x1be); + struct partition *entry = first; + int saved_cylinders = param->cylinders; + int num; + unsigned char end_head, end_sec; + + for(num = 0; num < 4; num++) + { + end_head = entry->end_head; + end_sec = entry->end_sector & 0x3f; + + if(end_head == 63) + { + param->heads = 64; + param->sectors = 32; + break; + } + else if(end_head == 127) + { + param->heads = 128; + param->sectors = 32; + break; + } + else if(end_head == 254) + { + param->heads = 255; + param->sectors = 63; + break; + } + entry++; + } + + if(num == 4) + { + end_head = first->end_head; + end_sec = first->end_sector & 0x3f; + } + + param->cylinders = disk->capacity / (param->heads * param->sectors); + + if(num < 4 && end_sec == param->sectors) + { + if(param->cylinders != saved_cylinders) + dprintk((KERN_DEBUG "Adopting geometry: heads=%d, sectors=%d from partition table %d.\n", + param->heads, param->sectors, num)); + } + else if(end_head > 0 || end_sec > 0) + { + dprintk((KERN_DEBUG "Strange geometry: heads=%d, sectors=%d in partition table %d.\n", + end_head + 1, end_sec, num)); + dprintk((KERN_DEBUG "Using geometry: heads=%d, sectors=%d.\n", + param->heads, param->sectors)); + } + } + brelse(buf); + return 0; +} + +/** + * aac_queuedepth - compute queue depths + * @host: SCSI host in question + * @dev: SCSI device we are considering + * + * Selects queue depths for each target device based on the host adapter's + * total capacity and the queue depth supported by the target device. + * A queue depth of one automatically disables tagged queueing. + */ + +static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev ) +{ + Scsi_Device * dptr; + + dprintk((KERN_DEBUG "aac_queuedepth.\n")); + dprintk((KERN_DEBUG "Device # Q Depth Online\n")); + dprintk((KERN_DEBUG "---------------------------\n")); + for(dptr = dev; dptr != NULL; dptr = dptr->next) + { + if(dptr->host == host) + { + dptr->queue_depth = 10; + dprintk((KERN_DEBUG " %2d %d %d\n", + dptr->id, dptr->queue_depth, dptr->online)); + } + } +} + +/*------------------------------------------------------------------------------ + aac_ioctl() + + Handle SCSI ioctls + *----------------------------------------------------------------------------*/ +static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg) +/*----------------------------------------------------------------------------*/ +{ + struct aac_dev *dev; + dprintk((KERN_DEBUG "aac_ioctl.\n")); + dev = (struct aac_dev *)scsi_dev_ptr->host->hostdata; + return aac_do_ioctl(dev, cmd, arg); +} + +/** + * aac_cfg_open - open a configuration file + * @inode: inode being opened + * @file: file handle attached + * + * Called when the configuration device is opened. Does the needed + * set up on the handle and then returns + * + * Bugs: This needs extending to check a given adapter is present + * so we can support hot plugging, and to ref count adapters. + */ + +static int aac_cfg_open(struct inode * inode, struct file * file ) +{ + unsigned minor_number = minor(inode->i_rdev); + if(minor_number >= aac_count) + return -ENODEV; + return 0; +} + +/** + * aac_cfg_release - close down an AAC config device + * @inode: inode of configuration file + * @file: file handle of configuration file + * + * Called when the last close of the configuration file handle + * is performed. + */ + +static int aac_cfg_release(struct inode * inode, struct file * file ) +{ + return 0; +} + +/** + * aac_cfg_ioctl - AAC configuration request + * @inode: inode of device + * @file: file handle + * @cmd: ioctl command code + * @arg: argument + * + * Handles a configuration ioctl. Currently this involves wrapping it + * up and feeding it into the nasty windowsalike glue layer. + * + * Bugs: Needs locking against parallel ioctls lower down + * Bugs: Needs to handle hot plugging + */ + +static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg ) +{ + struct aac_dev *dev = aac_devices[minor(inode->i_rdev)]; + return aac_do_ioctl(dev, cmd, (void *)arg); +} + +/* + * To use the low level SCSI driver support using the linux kernel loadable + * module interface we should initialize the global variable driver_interface + * (datatype Scsi_Host_Template) and then include the file scsi_module.c. + */ + +static Scsi_Host_Template driver_template = { + module: THIS_MODULE, + name: "AAC", + proc_info: aac_procinfo, + detect: aac_detect, + release: aac_release, + info: aac_driverinfo, + ioctl: aac_ioctl, + command: aac_command, + queuecommand: aac_queuecommand, + abort: aac_abortcommand, + reset: aac_resetcommand, + bios_param: aac_biosparm, + can_queue: AAC_NUM_IO_FIB, + this_id: 16, + sg_tablesize: 16, + max_sectors: 128, + cmd_per_lun: 1, + eh_abort_handler: aac_abortcommand, + use_clustering: ENABLE_CLUSTERING, +}; + +#include "scsi_module.c" + +/** + * aac_procinfo - Implement /proc/scsi// + * @proc_buffer: memory buffer for I/O + * @start_ptr: pointer to first valid data + * @offset: offset into file + * @bytes_available: space left + * @host_no: scsi host ident + * @write: direction of I/O + * + * Used to export driver statistics and other infos to the world outside + * the kernel using the proc file system. Also provides an interface to + * feed the driver with information. + * + * For reads + * - if offset > 0 return 0 + * - if offset == 0 write data to proc_buffer and set the start_ptr to + * beginning of proc_buffer, return the number of characters written. + * For writes + * - writes currently not supported, return 0 + * + * Bugs: Only offset zero is handled + */ + +static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset, + int bytes_available, int host_no, int write) +{ + if(write || offset > 0) + return 0; + *start_ptr = proc_buffer; + return sprintf(proc_buffer, "%s %d\n", "Raid Controller, scsi hba number", host_no); +} + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/rx.c linux-2.5/drivers/scsi/aacraid/rx.c --- linux-2.5.13/drivers/scsi/aacraid/rx.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/rx.c Mon Feb 4 16:35:16 2002 @@ -0,0 +1,413 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rx.c + * + * Abstract: Hardware miniport for Drawbridge specific hardware functions. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +static void aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct aac_dev *dev = dev_id; + unsigned long bellbits; + u8 intstat, mask; + + intstat = rx_readb(dev, MUnit.OISR); + /* + * Read mask and invert because drawbridge is reversed. + * This allows us to only service interrupts that have + * been enabled. + */ + mask = ~(rx_readb(dev, MUnit.OIMR)); + /* Check to see if this is our interrupt. If it isn't just return */ + if (intstat & mask) + { + bellbits = rx_readl(dev, OutboundDoorbellReg); + if (bellbits & DoorBellPrintfReady) + { + aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5]))); + rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); + rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); + } + else if (bellbits & DoorBellAdapterNormCmdReady) + { + aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); + } + else if (bellbits & DoorBellAdapterNormRespReady) + { + aac_response_normal(&dev->queues->queue[HostNormRespQueue]); + rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); + } + else if (bellbits & DoorBellAdapterNormCmdNotFull) + { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); + } + else if (bellbits & DoorBellAdapterNormRespNotFull) + { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); + } + } +} + +/** + * aac_rx_enable_interrupt - Enable event reporting + * @dev: Adapter + * @event: Event to enable + * + * Enable event reporting from the i960 for a given event. + */ + +static void aac_rx_enable_interrupt(struct aac_dev * dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_1); + break; + + case HostNormRespQue: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_2); + break; + + case AdapNormCmdNotFull: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_3); + break; + + case AdapNormRespNotFull: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_4); + break; + } +} + +/** + * aac_rx_disable_interrupt - Disable event reporting + * @dev: Adapter + * @event: Event to enable + * + * Disable event reporting from the i960 for a given event. + */ + +static void aac_rx_disable_interrupt(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + dev->irq_mask |= (OUTBOUNDDOORBELL_1); + break; + + case HostNormRespQue: + dev->irq_mask |= (OUTBOUNDDOORBELL_2); + break; + + case AdapNormCmdNotFull: + dev->irq_mask |= (OUTBOUNDDOORBELL_3); + break; + + case AdapNormRespNotFull: + dev->irq_mask |= (OUTBOUNDDOORBELL_4); + break; + } +} + +/** + * rx_sync_cmd - send a command and wait + * @dev: Adapter + * @command: Command to execute + * @p1: first parameter + * @ret: adapter status + * + * This routine will send a synchronous comamnd to the adapter and wait + * for its completion. + */ + +static int rx_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *status) +{ + unsigned long start; + int ok; + /* + * Write the command into Mailbox 0 + */ + rx_writel(dev, InboundMailbox0, cpu_to_le32(command)); + /* + * Write the parameters into Mailboxes 1 - 4 + */ + rx_writel(dev, InboundMailbox1, cpu_to_le32(p1)); + rx_writel(dev, InboundMailbox2, 0); + rx_writel(dev, InboundMailbox3, 0); + rx_writel(dev, InboundMailbox4, 0); + /* + * Clear the synch command doorbell to start on a clean slate. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + /* + * Disable doorbell interrupts + */ + rx_writeb(dev, MUnit.OIMR, rx_readb(dev, MUnit.OIMR) | 0x04); + /* + * Force the completion of the mask register write before issuing + * the interrupt. + */ + rx_readb (dev, MUnit.OIMR); + /* + * Signal that there is a new synch command + */ + rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0); + + ok = 0; + start = jiffies; + + /* + * Wait up to 30 seconds + */ + while (time_before(jiffies, start+30*HZ)) + { + udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ + /* + * Mon960 will set doorbell0 bit when it has completed the command. + */ + if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { + /* + * Clear the doorbell. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + ok = 1; + break; + } + /* + * Yield the processor in case we are slow + */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (ok != 1) { + /* + * Restore interrupt mask even though we timed out + */ + rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb); + return -ETIMEDOUT; + } + /* + * Pull the synch status from Mailbox 0. + */ + *status = le32_to_cpu(rx_readl(dev, IndexRegs.Mailbox[0])); + /* + * Clear the synch command doorbell. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + /* + * Restore interrupt mask + */ + rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb); + return 0; + +} + +/** + * aac_rx_interrupt_adapter - interrupt adapter + * @dev: Adapter + * + * Send an interrupt to the i960 and breakpoint it. + */ + +static void aac_rx_interrupt_adapter(struct aac_dev *dev) +{ + unsigned long ret; + rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret); +} + +/** + * aac_rx_notify_adapter - send an event to the adapter + * @dev: Adapter + * @event: Event to send + * + * Notify the i960 that something it probably cares about has + * happened. + */ + +static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case AdapNormCmdQue: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1); + break; + case HostNormRespNotFull: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4); + break; + case AdapNormRespQue: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2); + break; + case HostNormCmdNotFull: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3); + break; + case HostShutdown: +// rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret); + break; + case FastIo: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); + break; + case AdapPrintfDone: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5); + break; + default: + BUG(); + break; + } +} + +/** + * aac_rx_start_adapter - activate adapter + * @dev: Adapter + * + * Start up processing on an i960 based AAC adapter + */ + +static void aac_rx_start_adapter(struct aac_dev *dev) +{ + unsigned long status; + struct aac_init *init; + + init = dev->init; + init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ); + /* + * Tell the adapter we are back and up and running so it will scan + * its command queues and enable our interrupts + */ + dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4); + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + rx_writeb(dev, MUnit.OIMR, 0xff); + rx_writel(dev, MUnit.ODR, 0xffffffff); +// rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK); + rx_writeb(dev, MUnit.OIMR, 0xfb); + + rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &status); +} + +/** + * aac_rx_init - initialize an i960 based AAC card + * @dev: device to configure + * @devnum: adapter number + * + * Allocate and set up resources for the i960 based AAC variants. The + * device_interface in the commregion will be allocated and linked + * to the comm region. + */ + +int aac_rx_init(struct aac_dev *dev, unsigned long num) +{ + unsigned long start; + unsigned long status; + int instance; + const char * name; + + dev->devnum = num; + + instance = dev->id; + name = dev->name; + + /* + * Map in the registers from the adapter. + */ + if((dev->regs.rx = (struct rx_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) + { + printk(KERN_WARNING "aacraid: unable to map i960.\n" ); + return -1; + } + /* + * Check to see if the board failed any self tests. + */ + if (rx_readl(dev, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) { + printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); + return -1; + } + /* + * Check to see if the board panic'd while booting. + */ + if (rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) { + printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance); + return -1; + } + start = jiffies; + /* + * Wait for the adapter to be up and running. Wait up to 30 seconds. + */ + while (!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) + { + if(time_after(jiffies, start+30*HZ)) + { + status = rx_readl(dev, IndexRegs.Mailbox[7]) >> 16; + printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status); + return -1; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) + { + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance); + return -1; + } + /* + * Fill in the function dispatch table. + */ + dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; + dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt; + dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; + dev->a_ops.adapter_notify = aac_rx_notify_adapter; + + if (aac_init_adapter(dev) == NULL) + return -1; + /* + * Start any kernel threads needed + */ + dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); + /* + * Tell the adapter that all is configured, and it can start + * accepting requests + */ + aac_rx_start_adapter(dev); + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aacraid/sap1sup.c linux-2.5/drivers/scsi/aacraid/sap1sup.c --- linux-2.5.13/drivers/scsi/aacraid/sap1sup.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/sap1sup.c Thu Dec 13 16:32:36 2001 @@ -0,0 +1,394 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1sup.c + * + * Abstract: Drawbridge specific support functions + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +static void aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct aac_dev *dev = dev_id; + unsigned short intstat, mask; + + intstat = sa_readw(dev, DoorbellReg_p); + /* + * Read mask and invert because drawbridge is reversed. + * This allows us to only service interrupts that have been enabled. + */ + mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK)); + + /* Check to see if this is our interrupt. If it isn't just return */ + + if (intstat & mask) { + if (intstat & PrintfReady) { + aac_printf(dev, le32_to_cpu(sa_readl(dev, Mailbox5))); + sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */ + sa_writew(dev, DoorbellReg_s, PrintfDone); + } else if (intstat & DOORBELL_1) { // dev -> Host Normal Command Ready + aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); + sa_writew(dev, DoorbellClrReg_p, DOORBELL_1); + } else if (intstat & DOORBELL_2) { // dev -> Host Normal Response Ready + aac_response_normal(&dev->queues->queue[HostNormRespQueue]); + sa_writew(dev, DoorbellClrReg_p, DOORBELL_2); + } else if (intstat & DOORBELL_3) { // dev -> Host Normal Command Not Full + sa_writew(dev, DoorbellClrReg_p, DOORBELL_3); + } else if (intstat & DOORBELL_4) { // dev -> Host Normal Response Not Full + sa_writew(dev, DoorbellClrReg_p, DOORBELL_4); + } + } +} + +/** + * aac_sa_enable_interrupt - enable an interrupt event + * @dev: Which adapter to enable. + * @event: Which adapter event. + * + * This routine will enable the corresponding adapter event to cause an interrupt on + * the host. + */ + +void aac_sa_enable_interrupt(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1); + break; + + case HostNormRespQue: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2); + break; + + case AdapNormCmdNotFull: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3); + break; + + case AdapNormRespNotFull: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4); + break; + } +} + +/** + * aac_sa_disable_interrupt - disable an interrupt event + * @dev: Which adapter to enable. + * @event: Which adapter event. + * + * This routine will enable the corresponding adapter event to cause an interrupt on + * the host. + */ + +void aac_sa_disable_interrupt (struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_1); + break; + + case HostNormRespQue: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_2); + break; + + case AdapNormCmdNotFull: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_3); + break; + + case AdapNormRespNotFull: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_4); + break; + } +} + +/** + * aac_sa_notify_adapter - handle adapter notification + * @dev: Adapter that notification is for + * @event: Event to notidy + * + * Notify the adapter of an event + */ + +void aac_sa_notify_adapter(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case AdapNormCmdQue: + sa_writew(dev, DoorbellReg_s,DOORBELL_1); + break; + case HostNormRespNotFull: + sa_writew(dev, DoorbellReg_s,DOORBELL_4); + break; + case AdapNormRespQue: + sa_writew(dev, DoorbellReg_s,DOORBELL_2); + break; + case HostNormCmdNotFull: + sa_writew(dev, DoorbellReg_s,DOORBELL_3); + break; + case HostShutdown: + //sa_sync_cmd(dev, HOST_CRASHING, 0, &ret); + break; + case FastIo: + sa_writew(dev, DoorbellReg_s,DOORBELL_6); + break; + case AdapPrintfDone: + sa_writew(dev, DoorbellReg_s,DOORBELL_5); + break; + default: + BUG(); + break; + } +} + + +/** + * sa_sync_cmd - send a command and wait + * @dev: Adapter + * @command: Command to execute + * @p1: first parameter + * @ret: adapter status + * + * This routine will send a synchronous comamnd to the adapter and wait + * for its completion. + */ + +static int sa_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *ret) +{ + unsigned long start; + int ok; + /* + * Write the Command into Mailbox 0 + */ + sa_writel(dev, Mailbox0, cpu_to_le32(command)); + /* + * Write the parameters into Mailboxes 1 - 4 + */ + sa_writel(dev, Mailbox1, cpu_to_le32(p1)); + sa_writel(dev, Mailbox2, 0); + sa_writel(dev, Mailbox3, 0); + sa_writel(dev, Mailbox4, 0); + /* + * Clear the synch command doorbell to start on a clean slate. + */ + sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); + /* + * Signal that there is a new synch command + */ + sa_writew(dev, DoorbellReg_s, DOORBELL_0); + + ok = 0; + start = jiffies; + + while(time_before(jiffies, start+30*HZ)) + { + /* + * Delay 5uS so that the monitor gets access + */ + udelay(5); + /* + * Mon110 will set doorbell0 bit when it has + * completed the command. + */ + if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0) { + ok = 1; + break; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + if (ok != 1) + return -ETIMEDOUT; + /* + * Clear the synch command doorbell. + */ + sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); + /* + * Pull the synch status from Mailbox 0. + */ + *ret = le32_to_cpu(sa_readl(dev, Mailbox0)); + return 0; +} + +/** + * aac_sa_interrupt_adapter - interrupt an adapter + * @dev: Which adapter to enable. + * + * Breakpoint an adapter. + */ + +static void aac_sa_interrupt_adapter (struct aac_dev *dev) +{ + unsigned long ret; + sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret); +} + +/** + * aac_sa_start_adapter - activate adapter + * @dev: Adapter + * + * Start up processing on an ARM based AAC adapter + */ + +static void aac_sa_start_adapter(struct aac_dev *dev) +{ + unsigned long ret; + struct aac_init *init; + /* + * Fill in the remaining pieces of the init. + */ + init = dev->init; + init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ); + + dprintk(("INIT\n")); + /* + * Tell the adapter we are back and up and running so it will scan its command + * queues and enable our interrupts + */ + dev->irq_mask = (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4); + /* + * First clear out all interrupts. Then enable the one's that + * we can handle. + */ + dprintk(("MASK\n")); + sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff)); + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); + dprintk(("SYNCCMD\n")); + sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &ret); +} + +/** + * aac_sa_init - initialize an ARM based AAC card + * @dev: device to configure + * @devnum: adapter number + * + * Allocate and set up resources for the ARM based AAC variants. The + * device_interface in the commregion will be allocated and linked + * to the comm region. + */ + +int aac_sa_init(struct aac_dev *dev, unsigned long devnum) +{ + unsigned long start; + unsigned long status; + int instance; + const char *name; + + dev->devnum = devnum; + + dprintk(("PREINST\n")); + instance = dev->id; + name = dev->name; + + /* + * Map in the registers from the adapter. + */ + dprintk(("PREMAP\n")); + + if((dev->regs.sa = (struct sa_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) + { + printk(KERN_WARNING "aacraid: unable to map ARM.\n" ); + return -1; + } + /* + * Check to see if the board failed any self tests. + */ + if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) { + printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance); + return -1; + } + /* + * Check to see if the board panic'd while booting. + */ + if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) { + printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance); + return -1; + } + start = jiffies; + /* + * Wait for the adapter to be up and running. Wait up to 3 minutes. + */ + while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) { + if (time_after(start+180*HZ, jiffies)) { + status = sa_readl(dev, Mailbox7) >> 16; + printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %d.\n", name, instance, le32_to_cpu(status)); + return -1; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + dprintk(("ATIRQ\n")); + if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) { + printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance); + return -1; + } + + /* + * Fill in the function dispatch table. + */ + + dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; + dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; + dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; + dev->a_ops.adapter_notify = aac_sa_notify_adapter; + + dprintk(("FUNCDONE\n")); + + if(aac_init_adapter(dev) == NULL) + return -1; + + dprintk(("NEWADAPTDONE\n")); + /* + * Start any kernel threads needed + */ + dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); + /* + * Tell the adapter that all is configure, and it can start + * accepting requests + */ + dprintk(("STARTING\n")); + aac_sa_start_adapter(dev); + dprintk(("STARTED\n")); + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aha1542.c linux-2.5/drivers/scsi/aha1542.c --- linux-2.5.13/drivers/scsi/aha1542.c Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/scsi/aha1542.c Fri May 3 18:26:46 2002 @@ -168,6 +168,7 @@ static struct Scsi_Host *aha_host[7]; /* One for each IRQ level (9-15) */ +static spinlock_t aha1542_lock = SPIN_LOCK_UNLOCKED; @@ -218,31 +219,34 @@ static int aha1542_out(unsigned int base, unchar * cmdp, int len) { unsigned long flags = 0; + int got_lock; - save_flags(flags); if (len == 1) { + got_lock = 0; while (1 == 1) { WAIT(STATUS(base), CDF, 0, CDF); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); if (inb(STATUS(base)) & CDF) { - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); continue; } outb(*cmdp, DATA(base)); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); return 0; } } else { - cli(); + spin_lock_irqsave(&aha1542_lock, flags); + got_lock = 1; while (len--) { WAIT(STATUS(base), CDF, 0, CDF); outb(*cmdp++, DATA(base)); } - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); } return 0; fail: - restore_flags(flags); + if (got_lock) + spin_unlock_irqrestore(&aha1542_lock, flags); printk(KERN_ERR "aha1542_out failed(%d): ", len + 1); aha1542_stat(); return 1; @@ -255,16 +259,15 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); while (len--) { WAIT(STATUS(base), DF, DF, 0); *cmdp++ = inb(DATA(base)); } - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); return 0; fail: - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); printk(KERN_ERR "aha1542_in failed(%d): ", len + 1); aha1542_stat(); return 1; @@ -277,16 +280,15 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); while (len--) { WAITd(STATUS(base), DF, DF, 0, 100); *cmdp++ = inb(DATA(base)); } - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); return 0; fail: - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); return 1; } @@ -484,8 +486,7 @@ } aha1542_intr_reset(shost->io_port); - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1; if (mbi >= 2 * AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES; @@ -499,7 +500,7 @@ } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used); if (mb[mbi].status == 0) { - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); /* Hmm, no mail. Must have read it the last time around */ if (!number_serviced && !needs_restart) printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n"); @@ -514,7 +515,7 @@ mbistatus = mb[mbi].status; mb[mbi].status = 0; HOSTDATA(shost)->aha1542_last_mbi_used = mbi; - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); #ifdef DEBUG { @@ -653,8 +654,7 @@ /* Use the outgoing mailboxes in a round-robin fashion, because this is how the host adapter will scan for them */ - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; @@ -674,7 +674,7 @@ screwing with this cdb. */ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo; - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); #ifdef DEBUG printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done); @@ -1179,12 +1179,14 @@ } } for (indx = 0; indx < sizeof(bases) / sizeof(bases[0]); indx++) - if (bases[indx] != 0 && !check_region(bases[indx], 4)) { + if (bases[indx] != 0 && request_region(bases[indx], 4, "aha1542")) { shpnt = scsi_register(tpnt, sizeof(struct aha1542_hostdata)); - if(shpnt==NULL) + if(shpnt==NULL) { + release_region(bases[indx], 4); continue; + } /* For now we do this - until kmalloc is more intelligent we are resigned to stupid hacks like this */ if (SCSI_BUF_PA(shpnt) >= ISA_DMA_THRESHOLD) { @@ -1242,18 +1244,17 @@ DEB(aha1542_stat()); DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level)); - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) { printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n"); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); goto unregister; } if (dma_chan != 0xFF) { if (request_dma(dma_chan, "aha1542")) { printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n"); free_irq(irq_level, NULL); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); goto unregister; } if (dma_chan == 0 || dma_chan >= 5) { @@ -1274,7 +1275,7 @@ HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1); HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1); memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint)); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); #if 0 DEB(printk(" *** READ CAPACITY ***\n")); @@ -1308,10 +1309,10 @@ aha1542_command(0, cmd, buffer, 512); } #endif - request_region(bases[indx], 4, "aha1542"); /* Register the IO ports that we use */ count++; continue; unregister: + release_region(bases[indx], 4); scsi_unregister(shpnt); continue; @@ -1376,8 +1377,7 @@ ccb = HOSTDATA(SCpnt->host)->ccb; mb = HOSTDATA(SCpnt->host)->mb; - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; @@ -1398,7 +1398,7 @@ screwing with this cdb. */ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo; - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo])); /* This gets trashed for some reason */ @@ -1590,6 +1590,7 @@ return FAILED; } +#if 0 /* * These are the old error handling routines. They are only temporarily * here while we play with the new error handling code. @@ -1606,8 +1607,7 @@ inb(STATUS(SCpnt->host->io_port)), inb(INTRFLAGS(SCpnt->host->io_port))); - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); mb = HOSTDATA(SCpnt->host)->mb; mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1; if (mbi >= 2 * AHA1542_MAILBOXES) @@ -1620,7 +1620,7 @@ if (mbi >= 2 * AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES; } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); if (mb[mbi].status) { printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n", @@ -1648,15 +1648,17 @@ DEB(printk("aha1542_abort\n")); #if 0 - save_flags(flags); - cli(); - for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) + spin_lock_irqsave(&aha1542_lock, flags); + for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) { if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) { mb[mbo].status = 2; /* Abort command */ aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */ - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); break; - }; + } + } + if (AHA1542_MAILBOXES == mbo) + spin_unlock_irqrestore(&aha1542_lock, flags); #endif return SCSI_ABORT_SNOOZE; } @@ -1777,6 +1779,7 @@ to request sense information in order to decide what to do next. */ return SCSI_RESET_PUNT; } +#endif /* end of big comment block around old_abort + old_reset */ #include "sd.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aha1542.h linux-2.5/drivers/scsi/aha1542.h --- linux-2.5.13/drivers/scsi/aha1542.h Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/scsi/aha1542.h Fri May 3 17:56:20 2002 @@ -137,8 +137,10 @@ static int aha1542_bus_reset(Scsi_Cmnd * SCpnt); static int aha1542_dev_reset(Scsi_Cmnd * SCpnt); static int aha1542_host_reset(Scsi_Cmnd * SCpnt); +#if 0 static int aha1542_old_abort(Scsi_Cmnd * SCpnt); static int aha1542_old_reset(Scsi_Cmnd *, unsigned int); +#endif static int aha1542_biosparam(Disk *, kdev_t, int*); #define AHA1542_MAILBOXES 8 @@ -154,8 +156,6 @@ detect: aha1542_detect, \ command: aha1542_command, \ queuecommand: aha1542_queuecommand, \ - abort: aha1542_old_abort, \ - reset: aha1542_old_reset, \ eh_abort_handler: aha1542_abort, \ eh_device_reset_handler: aha1542_dev_reset, \ eh_bus_reset_handler: aha1542_bus_reset, \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx.h linux-2.5/drivers/scsi/aic7xxx/aic7xxx.h --- linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx.h Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx.h Fri May 3 03:49:07 2002 @@ -51,6 +51,7 @@ /************************* Forward Declarations *******************************/ struct ahc_platform_data; struct scb_platform_data; +struct seeprom_descriptor; /****************************** Useful Macros *********************************/ #ifndef MAX @@ -1116,6 +1117,7 @@ int ahc_suspend(struct ahc_softc *ahc); int ahc_resume(struct ahc_softc *ahc); void ahc_softc_insert(struct ahc_softc *); +struct ahc_softc *ahc_find_softc(struct ahc_softc *ahc); void ahc_set_unit(struct ahc_softc *, int); void ahc_set_name(struct ahc_softc *, char *); void ahc_alloc_scbs(struct ahc_softc *ahc); @@ -1221,4 +1223,8 @@ /******************************* Debug ***************************************/ void ahc_print_scb(struct scb *scb); void ahc_dump_card_state(struct ahc_softc *ahc); +/******************************* SEEPROM *************************************/ +int ahc_acquire_seeprom(struct ahc_softc *ahc, + struct seeprom_descriptor *sd); +void ahc_release_seeprom(struct seeprom_descriptor *sd); #endif /* _AIC7XXX_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx.reg linux-2.5/drivers/scsi/aic7xxx/aic7xxx.reg --- linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx.reg Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx.reg Fri May 3 03:49:07 2002 @@ -1316,7 +1316,7 @@ bit SDMAENACK 0x10 bit HDMAEN 0x08 bit HDMAENACK 0x08 - bit DIRECTION 0x04 + bit DIRECTION 0x04 /* Set indicates PCI->SCSI */ bit FIFOFLUSH 0x02 bit FIFORESET 0x01 } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_93cx6.c linux-2.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c --- linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Fri May 3 03:49:07 2002 @@ -77,9 +77,13 @@ */ static struct seeprom_cmd { uint8_t len; - uint8_t bits[3]; + uint8_t bits[9]; } seeprom_read = {3, {1, 1, 0}}; +static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; +static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; +static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}}; + /* * Wait for the SEERDY to go high; about 800 ns. */ @@ -90,6 +94,49 @@ (void)SEEPROM_INB(sd); /* Clear clock */ /* + * Send a START condition and the given command + */ +static void +send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd) +{ + uint8_t temp; + int i = 0; + + /* Send chip select for one clock cycle. */ + temp = sd->sd_MS ^ sd->sd_CS; + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + + for (i = 0; i < cmd->len; i++) { + if (cmd->bits[i] != 0) + temp ^= sd->sd_DO; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + if (cmd->bits[i] != 0) + temp ^= sd->sd_DO; + } +} + +/* + * Clear CS put the chip in the reset state, where it can wait for new commands. + */ +static void +reset_seeprom(struct seeprom_descriptor *sd) +{ + uint8_t temp; + + temp = sd->sd_MS; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); +} + +/* * Read the serial EEPROM and returns 1 if successful and 0 if * not successful. */ @@ -110,26 +157,14 @@ * will range from 0 to count-1. */ for (k = start_addr; k < count + start_addr; k++) { - /* Send chip select for one clock cycle. */ - temp = sd->sd_MS ^ sd->sd_CS; - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - /* * Now we're ready to send the read command followed by the * address of the 16-bit register we want to read. */ - for (i = 0; i < seeprom_read.len; i++) { - if (seeprom_read.bits[i] != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if (seeprom_read.bits[i] != 0) - temp ^= sd->sd_DO; - } + send_seeprom_cmd(sd, &seeprom_read); + /* Send the 6 or 8 bit address (MSB first, LSB last). */ + temp = sd->sd_MS ^ sd->sd_CS; for (i = (sd->sd_chip - 1); i >= 0; i--) { if ((k & (1 << i)) != 0) temp ^= sd->sd_DO; @@ -161,13 +196,7 @@ buf[k - start_addr] = v; /* Reset the chip select for the next command cycle. */ - temp = sd->sd_MS; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); + reset_seeprom(sd); } #ifdef AHC_DUMP_EEPROM printf("\nSerial EEPROM:\n\t"); @@ -179,6 +208,75 @@ } printf ("\n"); #endif + return (1); +} + +/* + * Write the serial EEPROM and return 1 if successful and 0 if + * not successful. + */ +int +ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, + u_int start_addr, u_int count) +{ + uint16_t v; + uint8_t temp; + int i, k; + + /* Place the chip into write-enable mode */ + send_seeprom_cmd(sd, &seeprom_ewen); + reset_seeprom(sd); + + /* Write all requested data out to the seeprom. */ + temp = sd->sd_MS ^ sd->sd_CS; + for (k = start_addr; k < count + start_addr; k++) { + /* Send the write command */ + send_seeprom_cmd(sd, &seeprom_write); + + /* Send the 6 or 8 bit address (MSB first). */ + for (i = (sd->sd_chip - 1); i >= 0; i--) { + if ((k & (1 << i)) != 0) + temp ^= sd->sd_DO; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + if ((k & (1 << i)) != 0) + temp ^= sd->sd_DO; + } + + /* Write the 16 bit value, MSB first */ + v = buf[k - start_addr]; + for (i = 15; i >= 0; i--) { + if ((v & (1 << i)) != 0) + temp ^= sd->sd_DO; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + if ((v & (1 << i)) != 0) + temp ^= sd->sd_DO; + } + + /* Wait for the chip to complete the write */ + temp = sd->sd_MS; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + temp = sd->sd_MS ^ sd->sd_CS; + do { + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + } while ((SEEPROM_DATA_INB(sd) & sd->sd_DI) == 0); + + reset_seeprom(sd); + } + + /* Put the chip back into write-protect mode */ + send_seeprom_cmd(sd, &seeprom_ewds); + reset_seeprom(sd); + return (1); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_93cx6.h linux-2.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h --- linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Fri May 3 01:22:47 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Fri May 3 03:15:19 2002 @@ -95,6 +95,8 @@ int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, u_int start_addr, u_int count); +int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, + u_int start_addr, u_int count); int verify_cksum(struct seeprom_config *sc); #endif /* _AIC7XXX_93CX6_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.5/drivers/scsi/aic7xxx/aic7xxx_core.c --- linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_core.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_core.c Fri May 3 03:49:07 2002 @@ -810,7 +810,12 @@ * target does a command complete. */ ahc_freeze_devq(ahc, scb); - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + if ((scb->flags & SCB_SENSE) == 0) { + ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + } else { + scb->flags &= ~SCB_SENSE; + ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + } ahc_freeze_scb(scb); if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1482,7 +1487,7 @@ memcpy(tstate, master_tstate, sizeof(*tstate)); memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); tstate->ultraenb = 0; - for (i = 0; i < 16; i++) { + for (i = 0; i < AHC_NUM_TARGETS; i++) { memset(&tstate->transinfo[i].curr, 0, sizeof(tstate->transinfo[i].curr)); memset(&tstate->transinfo[i].goal, 0, @@ -3527,7 +3532,7 @@ ahc->bugs = AHC_BUGNONE; ahc->flags = AHC_FNONE; - for (i = 0; i < 16; i++) + for (i = 0; i < AHC_NUM_TARGETS; i++) TAILQ_INIT(&ahc->untagged_queues[i]); if (ahc_platform_alloc(ahc, platform_arg) != 0) { ahc_free(ahc); @@ -3612,6 +3617,22 @@ else TAILQ_INSERT_TAIL(&ahc_tailq, ahc, links); ahc->init_level++; +} + +/* + * Verify that the passed in softc pointer is for a + * controller that is still configured. + */ +struct ahc_softc * +ahc_find_softc(struct ahc_softc *ahc) +{ + struct ahc_softc *list_ahc; + + TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { + if (list_ahc == ahc) + return (ahc); + } + return (NULL); } void diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-2.5/drivers/scsi/aic7xxx/aic7xxx_pci.c --- linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_pci.c Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_pci.c Fri May 3 03:49:07 2002 @@ -679,9 +679,6 @@ static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, int *externalcable_present, int *eeprom_present); -static int acquire_seeprom(struct ahc_softc *ahc, - struct seeprom_descriptor *sd); -static void release_seeprom(struct seeprom_descriptor *sd); static void write_brdctl(struct ahc_softc *ahc, uint8_t value); static uint8_t read_brdctl(struct ahc_softc *ahc); @@ -999,6 +996,14 @@ if ((ahc->features & AHC_ULTRA2) != 0) ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0; + else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C) + /* + * External SCBRAM arbitration is flakey + * on these chips. Unfortunately this means + * we don't use the extra SCB ram space on the + * 3940AUW. + */ + ramps = 0; else if (chip >= AHC_AIC7870) ramps = (devconfig & RAMPSM) != 0; else @@ -1201,7 +1206,7 @@ sd.sd_DO = SEEDO; sd.sd_DI = SEEDI; - have_seeprom = acquire_seeprom(ahc, &sd); + have_seeprom = ahc_acquire_seeprom(ahc, &sd); if (have_seeprom) { if (bootverbose) @@ -1229,7 +1234,7 @@ } sd.sd_chip = C56_66; } - release_seeprom(&sd); + ahc_release_seeprom(&sd); } if (!have_seeprom) { @@ -1407,9 +1412,9 @@ } if (have_autoterm) { - acquire_seeprom(ahc, &sd); + ahc_acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, adapter_control, sxfrctl1); - release_seeprom(&sd); + ahc_release_seeprom(&sd); } } @@ -1706,8 +1711,8 @@ *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0; } -static int -acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd) +int +ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd) { int wait; @@ -1734,8 +1739,8 @@ return(1); } -static void -release_seeprom(struct seeprom_descriptor *sd) +void +ahc_release_seeprom(struct seeprom_descriptor *sd) { /* Release access to the memory port and the serial EEPROM. */ SEEPROM_OUTB(sd, 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_proc.c linux-2.5/drivers/scsi/aic7xxx/aic7xxx_proc.c --- linux-2.5.13/drivers/scsi/aic7xxx/aic7xxx_proc.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_proc.c Fri May 3 03:49:07 2002 @@ -41,6 +41,7 @@ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" +#include "aic7xxx_93cx6.h" static void copy_mem_info(struct info_str *info, char *data, int len); static int copy_info(struct info_str *info, char *fmt, ...); @@ -225,6 +226,55 @@ copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen); } +static int +ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length) +{ + struct seeprom_descriptor sd; + int have_seeprom; + + if (length != sizeof(struct seeprom_config)) { + printf("ahc_proc_write_seeprom: incorrect buffer size\n"); + return (-EINVAL); + } + + have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer); + if (have_seeprom == 0) { + printf("ahc_proc_write_seeprom: checksum verification failuire\n"); + return (-EINVAL); + } + + sd.sd_ahc = ahc; + sd.sd_control_offset = SEECTL; + sd.sd_status_offset = SEECTL; + sd.sd_dataout_offset = SEECTL; + if (ahc->flags & AHC_LARGE_SEEPROM) + sd.sd_chip = C56_66; + else + sd.sd_chip = C46; + sd.sd_MS = SEEMS; + sd.sd_RDY = SEERDY; + sd.sd_CS = SEECS; + sd.sd_CK = SEECK; + sd.sd_DO = SEEDO; + sd.sd_DI = SEEDI; + + have_seeprom = ahc_acquire_seeprom(ahc, &sd); + if (!have_seeprom) { + printf("ahc_proc_write_seeprom: No Serial EEPROM\n"); + return (-EINVAL); + } else { + u_int start_addr; + + printf("aic7xxx: Writing Serial EEPROM\n"); + start_addr = 32 * (ahc->channel - 'A'); + ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr, + sizeof(struct seeprom_config)); + ahc_release_seeprom(&sd); + } + + return (length); +} + /* * Return information to handle /proc support for the driver. */ @@ -234,9 +284,12 @@ { struct ahc_softc *ahc; struct info_str info; + struct seeprom_descriptor sd; char ahc_info[256]; + u_int16_t buf[32]; u_int max_targ; u_int i; + int have_seeprom; TAILQ_FOREACH(ahc, &ahc_tailq, links) { if (ahc->platform_data->host->host_no == hostno) @@ -248,7 +301,7 @@ /* Has data been written to the file? */ if (inout == TRUE) - return (-ENOSYS); + return (ahc_proc_write_seeprom(ahc, buffer, length)); if (start) *start = buffer; @@ -261,7 +314,51 @@ copy_info(&info, "Adaptec AIC7xxx driver version: %s\n", AIC7XXX_DRIVER_VERSION); ahc_controller_info(ahc, ahc_info); - copy_info(&info, "%s\n", ahc_info); + copy_info(&info, "%s\n\n", ahc_info); + + sd.sd_ahc = ahc; + sd.sd_control_offset = SEECTL; + sd.sd_status_offset = SEECTL; + sd.sd_dataout_offset = SEECTL; + if (ahc->flags & AHC_LARGE_SEEPROM) + sd.sd_chip = C56_66; + else + sd.sd_chip = C46; + sd.sd_MS = SEEMS; + sd.sd_RDY = SEERDY; + sd.sd_CS = SEECS; + sd.sd_CK = SEECK; + sd.sd_DO = SEEDO; + sd.sd_DI = SEEDI; + + have_seeprom = ahc_acquire_seeprom(ahc, &sd); + if (!have_seeprom) + copy_info(&info, "No Serial EEPROM\n"); + else { + u_int start_addr; + + start_addr = 32 * (ahc->channel - 'A'); + have_seeprom = ahc_read_seeprom(&sd, (u_int16_t *)&buf, + start_addr, sizeof(buf)/2); + if (have_seeprom) + have_seeprom = + ahc_verify_cksum((struct seeprom_config*)&buf); + if (have_seeprom == 0) + copy_info(&info, "Corrupted Serial EEPROM\n"); + else { + copy_info(&info, "Serial EEPROM:\n"); + for (i = 0; i < sizeof(buf)/2; i++) { + if (((i % 8) == 0) && (i != 0)) { + copy_info(&info, "\n"); + } + copy_info(&info, "0x%.4x ", buf[i]); + } + copy_info(&info, "\n"); + } + ahc_release_seeprom(&sd); + } + + copy_info(&info, "\n"); max_targ = 15; if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/Makefile linux-2.5/drivers/scsi/aic7xxx/aicasm/Makefile --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/Makefile Fri May 3 01:22:47 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/Makefile Fri May 3 03:49:07 2002 @@ -1,13 +1,16 @@ PROG= aicasm -.SUFFIXES= .l .y .c +.SUFFIXES= .l .y .c .h CSRCS= aicasm.c aicasm_symbol.c -GENSRCS= aicasm_gram.c aicasm_scan.c -GENHDRS= y.tab.h aicdb.h +YSRCS= aicasm_gram.y aicasm_macro_gram.y +LSRCS= aicasm_scan.l aicasm_macro_scan.l -SRCS= ${GENSRCS} ${CSRCS} -CLEANFILES= ${GENSRCS} ${GENHDRS} y.output +GENHDRS= aicdb.h $(YSRCS:.y=.h) +GENSRCS= $(YSRCS:.y=.c) $(LSRCS:.l=.c) + +SRCS= ${CSRCS} ${GENSRCS} +CLEANFILES= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) # Override default kernel CFLAGS. This is a userland app. AICASM_CFLAGS:= -I/usr/include -I. -ldb YFLAGS= -d @@ -26,7 +29,7 @@ LFLAGS= -d endif -$(PROG): $(SRCS) $(GENHDRS) +$(PROG): ${GENHDRS} $(SRCS) $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) aicdb.h: @@ -45,8 +48,18 @@ clean: rm -f $(CLEANFILES) $(PROG) -y.tab.h aicasm_gram.c: aicasm_gram.y - $(YACC) $(YFLAGS) aicasm_gram.y - mv y.tab.c aicasm_gram.c +aicasm_gram.c aicasm_gram.h: aicasm_gram.y + $(YACC) $(YFLAGS) -b $(<:.y=) $< + mv $(<:.y=).tab.c $(<:.y=.c) + mv $(<:.y=).tab.h $(<:.y=.h) + +aicasm_macro_gram.c aicasm_macro_gram.h: aicasm_macro_gram.y + $(YACC) $(YFLAGS) -b $(<:.y=) -p mm $< + mv $(<:.y=).tab.c $(<:.y=.c) + mv $(<:.y=).tab.h $(<:.y=.h) + +aicasm_scan.c: aicasm_scan.l + $(LEX) $(LFLAGS) -o$@ $< -aicasm_scan.c: y.tab.h +aicasm_macro_scan.c: aicasm_macro_scan.l + $(LEX) $(LFLAGS) -Pmm -o$@ $< diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm.c linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm.c --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm.c Fri May 3 01:22:48 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm.c Wed Mar 27 13:07:17 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#11 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.c,v 1.29 2000/10/05 04:25:42 gibbs Exp $ */ @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,8 @@ FILE *regfile; char *listfilename; FILE *listfile; +int src_mode; +int dst_mode; static STAILQ_HEAD(,instruction) seq_program; struct cs_tailq cs_tailq; @@ -98,7 +101,9 @@ #if DEBUG extern int yy_flex_debug; +extern int mm_flex_debug; extern int yydebug; +extern int mmdebug; #endif extern FILE *yyin; extern int yyparse(void); @@ -131,7 +136,9 @@ listfile = NULL; #if DEBUG yy_flex_debug = 0; + mm_flex_debug = 0; yydebug = 0; + mmdebug = 0; #endif while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) { switch(ch) { @@ -139,8 +146,10 @@ #if DEBUG if (strcmp(optarg, "s") == 0) { yy_flex_debug = 1; + mm_flex_debug = 1; } else if (strcmp(optarg, "p") == 0) { yydebug = 1; + mmdebug = 1; } else { fprintf(stderr, "%s: -d Requires either an " "'s' or 'p' argument\n", appname); @@ -243,8 +252,7 @@ if (retval == 0) { if (SLIST_FIRST(&scope_stack) == NULL || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { - stop("Unterminated conditional expression", - EX_DATAERR); + stop("Unterminated conditional expression", EX_DATAERR); /* NOTREACHED */ } @@ -355,6 +363,10 @@ } fprintf(ofile, "\n};\n\n"); + if (patch_arg_list == NULL) + stop("Patch argument list not defined", + EX_DATAERR); + /* * Output patch information. Patch functions first. */ @@ -362,31 +374,33 @@ cur_node != NULL; cur_node = SLIST_NEXT(cur_node,links)) { fprintf(ofile, -"static int ahc_patch%d_func(struct ahc_softc *ahc); +"static int aic_patch%d_func(%s); static int -ahc_patch%d_func(struct ahc_softc *ahc) +aic_patch%d_func(%s) { return (%s); }\n\n", cur_node->symbol->info.condinfo->func_num, + patch_arg_list, cur_node->symbol->info.condinfo->func_num, + patch_arg_list, cur_node->symbol->name); } fprintf(ofile, -"typedef int patch_func_t (struct ahc_softc *); -struct patch { +"typedef int patch_func_t (%s); +static struct patch { patch_func_t *patch_func; uint32_t begin :10, skip_instr :10, skip_patch :12; -} patches[] = {\n"); +} patches[] = {\n", patch_arg_list); for(cur_patch = STAILQ_FIRST(&patches); cur_patch != NULL; cur_patch = STAILQ_NEXT(cur_patch,links)) { - fprintf(ofile, "%s\t{ ahc_patch%d_func, %d, %d, %d }", + fprintf(ofile, "%s\t{ aic_patch%d_func, %d, %d, %d }", cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n", cur_patch->patch_func, cur_patch->begin, cur_patch->skip_instr, cur_patch->skip_patch); @@ -395,7 +409,7 @@ fprintf(ofile, "\n};\n"); fprintf(ofile, -"struct cs { +"static struct cs { u_int16_t begin; u_int16_t end; } critical_sections[] = {\n"); @@ -411,8 +425,8 @@ fprintf(ofile, "\n};\n"); fprintf(ofile, -"const int num_critical_sections = sizeof(critical_sections) - / sizeof(*critical_sections);\n"); +"static const int num_critical_sections = sizeof(critical_sections) + / sizeof(*critical_sections);\n"); fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm.h linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm.h --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm.h Fri May 3 01:22:48 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm.h Wed Mar 27 13:07:17 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.h#7 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.h,v 1.11 2000/09/22 22:19:54 gibbs Exp $ */ @@ -78,10 +78,15 @@ extern char *appname; extern int yylineno; extern char *yyfilename; +extern char *patch_arg_list; extern char *versions; +extern int src_mode; +extern int dst_mode; +struct symbol; void stop(const char *errstring, int err_code); void include_file(char *file_name, include_type type); +void expand_macro(struct symbol *macro_symbol); struct instruction *seq_alloc(void); struct critical_section *cs_alloc(void); struct scope *scope_alloc(void); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y Wed May 1 21:01:21 2002 @@ -38,18 +38,20 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#9 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_gram.y,v 1.12 2000/10/31 18:44:32 gibbs Exp $ */ +#include + #include +#include #include #include #include #include -#include #ifdef __linux__ #include "../queue.h" #else @@ -62,21 +64,29 @@ int yylineno; char *yyfilename; +char *patch_arg_list; char *versions; +static char errbuf[255]; +static char regex_pattern[255]; static symbol_t *cur_symbol; +static symbol_t *scb_or_sram_symbol; static symtype cur_symtype; -static symbol_t *accumulator; +static symbol_ref_t accumulator; +static symbol_ref_t mode_ptr; static symbol_ref_t allones; static symbol_ref_t allzeros; static symbol_ref_t none; static symbol_ref_t sindex; static int instruction_ptr; +static int num_srams; static int sram_or_scb_offset; static int download_constant_count; static int in_critical_section; static void process_bitmask(int mask_type, symbol_t *sym, int mask); static void initialize_symbol(symbol_t *symbol); +static void add_macro_arg(const char *argtext, int position); +static void add_macro_body(const char *bodytext); static void process_register(symbol_t **p_symbol); static void format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed, symbol_ref_t *src, int ret); @@ -92,13 +102,12 @@ static void add_version(const char *verstring); static int is_download_const(expression_t *immed); -#define YYDEBUG 1 #define SRAM_SYMNAME "SRAM_BASE" #define SCB_SYMNAME "SCB_BASE" %} %union { - int value; + u_int value; char *str; symbol_t *sym; symbol_ref_t sym_ref; @@ -109,6 +118,8 @@ %token T_CONST +%token T_EXPORT + %token T_DOWNLOAD %token T_SCB @@ -119,10 +130,22 @@ %token T_SIZE +%token T_EXPR_LSHIFT + +%token T_EXPR_RSHIFT + %token T_ADDRESS %token T_ACCESS_MODE +%token T_MODES + +%token T_DEFINE + +%token T_SET_SRC_MODE + +%token T_SET_DST_MODE + %token T_MODE %token T_BEGIN_CS @@ -135,11 +158,11 @@ %token T_NUMBER -%token T_PATH T_STRING +%token T_PATH T_STRING T_ARG T_MACROBODY %token T_CEXPR -%token T_EOF T_INCLUDE T_VERSION +%token T_EOF T_INCLUDE T_VERSION T_PATCH_ARG_LIST %token T_SHR T_SHL T_ROR T_ROL @@ -163,7 +186,7 @@ %token T_NOP -%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX +%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX T_MODE_PTR %token T_A @@ -177,13 +200,15 @@ %type expression immediate immediate_or_a -%type ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne +%type export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne -%type numerical_value +%type numerical_value mode_value mode_list macro_arglist %left '|' %left '&' +%left T_EXPR_LSHIFT T_EXPR_RSHIFT %left '+' '-' +%left '*' '/' %right '~' %nonassoc UMINUS %% @@ -191,18 +216,26 @@ program: include | program include +| patch_arg_list +| program patch_arg_list | version | program version | register | program register | constant | program constant +| macrodefn +| program macrodefn | scratch_ram | program scratch_ram | scb | program scb | label | program label +| set_src_mode +| program set_src_mode +| set_dst_mode +| program set_dst_mode | critical_section_start | program critical_section_start | critical_section_end @@ -224,6 +257,18 @@ } ; +patch_arg_list: + T_PATCH_ARG_LIST '=' T_STRING + { + if (patch_arg_list != NULL) + stop("Patch argument list multiply defined", + EX_DATAERR); + patch_arg_list = strdup($3); + if (patch_arg_list == NULL) + stop("Unable to record patch arg list", EX_SOFTWARE); + } +; + version: T_VERSION '=' T_STRING { add_version($3); } @@ -280,10 +325,12 @@ reg_address | size | access_mode +| modes | bit_defn | mask_defn | alias | accumulator +| mode_pointer | allones | allzeros | none @@ -301,6 +348,18 @@ T_SIZE T_NUMBER { cur_symbol->info.rinfo->size = $2; + if (scb_or_sram_symbol != NULL) { + u_int max_addr; + u_int sym_max_addr; + + max_addr = scb_or_sram_symbol->info.rinfo->address + + scb_or_sram_symbol->info.rinfo->size; + sym_max_addr = cur_symbol->info.rinfo->address + + cur_symbol->info.rinfo->size; + + if (sym_max_addr > max_addr) + stop("SCB or SRAM space exhausted", EX_DATAERR); + } } ; @@ -311,6 +370,54 @@ } ; +modes: + T_MODES mode_list + { + cur_symbol->info.rinfo->modes = $2; + } +; + +mode_list: + mode_value + { + $$ = $1; + } +| mode_list ',' mode_value + { + $$ = $1 | $3; + } +; + +mode_value: + T_NUMBER + { + if ($1 > 4) { + stop("Valid register modes range between 0 and 4.", + EX_DATAERR); + /* NOTREACHED */ + } + + $$ = (0x1 << $1); + } +| T_SYMBOL + { + symbol_t *symbol; + + symbol = $1; + if (symbol->type != CONST) { + stop("Only \"const\" symbols allowed in " + "mode definitions.", EX_DATAERR); + /* NOTREACHED */ + } + if (symbol->info.cinfo->value > 4) { + stop("Valid register modes range between 0 and 4.", + EX_DATAERR); + /* NOTREACHED */ + } + $$ = (0x1 << symbol->info.cinfo->value); + } +; + bit_defn: T_BIT T_SYMBOL T_NUMBER { @@ -342,12 +449,24 @@ accumulator: T_ACCUM { - if (accumulator != NULL) { + if (accumulator.symbol != NULL) { stop("Only one accumulator definition allowed", EX_DATAERR); /* NOTREACHED */ } - accumulator = cur_symbol; + accumulator.symbol = cur_symbol; + } +; + +mode_pointer: + T_MODE_PTR + { + if (mode_ptr.symbol != NULL) { + stop("Only one mode pointer definition allowed", + EX_DATAERR); + /* NOTREACHED */ + } + mode_ptr.symbol = cur_symbol; } ; @@ -428,6 +547,34 @@ &($1.referenced_syms), &($3.referenced_syms)); } +| expression '*' expression + { + $$.value = $1.value * $3.value; + symlist_merge(&($$.referenced_syms), + &($1.referenced_syms), + &($3.referenced_syms)); + } +| expression '/' expression + { + $$.value = $1.value / $3.value; + symlist_merge(&($$.referenced_syms), + &($1.referenced_syms), + &($3.referenced_syms)); + } +| expression T_EXPR_LSHIFT expression + { + $$.value = $1.value << $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } +| expression T_EXPR_RSHIFT expression + { + $$.value = $1.value >> $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } | '(' expression ')' { $$ = $2; @@ -471,12 +618,10 @@ case UNINITIALIZED: default: { - char buf[255]; - - snprintf(buf, sizeof(buf), + snprintf(errbuf, sizeof(errbuf), "Undefined symbol %s referenced", symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); /* NOTREACHED */ break; } @@ -497,7 +642,6 @@ $2->type = CONST; initialize_symbol($2); $2->info.cinfo->value = $3; - $2->info.cinfo->define = $1; } | T_CONST T_SYMBOL T_DOWNLOAD { @@ -514,7 +658,54 @@ $2->type = DOWNLOAD_CONST; initialize_symbol($2); $2->info.cinfo->value = download_constant_count++; - $2->info.cinfo->define = FALSE; + } +; + +macrodefn_prologue: + T_DEFINE T_SYMBOL + { + if ($2->type != UNINITIALIZED) { + stop("Re-definition of symbol as a macro", + EX_DATAERR); + /* NOTREACHED */ + } + cur_symbol = $2; + cur_symbol->type = MACRO; + initialize_symbol(cur_symbol); + } +; + +macrodefn: + macrodefn_prologue T_MACROBODY + { + add_macro_body($2); + } +| macrodefn_prologue '(' macro_arglist ')' T_MACROBODY + { + add_macro_body($5); + cur_symbol->info.macroinfo->narg = $3; + } +; + +macro_arglist: + { + /* Macros can take no arguments */ + $$ = 0; + } +| T_ARG + { + $$ = 1; + add_macro_arg($1, 0); + } +| macro_arglist ',' T_ARG + { + if ($1 == 0) { + stop("Comma without preceeding argument in arg list", + EX_DATAERR); + /* NOTREACHED */ + } + $$ = $1 + 1; + add_macro_arg($3, $1); } ; @@ -532,13 +723,10 @@ scratch_ram: T_SRAM '{' { + snprintf(errbuf, sizeof(errbuf), "%s%d", SRAM_SYMNAME, + num_srams); cur_symbol = symtable_get(SRAM_SYMNAME); cur_symtype = SRAMLOC; - if (cur_symbol->type != UNINITIALIZED) { - stop("Only one SRAM definition allowed", - EX_DATAERR); - /* NOTREACHED */ - } cur_symbol->type = SRAMLOC; initialize_symbol(cur_symbol); } @@ -546,10 +734,15 @@ { sram_or_scb_offset = cur_symbol->info.rinfo->address; } - scb_or_sram_reg_list + size + { + scb_or_sram_symbol = cur_symbol; + } + scb_or_sram_attributes '}' { cur_symbol = NULL; + scb_or_sram_symbol = NULL; } ; @@ -572,13 +765,25 @@ { sram_or_scb_offset = cur_symbol->info.rinfo->address; } - scb_or_sram_reg_list + size + { + scb_or_sram_symbol = cur_symbol; + } + scb_or_sram_attributes '}' { cur_symbol = NULL; + scb_or_sram_symbol = NULL; } ; +scb_or_sram_attributes: + /* NULL definition is okay */ +| modes +| scb_or_sram_reg_list +| modes scb_or_sram_reg_list +; + scb_or_sram_reg_list: reg_definition | scb_or_sram_reg_list reg_definition @@ -619,11 +824,11 @@ } | T_A { - if (accumulator == NULL) { + if (accumulator.symbol == NULL) { stop("No accumulator has been defined", EX_DATAERR); /* NOTREACHED */ } - $$.symbol = accumulator; + $$.symbol = accumulator.symbol; $$.offset = 0; } ; @@ -644,6 +849,14 @@ immediate_or_a: expression { + if ($1.value == 0 && is_download_const(&$1) == 0) { + snprintf(errbuf, sizeof(errbuf), + "\nExpression evaluates to 0 and thus " + "references the accumulator.\n " + "If this is the desired effect, use 'A' " + "instead.\n"); + stop(errbuf, EX_DATAERR); + } $$ = $1; } | T_A @@ -676,8 +889,22 @@ { $$ = 1; } ; +set_src_mode: + T_SET_SRC_MODE T_NUMBER ';' + { + src_mode = $2; + } +; + +set_dst_mode: + T_SET_DST_MODE T_NUMBER ';' + { + dst_mode = $2; + } +; + critical_section_start: - T_BEGIN_CS + T_BEGIN_CS ';' { critical_section_t *cs; @@ -690,9 +917,10 @@ cs->begin_addr = instruction_ptr; in_critical_section = TRUE; } +; critical_section_end: - T_END_CS + T_END_CS ';' { critical_section_t *cs; @@ -704,17 +932,25 @@ cs->end_addr = instruction_ptr; in_critical_section = FALSE; } +; + +export: + { $$ = 0; } +| T_EXPORT + { $$ = 1; } +; label: - T_SYMBOL ':' + export T_SYMBOL ':' { - if ($1->type != UNINITIALIZED) { + if ($2->type != UNINITIALIZED) { stop("Program label multiply defined", EX_DATAERR); /* NOTREACHED */ } - $1->type = LABEL; - initialize_symbol($1); - $1->info.linfo->address = instruction_ptr; + $2->type = LABEL; + initialize_symbol($2); + $2->info.linfo->address = instruction_ptr; + $2->info.linfo->exported = $1; } ; @@ -1128,6 +1364,16 @@ } memset(symbol->info.rinfo, 0, sizeof(struct reg_info)); + /* + * Default to allowing access in all register modes + * or to the mode specified by the SCB or SRAM space + * we are in. + */ + if (scb_or_sram_symbol != NULL) + symbol->info.rinfo->modes = + scb_or_sram_symbol->info.rinfo->modes; + else + symbol->info.rinfo->modes = ~0; break; case ALIAS: symbol->info.ainfo = @@ -1181,6 +1427,17 @@ memset(symbol->info.condinfo, 0, sizeof(struct cond_info)); break; + case MACRO: + symbol->info.macroinfo = + (struct macro_info *)malloc(sizeof(struct macro_info)); + if (symbol->info.macroinfo == NULL) { + stop("Can't create macro info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.macroinfo, 0, + sizeof(struct macro_info)); + STAILQ_INIT(&symbol->info.macroinfo->args); + break; default: stop("Call to initialize_symbol with invalid symbol type", EX_SOFTWARE); @@ -1190,25 +1447,75 @@ } static void +add_macro_arg(const char *argtext, int argnum) +{ + struct macro_arg *marg; + int i; + int retval; + + + if (cur_symbol == NULL || cur_symbol->type != MACRO) { + stop("Invalid current symbol for adding macro arg", + EX_SOFTWARE); + /* NOTREACHED */ + } + + marg = (struct macro_arg *)malloc(sizeof(*marg)); + if (marg == NULL) { + stop("Can't create macro_arg structure", EX_SOFTWARE); + /* NOTREACHED */ + } + marg->replacement_text = NULL; + retval = snprintf(regex_pattern, sizeof(regex_pattern), + "[^-/A-Za-z0-9_](%s)([^-/A-Za-z0-9_]|$)", + argtext); + if (retval >= sizeof(regex_pattern)) { + stop("Regex text buffer too small for arg", + EX_SOFTWARE); + /* NOTREACHED */ + } + retval = regcomp(&marg->arg_regex, regex_pattern, REG_EXTENDED); + if (retval != 0) { + stop("Regex compilation failed", EX_SOFTWARE); + /* NOTREACHED */ + } + STAILQ_INSERT_TAIL(&cur_symbol->info.macroinfo->args, marg, links); +} + +static void +add_macro_body(const char *bodytext) +{ + if (cur_symbol == NULL || cur_symbol->type != MACRO) { + stop("Invalid current symbol for adding macro arg", + EX_SOFTWARE); + /* NOTREACHED */ + } + cur_symbol->info.macroinfo->body = strdup(bodytext); + if (cur_symbol->info.macroinfo->body == NULL) { + stop("Can't duplicate macro body text", EX_SOFTWARE); + /* NOTREACHED */ + } +} + +static void process_register(symbol_t **p_symbol) { - char buf[255]; symbol_t *symbol = *p_symbol; if (symbol->type == UNINITIALIZED) { - snprintf(buf, sizeof(buf), "Undefined register %s", + snprintf(errbuf, sizeof(errbuf), "Undefined register %s", symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); /* NOTREACHED */ } else if (symbol->type == ALIAS) { *p_symbol = symbol->info.ainfo->parent; } else if ((symbol->type != REGISTER) && (symbol->type != SCBLOC) && (symbol->type != SRAMLOC)) { - snprintf(buf, sizeof(buf), + snprintf(errbuf, sizeof(errbuf), "Specified symbol %s is not a register", symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); } } @@ -1242,6 +1549,47 @@ if (is_download_const(immed)) f1_instr->parity = 1; + else if (dest->symbol == mode_ptr.symbol) { + u_int src_value; + u_int dst_value; + + /* + * Attempt to update mode information if + * we are operating on the mode register. + */ + if (src->symbol == allones.symbol) + src_value = 0xFF; + else if (src->symbol == allzeros.symbol) + src_value = 0; + else if (src->symbol == mode_ptr.symbol) + src_value = (dst_mode << 4) | src_mode; + else + goto cant_update; + + switch (opcode) { + case AIC_OP_AND: + dst_value = src_value & immed->value; + break; + case AIC_OP_XOR: + dst_value = src_value ^ immed->value; + break; + case AIC_OP_ADD: + dst_value = (src_value + immed->value) & 0xFF; + break; + case AIC_OP_OR: + dst_value = src_value | immed->value; + break; + break; + case AIC_OP_BMOV: + dst_value = src_value; + break; + default: + goto cant_update; + } + src_mode = dst_value & 0xF; + dst_mode = (dst_value >> 4) & 0xF; +cant_update: + } symlist_free(&immed->referenced_syms); instruction_ptr++; @@ -1350,6 +1698,14 @@ static void test_readable_symbol(symbol_t *symbol) { + + if ((symbol->info.rinfo->modes & (0x1 << src_mode)) == 0) { + snprintf(errbuf, sizeof(errbuf), + "Register %s unavailable in source reg mode %d", + symbol->name, src_mode); + stop(errbuf, EX_DATAERR); + } + if (symbol->info.rinfo->mode == WO) { stop("Write Only register specified as source", EX_DATAERR); @@ -1360,6 +1716,14 @@ static void test_writable_symbol(symbol_t *symbol) { + + if ((symbol->info.rinfo->modes & (0x1 << dst_mode)) == 0) { + snprintf(errbuf, sizeof(errbuf), + "Register %s unavailable in destination reg mode %d", + symbol->name, dst_mode); + stop(errbuf, EX_DATAERR); + } + if (symbol->info.rinfo->mode == RO) { stop("Read Only register specified as destination", EX_DATAERR); @@ -1372,7 +1736,6 @@ { symbol_node_t *node; int and_op; - char buf[255]; and_op = FALSE; if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ) @@ -1385,11 +1748,11 @@ */ if (and_op == FALSE && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) { - snprintf(buf, sizeof(buf), + snprintf(errbuf, sizeof(errbuf), "Invalid bit(s) 0x%x in immediate written to %s", expression->value & ~symbol->info.rinfo->valid_bitmask, symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); /* NOTREACHED */ } @@ -1397,7 +1760,7 @@ * Now make sure that all of the symbols referenced by the * expression are defined for this register. */ - if(symbol->info.rinfo->typecheck_masks != FALSE) { + if (symbol->info.rinfo->typecheck_masks != FALSE) { for(node = expression->referenced_syms.slh_first; node != NULL; node = node->links.sle_next) { @@ -1405,11 +1768,11 @@ || node->symbol->type == BIT) && symlist_search(&node->symbol->info.minfo->symrefs, symbol->name) == NULL) { - snprintf(buf, sizeof(buf), + snprintf(errbuf, sizeof(errbuf), "Invalid bit or mask %s " "for register %s", node->symbol->name, symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); /* NOTREACHED */ } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h Wed Mar 27 13:07:17 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#7 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_insformat.h,v 1.3 2000/09/22 22:19:54 gibbs Exp $ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y Thu Mar 28 01:21:36 2002 @@ -0,0 +1,164 @@ +%{ +/* + * Sub-parser for macro invocation in the Aic7xxx SCSI + * Host adapter sequencer assembler. + * + * Copyright (c) 2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $Id$ + * + * $FreeBSD$ + */ + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include "../queue.h" +#else +#include +#endif + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "aicasm_insformat.h" + +static symbol_t *macro_symbol; + +static void add_macro_arg(const char *argtext, int position); + +%} + +%union { + int value; + char *str; + symbol_t *sym; +} + + +%token T_ARG + +%token T_SYMBOL + +%type macro_arglist + +%% + +macrocall: + T_SYMBOL '(' + { + macro_symbol = $1; + } + macro_arglist ')' + { + if (macro_symbol->info.macroinfo->narg != $4) { + printf("Narg == %d", macro_symbol->info.macroinfo->narg); + stop("Too few arguments for macro invocation", + EX_DATAERR); + /* NOTREACHED */ + } + macro_symbol = NULL; + YYACCEPT; + } +; + +macro_arglist: + { + /* Macros can take 0 arguments */ + $$ = 0; + } +| T_ARG + { + $$ = 1; + add_macro_arg($1, 1); + } +| macro_arglist ',' T_ARG + { + if ($1 == 0) { + stop("Comma without preceeding argument in arg list", + EX_DATAERR); + /* NOTREACHED */ + } + $$ = $1 + 1; + add_macro_arg($3, $$); + } +; + +%% + +static void +add_macro_arg(const char *argtext, int argnum) +{ + struct macro_arg *marg; + int i; + + if (macro_symbol == NULL || macro_symbol->type != MACRO) { + stop("Invalid current symbol for adding macro arg", + EX_SOFTWARE); + /* NOTREACHED */ + } + /* + * Macro Invocation. Find the appropriate argument and fill + * in the replace ment text for this call. + */ + i = 0; + STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { + i++; + if (i == argnum) + break; + } + if (marg == NULL) { + stop("Too many arguments for macro invocation", EX_DATAERR); + /* NOTREACHED */ + } + marg->replacement_text = strdup(argtext); + if (marg->replacement_text == NULL) { + stop("Unable to replicate replacement text", EX_SOFTWARE); + /* NOTREACHED */ + } +} + +void +mmerror(const char *string) +{ + stop(string, EX_DATAERR); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l Thu Mar 28 01:21:36 2002 @@ -0,0 +1,154 @@ +%{ +/* + * Sub-Lexical Analyzer for macro invokation in + * the Aic7xxx SCSI Host adapter sequencer assembler. + * + * Copyright (c) 2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $Id$ + * + * $FreeBSD$ + */ + +#include + +#include +#include +#include +#include +#include +#ifdef __linux__ +#include "../queue.h" +#else +#include +#endif + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "aicasm_macro_gram.h" + +#define MAX_STR_CONST 4096 +static char string_buf[MAX_STR_CONST]; +static char *string_buf_ptr; +static int parren_count; +static char buf[255]; +%} + +WORD [A-Za-z_][-A-Za-z_0-9]* +SPACE [ \t]+ +MCARG [^(), \t]+ + +%x ARGLIST + +%% +\n { + ++yylineno; + } +{SPACE} ; +\( { + parren_count++; + if (parren_count == 1) { + string_buf_ptr = string_buf; + return ('('); + } + *string_buf_ptr++ = '('; + } +\) { + if (parren_count == 1) { + if (string_buf_ptr != string_buf) { + /* + * Return an argument and + * rescan this parren so we + * can return it as well. + */ + *string_buf_ptr = '\0'; + mmlval.str = string_buf; + string_buf_ptr = string_buf; + unput(')'); + return T_ARG; + } + BEGIN INITIAL; + return (')'); + } + parren_count--; + *string_buf_ptr++ = ')'; + } +{MCARG} { + char *yptr; + + yptr = mmtext; + while (*yptr) + *string_buf_ptr++ = *yptr++; + } +\, { + if (string_buf_ptr != string_buf) { + /* + * Return an argument and + * rescan this comma so we + * can return it as well. + */ + *string_buf_ptr = '\0'; + mmlval.str = string_buf; + string_buf_ptr = string_buf; + unput(','); + return T_ARG; + } + return ','; + } +{WORD}[(] { + /* May be a symbol or a macro invocation. */ + mmlval.sym = symtable_get(mmtext); + if (mmlval.sym->type != MACRO) { + stop("Expecting Macro Name", + EX_DATAERR); + } + unput('('); + parren_count = 0; + BEGIN ARGLIST; + return T_SYMBOL; + } +. { + snprintf(buf, sizeof(buf), "Invalid character " + "'%c'", mmtext[0]); + stop(buf, EX_DATAERR); + } +%% + +int +mmwrap() +{ + stop("EOF encountered in macro call", EX_DATAERR); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l Wed Mar 27 13:07:17 2002 @@ -38,14 +38,15 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#7 $ + * $Id$ * - * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_scan.l,v 1.13 2000/09/22 22:19:54 gibbs Exp $ + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_scan.l,v 1.13.2.3 2001/07/28 18:46:44 gibbs Exp $ */ #include #include +#include #include #include #include @@ -57,23 +58,31 @@ #include "aicasm.h" #include "aicasm_symbol.h" -#include "y.tab.h" +#include "aicasm_gram.h" -#define MAX_STR_CONST 256 -char string_buf[MAX_STR_CONST]; -char *string_buf_ptr; -int parren_count; -int quote_count; +/* This is used for macro body capture too, so err on the large size. */ +#define MAX_STR_CONST 4096 +static char string_buf[MAX_STR_CONST]; +static char *string_buf_ptr; +static int parren_count; +static int quote_count; +static char buf[255]; %} -PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]* +PATH ([/]*[-A-Za-z0-9_.])+ WORD [A-Za-z_][-A-Za-z_0-9]* SPACE [ \t]+ +MCARG [^(), \t]+ +MBODY ((\\[^\n])*[^\n\\]*)+ %x COMMENT %x CEXPR %x INCLUDE %x STRING +%x MACRODEF +%x MACROARGLIST +%x MACROCALLARGS +%x MACROBODY %% \n { ++yylineno; } @@ -122,6 +131,7 @@ } VERSION { return T_VERSION; } +PATCH_ARG_LIST { return T_PATCH_ARG_LIST; } \" { string_buf_ptr = string_buf; BEGIN STRING; @@ -140,14 +150,16 @@ yylval.str = string_buf; return T_STRING; } -{SPACE} ; +{SPACE} ; /* Register/SCB/SRAM definition keywords */ +export { return T_EXPORT; } register { return T_REGISTER; } const { yylval.value = FALSE; return T_CONST; } download { return T_DOWNLOAD; } address { return T_ADDRESS; } access_mode { return T_ACCESS_MODE; } +modes { return T_MODES; } RW|RO|WO { if (strcmp(yytext, "RW") == 0) yylval.value = RW; @@ -159,6 +171,8 @@ } BEGIN_CRITICAL { return T_BEGIN_CS; } END_CRITICAL { return T_END_CS; } +SET_SRC_MODE { return T_SET_SRC_MODE; } +SET_DST_MODE { return T_SET_DST_MODE; } bit { return T_BIT; } mask { return T_MASK; } alias { return T_ALIAS; } @@ -166,6 +180,7 @@ scb { return T_SCB; } scratch_ram { return T_SRAM; } accumulator { return T_ACCUM; } +mode_pointer { return T_MODE_PTR; } allones { return T_ALLONES; } allzeros { return T_ALLZEROS; } none { return T_NONE; } @@ -206,7 +221,9 @@ else { return T_ELSE; } /* Allowed Symbols */ -[-+,:()~|&."{};<>[\]!=] { return yytext[0]; } +\<\< { return T_EXPR_LSHIFT; } +\>\> { return T_EXPR_RSHIFT; } +[-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; } /* Number processing */ 0[0-7]* { @@ -223,7 +240,6 @@ yylval.value = strtol(yytext, NULL, 10); return T_NUMBER; } - /* Include Files */ #include{SPACE} { BEGIN INCLUDE; @@ -238,13 +254,7 @@ quote_count++; return yytext[0]; } -. { stop("Invalid include line", EX_DATAERR); } - - /* For parsing C include files with #define foo */ -#define { yylval.value = TRUE; return T_CONST; } - /* Throw away macros */ -#define[^\n]*[()]+[^\n]* ; -{PATH} { +{PATH} { char *yptr; yptr = yytext; @@ -255,12 +265,158 @@ *string_buf_ptr = '\0'; return T_PATH; } +. { stop("Invalid include line", EX_DATAERR); } +#define{SPACE} { + BEGIN MACRODEF; + return T_DEFINE; + } +{WORD}{SPACE} { + char *yptr; -{WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; } + /* Strip space and return as a normal symbol */ + yptr = yytext; + while (*yptr != ' ' && *yptr != '\t') + yptr++; + *yptr = '\0'; + yylval.sym = symtable_get(yytext); + string_buf_ptr = string_buf; + BEGIN MACROBODY; + return T_SYMBOL; + } +{WORD}\( { + /* + * We store the symbol with its opening + * parren so we can differentiate macros + * that take args from macros with the + * same name that do not take args as + * is allowed in C. + */ + BEGIN MACROARGLIST; + yylval.sym = symtable_get(yytext); + unput('('); + return T_SYMBOL; + } +{WORD} { + yylval.str = yytext; + return T_ARG; + } +{SPACE} ; +[(,] { + return yytext[0]; + } +[)] { + string_buf_ptr = string_buf; + BEGIN MACROBODY; + return ')'; + } +. { + snprintf(buf, sizeof(buf), "Invalid character " + "'%c' in macro argument list", + yytext[0]); + stop(buf, EX_DATAERR); + } +{SPACE} ; +\( { + parren_count++; + if (parren_count == 1) + return ('('); + *string_buf_ptr++ = '('; + } +\) { + parren_count--; + if (parren_count == 0) { + BEGIN INITIAL; + return (')'); + } + *string_buf_ptr++ = ')'; + } +{MCARG} { + char *yptr; -. { - char buf[255]; + yptr = yytext; + while (*yptr) + *string_buf_ptr++ = *yptr++; + } +\, { + if (string_buf_ptr != string_buf) { + /* + * Return an argument and + * rescan this comma so we + * can return it as well. + */ + *string_buf_ptr = '\0'; + yylval.str = string_buf; + string_buf_ptr = string_buf; + unput(','); + return T_ARG; + } + return ','; + } +\\\n { + /* Eat escaped newlines. */ + ++yylineno; + } +\n { + /* Macros end on the first unescaped newline. */ + BEGIN INITIAL; + *string_buf_ptr = '\0'; + yylval.str = string_buf; + ++yylineno; + return T_MACROBODY; + } +{MBODY} { + char *yptr; + + yptr = yytext; + while (*yptr) + *string_buf_ptr++ = *yptr++; + } +{WORD}\( { + char *yptr; + char *ycopy; + /* May be a symbol or a macro invocation. */ + yylval.sym = symtable_get(yytext); + if (yylval.sym->type == MACRO) { + YY_BUFFER_STATE old_state; + YY_BUFFER_STATE temp_state; + + ycopy = strdup(yytext); + yptr = ycopy + yyleng; + while (yptr > ycopy) + unput(*--yptr); + old_state = YY_CURRENT_BUFFER; + temp_state = + yy_create_buffer(stdin, + YY_BUF_SIZE); + yy_switch_to_buffer(temp_state); + mm_switch_to_buffer(old_state); + mmparse(); + mm_switch_to_buffer(temp_state); + yy_switch_to_buffer(old_state); + mm_delete_buffer(temp_state); + expand_macro(yylval.sym); + } else { + if (yylval.sym->type == UNINITIALIZED) { + /* Try without the '(' */ + symbol_delete(yylval.sym); + yytext[yyleng-1] = '\0'; + yylval.sym = + symtable_get(yytext); + } + unput('('); + return T_SYMBOL; + } + } +{WORD} { + yylval.sym = symtable_get(yytext); + if (yylval.sym->type == MACRO) { + expand_macro(yylval.sym); + } else { + return T_SYMBOL; + } + } +. { snprintf(buf, sizeof(buf), "Invalid character " "'%c'", yytext[0]); stop(buf, EX_DATAERR); @@ -327,6 +483,92 @@ yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); yylineno = 1; yyfilename = strdup(file_name); +} + +static void next_substitution(struct symbol *mac_symbol, const char *body_pos, + const char **next_match, + struct macro_arg **match_marg, regmatch_t *match); + +void +expand_macro(struct symbol *macro_symbol) +{ + struct macro_arg *marg; + struct macro_arg *match_marg; + const char *body_head; + const char *body_pos; + const char *next_match; + + /* + * Due to the nature of unput, we must work + * backwards through the macro body performing + * any expansions. + */ + body_head = macro_symbol->info.macroinfo->body; + body_pos = body_head + strlen(body_head); + while (body_pos > body_head) { + regmatch_t match; + + next_match = body_head; + match_marg = NULL; + next_substitution(macro_symbol, body_pos, &next_match, + &match_marg, &match); + + /* Put back everything up until the replacement. */ + while (body_pos > next_match) + unput(*--body_pos); + + /* Perform the replacement. */ + if (match_marg != NULL) { + const char *strp; + + next_match = match_marg->replacement_text; + strp = next_match + strlen(next_match); + while (strp > next_match) + unput(*--strp); + + /* Skip past the unexpanded macro arg. */ + body_pos -= match.rm_eo - match.rm_so; + } + } + + /* Cleanup replacement text. */ + STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { + free(marg->replacement_text); + } +} + +/* + * Find the next substitution in the macro working backwards from + * body_pos until the beginning of the macro buffer. next_match + * should be initialized to the beginning of the macro buffer prior + * to calling this routine. + */ +static void +next_substitution(struct symbol *mac_symbol, const char *body_pos, + const char **next_match, struct macro_arg **match_marg, + regmatch_t *match) +{ + regmatch_t matches[2]; + struct macro_arg *marg; + const char *search_pos; + int retval; + + do { + search_pos = *next_match; + + STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) { + + retval = regexec(&marg->arg_regex, search_pos, 2, + matches, 0); + if (retval == 0 + && (matches[1].rm_eo + search_pos) <= body_pos + && (matches[1].rm_eo + search_pos) > *next_match) { + *match = matches[1]; + *next_match = match->rm_eo + search_pos; + *match_marg = marg; + } + } + } while (search_pos != *next_match); } int diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Wed Mar 27 13:07:17 2002 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#9 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $ */ @@ -49,6 +49,7 @@ #include #endif #include +#include #include #include #include @@ -318,12 +319,15 @@ symlist_t constants; symlist_t download_constants; symlist_t aliases; + symlist_t exported_labels; + u_int i; SLIST_INIT(®isters); SLIST_INIT(&masks); SLIST_INIT(&constants); SLIST_INIT(&download_constants); SLIST_INIT(&aliases); + SLIST_INIT(&exported_labels); if (symtable != NULL) { DBT key; @@ -345,10 +349,8 @@ symlist_add(&masks, cursym, SYMLIST_SORT); break; case CONST: - if (cursym->info.cinfo->define == FALSE) { - symlist_add(&constants, cursym, - SYMLIST_INSERT_HEAD); - } + symlist_add(&constants, cursym, + SYMLIST_INSERT_HEAD); break; case DOWNLOAD_CONST: symlist_add(&download_constants, cursym, @@ -358,6 +360,12 @@ symlist_add(&aliases, cursym, SYMLIST_INSERT_HEAD); break; + case LABEL: + if (cursym->info.linfo->exported == 0) + break; + symlist_add(&exported_labels, cursym, + SYMLIST_INSERT_HEAD); + break; default: break; } @@ -403,7 +411,7 @@ %s */\n", versions); while (SLIST_FIRST(®isters) != NULL) { symbol_node_t *curnode; - u_int8_t value; + u_int value; char *tab_str; char *tab_str2; @@ -463,7 +471,7 @@ fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); - while (SLIST_FIRST(&download_constants) != NULL) { + for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) { symbol_node_t *curnode; curnode = SLIST_FIRST(&download_constants); @@ -471,6 +479,20 @@ fprintf(ofile, "#define\t%-8s\t0x%02x\n", curnode->symbol->name, curnode->symbol->info.cinfo->value); + free(curnode); + } + fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i); + + fprintf(ofile, "\n\n/* Exported Labels */\n"); + + while (SLIST_FIRST(&exported_labels) != NULL) { + symbol_node_t *curnode; + + curnode = SLIST_FIRST(&exported_labels); + SLIST_REMOVE_HEAD(&exported_labels, links); + fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n", + curnode->symbol->name, + curnode->symbol->info.linfo->address); free(curnode); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h --- linux-2.5.13/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h Wed Mar 27 13:07:17 2002 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.h#6 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.h,v 1.11 2000/09/22 22:19:55 gibbs Exp $ */ @@ -58,8 +58,9 @@ CONST, DOWNLOAD_CONST, LABEL, - CONDITIONAL -}symtype; + CONDITIONAL, + MACRO +} symtype; typedef enum { RO = 0x01, @@ -68,10 +69,11 @@ }amode_t; struct reg_info { - u_int8_t address; + u_int address; int size; amode_t mode; u_int8_t valid_bitmask; + u_int8_t modes; int typecheck_masks; }; @@ -83,8 +85,8 @@ }; struct const_info { - u_int8_t value; - int define; + u_int value; + int define; }; struct alias_info { @@ -93,12 +95,26 @@ struct label_info { int address; + int exported; }; struct cond_info { int func_num; }; +struct macro_arg { + STAILQ_ENTRY(macro_arg) links; + regex_t arg_regex; + char *replacement_text; +}; +STAILQ_HEAD(macro_arg_list, macro_arg) args; + +struct macro_info { + struct macro_arg_list args; + int narg; + const char* body; +}; + typedef struct expression_info { symlist_t referenced_syms; int value; @@ -108,12 +124,13 @@ char *name; symtype type; union { - struct reg_info *rinfo; - struct mask_info *minfo; + struct reg_info *rinfo; + struct mask_info *minfo; struct const_info *cinfo; struct alias_info *ainfo; struct label_info *linfo; - struct cond_info *condinfo; + struct cond_info *condinfo; + struct macro_info *macroinfo; }info; } symbol_t; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/atari_NCR5380.c linux-2.5/drivers/scsi/atari_NCR5380.c --- linux-2.5.13/drivers/scsi/atari_NCR5380.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/scsi/atari_NCR5380.c Wed Mar 27 13:07:17 2002 @@ -644,10 +644,7 @@ static volatile int main_running = 0; static struct tq_struct NCR5380_tqueue = { - NULL, /* next */ - 0, /* sync */ - (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */ - NULL /* data */ + routine: (void (*)(void*))NCR5380_main /* must have (void *) arg... */ }; static __inline__ void queue_main(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/atari_scsi.c linux-2.5/drivers/scsi/atari_scsi.c --- linux-2.5.13/drivers/scsi/atari_scsi.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/scsi/atari_scsi.c Wed Mar 27 13:07:17 2002 @@ -1144,3 +1144,5 @@ static Scsi_Host_Template driver_template = ATARI_SCSI; #include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/blz1230.c linux-2.5/drivers/scsi/blz1230.c --- linux-2.5.13/drivers/scsi/blz1230.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/scsi/blz1230.c Wed Mar 27 13:07:17 2002 @@ -296,3 +296,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/blz2060.c linux-2.5/drivers/scsi/blz2060.c --- linux-2.5.13/drivers/scsi/blz2060.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/scsi/blz2060.c Wed Mar 27 13:07:17 2002 @@ -254,3 +254,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/cpqfcTSinit.c linux-2.5/drivers/scsi/cpqfcTSinit.c --- linux-2.5.13/drivers/scsi/cpqfcTSinit.c Fri May 3 01:22:40 2002 +++ linux-2.5/drivers/scsi/cpqfcTSinit.c Fri May 3 12:28:12 2002 @@ -532,7 +532,7 @@ // must be super user to send stuff directly to the // controller and/or physical drives... - if( !capable(CAP_SYS_ADMIN) ) + if( !capable(CAP_RAW_IO) ) return -EPERM; // copy the caller's struct to our space. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/cyberstorm.c linux-2.5/drivers/scsi/cyberstorm.c --- linux-2.5.13/drivers/scsi/cyberstorm.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/scsi/cyberstorm.c Wed Mar 27 13:07:17 2002 @@ -320,3 +320,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/cyberstormII.c linux-2.5/drivers/scsi/cyberstormII.c --- linux-2.5.13/drivers/scsi/cyberstormII.c Fri May 3 01:22:46 2002 +++ linux-2.5/drivers/scsi/cyberstormII.c Wed Mar 27 13:07:17 2002 @@ -271,3 +271,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/dtc.c linux-2.5/drivers/scsi/dtc.c --- linux-2.5.13/drivers/scsi/dtc.c Fri May 3 01:22:55 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.13/drivers/scsi/fastlane.c linux-2.5/drivers/scsi/fastlane.c --- linux-2.5.13/drivers/scsi/fastlane.c Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/scsi/fastlane.c Wed Mar 27 13:07:17 2002 @@ -372,3 +372,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/fdomain.c linux-2.5/drivers/scsi/fdomain.c --- linux-2.5.13/drivers/scsi/fdomain.c Fri May 3 01:22:43 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.13/drivers/scsi/g_NCR5380.c linux-2.5/drivers/scsi/g_NCR5380.c --- linux-2.5.13/drivers/scsi/g_NCR5380.c Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/scsi/g_NCR5380.c Tue Dec 18 15:31:05 2001 @@ -77,7 +77,7 @@ * IRQ line if overridden on the command line. * */ - + /* * $Log: generic_NCR5380.c,v $ */ @@ -124,787 +124,772 @@ #include #define NCR_NOT_SET 0 -static int ncr_irq=NCR_NOT_SET; -static int ncr_dma=NCR_NOT_SET; -static int ncr_addr=NCR_NOT_SET; -static int ncr_5380=NCR_NOT_SET; -static int ncr_53c400=NCR_NOT_SET; -static int ncr_53c400a=NCR_NOT_SET; -static int dtc_3181e=NCR_NOT_SET; +static int ncr_irq = NCR_NOT_SET; +static int ncr_dma = NCR_NOT_SET; +static int ncr_addr = NCR_NOT_SET; +static int ncr_5380 = NCR_NOT_SET; +static int ncr_53c400 = NCR_NOT_SET; +static int ncr_53c400a = NCR_NOT_SET; +static int dtc_3181e = NCR_NOT_SET; static struct override { NCR5380_implementation_fields; - int irq; - int dma; - int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ -} overrides -#ifdef GENERIC_NCR5380_OVERRIDE - [] __initdata = GENERIC_NCR5380_OVERRIDE; + int irq; + int dma; + int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ +} overrides +#ifdef GENERIC_NCR5380_OVERRIDE +[] __initdata = GENERIC_NCR5380_OVERRIDE; #else - [1] __initdata = {{0,},}; +[1] __initdata = { { 0,},}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) -/* - * Function : static internal_setup(int board, char *str, int *ints) +/** + * internal_setup - handle lilo command string override + * @board: BOARD_* identifier for the board + * @str: unused + * @ints: numeric parameters * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : board - either BOARD_NCR5380 for a normal NCR5380 board, - * or BOARD_NCR53C400 for a NCR53C400 board. str - unused, ints - - * array of integer parameters with ints[0] equal to the number of ints. + * Do LILO command line initialization of the overrides array. Display + * errors when needed * + * Locks: none */ -static void __init internal_setup(int board, char *str, int *ints){ - static int commandline_current = 0; - switch (board) { - case BOARD_NCR5380: - if (ints[0] != 2 && ints[0] != 3) { - printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); - return; - } - break; - case BOARD_NCR53C400: - if (ints[0] != 2) { - printk("generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_NCR53C400A: - if (ints[0] != 2) { - printk("generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_DTC3181E: - if (ints[0] != 2) { - printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - } - - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type)ints[1]; - overrides[commandline_current].irq = ints[2]; - if (ints[0] == 3) - overrides[commandline_current].dma = ints[3]; - else - overrides[commandline_current].dma = DMA_NONE; - overrides[commandline_current].board = board; - ++commandline_current; - } +static void __init internal_setup(int board, char *str, int *ints) +{ + static int commandline_current = 0; + switch (board) { + case BOARD_NCR5380: + if (ints[0] != 2 && ints[0] != 3) { + printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); + return; + } + break; + case BOARD_NCR53C400: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_NCR53C400A: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_DTC3181E: + if (ints[0] != 2) { + printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + } + + if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1]; + overrides[commandline_current].irq = ints[2]; + if (ints[0] == 3) + overrides[commandline_current].dma = ints[3]; + else + overrides[commandline_current].dma = DMA_NONE; + overrides[commandline_current].board = board; + ++commandline_current; + } } -/* - * Function : generic_NCR5380_setup (char *str, int *ints) +/** + * do_NCR53C80_setup - set up entry point + * @str: unused * - * 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. + * Setup function invoked at boot to parse the ncr5380= command + * line. */ -void __init generic_NCR5380_setup (char *str, int *ints){ - internal_setup (BOARD_NCR5380, str, ints); +static int __init do_NCR5380_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR5380, str, ints); + return 1; } -/* - * Function : generic_NCR53C400_setup (char *str, int *ints) +/** + * do_NCR53C400_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * 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. + * Setup function invoked at boot to parse the ncr53c400= command + * line. */ -void __init generic_NCR53C400_setup (char *str, int *ints){ - internal_setup (BOARD_NCR53C400, str, ints); +static int __init do_NCR53C400_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400, str, ints); + return 1; } -/* - * Function : generic_NCR53C400A_setup (char *str, int *ints) +/** + * do_NCR53C400A_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * 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. + * Setup function invoked at boot to parse the ncr53c400a= command + * line. */ -void generic_NCR53C400A_setup (char *str, int *ints) { - internal_setup (BOARD_NCR53C400A, str, ints); +static int __init do_NCR53C400A_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400A, str, ints); + return 1; } -/* - * Function : generic_DTC3181E_setup (char *str, int *ints) +/** + * do_DTC3181E_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * 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. + * Setup function invoked at boot to parse the dtc3181e= command + * line. */ -void generic_DTC3181E_setup (char *str, int *ints) { - internal_setup (BOARD_DTC3181E, str, ints); +static int __init do_DTC3181E_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_DTC3181E, str, ints); + return 1; } -/* - * Function : int generic_NCR5380_detect(Scsi_Host_Template * tpnt) +/** + * generic_NCR5380_detect - look for NCR5380 controllers + * @tpnt: the scsi template * - * Purpose : initializes generic NCR5380 driver based on the - * command line / compile time port and irq definitions. + * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E + * and DTC436(ISAPnP) controllers. If overrides have been set we use + * them. * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. + * The caller supplied NCR5380_init function is invoked from here, before + * the interrupt line is taken. * + * Locks: none */ -int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0; - int count, i; - u_int *ports; - u_int ncr_53c400a_ports[] = {0x280, 0x290, 0x300, 0x310, 0x330, - 0x340, 0x348, 0x350, 0}; - u_int dtc_3181e_ports[] = {0x220, 0x240, 0x280, 0x2a0, 0x2c0, - 0x300, 0x320, 0x340, 0}; - int flags = 0; - struct Scsi_Host *instance; - - if (ncr_irq != NCR_NOT_SET) - overrides[0].irq=ncr_irq; - if (ncr_dma != NCR_NOT_SET) - overrides[0].dma=ncr_dma; - if (ncr_addr != NCR_NOT_SET) - overrides[0].NCR5380_map_name=(NCR5380_map_type)ncr_addr; - if (ncr_5380 != NCR_NOT_SET) - overrides[0].board=BOARD_NCR5380; - else if (ncr_53c400 != NCR_NOT_SET) - overrides[0].board=BOARD_NCR53C400; - else if (ncr_53c400a != NCR_NOT_SET) - overrides[0].board=BOARD_NCR53C400A; - else if (dtc_3181e != NCR_NOT_SET) - overrides[0].board=BOARD_DTC3181E; - - if (!current_override && isapnp_present()) { - struct pci_dev *dev = NULL; - count = 0; - while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), dev))) { - if (count >= NO_OVERRIDES) - break; - if (!dev->active && dev->prepare(dev) < 0) { - printk(KERN_ERR "dtc436e probe: prepare failed\n"); - continue; - } - if (!(dev->resource[0].flags & IORESOURCE_IO)) - continue; - if (!dev->active && dev->activate(dev) < 0) { - printk(KERN_ERR "dtc436e probe: activate failed\n"); - continue; - } - if (dev->irq_resource[0].flags & IORESOURCE_IRQ) - overrides[count].irq=dev->irq_resource[0].start; - else - overrides[count].irq=IRQ_NONE; - if (dev->dma_resource[0].flags & IORESOURCE_DMA) - overrides[count].dma=dev->dma_resource[0].start; - else - overrides[count].dma=DMA_NONE; - overrides[count].NCR5380_map_name=(NCR5380_map_type)dev->resource[0].start; - overrides[count].board=BOARD_DTC3181E; - count++; - } - } - - tpnt->proc_name = "g_NCR5380"; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - if (!(overrides[current_override].NCR5380_map_name)) - continue; - - ports = 0; - switch (overrides[current_override].board) { - case BOARD_NCR5380: - flags = FLAG_NO_PSEUDO_DMA; - break; - case BOARD_NCR53C400: - flags = FLAG_NCR53C400; - break; - case BOARD_NCR53C400A: - flags = FLAG_NO_PSEUDO_DMA; - ports = ncr_53c400a_ports; - break; - case BOARD_DTC3181E: - flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; - ports = dtc_3181e_ports; - break; +int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0; + int count, i; + unsigned int *ports; + static unsigned int __initdata ncr_53c400a_ports[] = { + 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 + }; + static unsigned int __initdata dtc_3181e_ports[] = { + 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0 + }; + int flags = 0; + struct Scsi_Host *instance; + + if (ncr_irq != NCR_NOT_SET) + overrides[0].irq = ncr_irq; + if (ncr_dma != NCR_NOT_SET) + overrides[0].dma = ncr_dma; + if (ncr_addr != NCR_NOT_SET) + overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr; + if (ncr_5380 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR5380; + else if (ncr_53c400 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400; + else if (ncr_53c400a != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400A; + else if (dtc_3181e != NCR_NOT_SET) + overrides[0].board = BOARD_DTC3181E; + + if (!current_override && isapnp_present()) { + struct pci_dev *dev = NULL; + count = 0; + while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { + if (count >= NO_OVERRIDES) + break; + if (!dev->active && dev->prepare(dev) < 0) { + printk(KERN_ERR "dtc436e probe: prepare failed\n"); + continue; + } + if (!(dev->resource[0].flags & IORESOURCE_IO)) + continue; + if (!dev->active && dev->activate(dev) < 0) { + printk(KERN_ERR "dtc436e probe: activate failed\n"); + continue; + } + if (dev->irq_resource[0].flags & IORESOURCE_IRQ) + overrides[count].irq = dev->irq_resource[0].start; + else + overrides[count].irq = IRQ_NONE; + if (dev->dma_resource[0].flags & IORESOURCE_DMA) + overrides[count].dma = dev->dma_resource[0].start; + else + overrides[count].dma = DMA_NONE; + overrides[count].NCR5380_map_name = (NCR5380_map_type) dev->resource[0].start; + overrides[count].board = BOARD_DTC3181E; + count++; + } } + tpnt->proc_name = "g_NCR5380"; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) { + if (!(overrides[current_override].NCR5380_map_name)) + continue; + + ports = 0; + switch (overrides[current_override].board) { + case BOARD_NCR5380: + flags = FLAG_NO_PSEUDO_DMA; + break; + case BOARD_NCR53C400: + flags = FLAG_NCR53C400; + break; + case BOARD_NCR53C400A: + flags = FLAG_NO_PSEUDO_DMA; + ports = ncr_53c400a_ports; + break; + case BOARD_DTC3181E: + flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; + ports = dtc_3181e_ports; + break; + } + #ifdef CONFIG_SCSI_G_NCR5380_PORT - if (ports) { - /* wakeup sequence for the NCR53C400A and DTC3181E*/ + if (ports) { + /* wakeup sequence for the NCR53C400A and DTC3181E */ - /* Disable the adapter and look for a free io port */ - outb(0x59, 0x779); - outb(0xb9, 0x379); - outb(0xc5, 0x379); - outb(0xae, 0x379); - outb(0xa6, 0x379); - outb(0x00, 0x379); - - if (overrides[current_override].NCR5380_map_name != PORT_AUTO) - for(i=0; ports[i]; i++) { - if (overrides[current_override].NCR5380_map_name == ports[i]) - break; - } - else - for(i=0; ports[i]; i++) { - if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff)) - break; - } - if (ports[i]) { - outb(0x59, 0x779); - outb(0xb9, 0x379); - outb(0xc5, 0x379); - outb(0xae, 0x379); - outb(0xa6, 0x379); - outb(0x80 | i, 0x379); /* set io port to be used */ - outb(0xc0, ports[i] + 9); - if (inb(ports[i] + 9) != 0x80) - continue; - else - overrides[current_override].NCR5380_map_name=ports[i]; - } else - continue; - } + /* Disable the adapter and look for a free io port */ + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x00, 0x379); + + if (overrides[current_override].NCR5380_map_name != PORT_AUTO) + for (i = 0; ports[i]; i++) { + if (overrides[current_override].NCR5380_map_name == ports[i]) + break; + } else + for (i = 0; ports[i]; i++) { + if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff)) + break; + } + if (ports[i]) { + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x80 | i, 0x379); /* set io port to be used */ + outb(0xc0, ports[i] + 9); + if (inb(ports[i] + 9) != 0x80) + continue; + else + overrides[current_override].NCR5380_map_name = ports[i]; + } else + continue; + } - request_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size, "ncr5380"); + request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); #else - if(check_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size)) - continue; - request_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size, "ncr5380"); + if (check_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size)) + continue; + request_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); #endif - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - { + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) { #ifdef CONFIG_SCSI_G_NCR5380_PORT - release_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size); + release_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); #else - release_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size); + release_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); #endif - continue; - } - - instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; - - NCR5380_init(instance, flags); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, 0xffff); + continue; + } - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } + instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; - 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, flags); - printk("scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int)instance->NCR5380_instance_name); - 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, GENERIC_NCR5380_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; -} + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, 0xffff); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", 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); + } -const char * generic_NCR5380_info (struct Scsi_Host* host) { - static const char string[]="Generic NCR5380/53C400 Driver"; - return string; + printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name); + 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, GENERIC_NCR5380_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); + + ++current_override; + ++count; + } + return count; +} + +/** + * generic_NCR5380_info - reporting string + * @host: NCR5380 to report on + * + * Report driver information for the NCR5380 + */ + +const char *generic_NCR5380_info(struct Scsi_Host *host) +{ + static const char string[] = "Generic NCR5380/53C400 Driver"; + return string; } -int generic_NCR5380_release_resources(struct Scsi_Host * instance) +/** + * generic_NCR5380_release_resources - free resources + * @instance: host adapter to clean up + * + * Free the generic interface resources from this adapter. + * + * Locks: none + */ + +int generic_NCR5380_release_resources(struct Scsi_Host *instance) { - NCR5380_local_declare(); - - NCR5380_setup(instance); + NCR5380_local_declare(); + NCR5380_setup(instance); #ifdef CONFIG_SCSI_G_NCR5380_PORT - release_region(instance->NCR5380_instance_name, NCR5380_region_size); + release_region(instance->NCR5380_instance_name, NCR5380_region_size); #else - release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); -#endif + release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); +#endif - if (instance->irq != IRQ_NONE) - free_irq(instance->irq, NULL); + if (instance->irq != IRQ_NONE) + free_irq(instance->irq, NULL); return 0; } #ifdef BIOSPARAM -/* - * Function : int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * generic_NCR5380_biosparam + * @disk: disk to compute geometry for + * @dev: device identifier for this disk + * @ip: sizes to fill in * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for - * the specified device / size. + * 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} + * XXX Most SCSI boards use this mapping, I could be incorrect. Someone + * 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. * - * 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. + * Locks: none */ int generic_NCR5380_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; } #endif #if NCR53C400_PSEUDO_DMA -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, int len) -{ - int blocks = len / 128; - int start = 0; - int bl; -#ifdef CONFIG_SCSI_G_NCR5380_PORT - int i; -#endif - NCR5380_local_declare(); - - NCR5380_setup(instance); - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: About to read %d blocks for %d bytes\n", blocks, len); -#endif - - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); - NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); - while (1) { - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: %d blocks left\n", blocks); -#endif - - if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { -#if (NDEBUG & NDEBUG_C400_PREAD) - if (blocks) - printk("53C400r: blocks still == %d\n", blocks); - else - printk("53C400r: Exiting loop\n"); -#endif - break; - } - -#if 1 - if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { - printk("53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); - return -1; - } -#endif - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Waiting for buffer, bl=%d\n", bl); -#endif - - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Transferring 128 bytes\n"); -#endif +/** + * NCR5380_pread - pseudo DMA read + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY); #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - dst[start+i] = NCR5380_read(C400_HOST_BUFFER); + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); #endif - start+=128; - blocks--; - } - - if (blocks) { -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: EXTRA: Waiting for buffer\n"); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; + start += 128; + blocks--; + } + + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + { + // FIXME - no timeout + } -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Transferring EXTRA 128 bytes\n"); -#endif #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - dst[start+i] = NCR5380_read(C400_HOST_BUFFER); + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128); -#endif - start+=128; - blocks--; - } -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: No EXTRA required\n"); -#endif - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Final values: blocks=%d start=%d\n", blocks, start); -#endif - - if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) - printk("53C400r: no 53C80 gated irq after transfer"); -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: Got 53C80 interrupt and tried to clear it\n"); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); #endif + start += 128; + blocks--; + } -/* DON'T DO THIS - THEY NEVER ARRIVE! - printk("53C400r: Waiting for 53C80 registers\n"); - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) - ; -*/ + if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + printk("53C400r: no 53C80 gated irq after transfer"); - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) - printk("53C400r: no end dma signal\n"); -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: end dma as expected\n"); +#if 0 + /* + * DON'T DO THIS - THEY NEVER ARRIVE! + */ + printk("53C400r: Waiting for 53C80 registers\n"); + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) + ; #endif - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - return 0; -} + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400r: no end dma signal\n"); -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, int len) -{ - int blocks = len / 128; - int start = 0; - int i; - int bl; - NCR5380_local_declare(); - - NCR5380_setup(instance); - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: About to write %d blocks for %d bytes\n", blocks, len); -#endif - - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); - NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); - while (1) { - if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { - printk("53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); - return -1; - } - - if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - if (blocks) - printk("53C400w: exiting loop, blocks still == %d\n", blocks); - else - printk("53C400w: exiting loop\n"); -#endif - break; - } + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + return 0; +} -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: %d blocks left\n", blocks); +/** + * NCR5380_write - pseudo DMA write + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ - printk("53C400w: waiting for buffer, bl=%d\n", bl); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + int i; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: transferring 128 bytes\n"); -#endif + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - timeout #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - NCR5380_write(C400_HOST_BUFFER, src[start+i]); + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); #endif - start+=128; - blocks--; - } - if (blocks) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: EXTRA waiting for buffer\n"); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; + start += 128; + blocks--; + } + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - no timeout -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: transferring EXTRA 128 bytes\n"); -#endif #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - NCR5380_write(C400_HOST_BUFFER, src[start+i]); + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128); -#endif - start+=128; - blocks--; - } -#if (NDEBUG & NDEBUG_C400_PWRITE) - else - printk("53C400w: No EXTRA required\n"); -#endif - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: Final values: blocks=%d start=%d\n", blocks, start); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); #endif + start += 128; + blocks--; + } #if 0 - printk("53C400w: waiting for registers to be available\n"); - THEY NEVER DO! - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) - ; - printk("53C400w: Got em\n"); -#endif - - /* Let's wait for this instead - could be ugly */ - /* All documentation says to check for this. Maybe my hardware is too - * fast. Waiting for it seems to work fine! KLL - */ - while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) - ; - - /* - * I know. i is certainly != 0 here but the loop is new. See previous - * comment. - */ - if (i) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got 53C80 gated irq (last block)\n"); -#endif - if (!((i=NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) - printk("53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n",i); -#if (NDEBUG & NDEBUG_C400_PWRITE) - else - printk("53C400w: Got END OF DMA\n"); -#endif - } - else - printk("53C400w: no 53C80 gated irq after transfer (last block)\n"); + printk("53C400w: waiting for registers to be available\n"); + THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG); + printk("53C400w: Got em\n"); +#endif + + /* Let's wait for this instead - could be ugly */ + /* All documentation says to check for this. Maybe my hardware is too + * fast. Waiting for it seems to work fine! KLL + */ + while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + ; // FIXME - no timeout + + /* + * I know. i is certainly != 0 here but the loop is new. See previous + * comment. + */ + if (i) { + if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i); + } else + printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n"); #if 0 - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { - printk("53C400w: no end dma signal\n"); - } -#endif - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: waiting for last byte...\n"); -#endif - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) - ; - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got last byte.\n"); - printk("53C400w: pwrite exiting with status 0, whoopee!\n"); + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { + printk(KERN_ERR "53C400w: no end dma signal\n"); + } #endif - return 0; + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) + ; // TIMEOUT + return 0; } -#endif /* PSEUDO_DMA */ +#endif /* PSEUDO_DMA */ +/* + * Include the NCR5380 core code that we build our driver around + */ + #include "NCR5380.c" #define PRINTP(x) len += sprintf(buffer+len, x) #define ANDP , -static int sprint_opcode(char* buffer, int len, int opcode) { - int start = len; - PRINTP("0x%02x " ANDP opcode); - return len-start; -} - -static int sprint_command (char* buffer, int len, unsigned char *command) { - int i,s,start=len; - len += sprint_opcode(buffer, len, command[0]); - for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - PRINTP("%02x " ANDP command[i]); - PRINTP("\n"); - return len-start; -} - -static int sprint_Scsi_Cmnd (char* buffer, int len, Scsi_Cmnd *cmd) { - int start = len; - PRINTP("host number %d destination target %d, lun %d\n" ANDP - cmd->host->host_no ANDP - cmd->target ANDP - cmd->lun); - PRINTP(" command = "); - len += sprint_command (buffer, len, cmd->cmnd); - return len-start; -} - -int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout) -{ - int len = 0; - NCR5380_local_declare(); - unsigned long flags; - unsigned char status; - int i; - struct Scsi_Host *scsi_ptr; - Scsi_Cmnd *ptr; - struct NCR5380_hostdata *hostdata; +static int sprint_opcode(char *buffer, int len, int opcode) +{ + int start = len; + PRINTP("0x%02x " ANDP opcode); + return len - start; +} + +static int sprint_command(char *buffer, int len, unsigned char *command) +{ + int i, s, start = len; + len += sprint_opcode(buffer, len, command[0]); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + PRINTP("%02x " ANDP command[i]); + PRINTP("\n"); + return len - start; +} + +/** + * sprintf_Scsi_Cmnd - print a scsi command + * @buffer: buffr to print into + * @len: buffer length + * @cmd: SCSI command block + * + * Print out the target and command data in hex + */ + +static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd) +{ + int start = len; + PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->host->host_no ANDP cmd->target ANDP cmd->lun); + PRINTP(" command = "); + len += sprint_command(buffer, len, cmd->cmnd); + return len - start; +} + +/** + * generic_NCR5380_proc_info - /proc for NCR5380 driver + * @buffer: buffer to print into + * @start: start position + * @offset: offset into buffer + * @len: length + * @hostno: instance to affect + * @inout: read/write + * + * Provide the procfs information for the 5380 controller. We fill + * this with useful debugging information including the commands + * being executed, disconnected command queue and the statistical + * data + * + * Locks: global cli/lock for queue walk + */ + +int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +{ + int len = 0; + NCR5380_local_declare(); + unsigned long flags; + unsigned char status; + int i; + struct Scsi_Host *scsi_ptr; + Scsi_Cmnd *ptr; + struct NCR5380_hostdata *hostdata; #ifdef NCR5380_STATS - Scsi_Device *dev; - extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; + Scsi_Device *dev; + extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); - for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next) - if (scsi_ptr->host_no == hostno) - break; - NCR5380_setup(scsi_ptr); - hostdata = (struct NCR5380_hostdata *)scsi_ptr->hostdata; - - PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); - PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); - PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); + for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr = scsi_ptr->next) + if (scsi_ptr->host_no == hostno) + break; + NCR5380_setup(scsi_ptr); + hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata; + + PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); + PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); + PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); #ifdef NCR53C400 - PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); - PRINTP("NCR53C400 card%s detected\n" ANDP (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not"); + PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); + PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not"); # if NCR53C400_PSEUDO_DMA - PRINTP("NCR53C400 pseudo DMA used\n"); + PRINTP("NCR53C400 pseudo DMA used\n"); # endif #else - PRINTP("NO NCR53C400 driver extensions\n"); + PRINTP("NO NCR53C400 driver extensions\n"); #endif - PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); - if (scsi_ptr->irq == IRQ_NONE) - PRINTP("no interrupt\n"); - else - PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); + PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); + if (scsi_ptr->irq == IRQ_NONE) + PRINTP("no interrupt\n"); + else + PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); #ifdef NCR5380_STATS - if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) - PRINTP("There are commands pending, transfer rates may be crud\n"); - if (hostdata->pendingr) - PRINTP(" %d pending reads" ANDP hostdata->pendingr); - if (hostdata->pendingw) - PRINTP(" %d pending writes" ANDP hostdata->pendingw); - if (hostdata->pendingr || hostdata->pendingw) - PRINTP("\n"); - for (dev = scsi_ptr->host_queue; dev; dev=dev->next) { - unsigned long br = hostdata->bytes_read[dev->id]; - unsigned long bw = hostdata->bytes_write[dev->id]; - long tr = hostdata->time_read[dev->id] / HZ; - long tw = hostdata->time_write[dev->id] / HZ; - - PRINTP(" T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int)dev->type] : "Unknown"); - for (i=0; i<8; i++) - if (dev->vendor[i] >= 0x20) - *(buffer+(len++)) = dev->vendor[i]; - *(buffer+(len++)) = ' '; - for (i=0; i<16; i++) - if (dev->model[i] >= 0x20) - *(buffer+(len++)) = dev->model[i]; - *(buffer+(len++)) = ' '; - for (i=0; i<4; i++) - if (dev->rev[i] >= 0x20) - *(buffer+(len++)) = dev->rev[i]; - *(buffer+(len++)) = ' '; - - PRINTP("\n%10ld kb read in %5ld secs" ANDP br/1024 ANDP tr); - if (tr) - PRINTP(" @ %5ld bps" ANDP br / tr); - - PRINTP("\n%10ld kb written in %5ld secs" ANDP bw/1024 ANDP tw); - if (tw) - PRINTP(" @ %5ld bps" ANDP bw / tw); - PRINTP("\n"); - } -#endif - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - PRINTP("REQ not asserted, phase unknown.\n"); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i) - ; - PRINTP("Phase %s\n" ANDP phases[i].name); - } - - if (!hostdata->connected) { - PRINTP("No currently connected command\n"); - } else { - len += sprint_Scsi_Cmnd (buffer, len, (Scsi_Cmnd *) hostdata->connected); - } - - PRINTP("issue_queue\n"); - - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) - len += sprint_Scsi_Cmnd (buffer, len, ptr); - - PRINTP("disconnected_queue\n"); - - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) - len += sprint_Scsi_Cmnd (buffer, len, ptr); - - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - restore_flags(flags); - return len; + if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) + PRINTP("There are commands pending, transfer rates may be crud\n"); + if (hostdata->pendingr) + PRINTP(" %d pending reads" ANDP hostdata->pendingr); + if (hostdata->pendingw) + PRINTP(" %d pending writes" ANDP hostdata->pendingw); + if (hostdata->pendingr || hostdata->pendingw) + PRINTP("\n"); + for (dev = scsi_ptr->host_queue; dev; dev = dev->next) { + unsigned long br = hostdata->bytes_read[dev->id]; + unsigned long bw = hostdata->bytes_write[dev->id]; + long tr = hostdata->time_read[dev->id] / HZ; + long tw = hostdata->time_write[dev->id] / HZ; + + PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown"); + for (i = 0; i < 8; i++) + if (dev->vendor[i] >= 0x20) + *(buffer + (len++)) = dev->vendor[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 16; i++) + if (dev->model[i] >= 0x20) + *(buffer + (len++)) = dev->model[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 4; i++) + if (dev->rev[i] >= 0x20) + *(buffer + (len++)) = dev->rev[i]; + *(buffer + (len++)) = ' '; + + PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr); + if (tr) + PRINTP(" @ %5ld bps" ANDP br / tr); + + PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw); + if (tw) + PRINTP(" @ %5ld bps" ANDP bw / tw); + PRINTP("\n"); + } +#endif + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + PRINTP("REQ not asserted, phase unknown.\n"); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); + PRINTP("Phase %s\n" ANDP phases[i].name); + } + + if (!hostdata->connected) { + PRINTP("No currently connected command\n"); + } else { + len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected); + } + + PRINTP("issue_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + PRINTP("disconnected_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + *start = buffer + offset; + len -= offset; + if (len > length) + len = length; + restore_flags(flags); + return len; } #undef PRINTP #undef ANDP -/* Eventually this will go into an include file, but this will be later */ +/* + * Eventually this will go into an include file, but this will be later + */ static Scsi_Host_Template driver_template = GENERIC_NCR5380; #include #include "scsi_module.c" -#ifdef MODULE - MODULE_PARM(ncr_irq, "i"); MODULE_PARM(ncr_dma, "i"); MODULE_PARM(ncr_addr, "i"); @@ -913,65 +898,20 @@ MODULE_PARM(ncr_53c400a, "i"); MODULE_PARM(dtc_3181e, "i"); MODULE_LICENSE("GPL"); -#else - -static int __init do_NCR5380_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR5380_setup(str,ints); - - return 1; -} - -static int __init do_NCR53C400_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR53C400_setup(str,ints); - return 1; -} - -static int __init do_NCR53C400A_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR53C400A_setup(str,ints); - - return 1; -} - -static int __init do_DTC3181E_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_DTC3181E_setup(str,ints); - - return 1; -} - -__setup("ncr5380=", do_NCR5380_setup); -__setup("ncr53c400=", do_NCR53C400_setup); -__setup("ncr53c400a=", do_NCR53C400A_setup); -__setup("dtc3181e=", do_DTC3181E_setup); static struct isapnp_device_id id_table[] __devinitdata = { { - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), - 0 - }, + ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), + 0}, {0} }; MODULE_DEVICE_TABLE(isapnp, id_table); -MODULE_LICENSE("GPL"); -#endif - +__setup("ncr5380=", do_NCR5380_setup); +__setup("ncr53c400=", do_NCR53C400_setup); +__setup("ncr53c400a=", do_NCR53C400A_setup); +__setup("dtc3181e=", do_DTC3181E_setup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/g_NCR5380.h linux-2.5/drivers/scsi/g_NCR5380.h --- linux-2.5.13/drivers/scsi/g_NCR5380.h Fri May 3 01:22:38 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.13/drivers/scsi/gvp11.c linux-2.5/drivers/scsi/gvp11.c --- linux-2.5.13/drivers/scsi/gvp11.c Fri May 3 01:22:56 2002 +++ linux-2.5/drivers/scsi/gvp11.c Wed Mar 27 13:07:17 2002 @@ -372,3 +372,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/hosts.h linux-2.5/drivers/scsi/hosts.h --- linux-2.5.13/drivers/scsi/hosts.h Fri May 3 01:22:48 2002 +++ linux-2.5/drivers/scsi/hosts.h Tue Apr 23 12:13:04 2002 @@ -166,40 +166,6 @@ 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); - - /* * This function is used to select synchronous communications, * which will result in a higher data throughput. Not implemented * yet. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/i60uscsi.c linux-2.5/drivers/scsi/i60uscsi.c --- linux-2.5.13/drivers/scsi/i60uscsi.c Fri May 3 01:22:43 2002 +++ linux-2.5/drivers/scsi/i60uscsi.c Mon Jan 14 22:39:45 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.13/drivers/scsi/ibmmca.c linux-2.5/drivers/scsi/ibmmca.c --- linux-2.5.13/drivers/scsi/ibmmca.c Fri May 3 01:22: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.13/drivers/scsi/ide-scsi.c linux-2.5/drivers/scsi/ide-scsi.c --- linux-2.5.13/drivers/scsi/ide-scsi.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/scsi/ide-scsi.c Wed May 1 19:31:30 2002 @@ -799,14 +799,20 @@ return 0; } -int idescsi_abort (Scsi_Cmnd *cmd) +/* try to do correct thing for scsi subsystem's new eh */ +int idescsi_device_reset (Scsi_Cmnd *cmd) { - return SCSI_ABORT_SNOOZE; -} + ide_drive_t *drive = idescsi_drives[cmd->target]; + struct request req; -int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags) -{ - return SCSI_RESET_SUCCESS; + ide_init_drive_cmd(&req); + req.flags = REQ_SPECIAL; +/* FIX ME, the next executable line causes on oops in lk 2.5.10-dj1 + * [code copied from ide-cd's ide_cdrom_reset(), does it work?] + */ + ide_do_drive_cmd(drive, &req, ide_wait); + + return SUCCESS; } int idescsi_bios (Disk *disk, kdev_t dev, int *parm) @@ -829,8 +835,8 @@ info: idescsi_info, ioctl: idescsi_ioctl, queuecommand: idescsi_queue, - abort: idescsi_abort, - reset: idescsi_reset, + eh_device_reset_handler: + idescsi_device_reset, bios_param: idescsi_bios, can_queue: 10, this_id: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/imm.c linux-2.5/drivers/scsi/imm.c --- linux-2.5.13/drivers/scsi/imm.c Fri May 3 01:22:57 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.13/drivers/scsi/ips.c linux-2.5/drivers/scsi/ips.c --- linux-2.5.13/drivers/scsi/ips.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/scsi/ips.c Fri May 3 02:05:04 2002 @@ -192,6 +192,7 @@ #ifdef MODULE static char *ips = NULL; MODULE_PARM(ips, "s"); + MODULE_LICENSE("GPL"); #endif /* @@ -783,7 +784,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); @@ -792,8 +793,6 @@ continue; } - - request_region(io_addr, io_len, "ips"); } /* get planer status */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/mac_NCR5380.c linux-2.5/drivers/scsi/mac_NCR5380.c --- linux-2.5.13/drivers/scsi/mac_NCR5380.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/scsi/mac_NCR5380.c Wed Mar 27 13:07:17 2002 @@ -662,10 +662,7 @@ static volatile int main_running = 0; static struct tq_struct NCR5380_tqueue = { - NULL, /* next */ - 0, /* sync */ - (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */ - NULL /* data */ + routine: (void (*)(void*))NCR5380_main /* must have (void *) arg... */ }; static __inline__ void queue_main(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/mac_esp.c linux-2.5/drivers/scsi/mac_esp.c --- linux-2.5.13/drivers/scsi/mac_esp.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/scsi/mac_esp.c Wed Mar 27 13:07:17 2002 @@ -713,3 +713,5 @@ static Scsi_Host_Template driver_template = SCSI_MAC_ESP; #include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/megaraid.c linux-2.5/drivers/scsi/megaraid.c --- linux-2.5.13/drivers/scsi/megaraid.c Fri May 3 01:22:37 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.13/drivers/scsi/mesh.c linux-2.5/drivers/scsi/mesh.c --- linux-2.5.13/drivers/scsi/mesh.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/scsi/mesh.c Wed Jan 30 21:57:15 2002 @@ -28,7 +28,8 @@ #include #include #include -#include +#include +#include #ifdef CONFIG_PMAC_PBOOK #include #include @@ -155,7 +156,6 @@ struct mesh_target tgts[8]; void *dma_cmd_space; struct device_node *ofnode; - u8* mio_base; #ifndef MESH_NEW_STYLE_EH Scsi_Cmnd *completed_q; Scsi_Cmnd *completed_qtail; @@ -258,8 +258,6 @@ if (mesh == 0) mesh = find_compatible_devices("scsi", "chrp,mesh0"); for (; mesh != 0; mesh = mesh->next) { - struct device_node *mio; - if (mesh->n_addrs != 2 || mesh->n_intrs != 2) { printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs" " (got %d,%d)", mesh->n_addrs, mesh->n_intrs); @@ -325,12 +323,6 @@ if (mesh_sync_period < minper) mesh_sync_period = minper; - ms->mio_base = 0; - for (mio = ms->ofnode->parent; mio; mio = mio->parent) - if (strcmp(mio->name, "mac-io") == 0 && mio->n_addrs > 0) - break; - if (mio) - ms->mio_base = (u8 *) ioremap(mio->addrs[0].address, 0x40); set_mesh_power(ms, 1); mesh_init(ms); @@ -363,11 +355,9 @@ iounmap((void *) ms->mesh); if (ms->dma) iounmap((void *) ms->dma); - if (ms->mio_base) - iounmap((void *) ms->mio_base); kfree(ms->dma_cmd_space); free_irq(ms->meshintr, ms); - feature_clear(ms->ofnode, FEATURE_MESH_enable); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 0); return 0; } @@ -377,16 +367,10 @@ if (_machine != _MACH_Pmac) return; if (state) { - feature_set(ms->ofnode, FEATURE_MESH_enable); - /* This seems to enable the termination power. strangely - this doesn't fully agree with OF, but with MacOS */ - if (ms->mio_base) - out_8(ms->mio_base + 0x36, 0x70); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 1); mdelay(200); } else { - feature_clear(ms->ofnode, FEATURE_MESH_enable); - if (ms->mio_base) - out_8(ms->mio_base + 0x36, 0x34); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 0); mdelay(10); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/oktagon_esp.c linux-2.5/drivers/scsi/oktagon_esp.c --- linux-2.5.13/drivers/scsi/oktagon_esp.c Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/scsi/oktagon_esp.c Wed Mar 27 13:07:17 2002 @@ -77,7 +77,9 @@ long oktag_to_io(long *paddr, long *addr, long len); long oktag_from_io(long *addr, long *paddr, long len); -static struct tq_struct tq_fake_dma = { NULL, 0, dma_commit, NULL }; +static struct tq_struct tq_fake_dma = { + routine: dma_commit, +}; #define DMA_MAXTRANSFER 0x8000 @@ -589,3 +591,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/osst.c linux-2.5/drivers/scsi/osst.c --- linux-2.5.13/drivers/scsi/osst.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/scsi/osst.c Fri Feb 8 02:15:53 2002 @@ -16,15 +16,15 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - $Header: /home/cvsroot/Driver/osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $ + $Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $ Microscopic alterations - Rik Ling, 2000/12/21 Last modified: Wed Feb 2 22:04:05 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 */ -static const char * cvsid = "$Id: osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $"; -const char * osst_version = "0.9.8"; +static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $"; +const char * osst_version = "0.9.10"; /* The "failure to reconnect" firmware bug */ #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ @@ -226,20 +226,20 @@ SRpnt->sr_cmnd[0] != MODE_SENSE && SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ if (driver_byte(result) & DRIVER_SENSE) { - printk(KERN_WARNING "osst%d:W: Error with sense data: ", dev); - print_req_sense("osst", SRpnt); + printk(KERN_WARNING "osst%d:W: Command with sense data: ", dev); + print_req_sense("osst:", SRpnt); } else { static int notyetprinted = 1; printk(KERN_WARNING - "osst%d:W: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", + "osst%d:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK, host_byte(result)); if (notyetprinted) { notyetprinted = 0; printk(KERN_INFO - "osst%d:I: This error may be caused by your scsi controller,\n", dev); + "osst%d:I: This warning may be caused by your scsi controller,\n", dev); printk(KERN_INFO "osst%d:I: it has been reported with some Buslogic cards.\n", dev); } @@ -271,11 +271,10 @@ /* Wakeup from interrupt */ static void osst_sleep_done (Scsi_Cmnd * SCpnt) { - unsigned int dev; + unsigned int dev = TAPE_NR(SCpnt->request.rq_dev); OS_Scsi_Tape * STp; - if ((dev = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) { - STp = os_scsi_tapes[dev]; + if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) { if ((STp->buffer)->writing && (SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x40)) { @@ -482,7 +481,8 @@ memset(page_address(STp->buffer->sg[i].page), 0, STp->buffer->sg[i].length); strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); - } + } else + STp->buffer->buffer_bytes = OS_FRAME_SIZE; return 1; } if (STp->buffer->syscall_result) { @@ -621,8 +621,10 @@ if (!SRpnt) return (-EBUSY); while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 && - (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8) ) { + (( SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 && + (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8) ) || + ( SRpnt->sr_sense_buffer[2] == 6 && SRpnt->sr_sense_buffer[12] == 0x28 && + SRpnt->sr_sense_buffer[13] == 0 ) )) { #if DEBUG if (debugging) { printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev); @@ -630,7 +632,7 @@ debugging = 0; } #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); memset(cmd, 0, MAX_COMMAND_SIZE); @@ -658,6 +660,66 @@ return 0; } +/* + * Wait for a tape to be inserted in the unit + */ +static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout) +{ + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Request * SRpnt; + long startwait = jiffies; +#if DEBUG + int dbg = debugging; + int dev = TAPE_NR(STp->devt); + + printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait for medium\n", dev); +#endif + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE); + *aSRpnt = SRpnt; + if (!SRpnt) return (-EBUSY); + + while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && + SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 0x3a && + SRpnt->sr_sense_buffer[13] == 0 ) { +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait medium\n", dev); + printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); + debugging = 0; + } +#endif + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE); + } + *aSRpnt = SRpnt; +#if DEBUG + debugging = dbg; +#endif + if ( STp->buffer->syscall_result && SRpnt->sr_sense_buffer[2] != 2 && + SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait medium\n", dev); + printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev, + STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2], + SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]); +#endif + return 0; + } +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait medium\n", dev); +#endif + return 1; +} + static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame) { int retval; @@ -696,7 +758,7 @@ result = osst_write_error_recovery(STp, aSRpnt, 0); result |= osst_wait_ready(STp, aSRpnt, 5 * 60); - STp->ps[STp->partition].rw = ST_IDLE; + STp->ps[STp->partition].rw = OS_WRITING_COMPLETE; return (result); } @@ -745,7 +807,7 @@ notyetprinted--; } #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout (HZ / OSST_POLL_PER_SEC); } #if DEBUG @@ -903,6 +965,8 @@ #endif if ( osst_initiate_read(STp, aSRpnt) || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) { + if (STp->raw) + return (-EIO); position = osst_get_frame_position(STp, aSRpnt); if (position >= 0xbae && position < 0xbb8) position = 0xbb8; @@ -968,7 +1032,7 @@ if (cnt > 1) { STp->recover_count++; STp->recover_erreg++; - printk(KERN_WARNING "osst%d:I: Read error at position %d recovered\n", + printk(KERN_WARNING "osst%d:I: Don't worry, Read error at position %d recovered\n", dev, STp->read_error_frame); } STp->read_count++; @@ -1525,7 +1589,10 @@ retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); else retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); - printk(KERN_WARNING "osst%d:I: Write error%srecovered\n", dev, retval?" not ":" "); + printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev, + retval?"E" :"I", + retval?"" :"Don't worry, ", + retval?" not ":" "); break; case OS_WRITE_LAST_MARK: printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev); @@ -1596,7 +1663,7 @@ mt_count, last_mark_ppos); #endif if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) { - osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG @@ -1628,7 +1695,7 @@ #if DEBUG printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos); #endif - osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); cnt++; if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG @@ -1755,7 +1822,7 @@ #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); } else { - osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", @@ -1795,7 +1862,7 @@ #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); } - osst_set_frame_position(STp, aSRpnt, STp->first_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG @@ -1827,7 +1894,7 @@ #if DEBUG else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos); #endif - osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); cnt++; if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG @@ -2464,7 +2531,7 @@ } #if DEBUG - printk(KERN_INFO "osst%d:D: Block Size changed to 32.5K\n", dev); + printk(KERN_INFO "osst%d:D: Drive Block Size changed to 32.5K\n", dev); /* * In debug mode, we want to see as many errors as possible * to test the error recovery mechanism. @@ -3402,6 +3469,7 @@ if (retval) goto out; STps->rw = ST_IDLE; + /* FIXME -- this may leave the tape without EOD and up2date headers */ } if ((count % STp->block_size) != 0) { @@ -3814,6 +3882,10 @@ ioctl_result = osst_flush_write_buffer(STp, &SRpnt); else ioctl_result = 0; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).\n", dev, arg); +#endif for (i=0; i= 0) fileno += arg; @@ -3833,14 +3905,9 @@ cmd[4] = arg; timeout = STp->timeout; #if DEBUG - if (debugging) { - if (cmd_in == MTWEOF) - printk(OSST_DEB_MSG "osst%d:D: Writing %d filemarks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - else - printk(OSST_DEB_MSG "osst%d:D: Writing %d setmarks.\n", dev, + if (debugging) + printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).\n", dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - } #endif if (fileno >= 0) fileno += arg; @@ -3853,8 +3920,12 @@ case MTRETEN: cmd[0] = START_STOP; cmd[1] = 1; /* Don't wait for completion */ - if (cmd_in == MTLOAD) + if (cmd_in == MTLOAD) { + if (STp->ready == ST_NO_TAPE) + cmd[4] = 4; /* open tray */ + else cmd[4] = 1; /* load */ + } if (cmd_in == MTRETEN) cmd[4] = 3; /* retension then mount */ if (cmd_in == MTOFFL) @@ -3993,7 +4064,7 @@ printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result); #endif - if (!ioctl_result) { + if (!ioctl_result) { /* success */ if (cmd_in == MTFSFM) { fileno--; @@ -4070,6 +4141,8 @@ if (cmd_in == MTLOCK) STp->door_locked = ST_LOCK_FAILS; + if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60)) + ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60); } *aSRpnt = SRpnt; @@ -4110,6 +4183,7 @@ __MOD_INC_USE_COUNT(STp->device->host->hostt->module); if (osst_template.module) __MOD_INC_USE_COUNT(osst_template.module); + STp->device->access_count++; if (mode != STp->current_mode) { #if DEBUG @@ -4126,6 +4200,8 @@ STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); STp->raw = (minor(inode->i_rdev) & 0x40) != 0; + if (STp->raw) + STp->header_ok = 0; /* Allocate a buffer for this user */ need_dma_buffer = STp->restr_dma; @@ -4216,7 +4292,7 @@ STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ for (i=0; i < ST_NBR_PARTITIONS; i++) { STps = &(STp->ps[i]); - STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ + STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ STps->eof = ST_NOEOF; STps->at_sm = 0; STps->last_block_valid = FALSE; @@ -4264,8 +4340,8 @@ STp->door_locked = ST_LOCKED_AUTO; } if (!STp->frame_in_buffer) { - STp->block_size = (STp->raw) ? OS_FRAME_SIZE : ( - (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); + STp->block_size = (STm->default_blksize > 0) ? + STm->default_blksize : OS_DATA_SIZE; STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; } STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; @@ -4358,8 +4434,6 @@ return 0; } - STp->min_block = STp->max_block = (-1); - osst_configure_onstream(STp, &SRpnt); /* STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */ @@ -4386,11 +4460,9 @@ } else STp->buffer->aux = NULL; /* this had better never happen! */ - STp->block_size = (STp->raw) ? OS_FRAME_SIZE : ( + STp->block_size = STp->raw ? OS_FRAME_SIZE : ( (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); - STp->min_block = 512; - STp->max_block = OS_DATA_SIZE; - STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; + STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size; STp->buffer->buffer_bytes = STp->buffer->read_pointer = STp->frame_in_buffer = 0; @@ -4448,6 +4520,8 @@ STp->buffer = NULL; } STp->in_use = 0; + STp->header_ok = 0; + STp->device->access_count--; if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); @@ -4484,7 +4558,7 @@ if (result != 0 && result != (-ENOSPC)) goto out; } - if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) { + if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) { #if DEBUG if (debugging) { @@ -4494,16 +4568,17 @@ dev, STp->nbr_waits, STp->nbr_finished); } #endif + if (STp->write_type != OS_WRITE_NEW_MARK) { + /* true unless the user wrote the filemark for us */ + result = osst_flush_drive_buffer(STp, &SRpnt); + if (result < 0) goto out; + result = osst_write_filemark(STp, &SRpnt); + if (result < 0) goto out; - result = osst_flush_drive_buffer(STp, &SRpnt); - if (result < 0) goto out; - result = osst_write_filemark(STp, &SRpnt); - if (result < 0) goto out; - - if (STps->drv_file >= 0) - STps->drv_file++ ; - STps->drv_block = 0; - + if (STps->drv_file >= 0) + STps->drv_file++ ; + STps->drv_block = 0; + } result = osst_write_eod(STp, &SRpnt); osst_write_header(STp, &SRpnt, !(STp->rew_at_close)); @@ -4587,7 +4662,12 @@ if (STp->buffer != NULL) STp->buffer->in_use = 0; + if (STp->raw) + STp->header_ok = 0; + STp->in_use = 0; + STp->device->access_count--; + if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); if(osst_template.module) @@ -4637,7 +4717,10 @@ cmd_type = _IOC_TYPE(cmd_in); cmd_nr = _IOC_NR(cmd_in); - +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s mode\n", dev, + cmd_type, cmd_nr, STp->raw?"raw":"normal"); +#endif if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { struct mtop mtc; @@ -4720,8 +4803,8 @@ } } - if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && - mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM && + if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM && + mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK && mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ @@ -4773,7 +4856,10 @@ } if (mtc.mt_op == MTSEEK) { - i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); + if (STp->raw) + i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0); + else + i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); if (!STp->can_partitions) STp->ps[0].rw = ST_IDLE; retval = i; @@ -4878,7 +4964,10 @@ retval = (-EINVAL); goto out; } - blk = osst_get_sector(STp, &SRpnt); + if (STp->raw) + blk = osst_get_frame_position(STp, &SRpnt); + else + blk = osst_get_sector(STp, &SRpnt); if (blk < 0) { retval = blk; goto out; @@ -4972,7 +5061,7 @@ tb = NULL; break; } - tb->sg[segs].page = NULL; + tb->sg[segs].page = NULL; tb->sg[segs].length = b_size; got += b_size; segs++; @@ -5424,6 +5513,8 @@ tpnt->partition = 0; tpnt->new_partition = 0; tpnt->nbr_partitions = 0; + tpnt->min_block = 512; + tpnt->max_block = OS_DATA_SIZE; tpnt->timeout = OSST_TIMEOUT; tpnt->long_timeout = OSST_LONG_TIMEOUT; @@ -5463,6 +5554,7 @@ tpnt->current_mode = 0; tpnt->modes[0].defined = TRUE; + tpnt->modes[2].defined = TRUE; tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE; init_MUTEX(&tpnt->lock); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/osst.h linux-2.5/drivers/scsi/osst.h --- linux-2.5.13/drivers/scsi/osst.h Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/scsi/osst.h Wed Mar 27 17:06:28 2002 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvsroot/Driver/osst.h,v 1.11 2001/01/26 01:54:49 riede Exp $ + * $Header: /home/cvsroot/Driver/osst.h,v 1.12 2001/10/11 00:30:15 riede Exp $ */ #include @@ -638,3 +638,5 @@ #define OS_WRITE_HEADER 4 #define OS_WRITE_FILLER 5 +/* Additional rw state */ +#define OS_WRITING_COMPLETE 3 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/pas16.c linux-2.5/drivers/scsi/pas16.c --- linux-2.5.13/drivers/scsi/pas16.c Fri May 3 01:22:38 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.13/drivers/scsi/pci2000.c linux-2.5/drivers/scsi/pci2000.c --- linux-2.5.13/drivers/scsi/pci2000.c Fri May 3 01:22:41 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.13/drivers/scsi/pcmcia/aha152x_stub.c linux-2.5/drivers/scsi/pcmcia/aha152x_stub.c --- linux-2.5.13/drivers/scsi/pcmcia/aha152x_stub.c Fri May 3 01:22:48 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.13/drivers/scsi/pcmcia/fdomain_stub.c linux-2.5/drivers/scsi/pcmcia/fdomain_stub.c --- linux-2.5.13/drivers/scsi/pcmcia/fdomain_stub.c Fri May 3 01:22:54 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.13/drivers/scsi/pcmcia/qlogic_stub.c linux-2.5/drivers/scsi/pcmcia/qlogic_stub.c --- linux-2.5.13/drivers/scsi/pcmcia/qlogic_stub.c Fri May 3 01:22:54 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.13/drivers/scsi/ppa.c linux-2.5/drivers/scsi/ppa.c --- linux-2.5.13/drivers/scsi/ppa.c Fri May 3 01:22: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.13/drivers/scsi/scsi.c linux-2.5/drivers/scsi/scsi.c --- linux-2.5.13/drivers/scsi/scsi.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/scsi/scsi.c Sun Apr 14 17:12:08 2002 @@ -75,6 +75,8 @@ #include #endif +#undef USE_STATIC_SCSI_MEMORY + struct proc_dir_entry *proc_scsi; #ifdef CONFIG_PROC_FS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/scsi.h linux-2.5/drivers/scsi/scsi.h --- linux-2.5.13/drivers/scsi/scsi.h Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/scsi/scsi.h Thu May 2 01:16:43 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.13/drivers/scsi/scsi_debug.c linux-2.5/drivers/scsi/scsi_debug.c --- linux-2.5.13/drivers/scsi/scsi_debug.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/scsi/scsi_debug.c Sat May 4 11:48:27 2002 @@ -32,15 +32,15 @@ #include #include #include +#include -#include #include #include #include "scsi.h" #include "hosts.h" -#include +#include #ifndef LINUX_VERSION_CODE #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/sd.c linux-2.5/drivers/scsi/sd.c --- linux-2.5.13/drivers/scsi/sd.c Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/scsi/sd.c Sat May 4 11:48:09 2002 @@ -41,11 +41,10 @@ #include #include #include - +#include #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); @@ -1094,7 +1094,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 @@ -1141,10 +1153,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); @@ -1165,9 +1173,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, @@ -1253,17 +1260,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 @@ -1315,6 +1324,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) { @@ -1595,6 +1606,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.13/drivers/scsi/sgiwd93.c linux-2.5/drivers/scsi/sgiwd93.c --- linux-2.5.13/drivers/scsi/sgiwd93.c Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/scsi/sgiwd93.c Sun Mar 3 17:54:36 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,29 +39,34 @@ 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(wd33c93_regs *regp, unsigned long value) +static inline void write_wd33c93_count(const wd33c93_regs regs, + unsigned long value) { - regp->SASR = WD_TRANSFER_COUNT_MSB; - regp->SCMD = ((value >> 16) & 0xff); - regp->SCMD = ((value >> 8) & 0xff); - regp->SCMD = ((value >> 0) & 0xff); + *regs.SASR = WD_TRANSFER_COUNT_MSB; + mb(); + *regs.SCMD = ((value >> 16) & 0xff); + *regs.SCMD = ((value >> 8) & 0xff); + *regs.SCMD = ((value >> 0) & 0xff); + mb(); } -static inline unsigned long read_wd33c93_count(wd33c93_regs *regp) +static inline unsigned long read_wd33c93_count(const wd33c93_regs regs) { unsigned long value; - regp->SASR = WD_TRANSFER_COUNT_MSB; - value = ((regp->SCMD & 0xff) << 16); - value |= ((regp->SCMD & 0xff) << 8); - value |= ((regp->SCMD & 0xff) << 0); + *regs.SASR = WD_TRANSFER_COUNT_MSB; + mb(); + value = ((*regs.SCMD & 0xff) << 16); + value |= ((*regs.SCMD & 0xff) << 8); + value |= ((*regs.SCMD & 0xff) << 0); + mb(); return value; } @@ -81,7 +89,6 @@ unsigned long physaddr; unsigned long count; - dma_cache_wback_inv((unsigned long)addr,len); physaddr = PHYSADDR(addr); while (len) { /* @@ -100,7 +107,6 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata; - wd33c93_regs *regp = hdata->regp; struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; @@ -111,46 +117,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(regp, 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(regp, 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 @@ -165,10 +142,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; } @@ -176,7 +157,6 @@ int status) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata; - wd33c93_regs *regp = hdata->regp; struct hpc3_scsiregs *hregs; if (!SCpnt) @@ -196,44 +176,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(regp); - 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 @@ -263,6 +205,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) @@ -272,6 +217,7 @@ struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1; struct WD33C93_hostdata *hdata; struct WD33C93_hostdata *hdata1; + wd33c93_regs regs; uchar *buf; if(called) @@ -292,10 +238,11 @@ return 0; } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG0 | 0x03 | KSEG1 */ - wd33c93_init(sgiwd93_host, (wd33c93_regs *) KSEG1ADDR (0x1fbc0003), - dma_setup, dma_stop, WD33C93_FS_16_20); + 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; hdata->no_sync = 0; @@ -326,15 +273,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 */ - wd33c93_init(sgiwd93_host1, (wd33c93_regs *) KSEG1ADDR (0x1fbc8003), - dma_setup, dma_stop, WD33C93_FS_16_20); + 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); 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.13/drivers/scsi/sun3_NCR5380.c linux-2.5/drivers/scsi/sun3_NCR5380.c --- linux-2.5.13/drivers/scsi/sun3_NCR5380.c Fri May 3 01:22: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.13/drivers/scsi/sun3_scsi.c linux-2.5/drivers/scsi/sun3_scsi.c --- linux-2.5.13/drivers/scsi/sun3_scsi.c Fri May 3 01:22: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; @@ -609,3 +623,4 @@ #include "scsi_module.c" +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/scsi/sym53c8xx.c linux-2.5/drivers/scsi/sym53c8xx.c --- linux-2.5.13/drivers/scsi/sym53c8xx.c Fri May 3 01:22:42 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.13/drivers/scsi/t128.c linux-2.5/drivers/scsi/t128.c --- linux-2.5.13/drivers/scsi/t128.c Fri May 3 01:22:56 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.13/drivers/scsi/tmscsim.c linux-2.5/drivers/scsi/tmscsim.c --- linux-2.5.13/drivers/scsi/tmscsim.c Fri May 3 01:22:54 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.13/drivers/scsi/wd33c93.c linux-2.5/drivers/scsi/wd33c93.c --- linux-2.5.13/drivers/scsi/wd33c93.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/scsi/wd33c93.c Wed Mar 27 13:07:17 2002 @@ -1407,12 +1407,32 @@ -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); write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); @@ -2034,3 +2054,5 @@ { MOD_DEC_USE_COUNT; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/sgi/char/Makefile linux-2.5/drivers/sgi/char/Makefile --- linux-2.5.13/drivers/sgi/char/Makefile Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/sgi/char/Makefile Sun Mar 3 17:54:36 2002 @@ -9,7 +9,7 @@ O_TARGET := sgichar.o -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.13/drivers/sgi/char/ds1286.c linux-2.5/drivers/sgi/char/ds1286.c --- linux-2.5.13/drivers/sgi/char/ds1286.c Fri May 3 01:22:48 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.13/drivers/sgi/char/sgiserial.c linux-2.5/drivers/sgi/char/sgiserial.c --- linux-2.5.13/drivers/sgi/char/sgiserial.c Fri May 3 01:22:46 2002 +++ linux-2.5/drivers/sgi/char/sgiserial.c Wed May 1 17:26:08 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; @@ -1887,7 +1888,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; @@ -1913,9 +1916,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(); @@ -2014,7 +2017,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.13/drivers/tc/lk201.c linux-2.5/drivers/tc/lk201.c --- linux-2.5.13/drivers/tc/lk201.c Fri May 3 01:22:57 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.13/drivers/tc/lk201.h linux-2.5/drivers/tc/lk201.h --- linux-2.5.13/drivers/tc/lk201.h Fri May 3 01:22:52 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.13/drivers/tc/zs.c linux-2.5/drivers/tc/zs.c --- linux-2.5.13/drivers/tc/zs.c Fri May 3 01:22:47 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.13/drivers/telephony/Config.help linux-2.5/drivers/telephony/Config.help --- linux-2.5.13/drivers/telephony/Config.help Fri May 3 01:22:57 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.13/drivers/telephony/Config.in linux-2.5/drivers/telephony/Config.in --- linux-2.5.13/drivers/telephony/Config.in Fri May 3 01:22:55 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.13/drivers/telephony/ixj.c linux-2.5/drivers/telephony/ixj.c --- linux-2.5.13/drivers/telephony/ixj.c Fri May 3 01:22:39 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.13/drivers/usb/CDCEther.h linux-2.5/drivers/usb/CDCEther.h --- linux-2.5.13/drivers/usb/CDCEther.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/usb/CDCEther.h Sat Apr 13 17:42:56 2002 @@ -0,0 +1,99 @@ +// Portions of this file taken from +// Petko Manolov - Petkan (petkan@dce.bg) +// from his driver pegasus.h + +/* + * 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 + */ + +/* From CDC Spec Table 24 */ +#define CS_INTERFACE 0x24 + +#define CDC_ETHER_MAX_MTU 1536 + +/* These definitions are used with the ether_dev_t flags element */ +#define CDC_ETHER_PRESENT 0x00000001 +#define CDC_ETHER_RUNNING 0x00000002 +#define CDC_ETHER_TX_BUSY 0x00000004 +#define CDC_ETHER_RX_BUSY 0x00000008 +#define CDC_ETHER_UNPLUG 0x00000040 + +#define CDC_ETHER_TX_TIMEOUT (HZ*10) + +#define TX_UNDERRUN 0x80 +#define EXCESSIVE_COL 0x40 +#define LATE_COL 0x20 +#define NO_CARRIER 0x10 +#define LOSS_CARRIER 0x08 +#define JABBER_TIMEOUT 0x04 + +#define CDC_ETHER_REQT_READ 0xc0 +#define CDC_ETHER_REQT_WRITE 0x40 +#define CDC_ETHER_REQ_GET_REGS 0xf0 +#define CDC_ETHER_REQ_SET_REGS 0xf1 +#define CDC_ETHER_REQ_SET_REG PIPERIDER_REQ_SET_REGS +#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) + +#define MODE_FLAG_PROMISCUOUS (1<<0) +#define MODE_FLAG_ALL_MULTICAST (1<<1) +#define MODE_FLAG_DIRECTED (1<<2) +#define MODE_FLAG_BROADCAST (1<<3) +#define MODE_FLAG_MULTICAST (1<<4) + +#define SET_ETHERNET_MULTICAST_FILTER 0x40 +#define SET_ETHERNET_PACKET_FILTER 0x43 + +typedef struct _ether_dev_t { + struct usb_device *usb; + struct net_device *net; + struct net_device_stats stats; + unsigned flags; + int configuration_num; + int bConfigurationValue; + int comm_interface; + int comm_bInterfaceNumber; + int comm_interface_altset_num; + int comm_bAlternateSetting; + int comm_ep_in; + int data_interface; + int data_bInterfaceNumber; + int data_interface_altset_num_with_traffic; + int data_bAlternateSetting_with_traffic; + int data_interface_altset_num_without_traffic; + int data_bAlternateSetting_without_traffic; + int data_ep_in; + int data_ep_out; + int data_ep_out_size; + __u16 bcdCDC; + __u8 iMACAddress; + __u32 bmEthernetStatistics; + __u16 wMaxSegmentSize; + __u16 mode_flags; + __u16 wNumberMCFilters; + __u8 bNumberPowerFilters; + int intr_interval; + struct urb *rx_urb, *tx_urb, *intr_urb; + unsigned char ALIGN(rx_buff[CDC_ETHER_MAX_MTU]); + unsigned char ALIGN(tx_buff[CDC_ETHER_MAX_MTU]); + unsigned char ALIGN(intr_buff[8]); +} ether_dev_t; + +#define REQ_HDR_FUNC_DESCR 0x0001 +#define REQ_UNION_FUNC_DESCR 0x0002 +#define REQ_ETH_FUNC_DESCR 0x0004 +#define REQUIREMENTS_TOTAL 0x0007 + + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/Config.in linux-2.5/drivers/usb/Config.in --- linux-2.5.13/drivers/usb/Config.in Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/usb/Config.in Thu Apr 25 03:00:03 2002 @@ -15,7 +15,7 @@ source drivers/usb/storage/Config.in source drivers/usb/input/Config.in - + source drivers/usb/image/Config.in source drivers/usb/media/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/Makefile linux-2.5/drivers/usb/Makefile --- linux-2.5.13/drivers/usb/Makefile Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/usb/Makefile Thu Apr 25 03:00:03 2002 @@ -17,7 +17,7 @@ subdir-$(CONFIG_USB_ACM) += class subdir-$(CONFIG_USB_AUDIO) += class -subdir-$(CONFIG_USB_BLUETOOTH) += class +subdir-$(CONFIG_USB_BLUETOOTH_TTY) += class subdir-$(CONFIG_USB_PRINTER) += class subdir-$(CONFIG_USB_STORAGE) += storage diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/class/audio.c linux-2.5/drivers/usb/class/audio.c --- linux-2.5.13/drivers/usb/class/audio.c Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/usb/class/audio.c Mon Apr 22 02:24:21 2002 @@ -2347,6 +2347,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.13/drivers/usb/core/hub.h linux-2.5/drivers/usb/core/hub.h --- linux-2.5.13/drivers/usb/core/hub.h Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/usb/core/hub.h Sun Apr 14 12:30:36 2002 @@ -9,6 +9,7 @@ */ #include +#include /* likely()/unlikely() */ /* * Hub request types diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/host/usb-ohci.c linux-2.5/drivers/usb/host/usb-ohci.c --- linux-2.5.13/drivers/usb/host/usb-ohci.c Fri May 3 01:22:44 2002 +++ linux-2.5/drivers/usb/host/usb-ohci.c Mon Apr 22 02:24:21 2002 @@ -83,7 +83,8 @@ #ifdef CONFIG_PMAC_PBOOK -#include +#include +#include #include #ifndef CONFIG_PM #define CONFIG_PM @@ -2727,12 +2728,12 @@ pci_write_config_word (dev, PCI_COMMAND, cmd); #ifdef CONFIG_PMAC_PBOOK { - struct device_node *of_node; + struct device_node *of_node; - /* Disable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (ohci->ohci_dev); - if (of_node && _machine == _MACH_Pmac) - feature_set_usb_power (of_node, 0); + /* Disable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (ohci->ohci_dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); } #endif return 0; @@ -2757,12 +2758,12 @@ #ifdef CONFIG_PMAC_PBOOK { - struct device_node *of_node; + struct device_node *of_node; - /* Re-enable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (ohci->ohci_dev); - if (of_node && _machine == _MACH_Pmac) - feature_set_usb_power (of_node, 1); + /* Re-enable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (ohci->ohci_dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/input/hid-core.c linux-2.5/drivers/usb/input/hid-core.c --- linux-2.5.13/drivers/usb/input/hid-core.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/usb/input/hid-core.c Wed May 1 17:26:08 2002 @@ -1477,20 +1477,20 @@ { struct hid_device *hid = ptr; + dbg("cleanup called"); usb_unlink_urb(hid->urbin); usb_unlink_urb(hid->urbout); usb_unlink_urb(hid->urbctrl); - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_disconnect(hid); - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_disconnect(hid); - usb_free_urb(hid->urbin); usb_free_urb(hid->urbctrl); if (hid->urbout) usb_free_urb(hid->urbout); + if (hid->claimed & HID_CLAIMED_INPUT) + hidinput_disconnect(hid); + if (hid->claimed & HID_CLAIMED_HIDDEV) + hiddev_disconnect(hid); hid_free_device(hid); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/media/pwc-ctrl.c linux-2.5/drivers/usb/media/pwc-ctrl.c --- linux-2.5.13/drivers/usb/media/pwc-ctrl.c Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/usb/media/pwc-ctrl.c Sun Apr 14 23:00:47 2002 @@ -1,7 +1,7 @@ /* Driver for Philips webcam Functions that send various control messages to the webcam, including video modes. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 @@ -78,10 +78,12 @@ #define READ_SHUTTER_FORMATTER 0x0600 #define READ_RED_GAIN_FORMATTER 0x0700 #define READ_BLUE_GAIN_FORMATTER 0x0800 +#define SENSOR_TYPE_FORMATTER1 0x0C00 #define READ_RAW_Y_MEAN_FORMATTER 0x3100 #define SET_POWER_SAVE_MODE_FORMATTER 0x3200 #define MIRROR_IMAGE_FORMATTER 0x3300 #define LED_FORMATTER 0x3400 +#define SENSOR_TYPE_FORMATTER2 0x3700 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 @@ -162,6 +164,21 @@ /****************************************************************************/ +#define SendControlMsg(request, value, buflen) \ + usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ + request, \ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) + +#define RecvControlMsg(request, value, buflen) \ + usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ + request, \ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) #if PWC_DEBUG @@ -241,7 +258,7 @@ ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); if (ret < 0) return ret; - if (pEntry->compressed) + if (pEntry->compressed && pdev->decompressor != NULL) pdev->decompressor->init(pdev->release, buf, pdev->decompress_data); /* Set various parameters */ @@ -911,7 +928,7 @@ int ret; ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, + GET_CHROM_CTL, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, PRESET_MANUAL_RED_GAIN_FORMATTER, pdev->vcinterface, @@ -950,7 +967,7 @@ int ret; ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, + GET_CHROM_CTL, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, PRESET_MANUAL_BLUE_GAIN_FORMATTER, pdev->vcinterface, @@ -962,6 +979,7 @@ return (buf << 8); } + /* The following two functions are different, since they only read the internal red/blue gains, which may be different from the manual gains set or read above. @@ -997,10 +1015,73 @@ &buf, 1, HZ / 2); if (ret < 0) - return ret; + return ret; return (buf << 8); } + + +static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) +{ + unsigned char buf; + + /* useful range is 0x01..0x20 */ + buf = speed / 0x7f0; + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_CHROM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AWB_CONTROL_SPEED_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + +static inline int pwc_get_wb_speed(struct pwc_device *pdev) +{ + unsigned char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_CHROM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AWB_CONTROL_SPEED_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return (buf * 0x7f0); +} + + +static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) +{ + unsigned char buf; + + /* useful range is 0x01..0x3F */ + buf = (delay >> 10); + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_CHROM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AWB_CONTROL_DELAY_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + +static inline int pwc_get_wb_delay(struct pwc_device *pdev) +{ + unsigned char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_CHROM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AWB_CONTROL_DELAY_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return (buf << 10); +} + int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/media/pwc-if.c linux-2.5/drivers/usb/media/pwc-if.c --- linux-2.5.13/drivers/usb/media/pwc-if.c Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/usb/media/pwc-if.c Mon Apr 15 01:00:20 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam USB and Video4Linux interface part. - (C) 1999-2001 Nemosoft Unv. + (C) 1999-2002 Nemosoft Unv. 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 @@ -67,7 +67,7 @@ /* hotplug device table support */ static __devinitdata struct usb_device_id pwc_device_table [] = { - { USB_DEVICE(0x0471, 0x0302) }, + { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ { USB_DEVICE(0x0471, 0x0303) }, { USB_DEVICE(0x0471, 0x0304) }, { USB_DEVICE(0x0471, 0x0307) }, @@ -76,12 +76,14 @@ { USB_DEVICE(0x0471, 0x0310) }, { USB_DEVICE(0x0471, 0x0311) }, { USB_DEVICE(0x0471, 0x0312) }, - { USB_DEVICE(0x069A, 0x0001) }, - { USB_DEVICE(0x046D, 0x08b0) }, - { USB_DEVICE(0x055D, 0x9000) }, + { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ + { USB_DEVICE(0x046D, 0x08b0) }, /* Logitech */ + { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ { USB_DEVICE(0x055D, 0x9001) }, - { USB_DEVICE(0x041E, 0x400C) }, - { USB_DEVICE(0x04CC, 0x8116) }, + { USB_DEVICE(0x041E, 0x400C) }, /* Creative */ + { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ + { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ + { USB_DEVICE(0x0d81, 0x1900) }, { } }; MODULE_DEVICE_TABLE(usb, pwc_device_table); @@ -106,7 +108,7 @@ static int default_mbufs = 2; /* Default number of mmap() buffers */ int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; static int power_save = 0; -static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */ +static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ static struct { int type; @@ -167,7 +169,7 @@ succeeded. The pwc_device struct links back to both structures. When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register as a V4L device, but + list of known USB devices; I also de-register it as a V4L device, but unfortunately I can't free the memory since the struct is still in use by the file descriptor. This free-ing is then deferend until the first opportunity. Crude, but it works. @@ -315,6 +317,8 @@ for (; i < MAX_IMAGES; i++) pdev->image_ptr[i] = NULL; + kbuf = NULL; + Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n"); return 0; } @@ -369,6 +373,7 @@ rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); } pdev->image_data = NULL; + Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); } @@ -570,12 +575,10 @@ pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; } -/* 2001-10-14: The YUV420 is still there, but you can only set it from within - a program (YUV420P being the default) */ +/* 2001-10-14: YUV420P is the only palette remaining. */ static int pwc_set_palette(struct pwc_device *pdev, int pal) { - if ( pal == VIDEO_PALETTE_YUV420 - || pal == VIDEO_PALETTE_YUV420P + if ( pal == VIDEO_PALETTE_YUV420P #if PWC_DEBUG || pal == VIDEO_PALETTE_RAW #endif @@ -869,7 +872,6 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) { int ret; - /* Stop isoc stuff */ pwc_isoc_cleanup(pdev); /* Reset parameters */ @@ -933,6 +935,29 @@ if (usb_set_interface(pdev->udev, 0, 0)) Info("Failed to set alternate interface to 0.\n"); pdev->usb_init = 1; + + if (pwc_trace & TRACE_OPEN) { + /* Query CMOS sensor type */ + const char *sensor_type = NULL; + + i = pwc_get_cmos_sensor(pdev); + switch(i) { + case -1: /* Unknown, show nothing */; break; + case 0x00: sensor_type = "Hyundai CMOS sensor"; break; + case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; + case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; + case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; + case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; + case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; + case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; + case 0x40: sensor_type = "UPA 1021 sensor"; break; + case 0x100: sensor_type = "VGA sensor"; break; + case 0x101: sensor_type = "PAL MR sensor"; break; + default: sensor_type = "unknown type of sensor"; break; + } + if (sensor_type != NULL) + Info("Thes %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); + } } /* Turn on camera */ @@ -1512,6 +1537,7 @@ pdev = vdev->priv; /* FIXME - audit mmap during a read */ + /* Nemo: 9 months and 20 kernel revisions later I still don't know what you mean by this :-) */ pos = (unsigned long)pdev->image_data; while (size > 0) { page = kvirt_to_pa(pos); @@ -1543,7 +1569,7 @@ int vendor_id, product_id, type_id; int i, hint; int video_nr = -1; /* default: use next available device */ - char serial_number[30]; + char serial_number[30], *name; free_mem_leak(); @@ -1564,38 +1590,47 @@ switch (product_id) { case 0x0302: Info("Philips PCA645VC USB webcam detected.\n"); + name = "Philips 645 webcam"; type_id = 645; break; case 0x0303: Info("Philips PCA646VC USB webcam detected.\n"); + name = "Philips 646 webcam"; type_id = 646; break; case 0x0304: Info("Askey VC010 type 2 USB webcam detected.\n"); + name = "Askey VC010 webcam"; type_id = 646; break; case 0x0307: Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); + name = "Philips 675 webcam"; type_id = 675; break; case 0x0308: Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + name = "Philips 680 webcam"; type_id = 680; break; case 0x030C: Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); + name = "Philips 690 webcam"; type_id = 690; break; case 0x0310: Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n"); + name = "Philips 730 webcam"; type_id = 730; break; case 0x0311: Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n"); + name = "Philips 740 webcam"; type_id = 740; break; case 0x0312: Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); + name = "Philips 750 webcam"; type_id = 750; break; default: @@ -1607,6 +1642,7 @@ switch(product_id) { case 0x0001: Info("Askey VC010 type 1 USB webcam detected.\n"); + name = "Askey VC010 webcam"; type_id = 645; break; default: @@ -1617,7 +1653,8 @@ else if (vendor_id == 0x046d) { switch(product_id) { case 0x08b0: - Info("Logitech QuickCam 3000 Pro detected.\n"); + Info("Logitech QuickCam 3000 Pro USB webcam detected.\n"); + name = "Logitech QuickCam 3000 Pro"; type_id = 730; break; default: @@ -1633,10 +1670,12 @@ switch(product_id) { case 0x9000: Info("Samsung MPC-C10 USB webcam detected.\n"); + name = "Samsung MPC-C10"; type_id = 675; break; case 0x9001: Info("Samsung MPC-C30 USB webcam detected.\n"); + name = "Samsung MPC-C30"; type_id = 675; break; default: @@ -1648,6 +1687,7 @@ switch(product_id) { case 0x400c: Info("Creative Labs Webcam 5 detected.\n"); + name = "Creative Labs Webcam 5"; type_id = 730; break; default: @@ -1658,7 +1698,8 @@ else if (vendor_id == 0x04cc) { switch(product_id) { case 0x8116: - Info("SOTEC CMS-001 USB webcam detected.\n"); + Info("Sotec Afina Eye USB webcam detected.\n"); + name = "Sotec Afina Eye"; type_id = 730; break; default: @@ -1666,7 +1707,25 @@ break; } } - else return NULL; /* Not Philips, Askey, Logitech, Samsung, Creative or SOTEC, for sure. */ + else if (vendor_id == 0x0d81) { + switch(product_id) { + case 0x1900: + Info("Visionite VCS-UC300 USB webcam detected.\n"); + name = "Visionite VCS-UC300"; + type_id = 740; /* CCD sensor */ + break; + case 0x1910: + Info("Visionite VCS-UM100 USB webcam detected.\n"); + name = "Visionite VCS-UM100"; + type_id = 730; /* CMOS sensor */ + break; + default: + return NULL; + break; + } + } + else + return NULL; /* Not any of the know types; but the list keeps growing. */ memset(serial_number, 0, 30); usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); @@ -1700,7 +1759,7 @@ return NULL; } memcpy(vdev, &pwc_template, sizeof(pwc_template)); - sprintf(vdev->name, "Philips %d webcam", pdev->type); + strcpy(vdev->name, name); SET_MODULE_OWNER(vdev); pdev->vdev = vdev; vdev->priv = pdev; @@ -1708,7 +1767,6 @@ pdev->release = udev->descriptor.bcdDevice; Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); - /* Now search device_hint[] table for a match, so we can hint a node number. */ for (hint = 0; hint < MAX_DEV_HINTS; hint++) { if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && @@ -1873,11 +1931,12 @@ char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n"); - Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30, the Creative WebCam 5 and the SOTEC CMS-001.\n"); + Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30,\n"); + Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); if (fps) { - if (fps < 5 || fps > 30) { - Err("Framerate out of bounds (5-30).\n"); + if (fps < 4 || fps > 30) { + Err("Framerate out of bounds (4-30).\n"); return -EINVAL; } default_fps = fps; @@ -1929,9 +1988,9 @@ if (power_save) Info("Enabling power save on open/close.\n"); if (leds[0] >= 0) - led_on = leds[0] / 100; + led_on = leds[0]; if (leds[1] >= 0) - led_off = leds[1] / 100; + led_off = leds[1]; /* Big device node whoopla. Basicly, it allows you to assign a device node (/dev/videoX) to a camera, based on its type diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/media/pwc-ioctl.h linux-2.5/drivers/usb/media/pwc-ioctl.h --- linux-2.5.13/drivers/usb/media/pwc-ioctl.h Fri May 3 01:22:52 2002 +++ linux-2.5/drivers/usb/media/pwc-ioctl.h Sat Apr 13 17:42:56 2002 @@ -1,7 +1,7 @@ #ifndef PWC_IOCTL_H #define PWC_IOCTL_H -/* (C) 2001 Nemosoft Unv. webcam@smcc.demon.nl +/* (C) 2001-2002 Nemosoft Unv. webcam@smcc.demon.nl 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 @@ -18,7 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/* This is pwc-ioctl.h belonging to PWC 8.6 */ + +/* Changes 2001/08/03 Alvarado Added ioctl constants to access methods for changing white balance and red/blue gains @@ -52,6 +54,14 @@ #define PWC_FPS_SNAPSHOT 0x00400000 + +struct pwc_probe +{ + char name[32]; + int type; +}; + + /* pwc_whitebalance.mode values */ #define PWC_WB_INDOOR 0 #define PWC_WB_OUTDOOR 1 @@ -63,9 +73,9 @@ Set mode to one of the PWC_WB_* values above. *red and *blue are the respective gains of these colour components inside the camera; range 0..65535 - When mode == PWC_WB_MANUAL, manual_red and manual_blue are set or read; + When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; otherwise undefined. - read_red and read_blue are read-only. + 'read_red' and 'read_blue' are read-only. */ struct pwc_whitebalance @@ -75,6 +85,17 @@ int read_red, read_blue; /* R/O */ }; +/* + 'control_speed' and 'control_delay' are used in automatic whitebalance mode, + and tell the camera how fast it should react to changes in lighting, and + with how much delay. Valid values are 0..65535. +*/ +struct pwc_wb_speed +{ + int control_speed; + int control_delay; + +}; /* Used with VIDIOCPWC[SG]LED */ struct pwc_leds @@ -104,6 +125,19 @@ /* Get preferred compression quality */ #define VIDIOCPWCGCQUAL _IOR('v', 195, int) + + /* This is a probe function; since so many devices are supported, it + becomes difficult to include all the names in programs that want to + check for the enhanced Philips stuff. So in stead, try this PROBE; + it returns a structure with the original name, and the corresponding + Philips type. + To use, fill the structure with zeroes, call PROBE and if that succeeds, + compare the name with that returned from VIDIOCGCAP; they should be the + same. If so, you can be assured it is a Philips (OEM) cam and the type + is valid. + */ +#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) + /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ #define VIDIOCPWCSAGC _IOW('v', 200, int) /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ @@ -115,9 +149,28 @@ #define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) #define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - /* Turn LED on/off ; int range 0..65535 */ + /* Auto WB speed */ +#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) +#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) + + /* LEDs on/off/blink; int range 0..65535 */ #define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) - /* Get state of LED; int range 0..65535 */ #define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) + + /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ +#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) +#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) + + /* Backlight compensation; 0 = off, otherwise on */ +#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) +#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) + + /* Flickerless mode; = 0 off, otherwise on */ +#define VIDIOCPWCSFLICKER _IOW('v', 208, int) +#define VIDIOCPWCGFLICKER _IOR('v', 208, int) + + /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ +#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) +#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/media/pwc-misc.c linux-2.5/drivers/usb/media/pwc-misc.c --- linux-2.5.13/drivers/usb/media/pwc-misc.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/usb/media/pwc-misc.c Sun Apr 14 23:00:47 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam Various miscellaneous functions and tables. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/media/pwc-uncompress.c linux-2.5/drivers/usb/media/pwc-uncompress.c --- linux-2.5.13/drivers/usb/media/pwc-uncompress.c Fri May 3 01:22:37 2002 +++ linux-2.5/drivers/usb/media/pwc-uncompress.c Sun Apr 14 23:00:47 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam Decompression frontend. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/media/pwc-uncompress.h linux-2.5/drivers/usb/media/pwc-uncompress.h --- linux-2.5.13/drivers/usb/media/pwc-uncompress.h Fri May 3 01:22:47 2002 +++ linux-2.5/drivers/usb/media/pwc-uncompress.h Sat Apr 13 17:42:56 2002 @@ -1,4 +1,4 @@ -/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) +/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 @@ -20,8 +20,8 @@ significant change should be reflected by increasing the pwc_decompressor_version major number. */ -#ifndef PWC_DEC_H -#define PWC_DEC_H +#ifndef PWC_UNCOMPRESS_H +#define PWC_UNCOMPRESS_H #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/media/pwc.h linux-2.5/drivers/usb/media/pwc.h --- linux-2.5.13/drivers/usb/media/pwc.h Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/usb/media/pwc.h Sat Apr 13 17:42:56 2002 @@ -1,4 +1,4 @@ -/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) +/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 @@ -60,8 +60,8 @@ /* Version block */ #define PWC_MAJOR 8 -#define PWC_MINOR 5 -#define PWC_VERSION "8.5" +#define PWC_MINOR 6 +#define PWC_VERSION "8.6" #define PWC_NAME "pwc" /* Turn certain features on/off */ @@ -247,6 +247,7 @@ extern int pwc_set_saturation(struct pwc_device *pdev, int value); extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); +extern int pwc_get_cmos_sensor(struct pwc_device *pdev); /* Power down or up the camera; not supported by all models */ extern int pwc_camera_power(struct pwc_device *pdev, int power); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/powermate.c linux-2.5/drivers/usb/powermate.c --- linux-2.5.13/drivers/usb/powermate.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/usb/powermate.c Fri Feb 8 09:44:26 2002 @@ -0,0 +1,356 @@ +/* + * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial. + * + * v1.0, (c)2002 William R Sowerbutts + * + * This device is a stainless steel knob which connects over USB. It can measure + * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with + * a spring for automatic release. The base contains a pair of LEDs which illuminate + * the translucent base. It rotates without limit and reports its relative rotation + * back to the host when polled by the USB controller. + * + * Testing with the knob I have has shown that it measures approximately 94 "clicks" + * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was + * a variable speed cordless electric drill) has shown that the device can measure + * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from + * the host. If it counts more than 7 clicks before it is polled, it will wrap back + * to zero and start counting again. This was at quite high speed, however, almost + * certainly faster than the human hand could turn it. + * + * The device's microcontroller can be programmed to set the LED to either a constant + * intensity, or to a rhythmic pulsing. Several patterns and speeds are available. + * + * Griffin were very happy to provide documentation and free hardware for development. + * + */ + +#include +#include +#include +#include +#include +#include + +#define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ +#define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */ +#define POWERMATE_PRODUCT_OLD 0x04AA /* Griffin soundKnob */ + +/* these are the command codes we send to the device */ +#define SET_STATIC_BRIGHTNESS 0x01 +#define SET_PULSE_ASLEEP 0x02 +#define SET_PULSE_AWAKE 0x03 +#define SET_PULSE_MODE 0x04 + +/* these refer to bits in the powermate_device's requires_update field. */ +#define UPDATE_STATIC_BRIGHTNESS (1<<0) +#define UPDATE_PULSE_ASLEEP (1<<1) +#define UPDATE_PULSE_AWAKE (1<<2) +#define UPDATE_PULSE_MODE (1<<3) + +#define POWERMATE_PAYLOAD_SIZE 3 +struct powermate_device { + signed char data[POWERMATE_PAYLOAD_SIZE]; + struct urb irq, config; + struct usb_ctrlrequest configcr; + struct usb_device *udev; + struct input_dev input; + struct semaphore lock; + int static_brightness; + int pulse_speed; + int pulse_table; + int pulse_asleep; + int pulse_awake; + int requires_update; // physical settings which are out of sync + char phys[64]; +}; + +static char pm_name_powermate[] = "Griffin PowerMate"; +static char pm_name_soundknob[] = "Griffin SoundKnob"; + +static void powermate_config_complete(struct urb *urb); /* forward declararation of callback */ + +/* Callback for data arriving from the PowerMate over the USB interrupt pipe */ +static void powermate_irq(struct urb *urb) +{ + struct powermate_device *pm = urb->context; + + if(urb->status) + return; + + /* handle updates to device state */ + input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01); + input_report_rel(&pm->input, REL_DIAL, pm->data[1]); +} + +/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */ +static void powermate_sync_state(struct powermate_device *pm) +{ + if(pm->requires_update == 0) + return; /* no updates are required */ + if(pm->config.status == -EINPROGRESS) + return; /* an update is already in progress; it'll issue this update when it completes */ + + if(pm->requires_update & UPDATE_STATIC_BRIGHTNESS){ + pm->configcr.wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); + pm->configcr.wIndex = cpu_to_le16( pm->static_brightness ); + pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; + }else if(pm->requires_update & UPDATE_PULSE_ASLEEP){ + pm->configcr.wValue = cpu_to_le16( SET_PULSE_ASLEEP ); + pm->configcr.wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 ); + pm->requires_update &= ~UPDATE_PULSE_ASLEEP; + }else if(pm->requires_update & UPDATE_PULSE_AWAKE){ + pm->configcr.wValue = cpu_to_le16( SET_PULSE_AWAKE ); + pm->configcr.wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 ); + pm->requires_update &= ~UPDATE_PULSE_AWAKE; + }else if(pm->requires_update & UPDATE_PULSE_MODE){ + int op, arg; + /* the powermate takes an operation and an argument for its pulse algorithm. + the operation can be: + 0: divide the speed + 1: pulse at normal speed + 2: multiply the speed + the argument only has an effect for operations 0 and 2, and ranges between + 1 (least effect) to 255 (maximum effect). + + thus, several states are equivalent and are coalesced into one state. + + we map this onto a range from 0 to 510, with: + 0 -- 254 -- use divide (0 = slowest) + 255 -- use normal speed + 256 -- 510 -- use multiple (510 = fastest). + + Only values of 'arg' quite close to 255 are particularly useful/spectacular. + */ + if(pm->pulse_speed < 255){ + op = 0; // divide + arg = 255 - pm->pulse_speed; + }else if(pm->pulse_speed > 255){ + op = 2; // multiply + arg = pm->pulse_speed - 255; + }else{ + op = 1; // normal speed + arg = 0; // can be any value + } + pm->configcr.wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); + pm->configcr.wIndex = cpu_to_le16( (arg << 8) | op ); + pm->requires_update &= ~UPDATE_PULSE_MODE; + }else{ + printk(KERN_ERR "powermate: unknown update required"); + pm->requires_update = 0; /* fudge the bug */ + return; + } + +/* printk("powermate: %04x %04x\n", pm->configcr.wValue, pm->configcr.wIndex); */ + + pm->config.dev = pm->udev; /* is this necessary? */ + pm->configcr.bRequestType = 0x41; /* vendor request */ + pm->configcr.bRequest = 0x01; + pm->configcr.wLength = 0; + + FILL_CONTROL_URB(&pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), + (void*)&pm->configcr, 0, 0, powermate_config_complete, pm); + + if(usb_submit_urb(&pm->config, GFP_KERNEL)) + printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); +} + +/* Called when our asynchronous control message completes. We may need to issue another immediately */ +static void powermate_config_complete(struct urb *urb) +{ + struct powermate_device *pm = urb->context; + + if(urb->status) + printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); + + down(&pm->lock); + powermate_sync_state(pm); + up(&pm->lock); +} + +/* Set the LED up as described and begin the sync with the hardware if required */ +static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, + int pulse_table, int pulse_asleep, int pulse_awake) +{ + if(pulse_speed < 0) + pulse_speed = 0; + if(pulse_table < 0) + pulse_table = 0; + if(pulse_speed > 510) + pulse_speed = 510; + if(pulse_table > 2) + pulse_table = 2; + + pulse_asleep = !!pulse_asleep; + pulse_awake = !!pulse_awake; + + down(&pm->lock); + + /* mark state updates which are required */ + if(static_brightness != pm->static_brightness){ + pm->static_brightness = static_brightness; + pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; + } + if(pulse_asleep != pm->pulse_asleep){ + pm->pulse_asleep = pulse_asleep; + pm->requires_update |= UPDATE_PULSE_ASLEEP; + } + if(pulse_awake != pm->pulse_awake){ + pm->pulse_awake = pulse_awake; + pm->requires_update |= UPDATE_PULSE_AWAKE; + } + if(pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){ + pm->pulse_speed = pulse_speed; + pm->pulse_table = pulse_table; + pm->requires_update |= UPDATE_PULSE_MODE; + } + + powermate_sync_state(pm); + + up(&pm->lock); +} + +/* Callback from the Input layer when an event arrives from userspace to configure the LED */ +static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value) +{ + unsigned int command = (unsigned int)_value; + struct powermate_device *pm = dev->private; + + if(type == EV_MSC && code == MSC_PULSELED){ + /* + bits 0- 7: 8 bits: LED brightness + bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster. + bits 17-18: 2 bits: pulse table (0, 1, 2 valid) + bit 19: 1 bit : pulse whilst asleep? + bit 20: 1 bit : pulse constantly? + */ + int static_brightness = command & 0xFF; // bits 0-7 + int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16 + int pulse_table = (command >> 17) & 0x3; // bits 17-18 + int pulse_asleep = (command >> 19) & 0x1; // bit 19 + int pulse_awake = (command >> 20) & 0x1; // bit 20 + + powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake); + } + + return 0; +} + +/* Called whenever a USB device matching one in our supported devices table is connected */ +static void *powermate_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct powermate_device *pm; + int pipe, maxp; + char path[64]; + + interface = udev->config[0].interface[ifnum].altsetting + 0; + endpoint = interface->endpoint + 0; + if (!(endpoint->bEndpointAddress & 0x80)) return NULL; + if ((endpoint->bmAttributes & 3) != 3) return NULL; + + usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, interface->bInterfaceNumber, NULL, 0, + HZ * USB_CTRL_SET_TIMEOUT); + + if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL))) + return NULL; + + memset(pm, 0, sizeof(struct powermate_device)); + pm->udev = udev; + + init_MUTEX(&pm->lock); + + /* get a handle to the interrupt data pipe */ + pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + + if(maxp != POWERMATE_PAYLOAD_SIZE) + printk("powermate: Expected payload of %d bytes, found %d bytes!\n", POWERMATE_PAYLOAD_SIZE, maxp); + + FILL_INT_URB(&pm->irq, udev, pipe, pm->data, POWERMATE_PAYLOAD_SIZE, powermate_irq, pm, endpoint->bInterval); + + /* register our interrupt URB with the USB system */ + if(usb_submit_urb(&pm->irq, GFP_KERNEL)) { + kfree(pm); + return NULL; /* failure */ + } + + switch (udev->descriptor.idProduct) { + case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break; + case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break; + default: + pm->input.name = pm_name_soundknob; + printk(KERN_WARNING "powermate: unknown product id %04x\n", udev->descriptor.idProduct); + } + + pm->input.private = pm; + pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); + pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0); + pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); + pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); + pm->input.idbus = BUS_USB; + pm->input.idvendor = udev->descriptor.idVendor; + pm->input.idproduct = udev->descriptor.idProduct; + pm->input.idversion = udev->descriptor.bcdDevice; + pm->input.event = powermate_input_event; + + input_register_device(&pm->input); + + usb_make_path(udev, path, 64); + snprintf(pm->phys, 64, "%s/input0", path); + printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys); + + /* force an update of everything */ + pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; + powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters + + return pm; +} + +/* Called when a USB device we've accepted ownership of is removed */ +static void powermate_disconnect(struct usb_device *dev, void *ptr) +{ + struct powermate_device *pm = ptr; + down(&pm->lock); + pm->requires_update = 0; + usb_unlink_urb(&pm->irq); + input_unregister_device(&pm->input); + + kfree(pm); +} + +static struct usb_device_id powermate_devices [] = { + { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) }, + { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, powermate_devices); + +static struct usb_driver powermate_driver = { + name: "powermate", + probe: powermate_probe, + disconnect: powermate_disconnect, + id_table: powermate_devices, +}; + +int powermate_init(void) +{ + if (usb_register(&powermate_driver) < 0) + return -1; + return 0; +} + +void powermate_cleanup(void) +{ + usb_deregister(&powermate_driver); +} + +module_init(powermate_init); +module_exit(powermate_cleanup); + +MODULE_AUTHOR( "William R Sowerbutts" ); +MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" ); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/serial/usbserial.c linux-2.5/drivers/usb/serial/usbserial.c --- linux-2.5.13/drivers/usb/serial/usbserial.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/usb/serial/usbserial.c Mon Apr 22 02:24:22 2002 @@ -1665,7 +1665,7 @@ #if 0 static kdev_t usb_console_device(struct console *co) { - return MKDEV(SERIAL_TTY_MAJOR, co->index); /* TBD */ + return mk_kdev(SERIAL_TTY_MAJOR, co->index); /* TBD */ } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/datafab.c linux-2.5/drivers/usb/storage/datafab.c --- linux-2.5.13/drivers/usb/storage/datafab.c Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/usb/storage/datafab.c Wed Mar 27 13:07:17 2002 @@ -1,16 +1,25 @@ /* Driver for Datafab USB Compact Flash reader * + * $Id: datafab.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $ + * * datafab driver v0.1: * * First release * * Current development and maintenance by: * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) - * many thanks to Robert Baruch for the SanDisk SmartMedia reader driver + * + * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver * which I used as a template for this driver. + * * Some bugfixes and scatter-gather code by Gregory P. Smith * (greg-usb@electricrain.com) * + * Fix for media change by Joerg Schneider (js@joergschneider.com) + * + * Other contributors: + * (c) 2002 Alan Stern + * * 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, or (at your option) any @@ -102,7 +111,7 @@ if (result == -EPIPE) { US_DEBUGP("datafab_raw_bulk: EPIPE. clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -800,6 +809,23 @@ // return USB_STOR_TRANSPORT_GOOD; } + + if (srb->cmnd[0] == START_STOP) { + /* this is used by sd.c'check_scsidisk_media_change to detect + media change */ + US_DEBUGP("datafab_transport: START_STOP.\n"); + /* the first datafab_id_device after a media change returns + an error (determined experimentally) */ + rc = datafab_id_device(us, info); + if (rc == USB_STOR_TRANSPORT_GOOD) { + info->sense_key = NO_SENSE; + srb->result = SUCCESS; + } else { + info->sense_key = UNIT_ATTENTION; + srb->result = CHECK_CONDITION; + } + return rc; + } US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]); return USB_STOR_TRANSPORT_ERROR; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/debug.c linux-2.5/drivers/usb/storage/debug.c --- linux-2.5.13/drivers/usb/storage/debug.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/usb/storage/debug.c Wed Mar 27 13:07:17 2002 @@ -1,10 +1,13 @@ /* Driver for USB Mass Storage compliant devices * Debugging Functions Source Code File * - * $Id: debug.c,v 1.5 2001/06/27 23:20:45 mdharm Exp $ + * $Id: debug.c,v 1.8 2002/02/25 00:40:13 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * Developed with the assistance of: + * (c) 2002 Alan Stern * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -302,9 +305,11 @@ case 0x1902: what="defect list error in primary list"; break; case 0x1903: what="defect list error in grown list"; break; case 0x1C00: what="defect list not found"; break; + case 0x2000: what="invalid command operation code"; break; case 0x2400: what="invalid field in CDB"; break; case 0x2703: what="associated write protect"; break; case 0x2800: what="not ready to ready transition"; break; + case 0x2900: what="device reset occurred"; break; case 0x2903: what="bus device reset function occurred"; break; case 0x2904: what="device internal reset"; break; case 0x2B00: what="copy can't execute / host can't disconnect"; break; @@ -327,7 +332,7 @@ case 0x3502: what="enclosure services unavailable"; break; case 0x3503: what="enclosure services transfer failure"; break; case 0x3504: what="enclosure services transfer refused"; break; - case 0x3A00: what="medium not present"; break; + case 0x3A00: what="media not present"; break; case 0x3B0F: what="end of medium reached"; break; case 0x3F02: what="changed operating definition"; break; case 0x4100: what="data path failure (should use 40 NN)"; break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/isd200.c linux-2.5/drivers/usb/storage/isd200.c --- linux-2.5.13/drivers/usb/storage/isd200.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/usb/storage/isd200.c Wed Mar 27 13:07:17 2002 @@ -1,9 +1,15 @@ /* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC * - * First release + * $Id: isd200.c,v 1.14 2002/02/25 00:40:13 mdharm Exp $ * - * Current development and maintenance by: - * (c) 2000 In-System Design, Inc. (support@in-system.com) + * Current development and maintenance: + * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se) + * + * Developed with the assistance of: + * (C) 2002 Alan Stern + * + * Initial work: + * (C) 2000 In-System Design, Inc. (support@in-system.com) * * The ISD200 ASIC does not natively support ATA devices. The chip * does implement an interface, the ATA Command Block (ATACB) which provides @@ -27,6 +33,10 @@ * * 2001-02-24: Removed lots of duplicate code and simplified the structure. * (bjorn@haxx.se) + * 2002-01-16: Fixed endianness bug so it works on the ppc arch. + * (Luc Saillard ) + * 2002-01-17: All bitfields removed. + * (bjorn@haxx.se) */ @@ -45,15 +55,6 @@ #include #include -/* - * Inquiry defines. Used to interpret data returned from target as result - * of inquiry command. - * - * DeviceType field - */ - -#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ - /* Timeout defines (in Seconds) */ #define ISD200_ENUM_BSY_TIMEOUT 35 @@ -88,6 +89,19 @@ #define ACTION_SELECT_6 0x40 #define ACTION_SELECT_7 0x80 +/* Register Select bits */ +#define REG_ALTERNATE_STATUS 0x01 +#define REG_DEVICE_CONTROL 0x01 +#define REG_ERROR 0x02 +#define REG_FEATURES 0x02 +#define REG_SECTOR_COUNT 0x04 +#define REG_SECTOR_NUMBER 0x08 +#define REG_CYLINDER_LOW 0x10 +#define REG_CYLINDER_HIGH 0x20 +#define REG_DEVICE_HEAD 0x40 +#define REG_STATUS 0x80 +#define REG_COMMAND 0x80 + /* ATA error definitions not in */ #define ATA_ERROR_MEDIA_CHANGE 0x20 @@ -152,20 +166,8 @@ struct { unsigned char SignatureByte0; unsigned char SignatureByte1; - unsigned char ReadRegisterAccessBit : 1; - unsigned char NoDeviceSelectionBit : 1; - unsigned char NoBSYPollBit : 1; - unsigned char IgnorePhaseErrorBit : 1; - unsigned char IgnoreDeviceErrorBit : 1; - unsigned char Reserved0Bit : 3; - unsigned char SelectAlternateStatus : 1; - unsigned char SelectError : 1; - unsigned char SelectSectorCount : 1; - unsigned char SelectSectorNumber : 1; - unsigned char SelectCylinderLow : 1; - unsigned char SelectCylinderHigh : 1; - unsigned char SelectDeviceHead : 1; - unsigned char SelectStatus : 1; + unsigned char ActionSelect; + unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char AlternateStatusByte; unsigned char ErrorByte; @@ -181,20 +183,8 @@ struct { unsigned char SignatureByte0; unsigned char SignatureByte1; - unsigned char ReadRegisterAccessBit : 1; - unsigned char NoDeviceSelectionBit : 1; - unsigned char NoBSYPollBit : 1; - unsigned char IgnorePhaseErrorBit : 1; - unsigned char IgnoreDeviceErrorBit : 1; - unsigned char Reserved0Bit : 3; - unsigned char SelectDeviceControl : 1; - unsigned char SelectFeatures : 1; - unsigned char SelectSectorCount : 1; - unsigned char SelectSectorNumber : 1; - unsigned char SelectCylinderLow : 1; - unsigned char SelectCylinderHigh : 1; - unsigned char SelectDeviceHead : 1; - unsigned char SelectCommand : 1; + unsigned char ActionSelect; + unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char DeviceControlByte; unsigned char FeaturesByte; @@ -218,27 +208,20 @@ * includes fields through ProductRevisionLevel. */ +/* + * DeviceType field + */ +#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ +#define DEVICE_REMOVABLE 0x80 + struct inquiry_data { - unsigned char DeviceType : 5; - unsigned char DeviceTypeQualifier : 3; - unsigned char DeviceTypeModifier : 7; - unsigned char RemovableMedia : 1; + unsigned char DeviceType; + unsigned char DeviceTypeModifier; unsigned char Versions; - unsigned char ResponseDataFormat : 4; - unsigned char HiSupport : 1; - unsigned char NormACA : 1; - unsigned char ReservedBit : 1; - unsigned char AERC : 1; + unsigned char Format; unsigned char AdditionalLength; unsigned char Reserved[2]; - unsigned char SoftReset : 1; - unsigned char CommandQueue : 1; - unsigned char Reserved2 : 1; - unsigned char LinkedCommands : 1; - unsigned char Synchronous : 1; - unsigned char Wide16Bit : 1; - unsigned char Wide32Bit : 1; - unsigned char RelativeAddressing : 1; + unsigned char Capability; unsigned char VendorId[8]; unsigned char ProductId[16]; unsigned char ProductRevisionLevel[4]; @@ -257,25 +240,30 @@ * ISD200 CONFIG data struct */ +#define ATACFG_TIMING 0x0f +#define ATACFG_ATAPI_RESET 0x10 +#define ATACFG_MASTER 0x20 +#define ATACFG_BLOCKSIZE 0xa0 + +#define ATACFGE_LAST_LUN 0x07 +#define ATACFGE_DESC_OVERRIDE 0x08 +#define ATACFGE_STATE_SUSPEND 0x10 +#define ATACFGE_SKIP_BOOT 0x20 +#define ATACFGE_CONF_DESC2 0x40 +#define ATACFGE_INIT_STATUS 0x80 + +#define CFG_CAPABILITY_SRST 0x01 + struct isd200_config { unsigned char EventNotification; unsigned char ExternalClock; unsigned char ATAInitTimeout; - unsigned char ATATiming : 4; - unsigned char ATAPIReset : 1; - unsigned char MasterSlaveSelection : 1; - unsigned char ATAPICommandBlockSize : 2; + unsigned char ATAConfig; unsigned char ATAMajorCommand; unsigned char ATAMinorCommand; - unsigned char LastLUNIdentifier : 3; - unsigned char DescriptOverride : 1; - unsigned char ATA3StateSuspend : 1; - unsigned char SkipDeviceBoot : 1; - unsigned char ConfigDescriptor2 : 1; - unsigned char InitStatus : 1; - unsigned char SRSTEnable : 1; - unsigned char Reserved0 : 7; -}; + unsigned char ATAExtraConfig; + unsigned char Capability; +}__attribute__ ((packed)); /* @@ -321,15 +309,16 @@ * Sense Data Format */ +#define SENSE_ERRCODE 0x7f +#define SENSE_ERRCODE_VALID 0x80 +#define SENSE_FLAG_SENSE_KEY 0x0f +#define SENSE_FLAG_BAD_LENGTH 0x20 +#define SENSE_FLAG_END_OF_MEDIA 0x40 +#define SENSE_FLAG_FILE_MARK 0x80 struct sense_data { - unsigned char ErrorCode:7; - unsigned char Valid:1; - unsigned char SegmentNumber; - unsigned char SenseKey:4; - unsigned char Reserved:1; - unsigned char IncorrectLength:1; - unsigned char EndOfMedia:1; - unsigned char FileMark:1; + unsigned char ErrorCode; + unsigned char SegmentNumber; + unsigned char Flags; unsigned char Information[4]; unsigned char AdditionalSenseLength; unsigned char CommandSpecificInformation[4]; @@ -349,7 +338,6 @@ * Helper routines ***********************************************************************/ - /************************************************************************** * isd200_build_sense * @@ -366,38 +354,33 @@ unsigned char error = info->ATARegs[IDE_ERROR_OFFSET]; if(error & ATA_ERROR_MEDIA_CHANGE) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = UNIT_ATTENTION; + buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & MCR_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = UNIT_ATTENTION; + buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & TRK0_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = NOT_READY; + buf->Flags = NOT_READY; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & ECC_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = DATA_PROTECT; + buf->Flags = DATA_PROTECT; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else { buf->ErrorCode = 0; - buf->Valid = 0; buf->AdditionalSenseLength = 0; - buf->SenseKey = 0; + buf->Flags = 0; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } @@ -442,7 +425,7 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } /* did we send all the data? */ @@ -593,7 +576,7 @@ US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0xFF), - bcb.DataTransferLength, bcb.Flags, bcb.Length); + le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); @@ -603,7 +586,7 @@ else if (result == -EPIPE) { /* if we stall, we need to clear it before we go on */ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } else if (result) return ISD200_TRANSPORT_ERROR; @@ -633,7 +616,7 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); @@ -647,7 +630,7 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); return ISD200_TRANSPORT_ERROR; } } @@ -716,10 +699,9 @@ case ACTION_READ_STATUS: US_DEBUGP(" isd200_action(READ_STATUS)\n"); ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; - ata.read.SelectStatus = 1; - ata.read.SelectError = 1; - ata.read.SelectCylinderHigh = 1; - ata.read.SelectCylinderLow = 1; + ata.generic.RegisterSelect = + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_STATUS | REG_ERROR; srb.sc_data_direction = SCSI_DATA_READ; srb.request_buffer = pointer; srb.request_bufflen = value; @@ -730,7 +712,7 @@ ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4| ACTION_SELECT_5; - ata.write.SelectDeviceHead = 1; + ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -739,7 +721,7 @@ US_DEBUGP(" isd200_action(RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; - ata.write.SelectDeviceControl = 1; + ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -748,7 +730,7 @@ US_DEBUGP(" isd200_action(REENABLE)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; - ata.write.SelectDeviceControl = 1; + ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -756,16 +738,15 @@ case ACTION_SOFT_RESET: US_DEBUGP(" isd200_action(SOFT_RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; - ata.write.SelectDeviceHead = 1; + ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; - ata.write.SelectCommand = 1; ata.write.CommandByte = WIN_SRST; srb.sc_data_direction = SCSI_DATA_NONE; break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); - ata.write.SelectCommand = 1; + ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; srb.sc_data_direction = SCSI_DATA_READ; srb.request_buffer = (void *)&info->drive; @@ -886,6 +867,43 @@ srb->result = CHECK_CONDITION; } +#ifdef CONFIG_USB_STORAGE_DEBUG +static void isd200_log_config( struct isd200_info* info ) +{ + US_DEBUGP(" Event Notification: 0x%x\n", + info->ConfigData.EventNotification); + US_DEBUGP(" External Clock: 0x%x\n", + info->ConfigData.ExternalClock); + US_DEBUGP(" ATA Init Timeout: 0x%x\n", + info->ConfigData.ATAInitTimeout); + US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", + (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6); + US_DEBUGP(" Master/Slave Selection: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_MASTER); + US_DEBUGP(" ATAPI Reset: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET); + US_DEBUGP(" ATA Timing: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_TIMING); + US_DEBUGP(" ATA Major Command: 0x%x\n", + info->ConfigData.ATAMajorCommand); + US_DEBUGP(" ATA Minor Command: 0x%x\n", + info->ConfigData.ATAMinorCommand); + US_DEBUGP(" Init Status: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS); + US_DEBUGP(" Config Descriptor 2: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2); + US_DEBUGP(" Skip Device Boot: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT); + US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND); + US_DEBUGP(" Descriptor Override: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE); + US_DEBUGP(" Last LUN Identifier: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN); + US_DEBUGP(" SRST Enable: 0x%x\n", + info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST); +} +#endif /************************************************************************** * isd200_write_config @@ -901,26 +919,11 @@ int retStatus = ISD200_GOOD; int result; - +#ifdef CONFIG_USB_STORAGE_DEBUG US_DEBUGP("Entering isd200_write_config\n"); - US_DEBUGP(" Writing the following ISD200 Config Data:\n"); - US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection); - US_DEBUGP(" ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset); - US_DEBUGP(" ATA Timing: 0x%x\n", info->ConfigData.ATATiming); - US_DEBUGP(" ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", info->ConfigData.InitStatus); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend); - US_DEBUGP(" Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier); - US_DEBUGP(" SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable); + isd200_log_config(info); +#endif /* let's send the command via the control pipe */ result = usb_stor_control_msg( @@ -941,8 +944,8 @@ /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0)); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); } @@ -986,30 +989,17 @@ if (result >= 0) { US_DEBUGP(" Retrieved the following ISD200 Config Data:\n"); - US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection); - US_DEBUGP(" ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset); - US_DEBUGP(" ATA Timing: 0x%x\n", info->ConfigData.ATATiming); - US_DEBUGP(" ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", info->ConfigData.InitStatus); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend); - US_DEBUGP(" Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier); - US_DEBUGP(" SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable); +#ifdef CONFIG_USB_STORAGE_DEBUG + isd200_log_config(info); +#endif } else { US_DEBUGP(" Request to get ISD200 Config Data failed!\n"); /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0)); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); } @@ -1175,11 +1165,12 @@ break; } } else { - US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); + US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); + break; } /* check for timeout on this request */ - if (jiffies >= endTime) { + if (time_after_eq(jiffies, endTime)) { if (!detect) US_DEBUGP(" BSY check timeout, just continue with next operation...\n"); else @@ -1223,9 +1214,10 @@ } isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; - if (info->ConfigData.MasterSlaveSelection != isslave) { + if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) { US_DEBUGP(" Setting Master/Slave selection to %d\n", isslave); - info->ConfigData.MasterSlaveSelection = isslave; + info->ConfigData.ATAConfig &= 0x3f; + info->ConfigData.ATAConfig |= (isslave<<6); retStatus = isd200_write_config(us); } } @@ -1272,6 +1264,8 @@ } else { /* ATA Command Identify successful */ int i; + __u16 *src, *dest; + ide_fix_driveid(&info->drive); US_DEBUGP(" Identify Data Structure:\n"); US_DEBUGP(" config = 0x%x\n", info->drive.config); @@ -1317,31 +1311,25 @@ if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) { /* set the removable bit */ - info->InquiryData.RemovableMedia = 1; + info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; info->DeviceFlags |= DF_REMOVABLE_MEDIA; } /* Fill in vendor identification fields */ - for (i = 0; i < 20; i += 2) { - info->InquiryData.VendorId[i] = - info->drive.model[i + 1]; - info->InquiryData.VendorId[i+1] = - info->drive.model[i]; - } - - /* Initialize unused portion of product id */ - for (i = 0; i < 4; i++) { - info->InquiryData.ProductId[12+i] = ' '; - } - - /* Move firmware revision from IDENTIFY data to */ - /* product revision in INQUIRY data */ - for (i = 0; i < 4; i += 2) { - info->InquiryData.ProductRevisionLevel[i] = - info->drive.fw_rev[i+1]; - info->InquiryData.ProductRevisionLevel[i+1] = - info->drive.fw_rev[i]; - } + src = (__u16*)info->drive.model; + dest = (__u16*)info->InquiryData.VendorId; + for (i=0;i<4;i++) + dest[i] = be16_to_cpu(src[i]); + + src = (__u16*)(info->drive.model+8); + dest = (__u16*)info->InquiryData.ProductId; + for (i=0;i<8;i++) + dest[i] = be16_to_cpu(src[i]); + + src = (__u16*)info->drive.fw_rev; + dest = (__u16*)info->InquiryData.ProductRevisionLevel; + for (i=0;i<2;i++) + dest[i] = be16_to_cpu(src[i]); /* determine if it supports Media Status Notification */ if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) { @@ -1483,7 +1471,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { @@ -1504,7 +1492,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { @@ -1561,17 +1549,15 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectSectorCount = 1; + ataCdb->generic.RegisterSelect = + REG_SECTOR_COUNT | REG_SECTOR_NUMBER | + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_DEVICE_HEAD | REG_COMMAND; ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SelectSectorNumber = 1; ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.SelectCylinderHigh = 1; ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.SelectCylinderLow = 1; ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.SelectDeviceHead = 1; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.SelectCommand = 1; ataCdb->write.CommandByte = WIN_READ; break; @@ -1594,17 +1580,15 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectSectorCount = 1; + ataCdb->generic.RegisterSelect = + REG_SECTOR_COUNT | REG_SECTOR_NUMBER | + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_DEVICE_HEAD | REG_COMMAND; ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SelectSectorNumber = 1; ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.SelectCylinderHigh = 1; ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.SelectCylinderLow = 1; ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.SelectDeviceHead = 1; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.SelectCommand = 1; ataCdb->write.CommandByte = WIN_WRITE; break; @@ -1617,7 +1601,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? WIN_DOORLOCK : WIN_DOORUNLOCK; srb->request_bufflen = 0; @@ -1640,14 +1624,14 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 0; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; } else if ((srb->cmnd[4] & 0x3) == 0x1) { US_DEBUGP(" Get Media Status\n"); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/jumpshot.c linux-2.5/drivers/usb/storage/jumpshot.c --- linux-2.5.13/drivers/usb/storage/jumpshot.c Fri May 3 01:22:39 2002 +++ linux-2.5/drivers/usb/storage/jumpshot.c Fri May 3 12:57:31 2002 @@ -1,16 +1,26 @@ /* Driver for Lexar "Jumpshot" Compact Flash reader * + * $Id: jumpshot.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $ + * * jumpshot driver v0.1: * * First release * * Current development and maintenance by: * (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org) - * many thanks to Robert Baruch for the SanDisk SmartMedia reader driver + * + * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver * which I used as a template for this driver. + * * Some bugfixes and scatter-gather code by Gregory P. Smith * (greg-usb@electricrain.com) * + * Fix for media change by Joerg Schneider (js@joergschneider.com) + * + * Developed with the assistance of: + * + * (C) 2002 Alan Stern + * * 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, or (at your option) any @@ -128,8 +138,8 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("jumpshot_send_control: -- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("jumpshot_send_control: -- usb_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("jumpshot_send_control: -- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -161,7 +171,7 @@ if (result == -EPIPE) { US_DEBUGP("jumpshot_raw_bulk: EPIPE. clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -798,6 +808,23 @@ // return USB_STOR_TRANSPORT_GOOD; } + + if (srb->cmnd[0] == START_STOP) { + /* this is used by sd.c'check_scsidisk_media_change to detect + media change */ + US_DEBUGP("jumpshot_transport: START_STOP.\n"); + /* the first jumpshot_id_device after a media change returns + an error (determined experimentally) */ + rc = jumpshot_id_device(us, info); + if (rc == USB_STOR_TRANSPORT_GOOD) { + info->sense_key = NO_SENSE; + srb->result = SUCCESS; + } else { + info->sense_key = UNIT_ATTENTION; + srb->result = CHECK_CONDITION; + } + return rc; + } US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]); return USB_STOR_TRANSPORT_ERROR; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/protocol.c linux-2.5/drivers/usb/storage/protocol.c --- linux-2.5.13/drivers/usb/storage/protocol.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/usb/storage/protocol.c Wed Mar 27 13:07:17 2002 @@ -1,12 +1,13 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $ + * $Id: protocol.c,v 1.13 2002/02/25 00:34:56 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * (c) 2002 Alan Stern (stern@rowland.org) * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -94,9 +95,11 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) @@ -165,13 +168,15 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if (old_cmnd == MODE_SENSE) + usb_stor_scsiSense10to6(srb); + + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } @@ -260,13 +265,15 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* Fix the data for an INQUIRY, if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if (old_cmnd == MODE_SENSE) + usb_stor_scsiSense10to6(srb); + + /* Fix the data for an INQUIRY, if necessary */ + fix_inquiry_data(srb); + } } void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) @@ -327,13 +334,14 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE) - && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE)) + usb_stor_scsiSense10to6(srb); + + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/shuttle_usbat.c linux-2.5/drivers/usb/storage/shuttle_usbat.c --- linux-2.5.13/drivers/usb/storage/shuttle_usbat.c Fri May 3 01:22:38 2002 +++ linux-2.5/drivers/usb/storage/shuttle_usbat.c Wed Mar 27 13:07:17 2002 @@ -1,10 +1,13 @@ /* Driver for SCM Microsystems USB-ATAPI cable * - * $Id: shuttle_usbat.c,v 1.15 2001/12/08 23:32:48 mdharm Exp $ + * $Id: shuttle_usbat.c,v 1.16 2002/02/25 00:40:13 mdharm Exp $ * * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * + * Developed with the assistance of: + * (c) 2002 Alan Stern + * * Many originally ATAPI devices were slightly modified to meet the USB * market by using some kind of translation from ATAPI to USB on the host, * and the peripheral would translate from USB back to ATAPI. @@ -107,8 +110,8 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -140,7 +143,7 @@ US_DEBUGP("EPIPE: clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -515,7 +518,7 @@ */ if (direction==SCSI_DATA_READ && i==0) - usb_clear_halt(us->pusb_dev, + usb_stor_clear_halt(us, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); /* @@ -675,9 +678,15 @@ len = short_pack(data[7+9], data[7+8]); len <<= 16; len |= data[7+7]; + US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); srb->transfersize = srb->request_bufflen/len; } + if (!srb->transfersize) { + srb->transfersize = 2048; /* A guess */ + US_DEBUGP("handle_read10: transfersize 0, forcing %d\n", + srb->transfersize); + } len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/transport.c linux-2.5/drivers/usb/storage/transport.c --- linux-2.5.13/drivers/usb/storage/transport.c Fri May 3 01:22:49 2002 +++ linux-2.5/drivers/usb/storage/transport.c Wed Mar 27 13:07:17 2002 @@ -1,13 +1,14 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.42 2001/12/08 23:32:48 mdharm Exp $ + * $Id: transport.c,v 1.44 2002/02/25 00:43:41 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) + * (c) 2002 Alan Stern * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -335,31 +336,7 @@ len = srb->request_bufflen; } -return len; -} - -/* This is a version of usb_clear_halt() that doesn't read the status from - * the device -- this is because some devices crash their internal firmware - * when the status is requested after a halt - */ -int usb_stor_clear_halt(struct usb_device *dev, int pipe) -{ - int result; - int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); - - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0, HZ * 3); - - /* this is a failure case */ - if (result < 0) - return result; - - /* reset the toggles and endpoint flags */ - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - - return 0; + return len; } /*********************************************************************** @@ -481,6 +458,34 @@ return us->current_urb->status; } +/* This is a version of usb_clear_halt() that doesn't read the status from + * the device -- this is because some devices crash their internal firmware + * when the status is requested after a halt + */ +int usb_stor_clear_halt(struct us_data *us, int pipe) +{ + int result; + int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); + + result = usb_stor_control_msg(us, + usb_sndctrlpipe(us->pusb_dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, + endp, NULL, 0); /* note: no 3*HZ timeout */ + US_DEBUGP("usb_stor_clear_halt: result=%d\n", result); + + /* this is a failure case */ + if (result < 0) + return result; + + /* reset the toggles and endpoint flags */ + usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe)); + usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe), 0); + + return 0; +} + /* * Transfer one SCSI scatter-gather buffer via bulk transfer * @@ -513,7 +518,13 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); + } + + /* did we abort this command? */ + if (result == -ENOENT) { + US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; } /* did we send all the data? */ @@ -522,21 +533,14 @@ return US_BULK_TRANSFER_GOOD; } - /* uh oh... we have an error code, so something went wrong. */ - if (result) { - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) { - US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); - return US_BULK_TRANSFER_FAILED; - } - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } + /* NAK - that means we've retried a few times already */ + if (result == -ETIMEDOUT) { + US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); + return US_BULK_TRANSFER_FAILED; + } - /* the catch-all case */ + /* the catch-all error case */ + if (result) { US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); return US_BULK_TRANSFER_FAILED; } @@ -550,7 +554,7 @@ * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * - * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this + * Note that this uses usb_stor_transfer_partial to achieve its goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */ @@ -631,6 +635,14 @@ return; } + /* if there is a transport error, reset and don't auto-sense */ + if (result == USB_STOR_TRANSPORT_ERROR) { + US_DEBUGP("-- transport indicates error, resetting\n"); + us->transport_reset(us); + srb->result = DID_ERROR << 16; + return; + } + /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible @@ -660,7 +672,7 @@ } /* - * If we have an error, we're going to do a REQUEST_SENSE + * If we have a failure, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ @@ -668,13 +680,6 @@ US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } - if (result == USB_STOR_TRANSPORT_ERROR) { - us->transport_reset(us); - US_DEBUGP("-- transport indicates transport failure\n"); - need_auto_sense = 0; - srb->result = DID_ERROR << 16; - return; - } /* * Also, if we have a short transfer on a command that can't have @@ -730,6 +735,19 @@ /* issue the auto-sense command */ temp_result = us->transport(us->srb, us); + + /* let's clean up right away */ + srb->request_buffer = old_request_buffer; + srb->request_bufflen = old_request_bufflen; + srb->use_sg = old_sg; + srb->sc_data_direction = old_sc_data_direction; + memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); + + if (temp_result == USB_STOR_TRANSPORT_ABORTED) { + US_DEBUGP("-- auto-sense aborted\n"); + srb->result = DID_ABORT << 16; + return; + } if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); @@ -760,13 +778,6 @@ /* set the result so the higher layers expect this data */ srb->result = CHECK_CONDITION << 1; - /* we're done here, let's clean up */ - srb->request_buffer = old_request_buffer; - srb->request_bufflen = old_request_bufflen; - srb->use_sg = old_sg; - srb->sc_data_direction = old_sc_data_direction; - memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); - /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) srb->result = GOOD << 1; @@ -864,21 +875,25 @@ if (result < 0) { /* Reset flag for status notification */ atomic_set(us->ip_wanted, 0); + } + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + + /* STALL must be cleared when it is detected */ + if (result == -EPIPE) { + US_DEBUGP("-- Stall on control pipe. Clearing\n"); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; + return USB_STOR_TRANSPORT_FAILED; + } - /* STALL must be cleared when they are detected */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); - return USB_STOR_TRANSPORT_FAILED; - } - + if (result < 0) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } @@ -887,12 +902,18 @@ /* transfer the data payload for this command, if one exists*/ if (usb_stor_transfer_length(srb)) { usb_stor_transfer(srb, us); - US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); + result = srb->result; + US_DEBUGP("CBI data stage result is 0x%x\n", result); - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) { + /* report any errors */ + if (result == US_BULK_TRANSFER_ABORTED) { + atomic_set(us->ip_wanted, 0); return USB_STOR_TRANSPORT_ABORTED; } + if (result == US_BULK_TRANSFER_FAILED) { + atomic_set(us->ip_wanted, 0); + return USB_STOR_TRANSPORT_FAILED; + } } /* STATUS STAGE */ @@ -976,10 +997,12 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_FAILED; } @@ -991,11 +1014,16 @@ /* transfer the data payload for this command, if one exists*/ if (usb_stor_transfer_length(srb)) { usb_stor_transfer(srb, us); - US_DEBUGP("CB data stage result is 0x%x\n", srb->result); + result = srb->result; + US_DEBUGP("CB data stage result is 0x%x\n", result); - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) + /* report any errors */ + if (result == US_BULK_TRANSFER_ABORTED) { return USB_STOR_TRANSPORT_ABORTED; + } + if (result == US_BULK_TRANSFER_FAILED) { + return USB_STOR_TRANSPORT_FAILED; + } } /* STATUS STAGE */ @@ -1016,7 +1044,8 @@ int result; int pipe; - /* issue the command */ + /* issue the command -- use usb_control_msg() because + * the state machine is not yet alive */ pipe = usb_rcvctrlpipe(us->pusb_dev, 0); result = usb_control_msg(us->pusb_dev, pipe, US_BULK_GET_MAX_LUN, @@ -1034,7 +1063,10 @@ /* if we get a STALL, clear the stall */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + + /* Use usb_clear_halt() because the state machine + * is not yet alive */ + usb_clear_halt(us->pusb_dev, pipe); } /* return the default -- no LUNs */ @@ -1051,10 +1083,6 @@ int pipe; int partial; - /* if the device was removed, then we're already reset */ - if (!us->pusb_dev) - return SUCCESS; - /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); @@ -1088,7 +1116,12 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + result = -EPIPE; } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; @@ -1099,11 +1132,11 @@ /* send/receive data payload, if there is any */ if (bcb.DataTransferLength) { usb_stor_transfer(srb, us); - US_DEBUGP("Bulk data transfer result 0x%x\n", - srb->result); + result = srb->result; + US_DEBUGP("Bulk data transfer result 0x%x\n", result); /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) + if (result == US_BULK_TRANSFER_ABORTED) return USB_STOR_TRANSPORT_ABORTED; } } @@ -1127,8 +1160,12 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_msg(us, &bcs, pipe, @@ -1141,7 +1178,11 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ERROR; } } @@ -1157,7 +1198,7 @@ le32_to_cpu(bcs.Signature), bcs.Tag, bcs.Residue, bcs.Status); if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || - bcs.Tag != bcb.Tag || + ((bcs.Tag != bcb.Tag ) && (!(us->flags & US_FL_SL_IDE_BUG))) || bcs.Status > US_BULK_STAT_PHASE || partial != 13) { US_DEBUGP("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; @@ -1220,10 +1261,10 @@ set_current_state(TASK_RUNNING); US_DEBUGP("CB_reset: clearing endpoint halt\n"); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); + usb_stor_clear_halt(us, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_stor_clear_halt(us, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); /* return a result code based on the result of the control message */ @@ -1259,10 +1300,10 @@ schedule_timeout(HZ*6); set_current_state(TASK_RUNNING); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_stor_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + usb_stor_clear_halt(us, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_stor_clear_halt(us, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("Bulk soft reset completed\n"); return SUCCESS; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/transport.h linux-2.5/drivers/usb/storage/transport.h --- linux-2.5.13/drivers/usb/storage/transport.h Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/usb/storage/transport.h Wed Mar 27 21:56:43 2002 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Transport Functions Header File * - * $Id: transport.h,v 1.15 2001/03/17 20:06:23 jrmayfield Exp $ + * $Id: transport.h,v 1.17 2002/02/25 00:43:41 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -151,6 +151,6 @@ unsigned int*); extern int usb_stor_control_msg(struct us_data*, unsigned int, u8, u8, u16, u16, void*, u16); +extern int usb_stor_clear_halt(struct us_data*, int ); extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*); -extern int usb_stor_clear_halt(struct usb_device*, int ); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/unusual_devs.h linux-2.5/drivers/usb/storage/unusual_devs.h --- linux-2.5.13/drivers/usb/storage/unusual_devs.h Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/usb/storage/unusual_devs.h Fri May 3 12:57:31 2002 @@ -1,10 +1,10 @@ /* Driver for USB Mass Storage compliant devices * Ununsual Devices File * - * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $ + * $Id: unusual_devs.h,v 1.32 2002/02/25 02:41:24 mdharm Exp $ * * Current development and maintenance by: - * (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Initial work by: * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc. @@ -106,9 +106,31 @@ * 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, + "ScanLogic", + "SL11R-IDE 0049SQFP-1.2 A002", + 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. @@ -198,7 +220,7 @@ /* This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0422, "Sony", - "DSC-S30/S70/S75/505V/F505", + "DSC-S30/S70/S75/505V/F505/F707", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), @@ -223,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 ), @@ -254,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 @@ -289,9 +311,36 @@ "Lexar", "Jumpshot USB CF Reader", US_SC_SCSI, US_PR_JUMPSHOT, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), #endif +/* Reported by Carlos Villegas + * This device needs an INQUIRY of exactly 36-bytes to function. + * That is the only reason this entry is needed. + */ +UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, + "SIIG", + "CompactFlash Card Reader", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + +/* Reported by Peter Marks + * Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly + * 36 bytes of data. No more, no less. That is the only reason this entry + * is needed. + */ +UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, + "EagleTec", + "External Hard Disk", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + +UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0x9999, + "Unknown", + "GL641USB based CF Card reader", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY | US_FL_MODE_XLATE), + UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, "TEAC", "Floppy Drive", @@ -305,13 +354,21 @@ US_FL_SINGLE_LUN | US_FL_START_STOP ), #endif +/* 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 ), + /* 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", @@ -336,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, @@ -351,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, @@ -381,7 +438,7 @@ "Datafab", "MDCFE-B USB CF Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), /* * The following Datafab-based devices may or may not work @@ -398,38 +455,38 @@ "SIIG/Datafab", "SIIG/Datafab Memory Stick+CF Reader/Writer", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff, "Datafab/Unknown", "Datafab-based Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff, "Datafab/Unknown", "Datafab-based Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff, "PNY/Datafab", "PNY/Datafab CF+SM Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff, "Simple Tech/Datafab", "Simple Tech/Datafab CF+SM Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), /* Submitted by Olaf Hering */ UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, "Datafab Systems, Inc.", "USB to CF + SM Combo (LC1)", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), #endif /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant @@ -440,10 +497,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", @@ -451,14 +508,27 @@ US_SC_SCSI, US_PR_CB, NULL, US_FL_MODE_XLATE ), +UNUSUAL_DEV( 0x0a16, 0x8888, 0x0100, 0x0100, + "IBM", + "IBM USB Memory Key", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + #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 */ +UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001, + "Global Channel Solutions", + "EasyDisk EDxxxx", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), + /* Submitted by Brian Hall * Needed for START_STOP flag */ UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, @@ -469,9 +539,12 @@ /* Reported by Dan Pilone * The device needs the flags only. + * Also reported by Brian Hall , again for flags. + * I also suspect this device may have a broken serial number. */ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, "CCYU TECHNOLOGY", "EasyDisk Portable Device", US_SC_SCSI, US_PR_BULK, NULL, US_FL_MODE_XLATE | US_FL_START_STOP), + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/usb.c linux-2.5/drivers/usb/storage/usb.c --- linux-2.5.13/drivers/usb/storage/usb.c Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/usb/storage/usb.c Wed Mar 27 13:07:17 2002 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $ + * $Id: usb.c,v 1.73 2002/01/27 09:02:15 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) @@ -315,6 +315,7 @@ * so get rid of all our resources.. */ daemonize(); + reparent_to_init(); /* avoid getting signals */ spin_lock_irq(¤t->sigmask_lock); @@ -955,6 +956,7 @@ ss->protocol_name = "Unknown"; kfree(ss->current_urb); kfree(ss); + usb_dec_dev_use(dev); return NULL; break; } @@ -962,6 +964,8 @@ /* allocate an IRQ callback if one is needed */ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) { + kfree(ss->current_urb); + kfree(ss); usb_dec_dev_use(dev); return NULL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/usb/storage/usb.h linux-2.5/drivers/usb/storage/usb.h --- linux-2.5.13/drivers/usb/storage/usb.h Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/usb/storage/usb.h Wed Mar 27 17:07:18 2002 @@ -101,6 +101,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 */ #define USB_STOR_STRING_LEN 32 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/Config.help linux-2.5/drivers/video/Config.help --- linux-2.5.13/drivers/video/Config.help Fri May 3 01:22:45 2002 +++ linux-2.5/drivers/video/Config.help Sat Apr 27 00:11:03 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.13/drivers/video/Config.in linux-2.5/drivers/video/Config.in --- linux-2.5.13/drivers/video/Config.in Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/video/Config.in Tue Apr 16 02:15:51 2002 @@ -26,6 +26,9 @@ fi fi fi + if [ "$CONFIG_PCI" = "y" ]; then + tristate ' Permedia3 support (EXPERIMENTAL)' CONFIG_FB_PM3 + fi fi if [ "$CONFIG_ARM" = "y" ]; then dep_bool ' Acorn VIDC support' CONFIG_FB_ACORN $CONFIG_ARCH_ACORN @@ -156,6 +159,7 @@ tristate ' NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC tristate ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX tristate ' 3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1 + tristate ' Trident support (EXPERIMENTAL)' CONFIG_FB_TRIDENT fi fi if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then @@ -265,7 +269,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_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_PM3" = "y" -o "$CONFIG_FB_VIRTUAL" = "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_G364" = "y" -o \ @@ -285,7 +289,7 @@ 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_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_VIRTUAL" = "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_G364" = "m" -o \ @@ -304,7 +308,7 @@ fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ - "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ + "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ "$CONFIG_FB_Q40" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ @@ -320,7 +324,7 @@ 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_VESA" = "m" -o \ + "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ "$CONFIG_FB_Q40" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ @@ -354,19 +358,18 @@ fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ - "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_PM3" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ - "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ + "$CONFIG_FB_VODOO1" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \ - "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \ - "$CONFIG_FB_VOODOO1" = "y" ]; then + "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ - "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ @@ -377,6 +380,16 @@ define_tristate CONFIG_FBCON_CFB32 m fi fi + if [ "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ + "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_HIT" = "y" -o \ + "$CONFIG_FB_HP300" = "y" -o "$CONFIG_FB_Q40" = "y" -o \ + "$CONFIG_FB_ANAKIN" = "y" ]; then + define_tristate CONFIG_FBCON_ACCEL y + else + if [ "$CONFIG_FB_NEOMAGIC" = "m" ]; then + define_tristate CONFIG_FBCON_ACCEL m + fi + fi if [ "$CONFIG_FB_AMIGA" = "y" ]; then define_tristate CONFIG_FBCON_AFB y define_tristate CONFIG_FBCON_ILBM y diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/Makefile linux-2.5/drivers/video/Makefile --- linux-2.5.13/drivers/video/Makefile Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/video/Makefile Sat May 4 11:40:14 2002 @@ -1,5 +1,5 @@ # Makefile for the Linux video drivers. -# 5 Aug 1999, James Simmons, +# 5 Aug 1999, James Simmons, # Rewritten to use lists instead of if-statements. O_TARGET := video.o @@ -10,7 +10,7 @@ # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \ - fbcon-afb.o fbcon-ilbm.o fbgen.o \ + fbcon-afb.o fbcon-ilbm.o fbcon-accel.o \ fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \ fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ @@ -44,8 +44,9 @@ obj-$(CONFIG_FB_ACORN) += acornfb.o 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_Q40) += q40fb.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 @@ -62,18 +63,19 @@ obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o -obj-$(CONFIG_FB_HP300) += hpfb.o +obj-$(CONFIG_FB_HP300) += hpfb.o cfbfillrect.o cfbimgblt.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_CLGEN) += clgenfb.o +obj-$(CONFIG_FB_TRIDENT) += tridentfb.o obj-$(CONFIG_FB_S3TRIO) += S3triofb.o obj-$(CONFIG_FB_TGA) += tgafb.o -obj-$(CONFIG_FB_VESA) += vesafb.o +obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VGA16) += vga16fb.o fbcon-vga-planes.o obj-$(CONFIG_FB_VIRGE) += virgefb.o obj-$(CONFIG_FB_G364) += g364fb.o -obj-$(CONFIG_FB_FM2) += fm2fb.o +obj-$(CONFIG_FB_FM2) += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CREATOR) += creatorfb.o sbusfb.o obj-$(CONFIG_FB_CGSIX) += cgsixfb.o sbusfb.o obj-$(CONFIG_FB_BWTWO) += bwtwofb.o sbusfb.o @@ -111,10 +113,10 @@ obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_BWTWO) += bwtwofb.o -obj-$(CONFIG_FB_HGA) += hgafb.o +obj-$(CONFIG_FB_HGA) += hgafb.o obj-$(CONFIG_FB_SA1100) += sa1100fb.o obj-$(CONFIG_FB_VIRTUAL) += vfb.o -obj-$(CONFIG_FB_HIT) += hitfb.o +obj-$(CONFIG_FB_HIT) += hitfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_E1355) += epson1355fb.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o obj-$(CONFIG_FB_VOODOO1) += sstfb.o @@ -138,6 +140,7 @@ obj-$(CONFIG_FBCON_VGA) += fbcon-vga.o obj-$(CONFIG_FBCON_HGA) += fbcon-hga.o obj-$(CONFIG_FBCON_STI) += fbcon-sti.o +obj-$(CONFIG_FBCON_ACCEL) += fbcon-accel.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/acornfb.c linux-2.5/drivers/video/acornfb.c --- linux-2.5.13/drivers/video/acornfb.c Fri May 3 01:22:50 2002 +++ linux-2.5/drivers/video/acornfb.c Fri May 3 19:03:38 2002 @@ -1119,9 +1119,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.13/drivers/video/anakinfb.c linux-2.5/drivers/video/anakinfb.c --- linux-2.5.13/drivers/video/anakinfb.c Fri May 3 01:22:54 2002 +++ linux-2.5/drivers/video/anakinfb.c Tue Apr 23 10:28:53 2002 @@ -27,19 +27,30 @@ static struct fb_info fb_info; static struct display display; -static int -anakinfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) -{ - if (regno > 15) - return 1; +static struct fb_var_screeninfo anakinfb_var = { + xres: 400, + yres: 234, + xres_virtual: 400, + yres_virtual: 234, + bits_per_pixel: 16, + red: { 11, 5, 0 }, + green: { 5, 6, 0 }, + blue: { 0, 5, 0 }, + activate: FB_ACTIVATE_NOW, + height: -1, + width: -1, + vmode: FB_VMODE_NONINTERLACED, +}; - *red = colreg[regno] & 0xf800; - *green = colreg[regno] & 0x7e0 << 5; - *blue = colreg[regno] & 0x1f << 11; - *transp = 0; - return 0; -} +static struct fb_fix_screeninfo anakinfb_fix = { + id: "AnakinFB", + smem_start: VGA_START, + smem_len: VGA_SIZE, + type: FB_TYPE_PACKED_PIXELS, + visual: FB_VISUAL_TRUECOLOR, + line_length: 400*2, + accel: FB_ACCEL_NONE, +}; static int anakinfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, @@ -53,153 +64,48 @@ return 0; } -static int -anakinfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) -{ - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "AnakinFB"); - fix->smem_start = VGA_START; - fix->smem_len = VGA_SIZE; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - fix->visual = FB_VISUAL_TRUECOLOR; - fix->xpanstep = 0; - fix->ypanstep = 0; - fix->ywrapstep = 0; - fix->line_length = 400 * 2; - fix->accel = FB_ACCEL_NONE; - return 0; -} - -static int -anakinfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) -{ - memset(var, 0, sizeof(struct fb_var_screeninfo)); - var->xres = 400; - var->yres = 234; - var->xres_virtual = 400; - var->yres_virtual = 234; - var->xoffset = 0; - var->yoffset = 0; - var->bits_per_pixel = 16; - var->grayscale = 0; - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - var->nonstd = 0; - var->activate = FB_ACTIVATE_NOW; - var->height = -1; - var->width = -1; - var->pixclock = 0; - var->left_margin = 0; - var->right_margin = 0; - var->upper_margin = 0; - var->lower_margin = 0; - var->hsync_len = 0; - var->vsync_len = 0; - var->sync = 0; - var->vmode = FB_VMODE_NONINTERLACED; - return 0; -} - -static int -anakinfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) -{ - return -EINVAL; -} - -static int -anakinfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - if (con == info->currcon) - return fb_get_cmap(cmap, kspc, anakinfb_getcolreg, info); - else if (fb_display[con].cmap.len) - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else - fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2); - return 0; -} - -static int -anakinfb_switch_con(int con, struct fb_info *info) -{ - info->currcon = con; - return 0; - -} - -static int -anakinfb_updatevar(int con, struct fb_info *info) -{ - return 0; -} - -static void -anakinfb_blank(int blank, struct fb_info *info) -{ - /* - * TODO: use I2C to blank/unblank the screen - */ -} - static struct fb_ops anakinfb_ops = { owner: THIS_MODULE, - fb_get_fix: anakinfb_get_fix, - fb_get_var: anakinfb_get_var, - fb_set_var: anakinfb_set_var, - fb_get_cmap: anakinfb_get_cmap, + fb_get_fix: gen_get_fix, + fb_get_var: gen_get_var, + fb_set_var: gen_set_var, + fb_get_cmap: gen_get_cmap, fb_set_cmap: gen_set_cmap, fb_setcolreg: anakinfb_setcolreg, - fb_blank: anakinfb_blank, + fb_fillrect: cfb_fillrect, + fb_copyarea: cfb_copyarea, + fb_imageblit: cfb_imageblit, }; int __init anakinfb_init(void) { memset(&fb_info, 0, sizeof(struct fb_info)); - strcpy(fb_info.modename, "AnakinFB"); - fb_info.node = NODEV; + memset(&display, 0, sizeof(struct display)); + + strcpy(fb_info.modename, anakinfb_fix.id); + fb_info.node = fb_info.currcon = -1; fb_info.flags = FBINFO_FLAG_DEFAULT; fb_info.fbops = &anakinfb_ops; - fb_info.currcon = -1; + fb_info.var = anakinfb_var; + fb_info.fix = anakinfb_fix; fb_info.disp = &display; strcpy(fb_info.fontname, "VGA8x16"); fb_info.changevar = NULL; - fb_info.switch_con = &anakinfb_switch_con; - fb_info.updatevar = &anakinfb_updatevar; - - memset(&display, 0, sizeof(struct display)); - anakinfb_get_var(&display.var, 0, &fb_info); + fb_info.switch_con = gen_switch_con; + fb_info.updatevar = gen_update_var; if (!(request_mem_region(VGA_START, VGA_SIZE, "vga"))) return -ENOMEM; - if (!(fb_info.screen_base = ioremap(VGA_START, VGA_SIZE))) { + if (fb_info.screen_base = ioremap(VGA_START, VGA_SIZE)) { release_mem_region(VGA_START, VGA_SIZE); return -EIO; } - display.visual = FB_VISUAL_TRUECOLOR; - display.type = FB_TYPE_PACKED_PIXELS; - display.type_aux = 0; - display.ypanstep = 0; - display.ywrapstep = 0; - display.line_length = 400 * 2; - display.can_soft_blank = 1; - display.inverse = 0; - -#ifdef FBCON_HAS_CFB16 - display.dispsw = &fbcon_cfb16; - display.dispsw_data = colreg; -#else - display.dispsw = &fbcon_dummy; -#endif + + fb_alloc_cmap(&fb_info.cmap, 16, 0); + gen_set_disp(-1, &fb_info); if (register_framebuffer(&fb_info) < 0) { - iounmap(fb_info.screen_base); + iounmap(display.screen_base); release_mem_region(VGA_START, VGA_SIZE); return -EINVAL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/atafb.c linux-2.5/drivers/video/atafb.c --- linux-2.5.13/drivers/video/atafb.c Fri May 3 01:22:41 2002 +++ linux-2.5/drivers/video/atafb.c Fri May 3 19:03:38 2002 @@ -1596,7 +1596,7 @@ var->xoffset = up(var->xoffset, 2); } par->hw.falcon.line_offset = bpp * - (fb_display[fb_info.currcon].var.xres_virtual - fb_display[currcon].var.xres) / 16; + (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16; if (par->hw.falcon.xoffset) par->hw.falcon.line_offset -= bpp; xoffset = var->xoffset - par->hw.falcon.xoffset; @@ -2840,8 +2840,8 @@ if (!options || !*options) return 0; - - for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { + + while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; if ((temp=get_video_mode(this_opt))) default_par=temp; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/aty/atyfb.h linux-2.5/drivers/video/aty/atyfb.h --- linux-2.5.13/drivers/video/aty/atyfb.h Fri May 3 01:22:55 2002 +++ linux-2.5/drivers/video/aty/atyfb.h Sun Jan 20 17:34:03 2002 @@ -112,17 +112,6 @@ const struct aty_pll_ops *pll_ops; struct display disp; struct display_switch dispsw; - union { -#ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB24 - u32 cfb24[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u32 cfb32[16]; -#endif - } fbcon_cmap; u8 blitter_may_be_busy; #ifdef __sparc__ u8 mmaped; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/aty/atyfb_base.c linux-2.5/drivers/video/aty/atyfb_base.c --- linux-2.5.13/drivers/video/aty/atyfb_base.c Fri May 3 01:22:42 2002 +++ linux-2.5/drivers/video/aty/atyfb_base.c Fri May 3 19:03:39 2002 @@ -1,3 +1,4 @@ + /* * ATI Frame Buffer Device Driver Core * @@ -87,6 +88,9 @@ #include #include #endif +#ifdef CONFIG_BOOTX_TEXT +#include +#endif #ifdef CONFIG_NVRAM #include #endif @@ -153,8 +157,6 @@ static int atyfb_blank(int blank, struct fb_info *fb); static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); -static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info); #ifdef __sparc__ @@ -227,7 +229,7 @@ fb_get_var: atyfb_get_var, fb_set_var: atyfb_set_var, fb_get_cmap: atyfb_get_cmap, - fb_set_cmap: atyfb_set_cmap, + fb_set_cmap: gen_set_cmap, fb_setcolreg: atyfb_setcolreg, fb_pan_display: atyfb_pan_display, fb_blank: atyfb_blank, @@ -251,7 +253,7 @@ #endif #ifdef CONFIG_PPC -#ifdef CONFIG_NVRAM_NOT_DEFINED +#ifndef CONFIG_NVRAM static int default_vmode __initdata = VMODE_NVRAM; static int default_cmode __initdata = CMODE_NVRAM; #else @@ -267,8 +269,12 @@ static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; #endif +#ifdef CONFIG_FB_ATY_GX static char m64n_gx[] __initdata = "mach64GX (ATI888GX00)"; static char m64n_cx[] __initdata = "mach64CX (ATI888CX00)"; +#endif /* CONFIG_FB_ATY_GX */ + +#ifdef CONFIG_FB_ATY_CT static char m64n_ct[] __initdata = "mach64CT (ATI264CT)"; static char m64n_et[] __initdata = "mach64ET (ATI264ET)"; static char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)"; @@ -291,7 +297,7 @@ static char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)"; static char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)"; static char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)"; - +#endif /* CONFIG_FB_ATY_CT */ static struct { u16 pci_id, chip_type; @@ -353,14 +359,22 @@ #endif /* CONFIG_FB_ATY_CT */ }; +#if defined(CONFIG_FB_ATY_GX) || defined(CONFIG_FB_ATY_CT) static char ram_dram[] __initdata = "DRAM"; +static char ram_resv[] __initdata = "RESV"; +#endif /* CONFIG_FB_ATY_GX || CONFIG_FB_ATY_CT */ + +#ifdef CONFIG_FB_ATY_GX static char ram_vram[] __initdata = "VRAM"; +#endif /* CONFIG_FB_ATY_GX */ + +#ifdef CONFIG_FB_ATY_CT static char ram_edo[] __initdata = "EDO"; static char ram_sdram[] __initdata = "SDRAM"; static char ram_sgram[] __initdata = "SGRAM"; static char ram_wram[] __initdata = "WRAM"; static char ram_off[] __initdata = "OFF"; -static char ram_resv[] __initdata = "RESV"; +#endif /* CONFIG_FB_ATY_CT */ #ifdef CONFIG_FB_ATY_GX static char *aty_gx_ram[8] __initdata = { @@ -376,6 +390,7 @@ }; #endif /* CONFIG_FB_ATY_CT */ +static u32 pseudo_palette[17]; #if defined(CONFIG_PPC) @@ -815,6 +830,13 @@ display_info.disp_reg_address = info->ati_regbase_phys; } #endif /* CONFIG_FB_COMPAT_XPMAC */ +#ifdef CONFIG_BOOTX_TEXT + btext_update_display(info->frame_buffer_phys, + (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8, + ((par->crtc.v_tot_disp>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); +#endif /* CONFIG_BOOTX_TEXT */ } static int atyfb_decode_var(const struct fb_var_screeninfo *var, @@ -918,7 +940,7 @@ fb->mmaped = 0; if (fb->vtconsole != -1) - vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; + vt_cons->vc_cons[fb->vtconsole]->vc_mode = KD_TEXT; fb->vtconsole = -1; if (was_mmaped) { @@ -1046,21 +1068,21 @@ case 16: info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb16; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif #ifdef FBCON_HAS_CFB24 case 24: info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb24; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif #ifdef FBCON_HAS_CFB32 case 32: info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb32; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif default: @@ -1113,7 +1135,6 @@ struct fb_fix_screeninfo fix; encode_fix(&fix, &par, info); - fb->screen_base = (char *)info->frame_buffer; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -1188,33 +1209,6 @@ return 0; } - /* - * Set the Colormap - */ - -static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - int err; - struct display *disp; - - if (con >= 0) - disp = &fb_display[con]; - else - disp = info->disp; - if (!disp->cmap.len) { /* no colormap allocated? */ - int size = disp->var.bits_per_pixel == 16 ? 32 : 256; - if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) - return err; - } - if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ - return fb_set_cmap(cmap, kspc, info); - else - fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); - return 0; -} - - #ifdef DEBUG #define ATYIO_CLKR 0x41545900 /* ATY\00 */ #define ATYIO_CLKW 0x41545901 /* ATY\01 */ @@ -1410,7 +1404,7 @@ fb->mmaped = 1; if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { fb->vtconsole = lastconsole; - vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; + vt_cons->vc_cons[lastconsole]->vc_mode = KD_GRAPHICS; } } return 0; @@ -1634,6 +1628,8 @@ } break; case PBOOK_SLEEP_NOW: + if (info->fb_info.currcon >= 0) + fb_display[info->fb_info.currcon].dispsw = &fbcon_dummy; if (info->blitter_may_be_busy) wait_for_idle(info); /* Stop accel engine (stop bus mastering) */ @@ -1663,7 +1659,11 @@ info->save_framebuffer = 0; } /* Restore display */ - atyfb_set_par(&info->current_par, info); + if (info->fb_info.currcon >= 0) { + atyfb_set_dispsw(&fb_display[info->fb_info.currcon], + info, info->current_par.crtc.bpp, + info->current_par.accel_flags & FB_ACCELF_TEXT); + } atyfb_blank(0, (struct fb_info *)info); break; } @@ -1984,8 +1984,9 @@ strcpy(info->fb_info.modename, atyfb_name); info->fb_info.node = NODEV; info->fb_info.fbops = &atyfb_ops; + info->fb_info.currcon = -1; info->fb_info.disp = disp; - info->fb_info.currcon = -1; + info->fb_info.pseudo_palette = pseudo_palette; strcpy(info->fb_info.fontname, fontname); info->fb_info.changevar = NULL; info->fb_info.switch_con = &atyfbcon_switch; @@ -2016,13 +2017,6 @@ if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) var = default_var; } else { -#ifdef CONFIG_NVRAM - if (default_vmode == VMODE_NVRAM) { - default_vmode = nvram_read_byte(NV_VMODE); - if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_CHOOSE; - } -#endif if (default_vmode == VMODE_CHOOSE) { if (M64_HAS(G3_PB_1024x768)) /* G3 PowerBook with 1024x768 LCD */ @@ -2135,11 +2129,16 @@ return -ENXIO; #else u16 tmp; + int aux_app; + unsigned long raddr; #endif while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) { if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { struct resource *rp; +#ifndef __sparc__ + struct resource *rrp; +#endif for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--) if (pdev->device == aty_chips[i].pci_id) @@ -2176,7 +2175,7 @@ /* * Map in big-endian aperture. */ - info->frame_buffer = (unsigned long) addr + 0x800000UL; + info->fb_info.screen_base = (unsigned long) addr + 0x800000UL; info->frame_buffer_phys = addr + 0x800000UL; /* @@ -2371,9 +2370,19 @@ } #else /* __sparc__ */ - info->ati_regbase_phys = 0x7ff000 + addr; - info->ati_regbase = (unsigned long) - ioremap(info->ati_regbase_phys, 0x1000); + aux_app = 0; + raddr = addr + 0x7ff000UL; + rrp = &pdev->resource[2]; + if ((rrp->flags & IORESOURCE_MEM) + && request_mem_region(rrp->start, rrp->end - rrp->start + 1, + "atyfb")) { + aux_app = 1; + raddr = rrp->start; + printk(KERN_INFO "atyfb: using auxiliary register aperture\n"); + } + + info->ati_regbase_phys = raddr; + info->ati_regbase = (unsigned long) ioremap(raddr, 0x1000); if(!info->ati_regbase) { kfree(info); @@ -2381,8 +2390,8 @@ return -ENOMEM; } - info->ati_regbase_phys += 0xc00; - info->ati_regbase += 0xc00; + info->ati_regbase_phys += aux_app? 0x400: 0xc00; + info->ati_regbase += aux_app? 0x400: 0xc00; /* * Enable memory-space accesses using config-space @@ -2401,9 +2410,9 @@ /* Map in frame buffer */ info->frame_buffer_phys = addr; - info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); + info->fb_info.screen_base = ioremap(addr, 0x800000); - if(!info->frame_buffer) { + if(!info->fb_info.screen_base) { kfree(info); release_mem_region(res_start, res_size); return -ENXIO; @@ -2427,7 +2436,7 @@ * Add /dev/fb mmap values. */ info->mmap_map[0].voff = 0x8000000000000000UL; - info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK; + info->mmap_map[0].poff = info->fb_info.screen_base & PAGE_MASK; info->mmap_map[0].size = info->total_vram; info->mmap_map[0].prot_mask = _PAGE_CACHE; info->mmap_map[0].prot_flag = _PAGE_E; @@ -2476,7 +2485,7 @@ * Map the video memory (physical address given) to somewhere in the * kernel address space. */ - info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); + info->fb_info.screen_base = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); info->frame_buffer_phys = info->frame_buffer; /* Fake! */ info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul; info->ati_regbase_phys = info->ati_regbase; /* Fake! */ @@ -2518,6 +2527,8 @@ return 0; while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; if (!strncmp(this_opt, "font:", 5)) { char *p; int i; @@ -2625,7 +2636,7 @@ #ifdef CONFIG_FB_ATY_CT /* Erase HW Cursor */ - if (info->cursor && (fb->currcon >= 0)) + if (info->cursor) atyfb_cursor(&fb_display[fb->currcon], CM_ERASE, info->cursor->pos.x, info->cursor->pos.y); #endif /* CONFIG_FB_ATY_CT */ @@ -2746,20 +2757,19 @@ switch (info->current_par.crtc.bpp) { #ifdef FBCON_HAS_CFB16 case 16: - info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | - regno; + ((u16 *)(info->fb_info.pseudo_palette))[regno] = (regno << 10) | (regno << 5) | regno; break; #endif #ifdef FBCON_HAS_CFB24 case 24: - info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | - regno; + ((u32 *)(info->fb_info.pseudo_palette))[regno] = (regno << 16) | (regno << 8) | regno; break; #endif #ifdef FBCON_HAS_CFB32 case 32: i = (regno << 8) | regno; - info->fbcon_cmap.cfb32[regno] = (i << 16) | i; + + ((u32 *)(info->fb_info.pseudo_palette))[regno] = (i << 16) | i; break; #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/aty/mach64_cursor.c linux-2.5/drivers/video/aty/mach64_cursor.c --- linux-2.5.13/drivers/video/aty/mach64_cursor.c Fri May 3 01:22:57 2002 +++ linux-2.5/drivers/video/aty/mach64_cursor.c Sat Jan 26 00:14:25 2002 @@ -246,14 +246,14 @@ cursor->offset = fb->total_vram; #ifdef __sparc__ - addr = fb->frame_buffer - 0x800000 + cursor->offset; + addr =(unsigned long) fb->fb_info.screen_base - 0x800000 + cursor->offset; cursor->ram = (u8 *)addr; #else #ifdef __BIG_ENDIAN addr = fb->frame_buffer_phys - 0x800000 + cursor->offset; cursor->ram = (u8 *)ioremap(addr, 1024); #else - addr = fb->frame_buffer + cursor->offset; + addr =(unsigned long) fb->fb_info.screen_base + cursor->offset; cursor->ram = (u8 *)addr; #endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/aty128.h linux-2.5/drivers/video/aty128.h --- linux-2.5.13/drivers/video/aty128.h Fri May 3 01:22:51 2002 +++ linux-2.5/drivers/video/aty128.h Tue Jan 8 01:17:10 2002 @@ -13,6 +13,7 @@ #define CLOCK_CNTL_DATA 0x000c #define BIOS_0_SCRATCH 0x0010 #define BUS_CNTL 0x0030 +#define BUS_CNTL1 0x0034 #define GEN_INT_CNTL 0x0040 #define CRTC_GEN_CNTL 0x0050 #define CRTC_EXT_CNTL 0x0054 @@ -24,6 +25,7 @@ #define GEN_RESET_CNTL 0x00f0 #define CONFIG_MEMSIZE 0x00f8 #define MEM_CNTL 0x0140 +#define MEM_POWER_MISC 0x015c #define AGP_BASE 0x0170 #define AGP_CNTL 0x0174 #define AGP_APER_OFFSET 0x0178 @@ -37,6 +39,9 @@ #define CRTC_H_SYNC_STRT_WID 0x0204 #define CRTC_V_TOTAL_DISP 0x0208 #define CRTC_V_SYNC_STRT_WID 0x020c +#define CRTC_VLINE_CRNT_VLINE 0x0210 +#define CRTC_CRNT_FRAME 0x0214 +#define CRTC_GUI_TRIG_VLINE 0x0218 #define CRTC_OFFSET 0x0224 #define CRTC_OFFSET_CNTL 0x0228 #define CRTC_PITCH 0x022c @@ -48,6 +53,20 @@ #define DDA_ON_OFF 0x02e4 #define VGA_DDA_CONFIG 0x02e8 #define VGA_DDA_ON_OFF 0x02ec +#define CRTC2_H_TOTAL_DISP 0x0300 +#define CRTC2_H_SYNC_STRT_WID 0x0304 +#define CRTC2_V_TOTAL_DISP 0x0308 +#define CRTC2_V_SYNC_STRT_WID 0x030c +#define CRTC2_VLINE_CRNT_VLINE 0x0310 +#define CRTC2_CRNT_FRAME 0x0314 +#define CRTC2_GUI_TRIG_VLINE 0x0318 +#define CRTC2_OFFSET 0x0324 +#define CRTC2_OFFSET_CNTL 0x0328 +#define CRTC2_PITCH 0x032c +#define DDA2_CONFIG 0x03e0 +#define DDA2_ON_OFF 0x03e4 +#define CRTC2_GEN_CNTL 0x03f8 +#define CRTC2_STATUS 0x03fc #define OV0_SCALE_CNTL 0x0420 #define SUBPIC_CNTL 0x0540 #define PM4_BUFFER_OFFSET 0x0700 @@ -237,6 +256,10 @@ #define AGP_PLL_CNTL 0x0010 #define FCP_CNTL 0x0012 #define PLL_TEST_CNTL 0x0013 +#define P2PLL_CNTL 0x002a +#define P2PLL_REF_DIV 0x002b +#define P2PLL_DIV_0 0x002b +#define POWER_MANAGEMENT 0x002f #define PPLL_RESET 0x01 #define PPLL_ATOMIC_UPDATE_EN 0x10000 @@ -254,6 +277,14 @@ /* CRTC control values (CRTC_GEN_CNTL) */ #define CRTC_CSYNC_EN 0x00000010 +#define CRTC2_DBL_SCAN_EN 0x00000001 +#define CRTC2_DISPLAY_DIS 0x00800000 +#define CRTC2_FIFO_EXTSENSE 0x00200000 +#define CRTC2_ICON_EN 0x00100000 +#define CRTC2_CUR_EN 0x00010000 +#define CRTC2_EN 0x02000000 +#define CRTC2_DISP_REQ_EN_B 0x04000000 + #define CRTC_PIX_WIDTH_MASK 0x00000700 #define CRTC_PIX_WIDTH_4BPP 0x00000100 #define CRTC_PIX_WIDTH_8BPP 0x00000200 @@ -267,10 +298,14 @@ #define DAC_MASK 0xFF000000 #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 -#define DAC_RANGE_CNTL 0x00000003 +#define DAC_CLK_SEL 0x00000010 #define DAC_PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PALETTE2_SNOOP_EN 0x00000040 #define DAC_PDWN 0x00008000 +/* CRTC_EXT_CNTL */ +#define CRT_CRTC_ON 0x00008000 + /* GEN_RESET_CNTL bit constants */ #define SOFT_RESET_GUI 0x00000001 #define SOFT_RESET_VCLK 0x00000100 @@ -348,5 +383,37 @@ #define LVDS_BL_MOD_EN 0x00010000 #define LVDS_DIGION 0x00040000 #define LVDS_BLON 0x00080000 +#define LVDS_ON 0x00000001 +#define LVDS_DISPLAY_DIS 0x00000002 +#define LVDS_PANEL_TYPE_2PIX_PER_CLK 0x00000004 +#define LVDS_PANEL_24BITS_TFT 0x00000008 +#define LVDS_FRAME_MOD_NO 0x00000000 +#define LVDS_FRAME_MOD_2_LEVELS 0x00000010 +#define LVDS_FRAME_MOD_4_LEVELS 0x00000020 +#define LVDS_RST_FM 0x00000040 +#define LVDS_EN 0x00000080 + +/* CRTC2_GEN_CNTL constants */ +#define CRTC2_EN 0x02000000 + +/* POWER_MANAGEMENT constants */ +#define PWR_MGT_ON 0x00000001 +#define PWR_MGT_MODE_MASK 0x00000006 +#define PWR_MGT_MODE_PIN 0x00000000 +#define PWR_MGT_MODE_REGISTER 0x00000002 +#define PWR_MGT_MODE_TIMER 0x00000004 +#define PWR_MGT_MODE_PCI 0x00000006 +#define PWR_MGT_AUTO_PWR_UP_EN 0x00000008 +#define PWR_MGT_ACTIVITY_PIN_ON 0x00000010 +#define PWR_MGT_STANDBY_POL 0x00000020 +#define PWR_MGT_SUSPEND_POL 0x00000040 +#define PWR_MGT_SELF_REFRESH 0x00000080 +#define PWR_MGT_ACTIVITY_PIN_EN 0x00000100 +#define PWR_MGT_KEYBD_SNOOP 0x00000200 +#define PWR_MGT_TRISTATE_MEM_EN 0x00000800 +#define PWR_MGT_SELW4MS 0x00001000 +#define PWR_MGT_SLOWDOWN_MCLK 0x00002000 + +#define PMI_PMSCR_REG 0x60 #endif /* REG_RAGE128_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.13/drivers/video/aty128fb.c linux-2.5/drivers/video/aty128fb.c --- linux-2.5.13/drivers/video/aty128fb.c Fri May 3 01:22:53 2002 +++ linux-2.5/drivers/video/aty128fb.c Fri May 3 19:03:38 2002 @@ -7,13 +7,19 @@ * Ani Joshi / Jeff Garzik * - Code cleanup * + * Michel Dänzer + * - 15/16 bit cleanup + * - fix panning + * + * Benjamin Herrenschmidt + * - pmac-specific PM stuff + * * Andreas Hundt * - FB_ACTIVATE fixes * * Based off of Geert's atyfb.c and vfb.c. * * TODO: - * - panning * - monitor sensing (DDC) * - virtual display * - other platform support (only ppc/x86 supported) @@ -70,6 +76,9 @@ #ifdef CONFIG_FB_COMPAT_XPMAC #include #endif +#ifdef CONFIG_BOOTX_TEXT +#include +#endif /* CONFIG_BOOTX_TEXT */ #include