diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/Changes linux-2.5/Documentation/Changes --- linux-2.5.23/Documentation/Changes Wed Jun 19 03:11:58 2002 +++ linux-2.5/Documentation/Changes Tue Jun 4 00:29:15 2002 @@ -77,11 +77,13 @@ have not received much testing for Linux kernel compilation, and there are almost certainly bugs (mainly, but not exclusively, in the kernel) that will need to be fixed in order to use these compilers. In any case, using -pgcc instead of plain gcc is just asking for trouble. +pgcc instead of egcs or plain gcc is just asking for trouble. -Note that gcc 2.7.2.3 and gcc 2.91.66 (egcs-1.1.2) are no longer supported -kernel compilers. The kernel no longer works around bugs in these versions, -and, in fact, will refuse to be compiled with it. +Note that gcc 2.7.2.3 is no longer a supported kernel compiler. The kernel +no longer works around bugs in gcc 2.7.2.3 and, in fact, will refuse to +be compiled with it. egcs-1.1.2 has register allocation problems in very +obscure cases. We have ensured the kernel does not trip these in any known +situation. The 2.5 tree is likely to drop egcs-1.1.2 workarounds. The Red Hat gcc 2.96 compiler subtree can also be used to build this tree. You should ensure you use gcc-2.96-74 or later. gcc-2.96-54 will not build @@ -272,6 +274,10 @@ Kernel compilation ****************** + +egcs 1.1.2 (gcc 2.91.66) +------------------------ +o gcc 2.95.3 ---------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/DocBook/Makefile linux-2.5/Documentation/DocBook/Makefile --- linux-2.5.23/Documentation/DocBook/Makefile Wed Jun 19 03:11:54 2002 +++ linux-2.5/Documentation/DocBook/Makefile Wed Jun 12 03:01:47 2002 @@ -32,6 +32,8 @@ htmldocs: $(HTML) +man: kernel-api-man + %.eps: %.fig fig2dev -Leps $< $@ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/DocBook/kernel-api.tmpl linux-2.5/Documentation/DocBook/kernel-api.tmpl --- linux-2.5.23/Documentation/DocBook/kernel-api.tmpl Wed Jun 19 03:11:45 2002 +++ linux-2.5/Documentation/DocBook/kernel-api.tmpl Tue Jun 4 20:15:04 2002 @@ -48,6 +48,12 @@ Delaying, scheduling, and timer routines !Ekernel/sched.c +!Ekernel/context.c +!Ekernel/timer.c + + + Misc functions +!Ekernel/exit.c @@ -358,7 +364,7 @@ !Edrivers/video/fbcmap.c Frame Buffer Generic Functions -!Idrivers/video/fbgen.c +!Edrivers/video/fbgen.c Frame Buffer Video Mode Database !Idrivers/video/modedb.c diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/DocBook/sis900.tmpl linux-2.5/Documentation/DocBook/sis900.tmpl --- linux-2.5.23/Documentation/DocBook/sis900.tmpl Wed Jun 19 03:11:45 2002 +++ linux-2.5/Documentation/DocBook/sis900.tmpl Tue Jun 4 15:45:28 2002 @@ -323,8 +323,8 @@ The 1.06 revision can be found in kernel version later than 2.3.15 and pre-2.2.14, and 1.07 revision can be found in kernel version 2.4.0. If you have no prior experience in networking under Linux, please read -Ethernet HOWTO and -Networking HOWTO available from +Ethernet HOWTO and +Networking HOWTO available from Linux Documentation Project (LDP). @@ -435,7 +435,7 @@ Typical values are "10baseT"(twisted-pair 10Mbps Ethernet) or "100baseT" (twisted-pair 100Mbps Ethernet). For more information on how to configure network interface, please refer to -Networking HOWTO. +Networking HOWTO. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/arm/README linux-2.5/Documentation/arm/README --- linux-2.5.23/Documentation/arm/README Wed Jun 19 03:11:52 2002 +++ linux-2.5/Documentation/arm/README Wed May 8 14:50:36 2002 @@ -7,8 +7,8 @@ --------------------- In order to compile ARM Linux, you will need a compiler capable of - generating ARM ELF code with GNU extensions. GCC 2.95.1 and EGCS 1.1.2 - are good compilers. + generating ARM ELF code with GNU extensions. GCC 2.95.3 is a good + compiler. To build ARM Linux natively, you shouldn't have to alter the ARCH = line in the top level Makefile. However, if you don't have the ARM Linux ELF diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/fb/README-sstfb.txt linux-2.5/Documentation/fb/README-sstfb.txt --- linux-2.5.23/Documentation/fb/README-sstfb.txt Wed Jun 19 03:11:49 2002 +++ linux-2.5/Documentation/fb/README-sstfb.txt Fri Jun 7 02:36:08 2002 @@ -9,12 +9,12 @@ combinations and it seems that it works. The main page is located at , and if you want the latest version, check out the CVS, as the driver is a work - in progress, i feel incomfortable with releasing tarballs of something + in progress, I feel uncomfortable with releasing tarballs of something not completely working...Don't worry, it's still more than useable (I eat my own dog food) Please read the Bug section, and report any success or failure to me - (Ghozlane Toumi ). + (Ghozlane Toumi ). BTW, If you have only one monitor , and you don't feel like playing with the vga passthrou cable, I can only suggest borrowing a screen somewhere... @@ -22,8 +22,9 @@ Installation - This driver (should) work on ix86, with any 2.2.x kernel (tested + This driver (should) work on ix86, with "late" 2.2.x kernel (tested with x = 19) and "recent" 2.4.x kernel, as a module or compiled in. + It has been included in mainstream kernel since the infamous 2.4.10. You can apply the patches found in sstfb/kernel/*-2.{2|4}.x.patch, and copy sstfb.c to linux/drivers/video/, or apply a single patch, sstfb/patch-2.{2|4}.x-sstfb-yymmdd to your linux source tree. @@ -41,7 +42,7 @@ module, the 3dfx takes control of the output, so you'll have to plug the monitor to the "normal" video board in order to issue the commands, or you can blindly use sst_dbg_vgapass - in the tools directory (See Tools). The latest option is pass the + in the tools directory (See Tools). The latest solution is pass the parameter vgapass=1 when insmodding the driver. (See Kernel/Modules Options) @@ -77,36 +78,39 @@ in kernel : video=sstfb:option1,option2:value2,option3 ... sstfb supports the folowing options : - module kernel description - vgapass=1 vgapass enable or disable VGA passthrou cable - vgapass=0 vganopass when enabled, the monitor will - get the signal from the VGA board - and not from the voodoo. default nopass - - mem=x mem:x force frame buffer memory in MiB - allowed values: 1, 2, 4. default detect - - inverse=1 inverse suposed to enable inverse console. - doesn't work ... - - clipping=1 clipping enable or disable clipping . with - clipping=0 noclipping clipping enabled, all offscreen reads - and writes are disgarded. default: - enable clipping. - - gfxclk=x gfxclk:x force graphic clock frequency (in MHz) - becarefull with this option . - default is 50Mhz for voodoo1, 75MHz - for voodoo2. Be carefull, this one is - dangerous. default=auto - - slowpci=0 slowpci enable or disable fast PCI read/writes - slowpci=1 fastpci default : fastpci - - dev=x dev:x attach the driver to device number x - 0 is the first compatible board (in - lspci order) +Module Kernel Description + +vgapass=0 vganopass Enable or disable VGA passthrou cable. +vgapass=1 vgapass When enabled, the monitor will get the signal + from the VGA board and not from the voodoo. + Default: nopass + +mem=x mem:x Force frame buffer memory in MiB + allowed values: 0, 1, 2, 4. + Default: 0 (= autodetect) + +inverse=1 inverse Supposed to enable inverse console. + doesn't work yet... + +clipping=1 clipping Enable or disable clipping. +clipping=0 noclipping With clipping enabled, all offscreen + reads and writes are disgarded. + Default: enable clipping. + +gfxclk=x gfxclk:x Force graphic clock frequency (in MHz). + Be carefull with this option, it may be + DANGEROUS. + Default: auto + 50Mhz for Voodoo 1, + 75MHz for Voodoo 2. + +slowpci=1 fastpci Enable or disable fast PCI read/writes. +slowpci=1 slowpci Default : fastpci + +dev=x dev:x Attach the driver to device number x. + 0 is the first compatible board (in + lspci order) Tools @@ -126,8 +130,8 @@ - DO NOT use glide while the sstfb module is in, you'll most likely hang your computer. - - if you see some artefacts (pixels not cleaning and stuff like that), - try turning off clipping (clipping=0) + - If you see some artefacts (pixels not cleaning and stuff like that), + try turning off clipping (clipping=0), and/or using slowpci - the driver don't detect the 4Mb frame buffer voodoos, it seems that the 2 last Mbs wrap around. looking into that . - The driver is 16 bpp only, 24/32 won't work. @@ -137,8 +141,8 @@ patterns at the border of your windows (the pixels loose the lowest byte -> basicaly the blue component nd some of the green) . I'm unable to reproduce this with XFree86-3.3, but one of the testers has this - problem with XFree86-4. I don't know yet if this is the drivers fault - or X's (most likely the driver, of course). + problem with XFree86-4. apparently recent Xfree86-4.x solve this + problem. - I didn't really test changing the palette, so you may find some weird things when playing with that. - Sometimes the driver will not recognise the DAC , and the @@ -147,6 +151,9 @@ contact me . - the 24/32 is not likely to work anytime soon , knowing that the hardware does ... unusual thigs in 24/32 bpp + - When used with anther video board, current limitations of linux + console subsystem can cause some troubles, specificaly, you should + disable software scrollback , as it can oops badly ... Todo @@ -154,14 +161,14 @@ - Buy more coffee. - test/port to other arch. - try to add panning using tweeks with front and back buffer . - - try to implement accel en voodoo2 , this board can actualy do a + - try to implement accel on voodoo2 , this board can actualy do a lot in 2D even if it was sold as a 3D only board ... ghoz. -- -Ghozlane Toumi +Ghozlane Toumi -$Date: 2001/08/29 00:21:11 $ +$Date: 2002/05/09 20:11:45 $ http://sstfb.sourceforge.net/README diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/fb/tridentfb.txt linux-2.5/Documentation/fb/tridentfb.txt --- linux-2.5.23/Documentation/fb/tridentfb.txt Wed Jun 19 03:11:50 2002 +++ linux-2.5/Documentation/fb/tridentfb.txt Fri Jun 7 02:36:08 2002 @@ -42,8 +42,14 @@ bpp - bits per pixel (8,16 or 32) mode - a mode name like 800x600 (as described in Documentation/fb/modedb.txt) +Example: +video=trident:memsize=2048,800x600 + 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 +If you have trouble with the driver you could check http://sf.net/projects/tridentfb +to see if there's a newer version available. + +Contact: jani@iv.ro diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/filesystems/fat_cvf.txt linux-2.5/Documentation/filesystems/fat_cvf.txt --- linux-2.5.23/Documentation/filesystems/fat_cvf.txt Wed Jun 19 03:11:49 2002 +++ linux-2.5/Documentation/filesystems/fat_cvf.txt Thu Jan 1 01:00:00 1970 @@ -1,210 +0,0 @@ -This is the main documentation for the CVF-FAT filesystem extension. 18Nov1998 - - -Table of Contents: - -1. The idea of CVF-FAT -2. Restrictions -3. Mount options -4. Description of the CVF-FAT interface -5. CVF Modules - ------------------------------------------------------------------------------- - - -1. The idea of CVF-FAT ------------------------------------------------------------------------------- - -CVF-FAT is a FAT filesystem extension that provides a generic interface for -Compressed Volume Files in FAT partitions. Popular CVF software, for -example, are Microsoft's Doublespace/Drivespace and Stac's Stacker. -Using the CVF-FAT interface, it is possible to load a module that handles -all the low-level disk access that has to do with on-the-fly compression -and decompression. Any other part of FAT filesystem access is still handled -by the FAT, MSDOS or VFAT or even UMSDOS driver. - -CVF access works by redirecting certain low-level routines from the FAT -driver to a loadable, CVF-format specific module. This module must fake -a normal FAT filesystem to the FAT driver while doing all the extra stuff -like compression and decompression silently. - - -2. Restrictions ------------------------------------------------------------------------------- - -- BMAP problems - - CVF filesystems cannot do bmap. It's impossible in principle. Thus - all actions that require bmap do not work (swapping, writable mmapping). - Read-only mmapping works because the FAT driver has a hack for this - situation :) Well, writable mmapping should now work using the readpage - interface function which has been hacked into the FAT driver just for - CVF-FAT :) - -- attention, DOSEmu users - - You may have to unmount all CVF partitions before running DOSEmu depending - on your configuration. If DOSEmu is configured to use wholedisk or - partition access (this is often the case to let DOSEmu access - compressed partitions) there's a risk of destroying your compressed - partitions or crashing your system because of confused drivers. - - Note that it is always safe to redirect the compressed partitions with - lredir or emufs.sys. Refer to the DOSEmu documentation for details. - - -3. Mount options ------------------------------------------------------------------------------- - -The CVF-FAT extension currently adds the following options to the FAT -driver's standard options: - - cvf_format=xxx - Forces the driver to use the CVF module "xxx" instead of auto-detection. - Without this option, the CVF-FAT interface asks all currently loaded - CVF modules whether they recognize the CVF. Therefore, this option is - only necessary if the CVF format is not recognized correctly - because of bugs or incompatibilities in the CVF modules. (It skips - the detect_cvf call.) "xxx" may be the text "none" (without the quotes) - to inhibit using any of the loaded CVF modules, just in case a CVF - module insists on mounting plain FAT filesystems by misunderstanding. - "xxx" may also be the text "autoload", which has a special meaning for - a module loader, but does not skip auto-detection. - - If the kernel supports kmod, the cvf_format=xxx option also controls - on-demand CVF module loading. Without this option, nothing is loaded - on demand. With cvf_format=xxx, a module "xxx" is requested automatically - before mounting the compressed filesystem (unless "xxx" is "none"). In - case there is a difference between the CVF format name and the module - name, setup aliases in your modules configuration. If the string "xxx" - is "autoload", a non-existent module "cvf_autoload" is requested which - can be used together with a special modules configuration (alias and - pre-install statements) in order to load more than one CVF module, let - them detect automatically which kind of CVF is to be mounted, and only - keep the "right" module in memory. For examples please refer to the - dmsdos documentation (ftp and http addresses see below). - - cvf_options=yyy - Option string passed to the CVF module. I.e. only the "yyy" is passed - (without the quotes). The documentation for each CVF module should - explain it since it is interpreted only by the CVF module. Note that - the string must not contain a comma (",") - this would lead to - misinterpretation by the FAT driver, which would recognize the text - after a comma as a FAT driver option and might get confused or print - strange error messages. The documentation for the CVF module should - offer a different separation symbol, for example the dot "." or the - plus sign "+", which is only valid inside the string "yyy". - - -4. Description of the CVF-FAT interface ------------------------------------------------------------------------------- - -Assuming you want to write your own CVF module, you need to write a lot of -interface functions. Most of them are covered in the kernel documentation -you can find on the net, and thus won't be described here. They have been -marked with "[...]" :-) Take a look at include/linux/fat_cvf.h. - -struct cvf_format -{ int cvf_version; - char* cvf_version_text; - unsigned long int flags; - int (*detect_cvf) (struct super_block*sb); - int (*mount_cvf) (struct super_block*sb,char*options); - int (*unmount_cvf) (struct super_block*sb); - [...] - void (*zero_out_cluster) (struct inode*, int clusternr); -} - -This structure defines the capabilities of a CVF module. It must be filled -out completely by a CVF module. Consider it as a kind of form that is used -to introduce the module to the FAT/CVF-FAT driver. - -It contains... - - cvf_version: - A version id which must be unique. Choose one. - - cvf_version_text: - A human readable version string that should be one short word - describing the CVF format the module implements. This text is used - for the cvf_format option. This name must also be unique. - - flags: - Bit coded flags, currently only used for a readpage/mmap hack that - provides both mmap and readpage functionality. If CVF_USE_READPAGE - is set, mmap is set to generic_file_mmap and readpage is caught - and redirected to the cvf_readpage function. If it is not set, - readpage is set to generic_readpage and mmap is caught and redirected - to cvf_mmap. (If you want writable mmap use the readpage interface.) - - detect_cvf: - A function that is called to decide whether the filesystem is a CVF of - the type the module supports. The detect_cvf function must return 0 - for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS - THE KIND OF CVF I SUPPORT". The function must maintain the module - usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning - and MOD_DEC_USE_COUNT at the end. The function *must not* assume that - successful recognition would lead to a call of the mount_cvf function - later. - - mount_cvf: - A function that sets up some values or initializes something additional - to what has to be done when a CVF is mounted. This is called at the - end of fat_read_super and must return 0 on success. Definitely, this - function must increment the module usage counter by MOD_INC_USE_COUNT. - This mount_cvf function is also responsible for interpreting a CVF - module specific option string (the "yyy" from the FAT mount option - "cvf_options=yyy") which cannot contain a comma (use for example the - dot "." as option separator symbol). - - unmount_cvf: - A function that is called when the filesystem is unmounted. Most likely - it only frees up some memory and calls MOD_DEC_USE_COUNT. The return - value might be ignored (it currently is ignored). - - [...]: - All other interface functions are "caught" FAT driver functions, i.e. - are executed by the FAT driver *instead* of the original FAT driver - functions. NULL means use the original FAT driver functions instead. - If you really want "no action", write a function that does nothing and - hang it in instead. - - zero_out_cluster: - The zero_out_cluster function is called when the fat driver wants to - zero out a (new) cluster. This is important for directories (mkdir). - If it is NULL, the FAT driver defaults to overwriting the whole - cluster with zeros. Note that clusternr is absolute, not relative - to the provided inode. - -Notes: - 1. The cvf_bmap function should be ignored. It really should never - get called from somewhere. I recommend redirecting it to a panic - or fatal error message so bugs show up immediately. - 2. The cvf_writepage function is ignored. This is because the fat - driver doesn't support it. This might change in future. I recommend - setting it to NULL (i.e use default). - -int register_cvf_format(struct cvf_format*cvf_format); - If you have just set up a variable containing the above structure, - call this function to introduce your CVF format to the FAT/CVF-FAT - driver. This is usually done in init_module. Be sure to check the - return value. Zero means success, everything else causes a kernel - message printed in the syslog describing the error that occurred. - Typical errors are: - - a module with the same version id is already registered or - - too many CVF formats. Hack fs/fat/cvf.c if you need more. - -int unregister_cvf_format(struct cvf_format*cvf_format); - This is usually called in cleanup_module. Return value =0 means - success. An error only occurs if you try to unregister a CVF format - that has not been previously registered. The code uses the version id - to distinguish the modules, so be sure to keep it unique. - -5. CVF Modules ------------------------------------------------------------------------------- - -Refer to the dmsdos module (the successor of the dmsdos filesystem) for a -sample implementation. It can currently be found at - - ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz - ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz - ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz - -(where x.y.z is to be replaced with the actual version number). Full -documentation about dmsdos is included in the dmsdos package, but can also -be found at - - http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html - http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese). diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/isapnp.txt linux-2.5/Documentation/isapnp.txt --- linux-2.5.23/Documentation/isapnp.txt Wed Jun 19 03:11:59 2002 +++ linux-2.5/Documentation/isapnp.txt Tue Jun 18 16:43:25 2002 @@ -29,6 +29,7 @@ poke - poke configuration byte to selected register pokew - poke configuration word to selected register poked - poke configuration dword to selected register +allow_dma0 - allow dma channel 0 during auto activation: 0=off, 1=on Explanation: - variable begins with zero diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/kbuild/random.txt linux-2.5/Documentation/kbuild/random.txt --- linux-2.5.23/Documentation/kbuild/random.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/Documentation/kbuild/random.txt Tue Jun 4 23:25:23 2002 @@ -0,0 +1,47 @@ +Code by Ghozlane Toumi , documentation by +Keith Owens + +In addition to the normal config targets you can make + + randconfig random configuration. + + allyes reply 'y' to all options, maximal kernel. + + allno reply 'n' to all options, minimal kernel. + + allmod build everything as modules where possible. + + +All random configurations will satisfy the config rules, that is, all +configurations should be valid. Any build errors indicate bugs in the +config dependency rules or in the Makefiles. + +You can constrain the random configuration, e.g. you may want to force +the use of modules or the absence of /proc or cramfs must be a module. +If file .force_default exists then it is read to preset selected +values, all other values will be randomly selected, subject to the +config rules. The syntax of .force_default is: + +CONFIG_foo=value + Force this value, for example CONFIG_MODULES=y, CONFIG_PROC_FS=n, + CONFIG_RAMFS=m. + +# CONFIG_foo is not set + Equivalent to CONFIG_foo=n, supported because this is the format used + in .config. NOTE: The leading '#' is required. + +# list CONFIG_foo val1,val2,val3 + Pick a value for CONFIG_foo from the list. CONFIG_foo must be an int + or hex option. NOTE: The leading '#' is required. + +# range CONFIG_foo min max + Pick a value for CONFIG_foo in the range min <=> max. CONFIG_foo + must be an int option. NOTE: The leading '#' is required. + +If you have repeated settings of the same option in .force_default then +values take precedence over lists which take precedence over range. +Within each group the last setting for an option is used. + +Answers "randomised" are bool(), tristate(), dep_tristate() and +choice(). Unless specified in .force_default, int, hex, and string +options use the default values from config.in. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/kernel-doc-nano-HOWTO.txt linux-2.5/Documentation/kernel-doc-nano-HOWTO.txt --- linux-2.5.23/Documentation/kernel-doc-nano-HOWTO.txt Wed Jun 19 03:11:54 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.23/Documentation/kernel-docs.txt linux-2.5/Documentation/kernel-docs.txt --- linux-2.5.23/Documentation/kernel-docs.txt Wed Jun 19 03:11:56 2002 +++ linux-2.5/Documentation/kernel-docs.txt Tue Jun 4 15:45:28 2002 @@ -41,7 +41,7 @@ * Title: "The Linux Kernel" Author: David A. Rusling. - URL: http://www.linuxdoc.org/LDP/tlk/tlk.html + URL: http://www.tldp.org/LDP/tlk/tlk.html Keywords: everything!, book. Description: On line, 200 pages book describing most aspects of the Linux Kernel. Probably, the first reference for beginners. @@ -57,7 +57,7 @@ * Title: "The Linux Kernel Hackers' Guide" Author: Michael K.Johnson and others. - URL: http://www.linuxdoc.org/LDP/khg/HyperNews/get/khg.html + URL: http://www.tldp.org/LDP/khg/HyperNews/get/khg.html Keywords: everything! Description: No more Postscript book-like version. Only HTML now. Many people have contributed. The interface is similar to web @@ -277,7 +277,7 @@ * Title: "Linux Kernel Module Programming Guide" Author: Ori Pomerantz. - URL: http://www.linuxdoc.org/LDP/lkmpg/mpg.html + URL: http://www.tldp.org/LDP/lkmpg/mpg.html Keywords: modules, GPL book, /proc, ioctls, system calls, interrupt handlers . Description: Very nice 92 pages GPL book on the topic of modules diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/kernel-parameters.txt linux-2.5/Documentation/kernel-parameters.txt --- linux-2.5.23/Documentation/kernel-parameters.txt Wed Jun 19 03:11:55 2002 +++ linux-2.5/Documentation/kernel-parameters.txt Sat Jun 1 00:34:32 2002 @@ -127,7 +127,7 @@ BusLogic= [HW,SCSI] - cachesize= [BUGS=ix86] Override level 2 CPU cache size detection. + cachesize= [BUGS=IA-32] Override level 2 CPU cache size detection. Sometimes CPU hardware bugs make them report the cache size incorrectly. The kernel will attempt work arounds to fix known problems, but for some CPUs it is not @@ -319,8 +319,6 @@ max_scsi_luns= [SCSI] - mca-pentium [BUGS=ix86] - mcd= [HW,CD] mcdx= [HW,CD] @@ -339,6 +337,9 @@ memfrac= [KNL] + mem=nopentium [BUGS=IA-32] Disable usage of 4MB pages for kernel + memory. + mga= [HW,DRM] mpu401= [HW,SOUND] @@ -365,9 +366,9 @@ nfsroot= [NFS] nfs root filesystem for disk-less boxes. - nmi_watchdog= [KNL,BUGS=ix86] debugging features for SMP kernels. + nmi_watchdog= [KNL,BUGS=IA-32] debugging features for SMP kernels. - no387 [BUGS=ix86] Tells the kernel to use the 387 maths + no387 [BUGS=IA-32] Tells the kernel to use the 387 maths emulation library even if a 387 maths coprocessor is present. @@ -385,7 +386,9 @@ nohlt [BUGS=ARM] - no-hlt [BUGS=ix86] + no-hlt [BUGS=IA-32] + + noht [SMP,IA-32] Disables P4 Xeon(tm) HyperThreading. noisapnp [ISAPNP] Disables ISA PnP code. @@ -402,7 +405,7 @@ nosync [HW, M68K] Disables sync negotiation for all devices. - notsc [BUGS=ix86] Disable Time Stamp Counter + notsc [BUGS=IA-32] Disable Time Stamp Counter nowb [ARM] @@ -518,7 +521,7 @@ ramdisk_start= [RAM] Starting block of RAM disk image (so you can place it after the kernel image on a boot floppy). - reboot= [BUGS=ix86] + reboot= [BUGS=IA-32] reserve= [KNL,BUGS] force the kernel to ignore some iomem area. @@ -607,7 +610,7 @@ video= [FB] frame buffer configuration. - vga= [BOOT] on ix386, select a particular video mode + vga= [BOOT] on IA-32, select a particular video mode (use vga=ask for menu). This is actually a boot loader parameter; the value is passed to the kernel using a special protocol. See diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/networking/pktgen.txt linux-2.5/Documentation/networking/pktgen.txt --- linux-2.5.23/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.23/Documentation/networking/skfp.txt linux-2.5/Documentation/networking/skfp.txt --- linux-2.5.23/Documentation/networking/skfp.txt Wed Jun 19 03:11:44 2002 +++ linux-2.5/Documentation/networking/skfp.txt Fri Jun 7 02:36:08 2002 @@ -143,6 +143,10 @@ (6) HISTORY =========== +v2.07 (20020506) (In-Kernel version) + Fix: Transmit Descriptor struct + Fix: Receive Descriptor struct + v2.06 (20000511) (In-Kernel version) New features: - 64 bit support diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/s390/Debugging390.txt linux-2.5/Documentation/s390/Debugging390.txt --- linux-2.5.23/Documentation/s390/Debugging390.txt Wed Jun 19 03:11:49 2002 +++ linux-2.5/Documentation/s390/Debugging390.txt Wed Jun 12 03:01:47 2002 @@ -238,7 +238,7 @@ On 390 our limitations & strengths make us slightly different. For backward compatibility ( because of the psw address hi bit which -indicates whether we are in 31 or 24 bit mode ) we are only allowed +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. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/scsi-generic.txt linux-2.5/Documentation/scsi-generic.txt --- linux-2.5.23/Documentation/scsi-generic.txt Wed Jun 19 03:11:56 2002 +++ linux-2.5/Documentation/scsi-generic.txt Tue Jun 4 15:45:28 2002 @@ -30,7 +30,7 @@ ======================= The most recent documentation of the sg driver is kept at the Linux Documentation Project's (LDP) site: -http://www.linuxdoc.org/HOWTO/SCSI-Generic-HOWTO +http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO This describes the sg version 3 driver found in the lk 2.4 series. The LDP renders documents in single and multiple page HTML, postscript and pdf. This document can also be found at: @@ -51,7 +51,7 @@ can be found at the top of the /usr/src/linux/drivers/scsi/sg.c file. A more general description of the Linux SCSI subsystem of which sg is a -part can be found at http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO . +part can be found at http://www.tldp.org/HOWTO/SCSI-2.4-HOWTO . Example code and utilities diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/scsi.txt linux-2.5/Documentation/scsi.txt --- linux-2.5.23/Documentation/scsi.txt Wed Jun 19 03:11:47 2002 +++ linux-2.5/Documentation/scsi.txt Tue Jun 4 15:45:28 2002 @@ -2,7 +2,7 @@ ============================ The Linux Documentation Project (LDP) maintains a document describing the SCSI subsystem in the Linux kernel (lk) 2.4 series. See: -http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single +http://www.tldp.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single and multiple page HTML renderings as well as postscript and pdf. It can also be found at http://www.torque.net/scsi/SCSI-2.4-HOWTO . diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/sound/oss/PAS16 linux-2.5/Documentation/sound/oss/PAS16 --- linux-2.5.23/Documentation/sound/oss/PAS16 Wed Jun 19 03:11:59 2002 +++ linux-2.5/Documentation/sound/oss/PAS16 Tue Jun 4 15:45:28 2002 @@ -71,7 +71,7 @@ interrupt and DMA channel), because you will be asked for it. You want to read the Sound-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . General information + http://www.tldp.org/docs.html#howto . General information about the modular sound system is contained in the files Documentation/sound/Introduction. The file Documentation/sound/README.OSS contains some slightly outdated but diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/Documentation/sound/rme96xx linux-2.5/Documentation/sound/rme96xx --- linux-2.5.23/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.23/Documentation/sysctl/vm.txt linux-2.5/Documentation/sysctl/vm.txt --- linux-2.5.23/Documentation/sysctl/vm.txt Wed Jun 19 03:11:57 2002 +++ linux-2.5/Documentation/sysctl/vm.txt Wed Jun 19 07:35:17 2002 @@ -17,6 +17,7 @@ Currently, these files are in /proc/sys/vm: - kswapd +- max_map_count - overcommit_memory - page-cluster - dirty_async_ratio @@ -79,6 +80,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.23/MAINTAINERS linux-2.5/MAINTAINERS --- linux-2.5.23/MAINTAINERS Wed Jun 19 03:11:56 2002 +++ linux-2.5/MAINTAINERS Wed Jun 19 07:35:17 2002 @@ -550,14 +550,12 @@ S: Maintained EXT2 FILE SYSTEM -P: Remy Card -M: Remy.Card@linux.org -L: linux-kernel@vger.kernel.org +L: ext2-devel@lists.sourceforge.net S: Maintained EXT3 FILE SYSTEM -P: Remy Card, Stephen Tweedie -M: sct@redhat.com, akpm@zip.com.au, adilger@turbolinux.com +P: Stephen Tweedie, Andrew Morton +M: sct@redhat.com, akpm@zip.com.au, adilger@clusterfs.com L: ext3-users@redhat.com S: Maintained @@ -632,7 +630,7 @@ HFS FILESYSTEM P: Adrian Sun -M: asun@cobaltnet.com +M: Adrian.Sun@sun.com L: linux-kernel@vger.kernel.org S: Maintained @@ -683,7 +681,7 @@ i386 BOOT CODE P: Riley H. Williams -M: rhw@memalpha.cx +M: Riley@Williams.Name L: Linux-Kernel@vger.kernel.org S: Maintained @@ -714,7 +712,7 @@ S: Maintained IBM ServeRAID RAID DRIVER -P: Jack Hammer +P: Jack Hammer P: Dave Jeffrey M: ipslinux@us.ibm.com W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html @@ -1070,8 +1068,8 @@ NATSEMI ETHERNET DRIVER (DP8381x) P: Tim Hockin -M: thockin@hockin.org -S: Maintained +M: thockin@hockin.org +S: Maintained NCP FILESYSTEM P: Petr Vandrovec @@ -1207,6 +1205,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 @@ -1277,6 +1281,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 @@ -1323,10 +1341,10 @@ S: Maintained RADEON FRAMEBUFFER DISPLAY DRIVER -P: Ani Joshi -M: ajoshi@shell.unixbox.com -L: linux-fbdev-devel@lists.sourceforge.net -S: Maintained +P: Ani Joshi +M: ajoshi@shell.unixbox.com +L: linux-fbdev-devel@lists.sourceforge.net +S: Maintained RAGE128 FRAMEBUFFER DISPLAY DRIVER P: Ani Joshi @@ -1364,6 +1382,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 @@ -1391,13 +1415,18 @@ L: linux-kernel@vger.kernel.org S: Maintained +SC1200 WDT DRIVER +P: Zwane Mwaikambo +M: zwane@commfireservices.com +S: Maintained + SCHEDULER P: Ingo Molnar M: mingo@elte.hu P: Robert Love M: rml@tech9.net L: linux-kernel@vger.kernel.org -S: Maintained +S: Maintain SCSI CDROM DRIVER P: Jens Axboe @@ -1561,6 +1590,13 @@ M: hch@infradead.org S: Maintained +TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER +P: Stephane Dalton +M: sdalton@videotron.ca +P: Stéphane Doyon +M: s.doyon@videotron.ca +S: Maintained + TI GRAPH LINK USB (SilverLink) CABLE DRIVER P: Romain Lievin M: roms@lpg.ticalc.org @@ -1687,6 +1723,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 @@ -1763,6 +1805,13 @@ W: http://www.beattie-home.net/linux S: Maintained +USB RTL8150 DRIVER +P: Petko Manolov +M: petkan@users.sourceforge.net +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + USB SE401 DRIVER P: Jeroen Vreeken M: pe1rxq@amsat.org @@ -1865,7 +1914,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.23/Makefile linux-2.5/Makefile --- linux-2.5.23/Makefile Wed Jun 19 03:11:47 2002 +++ linux-2.5/Makefile Wed Jun 19 19:05:43 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 23 -EXTRAVERSION = +EXTRAVERSION =-dj2 # We are using a recursive build, so we need to do a little thinking # to get the ordering right. @@ -30,7 +30,7 @@ TOPDIR := $(CURDIR) HPATH = $(TOPDIR)/include -FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net +FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer @@ -126,6 +126,16 @@ tags TAGS sgmldocs psdocs pdfdocs htmldocs \ checkconfig checkhelp checkincludes +# Link components for vmlinux +# --------------------------------------------------------------------------- +SUBDIRS := init kernel mm fs ipc lib drivers sound net +INIT := init/init.o +CORE_FILES := kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o +LIBS := lib/lib.a +DRIVERS := drivers/built-in.o sound/sound.o +NETWORKS := net/network.o + + ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),) # Here goes the main Makefile @@ -173,22 +183,16 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH) CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ - -fomit-frame-pointer -fno-strict-aliasing -fno-common + -fno-strict-aliasing -fno-common +ifndef CONFIG_FRAME_POINTER +CFLAGS += -fomit-frame-pointer +endif AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) ifdef CONFIG_MODULES EXPORT_FLAGS := -DEXPORT_SYMTAB endif -# Link components for vmlinux -# --------------------------------------------------------------------------- -SUBDIRS := init kernel mm fs ipc lib drivers sound net -INIT := init/init.o -CORE_FILES := kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o -LIBS := lib/lib.a -DRIVERS := drivers/built-in.o sound/sound.o -NETWORKS := net/network.o - include arch/$(ARCH)/Makefile export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS @@ -607,7 +611,7 @@ mrproper: clean archmrproper @echo 'Making mrproper' - @find . \( -size 0 -o -name .depend -o -name .\*.cmd \) \ + @find . \( -name .depend -o -name .\*.cmd \) \ -type f -print | xargs rm -f @rm -f $(MRPROPER_FILES) @rm -rf $(MRPROPER_DIRS) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/README linux-2.5/README --- linux-2.5.23/README Wed Jun 19 03:11:52 2002 +++ linux-2.5/README Tue Jun 4 00:29:15 2002 @@ -153,9 +153,8 @@ COMPILING the kernel: - - Make sure you have gcc 2.95.3 available. - gcc 2.91.66 (egcs-1.1.2), and gcc 2.7.2.3 are known to miscompile - some parts of the kernel, and are *no longer supported*. + - Make sure you have gcc 2.95.3 available. gcc 2.91.66 (egcs-1.1.2) may + also work but is not as safe, and *gcc 2.7.2.3 is no longer supported*. Also remember to upgrade your binutils package (for as/ld/nm and company) if necessary. For more information, refer to ./Documentation/Changes. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/alpha/Config.help linux-2.5/arch/alpha/Config.help --- linux-2.5.23/arch/alpha/Config.help Wed Jun 19 03:11:47 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.23/arch/alpha/kernel/alpha_ksyms.c linux-2.5/arch/alpha/kernel/alpha_ksyms.c --- linux-2.5.23/arch/alpha/kernel/alpha_ksyms.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/arch/alpha/kernel/alpha_ksyms.c Sat Jun 1 00:34:32 2002 @@ -214,6 +214,7 @@ EXPORT_SYMBOL(smp_imb); EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(__cpu_number_map); +EXPORT_SYMBOL(__cpu_logical_map); EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function_on_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/alpha/kernel/pci_iommu.c linux-2.5/arch/alpha/kernel/pci_iommu.c --- linux-2.5.23/arch/alpha/kernel/pci_iommu.c Wed Jun 19 03:11:59 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.23/arch/alpha/kernel/proto.h linux-2.5/arch/alpha/kernel/proto.h --- linux-2.5.23/arch/alpha/kernel/proto.h Wed Jun 19 03:11:49 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.23/arch/alpha/kernel/smc37c669.c linux-2.5/arch/alpha/kernel/smc37c669.c --- linux-2.5.23/arch/alpha/kernel/smc37c669.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/arch/alpha/kernel/smc37c669.c Mon Jun 17 22:52:24 2002 @@ -2470,7 +2470,7 @@ * * RETURNS: * - * Nothing + * 1 if the chip found, 0 otherwise * * ARGUMENTS: * @@ -2481,7 +2481,7 @@ * None * */ -void __init SMC669_Init ( int index ) +int __init SMC669_Init ( int index ) { SMC37c669_CONFIG_REGS *SMC_base; unsigned long flags; @@ -2544,11 +2544,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.23/arch/alpha/kernel/smp.c linux-2.5/arch/alpha/kernel/smp.c --- linux-2.5.23/arch/alpha/kernel/smp.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/arch/alpha/kernel/smp.c Fri May 17 00:17:52 2002 @@ -181,9 +181,23 @@ calibrate_delay. */ wait_boot_cpu_to_stop(cpuid); mb(); +try_again: calibrate_delay(); smp_store_cpu_info(cpuid); + + { +#define LPJ(c) ((long)cpu_data[c].loops_per_jiffy) + static int tries = 3; + long diff = LPJ(boot_cpuid) - LPJ(cpuid); + if (diff < 0) diff = -diff; + + if (diff > LPJ(boot_cpuid)/10 && --tries) { + printk("Bogus BogoMIPS for cpu %d - retrying...\n", cpuid); + goto try_again; + } + } + /* Allow master to continue only after we written loops_per_jiffy. */ wmb(); smp_secondary_alive = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/alpha/kernel/sys_miata.c linux-2.5/arch/alpha/kernel/sys_miata.c --- linux-2.5.23/arch/alpha/kernel/sys_miata.c Wed Jun 19 03:11:55 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.23/arch/arm/config.in linux-2.5/arch/arm/config.in --- linux-2.5.23/arch/arm/config.in Wed Jun 19 03:11:49 2002 +++ linux-2.5/arch/arm/config.in Mon Jun 3 17:10:18 2002 @@ -563,9 +563,6 @@ source drivers/isdn/Config.in -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in source drivers/char/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/arm/mach-footbridge/netwinder-hw.c linux-2.5/arch/arm/mach-footbridge/netwinder-hw.c --- linux-2.5.23/arch/arm/mach-footbridge/netwinder-hw.c Wed Jun 19 03:11:47 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.23/arch/arm/mach-shark/leds.c linux-2.5/arch/arm/mach-shark/leds.c --- linux-2.5.23/arch/arm/mach-shark/leds.c Wed Jun 19 03:11:54 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.23/arch/cris/boot/compressed/Makefile linux-2.5/arch/cris/boot/compressed/Makefile --- linux-2.5.23/arch/cris/boot/compressed/Makefile Wed Jun 19 03:11:45 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.23/arch/cris/boot/rescue/Makefile linux-2.5/arch/cris/boot/rescue/Makefile --- linux-2.5.23/arch/cris/boot/rescue/Makefile Wed Jun 19 03:11:53 2002 +++ linux-2.5/arch/cris/boot/rescue/Makefile Tue May 21 22:53:42 2002 @@ -3,6 +3,8 @@ # ifndef TOPDIR TOPDIR = ../../../.. +HPATH = $(TOPDIR)/include +export HPATH endif CC = gcc-cris -mlinux -I $(TOPDIR)/include CFLAGS = -O2 @@ -52,3 +54,8 @@ modules: modules-install: + +depend: + $(CC) -M *.S > .depend + +-include .depend diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/cris/config.in linux-2.5/arch/cris/config.in --- linux-2.5.23/arch/cris/config.in Wed Jun 19 03:11:56 2002 +++ linux-2.5/arch/cris/config.in Mon May 6 14:18:19 2002 @@ -196,9 +196,6 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in source drivers/char/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/cris/drivers/ethernet.c linux-2.5/arch/cris/drivers/ethernet.c --- linux-2.5.23/arch/cris/drivers/ethernet.c Wed Jun 19 03:11:54 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.23/arch/cris/drivers/serial.c linux-2.5/arch/cris/drivers/serial.c --- linux-2.5.23/arch/cris/drivers/serial.c Wed Jun 19 03:11:48 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.23/arch/cris/drivers/serial.h linux-2.5/arch/cris/drivers/serial.h --- linux-2.5.23/arch/cris/drivers/serial.h Wed Jun 19 03:11:52 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.23/arch/i386/Config.help linux-2.5/arch/i386/Config.help --- linux-2.5.23/arch/i386/Config.help Wed Jun 19 03:11:47 2002 +++ linux-2.5/arch/i386/Config.help Mon Jun 17 22:52:25 2002 @@ -416,7 +416,7 @@ - "Winchip-C6" for original IDT Winchip. - "Winchip-2" for IDT Winchip 2. - "Winchip-2A" for IDT Winchips with 3dNow! capabilities. - - "CyrixIII" for VIA Cyrix III or VIA C3. + - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3. If you don't know what to do, choose "386". @@ -635,6 +635,18 @@ just add about 9 KB to your kernel. See for more information. + +CONFIG_IKCONFIG + This option enables the complete Linux kernel ".config" file contents + to be saved in the kernel (zipped) image file. It provides + documentation of which kernel options are used in a running kernel or + in an on-disk kernel. It can be extracted from the kernel image file + with a script and used as input to rebuild the current kernel or to + build another kernel. Since the kernel image is zipped, using this + option adds approximately 8 KB to a kernel image file. + This option is not available as a module. If you want a separate + file to save the kernel's .config contents, use 'installkernel' or 'cp' + or a similar tool, or just save it in '/lib/modules/'. CONFIG_PM "Power Management" means that parts of your computer are shut diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/boot/compressed/misc.c linux-2.5/arch/i386/boot/compressed/misc.c --- linux-2.5.23/arch/i386/boot/compressed/misc.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/arch/i386/boot/compressed/misc.c Wed May 8 15:05:39 2002 @@ -202,10 +202,10 @@ SCREEN_INFO.orig_y = y; pos = (x + cols * y) * 2; /* Update cursor position */ - outb_p(14, vidport); - outb_p(0xff & (pos >> 9), vidport+1); - outb_p(15, vidport); - outb_p(0xff & (pos >> 1), vidport+1); + outb_local_p(14, vidport); + outb_local_p(0xff & (pos >> 9), vidport+1); + outb_local_p(15, vidport); + outb_local_p(0xff & (pos >> 1), vidport+1); } static void* memset(void* s, int c, size_t n) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/config.in linux-2.5/arch/i386/config.in --- linux-2.5.23/arch/i386/config.in Wed Jun 19 03:11:51 2002 +++ linux-2.5/arch/i386/config.in Wed Jun 19 20:30:05 2002 @@ -5,7 +5,6 @@ mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_X86 y -define_bool CONFIG_ISA y define_bool CONFIG_SBUS n define_bool CONFIG_UID16 y @@ -30,7 +29,7 @@ Winchip-C6 CONFIG_MWINCHIPC6 \ Winchip-2 CONFIG_MWINCHIP2 \ Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ - CyrixIII/C3 CONFIG_MCYRIXIII" Pentium-Pro + CyrixIII/VIA-C3 CONFIG_MCYRIXIII" Pentium-Pro # # Define implied options from the CPU selection here # @@ -169,9 +168,23 @@ fi bool 'Machine Check Exception' CONFIG_X86_MCE -dep_bool 'Check for non-fatal errors on Athlon/Duron' CONFIG_X86_MCE_NONFATAL $CONFIG_X86_MCE -dep_bool 'check for P4 thermal throttling interrupt.' CONFIG_X86_MCE_P4THERMAL $CONFIG_X86_MCE $CONFIG_X86_UP_APIC +dep_bool ' Check for non-fatal errors on Athlon/Duron' CONFIG_X86_MCE_NONFATAL $CONFIG_X86_MCE +if [ "$CONFIG_SMP" == "y" ]; then + bool ' Check for P4 thermal throttling interrupt.' CONFIG_X86_MCE_P4THERMAL +else + dep_bool ' Check for P4 thermal throttling interrupt.' CONFIG_X86_MCE_P4THERMAL $CONFIG_X86_MCE $CONFIG_X86_UP_APIC +fi +bool 'CPU Frequency scaling' CONFIG_CPU_FREQ +if [ "$CONFIG_CPU_FREQ" != "n" ]; then + bool ' AMD K6-2/K6-3 PowerNow!' CONFIG_X86_POWERNOW_K6 + bool ' Intel Pentium 3 Speedstep' CONFIG_X86_SPEEDSTEP + bool ' Intel Pentium 4 clock modulation' CONFIG_X86_P4_CLOCKMOD + if [ "$CONFIG_MELAN" = "y" ]; then + bool ' AMD Elan' CONFIG_ELAN_CPUFREQ + fi + bool ' VIA Cyrix III Longhaul' CONFIG_X86_LONGHAUL +fi tristate 'Toshiba Laptop support' CONFIG_TOSHIBA tristate 'Dell laptop support' CONFIG_I8K @@ -226,6 +239,8 @@ bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi +dep_mbool 'Software Suspend (EXPERIMENTAL)' CONFIG_SOFTWARE_SUSPEND $CONFIG_PM $CONFIG_EXPERIMENTAL + endmenu mainmenu_option next_comment @@ -260,7 +275,9 @@ source drivers/pci/Config.in -bool 'EISA support' CONFIG_EISA +bool 'ISA support' CONFIG_ISA + +dep_bool 'EISA support' CONFIG_EISA $CONFIG_ISA if [ "$CONFIG_VISWS" != "y" ]; then bool 'MCA support' CONFIG_MCA @@ -292,6 +309,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 + endmenu source drivers/mtd/Config.in @@ -358,7 +377,10 @@ source drivers/isdn/Config.in +if [ "$CONFIG_ISA" != "n" ]; then + mainmenu_option next_comment + comment 'Old CD-ROM drivers (not SCSI, not IDE)' bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI @@ -367,10 +389,10 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# +fi + source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in @@ -406,19 +428,18 @@ mainmenu_option next_comment comment 'Kernel hacking' -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_bool 'Software Suspend' CONFIG_SOFTWARE_SUSPEND $CONFIG_PM -fi - 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.23/arch/i386/defconfig linux-2.5/arch/i386/defconfig --- linux-2.5.23/arch/i386/defconfig Wed Jun 19 03:11:48 2002 +++ linux-2.5/arch/i386/defconfig Sat May 25 19:51:58 2002 @@ -117,6 +117,7 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y +CONFIG_IKCONFIG=n CONFIG_PM=y # CONFIG_APM is not set # CONFIG_SOFTWARE_SUSPEND is not set @@ -493,10 +494,10 @@ # CONFIG_PCMCIA_3C574 is not set # CONFIG_PCMCIA_FMVJ18X is not set CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set # CONFIG_PCMCIA_NMCLAN is not set # CONFIG_PCMCIA_SMC91C92 is not set # CONFIG_PCMCIA_XIRC2PS is not set -# CONFIG_PCMCIA_AXNET is not set # CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_IBMTR is not set CONFIG_NET_PCMCIA_RADIO=y @@ -526,21 +527,61 @@ # # Input device support # -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set # CONFIG_GAMEPORT is not set CONFIG_SOUND_GAMEPORT=y # CONFIG_GAMEPORT_NS558 is not set # CONFIG_GAMEPORT_L4 is not set # CONFIG_INPUT_EMU10K1 is not set -# CONFIG_GAMEPORT_PCIGAME is not set # CONFIG_GAMEPORT_FM801 is not set # CONFIG_GAMEPORT_CS461x is not set -# CONFIG_SERIO is not set -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_PS2SERKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=y +# CONFIG_MOUSE_GUNZE is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE_USB is not set +# CONFIG_JOYSTICK_IFORCE_232 is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDDLER is not set +# CONFIG_JOYSTICK_DB9 is not set +# CONFIG_JOYSTICK_GAMECON is not set +# CONFIG_JOYSTICK_TURBOGRAFX is not set # # Character devices @@ -561,15 +602,6 @@ # I2C support # # CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set # CONFIG_QIC02_TAPE is not set # @@ -602,6 +634,7 @@ CONFIG_DRM_RADEON=y # CONFIG_DRM_I810 is not set # CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set # # PCMCIA character devices @@ -840,13 +873,9 @@ # # USB Human Interface Devices (HID) # -# CONFIG_USB_HID is not set - -# -# Input core support is needed for USB HID input layer or HIDBP support -# -# CONFIG_USB_HIDINPUT is not set +CONFIG_USB_HID=y # CONFIG_USB_HIDDEV is not set +# CONFIG_USB_WACOM is not set # CONFIG_USB_KBD is not set # CONFIG_USB_MOUSE is not set # CONFIG_USB_WACOM is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/Makefile linux-2.5/arch/i386/kernel/Makefile --- linux-2.5.23/arch/i386/kernel/Makefile Wed Jun 19 03:11:49 2002 +++ linux-2.5/arch/i386/kernel/Makefile Wed Jun 19 18:26:47 2002 @@ -6,7 +6,7 @@ O_TARGET := kernel.o -export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o +export-objs := mca.o msr.o cpuid.o microcode.o i386_ksyms.o time.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ @@ -15,7 +15,7 @@ obj-y += cpu/ obj-$(CONFIG_MCA) += mca.o -obj-$(CONFIG_MTRR) += mtrr.o +obj-$(CONFIG_EISA) += eisa.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o @@ -26,6 +26,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o +obj-$(CONFIG_ACPI_SLEEP) += suspend.o ifdef CONFIG_VISWS obj-y += setup-visws.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/apic.c linux-2.5/arch/i386/kernel/apic.c --- linux-2.5.23/arch/i386/kernel/apic.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/arch/i386/kernel/apic.c Wed Jun 19 07:35:18 2002 @@ -700,7 +700,15 @@ for (i = 0; i < nr_ioapics; i++) { if (smp_found_config) { ioapic_phys = mp_ioapics[i].mpc_apicaddr; + if (!ioapic_phys) { + printk(KERN_ERR "WARNING: bogus zero IO-APIC address found in MPTABLE, disabling IO/APIC support!\n"); + + smp_found_config = 0; + skip_ioapic_setup = 1; + goto fake_ioapic_page; + } } else { +fake_ioapic_page: ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); ioapic_phys = __pa(ioapic_phys); } @@ -1063,7 +1071,6 @@ * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -unsigned int apic_timer_irqs [NR_CPUS]; void smp_apic_timer_interrupt(struct pt_regs regs) { @@ -1072,7 +1079,7 @@ /* * the NMI deadlock-detector uses this. */ - apic_timer_irqs[cpu]++; + irq_stat[cpu].apic_timer_irqs++; /* * NOTE! We'd better ACK the irq immediately, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/apm.c linux-2.5/arch/i386/kernel/apm.c --- linux-2.5.23/arch/i386/kernel/apm.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/arch/i386/kernel/apm.c Wed Jun 19 07:35:18 2002 @@ -922,9 +922,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 = { @@ -1171,17 +1171,14 @@ { #ifdef INIT_TIMER_AFTER_SUSPEND unsigned long flags; + extern spinlock_t i8253_lock; - save_flags(flags); - cli(); + spin_lock_irqsave(&i8253_lock, flags); /* set the clock to 100 Hz */ - outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - udelay(10); - outb_p(LATCH & 0xff , 0x40); /* LSB */ - udelay(10); - outb(LATCH >> 8 , 0x40); /* MSB */ - udelay(10); - restore_flags(flags); + outb_p(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff, 0x40); /* LSB */ + outb_p(LATCH >> 8, 0x40); /* MSB */ + spin_unlock_irqrestore(&i8253_lock, flags); #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/Makefile linux-2.5/arch/i386/kernel/cpu/Makefile --- linux-2.5.23/arch/i386/kernel/cpu/Makefile Wed Jun 19 03:11:55 2002 +++ linux-2.5/arch/i386/kernel/cpu/Makefile Wed Jun 19 18:28:12 2002 @@ -13,4 +13,9 @@ obj-y += nexgen.o obj-y += umc.o +obj-$(CONFIG_MTRR) += mtrr/ + +obj-y += cpufreq/ +obj-m += cpufreq/ + include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/amd.c linux-2.5/arch/i386/kernel/cpu/amd.c --- linux-2.5.23/arch/i386/kernel/cpu/amd.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/arch/i386/kernel/cpu/amd.c Mon Jun 10 13:14:22 2002 @@ -141,7 +141,7 @@ * here. */ if (c->x86_model == 6 || c->x86_model == 7) { - if (!test_bit(X86_FEATURE_XMM, c->x86_capability)) { + if (!cpu_has(c, X86_FEATURE_XMM)) { printk(KERN_INFO "Enabling disabled K7/SSE Support.\n"); rdmsr(MSR_K7_HWCR, l, h); l &= ~0x00008000; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/cpufreq/Makefile linux-2.5/arch/i386/kernel/cpu/cpufreq/Makefile --- linux-2.5.23/arch/i386/kernel/cpu/cpufreq/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/cpufreq/Makefile Sun Jun 9 01:26:58 2002 @@ -0,0 +1,9 @@ +O_TARGET := built-in.o + +obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o +obj-$(CONFIG_X86_LONGHAUL) += longhaul.o +obj-$(CONFIG_X86_SPEEDSTEP) += speedstep.o +obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o +obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/cpufreq/elanfreq.c linux-2.5/arch/i386/kernel/cpu/cpufreq/elanfreq.c --- linux-2.5.23/arch/i386/kernel/cpu/cpufreq/elanfreq.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/cpufreq/elanfreq.c Wed Jun 19 08:06:37 2002 @@ -0,0 +1,235 @@ +/* + * elanfreq: cpufreq driver for the AMD ELAN family + * + * (c) Copyright 2002 Robert Schwebel + * + * Parts of this code are (c) Sven Geggus + * + * 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. + * + * 2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel + * + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */ +#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */ + +#define SAFE_FREQ 33000 /* every Elan CPU can run at 33 MHz */ + +static int currentspeed; /* current frequency in kHz */ +static unsigned int elanfreq_initialised; + +MODULE_LICENSE("GPL"); + +MODULE_AUTHOR( + "Robert Schwebel , Sven Geggus " +); +MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs"); + +struct s_elan_multiplier { + int clock; /* frequency in kHz */ + int val40h; /* PMU Force Mode register */ + int val80h; /* CPU Clock Speed Register */ +}; + +/* + * It is important that the frequencies + * are listed in ascending order here! + */ +struct s_elan_multiplier elan_multiplier[] = { + {1000, 0x02, 0x18}, + {2000, 0x02, 0x10}, + {4000, 0x02, 0x08}, + {8000, 0x00, 0x00}, + {16000, 0x00, 0x02}, + {33000, 0x00, 0x04}, + {66000, 0x01, 0x04}, + {99000, 0x01, 0x05} +}; + + +/** + * elanfreq_get_cpu_frequency: determine current cpu speed + * + * Finds out at which frequency the CPU of the Elan SOC runs + * at the moment. Frequencies from 1 to 33 MHz are generated + * the normal way, 66 and 99 MHz are called "Hyperspeed Mode" + * and have the rest of the chip running with 33 MHz. + */ + +static unsigned int elanfreq_get_cpu_frequency(void) +{ + u8 clockspeed_reg; /* Clock Speed Register */ + + cli(); + outb_p(0x80,REG_CSCIR); + clockspeed_reg = inb_p(REG_CSCDR); + sti(); + + if ((clockspeed_reg & 0xE0) == 0xE0) { return 0; } + + /* Are we in CPU clock multiplied mode (66/99 MHz)? */ + if ((clockspeed_reg & 0xE0) == 0xC0) { + if ((clockspeed_reg & 0x01) == 0) { + return 66000; + } else { + return 99000; + } + } + + /* 33 MHz is not 32 MHz... */ + if ((clockspeed_reg & 0xE0)==0xA0) + return 33000; + + return ((1<<((clockspeed_reg & 0xE0) >> 5)) * 1000); +} + + +/** + * elanfreq_set_cpu_frequency: Change the CPU core frequency + * @freq: frequency in kHz + * + * This function takes a frequency value and changes the CPU frequency + * according to this. Note that the frequency has to be checked by + * elanfreq_validatespeed() for correctness! + * + * There is no return value. + */ + +static void elanfreq_set_cpu_frequency (unsigned int freq) { + + int i; + + printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",freq); + + /* search table entry for given Mhz value */ + for (i=0; i<(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier)); i++) + { + if (elan_multiplier[i].clock==freq) break; + } + + /* XXX Shouldn't we have a sanity check here or can we rely on + the frequency having been checked before ??? */ + + /* + * Access to the Elan's internal registers is indexed via + * 0x22: Chip Setup & Control Register Index Register (CSCI) + * 0x23: Chip Setup & Control Register Data Register (CSCD) + * + */ + + /* + * 0x40 is the Power Management Unit's Force Mode Register. + * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency) + */ + + cli(); + outb_p(0x40,REG_CSCIR); /* Disable hyperspeed mode */ + outb_p(0x00,REG_CSCDR); + sti(); /* wait till internal pipelines and */ + udelay(1000); /* buffers have cleaned up */ + + cli(); + + /* now, set the CPU clock speed register (0x80) */ + outb_p(0x80,REG_CSCIR); + outb_p(elan_multiplier[i].val80h,REG_CSCDR); + + /* now, the hyperspeed bit in PMU Force Mode Register (0x40) */ + outb_p(0x40,REG_CSCIR); + outb_p(elan_multiplier[i].val40h,REG_CSCDR); + udelay(10000); + sti(); + + currentspeed=freq; + +}; + + +/** + * elanfreq_validatespeed: test if frequency is valid + * @freq: frequency in kHz + * + * This function checks if a given frequency in kHz is valid for the + * hardware supported by the driver. It returns a "best fit" frequency + * which might be different from the given one. + */ + +static unsigned int elanfreq_validatespeed (unsigned int freq) +{ + unsigned int best = 0; + int i; + + for (i=0; i<(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier)); i++) + { + if (freq >= elan_multiplier[i].clock) + { + best = elan_multiplier[i].clock; + + } + } + + return best; +} + + + +/* + * Module init and exit code + */ + +static int __init elanfreq_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + cpufreq_driver_t driver; + int ret; + + /* Test if we have the right hardware */ + if ((c->x86_vendor != X86_VENDOR_AMD) || + (c->x86 != 4) || (c->x86_model!=10)) + { + printk(KERN_INFO "elanfreq: error: no Elan processor found!\n"); + return -ENODEV; + } + + driver.freq.cur = elanfreq_get_cpu_frequency(); + driver.validate = &elanfreq_validatespeed; + driver.setspeed = &elanfreq_set_cpu_frequency; + + ret = cpufreq_register(driver); + if (ret) + return ret; + + elanfreq_initialised = 1, + + return 0; +} + + +static void __exit elanfreq_exit(void) +{ + if (elanfreq_initialised) + cpufreq_unregister(); +} + +module_init(elanfreq_init); +module_exit(elanfreq_exit); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/cpufreq/longhaul.c linux-2.5/arch/i386/kernel/cpu/cpufreq/longhaul.c --- linux-2.5.23/arch/i386/kernel/cpu/cpufreq/longhaul.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/cpufreq/longhaul.c Wed Jun 19 08:06:37 2002 @@ -0,0 +1,699 @@ +/* + * $Id: longhaul.c,v 1.51 2002/06/16 19:55:03 db Exp $ + * + * (C) 2001 Dave Jones. + * (C) 2002 Padraig Brady. + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon datasheets & sample CPUs kindly provided by VIA. + * + * VIA have currently 3 different versions of Longhaul. + * + * +---------------------+----------+---------------------------------+ + * | Marketing name | Codename | longhaul version / features. | + * +---------------------+----------+---------------------------------+ + * | Samuel/CyrixIII | C5A | v1 : multipliers only | + * | Samuel2/C3 | C3E/C5B | v1 : multiplier only | + * | Ezra | C5C | v2 : multipliers & voltage | + * | Ezra-T | C5M/C5N | v3 : multipliers, voltage & FSB | + * +---------------------+----------+---------------------------------+ + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG + +#ifdef DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0); +#endif + +static int numscales=16, numvscales; +static int minvid, maxvid; +static int can_scale_voltage; +static int can_scale_fsb; +static int vrmrev; + + +/* Module parameters */ +static int dont_scale_voltage; +static int dont_scale_fsb; +static int current_fsb; +static int favour_fast_fsb; + +#define __hlt() __asm__ __volatile__("hlt": : :"memory") + +/* + * Clock ratio tables. + * The eblcr ones specify the ratio read from the CPU. + * The clock_ratio ones specify what to write to the CPU. + */ + +/* VIA C3 Samuel 1 & Samuel 2 (stepping 0)*/ +static int __initdata longhaul1_clock_ratio[16] = { + -1, /* 0000 -> RESERVED */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + -1, /* 0011 -> RESERVED */ + -1, /* 0100 -> RESERVED */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + -1, /* 1110 -> RESERVED */ + -1, /* 1111 -> RESERVED */ +}; + +static int __initdata samuel1_eblcr[16] = { + 50, /* 0000 -> RESERVED */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + -1, /* 0011 -> RESERVED */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + -1, /* 0111 -> RESERVED */ + -1, /* 1000 -> RESERVED */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + -1, /* 1100 -> RESERVED */ + 75, /* 1101 -> 7.5x */ + -1, /* 1110 -> RESERVED */ + 65, /* 1111 -> 6.5x */ +}; + +/* VIA C3 Samuel2 Stepping 1->15 & VIA C3 Ezra */ +static int __initdata longhaul2_clock_ratio[16] = { + 100, /* 0000 -> 10.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ +}; + +static int __initdata samuel2_eblcr[16] = { + 90, /* 0000 -> 9.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 110, /* 0111 -> 11.0x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 130, /* 1110 -> 13.0x */ + 65, /* 1111 -> 6.5x */ +}; + +static int __initdata ezra_eblcr[16] = { + 90, /* 0000 -> 9.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 50, /* 1000 -> 5.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ +}; + +/* VIA C5M. */ +static int __initdata longhaul3_clock_ratio[32] = { + 100, /* 0000 -> 10.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ + + -1, /* 0000 -> RESERVED (10.0x) */ + 110, /* 0001 -> 11.0x */ + 120, /* 0010 -> 12.0x */ + -1, /* 0011 -> RESERVED (9.0x)*/ + 105, /* 0100 -> 10.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 135, /* 0111 -> 13.5x */ + 140, /* 1000 -> 14.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 130, /* 1011 -> 13.0x */ + 145, /* 1100 -> 14.5x */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + -1, /* 1111 -> RESERVED (12.0x) */ +}; + +static int __initdata c5m_eblcr[32] = { + 90, /* 0000 -> 9.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 50, /* 1000 -> 5.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ + + -1, /* 0000 -> RESERVED (9.0x) */ + 110, /* 0001 -> 11.0x */ + 120, /* 0010 -> 12.0x */ + -1, /* 0011 -> RESERVED (10.0x)*/ + 135, /* 0100 -> 13.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 105, /* 0111 -> 10.5x */ + 130, /* 1000 -> 13.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 140, /* 1011 -> 14.0x */ + -1, /* 1100 -> RESERVED (12.0x) */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + 145, /* 1111 -> 14.5x */ +}; + +/* fsb values as defined in CPU */ +static unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 }; +/* fsb values to favour low fsb speed (lower power) */ +static unsigned int power_fsb_table[] = { 66, 100, 133, -1 }; +/* fsb values to favour high fsb speed (for e.g. if lowering CPU + freq because of heat, but want to maintain highest performance possible) */ +static unsigned int perf_fsb_table[] = { 133, 100, 66, -1 }; +static unsigned int *fsb_search_table; + +/* Voltage scales. Div by 1000 to get actual voltage. */ +static int __initdata vrm85scales[32] = { + 1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700, + 1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300, + 1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725, + 1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325, +}; + +static int __initdata mobilevrmscales[32] = { + 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, + 1600, 1550, 1500, 1450, 1500, 1350, 1300, -1, + 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, + 1075, 1050, 1025, 1000, 975, 950, 925, -1, +}; + +/* Clock ratios multiplied by 10 */ +static int clock_ratio[32]; +static int eblcr_table[32]; +static int voltage_table[32]; +static int highest_speed, lowest_speed; +static int longhaul; /* version. */ + +/* + * All integer math. + * Input: + * ratio is multiplier*10, for e.g. 15 = 1.5, 12=1.2 + * Output: + * return value is in units of fsb input parameter + */ +static unsigned int get_clock_from_ratio(int ratio, unsigned fsb) +{ + unsigned int clock=0; + + if (ratio > 0 && fsb != 0) { + clock = (ratio/10)*fsb; + if (ratio%10) + clock += (fsb/(10/(ratio%10))); + } + return clock; +} + +static unsigned int longhaul_validatespeed_fsb(unsigned int freq, unsigned fsb, unsigned int oldbest) +{ + int i; + unsigned int newclock; + unsigned int best=0; + + best = oldbest; + + /* Find closest MHz match. */ + for (i=0; i best) && (newclock <= (freq+1))) + if ((newclock>=lowest_speed) && (newclock<=highest_speed)) + best = newclock; + } + return best; +} + +/* Determine nearest speed possible for the desired fsb speed */ +static unsigned int longhaul_validatespeed (unsigned int freq) +{ + unsigned int best=0; + + if (freqhighest_speed) + freq=highest_speed; + + if (can_scale_fsb==1) { + int fsb_index; + for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++) + best = longhaul_validatespeed_fsb (freq, fsb_search_table[fsb_index], best); + } else { + /* Can only scale multiplier. */ + best = longhaul_validatespeed_fsb (freq, current_fsb, best); + } + + return best; +} + +/* + * longhaul_set_cpu_frequency() + * This gets passed a MHz value that has been preprocessed + * with longhaul_validatespeed(). + * + * Note this function is only called if a new frequency has been selected. + */ + +static void longhaul_set_cpu_frequency (unsigned int Mhz) +{ + int index; + unsigned int bestfsb=-1; + unsigned long lo, hi; + int bits=-1; + int revkey; + int vidindex, i; + + /* Find out which mult bit-pattern & FSB we want */ + for (index=0; index>18; + return eblcr_fsb_table[invalue]; + } else { + return current_fsb; + } +} + + +static int __init longhaul_get_cpu_mult (void) +{ + unsigned long invalue=0,lo, hi; + + rdmsr (0x2a, lo, hi); + invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; + if (longhaul==3) { + if (lo & (1<<27)) + invalue+=16; + } + return eblcr_table[invalue]; +} + + +static void __init longhaul_get_ranges (void) +{ + unsigned long lo, hi, invalue; + unsigned int minmult=0, maxmult=0, minfsb=0, maxfsb=0; + unsigned int multipliers[32]= { + 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, + -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 }; + unsigned int fsb_table[4] = { 133, 100, -1, 66 }; + + switch (longhaul) { + case 1: + //FIXME: fill in from datasheet + break; + + case 2 ... 3: + rdmsr (0x110a, lo, hi); + + invalue = (hi & (1<<0|1<<1|1<<2|1<<3)); + if (hi & (1<<11)) + invalue += 16; + maxmult=multipliers[invalue]; + + #if 0 /* This is MaxMhz @ Min Voltage. Ignore for now */ + invalue = (hi & (1<<16|1<<17|1<<18|1<<19)) >> 16; + if (hi & (1<<27)) + invalue += 16; + minmult = multipliers[invalue]; + #else + minmult = 3; /* as per spec */ + #endif + + if (can_scale_fsb==1) { + invalue = (hi & (1<<9|1<<10)) >> 9; + maxfsb = fsb_table[invalue]; + + invalue = (hi & (1<<25|1<<26)) >> 25; + minfsb = fsb_table[invalue]; + + dprintk (KERN_INFO "longhaul: Min FSB=%d Max FSB=%d\n", + minfsb, maxfsb); + } else { + minfsb = maxfsb = current_fsb; + } + break; + } + + highest_speed = get_clock_from_ratio(maxmult, maxfsb); + lowest_speed = get_clock_from_ratio(minmult, minfsb); + + dprintk (KERN_INFO "longhaul: MinMult(x10)=%d MaxMult(x10)=%d\n", + minmult, maxmult); + dprintk (KERN_INFO "longhaul: Lowestspeed=%d Highestspeed=%d\n", + lowest_speed, highest_speed); +} + + +static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned long hi) +{ + int revkey; + + can_scale_voltage = 1; + + minvid = (hi & (1<<20|1<<21|1<<22|1<<23|1<<24)) >> 20; /* 56:52 */ + maxvid = (hi & (1<<4|1<<5|1<<6|1<<7|1<<8)) >> 4; /* 40:36 */ + vrmrev = (lo & (1<<15))>>15; + + if (vrmrev==0) { + dprintk (KERN_INFO "longhaul: VRM 8.5 : "); + memcpy (voltage_table, vrm85scales, sizeof(voltage_table)); + numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25; + } else { + dprintk (KERN_INFO "longhaul: Mobile VRM : "); + memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table)); + numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5; + } + + /* Current voltage isn't readable at first, so we need to + set it to a known value. The spec says to use maxvid */ + revkey = (lo & 0xf)<<4; /* Rev key. */ + lo &= 0xfe0fff0f; /* Mask unneeded bits */ + lo |= (1<<9); /* EnableSoftVID */ + lo |= revkey; /* Reinsert key */ + lo |= maxvid << 20; + wrmsr (0x110a, lo, hi); + minvid = voltage_table[minvid]; + maxvid = voltage_table[maxvid]; + dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n", + maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales); +} + + +static int __init longhaul_init (void) +{ + struct cpuinfo_x86 *c = cpu_data; + unsigned int currentspeed; + static int currentmult; + unsigned long lo, hi; + int ret; + cpufreq_driver_t driver; + + if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) ) + return -ENODEV; + + switch (c->x86_model) { + case 6: /* VIA C3 Samuel C5A */ + return -ENODEV; // See line 499 + longhaul=1; + memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio)); + memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr)); + break; + + case 7: /* C5B / C5C */ + switch (c->x86_mask) { + case 0: + return -ENODEV; // See line 499 + longhaul=1; + memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio)); + memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr)); + break; + case 1 ... 15: + longhaul=2; + memcpy (clock_ratio, longhaul2_clock_ratio, sizeof(longhaul2_clock_ratio)); + memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr)); + break; + } + break; + + case 8: /* C5M/C5N */ + return -ENODEV; // Waiting on updated docs from VIA before this is usable + longhaul=3; + numscales=32; + memcpy (clock_ratio, longhaul3_clock_ratio, sizeof(longhaul3_clock_ratio)); + memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr)); + break; + + default: + printk (KERN_INFO "longhaul: Unknown VIA CPU. Contact davej@suse.de\n"); + return -ENODEV; + } + + printk (KERN_INFO "longhaul: VIA CPU detected. Longhaul version %d supported\n", longhaul); + + if (favour_fast_fsb==1) + fsb_search_table = perf_fsb_table; + else + fsb_search_table = power_fsb_table; + + current_fsb = longhaul_get_cpu_fsb(); + currentmult = longhaul_get_cpu_mult(); + currentspeed = get_clock_from_ratio(currentmult, current_fsb); + + dprintk (KERN_INFO "longhaul: CPU currently at %dMHz (%d x %d.%d)\n", + currentspeed, current_fsb, currentmult/10, currentmult%10); + + if (longhaul==2 || longhaul==3) { + rdmsr (0x110a, lo, hi); + if ((lo & (1<<0)) && (dont_scale_voltage==0)) + longhaul_setup_voltagescaling (lo, hi); + + if ((lo & (1<<1)) && (dont_scale_fsb==0) && (current_fsb==0)) + can_scale_fsb = 1; + } + + longhaul_get_ranges(); + + driver.freq.min = (unsigned int) lowest_speed * 1000; + driver.freq.max = (unsigned int) highest_speed * 1000; + driver.freq.cur = currentspeed * 1000; + driver.validate = &longhaul_validatespeed; + driver.setspeed = &longhaul_set_cpu_frequency; + + ret = cpufreq_register(driver); + + if (ret) { + longhaul = 0; + return ret; + } + + return 0; +} + + +static void __exit longhaul_exit (void) +{ + if (longhaul) + cpufreq_unregister(); +} + +MODULE_PARM (dont_scale_fsb, "i"); +MODULE_PARM (dont_scale_voltage, "i"); +MODULE_PARM (current_fsb, "i"); +MODULE_PARM (favour_fast_fsb, "i"); + +MODULE_AUTHOR ("Dave Jones "); +MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); +MODULE_LICENSE ("GPL"); + +module_init(longhaul_init); +module_exit(longhaul_exit); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c linux-2.5/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c --- linux-2.5.23/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c Wed Jun 19 08:06:37 2002 @@ -0,0 +1,234 @@ +/* + * Pentium 4/Xeon CPU on demand clock modulation/speed scaling + * (C) 2002 Zwane Mwaikambo + * (C) 2002 Tora T. Engstad + * 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. + * + * 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. + * + * Date Errata Description + * 20020525 N44, O17 12.5% or 25% DC causes lockup + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* i'll be submitting a patch to lkml for this */ +#ifndef MSR_IA32_THERM_CONTROL +#define MSR_IA32_THERM_CONTROL 0x19a +#endif + +#define PFX "cpufreq: " + +/* + * Duty Cycle (3bits), note DC_DISABLE is not specified in + * intel docs i just use it to mean disable + */ +enum { + DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT, + DC_64PT, DC_75PT, DC_88PT, DC_DISABLE +}; + +static int has_N44_O17_errata; +static int stock_freq; +MODULE_PARM(stock_freq, "i"); + +static unsigned int cpufreq_p4_initialised; + +static int cpufreq_p4_validatedc(unsigned int percent, unsigned int *pct) +{ + u32 l, h; + int dc, cpu = smp_processor_id(); + + /* FYI: Thermal monitor takes precedence and does a 50% DC modulation + * so we'll just return the thermal throttled settings to keep everybody + * happy. returning -EBUSY would have been better. + */ + rdmsr(MSR_IA32_THERM_STATUS, l, h); + if (l & 0x01) { + printk(KERN_INFO PFX "CPU#%d currently thermal throttled\n", cpu); + dc = DC_50PT; + *pct = 50; + goto done; + } + + switch (percent) { + default: + case DC_RESV: + case 1 ... 13: + dc = DC_DFLT; + *pct = 13; + break; + case 14 ... 25: + dc = DC_25PT; + *pct = 25; + break; + case 26 ... 38: + dc = DC_38PT; + *pct = 38; + break; + case 39 ... 50: + dc = DC_50PT; + *pct = 50; + break; + case 51 ... 64: + dc = DC_64PT; + *pct = 64; + break; + case 65 ... 75: + dc = DC_75PT; + *pct = 75; + break; + case 76 ... 88: + dc = DC_88PT; + *pct = 88; + break; + case 89 ... 100: + dc = DC_DISABLE; + *pct = 100; + break; + } + + if (has_N44_O17_errata && (dc == DC_25PT || dc == DC_DFLT)) { + dc = DC_38PT; + *pct = 38; + } + +done: + return dc; +} + +static int cpufreq_p4_setdc(unsigned int percent) +{ + u32 l, h; + int pct, dc, cpu = smp_processor_id(); + + dc = cpufreq_p4_validatedc(percent, &pct); + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + + if (dc == DC_DISABLE) { + printk(KERN_INFO PFX "CPU#%d disabling modulation\n", cpu); + wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + } else { + printk(KERN_INFO PFX "CPU#%d setting duty cycle to %d%%\n", cpu, pct); + wrmsr(MSR_IA32_THERM_CONTROL, l | (dc & 0x7) | (1<<4), h); + } + + return 0; +} + +static unsigned int cpufreq_p4_validate_speed(unsigned int khz) +{ + unsigned int percent, valid_percent, valid_khz; + + percent = (khz * 100) / stock_freq; + cpufreq_p4_validatedc(percent, &valid_percent); + valid_khz = (stock_freq * valid_percent) / 100; + + return valid_khz; +} + +static void cpufreq_p4_set_cpuspeed(unsigned int khz) +{ + unsigned int percent; + + percent = (khz * 100) / stock_freq; + cpufreq_p4_setdc(percent); +} + +int __init cpufreq_p4_init(void) +{ + u32 l, h; + struct cpuinfo_x86 *c = cpu_data; + int cpu = smp_processor_id(); + int cpuid; + int ret; + cpufreq_driver_t driver; + + /* + * THERM_CONTROL is architectural for IA32 now, so + * we can rely on the capability checks + */ + if (c->x86_vendor != X86_VENDOR_INTEL) + return -ENODEV; + + if (!test_bit(X86_FEATURE_ACPI, c->x86_capability) || + !test_bit(X86_FEATURE_ACC, c->x86_capability)) + return -ENODEV; + + /* Errata workarounds */ + cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; + switch (cpuid) { + case 0x0f07: + case 0x0f0a: + case 0x0f11: + case 0x0f12: + has_N44_O17_errata = 1; + default: + break; + } + + /* + * [ 63-5=Reserved | 4=EN | 3-2=DC | 0 ] + * DC - Clock modulation duty cycle + * EN - Enable clock modulation + */ + + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + wrmsr(MSR_IA32_THERM_CONTROL, l | (1<<4), h); + + printk(KERN_INFO PFX "CPU#%d P4/Xeon(TM) CPU On-Demand Clock Modulation available\n", cpu); + + driver.freq.cur=0; + driver.freq.min=0; + driver.freq.max=stock_freq; + driver.validate=&cpufreq_p4_validate_speed; + driver.setspeed=&cpufreq_p4_set_cpuspeed; + + ret = cpufreq_register(driver); + if (ret) { + return ret; + } + + cpufreq_p4_initialised = 1; + stock_freq = cpufreq_get(); /* ugg :( */ + + return 0; +} + + +void __exit cpufreq_p4_exit(void) +{ + u32 l, h; + + if (cpufreq_p4_initialised) { + cpufreq_unregister(); + /* return back to a non modulated state */ + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + cpufreq_p4_initialised = 0; + } +} + +MODULE_AUTHOR ("Zwane Mwaikambo "); +MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_p4_init); +module_exit(cpufreq_p4_exit); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/cpufreq/powernow-k6.c linux-2.5/arch/i386/kernel/cpu/cpufreq/powernow-k6.c --- linux-2.5.23/arch/i386/kernel/cpu/cpufreq/powernow-k6.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/cpufreq/powernow-k6.c Wed Jun 19 08:06:37 2002 @@ -0,0 +1,123 @@ +/* + * $Id: powernow-k6.c,v 1.18 2002/06/12 14:37:27 db Exp $ + * This file is part of Powertweak Linux (http://www.powertweak.org) + * and is shared with the Linux Kernel module. + * + * (C) 2000, 2001 Dave Jones, Arjan van de Ven, Janne Pänkälä. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * Version $Id: powernow-k6.c,v 1.18 2002/06/12 14:37:27 db Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long cpu_khz=350000; + +/* Clock ratio multiplied by 10 */ +static int clock_ratio[8] = { + 45, /* 000 -> 4.5x */ + 50, /* 001 -> 5.0x */ + 40, /* 010 -> 4.0x */ + 55, /* 011 -> 5.5x */ + 20, /* 100 -> 2.0x */ + 30, /* 101 -> 3.0x */ + 60, /* 110 -> 6.0x */ + 35 /* 111 -> 3.5x */ +}; + +static unsigned int clock_bogomips[8]; + +static unsigned int busfreq; +unsigned int minfreq,maxfreq; + +void set_cpu_frequency_K6(unsigned int Mhz) +{ + int i; + unsigned int best=200; /* safe initial values */ + unsigned int besti=4; + unsigned long outvalue=0,invalue=0; + unsigned long msrval; + + /* Find out which bit-pattern we want */ + + for (i=0;i<8;i++) { + unsigned int newclock; + newclock = (clock_ratio[i]*busfreq/10); + if ((newclock > best) && (newclock <= (Mhz+1))) { + /* +1 is for compensating rounding errors */ + best = newclock; + besti = i; + } + } + + /* "besti" now contains the bitpattern of the new multiplier. + we now need to transform it to the BVC format, see AMD#23446 */ + + outvalue = (1<<12) | (1<<10) | (1<<9) | (besti<<5); + + msrval = 0xFFF1; /* FIXME!! we should check if 0xfff0 is available */ + wrmsr(0xC0000086,msrval,0); /* enable the PowerNow port */ + invalue=inl(0xfff8); + invalue = invalue & 15; + outvalue = outvalue | invalue; + outl(outvalue ,0xFFF8); + msrval = 0xFFF0; + wrmsr(0xC0000086,msrval,0); /* disable it again */ + + /* now adjust bogomips */ + if (!clock_bogomips[besti]) { + /*scale_bogomips(clock_ratio[besti]);*/ + clock_bogomips[besti] = loops_per_jiffy; + } else { + loops_per_jiffy = clock_bogomips[besti]; + } +} + +static int get_cpu_multiplier(void) +{ + unsigned long invalue=0,msrval; + + + msrval = 0xFFF1; /* FIXME!! we should check if 0xfff0 is available */ + wrmsr(0xC0000086, msrval,0 ); /* enable the PowerNow port */ + invalue=inl(0xfff8); + msrval = 0xFFF0; + wrmsr(0xC0000086, msrval,0 ); /* disable it again */ + + printk("Clock ratio is %i\n",clock_ratio[(invalue >> 5)&7]); + return clock_ratio[(invalue >> 5)&7]; +} + +int PowerNow_k6plus_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) || + ((c->x86_model != 12) && (c->x86_model != 13))) + return -ENODEV; + + busfreq = cpu_khz / get_cpu_multiplier() / 100; + //cpufreq_init(0, 0, 0); + return 0; +} + +void PowerNow_k6plus_exit(void) +{ +} + +MODULE_AUTHOR ("Arjan van de Ven , Dave Jones "); +MODULE_DESCRIPTION ("Longhaul driver for AMD K6-2+ / K6-3+ processors."); + +MODULE_LICENSE ("GPL"); +module_init(PowerNow_k6plus_init); +module_exit(PowerNow_k6plus_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/cpufreq/speedstep.c linux-2.5/arch/i386/kernel/cpu/cpufreq/speedstep.c --- linux-2.5.23/arch/i386/kernel/cpu/cpufreq/speedstep.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/cpufreq/speedstep.c Wed Jun 19 08:06:37 2002 @@ -0,0 +1,601 @@ +/* + * $Id: speedstep.c,v 1.27 2002/06/12 14:37:27 db Exp $ + * + * (C) 2001 Dave Jones, Arjan van de ven. + * (C) 2002 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon reverse engineered information, and on Intel documentation + * for chipsets ICH2-M and ICH3-M. + * + * Many thanks to Ducrot Bruno for finding and fixing the last + * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler + * for extensive testing. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + * + * Version $Id: speedstep.c,v 1.27 2002/06/12 14:37:27 db Exp $ + */ + + +/********************************************************************* + * SPEEDSTEP - DEFINITIONS * + *********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* speedstep_chipset: + * It is necessary to know which chipset is used. As accesses to + * this device occur at various places in this module, we need a + * static struct pci_dev * pointing to that device. + */ +static unsigned int speedstep_chipset; +static struct pci_dev *speedstep_chipset_dev; + +#define SPEEDSTEP_CHIPSET_ICH2M 0x00000002 +#define SPEEDSTEP_CHIPSET_ICH3M 0x00000003 +#define SPEEDSTEP_CHIPSET_PIIX4 0x00000004 + + +/* speedstep_processor + */ +static unsigned int speedstep_processor; + +#define SPEEDSTEP_PROCESSOR_PIII_C 0x00000001 /* Coppermine core */ +#define SPEEDSTEP_PROCESSOR_PIII_T 0x00000002 /* Tulatin core */ + + +/* speedstep_[low,high]_freq + * There are only two frequency states for each processor. Values + * are in kHz for the time being. + */ +static unsigned int speedstep_low_freq; +static unsigned int speedstep_high_freq; + + +/* DEBUG + * Undefine it if you do not want verbose debug output + */ +#define SPEEDSTEP_DEBUG + +#ifdef SPEEDSTEP_DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0); +#endif + + + +/********************************************************************* + * LOW LEVEL CHIPSET INTERFACE * + *********************************************************************/ + +/* + * speedstep_get_frequency: + * Tries to read the SpeedStep state. Returns -EIO when there has been + * trouble to read the status or write to the control register, -EINVAL + * on an unsupported chipset, and zero on success. + */ +static int speedstep_get_frequency (unsigned int *freq) +{ + u32 pmbase; + u8 value; + + if (!speedstep_chipset_dev || !freq) + return -EINVAL; + + switch (speedstep_chipset) { + case SPEEDSTEP_CHIPSET_ICH2M: + case SPEEDSTEP_CHIPSET_ICH3M: + /* get PMBASE */ + pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); + if (!(pmbase & 0x01)) + return -EIO; + + pmbase &= 0xFFFFFFFE; + if (!pmbase) + return -EIO; + + /* read state */ + local_irq_disable(); + value = inb(pmbase + 0x50); + local_irq_enable(); + + dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + *freq = (value & 0x01) ? speedstep_low_freq : \ + speedstep_high_freq; + return 0; + + } + + printk (KERN_ERR "cpufreq: setting CPU frequency on this chipset unsupported.\n"); + return -EINVAL; +} + + +/* + * speedstep_set_frequency: + * Tries to change the SpeedStep state. + */ +void speedstep_set_frequency (unsigned int freq) +{ + u32 pmbase; + u8 pm2_blk; + u8 value; + unsigned long flags; + + if (!speedstep_chipset_dev || !freq) { + printk(KERN_ERR "cpufreq: unknown chipset or state\n"); + return; + } + + switch (speedstep_chipset) { + case SPEEDSTEP_CHIPSET_ICH2M: + case SPEEDSTEP_CHIPSET_ICH3M: + /* get PMBASE */ + pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); + if (!(pmbase & 0x01)) + return; + + pmbase &= 0xFFFFFFFE; + if (!pmbase) + return; + + /* read state */ + local_irq_disable(); + value = inb(pmbase + 0x50); + local_irq_enable(); + + dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + /* write new state, but only if indeed a transition + * is necessary */ + if (freq == ((value & 0x01) ? speedstep_low_freq : \ + speedstep_high_freq)) + return; + + value = (freq == speedstep_high_freq) ? 0x00 : 0x01; + + dprintk(KERN_DEBUG "cpufreq: writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); + + /* Disable IRQs */ + local_irq_save(flags); + local_irq_disable(); + + /* Disable bus master arbitration */ + pm2_blk = inb(pmbase + 0x20); + pm2_blk |= 0x01; + outb(pm2_blk, (pmbase + 0x20)); + + /* Actual transition */ + outb(value, (pmbase + 0x50)); + + /* Restore bus master arbitration */ + pm2_blk &= 0xfe; + outb(pm2_blk, (pmbase + 0x20)); + + /* Enable IRQs */ + local_irq_enable(); + local_irq_restore(flags); + + /* check if transition was sucessful */ + local_irq_disable(); + value = inb(pmbase + 0x50); + local_irq_enable(); + + dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + if (freq == ((value & 0x01) ? speedstep_low_freq : \ + speedstep_high_freq)) { + dprintk (KERN_INFO "cpufreq: change to %u MHz succeded\n", (freq / 1000)); + return; + } + + printk (KERN_ERR "cpufreq: change failed - I/O error\n"); + return; + } + + printk (KERN_ERR "cpufreq: setting CPU frequency on this chipset unsupported.\n"); + return; +} + + +/* + * speedstep_activate: + * Tries to activate the SpeedStep status and control registers. + * Returns -EINVAL on an unsupported chipset, and zero on success. + */ +static int speedstep_activate (void) +{ + if (!speedstep_chipset_dev) + return -EINVAL; + + switch (speedstep_chipset) { + case SPEEDSTEP_CHIPSET_ICH2M: + case SPEEDSTEP_CHIPSET_ICH3M: + { + u16 value = 0; + + pci_read_config_word(speedstep_chipset_dev, + 0x00A0, &value); + if (!(value & 0x08)) { + value |= 0x08; + dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n"); + pci_write_config_word(speedstep_chipset_dev, + 0x00A0, value); + } + + return 0; + } + case SPEEDSTEP_CHIPSET_PIIX4: + { + printk (KERN_ERR "cpufreq: SpeedStep (TM) on PIIX4 not yet supported.\n"); + return -EINVAL; + } + } + + printk (KERN_ERR "cpufreq: SpeedStep (TM) on this chipset unsupported.\n"); + return -EINVAL; +} + + +/* + * speedstep_detect_chipset: + * Detects PIIX4, ICH2-M and ICH3-M so far. The pci_dev points to + * the LPC bridge / PM module which contains all power-management + * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected + * chipset, or zero on failure. + */ +static unsigned int speedstep_detect_chipset (void) +{ + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801CA_12, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return SPEEDSTEP_CHIPSET_ICH3M; + + + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801BA_10, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return SPEEDSTEP_CHIPSET_ICH2M; + + + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return SPEEDSTEP_CHIPSET_PIIX4; + + return 0; +} + + + +/********************************************************************* + * LOW LEVEL PROCESSOR INTERFACE * + *********************************************************************/ + + +/* + * pentium6_get_fsb: + * Returns the Front Side Bus speed of the processor (in MHz). + */ +static inline unsigned int pentium6_get_fsb (void) +{ + /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */ + struct { + unsigned int value; /* Front Side Bus speed in MHz */ + u8 bitmap; /* power on configuration bits [18: 19] + (in MSR 0x2a) */ + } msr_decode_fsb [] = { + { 66, 0x0 }, + { 100, 0x2 }, + { 133, 0x1 }, + { 0, 0xf } + }; + u32 msr_lo, msr_hi; + int i = 0; + + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); + + msr_lo &= 0x00c0000; + msr_lo >>= 18; + + while (msr_lo != msr_decode_fsb[i].bitmap) { + if (msr_decode_fsb[i].bitmap == 0xff) + return -EINVAL; + i++; + } + + return msr_decode_fsb[i].value; +} + + +/* + * pentium6_get_ratio: + * Detects the current processor frequency multiplier ratio. + * Returns 10 times the value to properly manage .5 settings. + */ +static inline unsigned int pentium6_get_ratio(void) +{ + /* Intel processor frequency multipliers: + * See table 14 of p3_ds.pdf and table 22 of 29834003.pdf + */ + struct { + unsigned int ratio; /* Frequency Multiplier (x10) */ + u8 bitmap; /* power on configuration bits + [27, 25:22] (in MSR 0x2a) */ + } msr_decode_mult [] = { + { 30, 0x01 }, + { 35, 0x05 }, + { 40, 0x02 }, + { 45, 0x06 }, + { 50, 0x00 }, + { 55, 0x04 }, + { 60, 0x0b }, + { 65, 0x0f }, + { 70, 0x09 }, + { 75, 0x0d }, + { 80, 0x0a }, + { 85, 0x26 }, + { 90, 0x20 }, + { 100, 0x2b }, + { 0, 0xff } /* error or unknown value */ + }; + u32 msr_lo, msr_hi; + int i = 0; + struct cpuinfo_x86 *c = cpu_data; + + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); + + /* decode value */ + if ((c->x86_model == 0x08) && (c->x86_mask == 0x01)) + /* different on early Coppermine PIII */ + msr_lo &= 0x03c00000; + else + msr_lo &= 0x0bc00000; + + msr_lo >>= 22; + while (msr_lo != msr_decode_mult[i].bitmap) { + if (msr_decode_mult[i].bitmap == 0xff) + return -EINVAL; + i++; + } + + return msr_decode_mult[i].ratio; +} + + +/* + * speedstep_detect_processor: + * Returns the SPEEDSTEP_PROCESSOR_-number for the detected chipset, + * or zero on failure. + */ +static unsigned int speedstep_detect_processor (void) +{ + struct cpuinfo_x86 *c = cpu_data; + u32 ebx; + int check = 0; + + /* TBD: what about P4-M? */ + if ((c->x86_vendor != X86_VENDOR_INTEL) || (c->x86 != 6)) + return 0; + + switch (c->x86_model) { + case 0x0B: /* Intel PIII [Tulatin] */ + /* cpuid_ebx(1) is 0x04 for desktop PIII, + 0x06 for mobile PIII-M */ + ebx = cpuid_ebx(0x00000001); + + ebx &= 0x000000FF; + if (ebx != 0x06) + return 0; + + /* So far all PIII-M processors support SpeedStep. See + * Intel's 24540628.pdf of March 2002 + */ + + return SPEEDSTEP_PROCESSOR_PIII_T; + + case 0x08: /* Intel PIII [Coppermine] */ + /* all mobile PIII Coppermines have FSB 100 MHz */ + if (pentium6_get_fsb() != 100) + return 0; + + /* Unfortunatey, no information exists on how to check + * whether the processor is capable of SpeedStep. On + * processors that don't support it, doing such + * transitions might be harmful. So the user has to + * override this safety abort. + */ + +/* ---> */ check = 1; /* remove this line to enable SpeedStep. */ + /* See the comment above on why this check + * is necessary - Sorry for the inconvenience! + */ + + if (check) { + printk(KERN_INFO "cpufreq: Intel PIII (Coppermine) detected. If you are sure this is a\n"); + printk(KERN_INFO "cpufreq: SpeedStep capable processor, please remove line %u in\n", (__LINE__ - 7)); + printk(KERN_INFO "cpufreq: linux/arch/i386/kernel/cpufreq/speedstep.c.\n"); + return 0; + } + + return SPEEDSTEP_PROCESSOR_PIII_C; + + default: + return 0; + } +} + + + +/********************************************************************* + * HIGH LEVEL FUNCTIONS * + *********************************************************************/ + +/* + * speedstep_detect_speeds: + * Detects the low and high CPU frequencies in kHz. Returns 0 on + * success or -EINVAL / -EIO on problems. + */ +static int speedstep_detect_speeds (void) +{ + unsigned int state; + unsigned int fsb; + int i; + int result; + + fsb = pentium6_get_fsb(); + + for (i=0; i<2; i++) { + /* read the current state */ + result = speedstep_get_frequency(&state); + if (result) + return result; + + /* save the correct value, and switch to other */ + if (state == speedstep_low_freq) { + speedstep_low_freq = + pentium6_get_ratio() * fsb * 100; + speedstep_set_frequency(speedstep_high_freq); + } else { + speedstep_high_freq = + pentium6_get_ratio() * fsb * 100; + speedstep_set_frequency(speedstep_low_freq); + } + } + + if (!speedstep_low_freq || !speedstep_high_freq) + return -EIO; + else + return 0; +} + + +/* + * speedstep_validate_frequency: + * makes sure the CPU frequency to be set is valid. + */ +unsigned int speedstep_validate_frequency(unsigned int kHz) +{ + if (((int) (kHz - speedstep_low_freq)) < + ((int) (speedstep_high_freq - kHz))) + return speedstep_low_freq; + else + return speedstep_high_freq; +} + + +/* + * speedstep_init: + * Initializes the SpeedStep support. Returns -ENODEV on unsupported + * devices, -EINVAL on problems during initiatization, and zero on + * success. + */ +static int __init speedstep_init(void) +{ + int result; + unsigned int speed; + cpufreq_driver_t driver; + + printk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) support $Revision: 1.27 $\n"); + + /* detect processor */ + speedstep_processor = speedstep_detect_processor(); + + /* detect chipset */ + speedstep_chipset = speedstep_detect_chipset(); + if ((!speedstep_chipset) || (!speedstep_processor)) { + printk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this %s not (yet) available.\n", speedstep_processor ? "chipset" : "processor"); + return -ENODEV; + } + + /* startup values, correct ones will be detected later */ + speedstep_low_freq = 1; + speedstep_high_freq = 2; + + /* define method to be used */ + dprintk(KERN_DEBUG "cpufreq: chipset 0x%x - processor 0x%x\n", + speedstep_chipset, speedstep_processor); + + /* activate speedstep support */ + result = speedstep_activate(); + if (result) { + speedstep_chipset = 0; + return result; + } + + /* detect low and high frequency */ + result = speedstep_detect_speeds(); + if (result) { + speedstep_chipset = 0; + return result; + } + + /* get current speed setting */ + result = speedstep_get_frequency(&speed); + if (result) { + speedstep_chipset = 0; + return result; + } + + dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", + (speed == speedstep_low_freq) ? "low" : "high", + (speed / 1000)); + + /* initialization of main "cpufreq" code*/ + driver.freq.min = speedstep_low_freq; + driver.freq.max = speedstep_high_freq; + driver.freq.cur = speed; + driver.validate = &speedstep_validate_frequency; + driver.setspeed = &speedstep_set_frequency; + + result = cpufreq_register(driver); + if (result) { + speedstep_chipset = 0; + return result; + } + + return 0; +} + + +/* + * speedstep_exit: + * Unregisters SpeedStep support. + */ +static void __exit speedstep_exit(void) +{ + if (speedstep_chipset) + cpufreq_unregister(); +} + + + +MODULE_AUTHOR ("Dave Jones , Dominik Brodowski "); +MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors."); +MODULE_LICENSE ("GPL"); +module_init(speedstep_init); +module_exit(speedstep_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/cyrix.c linux-2.5/arch/i386/kernel/cpu/cyrix.c --- linux-2.5.23/arch/i386/kernel/cpu/cyrix.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/arch/i386/kernel/cpu/cyrix.c Mon Jun 10 13:14:38 2002 @@ -2,8 +2,6 @@ #include #include #include -#include - #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/intel.c linux-2.5/arch/i386/kernel/cpu/intel.c --- linux-2.5.23/arch/i386/kernel/cpu/intel.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/arch/i386/kernel/cpu/intel.c Mon Jun 10 13:16:31 2002 @@ -62,8 +62,7 @@ static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c) { - if( test_bit(X86_FEATURE_PN, c->x86_capability) && - disable_x86_serial_nr ) { + if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) { /* Disable processor serial number */ unsigned long lo,hi; rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi); @@ -92,6 +91,26 @@ __setup("noht", P4_disable_ht); +/* + * P4 Xeon errata 037 workaround. + * Hardware prefetcher may cause stale data to be loaded into the cache. + */ +static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c) +{ + unsigned long lo, hi; + + if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) { + rdmsr (MSR_IA32_MISC_ENABLE, lo, hi); + if ((lo & (1<<9)) == 0) { + printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n"); + printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n"); + lo |= (1<<9); /* Disable hw prefetching */ + wrmsr (MSR_IA32_MISC_ENABLE, lo, hi); + } + } +} + + static void __init init_intel(struct cpuinfo_x86 *c) { char *p = NULL; @@ -266,7 +285,7 @@ strcpy(c->x86_model_id, p); #ifdef CONFIG_SMP - if (test_bit(X86_FEATURE_HT, c->x86_capability) && !disable_P4_HT) { + if (cpu_has(c, X86_FEATURE_HT) && !disable_P4_HT) { extern int phys_proc_id[NR_CPUS]; u32 eax, ebx, ecx, edx; @@ -315,12 +334,16 @@ too_many_siblings: if (disable_P4_HT) - clear_bit(X86_FEATURE_HT, c->x86_capability); + clear_bit(X86_FEATURE_HT, &c->x86_capability); #endif /* Disable the PN if appropriate */ squash_the_stupid_serial_number(c); + + /* Work around errata */ + Intel_errata_workarounds(c); } + static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/Makefile linux-2.5/arch/i386/kernel/cpu/mtrr/Makefile --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/Makefile Wed Jun 19 20:07:19 2002 @@ -0,0 +1,10 @@ +O_TARGET := built-in.o + +obj-y := main.o if.o generic.o state.o +obj-y += amd.o +obj-y += cyrix.o +obj-y += centaur.o + +export-objs := main.o + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/amd.c linux-2.5/arch/i386/kernel/cpu/mtrr/amd.c --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/amd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/amd.c Wed Jun 19 20:06:16 2002 @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include "mtrr.h" + +static void +amd_get_mtrr(unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type * type) +{ + unsigned long low, high; + + rdmsr(MSR_K6_UWCCR, low, high); + /* Upper dword is region 1, lower is region 0 */ + if (reg == 1) + low = high; + /* The base masks off on the right alignment */ + *base = (low & 0xFFFE0000) >> PAGE_SHIFT; + *type = 0; + if (low & 1) + *type = MTRR_TYPE_UNCACHABLE; + if (low & 2) + *type = MTRR_TYPE_WRCOMB; + if (!(low & 3)) { + *size = 0; + return; + } + /* + * This needs a little explaining. The size is stored as an + * inverted mask of bits of 128K granularity 15 bits long offset + * 2 bits + * + * So to get a size we do invert the mask and add 1 to the lowest + * mask bit (4 as its 2 bits in). This gives us a size we then shift + * to turn into 128K blocks + * + * eg 111 1111 1111 1100 is 512K + * + * invert 000 0000 0000 0011 + * +1 000 0000 0000 0100 + * *128K ... + */ + low = (~low) & 0x1FFFC; + *size = (low + 4) << (15 - PAGE_SHIFT); + return; +} + +static void amd_set_mtrr(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type) +/* [SUMMARY] Set variable MTRR register on the local CPU. + The register to set. + The base address of the region. + The size of the region. If this is 0 the region is disabled. + The type of the region. + If TRUE, do the change safely. If FALSE, safety measures should + be done externally. + [RETURNS] Nothing. +*/ +{ + u32 regs[2]; + + /* + * Low is MTRR0 , High MTRR 1 + */ + rdmsr(MSR_K6_UWCCR, regs[0], regs[1]); + /* + * Blank to disable + */ + if (size == 0) + regs[reg] = 0; + else + /* Set the register to the base, the type (off by one) and an + inverted bitmask of the size The size is the only odd + bit. We are fed say 512K We invert this and we get 111 1111 + 1111 1011 but if you subtract one and invert you get the + desired 111 1111 1111 1100 mask + + But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! */ + regs[reg] = (-size >> (15 - PAGE_SHIFT) & 0x0001FFFC) + | (base << PAGE_SHIFT) | (type + 1); + + /* + * The writeback rule is quite specific. See the manual. Its + * disable local interrupts, write back the cache, set the mtrr + */ + wbinvd(); + wrmsr(MSR_K6_UWCCR, regs[0], regs[1]); +} + +static int amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type) +{ + /* Apply the K6 block alignment and size rules + In order + o Uncached or gathering only + o 128K or bigger block + o Power of 2 block + o base suitably aligned to the power + */ + if (type > MTRR_TYPE_WRCOMB || size < (1 << (17 - PAGE_SHIFT)) + || (size & ~(size - 1)) - size || (base & (size - 1))) + return -EINVAL; + return 0; +} + +static struct mtrr_ops amd_mtrr_ops = { + vendor: X86_VENDOR_AMD, + set: amd_set_mtrr, + get: amd_get_mtrr, + get_free_region: generic_get_free_region, + validate_add_page: amd_validate_add_page, + have_wrcomb: positive_have_wrcomb, +}; + +int __init amd_init_mtrr(void) +{ + set_mtrr_ops(&amd_mtrr_ops); + return 0; +} + +//arch_initcall(amd_mtrr_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/centaur.c linux-2.5/arch/i386/kernel/cpu/mtrr/centaur.c --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/centaur.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/centaur.c Wed Jun 19 20:06:16 2002 @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include "mtrr.h" + +static struct { + unsigned long high; + unsigned long low; +} centaur_mcr[8]; + +static u8 centaur_mcr_reserved; +static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ + +/* + * Report boot time MCR setups + */ + +static int +centaur_get_free_region(unsigned long base, unsigned long size) +/* [SUMMARY] Get a free MTRR. + The starting (base) address of the region. + The size (in bytes) of the region. + [RETURNS] The index of the region on success, else -1 on error. +*/ +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + + max = num_var_ranges; + for (i = 0; i < max; ++i) { + if (centaur_mcr_reserved & (1 << i)) + continue; + mtrr_if->get(i, &lbase, &lsize, <ype); + if (lsize == 0) + return i; + } + return -ENOSPC; +} + +void +mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) +{ + centaur_mcr[mcr].low = lo; + centaur_mcr[mcr].high = hi; +} + +static void +centaur_get_mcr(unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type * type) +{ + *base = centaur_mcr[reg].high >> PAGE_SHIFT; + *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; + *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ + if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2)) + *type = MTRR_TYPE_UNCACHABLE; + if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25) + *type = MTRR_TYPE_WRBACK; + if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31) + *type = MTRR_TYPE_WRBACK; + +} + +static void centaur_set_mcr(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type) +{ + unsigned long low, high; + + if (size == 0) { + /* Disable */ + high = low = 0; + } else { + high = base << PAGE_SHIFT; + if (centaur_mcr_type == 0) + low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + else { + if (type == MTRR_TYPE_UNCACHABLE) + low = -size << PAGE_SHIFT | 0x02; /* NC */ + else + low = -size << PAGE_SHIFT | 0x09; /* WWO,WC */ + } + } + centaur_mcr[reg].high = high; + centaur_mcr[reg].low = low; + wrmsr(MSR_IDT_MCR0 + reg, low, high); +} +/* + * Initialise the later (saner) Winchip MCR variant. In this version + * the BIOS can pass us the registers it has used (but not their values) + * and the control register is read/write + */ + +static void __init +centaur_mcr1_init(void) +{ + unsigned i; + u32 lo, hi; + + /* Unfortunately, MCR's are read-only, so there is no way to + * find out what the bios might have done. + */ + + rdmsr(MSR_IDT_MCR_CTRL, lo, hi); + if (((lo >> 17) & 7) == 1) { /* Type 1 Winchip2 MCR */ + lo &= ~0x1C0; /* clear key */ + lo |= 0x040; /* set key to 1 */ + wrmsr(MSR_IDT_MCR_CTRL, lo, hi); /* unlock MCR */ + } + + centaur_mcr_type = 1; + + /* + * Clear any unconfigured MCR's. + */ + + for (i = 0; i < 8; ++i) { + if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) { + if (!(lo & (1 << (9 + i)))) + wrmsr(MSR_IDT_MCR0 + i, 0, 0); + else + /* + * If the BIOS set up an MCR we cannot see it + * but we don't wish to obliterate it + */ + centaur_mcr_reserved |= (1 << i); + } + } + /* + * Throw the main write-combining switch... + * However if OOSTORE is enabled then people have already done far + * cleverer things and we should behave. + */ + + lo |= 15; /* Write combine enables */ + wrmsr(MSR_IDT_MCR_CTRL, lo, hi); +} + +/* + * Initialise the original winchip with read only MCR registers + * no used bitmask for the BIOS to pass on and write only control + */ + +static void __init +centaur_mcr0_init(void) +{ + unsigned i; + + /* Unfortunately, MCR's are read-only, so there is no way to + * find out what the bios might have done. + */ + + /* Clear any unconfigured MCR's. + * This way we are sure that the centaur_mcr array contains the actual + * values. The disadvantage is that any BIOS tweaks are thus undone. + * + */ + for (i = 0; i < 8; ++i) { + if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) + wrmsr(MSR_IDT_MCR0 + i, 0, 0); + } + + wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); /* Write only */ +} + +/* + * Initialise Winchip series MCR registers + */ + +static void __init +centaur_mcr_init(void) +{ + struct set_mtrr_context ctxt; + + set_mtrr_prepare_save(&ctxt); + set_mtrr_cache_disable(&ctxt); + + if (boot_cpu_data.x86_model == 4) + centaur_mcr0_init(); + else if (boot_cpu_data.x86_model == 8 || boot_cpu_data.x86_model == 9) + centaur_mcr1_init(); + + set_mtrr_done(&ctxt); +} + +static int centaur_validate_add_page(unsigned long base, + unsigned long size, unsigned int type) +{ + /* + * FIXME: Winchip2 supports uncached + */ + if (type != MTRR_TYPE_WRCOMB && + (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) { + printk(KERN_WARNING + "mtrr: only write-combining%s supported\n", + centaur_mcr_type ? " and uncacheable are" + : " is"); + return -EINVAL; + } + return 0; +} + +static struct mtrr_ops centaur_mtrr_ops = { + vendor: X86_VENDOR_CENTAUR, + init: centaur_mcr_init, + set: centaur_set_mcr, + get: centaur_get_mcr, + get_free_region: centaur_get_free_region, + validate_add_page: centaur_validate_add_page, + have_wrcomb: positive_have_wrcomb, +}; + +int __init centaur_init_mtrr(void) +{ + set_mtrr_ops(¢aur_mtrr_ops); + return 0; +} + +//arch_initcall(centaur_init_mtrr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/changelog linux-2.5/arch/i386/kernel/cpu/mtrr/changelog --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/changelog Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/changelog Wed Jun 19 18:15:58 2002 @@ -0,0 +1,229 @@ + ChangeLog + + Prehistory Martin Tischhäuser + Initial register-setting code (from proform-1.0). + 19971216 Richard Gooch + Original version for /proc/mtrr interface, SMP-safe. + v1.0 + 19971217 Richard Gooch + Bug fix for ioctls()'s. + Added sample code in Documentation/mtrr.txt + v1.1 + 19971218 Richard Gooch + Disallow overlapping regions. + 19971219 Jens Maurer + Register-setting fixups. + v1.2 + 19971222 Richard Gooch + Fixups for kernel 2.1.75. + v1.3 + 19971229 David Wragg + Register-setting fixups and conformity with Intel conventions. + 19971229 Richard Gooch + Cosmetic changes and wrote this ChangeLog ;-) + 19980106 Richard Gooch + Fixups for kernel 2.1.78. + v1.4 + 19980119 David Wragg + Included passive-release enable code (elsewhere in PCI setup). + v1.5 + 19980131 Richard Gooch + Replaced global kernel lock with private spinlock. + v1.6 + 19980201 Richard Gooch + Added wait for other CPUs to complete changes. + v1.7 + 19980202 Richard Gooch + Bug fix in definition of for UP. + v1.8 + 19980319 Richard Gooch + Fixups for kernel 2.1.90. + 19980323 Richard Gooch + Move SMP BIOS fixup before secondary CPUs call + v1.9 + 19980325 Richard Gooch + Fixed test for overlapping regions: confused by adjacent regions + 19980326 Richard Gooch + Added wbinvd in . + 19980401 Richard Gooch + Bug fix for non-SMP compilation. + 19980418 David Wragg + Fixed-MTRR synchronisation for SMP and use atomic operations + instead of spinlocks. + 19980418 Richard Gooch + Differentiate different MTRR register classes for BIOS fixup. + v1.10 + 19980419 David Wragg + Bug fix in variable MTRR synchronisation. + v1.11 + 19980419 Richard Gooch + Fixups for kernel 2.1.97. + v1.12 + 19980421 Richard Gooch + Safer synchronisation across CPUs when changing MTRRs. + v1.13 + 19980423 Richard Gooch + Bugfix for SMP systems without MTRR support. + v1.14 + 19980427 Richard Gooch + Trap calls to and on non-MTRR machines. + v1.15 + 19980427 Richard Gooch + Use atomic bitops for setting SMP change mask. + v1.16 + 19980428 Richard Gooch + Removed spurious diagnostic message. + v1.17 + 19980429 Richard Gooch + Moved register-setting macros into this file. + Moved setup code from init/main.c to i386-specific areas. + v1.18 + 19980502 Richard Gooch + Moved MTRR detection outside conditionals in . + v1.19 + 19980502 Richard Gooch + Documentation improvement: mention Pentium II and AGP. + v1.20 + 19980521 Richard Gooch + Only manipulate interrupt enable flag on local CPU. + Allow enclosed uncachable regions. + v1.21 + 19980611 Richard Gooch + Always define . + v1.22 + 19980901 Richard Gooch + Removed module support in order to tidy up code. + Added sanity check for / before . + Created addition queue for prior to SMP commence. + v1.23 + 19980902 Richard Gooch + Ported patch to kernel 2.1.120-pre3. + v1.24 + 19980910 Richard Gooch + Removed sanity checks and addition queue: Linus prefers an OOPS. + v1.25 + 19981001 Richard Gooch + Fixed harmless compiler warning in include/asm-i386/mtrr.h + Fixed version numbering and history for v1.23 -> v1.24. + v1.26 + 19990118 Richard Gooch + Added devfs support. + v1.27 + 19990123 Richard Gooch + Changed locking to spin with reschedule. + Made use of new . + v1.28 + 19990201 Zoltán Böszörményi + Extended the driver to be able to use Cyrix style ARRs. + 19990204 Richard Gooch + Restructured Cyrix support. + v1.29 + 19990204 Zoltán Böszörményi + Refined ARR support: enable MAPEN in set_mtrr_prepare() + and disable MAPEN in set_mtrr_done(). + 19990205 Richard Gooch + Minor cleanups. + v1.30 + 19990208 Zoltán Böszörményi + Protect plain 6x86s (and other processors without the + Page Global Enable feature) against accessing CR4 in + set_mtrr_prepare() and set_mtrr_done(). + 19990210 Richard Gooch + Turned and into function pointers. + v1.31 + 19990212 Zoltán Böszörményi + Major rewrite of cyrix_arr_init(): do not touch ARRs, + leave them as the BIOS have set them up. + Enable usage of all 8 ARRs. + Avoid multiplications by 3 everywhere and other + code clean ups/speed ups. + 19990213 Zoltán Böszörményi + Set up other Cyrix processors identical to the boot cpu. + Since Cyrix don't support Intel APIC, this is l'art pour l'art. + Weigh ARRs by size: + If size <= 32M is given, set up ARR# we were given. + If size > 32M is given, set up ARR7 only if it is free, + fail otherwise. + 19990214 Zoltán Böszörményi + Also check for size >= 256K if we are to set up ARR7, + mtrr_add() returns the value it gets from set_mtrr() + 19990218 Zoltán Böszörményi + Remove Cyrix "coma bug" workaround from here. + Moved to linux/arch/i386/kernel/setup.c and + linux/include/asm-i386/bugs.h + 19990228 Richard Gooch + Added MTRRIOC_KILL_ENTRY ioctl(2) + Trap for counter underflow in . + Trap for 4 MiB aligned regions for PPro, stepping <= 7. + 19990301 Richard Gooch + Created hook. + 19990305 Richard Gooch + Temporarily disable AMD support now MTRR capability flag is set. + v1.32 + 19990308 Zoltán Böszörményi + Adjust my changes (19990212-19990218) to Richard Gooch's + latest changes. (19990228-19990305) + v1.33 + 19990309 Richard Gooch + Fixed typo in message. + 19990310 Richard Gooch + Support K6-II/III based on Alan Cox's patches. + v1.34 + 19990511 Bart Hartgers + Support Centaur C6 MCR's. + 19990512 Richard Gooch + Minor cleanups. + v1.35 + 19990707 Zoltán Böszörményi + Check whether ARR3 is protected in cyrix_get_free_region() + and mtrr_del(). The code won't attempt to delete or change it + from now on if the BIOS protected ARR3. It silently skips ARR3 + in cyrix_get_free_region() or returns with an error code from + mtrr_del(). + 19990711 Zoltán Böszörményi + Reset some bits in the CCRs in cyrix_arr_init() to disable SMM + if ARR3 isn't protected. This is needed because if SMM is active + and ARR3 isn't protected then deleting and setting ARR3 again + may lock up the processor. With SMM entirely disabled, it does + not happen. + 19990812 Zoltán Böszörményi + Rearrange switch() statements so the driver accomodates to + the fact that the AMD Athlon handles its MTRRs the same way + as Intel does. + 19990814 Zoltán Böszörményi + Double check for Intel in mtrr_add()'s big switch() because + that revision check is only valid for Intel CPUs. + 19990819 Alan Cox + Tested Zoltan's changes on a pre production Athlon - 100% + success. + 19991008 Manfred Spraul + replaced spin_lock_reschedule() with a normal semaphore. + v1.36 + 20000221 Richard Gooch + Compile fix if procfs and devfs not enabled. + Formatting changes. + v1.37 + 20001109 H. Peter Anvin + Use the new centralized CPU feature detects. + + v1.38 + 20010309 Dave Jones + Add support for Cyrix III. + + v1.39 + 20010312 Dave Jones + Ugh, I broke AMD support. + Reworked fix by Troels Walsted Hansen + + v1.40 + 20010327 Dave Jones + Adapted Cyrix III support to include VIA C3. + + v2.0 + 20020306 Patrick Mochel + Split mtrr.c -> mtrr/*.c + Coverted to Linux Kernel Coding Style + Fixed several minor nits in form + Moved some SMP-only functions out, so they can be used + for power management in the future. + TODO: Fix user interface cruft. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/cyrix.c linux-2.5/arch/i386/kernel/cpu/mtrr/cyrix.c --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/cyrix.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/cyrix.c Wed Jun 19 21:35:14 2002 @@ -0,0 +1,378 @@ +#include +#include +#include +#include +#include +#include "mtrr.h" + +int arr3_protected; + +static void +cyrix_get_arr(unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type * type) +{ + unsigned long flags; + unsigned char arr, ccr3, rcr, shift; + + arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ + + /* Save flags and disable interrupts */ + local_irq_save(flags); + + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ + ((unsigned char *) base)[3] = getCx86(arr); + ((unsigned char *) base)[2] = getCx86(arr + 1); + ((unsigned char *) base)[1] = getCx86(arr + 2); + rcr = getCx86(CX86_RCR_BASE + reg); + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + + /* Enable interrupts if it was enabled previously */ + __restore_flags(flags); + shift = ((unsigned char *) base)[1] & 0x0f; + *base >>= PAGE_SHIFT; + + /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7 + * Note: shift==0xf means 4G, this is unsupported. + */ + if (shift) + *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1); + else + *size = 0; + + /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */ + if (reg < 7) { + switch (rcr) { + case 1: + *type = MTRR_TYPE_UNCACHABLE; + break; + case 8: + *type = MTRR_TYPE_WRBACK; + break; + case 9: + *type = MTRR_TYPE_WRCOMB; + break; + case 24: + default: + *type = MTRR_TYPE_WRTHROUGH; + break; + } + } else { + switch (rcr) { + case 0: + *type = MTRR_TYPE_UNCACHABLE; + break; + case 8: + *type = MTRR_TYPE_WRCOMB; + break; + case 9: + *type = MTRR_TYPE_WRBACK; + break; + case 25: + default: + *type = MTRR_TYPE_WRTHROUGH; + break; + } + } +} + +static int +cyrix_get_free_region(unsigned long base, unsigned long size) +/* [SUMMARY] Get a free ARR. + The starting (base) address of the region. + The size (in bytes) of the region. + [RETURNS] The index of the region on success, else -1 on error. +*/ +{ + int i; + mtrr_type ltype; + unsigned long lbase, lsize; + + /* If we are to set up a region >32M then look at ARR7 immediately */ + if (size > 0x2000) { + cyrix_get_arr(7, &lbase, &lsize, <ype); + if (lsize == 0) + return 7; + /* Else try ARR0-ARR6 first */ + } else { + for (i = 0; i < 7; i++) { + cyrix_get_arr(i, &lbase, &lsize, <ype); + if ((i == 3) && arr3_protected) + continue; + if (lsize == 0) + return i; + } + /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ + cyrix_get_arr(i, &lbase, &lsize, <ype); + if ((lsize == 0) && (size >= 0x40)) + return i; + } + return -ENOSPC; +} + +static void cyrix_set_arr(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type) +{ + unsigned char arr, arr_type, arr_size; + u32 cr0, ccr3; + u32 cr4 = 0; + + arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ + + /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */ + if (reg >= 7) + size >>= 6; + + size &= 0x7fff; /* make sure arr_size <= 14 */ + for (arr_size = 0; size; arr_size++, size >>= 1) ; + + if (reg < 7) { + switch (type) { + case MTRR_TYPE_UNCACHABLE: + arr_type = 1; + break; + case MTRR_TYPE_WRCOMB: + arr_type = 9; + break; + case MTRR_TYPE_WRTHROUGH: + arr_type = 24; + break; + default: + arr_type = 8; + break; + } + } else { + switch (type) { + case MTRR_TYPE_UNCACHABLE: + arr_type = 0; + break; + case MTRR_TYPE_WRCOMB: + arr_type = 8; + break; + case MTRR_TYPE_WRTHROUGH: + arr_type = 25; + break; + default: + arr_type = 9; + break; + } + } + + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if ( cpu_has_pge ) { + cr4 = read_cr4(); + write_cr4(cr4 & (unsigned char) ~(1 << 7)); + } + + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ + cr0 = read_cr0() | 0x40000000; + wbinvd(); + write_cr0(cr0); + wbinvd(); + + /* Cyrix ARRs - everything else were excluded at the top */ + ccr3 = getCx86(CX86_CCR3); + + /* Cyrix ARRs - everything else were excluded at the top */ + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); + + base <<= PAGE_SHIFT; + setCx86(arr, ((unsigned char *) &base)[3]); + setCx86(arr + 1, ((unsigned char *) &base)[2]); + setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size); + setCx86(CX86_RCR_BASE + reg, arr_type); + + /* Flush caches and TLBs */ + wbinvd(); + + /* Cyrix ARRs - everything else was excluded at the top */ + setCx86(CX86_CCR3, ccr3); + + /* Enable caches */ + write_cr0(read_cr0() & 0xbfffffff); + + /* Restore value of CR4 */ + if ( cpu_has_pge ) + write_cr4(cr4); +} + +typedef struct { + unsigned long base; + unsigned long size; + mtrr_type type; +} arr_state_t; + +arr_state_t arr_state[8] __initdata = { + {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, + {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL} +}; + +unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 }; + +static void __init +cyrix_arr_init_secondary(void) +{ + int i; + u32 cr0, ccr3, cr4 = 0; + + /* flush cache and enable MAPEN */ + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if ( cpu_has_pge ) { + cr4 = read_cr4(); + write_cr4(cr4 & (unsigned char) ~(1 << 7)); + } + + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ + cr0 = read_cr0() | 0x40000000; + wbinvd(); + write_cr0(cr0); + wbinvd(); + + /* Cyrix ARRs - everything else were excluded at the top */ + ccr3 = getCx86(CX86_CCR3); + + /* Cyrix ARRs - everything else were excluded at the top */ + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); + + /* the CCRs are not contiguous */ + for (i = 0; i < 4; i++) + setCx86(CX86_CCR0 + i, ccr_state[i]); + for (; i < 7; i++) + setCx86(CX86_CCR4 + i, ccr_state[i]); + for (i = 0; i < 8; i++) + cyrix_set_arr(i, arr_state[i].base, + arr_state[i].size, arr_state[i].type); + + /* Flush caches and TLBs */ + wbinvd(); + + /* Cyrix ARRs - everything else was excluded at the top */ + setCx86(CX86_CCR3, ccr3); + + /* Enable caches */ + write_cr0(read_cr0() & 0xbfffffff); + + /* Restore value of CR4 */ + if ( cpu_has_pge ) + write_cr4(cr4); +} + +/* + * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection + * with the SMM (System Management Mode) mode. So we need the following: + * Check whether SMI_LOCK (CCR3 bit 0) is set + * if it is set, write a warning message: ARR3 cannot be changed! + * (it cannot be changed until the next processor reset) + * if it is reset, then we can change it, set all the needed bits: + * - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset) + * - disable access to SMM memory (CCR1 bit 2 reset) + * - disable SMM mode (CCR1 bit 1 reset) + * - disable write protection of ARR3 (CCR6 bit 1 reset) + * - (maybe) disable ARR3 + * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set) + */ +static void __init +cyrix_arr_init(void) +{ + struct set_mtrr_context ctxt; + unsigned char ccr[7]; + int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 }; +#ifdef CONFIG_SMP + int i; +#endif + + /* flush cache and enable MAPEN */ + set_mtrr_prepare_save(&ctxt); + set_mtrr_cache_disable(&ctxt); + + /* Save all CCRs locally */ + ccr[0] = getCx86(CX86_CCR0); + ccr[1] = getCx86(CX86_CCR1); + ccr[2] = getCx86(CX86_CCR2); + ccr[3] = ctxt.ccr3; + ccr[4] = getCx86(CX86_CCR4); + ccr[5] = getCx86(CX86_CCR5); + ccr[6] = getCx86(CX86_CCR6); + + if (ccr[3] & 1) { + ccrc[3] = 1; + arr3_protected = 1; + } else { + /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and + * access to SMM memory through ARR3 (bit 7). + */ + if (ccr[1] & 0x80) { + ccr[1] &= 0x7f; + ccrc[1] |= 0x80; + } + if (ccr[1] & 0x04) { + ccr[1] &= 0xfb; + ccrc[1] |= 0x04; + } + if (ccr[1] & 0x02) { + ccr[1] &= 0xfd; + ccrc[1] |= 0x02; + } + arr3_protected = 0; + if (ccr[6] & 0x02) { + ccr[6] &= 0xfd; + ccrc[6] = 1; /* Disable write protection of ARR3 */ + setCx86(CX86_CCR6, ccr[6]); + } + /* Disable ARR3. This is safe now that we disabled SMM. */ + /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ + } + /* If we changed CCR1 in memory, change it in the processor, too. */ + if (ccrc[1]) + setCx86(CX86_CCR1, ccr[1]); + + /* Enable ARR usage by the processor */ + if (!(ccr[5] & 0x20)) { + ccr[5] |= 0x20; + ccrc[5] = 1; + setCx86(CX86_CCR5, ccr[5]); + } +#ifdef CONFIG_SMP + for (i = 0; i < 7; i++) + ccr_state[i] = ccr[i]; + for (i = 0; i < 8; i++) + cyrix_get_arr(i, + &arr_state[i].base, &arr_state[i].size, + &arr_state[i].type); +#endif + + set_mtrr_done(&ctxt); /* flush cache and disable MAPEN */ + + if (ccrc[5]) + printk("mtrr: ARR usage was not enabled, enabled manually\n"); + if (ccrc[3]) + printk("mtrr: ARR3 cannot be changed\n"); +/* + if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n"); + if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n"); + if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n"); +*/ + if (ccrc[6]) + printk("mtrr: ARR3 was write protected, unprotected\n"); +} + +static struct mtrr_ops cyrix_mtrr_ops = { + vendor: X86_VENDOR_CYRIX, + init: cyrix_arr_init, + init_secondary: cyrix_arr_init_secondary, + set: cyrix_set_arr, + get: cyrix_get_arr, + get_free_region: cyrix_get_free_region, + validate_add_page: generic_validate_add_page, + have_wrcomb: positive_have_wrcomb, +}; + +int __init cyrix_init_mtrr(void) +{ + set_mtrr_ops(&cyrix_mtrr_ops); + return 0; +} + +//arch_initcall(cyrix_init_mtrr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/generic.c linux-2.5/arch/i386/kernel/cpu/mtrr/generic.c --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/generic.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/generic.c Wed Jun 19 20:06:16 2002 @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include "mtrr.h" + + +int generic_get_free_region(unsigned long base, unsigned long size) +/* [SUMMARY] Get a free MTRR. + The starting (base) address of the region. + The size (in bytes) of the region. + [RETURNS] The index of the region on success, else -1 on error. +*/ +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + + max = num_var_ranges; + for (i = 0; i < max; ++i) { + mtrr_if->get(i, &lbase, &lsize, <ype); + if (lsize == 0) + return i; + } + return -ENOSPC; +} + + +void generic_get_mtrr(unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type * type) +{ + 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; + } + + 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; +} + +void generic_set_mtrr(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type) +/* [SUMMARY] Set variable MTRR register on the local CPU. + The register to set. + The base address of the region. + The size of the region. If this is 0 the region is disabled. + The type of the region. + If TRUE, do the change safely. If FALSE, safety measures should + be done externally. + [RETURNS] Nothing. +*/ +{ + u32 cr0, cr4 = 0; + u32 deftype_lo, deftype_hi; + + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if ( cpu_has_pge ) { + cr4 = read_cr4(); + write_cr4(cr4 & (unsigned char) ~(1 << 7)); + } + + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ + cr0 = read_cr0() | 0x40000000; + wbinvd(); + write_cr0(cr0); + wbinvd(); + + /* Save MTRR state */ + rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); + + /* Disable MTRRs, and set the default type to uncached */ + wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi); + + 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); + } 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)); + } + + /* Flush caches and TLBs */ + wbinvd(); + + /* Intel (P6) standard MTRRs */ + wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); + + /* Enable caches */ + write_cr0(read_cr0() & 0xbfffffff); + + /* Restore value of CR4 */ + if ( cpu_has_pge ) + write_cr4(cr4); +} + +int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type) +{ + unsigned long lbase, last; + + /* For Intel PPro stepping <= 7, must be 4 MiB aligned + and not touch 0x70000000->0x7003FFFF */ + if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model == 1 && + boot_cpu_data.x86_mask <= 7) { + if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) { + printk(KERN_WARNING + "mtrr: base(0x%lx000) is not 4 MiB aligned\n", + base); + return -EINVAL; + } + if (!(base + size < 0x70000000 || base > 0x7003FFFF) && + (type == MTRR_TYPE_WRCOMB + || type == MTRR_TYPE_WRBACK)) { + printk(KERN_WARNING + "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n"); + return -EINVAL; + } + } + + if (base + size < 0x100) { + printk(KERN_WARNING + "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n", + base, size); + return -EINVAL; + } + /* Check upper bits of base and last are equal and lower bits are 0 + for base and 1 for last */ + last = base + size - 1; + for (lbase = base; !(lbase & 1) && (last & 1); + lbase = lbase >> 1, last = last >> 1) ; + if (lbase != last) { + printk(KERN_WARNING + "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", + base, size); + return -EINVAL; + } + return 0; +} + + +int generic_have_wrcomb(void) +{ + unsigned long config, dummy; + rdmsr(MTRRcap_MSR, config, dummy); + return (config & (1 << 10)); +} + +int positive_have_wrcomb(void) +{ + return 1; +} + +/* generic structure... + */ +struct mtrr_ops generic_mtrr_ops = { + use_intel_if: 1, + init_secondary: generic_init_secondary, + get: generic_get_mtrr, + get_free_region: generic_get_free_region, + set: generic_set_mtrr, + validate_add_page: generic_validate_add_page, + have_wrcomb: generic_have_wrcomb, + +}; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/if.c linux-2.5/arch/i386/kernel/cpu/mtrr/if.c --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/if.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/if.c Wed Jun 19 19:33:27 2002 @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include +#include + +/* What kind of fucking hack is this? */ +#define MTRR_NEED_STRINGS + +#include +#include "mtrr.h" + +static char *ascii_buffer; +static unsigned int ascii_buf_bytes; + +extern unsigned int *usage_table; + +#define LINE_SIZE 80 + +static int +mtrr_file_add(unsigned long base, unsigned long size, + unsigned int type, char increment, struct file *file, int page) +{ + int reg, max; + unsigned int *fcount = file->private_data; + + max = num_var_ranges; + if (fcount == NULL) { + if ((fcount = + kmalloc(max * sizeof *fcount, GFP_KERNEL)) == NULL) { + printk("mtrr: could not allocate\n"); + return -ENOMEM; + } + memset(fcount, 0, max * sizeof *fcount); + file->private_data = fcount; + } + 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; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + } + reg = mtrr_add_page(base, size, type, 1); + if (reg >= 0) + ++fcount[reg]; + return reg; +} + +static int +mtrr_file_del(unsigned long base, unsigned long size, + struct file *file, int page) +{ + int reg; + unsigned int *fcount = file->private_data; + + 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; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + } + 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; +} + +static ssize_t +mtrr_read(struct file *file, char *buf, size_t len, loff_t * ppos) +{ + if (*ppos >= ascii_buf_bytes) + return 0; + if (*ppos + len > ascii_buf_bytes) + len = ascii_buf_bytes - *ppos; + if (copy_to_user(buf, ascii_buffer + *ppos, len)) + return -EFAULT; + *ppos += len; + return len; +} + +static ssize_t +mtrr_write(struct file *file, const char *buf, size_t len, loff_t * ppos) +/* Format of control line: + "base=%Lx size=%Lx type=%s" OR: + "disable=%d" +*/ +{ + int i, err; + unsigned long reg; + unsigned long long base, size; + char *ptr; + char line[LINE_SIZE]; + + 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); + if (len > LINE_SIZE) + len = LINE_SIZE; + if (copy_from_user(line, buf, len - 1)) + return -EFAULT; + 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); + if (err < 0) + return err; + return len; + } + if (strncmp(line, "base=", 5)) { + printk("mtrr: no \"base=\" in line: \"%s\"\n", line); + return -EINVAL; + } + 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; + } + 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; + } + for (; isspace(*ptr); ++ptr) ; + if (strncmp(ptr, "type=", 5)) { + printk("mtrr: no \"type=\" in line: \"%s\"\n", line); + return -EINVAL; + } + ptr += 5; + for (; isspace(*ptr); ++ptr) ; + for (i = 0; i < MTRR_NUM_TYPES; ++i) { +// if (strcmp(ptr, mtrr_strings[i])) + continue; + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + err = + mtrr_add_page((unsigned long) base, (unsigned long) size, i, + 1); + if (err < 0) + return err; + 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) +{ + int err; + mtrr_type type; + struct mtrr_sentry sentry; + struct mtrr_gentry gentry; + + switch (cmd) { + default: + return -ENOIOCTLCMD; + case MTRRIOC_ADD_ENTRY: + 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 (!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 (!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 (!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); + if (err < 0) + return err; + break; + case MTRRIOC_GET_ENTRY: + if (copy_from_user(&gentry, (void *) arg, sizeof gentry)) + return -EFAULT; + if (gentry.regnum >= num_var_ranges) + return -EINVAL; + mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type); + + /* 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; + } + + if (copy_to_user((void *) arg, &gentry, sizeof gentry)) + return -EFAULT; + break; + case MTRRIOC_ADD_PAGE_ENTRY: + 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 (!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 (!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 (!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); + if (err < 0) + return err; + break; + case MTRRIOC_GET_PAGE_ENTRY: + if (copy_from_user(&gentry, (void *) arg, sizeof gentry)) + return -EFAULT; + if (gentry.regnum >= num_var_ranges) + return -EINVAL; + mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type); + gentry.type = type; + + if (copy_to_user((void *) arg, &gentry, sizeof gentry)) + return -EFAULT; + break; + } + return 0; +} + +static int +mtrr_close(struct inode *ino, struct file *file) +{ + int i, max; + unsigned int *fcount = file->private_data; + + if (fcount == NULL) + return 0; + max = 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]; + } + } + 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, + release:mtrr_close, +}; + +# ifdef CONFIG_PROC_FS + +static struct proc_dir_entry *proc_root_mtrr; + +# endif /* CONFIG_PROC_FS */ + +static devfs_handle_t devfs_handle; + +char * attrib_to_str(int x) +{ + return (x <= 6) ? mtrr_strings[x] : "?"; +} + +void compute_ascii(void) +{ + char factor; + int i, max; + mtrr_type type; + unsigned long base, size; + + ascii_buf_bytes = 0; + max = num_var_ranges; + for (i = 0; i < max; i++) { + mtrr_if->get(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; + } else { + factor = 'M'; + size >>= 20 - PAGE_SHIFT; + } + sprintf + (ascii_buffer + ascii_buf_bytes, + "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n", + i, base, base >> (20 - PAGE_SHIFT), size, factor, + attrib_to_str(type), usage_table[i]); + ascii_buf_bytes += + strlen(ascii_buffer + ascii_buf_bytes); + } + } + devfs_set_file_size(devfs_handle, ascii_buf_bytes); +# ifdef CONFIG_PROC_FS + if (proc_root_mtrr) + proc_root_mtrr->size = ascii_buf_bytes; +# endif /* CONFIG_PROC_FS */ +} + +static int __init mtrr_if_init(void) +{ + int max = num_var_ranges; + + if ((ascii_buffer = kmalloc(max * LINE_SIZE, GFP_KERNEL)) == NULL) { + printk("mtrr: could not allocate\n"); + return -ENOMEM; + } + ascii_buf_bytes = 0; + compute_ascii(); +#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; + } +#endif +#ifdef USERSPACE_INTERFACE + devfs_handle = devfs_register(NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, + S_IFREG | S_IRUGO | S_IWUSR, + &mtrr_fops, NULL); +#endif + return 0; +} + +arch_initcall(mtrr_if_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/main.c linux-2.5/arch/i386/kernel/cpu/mtrr/main.c --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/main.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/main.c Wed Jun 19 19:32:23 2002 @@ -0,0 +1,627 @@ +/* Generic MTRR (Memory Type Range Register) driver. + + Copyright (C) 1997-2000 Richard Gooch + Copyright (c) 2002 Patrick Mochel + + 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. + + Richard Gooch may be reached by email at rgooch@atnf.csiro.au + The postal address is: + Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. + + Source: "Pentium Pro Family Developer's Manual, Volume 3: + Operating System Writer's Guide" (Intel document number 242692), + section 11.11.7 + + This was cleaned and made readable by Patrick Mochel + on 6-7 March 2002. + Source: Intel Architecture Software Developers Manual, Volume 3: + System Programming Guide; Section 9.11. (1997 edition - PPro). +*/ + +#include +#include +#include + +#define MTRR_NEED_STRINGS +#include + +#include +#include +#include +#include "mtrr.h" + +#define MTRR_VERSION "2.0 (20020519)" + +u32 num_var_ranges = 0; + +unsigned int *usage_table; +static DECLARE_MUTEX(main_lock); + +u32 size_or_mask, size_and_mask; + +static struct mtrr_ops * mtrr_ops[X86_VENDOR_NUM] = {}; +struct mtrr_ops * mtrr_if = NULL; + +__initdata char *mtrr_if_name[] = { + "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR" +}; + +static void set_mtrr(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type); + +static unsigned int arr3_protected; + +void set_mtrr_ops(struct mtrr_ops * ops) +{ + if (ops->vendor && ops->vendor < X86_VENDOR_NUM) + mtrr_ops[ops->vendor] = ops; +} + +/* Returns non-zero if we have the write-combining memory type */ +static int have_wrcomb(void) +{ + struct pci_dev *dev = NULL; + + /* WTF is this? + * Someone, please shoot me. + */ + + /* ServerWorks LE chipsets have problems with write-combining + Don't allow it and leave room for other chipsets to be tagged */ + + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { + if ((dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && + (dev->device == PCI_DEVICE_ID_SERVERWORKS_LE)) { + printk(KERN_INFO + "mtrr: Serverworks LE detected. Write-combining disabled.\n"); + return 0; + } + } + return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0); +} + +/* This function returns the number of variable MTRRs */ +void __init set_num_var_ranges(void) +{ + unsigned long config = 0, dummy; + + if (use_intel()) { + rdmsr(MTRRcap_MSR, config, dummy); + } else if (is_cpu(AMD)) + config = 2; + else if (is_cpu(CYRIX) || is_cpu(CENTAUR)) + config = 8; + num_var_ranges = config & 0xff; +} + +static char * attrib_to_str(int x) +{ + return (x <= 6) ? mtrr_strings[x] : "?"; +} + +static void init_table(void) +{ + int i, max; + + max = num_var_ranges; + if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL)) + == NULL) { + 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(); +#endif +} + +struct set_mtrr_data { + atomic_t count; + atomic_t gate; + unsigned long smp_base; + unsigned long smp_size; + unsigned int smp_reg; + mtrr_type smp_type; +}; + +#ifdef CONFIG_SMP + +static void ipi_handler(void *info) +/* [SUMMARY] Synchronisation handler. Executed by "other" CPUs. + [RETURNS] Nothing. +*/ +{ + struct set_mtrr_data *data = info; + unsigned long flags; + + local_irq_save(flags); + + atomic_dec(&data->count); + while(!atomic_read(&data->gate)) { + cpu_relax(); + barrier(); + } + + /* The master has cleared me to execute */ + mtrr_if->set(data->smp_reg, data->smp_base, + data->smp_size, data->smp_type); + + atomic_dec(&data->count); + while(atomic_read(&data->gate)) { + cpu_relax(); + barrier(); + } + local_irq_restore(flags); +} + +#endif + +/** + * set_mtrr - update mtrrs on all processors + * @reg: mtrr in question + * @base: mtrr base + * @size: mtrr size + * @type: mtrr type + * + * This is kinda tricky, but fortunately, Intel spelled it out for us cleanly: + * + * 1. Send IPI to do the following: + * 2. Disable Interrupts + * 3. Wait for all procs to do so + * 4. Enter no-fill cache mode + * 5. Flush caches + * 6. Clear PGE bit + * 7. Flush all TLBs + * 8. Disable all range registers + * 9. Update the MTRRs + * 10. Enable all range registers + * 11. Flush all TLBs and caches again + * 12. Enter normal cache mode and reenable caching + * 13. Set PGE + * 14. Wait for buddies to catch up + * 15. Enable interrupts. + * + * What does that mean for us? Well, first we set data.count to the number + * of CPUs. As each CPU disables interrupts, it'll decrement it once. We wait + * until it hits 0 and proceed. We set the data.gate flag and reset data.count. + * Meanwhile, they are waiting for that flag to be set. Once it's set, each + * CPU goes through the transition of updating MTRRs. The CPU vendors may each do it + * differently, so we call mtrr_if->set() callback and let them take care of it. + * When they're done, they again decrement data->count and wait for data.gate to + * be reset. + * When we finish, we wait for data.count to hit 0 and toggle the data.gate flag. + * Everyone then enables interrupts and we all continue on. + * + * Note that the mechanism is the same for UP systems, too; all the SMP stuff + * becomes nops. + */ +static void set_mtrr(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type) +{ + struct set_mtrr_data data; + unsigned long flags; + + data.smp_reg = reg; + data.smp_base = base; + data.smp_size = size; + data.smp_type = type; + atomic_set(&data.count, num_online_cpus() - 1); + atomic_set(&data.gate,0); + + /* 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"); + + local_irq_save(flags); + + while(atomic_read(&data.count)) { + cpu_relax(); + barrier(); + } + /* ok, reset count and toggle gate */ + atomic_set(&data.count, num_online_cpus() - 1); + atomic_set(&data.gate,1); + + /* do our MTRR business */ + mtrr_if->set(reg,base,size,type); + + /* wait for the others */ + while(atomic_read(&data.count)) { + cpu_relax(); + barrier(); + } + local_irq_restore(flags); + atomic_set(&data.gate,0); +} + +/** + * mtrr_add_page - Add a memory type region + * @base: Physical base address of region in pages (4 KB) + * @size: Physical size of region in pages (4 KB) + * @type: Type of MTRR desired + * @increment: If this is true do usage counting on the region + * + * Memory type region registers control the caching on newer Intel and + * non Intel processors. This function allows drivers to request an + * MTRR is added. The details and hardware specifics of each processor's + * implementation are hidden from the caller, but nevertheless the + * caller should expect to need to provide a power of two size on an + * equivalent power of two boundary. + * + * If the region cannot be added either because all regions are in use + * or the CPU cannot support it a negative value is returned. On success + * the register number for this entry is returned, but should be treated + * as a cookie only. + * + * On a multiprocessor machine the changes are made to all processors. + * This is required on x86 by the Intel processors. + * + * The available types are + * + * %MTRR_TYPE_UNCACHABLE - No caching + * + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever + * + * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts + * + * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes + * + * BUGS: Needs a quiet flag for the cases where drivers do not mind + * failures and do not wish system log messages to be sent. + */ + +int mtrr_add_page(unsigned long base, unsigned long size, + unsigned int type, char increment) +{ + int i; + mtrr_type ltype; + unsigned long lbase, lsize; + int error; + + if (!mtrr_if) + return -ENXIO; + + if ((error = mtrr_if->validate_add_page(base,size,type))) + return error; + + if (type >= MTRR_NUM_TYPES) { + printk("mtrr: type: %u illegal\n", type); + return -EINVAL; + } + + /* 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; + } + + if (base & size_or_mask || size & size_or_mask) { + printk("mtrr: base or size exceeds the MTRR width\n"); + return -EINVAL; + } + + error = -EINVAL; + + /* Search for existing MTRR */ + down(&main_lock); + for (i = 0; i < num_var_ranges; ++i) { + mtrr_if->get(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 */ + if ((base < lbase) || (base + size > lbase + lsize)) { + printk(KERN_WARNING + "mtrr: 0x%lx000,0x%lx000 overlaps existing" + " 0x%lx000,0x%lx000\n", base, size, lbase, + lsize); + goto out; + } + /* New region is enclosed by an existing region */ + if (ltype != type) { + if (type == MTRR_TYPE_UNCACHABLE) + continue; + printk ("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", + base, size, attrib_to_str(ltype), + attrib_to_str(type)); + goto out; + } + if (increment) + ++usage_table[i]; + compute_ascii(); + error = i; + goto out; + } + /* Search for an empty MTRR */ + i = mtrr_if->get_free_region(base, size); + if (i >= 0) { + set_mtrr(i, base, size, type); + usage_table[i] = 1; + compute_ascii(); + } else + printk("mtrr: no more MTRRs available\n"); + error = i; + out: + up(&main_lock); + return error; +} + +/** + * mtrr_add - Add a memory type region + * @base: Physical base address of region + * @size: Physical size of region + * @type: Type of MTRR desired + * @increment: If this is true do usage counting on the region + * + * Memory type region registers control the caching on newer Intel and + * non Intel processors. This function allows drivers to request an + * MTRR is added. The details and hardware specifics of each processor's + * implementation are hidden from the caller, but nevertheless the + * caller should expect to need to provide a power of two size on an + * equivalent power of two boundary. + * + * If the region cannot be added either because all regions are in use + * or the CPU cannot support it a negative value is returned. On success + * the register number for this entry is returned, but should be treated + * as a cookie only. + * + * On a multiprocessor machine the changes are made to all processors. + * This is required on x86 by the Intel processors. + * + * The available types are + * + * %MTRR_TYPE_UNCACHABLE - No caching + * + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever + * + * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts + * + * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes + * + * BUGS: Needs a quiet flag for the cases where drivers do not mind + * failures and do not wish system log messages to be sent. + */ + +int +mtrr_add(unsigned long base, unsigned long size, unsigned int type, + char increment) +{ + 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; + } + return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, + increment); +} + +/** + * mtrr_del_page - delete a memory type region + * @reg: Register returned by mtrr_add + * @base: Physical base address + * @size: Size of region + * + * If register is supplied then base and size are ignored. This is + * how drivers should call it. + * + * Releases an MTRR region. If the usage count drops to zero the + * register is freed and the region returns to default state. + * On success the register is returned, on failure a negative error + * code. + */ + +int mtrr_del_page(int reg, unsigned long base, unsigned long size) +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + int error = -EINVAL; + + if (!mtrr_if) + return -ENXIO; + + max = num_var_ranges; + down(&main_lock); + if (reg < 0) { + /* Search for existing MTRR */ + for (i = 0; i < max; ++i) { + mtrr_if->get(i, &lbase, &lsize, <ype); + if (lbase == base && lsize == size) { + reg = i; + break; + } + } + if (reg < 0) { + printk("mtrr: no MTRR for %lx000,%lx000 found\n", base, + size); + goto out; + } + } + if (reg >= max) { + printk("mtrr: register: %d too big\n", reg); + goto out; + } + if (is_cpu(CYRIX) && !use_intel()) { + if ((reg == 3) && arr3_protected) { + printk("mtrr: ARR3 cannot be changed\n"); + goto out; + } + } + mtrr_if->get(reg, &lbase, &lsize, <ype); + if (lsize < 1) { + printk("mtrr: MTRR %d not used\n", reg); + goto out; + } + if (usage_table[reg] < 1) { + printk("mtrr: reg: %d has count=0\n", reg); + goto out; + } + if (--usage_table[reg] < 1) + set_mtrr(reg, 0, 0, 0); + compute_ascii(); + error = reg; + out: + up(&main_lock); + return error; +} +/** + * mtrr_del - delete a memory type region + * @reg: Register returned by mtrr_add + * @base: Physical base address + * @size: Size of region + * + * If register is supplied then base and size are ignored. This is + * how drivers should call it. + * + * Releases an MTRR region. If the usage count drops to zero the + * register is freed and the region returns to default state. + * On success the register is returned, on failure a negative error + * code. + */ + +int +mtrr_del(int reg, unsigned long base, unsigned long size) +{ + if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { + printk("mtrr: size and base must be multiples of 4 kiB\n"); + printk("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); +} + +EXPORT_SYMBOL(mtrr_add); +EXPORT_SYMBOL(mtrr_del); + +/* HACK ALERT! + * These should be called implicitly, but we can't yet until all the initcall + * stuff is done... + */ +extern void amd_init_mtrr(void); +extern void cyrix_init_mtrr(void); +extern void centaur_init_mtrr(void); + +static void __init init_ifs(void) +{ + amd_init_mtrr(); + cyrix_init_mtrr(); + centaur_init_mtrr(); +} + +/** + * mtrr_init - initialie mtrrs on the boot CPU + * + * This needs to be called early; before any of the other CPUs are + * initialized (i.e. before smp_init()). + * + */ +int __init mtrr_init(void) +{ + init_ifs(); + + if ( cpu_has_mtrr ) { + mtrr_if = &generic_mtrr_ops; + size_or_mask = 0xff000000; /* 36 bits */ + size_and_mask = 0x00f00000; + + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + /* The original Athlon docs said that + total addressable memory is 44 bits wide. + It was not really clear whether its MTRRs + follow this or not. (Read: 44 or 36 bits). + However, "x86-64_overview.pdf" explicitly + states that "previous implementations support + 36 bit MTRRs" and also provides a way to + query the width (in bits) of the physical + addressable memory on the Hammer family. + */ + if (boot_cpu_data.x86 == 7 + && (cpuid_eax(0x80000000) >= 0x80000008)) { + 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; + } + /* Athlon MTRRs use an Intel-compatible interface for + * getting and setting */ + break; + case X86_VENDOR_CENTAUR: + if (boot_cpu_data.x86 == 6) { + /* VIA Cyrix family have Intel style MTRRs, but don't support PAE */ + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; + } + break; + + default: + break; + } + } else { + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if ( cpu_has_k6_mtrr ) { + /* Pre-Athlon (K6) AMD CPU MTRRs */ + mtrr_if = mtrr_ops[X86_VENDOR_AMD]; + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; + } + break; + case X86_VENDOR_CENTAUR: + if ( cpu_has_centaur_mcr ) { + mtrr_if = mtrr_ops[X86_VENDOR_CENTAUR]; + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; + } + break; + case X86_VENDOR_CYRIX: + if ( cpu_has_cyrix_arr ) { + mtrr_if = mtrr_ops[X86_VENDOR_CYRIX]; + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; + } + break; + default: + break; + } + } + if (mtrr_if) { + set_num_var_ranges(); + if (use_intel()) { + /* Only for Intel MTRRs */ + get_mtrr_state(); + } + init_table(); + } +#if 0 + printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n" + "mtrr: detected mtrr type: %s\n", + MTRR_VERSION, mtrr_if_name[mtrr_if]); +#endif + return mtrr_if ? -ENXIO : 0; +} + +//subsys_initcall(mtrr_init); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/mtrr.h linux-2.5/arch/i386/kernel/cpu/mtrr/mtrr.h --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/mtrr.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/mtrr.h Wed Jun 19 18:15:58 2002 @@ -0,0 +1,96 @@ +/* + * local mtrr defines. + */ + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define MTRRcap_MSR 0x0fe +#define MTRRdefType_MSR 0x2ff + +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) + +#define NUM_FIXED_RANGES 88 +#define MTRRfix64K_00000_MSR 0x250 +#define MTRRfix16K_80000_MSR 0x258 +#define MTRRfix16K_A0000_MSR 0x259 +#define MTRRfix4K_C0000_MSR 0x268 +#define MTRRfix4K_C8000_MSR 0x269 +#define MTRRfix4K_D0000_MSR 0x26a +#define MTRRfix4K_D8000_MSR 0x26b +#define MTRRfix4K_E0000_MSR 0x26c +#define MTRRfix4K_E8000_MSR 0x26d +#define MTRRfix4K_F0000_MSR 0x26e +#define MTRRfix4K_F8000_MSR 0x26f + +#define MTRR_CHANGE_MASK_FIXED 0x01 +#define MTRR_CHANGE_MASK_VARIABLE 0x02 +#define MTRR_CHANGE_MASK_DEFTYPE 0x04 + +/* In the Intel processor's MTRR interface, the MTRR type is always held in + an 8 bit field: */ +typedef u8 mtrr_type; + +struct mtrr_ops { + u32 vendor; + u32 use_intel_if; + void (*init)(void); + void (*init_secondary)(void); + void (*set)(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type); + void (*get)(unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type * type); + int (*get_free_region) (unsigned long base, unsigned long size); + + int (*validate_add_page)(unsigned long base, unsigned long size, + unsigned int type); + int (*have_wrcomb)(void); +}; + +extern int generic_get_free_region(unsigned long base, unsigned long size); +extern void generic_init_secondary(void); +extern int generic_validate_add_page(unsigned long base, unsigned long size, + unsigned int type); + +extern struct mtrr_ops generic_mtrr_ops; + +extern int generic_have_wrcomb(void); +extern int positive_have_wrcomb(void); + +/* library functions for processor-specific routines */ +struct set_mtrr_context { + unsigned long flags; + unsigned long deftype_lo; + unsigned long deftype_hi; + unsigned long cr4val; + unsigned long ccr3; +}; + +struct mtrr_var_range { + unsigned long base_lo; + unsigned long base_hi; + unsigned long mask_lo; + unsigned long mask_hi; +}; + +void set_mtrr_done(struct set_mtrr_context *ctxt); +void set_mtrr_cache_disable(struct set_mtrr_context *ctxt); +void set_mtrr_prepare_save(struct set_mtrr_context *ctxt); + +extern void set_mtrr_ops(struct mtrr_ops * ops); + +/* Don't even ask... */ +extern void compute_ascii(void); + +extern u32 size_or_mask, size_and_mask; +extern struct mtrr_ops * mtrr_if; + +#define is_cpu(vnd) (mtrr_if->vendor == X86_VENDOR_##vnd) +#define use_intel() (mtrr_if->use_intel_if == 1) + +extern unsigned int num_var_ranges; + +extern char * mtrr_if_name[]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/mtrr/state.c linux-2.5/arch/i386/kernel/cpu/mtrr/state.c --- linux-2.5.23/arch/i386/kernel/cpu/mtrr/state.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/mtrr/state.c Wed Jun 19 20:06:16 2002 @@ -0,0 +1,338 @@ +#include +#include +#include +#include +#include +#include +#include "mtrr.h" + +struct mtrr_state { + struct mtrr_var_range *var_ranges; + mtrr_type fixed_ranges[NUM_FIXED_RANGES]; + unsigned char enabled; + mtrr_type def_type; +}; + +static unsigned long smp_changes_mask __initdata = 0; +struct mtrr_state mtrr_state = {}; + +static int __init set_fixed_ranges(mtrr_type * frs) +{ + unsigned long *p = (unsigned long *) frs; + 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; + } + + for (i = 0; i < 2; i++) { + 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; + } + } + + for (i = 0; i < 8; i++) { + 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; + } + } + return changed; +} + +/* Set the MSR pair relating to a var range. Returns TRUE if + changes are made */ +static int __init set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) +{ + 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; + } + + 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; +} + +static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi) +/* [SUMMARY] Set the MTRR state for this CPU. + The MTRR state information to read. + Some relevant CPU context. + [NOTE] The CPU must already be in a safe state for MTRR changes. + [RETURNS] 0 if no changes made, else a mask indication what was changed. +*/ +{ + unsigned int i; + unsigned long change_mask = 0; + + for (i = 0; i < num_var_ranges; i++) + if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i])) + change_mask |= MTRR_CHANGE_MASK_VARIABLE; + + if (set_fixed_ranges(mtrr_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 */ + if ((deftype_lo & 0xff) != mtrr_state.def_type + || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) { + deftype_lo |= (mtrr_state.def_type | mtrr_state.enabled << 10); + change_mask |= MTRR_CHANGE_MASK_DEFTYPE; + } + + return change_mask; +} + + +/* Some BIOS's are fucked and don't set all MTRRs the same! */ +static void __init mtrr_state_warn(void) +{ + unsigned long mask = smp_changes_mask; + if (!mask) + return; + if (mask & MTRR_CHANGE_MASK_FIXED) + printk + ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_VARIABLE) + printk + ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_DEFTYPE) + printk + ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); + printk("mtrr: probably your BIOS does not setup all CPUs\n"); +} + +/* Free resources associated with a struct mtrr_state */ +static void __init finalize_mtrr_state(void) +{ + if (mtrr_state.var_ranges) + kfree(mtrr_state.var_ranges); + mtrr_state.var_ranges = NULL; +} + +/* Get the MSR pair relating to a var range */ +static void __init +get_mtrr_var_range(unsigned int index, 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); +} + +static void __init +get_fixed_ranges(mtrr_type * frs) +{ + unsigned long *p = (unsigned long *) frs; + int i; + + rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + + 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++) + rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); +} + +/* Grab all of the MTRR state for this CPU into *state */ +void get_mtrr_state(void) +{ + unsigned int i; + struct mtrr_var_range *vrs; + unsigned long lo, dummy; + + if (!mtrr_state.var_ranges) { + mtrr_state.var_ranges = kmalloc(num_var_ranges * sizeof (struct mtrr_var_range), + GFP_KERNEL); + if (!mtrr_state.var_ranges) + return; + } + vrs = mtrr_state.var_ranges; + + for (i = 0; i < num_var_ranges; i++) + get_mtrr_var_range(i, &vrs[i]); + get_fixed_ranges(mtrr_state.fixed_ranges); + + rdmsr(MTRRdefType_MSR, lo, dummy); + mtrr_state.def_type = (lo & 0xff); + mtrr_state.enabled = (lo & 0xc00) >> 10; +} + + +/* Put the processor into a state where MTRRs can be safely set */ +void set_mtrr_prepare_save(struct set_mtrr_context *ctxt) +{ + unsigned int cr0; + + /* Disable interrupts locally */ + local_irq_save(ctxt->flags); + + if (use_intel() || is_cpu(CYRIX)) { + + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if ( cpu_has_pge ) { + 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 */ + cr0 = read_cr0() | 0x40000000; + wbinvd(); + write_cr0(cr0); + wbinvd(); + + if (use_intel()) + /* Save MTRR state */ + rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + else + /* Cyrix ARRs - everything else were excluded at the top */ + ctxt->ccr3 = getCx86(CX86_CCR3); + } +} + +void set_mtrr_cache_disable(struct set_mtrr_context *ctxt) +{ + if (use_intel()) + /* Disable MTRRs, and set the default type to uncached */ + wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, + ctxt->deftype_hi); + else if (is_cpu(CYRIX)) + /* Cyrix ARRs - everything else were excluded at the top */ + setCx86(CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10); +} + +/* Restore the processor after a set_mtrr_prepare */ +void set_mtrr_done(struct set_mtrr_context *ctxt) +{ + if (use_intel() || is_cpu(CYRIX)) { + + /* Flush caches and TLBs */ + wbinvd(); + + /* Restore MTRRdefType */ + if (use_intel()) + /* Intel (P6) standard MTRRs */ + wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + else + /* Cyrix ARRs - everything else was excluded at the top */ + setCx86(CX86_CCR3, ctxt->ccr3); + + /* Enable caches */ + write_cr0(read_cr0() & 0xbfffffff); + + /* Restore value of CR4 */ + if ( cpu_has_pge ) + write_cr4(ctxt->cr4val); + } + /* Re-enable interrupts locally (if enabled previously) */ + local_irq_restore(ctxt->flags); +} + +void __init generic_init_secondary(void) +{ + u32 cr0, cr4 = 0; + u32 deftype_lo, deftype_hi; + unsigned long mask, count; + + /* 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 */ + + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if ( cpu_has_pge ) { + cr4 = read_cr4(); + write_cr4(cr4 & (unsigned char) ~(1 << 7)); + } + + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ + cr0 = read_cr0() | 0x40000000; + wbinvd(); + write_cr0(cr0); + wbinvd(); + + /* Save MTRR state */ + rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); + + /* Disable MTRRs, and set the default type to uncached */ + wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi); + + /* Actually set the state */ + mask = set_mtrr_state(deftype_lo,deftype_hi); + + /* Flush caches and TLBs */ + wbinvd(); + + /* Intel (P6) standard MTRRs */ + wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); + + /* Enable caches */ + write_cr0(read_cr0() & 0xbfffffff); + + /* Restore value of CR4 */ + if ( cpu_has_pge ) + write_cr4(cr4); + + /* 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; + } +} + +/** + * mtrr_init_secondary - setup AP MTRR state + * + * Yes, this code is exactly the same as the set_mtrr code, except for the + * piece in the middle - you set all the ranges at once, instead of one + * register at a time. + * Shoot me. + */ +void __init mtrr_init_secondary_cpu(void) +{ + unsigned long flags; + + if (!mtrr_if || !mtrr_if->init_secondary) { + /* I see no MTRRs I can support in SMP mode... */ + printk("mtrr: SMP support incomplete for this vendor\n"); + return; + } + + local_irq_save(flags); + mtrr_if->init_secondary(); + local_irq_restore(flags); +} + +/** + * mtrr_final_init - finalize initialization sequence. + */ +static int __init mtrr_finalize_state(void) +{ + if (use_intel()) { + finalize_mtrr_state(); + mtrr_state_warn(); + } + return 0; +} + +arch_initcall(mtrr_finalize_state); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/cpu/proc.c linux-2.5/arch/i386/kernel/cpu/proc.c --- linux-2.5.23/arch/i386/kernel/cpu/proc.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/arch/i386/kernel/cpu/proc.c Mon Jun 10 13:16:49 2002 @@ -66,7 +66,7 @@ else seq_printf(m, "stepping\t: unknown\n"); - if ( test_bit(X86_FEATURE_TSC, c->x86_capability) ) { + if ( cpu_has(c, X86_FEATURE_TSC) ) { seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n", cpu_khz / 1000, (cpu_khz % 1000)); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/dmi_scan.c linux-2.5/arch/i386/kernel/dmi_scan.c --- linux-2.5.23/arch/i386/kernel/dmi_scan.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/arch/i386/kernel/dmi_scan.c Mon Jun 17 22:52:25 2002 @@ -274,6 +274,62 @@ } /* + * Some machines, usually laptops, can't handle an enabled local APIC. + * The symptoms include hangs or reboots when suspending or resuming, + * attaching or detaching the power cord, or entering BIOS setup screens + * through magic key sequences. + */ +static int __init local_apic_kills_bios(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (!dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after + * resumes, and also at what appears to be asynchronous APM events, + * if the local APIC is enabled. + */ +static int __init apm_kills_local_apic(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (apm_info.bios.version && !dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Intel AL440LX mainboard will hang randomly if the local APIC + * timer is running and the APM BIOS hasn't been disabled. + */ +static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_use_local_apic_timer; + if (apm_info.bios.version && !dont_use_local_apic_timer) { + dont_use_local_apic_timer = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "The local APIC timer will not be used.\n", + d->ident); + } +#endif + return 0; +} +/* * Work around broken HP Pavilion Notebooks which assign USB to * IRQ 9 even though it is actually wired to IRQ 11 */ @@ -350,6 +406,7 @@ * The MP1.4 table is right however and so SMP kernels tend to work. */ +extern int skip_ioapic_setup; static __init int broken_pirq(struct dmi_blacklist *d) { printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n"); @@ -357,6 +414,9 @@ printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n"); printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n"); printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n"); +#ifdef CONFIG_X86_IO_APIC + skip_ioapic_setup = 0; +#endif return 0; } @@ -411,62 +471,6 @@ return 0; } -/* - * Some machines, usually laptops, can't handle an enabled local APIC. - * The symptoms include hangs or reboots when suspending or resuming, - * attaching or detaching the power cord, or entering BIOS setup screens - * through magic key sequences. - */ -static int __init local_apic_kills_bios(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int dont_enable_local_apic; - if (!dont_enable_local_apic) { - dont_enable_local_apic = 1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "Refusing to enable the local APIC.\n", - d->ident); - } -#endif - return 0; -} - -/* - * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after - * resumes, and also at what appears to be asynchronous APM events, - * if the local APIC is enabled. - */ -static int __init apm_kills_local_apic(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int dont_enable_local_apic; - if (apm_info.bios.version && !dont_enable_local_apic) { - dont_enable_local_apic = 1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "Refusing to enable the local APIC.\n", - d->ident); - } -#endif - return 0; -} - -/* - * The Intel AL440LX mainboard will hang randomly if the local APIC - * timer is running and the APM BIOS hasn't been disabled. - */ -static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int dont_use_local_apic_timer; - if (apm_info.bios.version && !dont_use_local_apic_timer) { - dont_use_local_apic_timer = 1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "The local APIC timer will not be used.\n", - d->ident); - } -#endif - return 0; -} /* * Simple "print if true" callback diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/eisa.c linux-2.5/arch/i386/kernel/eisa.c --- linux-2.5.23/arch/i386/kernel/eisa.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/eisa.c Wed Jun 19 14:33:41 2002 @@ -0,0 +1,58 @@ +/* + * 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); + if (eisa_iobus == NULL) + return; + + 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.23/arch/i386/kernel/head.S linux-2.5/arch/i386/kernel/head.S --- linux-2.5.23/arch/i386/kernel/head.S Wed Jun 19 03:11:47 2002 +++ linux-2.5/arch/i386/kernel/head.S Sun May 26 01:42:04 2002 @@ -82,7 +82,7 @@ * Initialize page tables */ movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */ - movl $007,%eax /* "007" doesn't mean with right to kill, but + movl $007,%eax /* "007" doesn't mean with license to kill, but PRESENT+RW+USER */ 2: stosl add $0x1000,%eax diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/i386_ksyms.c linux-2.5/arch/i386/kernel/i386_ksyms.c --- linux-2.5.23/arch/i386/kernel/i386_ksyms.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/arch/i386/kernel/i386_ksyms.c Wed Jun 19 10:27:38 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); @@ -50,19 +50,19 @@ EXPORT_SYMBOL(drive_info); #endif +extern unsigned long cpu_khz; extern unsigned long get_cmos_time(void); /* 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); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_extended_fpu); EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(ioremap_nocache); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -72,8 +72,10 @@ EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(get_cmos_time); +EXPORT_SYMBOL(cpu_khz); EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); +EXPORT_SYMBOL(empty_zero_page); #ifdef CONFIG_DEBUG_IOVIRT EXPORT_SYMBOL(__io_virt_debug); @@ -126,7 +128,7 @@ #ifdef CONFIG_SMP EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(kernel_flag_cacheline); EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL_NOVERS(__write_lock_failed); EXPORT_SYMBOL_NOVERS(__read_lock_failed); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/i8259.c linux-2.5/arch/i386/kernel/i8259.c --- linux-2.5.23/arch/i386/kernel/i8259.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/arch/i386/kernel/i8259.c Mon Jun 17 22:52:25 2002 @@ -372,6 +372,8 @@ void __init init_IRQ(void) { int i; + extern spinlock_t i8253_lock; + unsigned long flags; #ifndef CONFIG_X86_VISWS_APIC init_ISA_irqs(); @@ -427,9 +429,11 @@ * Set the clock to HZ Hz, we already have a valid * vector now: */ + spin_lock_irqsave(&i8253_lock, flags); outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40); /* LSB */ outb(LATCH >> 8 , 0x40); /* MSB */ + spin_unlock_irqrestore(&i8253_lock, flags); #ifndef CONFIG_VISWS setup_irq(2, &irq2); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/io_apic.c linux-2.5/arch/i386/kernel/io_apic.c --- linux-2.5.23/arch/i386/kernel/io_apic.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/arch/i386/kernel/io_apic.c Wed Jun 19 07:35:18 2002 @@ -219,6 +219,7 @@ #define IRQ_ALLOWED(cpu,allowed_mask) \ ((1 << cpu) & (allowed_mask)) +#if CONFIG_SMP static unsigned long move(int curr_cpu, unsigned long allowed_mask, unsigned long now, int direction) { int search_idle = 1; @@ -244,6 +245,7 @@ return cpu; } +#endif static inline void balance_irq(int irq) { @@ -276,13 +278,21 @@ int pirqs_enabled; int skip_ioapic_setup; -static int __init ioapic_setup(char *str) +static int __init noioapic_setup(char *str) { skip_ioapic_setup = 1; return 1; } -__setup("noapic", ioapic_setup); +__setup("noapic", noioapic_setup); + +static int __init ioapic_setup(char *str) +{ + skip_ioapic_setup = 0; + return 1; +} + +__setup("apic", ioapic_setup); static int __init ioapic_pirq_setup(char *str) { @@ -724,7 +734,14 @@ } irq = pin_2_irq(idx, apic, pin); - add_pin_to_irq(irq, apic, pin); + /* + * skip adding the timer int on secondary nodes, which causes + * a small but painful rift in the time-space continuum + */ + if (clustered_apic_mode && (apic != 0) && (irq == 0)) + continue; + else + add_pin_to_irq(irq, apic, pin); if (!apic && !IO_APIC_IRQ(irq)) continue; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/irq.c linux-2.5/arch/i386/kernel/irq.c --- linux-2.5.23/arch/i386/kernel/irq.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/arch/i386/kernel/irq.c Wed Jun 19 08:59:01 2002 @@ -172,7 +172,7 @@ seq_printf(p, "LOC: "); for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) - p += seq_printf(p, "%10u ", apic_timer_irqs[j]); + p += seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/mpparse.c linux-2.5/arch/i386/kernel/mpparse.c --- linux-2.5.23/arch/i386/kernel/mpparse.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/arch/i386/kernel/mpparse.c Wed Jun 19 20:17:43 2002 @@ -64,7 +64,7 @@ unsigned int boot_cpu_physical_apicid = -1U; unsigned int boot_cpu_logical_apicid = -1U; /* Internal processor count */ -static unsigned int num_processors; +static unsigned int __initdata num_processors; /* Bitmask of physically existing CPUs */ unsigned long phys_cpu_present_map; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/mtrr.c linux-2.5/arch/i386/kernel/mtrr.c --- linux-2.5.23/arch/i386/kernel/mtrr.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/arch/i386/kernel/mtrr.c Thu Jan 1 01:00:00 1970 @@ -1,2303 +0,0 @@ -/* Generic MTRR (Memory Type Range Register) driver. - - Copyright (C) 1997-2000 Richard Gooch - - 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. - - Richard Gooch may be reached by email at rgooch@atnf.csiro.au - The postal address is: - Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. - - Source: "Pentium Pro Family Developer's Manual, Volume 3: - Operating System Writer's Guide" (Intel document number 242692), - section 11.11.7 - - ChangeLog - - Prehistory Martin Tischhäuser - Initial register-setting code (from proform-1.0). - 19971216 Richard Gooch - Original version for /proc/mtrr interface, SMP-safe. - v1.0 - 19971217 Richard Gooch - Bug fix for ioctls()'s. - Added sample code in Documentation/mtrr.txt - v1.1 - 19971218 Richard Gooch - Disallow overlapping regions. - 19971219 Jens Maurer - Register-setting fixups. - v1.2 - 19971222 Richard Gooch - Fixups for kernel 2.1.75. - v1.3 - 19971229 David Wragg - Register-setting fixups and conformity with Intel conventions. - 19971229 Richard Gooch - Cosmetic changes and wrote this ChangeLog ;-) - 19980106 Richard Gooch - Fixups for kernel 2.1.78. - v1.4 - 19980119 David Wragg - Included passive-release enable code (elsewhere in PCI setup). - v1.5 - 19980131 Richard Gooch - Replaced global kernel lock with private spinlock. - v1.6 - 19980201 Richard Gooch - Added wait for other CPUs to complete changes. - v1.7 - 19980202 Richard Gooch - Bug fix in definition of for UP. - v1.8 - 19980319 Richard Gooch - Fixups for kernel 2.1.90. - 19980323 Richard Gooch - Move SMP BIOS fixup before secondary CPUs call - v1.9 - 19980325 Richard Gooch - Fixed test for overlapping regions: confused by adjacent regions - 19980326 Richard Gooch - Added wbinvd in . - 19980401 Richard Gooch - Bug fix for non-SMP compilation. - 19980418 David Wragg - Fixed-MTRR synchronisation for SMP and use atomic operations - instead of spinlocks. - 19980418 Richard Gooch - Differentiate different MTRR register classes for BIOS fixup. - v1.10 - 19980419 David Wragg - Bug fix in variable MTRR synchronisation. - v1.11 - 19980419 Richard Gooch - Fixups for kernel 2.1.97. - v1.12 - 19980421 Richard Gooch - Safer synchronisation across CPUs when changing MTRRs. - v1.13 - 19980423 Richard Gooch - Bugfix for SMP systems without MTRR support. - v1.14 - 19980427 Richard Gooch - Trap calls to and on non-MTRR machines. - v1.15 - 19980427 Richard Gooch - Use atomic bitops for setting SMP change mask. - v1.16 - 19980428 Richard Gooch - Removed spurious diagnostic message. - v1.17 - 19980429 Richard Gooch - Moved register-setting macros into this file. - Moved setup code from init/main.c to i386-specific areas. - v1.18 - 19980502 Richard Gooch - Moved MTRR detection outside conditionals in . - v1.19 - 19980502 Richard Gooch - Documentation improvement: mention Pentium II and AGP. - v1.20 - 19980521 Richard Gooch - Only manipulate interrupt enable flag on local CPU. - Allow enclosed uncachable regions. - v1.21 - 19980611 Richard Gooch - Always define . - v1.22 - 19980901 Richard Gooch - Removed module support in order to tidy up code. - Added sanity check for / before . - Created addition queue for prior to SMP commence. - v1.23 - 19980902 Richard Gooch - Ported patch to kernel 2.1.120-pre3. - v1.24 - 19980910 Richard Gooch - Removed sanity checks and addition queue: Linus prefers an OOPS. - v1.25 - 19981001 Richard Gooch - Fixed harmless compiler warning in include/asm-i386/mtrr.h - Fixed version numbering and history for v1.23 -> v1.24. - v1.26 - 19990118 Richard Gooch - Added devfs support. - v1.27 - 19990123 Richard Gooch - Changed locking to spin with reschedule. - Made use of new . - v1.28 - 19990201 Zoltán Böszörményi - Extended the driver to be able to use Cyrix style ARRs. - 19990204 Richard Gooch - Restructured Cyrix support. - v1.29 - 19990204 Zoltán Böszörményi - Refined ARR support: enable MAPEN in set_mtrr_prepare() - and disable MAPEN in set_mtrr_done(). - 19990205 Richard Gooch - Minor cleanups. - v1.30 - 19990208 Zoltán Böszörményi - Protect plain 6x86s (and other processors without the - Page Global Enable feature) against accessing CR4 in - set_mtrr_prepare() and set_mtrr_done(). - 19990210 Richard Gooch - Turned and into function pointers. - v1.31 - 19990212 Zoltán Böszörményi - Major rewrite of cyrix_arr_init(): do not touch ARRs, - leave them as the BIOS have set them up. - Enable usage of all 8 ARRs. - Avoid multiplications by 3 everywhere and other - code clean ups/speed ups. - 19990213 Zoltán Böszörményi - Set up other Cyrix processors identical to the boot cpu. - Since Cyrix don't support Intel APIC, this is l'art pour l'art. - Weigh ARRs by size: - If size <= 32M is given, set up ARR# we were given. - If size > 32M is given, set up ARR7 only if it is free, - fail otherwise. - 19990214 Zoltán Böszörményi - Also check for size >= 256K if we are to set up ARR7, - mtrr_add() returns the value it gets from set_mtrr() - 19990218 Zoltán Böszörményi - Remove Cyrix "coma bug" workaround from here. - Moved to linux/arch/i386/kernel/setup.c and - linux/include/asm-i386/bugs.h - 19990228 Richard Gooch - Added MTRRIOC_KILL_ENTRY ioctl(2) - Trap for counter underflow in . - Trap for 4 MiB aligned regions for PPro, stepping <= 7. - 19990301 Richard Gooch - Created hook. - 19990305 Richard Gooch - Temporarily disable AMD support now MTRR capability flag is set. - v1.32 - 19990308 Zoltán Böszörményi - Adjust my changes (19990212-19990218) to Richard Gooch's - latest changes. (19990228-19990305) - v1.33 - 19990309 Richard Gooch - Fixed typo in message. - 19990310 Richard Gooch - Support K6-II/III based on Alan Cox's patches. - v1.34 - 19990511 Bart Hartgers - Support Centaur C6 MCR's. - 19990512 Richard Gooch - Minor cleanups. - v1.35 - 19990707 Zoltán Böszörményi - Check whether ARR3 is protected in cyrix_get_free_region() - and mtrr_del(). The code won't attempt to delete or change it - from now on if the BIOS protected ARR3. It silently skips ARR3 - in cyrix_get_free_region() or returns with an error code from - mtrr_del(). - 19990711 Zoltán Böszörményi - Reset some bits in the CCRs in cyrix_arr_init() to disable SMM - if ARR3 isn't protected. This is needed because if SMM is active - and ARR3 isn't protected then deleting and setting ARR3 again - may lock up the processor. With SMM entirely disabled, it does - not happen. - 19990812 Zoltán Böszörményi - Rearrange switch() statements so the driver accomodates to - the fact that the AMD Athlon handles its MTRRs the same way - as Intel does. - 19990814 Zoltán Böszörményi - Double check for Intel in mtrr_add()'s big switch() because - that revision check is only valid for Intel CPUs. - 19990819 Alan Cox - Tested Zoltan's changes on a pre production Athlon - 100% - success. - 19991008 Manfred Spraul - replaced spin_lock_reschedule() with a normal semaphore. - v1.36 - 20000221 Richard Gooch - Compile fix if procfs and devfs not enabled. - Formatting changes. - v1.37 - 20001109 H. Peter Anvin - Use the new centralized CPU feature detects. - - v1.38 - 20010309 Dave Jones - Add support for Cyrix III. - - v1.39 - 20010312 Dave Jones - Ugh, I broke AMD support. - Reworked fix by Troels Walsted Hansen - - v1.40 - 20010327 Dave Jones - Adapted Cyrix III support to include VIA C3. - -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define MTRR_NEED_STRINGS -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define MTRR_VERSION "1.40 (20010327)" - -#define TRUE 1 -#define FALSE 0 - -/* - * The code assumes all processors support the same MTRR - * interface. This is generally a good assumption, but could - * potentially be a problem. - */ -enum mtrr_if_type { - MTRR_IF_NONE, /* No MTRRs supported */ - MTRR_IF_INTEL, /* Intel (P6) standard MTRRs */ - MTRR_IF_AMD_K6, /* AMD pre-Athlon MTRRs */ - MTRR_IF_CYRIX_ARR, /* Cyrix ARRs */ - MTRR_IF_CENTAUR_MCR, /* Centaur MCRs */ -} mtrr_if = MTRR_IF_NONE; - -static __initdata char *mtrr_if_name[] = { - "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR" -}; - -#define MTRRcap_MSR 0x0fe -#define MTRRdefType_MSR 0x2ff - -#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) -#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) - -#define NUM_FIXED_RANGES 88 -#define MTRRfix64K_00000_MSR 0x250 -#define MTRRfix16K_80000_MSR 0x258 -#define MTRRfix16K_A0000_MSR 0x259 -#define MTRRfix4K_C0000_MSR 0x268 -#define MTRRfix4K_C8000_MSR 0x269 -#define MTRRfix4K_D0000_MSR 0x26a -#define MTRRfix4K_D8000_MSR 0x26b -#define MTRRfix4K_E0000_MSR 0x26c -#define MTRRfix4K_E8000_MSR 0x26d -#define MTRRfix4K_F0000_MSR 0x26e -#define MTRRfix4K_F8000_MSR 0x26f - -#ifdef CONFIG_SMP -# define MTRR_CHANGE_MASK_FIXED 0x01 -# define MTRR_CHANGE_MASK_VARIABLE 0x02 -# define MTRR_CHANGE_MASK_DEFTYPE 0x04 -#endif - -/* In the Intel processor's MTRR interface, the MTRR type is always held in - an 8 bit field: */ -typedef u8 mtrr_type; - -#define LINE_SIZE 80 -#define JIFFIE_TIMEOUT 100 - -#ifdef CONFIG_SMP -# define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type) -#else -# define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \ - TRUE) -#endif - -#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS) -# define USERSPACE_INTERFACE -#endif - -#ifndef USERSPACE_INTERFACE -# define compute_ascii() while (0) -#endif - -#ifdef USERSPACE_INTERFACE -static char *ascii_buffer; -static unsigned int ascii_buf_bytes; -#endif -static unsigned int *usage_table; -static DECLARE_MUTEX(main_lock); - -/* Private functions */ -#ifdef USERSPACE_INTERFACE -static void compute_ascii (void); -#endif - - -struct set_mtrr_context -{ - unsigned long flags; - unsigned long deftype_lo; - unsigned long deftype_hi; - unsigned long cr4val; - unsigned long ccr3; -}; - -static int arr3_protected; - -/* Put the processor into a state where MTRRs can be safely set */ -static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt) -{ - /* Disable interrupts locally */ - __save_flags (ctxt->flags); __cli (); - - if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) - return; - - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if ( cpu_has_pge ) { - 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 */ - { - unsigned int cr0 = read_cr0() | 0x40000000; - wbinvd(); - write_cr0( cr0 ); - wbinvd(); - } - - if ( mtrr_if == MTRR_IF_INTEL ) { - /* Save MTRR state */ - rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); - } else { - /* Cyrix ARRs - everything else were excluded at the top */ - ctxt->ccr3 = getCx86 (CX86_CCR3); - } -} /* End Function set_mtrr_prepare_save */ - -static void set_mtrr_cache_disable (struct set_mtrr_context *ctxt) -{ - if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) - return; - - if ( mtrr_if == MTRR_IF_INTEL ) { - /* Disable MTRRs, and set the default type to uncached */ - wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); - } else { - /* Cyrix ARRs - everything else were excluded at the top */ - setCx86 (CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10); - } -} /* End Function set_mtrr_cache_disable */ - -/* Restore the processor after a set_mtrr_prepare */ -static void set_mtrr_done (struct set_mtrr_context *ctxt) -{ - if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) { - __restore_flags (ctxt->flags); - return; - } - - /* Flush caches and TLBs */ - wbinvd(); - - /* Restore MTRRdefType */ - if ( mtrr_if == MTRR_IF_INTEL ) { - /* Intel (P6) standard MTRRs */ - wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); - } else { - /* Cyrix ARRs - everything else was excluded at the top */ - setCx86 (CX86_CCR3, ctxt->ccr3); - } - - /* Enable caches */ - write_cr0( read_cr0() & 0xbfffffff ); - - /* Restore value of CR4 */ - if ( cpu_has_pge ) - write_cr4(ctxt->cr4val); - - /* Re-enable interrupts locally (if enabled previously) */ - __restore_flags (ctxt->flags); -} /* End Function set_mtrr_done */ - -/* This function returns the number of variable MTRRs */ -static unsigned int get_num_var_ranges (void) -{ - unsigned long config, dummy; - - switch ( mtrr_if ) - { - case MTRR_IF_INTEL: - rdmsr (MTRRcap_MSR, config, dummy); - return (config & 0xff); - case MTRR_IF_AMD_K6: - return 2; - case MTRR_IF_CYRIX_ARR: - return 8; - case MTRR_IF_CENTAUR_MCR: - return 8; - default: - return 0; - } -} /* End Function get_num_var_ranges */ - -/* Returns non-zero if we have the write-combining memory type */ -static int have_wrcomb (void) -{ - unsigned long config, dummy; - struct pci_dev *dev = NULL; - - /* ServerWorks LE chipsets have problems with write-combining - Don't allow it and leave room for other chipsets to be tagged */ - - if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { - if ((dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && - (dev->device == PCI_DEVICE_ID_SERVERWORKS_LE)) { - printk (KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n"); - return 0; - } - } - - switch ( mtrr_if ) - { - case MTRR_IF_INTEL: - rdmsr (MTRRcap_MSR, config, dummy); - return (config & (1<<10)); - case MTRR_IF_AMD_K6: - case MTRR_IF_CENTAUR_MCR: - case MTRR_IF_CYRIX_ARR: - return 1; - default: - return 0; - } -} /* End Function have_wrcomb */ - -static u32 size_or_mask, size_and_mask; - -static void intel_get_mtrr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) -{ - 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; - } - - 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; -} /* End Function intel_get_mtrr */ - -static void cyrix_get_arr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) -{ - unsigned long flags; - unsigned char arr, ccr3, rcr, shift; - - arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ - - /* Save flags and disable interrupts */ - __save_flags (flags); __cli (); - - ccr3 = getCx86 (CX86_CCR3); - setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - ((unsigned char *) base)[3] = getCx86 (arr); - ((unsigned char *) base)[2] = getCx86 (arr+1); - ((unsigned char *) base)[1] = getCx86 (arr+2); - rcr = getCx86(CX86_RCR_BASE + reg); - setCx86 (CX86_CCR3, ccr3); /* disable MAPEN */ - - /* Enable interrupts if it was enabled previously */ - __restore_flags (flags); - shift = ((unsigned char *) base)[1] & 0x0f; - *base >>= PAGE_SHIFT; - - /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7 - * Note: shift==0xf means 4G, this is unsupported. - */ - if (shift) - *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1); - else - *size = 0; - - /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */ - if (reg < 7) - { - switch (rcr) - { - case 1: *type = MTRR_TYPE_UNCACHABLE; break; - case 8: *type = MTRR_TYPE_WRBACK; break; - case 9: *type = MTRR_TYPE_WRCOMB; break; - case 24: - default: *type = MTRR_TYPE_WRTHROUGH; break; - } - } else - { - switch (rcr) - { - case 0: *type = MTRR_TYPE_UNCACHABLE; break; - case 8: *type = MTRR_TYPE_WRCOMB; break; - case 9: *type = MTRR_TYPE_WRBACK; break; - case 25: - default: *type = MTRR_TYPE_WRTHROUGH; break; - } - } -} /* End Function cyrix_get_arr */ - -static void amd_get_mtrr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) -{ - unsigned long low, high; - - rdmsr (MSR_K6_UWCCR, low, high); - /* Upper dword is region 1, lower is region 0 */ - if (reg == 1) low = high; - /* The base masks off on the right alignment */ - *base = (low & 0xFFFE0000) >> PAGE_SHIFT; - *type = 0; - if (low & 1) *type = MTRR_TYPE_UNCACHABLE; - if (low & 2) *type = MTRR_TYPE_WRCOMB; - if ( !(low & 3) ) - { - *size = 0; - return; - } - /* - * This needs a little explaining. The size is stored as an - * inverted mask of bits of 128K granularity 15 bits long offset - * 2 bits - * - * So to get a size we do invert the mask and add 1 to the lowest - * mask bit (4 as its 2 bits in). This gives us a size we then shift - * to turn into 128K blocks - * - * eg 111 1111 1111 1100 is 512K - * - * invert 000 0000 0000 0011 - * +1 000 0000 0000 0100 - * *128K ... - */ - low = (~low) & 0x1FFFC; - *size = (low + 4) << (15 - PAGE_SHIFT); - return; -} /* End Function amd_get_mtrr */ - -static struct -{ - unsigned long high; - unsigned long low; -} centaur_mcr[8]; - -static u8 centaur_mcr_reserved; -static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ - -/* - * Report boot time MCR setups - */ - -void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) -{ - centaur_mcr[mcr].low = lo; - centaur_mcr[mcr].high = hi; -} - -static void centaur_get_mcr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) -{ - *base = centaur_mcr[reg].high >> PAGE_SHIFT; - *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; - *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ - if(centaur_mcr_type==1 && ((centaur_mcr[reg].low&31)&2)) - *type = MTRR_TYPE_UNCACHABLE; - if(centaur_mcr_type==1 && (centaur_mcr[reg].low&31)==25) - *type = MTRR_TYPE_WRBACK; - if(centaur_mcr_type==0 && (centaur_mcr[reg].low&31)==31) - *type = MTRR_TYPE_WRBACK; - -} /* End Function centaur_get_mcr */ - -static void (*get_mtrr) (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type); - -static void intel_set_mtrr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) -/* [SUMMARY] Set variable MTRR register on the local CPU. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - If TRUE, do the change safely. If FALSE, safety measures should - be done externally. - [RETURNS] Nothing. -*/ -{ - struct set_mtrr_context ctxt; - - if (do_safe) { - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&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); - } - 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)); - } - if (do_safe) set_mtrr_done (&ctxt); -} /* End Function intel_set_mtrr_up */ - -static void cyrix_set_arr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) -{ - struct set_mtrr_context ctxt; - unsigned char arr, arr_type, arr_size; - - arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ - - /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */ - if (reg >= 7) - size >>= 6; - - size &= 0x7fff; /* make sure arr_size <= 14 */ - for(arr_size = 0; size; arr_size++, size >>= 1); - - if (reg<7) - { - switch (type) { - case MTRR_TYPE_UNCACHABLE: arr_type = 1; break; - case MTRR_TYPE_WRCOMB: arr_type = 9; break; - case MTRR_TYPE_WRTHROUGH: arr_type = 24; break; - default: arr_type = 8; break; - } - } - else - { - switch (type) - { - case MTRR_TYPE_UNCACHABLE: arr_type = 0; break; - case MTRR_TYPE_WRCOMB: arr_type = 8; break; - case MTRR_TYPE_WRTHROUGH: arr_type = 25; break; - default: arr_type = 9; break; - } - } - - if (do_safe) { - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - } - base <<= PAGE_SHIFT; - setCx86(arr, ((unsigned char *) &base)[3]); - setCx86(arr+1, ((unsigned char *) &base)[2]); - setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size); - setCx86(CX86_RCR_BASE + reg, arr_type); - if (do_safe) set_mtrr_done (&ctxt); -} /* End Function cyrix_set_arr_up */ - -static void amd_set_mtrr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) -/* [SUMMARY] Set variable MTRR register on the local CPU. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - If TRUE, do the change safely. If FALSE, safety measures should - be done externally. - [RETURNS] Nothing. -*/ -{ - u32 regs[2]; - struct set_mtrr_context ctxt; - - if (do_safe) { - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - } - /* - * Low is MTRR0 , High MTRR 1 - */ - rdmsr (MSR_K6_UWCCR, regs[0], regs[1]); - /* - * Blank to disable - */ - if (size == 0) - regs[reg] = 0; - else - /* Set the register to the base, the type (off by one) and an - inverted bitmask of the size The size is the only odd - bit. We are fed say 512K We invert this and we get 111 1111 - 1111 1011 but if you subtract one and invert you get the - desired 111 1111 1111 1100 mask - - But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! */ - regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC) - | (base<base_lo, vr->base_hi); - rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi); -} /* End Function get_mtrr_var_range */ - - -/* Set the MSR pair relating to a var range. Returns TRUE if - changes are made */ -static int __init set_mtrr_var_range_testing (unsigned int index, - struct mtrr_var_range *vr) -{ - 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; - } - - 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; -} /* End Function set_mtrr_var_range_testing */ - -static void __init get_fixed_ranges(mtrr_type *frs) -{ - unsigned long *p = (unsigned long *)frs; - int i; - - rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); - - 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++) - rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); -} /* End Function get_fixed_ranges */ - -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; - - rdmsr(MTRRfix64K_00000_MSR, lo, hi); - if (p[0] != lo || p[1] != hi) - { - wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); - changed = TRUE; - } - - for (i = 0; i < 2; i++) - { - 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; - } - } - - for (i = 0; i < 8; i++) - { - 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; - } - } - return changed; -} /* End Function set_fixed_ranges_testing */ - -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; -}; - - -/* Grab all of the MTRR state for this CPU into *state */ -static void __init get_mtrr_state(struct mtrr_state *state) -{ - unsigned int nvrs, i; - struct mtrr_var_range *vrs; - unsigned long lo, dummy; - - nvrs = state->num_var_ranges = get_num_var_ranges(); - vrs = state->var_ranges - = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); - if (vrs == NULL) - nvrs = state->num_var_ranges = 0; - - for (i = 0; i < nvrs; i++) - get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges (state->fixed_ranges); - - rdmsr (MTRRdefType_MSR, lo, dummy); - state->def_type = (lo & 0xff); - state->enabled = (lo & 0xc00) >> 10; -} /* End Function get_mtrr_state */ - - -/* Free resources associated with a struct mtrr_state */ -static void __init finalize_mtrr_state(struct mtrr_state *state) -{ - if (state->var_ranges) kfree (state->var_ranges); -} /* End Function finalize_mtrr_state */ - - -static unsigned long __init set_mtrr_state (struct mtrr_state *state, - struct set_mtrr_context *ctxt) -/* [SUMMARY] Set the MTRR state for this CPU. - The MTRR state information to read. - Some relevant CPU context. - [NOTE] The CPU must already be in a safe state for MTRR changes. - [RETURNS] 0 if no changes made, else a mask indication what was changed. -*/ -{ - unsigned int i; - unsigned long change_mask = 0; - - 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; - - 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 */ - 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; - } - - return change_mask; -} /* End Function set_mtrr_state */ - - -static atomic_t undone_count; -static volatile int wait_barrier_cache_disable = FALSE; -static volatile int wait_barrier_execute = FALSE; -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; -}; - -static void ipi_handler (void *info) -/* [SUMMARY] Synchronisation handler. Executed by "other" CPUs. - [RETURNS] Nothing. -*/ -{ - struct set_mtrr_data *data = info; - struct set_mtrr_context ctxt; - set_mtrr_prepare_save (&ctxt); - /* Notify master that I've flushed and disabled my cache */ - atomic_dec (&undone_count); - while (wait_barrier_cache_disable) { rep_nop(); barrier(); } - set_mtrr_cache_disable (&ctxt); - /* Notify master that I've flushed and disabled my cache */ - atomic_dec (&undone_count); - while (wait_barrier_execute) { rep_nop(); barrier(); } - /* 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); - /* Wait for master to clear me to enable cache and return */ - while (wait_barrier_cache_enable) { rep_nop(); barrier(); } - set_mtrr_done (&ctxt); -} /* End Function ipi_handler */ - -static void set_mtrr_smp (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) -{ - 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_cache_disable = TRUE; - wait_barrier_execute = TRUE; - wait_barrier_cache_enable = TRUE; - atomic_set (&undone_count, num_online_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 */ - set_mtrr_prepare_save (&ctxt); - /* Wait for all other CPUs to flush and disable their caches */ - while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } - /* Set up for completion wait and then release other CPUs to change MTRRs*/ - atomic_set (&undone_count, num_online_cpus() - 1); - wait_barrier_cache_disable = FALSE; - set_mtrr_cache_disable (&ctxt); - - /* Wait for all other CPUs to flush and disable their caches */ - while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } - /* Set up for completion wait and then release other CPUs to change MTRRs*/ - atomic_set (&undone_count, num_online_cpus() - 1); - wait_barrier_execute = FALSE; - (*set_mtrr_up) (reg, base, size, type, FALSE); - /* Now wait for other CPUs to complete the function */ - while (atomic_read (&undone_count) > 0) { rep_nop(); 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); -} /* End Function set_mtrr_smp */ - - -/* Some BIOS's are fucked and don't set all MTRRs the same! */ -static void __init mtrr_state_warn(unsigned long mask) -{ - if (!mask) return; - if (mask & MTRR_CHANGE_MASK_FIXED) - printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_VARIABLE) - printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_DEFTYPE) - printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); - printk ("mtrr: probably your BIOS does not setup all CPUs\n"); -} /* End Function mtrr_state_warn */ - -#endif /* CONFIG_SMP */ - -static char *attrib_to_str (int x) -{ - return (x <= 6) ? mtrr_strings[x] : "?"; -} /* End Function attrib_to_str */ - -static void init_table (void) -{ - int i, max; - - max = get_num_var_ranges (); - if ( ( usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL) ) - == NULL ) - { - 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 (); -#endif -} /* End Function init_table */ - -static int generic_get_free_region (unsigned long base, unsigned long size) -/* [SUMMARY] Get a free MTRR. - The starting (base) address of the region. - The size (in bytes) of the region. - [RETURNS] The index of the region on success, else -1 on error. -*/ -{ - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; - - max = get_num_var_ranges (); - for (i = 0; i < max; ++i) - { - (*get_mtrr) (i, &lbase, &lsize, <ype); - if (lsize == 0) return i; - } - return -ENOSPC; -} /* End Function generic_get_free_region */ - -static int centaur_get_free_region (unsigned long base, unsigned long size) -/* [SUMMARY] Get a free MTRR. - The starting (base) address of the region. - The size (in bytes) of the region. - [RETURNS] The index of the region on success, else -1 on error. -*/ -{ - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; - - max = get_num_var_ranges (); - for (i = 0; i < max; ++i) - { - if(centaur_mcr_reserved & (1< The starting (base) address of the region. - The size (in bytes) of the region. - [RETURNS] The index of the region on success, else -1 on error. -*/ -{ - int i; - mtrr_type ltype; - unsigned long lbase, lsize; - - /* If we are to set up a region >32M then look at ARR7 immediately */ - if (size > 0x2000) - { - cyrix_get_arr (7, &lbase, &lsize, <ype); - if (lsize == 0) return 7; - /* Else try ARR0-ARR6 first */ - } - else - { - for (i = 0; i < 7; i++) - { - cyrix_get_arr (i, &lbase, &lsize, <ype); - if ((i == 3) && arr3_protected) continue; - if (lsize == 0) return i; - } - /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ - cyrix_get_arr (i, &lbase, &lsize, <ype); - if ((lsize == 0) && (size >= 0x40)) return i; - } - return -ENOSPC; -} /* End Function cyrix_get_free_region */ - -static int (*get_free_region) (unsigned long base, - unsigned long size) = generic_get_free_region; - -/** - * mtrr_add_page - Add a memory type region - * @base: Physical base address of region in pages (4 KB) - * @size: Physical size of region in pages (4 KB) - * @type: Type of MTRR desired - * @increment: If this is true do usage counting on the region - * - * Memory type region registers control the caching on newer Intel and - * non Intel processors. This function allows drivers to request an - * MTRR is added. The details and hardware specifics of each processor's - * implementation are hidden from the caller, but nevertheless the - * caller should expect to need to provide a power of two size on an - * equivalent power of two boundary. - * - * If the region cannot be added either because all regions are in use - * or the CPU cannot support it a negative value is returned. On success - * the register number for this entry is returned, but should be treated - * as a cookie only. - * - * On a multiprocessor machine the changes are made to all processors. - * This is required on x86 by the Intel processors. - * - * The available types are - * - * %MTRR_TYPE_UNCACHABLE - No caching - * - * %MTRR_TYPE_WRBACK - Write data back in bursts whenever - * - * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts - * - * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes - * - * BUGS: Needs a quiet flag for the cases where drivers do not mind - * failures and do not wish system log messages to be sent. - */ - -int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, char increment) -{ -/* [SUMMARY] Add an MTRR entry. - The starting (base, in pages) address of the region. - The size of the region. (in pages) - The type of the new region. - If true and the region already exists, the usage count will be - incremented. - [RETURNS] The MTRR register on success, else a negative number indicating - the error code. - [NOTE] This routine uses a spinlock. -*/ - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize, last; - - switch ( mtrr_if ) - { - case MTRR_IF_NONE: - return -ENXIO; /* No MTRRs whatsoever */ - - case MTRR_IF_AMD_K6: - /* Apply the K6 block alignment and size rules - In order - o Uncached or gathering only - o 128K or bigger block - o Power of 2 block - o base suitably aligned to the power - */ - if ( type > MTRR_TYPE_WRCOMB || size < (1 << (17-PAGE_SHIFT)) || - (size & ~(size-1))-size || ( base & (size-1) ) ) - return -EINVAL; - break; - - case MTRR_IF_INTEL: - /* For Intel PPro stepping <= 7, must be 4 MiB aligned - and not touch 0x70000000->0x7003FFFF */ - if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - boot_cpu_data.x86 == 6 && - boot_cpu_data.x86_model == 1 && - boot_cpu_data.x86_mask <= 7 ) - { - if ( base & ((1 << (22-PAGE_SHIFT))-1) ) - { - printk (KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base); - return -EINVAL; - } - if (!(base + size < 0x70000000 || base > 0x7003FFFF) && - (type == MTRR_TYPE_WRCOMB || type == MTRR_TYPE_WRBACK)) - { - printk (KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n"); - return -EINVAL; - } - } - /* Fall through */ - - case MTRR_IF_CYRIX_ARR: - case MTRR_IF_CENTAUR_MCR: - if ( mtrr_if == MTRR_IF_CENTAUR_MCR ) - { - /* - * FIXME: Winchip2 supports uncached - */ - if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) - { - printk (KERN_WARNING "mtrr: only write-combining%s supported\n", - centaur_mcr_type?" and uncacheable are":" is"); - return -EINVAL; - } - } - else if (base + size < 0x100) - { - printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n", - base, size); - return -EINVAL; - } - /* Check upper bits of base and last are equal and lower bits are 0 - for base and 1 for last */ - last = base + size - 1; - for (lbase = base; !(lbase & 1) && (last & 1); - lbase = lbase >> 1, last = last >> 1); - if (lbase != last) - { - printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", - base, size); - return -EINVAL; - } - break; - - default: - return -EINVAL; - } - - if (type >= MTRR_NUM_TYPES) - { - printk ("mtrr: type: %u illegal\n", type); - return -EINVAL; - } - - /* 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; - } - - if ( base & size_or_mask || size & size_or_mask ) - { - 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 */ - down(&main_lock); - for (i = 0; i < max; ++i) - { - (*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 */ - 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 */ - if (ltype != type) - { - if (type == MTRR_TYPE_UNCACHABLE) continue; - up(&main_lock); - printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", - base, size, attrib_to_str (ltype), attrib_to_str (type) ); - return -EINVAL; - } - if (increment) ++usage_table[i]; - compute_ascii (); - up(&main_lock); - 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 (); - up(&main_lock); - return i; -} /* End Function mtrr_add_page */ - -/** - * mtrr_add - Add a memory type region - * @base: Physical base address of region - * @size: Physical size of region - * @type: Type of MTRR desired - * @increment: If this is true do usage counting on the region - * - * Memory type region registers control the caching on newer Intel and - * non Intel processors. This function allows drivers to request an - * MTRR is added. The details and hardware specifics of each processor's - * implementation are hidden from the caller, but nevertheless the - * caller should expect to need to provide a power of two size on an - * equivalent power of two boundary. - * - * If the region cannot be added either because all regions are in use - * or the CPU cannot support it a negative value is returned. On success - * the register number for this entry is returned, but should be treated - * as a cookie only. - * - * On a multiprocessor machine the changes are made to all processors. - * This is required on x86 by the Intel processors. - * - * The available types are - * - * %MTRR_TYPE_UNCACHABLE - No caching - * - * %MTRR_TYPE_WRBACK - Write data back in bursts whenever - * - * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts - * - * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes - * - * BUGS: Needs a quiet flag for the cases where drivers do not mind - * failures and do not wish system log messages to be sent. - */ - -int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment) -{ -/* [SUMMARY] Add an MTRR entry. - The starting (base) address of the region. - The size (in bytes) of the region. - The type of the new region. - If true and the region already exists, the usage count will be - incremented. - [RETURNS] The MTRR register on success, else a negative number indicating - the error code. -*/ - - if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) - { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; - } - return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment); -} /* End Function mtrr_add */ - -/** - * mtrr_del_page - delete a memory type region - * @reg: Register returned by mtrr_add - * @base: Physical base address - * @size: Size of region - * - * If register is supplied then base and size are ignored. This is - * how drivers should call it. - * - * Releases an MTRR region. If the usage count drops to zero the - * register is freed and the region returns to default state. - * On success the register is returned, on failure a negative error - * code. - */ - -int mtrr_del_page (int reg, unsigned long base, unsigned long size) -/* [SUMMARY] Delete MTRR/decrement usage count. - The register. If this is less than 0 then <> and <> must - be supplied. - The base address of the region. This is ignored if <> is >= 0. - The size of the region. This is ignored if <> is >= 0. - [RETURNS] The register on success, else a negative number indicating - the error code. - [NOTE] This routine uses a spinlock. -*/ -{ - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; - - if ( mtrr_if == MTRR_IF_NONE ) return -ENXIO; - - max = get_num_var_ranges (); - down (&main_lock); - if (reg < 0) - { - /* Search for existing MTRR */ - for (i = 0; i < max; ++i) - { - (*get_mtrr) (i, &lbase, &lsize, <ype); - if (lbase == base && lsize == size) - { - reg = i; - break; - } - } - if (reg < 0) - { - up(&main_lock); - printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size); - return -EINVAL; - } - } - if (reg >= max) - { - up (&main_lock); - printk ("mtrr: register: %d too big\n", reg); - return -EINVAL; - } - if ( mtrr_if == MTRR_IF_CYRIX_ARR ) - { - if ( (reg == 3) && arr3_protected ) - { - up (&main_lock); - printk ("mtrr: ARR3 cannot be changed\n"); - return -EINVAL; - } - } - (*get_mtrr) (reg, &lbase, &lsize, <ype); - if (lsize < 1) - { - 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; - } - if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); - compute_ascii (); - up (&main_lock); - return reg; -} /* End Function mtrr_del_page */ - -/** - * mtrr_del - delete a memory type region - * @reg: Register returned by mtrr_add - * @base: Physical base address - * @size: Size of region - * - * If register is supplied then base and size are ignored. This is - * how drivers should call it. - * - * Releases an MTRR region. If the usage count drops to zero the - * register is freed and the region returns to default state. - * On success the register is returned, on failure a negative error - * code. - */ - -int mtrr_del (int reg, unsigned long base, unsigned long size) -/* [SUMMARY] Delete MTRR/decrement usage count. - The register. If this is less than 0 then <> and <> must - be supplied. - The base address of the region. This is ignored if <> is >= 0. - The size of the region. This is ignored if <> is >= 0. - [RETURNS] The register on success, else a negative number indicating - the error code. -*/ -{ - 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; - } - return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); -} - -#ifdef USERSPACE_INTERFACE - -static int mtrr_file_add (unsigned long base, unsigned long size, - unsigned int type, char increment, struct file *file, int page) -{ - int reg, max; - unsigned int *fcount = file->private_data; - - 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; - } - memset (fcount, 0, max * sizeof *fcount); - file->private_data = fcount; - } - 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; - } - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - } - reg = mtrr_add_page (base, size, type, 1); - if (reg >= 0) ++fcount[reg]; - return reg; -} /* End Function mtrr_file_add */ - -static int mtrr_file_del (unsigned long base, unsigned long size, - struct file *file, int page) -{ - int reg; - unsigned int *fcount = file->private_data; - - 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; - } - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - } - 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; -} /* End Function mtrr_file_del */ - -static ssize_t mtrr_read (struct file *file, char *buf, size_t len, - loff_t *ppos) -{ - if (*ppos >= ascii_buf_bytes) return 0; - if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos; - if ( copy_to_user (buf, ascii_buffer + *ppos, len) ) return -EFAULT; - *ppos += len; - return len; -} /* End Function mtrr_read */ - -static ssize_t mtrr_write (struct file *file, const char *buf, size_t len, - loff_t *ppos) -/* Format of control line: - "base=%Lx size=%Lx type=%s" OR: - "disable=%d" -*/ -{ - int i, err; - unsigned long reg; - unsigned long long base, size; - char *ptr; - char line[LINE_SIZE]; - - 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); - if (len > LINE_SIZE) len = LINE_SIZE; - if ( copy_from_user (line, buf, len - 1) ) return -EFAULT; - 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); - if (err < 0) return err; - return len; - } - if ( strncmp (line, "base=", 5) ) - { - printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); - return -EINVAL; - } - 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; - } - 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; - } - for (; isspace (*ptr); ++ptr); - if ( strncmp (ptr, "type=", 5) ) - { - printk ("mtrr: no \"type=\" in line: \"%s\"\n", line); - return -EINVAL; - } - ptr += 5; - for (; isspace (*ptr); ++ptr); - for (i = 0; i < MTRR_NUM_TYPES; ++i) - { - if ( strcmp (ptr, mtrr_strings[i]) ) continue; - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - err = mtrr_add_page ((unsigned long)base, (unsigned long)size, i, 1); - if (err < 0) return err; - return len; - } - printk ("mtrr: illegal type: \"%s\"\n", ptr); - return -EINVAL; -} /* End Function mtrr_write */ - -static int mtrr_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int err; - mtrr_type type; - struct mtrr_sentry sentry; - struct mtrr_gentry gentry; - - switch (cmd) - { - default: - return -ENOIOCTLCMD; - case MTRRIOC_ADD_ENTRY: - 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 ( !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 ( !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 ( !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); - if (err < 0) return err; - break; - case MTRRIOC_GET_ENTRY: - if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) ) - return -EFAULT; - if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL; - (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); - - /* 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; - } - - if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) ) - return -EFAULT; - break; - case MTRRIOC_ADD_PAGE_ENTRY: - 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 ( !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 ( !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 ( !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); - if (err < 0) return err; - break; - case MTRRIOC_GET_PAGE_ENTRY: - if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) ) - return -EFAULT; - if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL; - (*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; -} /* End Function mtrr_ioctl */ - -static int mtrr_close (struct inode *ino, struct file *file) -{ - int i, max; - unsigned int *fcount = file->private_data; - - if (fcount == NULL) return 0; - 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]; - } - } - kfree (fcount); - file->private_data = NULL; - return 0; -} /* End Function mtrr_close */ - -static struct file_operations mtrr_fops = -{ - owner: THIS_MODULE, - read: mtrr_read, - write: mtrr_write, - ioctl: mtrr_ioctl, - release: mtrr_close, -}; - -# ifdef CONFIG_PROC_FS - -static struct proc_dir_entry *proc_root_mtrr; - -# endif /* CONFIG_PROC_FS */ - -static devfs_handle_t devfs_handle; - -static void compute_ascii (void) -{ - char factor; - int i, max; - mtrr_type type; - unsigned long base, size; - - ascii_buf_bytes = 0; - max = get_num_var_ranges (); - for (i = 0; i < max; i++) - { - (*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; - } - else - { - factor = 'M'; - size >>= 20 - PAGE_SHIFT; - } - sprintf - (ascii_buffer + ascii_buf_bytes, - "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n", - i, base, base >> (20 - PAGE_SHIFT), size, factor, - attrib_to_str (type), usage_table[i]); - ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); - } - } - devfs_set_file_size (devfs_handle, ascii_buf_bytes); -# ifdef CONFIG_PROC_FS - if (proc_root_mtrr) - proc_root_mtrr->size = ascii_buf_bytes; -# endif /* CONFIG_PROC_FS */ -} /* End Function compute_ascii */ - -#endif /* USERSPACE_INTERFACE */ - -EXPORT_SYMBOL(mtrr_add); -EXPORT_SYMBOL(mtrr_del); - -#ifdef CONFIG_SMP - -typedef struct -{ - unsigned long base; - unsigned long size; - mtrr_type type; -} arr_state_t; - -arr_state_t arr_state[8] __initdata = -{ - {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, - {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL} -}; - -unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 }; - -static void __init cyrix_arr_init_secondary(void) -{ - struct set_mtrr_context ctxt; - int i; - - /* flush cache and enable MAPEN */ - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - - /* the CCRs are not contiguous */ - for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]); - for( ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]); - for(i=0; i<8; i++) - cyrix_set_arr_up(i, - arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE); - - set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */ -} /* End Function cyrix_arr_init_secondary */ - -#endif - -/* - * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection - * with the SMM (System Management Mode) mode. So we need the following: - * Check whether SMI_LOCK (CCR3 bit 0) is set - * if it is set, write a warning message: ARR3 cannot be changed! - * (it cannot be changed until the next processor reset) - * if it is reset, then we can change it, set all the needed bits: - * - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset) - * - disable access to SMM memory (CCR1 bit 2 reset) - * - disable SMM mode (CCR1 bit 1 reset) - * - disable write protection of ARR3 (CCR6 bit 1 reset) - * - (maybe) disable ARR3 - * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set) - */ -static void __init cyrix_arr_init(void) -{ - struct set_mtrr_context ctxt; - unsigned char ccr[7]; - int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 }; -#ifdef CONFIG_SMP - int i; -#endif - - /* flush cache and enable MAPEN */ - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - - /* Save all CCRs locally */ - ccr[0] = getCx86 (CX86_CCR0); - ccr[1] = getCx86 (CX86_CCR1); - ccr[2] = getCx86 (CX86_CCR2); - ccr[3] = ctxt.ccr3; - ccr[4] = getCx86 (CX86_CCR4); - ccr[5] = getCx86 (CX86_CCR5); - ccr[6] = getCx86 (CX86_CCR6); - - if (ccr[3] & 1) - { - ccrc[3] = 1; - arr3_protected = 1; - } - else - { - /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and - * access to SMM memory through ARR3 (bit 7). - */ - if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } - if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } - if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } - arr3_protected = 0; - if (ccr[6] & 0x02) { - ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3 */ - setCx86 (CX86_CCR6, ccr[6]); - } - /* Disable ARR3. This is safe now that we disabled SMM. */ - /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ - } - /* If we changed CCR1 in memory, change it in the processor, too. */ - if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]); - - /* Enable ARR usage by the processor */ - if (!(ccr[5] & 0x20)) - { - ccr[5] |= 0x20; ccrc[5] = 1; - setCx86 (CX86_CCR5, ccr[5]); - } - -#ifdef CONFIG_SMP - for(i=0; i<7; i++) ccr_state[i] = ccr[i]; - for(i=0; i<8; i++) - cyrix_get_arr(i, - &arr_state[i].base, &arr_state[i].size, &arr_state[i].type); -#endif - - set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */ - - if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n"); - if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n"); -/* - if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n"); - if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n"); - if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n"); -*/ - if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n"); -} /* End Function cyrix_arr_init */ - -/* - * Initialise the later (saner) Winchip MCR variant. In this version - * the BIOS can pass us the registers it has used (but not their values) - * and the control register is read/write - */ - -static void __init centaur_mcr1_init(void) -{ - unsigned i; - u32 lo, hi; - - /* Unfortunately, MCR's are read-only, so there is no way to - * find out what the bios might have done. - */ - - rdmsr(MSR_IDT_MCR_CTRL, lo, hi); - if(((lo>>17)&7)==1) /* Type 1 Winchip2 MCR */ - { - lo&= ~0x1C0; /* clear key */ - lo|= 0x040; /* set key to 1 */ - wrmsr(MSR_IDT_MCR_CTRL, lo, hi); /* unlock MCR */ - } - - centaur_mcr_type = 1; - - /* - * Clear any unconfigured MCR's. - */ - - for (i = 0; i < 8; ++i) - { - if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) - { - if(!(lo & (1<<(9+i)))) - wrmsr (MSR_IDT_MCR0 + i , 0, 0); - else - /* - * If the BIOS set up an MCR we cannot see it - * but we don't wish to obliterate it - */ - centaur_mcr_reserved |= (1<= 0x80000008)) { - 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; - break; - } - size_or_mask = 0xff000000; /* 36 bits */ - size_and_mask = 0x00f00000; - break; - - case X86_VENDOR_CENTAUR: - /* VIA Cyrix family have Intel style MTRRs, but don't support PAE */ - if (boot_cpu_data.x86 == 6) { - size_or_mask = 0xfff00000; /* 32 bits */ - size_and_mask = 0; - } - break; - - default: - /* Intel, etc. */ - size_or_mask = 0xff000000; /* 36 bits */ - size_and_mask = 0x00f00000; - break; - } - - } else if ( cpu_has_k6_mtrr ) { - /* Pre-Athlon (K6) AMD CPU MTRRs */ - mtrr_if = MTRR_IF_AMD_K6; - get_mtrr = amd_get_mtrr; - set_mtrr_up = amd_set_mtrr_up; - size_or_mask = 0xfff00000; /* 32 bits */ - size_and_mask = 0; - } else if ( cpu_has_cyrix_arr ) { - /* Cyrix ARRs */ - mtrr_if = MTRR_IF_CYRIX_ARR; - get_mtrr = cyrix_get_arr; - set_mtrr_up = cyrix_set_arr_up; - get_free_region = cyrix_get_free_region; - cyrix_arr_init(); - size_or_mask = 0xfff00000; /* 32 bits */ - size_and_mask = 0; - } else if ( cpu_has_centaur_mcr ) { - /* Centaur MCRs */ - mtrr_if = MTRR_IF_CENTAUR_MCR; - get_mtrr = centaur_get_mcr; - set_mtrr_up = centaur_set_mcr_up; - get_free_region = centaur_get_free_region; - centaur_mcr_init(); - size_or_mask = 0xfff00000; /* 32 bits */ - size_and_mask = 0; - } else { - /* No supported MTRR interface */ - mtrr_if = MTRR_IF_NONE; - } - - printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n" - "mtrr: detected mtrr type: %s\n", - MTRR_VERSION, mtrr_if_name[mtrr_if]); - - return (mtrr_if != MTRR_IF_NONE); -} /* End Function mtrr_setup */ - -#ifdef CONFIG_SMP - -static volatile unsigned long smp_changes_mask __initdata = 0; -static struct mtrr_state smp_mtrr_state __initdata = {0, 0}; - -void __init mtrr_init_boot_cpu(void) -{ - if ( !mtrr_setup () ) - return; - - if ( mtrr_if == MTRR_IF_INTEL ) { - /* Only for Intel MTRRs */ - get_mtrr_state (&smp_mtrr_state); - } -} /* End Function mtrr_init_boot_cpu */ - -static void __init intel_mtrr_init_secondary_cpu(void) -{ - unsigned long mask, count; - struct set_mtrr_context ctxt; - - /* Note that this is not ideal, since the cache is only flushed/disabled - for this CPU while the MTRRs are changed, but changing this requires - more invasive changes to the way the kernel boots */ - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - mask = set_mtrr_state (&smp_mtrr_state, &ctxt); - set_mtrr_done (&ctxt); - /* 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; - } -} /* End Function intel_mtrr_init_secondary_cpu */ - -void __init mtrr_init_secondary_cpu(void) -{ - switch ( mtrr_if ) { - case MTRR_IF_INTEL: - /* Intel (P6) standard MTRRs */ - intel_mtrr_init_secondary_cpu(); - break; - case MTRR_IF_CYRIX_ARR: - /* This is _completely theoretical_! - * I assume here that one day Cyrix will support Intel APIC. - * In reality on non-Intel CPUs we won't even get to this routine. - * Hopefully no one will plug two Cyrix processors in a dual P5 board. - * :-) - */ - cyrix_arr_init_secondary (); - break; - case MTRR_IF_NONE: - break; - default: - /* I see no MTRRs I can support in SMP mode... */ - printk ("mtrr: SMP support incomplete for this vendor\n"); - } -} /* End Function mtrr_init_secondary_cpu */ -#endif /* CONFIG_SMP */ - -int __init mtrr_init(void) -{ -#ifdef CONFIG_SMP - /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */ - - if ( mtrr_if == MTRR_IF_INTEL ) { - finalize_mtrr_state (&smp_mtrr_state); - mtrr_state_warn (smp_changes_mask); - } -#else - if ( !mtrr_setup() ) - return 0; /* MTRRs not supported? */ -#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; - } -#endif -#ifdef USERSPACE_INTERFACE - 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; -} /* End Function mtrr_init */ - -/* - * Local Variables: - * mode:c - * c-file-style:"k&r" - * c-basic-offset:4 - * End: - */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/nmi.c linux-2.5/arch/i386/kernel/nmi.c --- linux-2.5.23/arch/i386/kernel/nmi.c Wed Jun 19 03:11:55 2002 +++ linux-2.5/arch/i386/kernel/nmi.c Wed Jun 19 21:35:14 2002 @@ -72,19 +72,20 @@ int __init check_nmi_watchdog (void) { - irq_cpustat_t tmp[NR_CPUS]; + unsigned int prev_nmi_count[NR_CPUS]; int cpu; printk(KERN_INFO "testing NMI watchdog ... "); - memcpy(tmp, irq_stat, sizeof(tmp)); + for (cpu = 0; cpu < NR_CPUS; ++cpu) + prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count; sti(); mdelay((10*1000)/nmi_hz); // wait 10 ticks for (cpu = 0; cpu < NR_CPUS; cpu++) { if (!cpu_online(cpu)) continue; - if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) { + if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) { printk("CPU#%d: NMI appears to be stuck!\n", cpu); return -1; } @@ -345,7 +346,7 @@ */ int sum, cpu = smp_processor_id(); - sum = apic_timer_irqs[cpu]; + sum = irq_stat[cpu].apic_timer_irqs; if (last_irq_sums[cpu] == sum) { /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/process.c linux-2.5/arch/i386/kernel/process.c --- linux-2.5.23/arch/i386/kernel/process.c Wed Jun 19 03:11:44 2002 +++ linux-2.5/arch/i386/kernel/process.c Mon Jun 17 22:52:25 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 */ }; @@ -542,6 +535,8 @@ BUG(); } } + + release_x86_irqs(dead_task); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/semaphore.c linux-2.5/arch/i386/kernel/semaphore.c --- linux-2.5.23/arch/i386/kernel/semaphore.c Wed Jun 19 03:11:53 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.23/arch/i386/kernel/smp.c linux-2.5/arch/i386/kernel/smp.c --- linux-2.5.23/arch/i386/kernel/smp.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/arch/i386/kernel/smp.c Wed Jun 19 07:35:18 2002 @@ -104,7 +104,7 @@ */ /* The 'big kernel lock' */ -spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +spinlock_cacheline_t kernel_flag_cacheline = {SPIN_LOCK_UNLOCKED}; struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0, }}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/smpboot.c linux-2.5/arch/i386/kernel/smpboot.c --- linux-2.5.23/arch/i386/kernel/smpboot.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/arch/i386/kernel/smpboot.c Wed Jun 19 20:17:43 2002 @@ -50,11 +50,11 @@ #include #include -/* Set if we find a B stepping CPU */ -static int smp_b_stepping; +/* Set if we find a B stepping CPU */ +static int __initdata smp_b_stepping; /* Setup configured maximum number of CPUs to activate */ -static int max_cpus = -1; +static int __initdata max_cpus = NR_CPUS; /* Number of siblings per CPU package */ int smp_num_siblings = 1; @@ -1146,7 +1146,7 @@ if (!(phys_cpu_present_map & (1 << bit))) continue; - if ((max_cpus >= 0) && (max_cpus <= cpucount+1)) + if (max_cpus <= cpucount+1) continue; do_boot_cpu(apicid); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/time.c linux-2.5/arch/i386/kernel/time.c --- linux-2.5.23/arch/i386/kernel/time.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/arch/i386/kernel/time.c Wed Jun 19 07:35:18 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 @@ -472,6 +475,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 @@ -500,6 +507,7 @@ rdtscl(last_tsc_low); +#ifndef CONFIG_CS5520 spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -512,6 +520,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); @@ -575,6 +636,8 @@ static unsigned long __init calibrate_tsc(void) { + unsigned long flags; + /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); @@ -585,9 +648,11 @@ * (interrupt on terminal count mode), binary count, * load 5 * LATCH count, (LSB and MSB) to begin countdown. */ + spin_lock_irqsave(&i8253_lock, flags); outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ + spin_unlock_irqrestore(&i8253_lock, flags); { unsigned long startlow, starthigh; @@ -686,6 +751,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.23/arch/i386/kernel/traps.c linux-2.5/arch/i386/kernel/traps.c --- linux-2.5.23/arch/i386/kernel/traps.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/arch/i386/kernel/traps.c Sat May 25 19:51:58 2002 @@ -955,8 +955,8 @@ } #endif -#ifdef CONFIG_EISA int EISA_bus; +#ifdef CONFIG_EISA static struct resource eisa_id = { "EISA ID", 0xc80, 0xc83, IORESOURCE_BUSY }; #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/kernel/vm86.c linux-2.5/arch/i386/kernel/vm86.c --- linux-2.5.23/arch/i386/kernel/vm86.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/arch/i386/kernel/vm86.c Sun May 26 01:38:09 2002 @@ -18,6 +18,7 @@ #include #include #include +#include /* * Known problems: @@ -98,23 +99,24 @@ pte_t *pte, *mapped; int i; + preempt_disable(); + spin_lock(&tsk->mm->page_table_lock); pgd = pgd_offset(tsk->mm, 0xA0000); if (pgd_none(*pgd)) - return; + goto out; if (pgd_bad(*pgd)) { pgd_ERROR(*pgd); pgd_clear(pgd); - return; + goto out; } pmd = pmd_offset(pgd, 0xA0000); if (pmd_none(*pmd)) - return; + goto out; if (pmd_bad(*pmd)) { pmd_ERROR(*pmd); pmd_clear(pmd); - return; + goto out; } - preempt_disable(); pte = mapped = pte_offset_map(pmd, 0xA0000); for (i = 0; i < 32; i++) { if (pte_present(*pte)) @@ -122,6 +124,8 @@ pte++; } pte_unmap(mapped); +out: + spin_unlock(&tsk->mm->page_table_lock); preempt_enable(); flush_tlb(); } @@ -331,74 +335,176 @@ * Boy are these ugly, but we need to do the correct 16-bit arithmetic. * Gcc makes a mess of it, so we do it inline and use non-obvious calling * conventions.. + * FIXME: is VM86_UNKNOWN really the correct return code? */ -#define pushb(base, ptr, val) \ -__asm__ __volatile__( \ - "decw %w0\n\t" \ - "movb %2,0(%1,%0)" \ - : "=r" (ptr) \ - : "r" (base), "q" (val), "0" (ptr)) - -#define pushw(base, ptr, val) \ -__asm__ __volatile__( \ - "decw %w0\n\t" \ - "movb %h2,0(%1,%0)\n\t" \ - "decw %w0\n\t" \ - "movb %b2,0(%1,%0)" \ - : "=r" (ptr) \ - : "r" (base), "q" (val), "0" (ptr)) - -#define pushl(base, ptr, val) \ -__asm__ __volatile__( \ - "decw %w0\n\t" \ - "rorl $16,%2\n\t" \ - "movb %h2,0(%1,%0)\n\t" \ - "decw %w0\n\t" \ - "movb %b2,0(%1,%0)\n\t" \ - "decw %w0\n\t" \ - "rorl $16,%2\n\t" \ - "movb %h2,0(%1,%0)\n\t" \ - "decw %w0\n\t" \ - "movb %b2,0(%1,%0)" \ - : "=r" (ptr) \ - : "r" (base), "q" (val), "0" (ptr)) - -#define popb(base, ptr) \ -({ unsigned long __res; \ -__asm__ __volatile__( \ - "movb 0(%1,%0),%b2\n\t" \ - "incw %w0" \ - : "=r" (ptr), "=r" (base), "=q" (__res) \ - : "0" (ptr), "1" (base), "2" (0)); \ -__res; }) - -#define popw(base, ptr) \ -({ unsigned long __res; \ -__asm__ __volatile__( \ - "movb 0(%1,%0),%b2\n\t" \ - "incw %w0\n\t" \ - "movb 0(%1,%0),%h2\n\t" \ - "incw %w0" \ - : "=r" (ptr), "=r" (base), "=q" (__res) \ - : "0" (ptr), "1" (base), "2" (0)); \ -__res; }) - -#define popl(base, ptr) \ -({ unsigned long __res; \ -__asm__ __volatile__( \ - "movb 0(%1,%0),%b2\n\t" \ - "incw %w0\n\t" \ - "movb 0(%1,%0),%h2\n\t" \ - "incw %w0\n\t" \ - "rorl $16,%2\n\t" \ - "movb 0(%1,%0),%b2\n\t" \ - "incw %w0\n\t" \ - "movb 0(%1,%0),%h2\n\t" \ - "incw %w0\n\t" \ - "rorl $16,%2" \ - : "=r" (ptr), "=r" (base), "=q" (__res) \ - : "0" (ptr), "1" (base)); \ -__res; }) +#define pushb(base, ptr, val, regs) \ + do { \ + int err; \ + __asm__ __volatile__( \ + "decw %w0\n\t" \ + "1: movb %3,0(%2,%0)\n\t" \ + "xor %1,%1\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "3: movl $1,%1\n\t" \ + " jmp 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (err) \ + : "r" (base), "q" (val), "0" (ptr)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + } while(0) + +#define pushw(base, ptr, val, regs) \ + do { \ + int err; \ + __asm__ __volatile__( \ + "decw %w0\n\t" \ + "1: movb %h3,0(%2,%0)\n\t" \ + "decw %w0\n\t" \ + "2: movb %b3,0(%2,%0)\n\t" \ + "xor %1,%1\n\t" \ + "3:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "4: movl $1,%1\n\t" \ + " jmp 3b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,4b\n" \ + " .long 2b,4b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (err) \ + : "r" (base), "q" (val), "0" (ptr)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + } while(0) + +#define pushl(base, ptr, val, regs) \ + do { \ + int err; \ + __asm__ __volatile__( \ + "decw %w0\n\t" \ + "rorl $16,%3\n\t" \ + "1: movb %h3,0(%2,%0)\n\t" \ + "decw %w0\n\t" \ + "2: movb %b3,0(%2,%0)\n\t" \ + "decw %w0\n\t" \ + "rorl $16,%3\n\t" \ + "3: movb %h3,0(%2,%0)\n\t" \ + "decw %w0\n\t" \ + "4: movb %b3,0(%2,%0)\n\t" \ + "xor %1,%1\n\t" \ + "5:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "6: movl $1,%1\n\t" \ + " jmp 5b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,6b\n" \ + " .long 2b,6b\n" \ + " .long 3b,6b\n" \ + " .long 4b,6b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (err) \ + : "r" (base), "q" (val), "0" (ptr)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + } while(0) + +#define popb(base, ptr, regs) \ + ({ \ + unsigned long __res; \ + unsigned int err; \ + __asm__ __volatile__( \ + "1:movb 0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "xor %3,%3\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "3: movl $1,%3\n\t" \ + " jmp 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (base), "=q" (__res), \ + "=r" (err) \ + : "0" (ptr), "1" (base), "2" (0)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + __res; \ + }) + +#define popw(base, ptr, regs) \ + ({ \ + unsigned long __res; \ + unsigned int err; \ + __asm__ __volatile__( \ + "1:movb 0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "2:movb 0(%1,%0),%h2\n\t" \ + "incw %w0\n\t" \ + "xor %3,%3\n\t" \ + "3:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "4: movl $1,%3\n\t" \ + " jmp 3b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,4b\n" \ + " .long 2b,4b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (base), "=q" (__res), \ + "=r" (err) \ + : "0" (ptr), "1" (base), "2" (0)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + __res; \ + }) + +#define popl(base, ptr, regs) \ + ({ \ + unsigned long __res; \ + unsigned int err; \ + __asm__ __volatile__( \ + "1:movb 0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "2:movb 0(%1,%0),%h2\n\t" \ + "incw %w0\n\t" \ + "rorl $16,%2\n\t" \ + "3:movb 0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "4:movb 0(%1,%0),%h2\n\t" \ + "incw %w0\n\t" \ + "rorl $16,%2\n\t" \ + "xor %3,%3\n\t" \ + "5:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "6: movl $1,%3\n\t" \ + " jmp 5b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,6b\n" \ + " .long 2b,6b\n" \ + " .long 3b,6b\n" \ + " .long 4b,6b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (base), "=q" (__res), \ + "=r" (err) \ + : "0" (ptr), "1" (base), "2" (0)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + __res; \ + }) static void do_int(struct kernel_vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp) { @@ -415,9 +521,9 @@ goto cannot_handle; if ((segoffs >> 16) == BIOSSEG) goto cannot_handle; - pushw(ssp, sp, get_vflags(regs)); - pushw(ssp, sp, regs->cs); - pushw(ssp, sp, IP(regs)); + pushw(ssp, sp, get_vflags(regs), regs); + pushw(ssp, sp, regs->cs, regs); + pushw(ssp, sp, IP(regs), regs); regs->cs = segoffs >> 16; SP(regs) -= 6; IP(regs) = segoffs & 0xffff; @@ -459,7 +565,7 @@ #define CHECK_IF_IN_TRAP \ if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \ - pushw(ssp,sp,popw(ssp,sp) | TF_MASK); + pushw(ssp,sp,popw(ssp,sp, regs) | TF_MASK, regs); #define VM86_FAULT_RETURN \ if (VMPI.force_return_for_pic && (VEFLAGS & (IF_MASK | VIF_MASK))) \ return_to_32bit(regs, VM86_PICRETURN); \ @@ -470,17 +576,17 @@ sp = SP(regs); ip = IP(regs); - switch (popb(csp, ip)) { + switch (popb(csp, ip, regs)) { /* operand size override */ case 0x66: - switch (popb(csp, ip)) { + switch (popb(csp, ip, regs)) { /* pushfd */ case 0x9c: SP(regs) -= 4; IP(regs) += 2; - pushl(ssp, sp, get_vflags(regs)); + pushl(ssp, sp, get_vflags(regs), regs); VM86_FAULT_RETURN; /* popfd */ @@ -488,16 +594,16 @@ SP(regs) += 4; IP(regs) += 2; CHECK_IF_IN_TRAP - set_vflags_long(popl(ssp, sp), regs); + set_vflags_long(popl(ssp, sp, regs), regs); VM86_FAULT_RETURN; /* iretd */ case 0xcf: SP(regs) += 12; - IP(regs) = (unsigned short)popl(ssp, sp); - regs->cs = (unsigned short)popl(ssp, sp); + IP(regs) = (unsigned short)popl(ssp, sp, regs); + regs->cs = (unsigned short)popl(ssp, sp, regs); CHECK_IF_IN_TRAP - set_vflags_long(popl(ssp, sp), regs); + set_vflags_long(popl(ssp, sp, regs), regs); VM86_FAULT_RETURN; /* need this to avoid a fallthrough */ default: @@ -508,7 +614,7 @@ case 0x9c: SP(regs) -= 2; IP(regs)++; - pushw(ssp, sp, get_vflags(regs)); + pushw(ssp, sp, get_vflags(regs), regs); VM86_FAULT_RETURN; /* popf */ @@ -516,12 +622,12 @@ SP(regs) += 2; IP(regs)++; CHECK_IF_IN_TRAP - set_vflags_short(popw(ssp, sp), regs); + set_vflags_short(popw(ssp, sp, regs), regs); VM86_FAULT_RETURN; /* int xx */ case 0xcd: { - int intno=popb(csp, ip); + int intno=popb(csp, ip, regs); IP(regs) += 2; if (VMPI.vm86dbg_active) { if ( (1 << (intno &7)) & VMPI.vm86dbg_intxxtab[intno >> 3] ) @@ -534,10 +640,10 @@ /* iret */ case 0xcf: SP(regs) += 6; - IP(regs) = popw(ssp, sp); - regs->cs = popw(ssp, sp); + IP(regs) = popw(ssp, sp, regs); + regs->cs = popw(ssp, sp, regs); CHECK_IF_IN_TRAP - set_vflags_short(popw(ssp, sp), regs); + set_vflags_short(popw(ssp, sp, regs), regs); VM86_FAULT_RETURN; /* cli */ @@ -615,6 +721,14 @@ } read_unlock(&tasklist_lock); return ret; +} + +void release_x86_irqs(struct task_struct *task) +{ + int i; + for (i=3; i<16; i++) + if (vm86_irqs[i].tsk == task) + free_vm86_irq(i); } static inline void handle_irq_zombies(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/math-emu/fpu_system.h linux-2.5/arch/i386/math-emu/fpu_system.h --- linux-2.5.23/arch/i386/math-emu/fpu_system.h Wed Jun 19 03:11:52 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.23/arch/i386/math-emu/reg_add_sub.c linux-2.5/arch/i386/math-emu/reg_add_sub.c --- linux-2.5.23/arch/i386/math-emu/reg_add_sub.c Wed Jun 19 03:11:55 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.23/arch/i386/math-emu/reg_compare.c linux-2.5/arch/i386/math-emu/reg_compare.c --- linux-2.5.23/arch/i386/math-emu/reg_compare.c Wed Jun 19 03:11:51 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.23/arch/i386/math-emu/reg_divide.c linux-2.5/arch/i386/math-emu/reg_divide.c --- linux-2.5.23/arch/i386/math-emu/reg_divide.c Wed Jun 19 03:11:56 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.23/arch/i386/math-emu/reg_ld_str.c linux-2.5/arch/i386/math-emu/reg_ld_str.c --- linux-2.5.23/arch/i386/math-emu/reg_ld_str.c Wed Jun 19 03:11:48 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.23/arch/i386/math-emu/reg_mul.c linux-2.5/arch/i386/math-emu/reg_mul.c --- linux-2.5.23/arch/i386/math-emu/reg_mul.c Wed Jun 19 03:11:51 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.23/arch/i386/mm/fault.c linux-2.5/arch/i386/mm/fault.c --- linux-2.5.23/arch/i386/mm/fault.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/arch/i386/mm/fault.c Tue Jun 18 16:20:24 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.. */ @@ -56,12 +54,16 @@ for (;;) { survive: - { - int fault = handle_mm_fault(current->mm, vma, start, 1); - if (!fault) + switch (handle_mm_fault(current->mm, vma, start, 1)) { + case VM_FAULT_SIGBUS: goto bad_area; - if (fault < 0) + case VM_FAULT_OOM: goto out_of_memory; + case VM_FAULT_MINOR: + case VM_FAULT_MAJOR: + break; + default: + BUG(); } if (!size) break; @@ -239,16 +241,18 @@ * the fault. */ switch (handle_mm_fault(mm, vma, address, write)) { - case 1: - tsk->min_flt++; - break; - case 2: - tsk->maj_flt++; - break; - case 0: - goto do_sigbus; - default: - goto out_of_memory; + case VM_FAULT_MINOR: + tsk->min_flt++; + break; + case VM_FAULT_MAJOR: + tsk->maj_flt++; + break; + case VM_FAULT_SIGBUS: + goto do_sigbus; + case VM_FAULT_OOM: + goto out_of_memory; + default: + BUG(); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/mm/init.c linux-2.5/arch/i386/mm/init.c --- linux-2.5.23/arch/i386/mm/init.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/arch/i386/mm/init.c Fri May 31 02:30:36 2002 @@ -405,21 +405,26 @@ void __init mem_init(void) { +#ifdef CONFIG_HIGHMEM +# ifdef CONFIG_M686 extern int ppro_with_ram_bug(void); + int bad_ppro = ppro_with_ram_bug(); +# else + int bad_ppro = 0; +# endif +#endif int codesize, reservedpages, datasize, initsize; int tmp; - int bad_ppro; if (!mem_map) BUG(); - bad_ppro = ppro_with_ram_bug(); - #ifdef CONFIG_HIGHMEM highmem_start_page = mem_map + highstart_pfn; max_mapnr = num_physpages = highend_pfn; + num_mappedpages = max_low_pfn; #else - max_mapnr = num_physpages = max_low_pfn; + max_mapnr = num_mappedpages = num_physpages = max_low_pfn; #endif high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); @@ -461,7 +466,7 @@ datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", + printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codesize >> 10, @@ -525,14 +530,14 @@ free_page(addr); totalram_pages++; } - printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); + printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { if (start < end) - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/i386/pci/fixup.c linux-2.5/arch/i386/pci/fixup.c --- linux-2.5.23/arch/i386/pci/fixup.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/arch/i386/pci/fixup.c Wed Jun 12 03:01:48 2002 @@ -157,7 +157,7 @@ causes screen corruption on the KL133/KM133 */ } - pci_read_config_byte(d, where, &v); + pci_read_config_byte(d, where, &v); if (v & ~mask) { printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ d->device, revision, where, v, mask, v & mask); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/ia64/config.in linux-2.5/arch/ia64/config.in --- linux-2.5.23/arch/ia64/config.in Wed Jun 19 03:11:55 2002 +++ linux-2.5/arch/ia64/config.in Sat Jun 1 00:34:32 2002 @@ -195,9 +195,6 @@ fi # !HP_SIM -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in source drivers/char/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/ia64/ia32/sys_ia32.c linux-2.5/arch/ia64/ia32/sys_ia32.c --- linux-2.5.23/arch/ia64/ia32/sys_ia32.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/arch/ia64/ia32/sys_ia32.c Wed Jun 19 07:35:18 2002 @@ -3756,12 +3756,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.23/arch/m68k/amiga/config.c linux-2.5/arch/m68k/amiga/config.c --- linux-2.5.23/arch/m68k/amiga/config.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/arch/m68k/amiga/config.c Fri May 10 02:05:24 2002 @@ -70,11 +70,13 @@ extern char m68k_debug_device[]; static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); +#ifndef CONFIG_KEYBOARD_AMIGA /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode); +#endif /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -389,9 +391,11 @@ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); mach_sched_init = amiga_sched_init; +#ifndef CONFIG_KEYBOARD_AMIGA mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; mach_kbd_translate = amiga_kbd_translate; +#endif SYSRQ_KEY = 0xff; mach_init_IRQ = amiga_init_IRQ; mach_default_handler = &amiga_default_handler; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/mips/Config.help linux-2.5/arch/mips/Config.help --- linux-2.5.23/arch/mips/Config.help Wed Jun 19 03:11:55 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.23/arch/mips/au1000/common/serial.c linux-2.5/arch/mips/au1000/common/serial.c --- linux-2.5.23/arch/mips/au1000/common/serial.c Wed Jun 19 03:11:51 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.23/arch/mips/baget/vacserial.c linux-2.5/arch/mips/baget/vacserial.c --- linux-2.5.23/arch/mips/baget/vacserial.c Wed Jun 19 03:11:56 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.23/arch/mips/config.in linux-2.5/arch/mips/config.in --- linux-2.5.23/arch/mips/config.in Wed Jun 19 03:11:56 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.23/arch/mips/jazz/setup.c linux-2.5/arch/mips/jazz/setup.c --- linux-2.5.23/arch/mips/jazz/setup.c Wed Jun 19 03:11:48 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.23/arch/mips/kernel/time.c linux-2.5/arch/mips/kernel/time.c --- linux-2.5.23/arch/mips/kernel/time.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/arch/mips/kernel/time.c Wed Jun 19 20:44:45 2002 @@ -3,7 +3,7 @@ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * * Common time service routines for MIPS machines. See - * Documents/MIPS/README.txt. + * Documentation/mips/time.README. * * 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 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/mips64/Config.help linux-2.5/arch/mips64/Config.help --- linux-2.5.23/arch/mips64/Config.help Wed Jun 19 03:11:51 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.23/arch/mips64/config.in linux-2.5/arch/mips64/config.in --- linux-2.5.23/arch/mips64/config.in Wed Jun 19 03:11:48 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.23/arch/mips64/kernel/ioctl32.c linux-2.5/arch/mips64/kernel/ioctl32.c --- linux-2.5.23/arch/mips64/kernel/ioctl32.c Wed Jun 19 03:11:55 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.23/arch/parisc/config.in linux-2.5/arch/parisc/config.in --- linux-2.5.23/arch/parisc/config.in Wed Jun 19 03:11:59 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.23/arch/parisc/kernel/pdc_cons.c linux-2.5/arch/parisc/kernel/pdc_cons.c --- linux-2.5.23/arch/parisc/kernel/pdc_cons.c Wed Jun 19 03:11:50 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.23/arch/parisc/kernel/traps.c linux-2.5/arch/parisc/kernel/traps.c --- linux-2.5.23/arch/parisc/kernel/traps.c Wed Jun 19 03:11:55 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.23/arch/ppc/4xx_io/serial_sicc.c linux-2.5/arch/ppc/4xx_io/serial_sicc.c --- linux-2.5.23/arch/ppc/4xx_io/serial_sicc.c Wed Jun 19 03:11:45 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.23/arch/ppc/8260_io/uart.c linux-2.5/arch/ppc/8260_io/uart.c --- linux-2.5.23/arch/ppc/8260_io/uart.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/arch/ppc/8260_io/uart.c Sat Jun 1 00:34:33 2002 @@ -2534,7 +2534,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/ppc/8xx_io/uart.c linux-2.5/arch/ppc/8xx_io/uart.c --- linux-2.5.23/arch/ppc/8xx_io/uart.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/arch/ppc/8xx_io/uart.c Sat Jun 1 00:34:33 2002 @@ -481,7 +481,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } else @@ -2582,7 +2582,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/ppc/Config.help linux-2.5/arch/ppc/Config.help --- linux-2.5.23/arch/ppc/Config.help Wed Jun 19 03:11:50 2002 +++ linux-2.5/arch/ppc/Config.help Sat Jun 1 00:34:33 2002 @@ -247,6 +247,31 @@ includes a server that supports the frame buffer device directly (XF68_FBDev). +CONFIG_VIODASD + If you are running on an iSeries system and you want to use + virtual disks created and managed by OS/400, say Y. + +CONFIG_VIODASD_IDE + This causes the iSeries virtual disks to look like IDE disks. + If you have programs or utilities that only support certain + kinds of disks, this option will cause iSeries virtual disks + to pretend to be IDE disks, which may satisfy the program. + +CONFIG_VIOCD + If you are running Linux on an IBM iSeries system and you want to + read a CD drive owned by OS/400, say Y here. + +CONFIG_VIOTAPE + If you are running Linux on an iSeries system and you want Linux + to read and/or write a tape drive owned by OS/400, say Y here. + +CONFIG_PMAC_APM_EMU + This driver provides an emulated /dev/apm_bios and /proc/apm. The + first one is mostly intended for XFree to sleep & wakeup properly, + the second one provides some battery information to allow existing + APM utilities to work. It provides less useful information than + tools specifically designed for PowerBooks or /proc/pmu/battery_x. + CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or any other SCSI device under Linux, say Y and make sure that you know diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/ppc/amiga/config.c linux-2.5/arch/ppc/amiga/config.c --- linux-2.5.23/arch/ppc/amiga/config.c Wed Jun 19 03:11:51 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.23/arch/ppc/xmon/start.c linux-2.5/arch/ppc/xmon/start.c --- linux-2.5.23/arch/ppc/xmon/start.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/arch/ppc/xmon/start.c Fri May 10 02:05:25 2002 @@ -98,7 +98,7 @@ #ifdef CONFIG_MAGIC_SYSRQ static void sysrq_handle_xmon(int key, struct pt_regs *regs, - struct kbd_struct *kbd, struct tty_struct *tty) + struct tty_struct *tty) { xmon(regs); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/ppc64/kernel/chrp_setup.c linux-2.5/arch/ppc64/kernel/chrp_setup.c --- linux-2.5.23/arch/ppc64/kernel/chrp_setup.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/arch/ppc64/kernel/chrp_setup.c Mon Jun 17 22:52:25 2002 @@ -122,12 +122,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.23/arch/ppc64/kernel/ioctl32.c linux-2.5/arch/ppc64/kernel/ioctl32.c --- linux-2.5.23/arch/ppc64/kernel/ioctl32.c Wed Jun 19 03:11:59 2002 +++ linux-2.5/arch/ppc64/kernel/ioctl32.c Mon Jun 3 17:10:19 2002 @@ -1794,6 +1794,8 @@ static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) { + struct tty_struct *tty = (struct tty_struct *) file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct consolefontdesc cfdarg; struct console_font_op op; int i, perm; @@ -1816,7 +1818,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); + return con_font_op(vc->display_fg->vc_cons[fg_console], &op); case GIO_FONTX: if (!cfdarg.chardata) return 0; @@ -1826,7 +1828,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); + i = con_font_op(vc->display_fg->vc_cons[fg_console], &op); if (i) return i; cfdarg.charheight = op.height; @@ -1849,9 +1851,10 @@ static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) { + struct tty_struct *tty = (struct tty_struct *) file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct console_font_op op; int perm = vt_check(file), i; - struct vt_struct *vt; if (perm < 0) return perm; @@ -1861,8 +1864,7 @@ return -EPERM; op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data); op.flags |= KD_FONT_FLAG_OLD; - vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; - i = con_font_op(vt->vc_num, &op); + i = con_font_op(vc, &op); if (i) return i; ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) @@ -1870,6 +1872,33 @@ return 0; } +struct unimapdesc32 { + unsigned short entry_ct; + u32 entries; +}; + +static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) +{ + struct tty_struct *tty = (struct tty_struct *) file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; + struct unimapdesc32 tmp; + int perm = vt_check(file); + + if (perm < 0) return perm; + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + switch (cmd) { + case PIO_UNIMAP: + if (!perm) return -EPERM; + return con_set_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, (struct unipair *)A(tmp.entries)); + case GIO_UNIMAP: + return con_get_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); + } + return 0; +} +#endif /* CONFIG_VT */ + +#ifdef CONFIG_FB struct fb_fix_screeninfo32 { char id[16]; /* identification string eg "TT Builtin" */ unsigned int smem_start; /* Start of frame buffer mem */ @@ -1994,29 +2023,8 @@ return err; } -struct unimapdesc32 { - unsigned short entry_ct; - u32 entries; -}; +#endif /* CONFIG_FB */ -static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) -{ - struct unimapdesc32 tmp; - int perm = vt_check(file); - - if (perm < 0) return perm; - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - switch (cmd) { - case PIO_UNIMAP: - if (!perm) return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries)); - case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); - } - return 0; -} -#endif /* CONFIG_VT */ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); @@ -4465,6 +4473,8 @@ HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl), HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl), HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl), +#endif +#ifdef CONFIG_FB HANDLE_IOCTL(FBIOGET_FSCREENINFO, do_fbioget_fscreeninfo_ioctl), HANDLE_IOCTL(FBIOGETCMAP, do_fbiogetcmap_ioctl), HANDLE_IOCTL(FBIOPUTCMAP, do_fbioputcmap_ioctl), diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/ppc64/kernel/sys_ppc32.c linux-2.5/arch/ppc64/kernel/sys_ppc32.c --- linux-2.5.23/arch/ppc64/kernel/sys_ppc32.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/arch/ppc64/kernel/sys_ppc32.c Wed Jun 19 07:35:18 2002 @@ -357,12 +357,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.23/arch/ppc64/xmon/start.c linux-2.5/arch/ppc64/xmon/start.c --- linux-2.5.23/arch/ppc64/xmon/start.c Wed Jun 19 03:11:55 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.23/arch/s390/Config.help linux-2.5/arch/s390/Config.help --- linux-2.5.23/arch/s390/Config.help Wed Jun 19 03:11:48 2002 +++ linux-2.5/arch/s390/Config.help Wed Jun 19 14:51:45 2002 @@ -177,7 +177,7 @@ obtained by channel subsystem calls. This will enable Linux to process link failures and resource accessibility events. Moreover, if you have procfs enabled, you'll be able to toggle chpids logically offline and online. Even - if you don't understand what this means, you should say "Y". + if you don't understand what this means, you should say "Y" CONFIG_PROCESS_DEBUG Say Y to print all process fault locations to the console. This is diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/s390x/kernel/linux32.c linux-2.5/arch/s390x/kernel/linux32.c --- linux-2.5.23/arch/s390x/kernel/linux32.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/arch/s390x/kernel/linux32.c Wed Jun 12 03:01:49 2002 @@ -1564,12 +1564,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.23/arch/sh/config.in linux-2.5/arch/sh/config.in --- linux-2.5.23/arch/sh/config.in Wed Jun 19 03:11:55 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.23/arch/sh/kernel/hd64465_gpio.c linux-2.5/arch/sh/kernel/hd64465_gpio.c --- linux-2.5.23/arch/sh/kernel/hd64465_gpio.c Wed Jun 19 03:11:57 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.23/arch/sh/kernel/pci-sh7751.c linux-2.5/arch/sh/kernel/pci-sh7751.c --- linux-2.5.23/arch/sh/kernel/pci-sh7751.c Wed Jun 19 03:11:48 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.23/arch/sparc/defconfig linux-2.5/arch/sparc/defconfig --- linux-2.5.23/arch/sparc/defconfig Wed Jun 19 03:11:57 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.23/arch/sparc/kernel/sunos_ioctl.c linux-2.5/arch/sparc/kernel/sunos_ioctl.c --- linux-2.5.23/arch/sparc/kernel/sunos_ioctl.c Wed Jun 19 03:11:52 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.23/arch/sparc64/config.in linux-2.5/arch/sparc64/config.in --- linux-2.5.23/arch/sparc64/config.in Wed Jun 19 03:11:51 2002 +++ linux-2.5/arch/sparc64/config.in Wed May 1 20:36:25 2002 @@ -292,5 +292,3 @@ fi endmenu - -source lib/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/sparc64/defconfig linux-2.5/arch/sparc64/defconfig --- linux-2.5.23/arch/sparc64/defconfig Wed Jun 19 03:11:52 2002 +++ linux-2.5/arch/sparc64/defconfig Wed Jun 19 07:35:18 2002 @@ -289,8 +289,6 @@ CONFIG_IDEDMA_PCI_AUTO=y CONFIG_IDEDMA_ONLYDISK=y CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_BLK_DEV_IDE_TCQ is not set -# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_AEC6280_BURST is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/sparc64/kernel/ioctl32.c linux-2.5/arch/sparc64/kernel/ioctl32.c --- linux-2.5.23/arch/sparc64/kernel/ioctl32.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/arch/sparc64/kernel/ioctl32.c Fri May 10 02:05:25 2002 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.136 2002/01/14 09:49:52 davem Exp $ +/* $Id: ioctl32.c,v 1.2 2002/03/22 20:13:58 jsimmons Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -872,6 +872,7 @@ return err ? -EFAULT : 0; } +#ifdef CONFIG_FB struct fbcmap32 { int index; /* first element (0 origin) */ int count; @@ -1111,6 +1112,7 @@ if (cmap.transp) kfree(cmap.transp); return err; } +#endif /* CONFIG_FB */ static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { @@ -2040,6 +2042,7 @@ return err; } +#ifdef CONFIG_VT extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int vt_check(struct file *file) @@ -2074,6 +2077,8 @@ static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct consolefontdesc cfdarg; struct console_font_op op; int i, perm; @@ -2096,7 +2101,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); + return con_font_op(vc->display_fg->vc_cons[fg_console].d, &op); case GIO_FONTX: if (!cfdarg.chardata) return 0; @@ -2106,7 +2111,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); + i = con_font_op(vc->display_fg->vc_cons[fg_console], &op); if (i) return i; cfdarg.charheight = op.height; @@ -2129,6 +2134,8 @@ static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct console_font_op op; int perm = vt_check(file), i; struct vt_struct *vt; @@ -2141,8 +2148,7 @@ return -EPERM; op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data); op.flags |= KD_FONT_FLAG_OLD; - vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; - i = con_font_op(vt->vc_num, &op); + i = con_font_op(vc, &op); if (i) return i; ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) @@ -2157,6 +2163,8 @@ static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct unimapdesc32 tmp; int perm = vt_check(file); @@ -2166,12 +2174,13 @@ switch (cmd) { case PIO_UNIMAP: if (!perm) return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries)); + return con_set_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, (struct unipair *)A(tmp.entries)); case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); + return con_get_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); } return 0; } +#endif /* CONFIG_VT */ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/sparc64/kernel/irq.c linux-2.5/arch/sparc64/kernel/irq.c --- linux-2.5.23/arch/sparc64/kernel/irq.c Wed Jun 19 03:11:53 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.23/arch/sparc64/kernel/pci_common.c linux-2.5/arch/sparc64/kernel/pci_common.c --- linux-2.5.23/arch/sparc64/kernel/pci_common.c Wed Jun 19 03:11:50 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.23/arch/sparc64/kernel/rtrap.S linux-2.5/arch/sparc64/kernel/rtrap.S --- linux-2.5.23/arch/sparc64/kernel/rtrap.S Wed Jun 19 03:11:54 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.23/arch/sparc64/kernel/smp.c linux-2.5/arch/sparc64/kernel/smp.c --- linux-2.5.23/arch/sparc64/kernel/smp.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/arch/sparc64/kernel/smp.c Mon Jun 17 22:52:25 2002 @@ -697,14 +697,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); @@ -832,23 +832,25 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - u32 ctx = CTX_HWBITS(mm->context); - int cpu = smp_processor_id(); + { + u32 ctx = CTX_HWBITS(mm->context); + int cpu = smp_processor_id(); - start &= PAGE_MASK; - end = PAGE_ALIGN(end); + start &= PAGE_MASK; + end = PAGE_ALIGN(end); - if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) { - mm->cpu_vm_mask = (1UL << cpu); - goto local_flush_and_out; - } + if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) { + mm->cpu_vm_mask = (1UL << cpu); + goto local_flush_and_out; + } - smp_cross_call_masked(&xcall_flush_tlb_range, - ctx, start, end, - mm->cpu_vm_mask); + smp_cross_call_masked(&xcall_flush_tlb_range, + ctx, start, end, + mm->cpu_vm_mask); - local_flush_and_out: - __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start)); + local_flush_and_out: + __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start)); + } } void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/sparc64/kernel/sunos_ioctl32.c linux-2.5/arch/sparc64/kernel/sunos_ioctl32.c --- linux-2.5.23/arch/sparc64/kernel/sunos_ioctl32.c Wed Jun 19 03:11:58 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.23/arch/sparc64/kernel/sys_sparc32.c linux-2.5/arch/sparc64/kernel/sys_sparc32.c --- linux-2.5.23/arch/sparc64/kernel/sys_sparc32.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/arch/sparc64/kernel/sys_sparc32.c Mon Jun 17 22:52:25 2002 @@ -1533,6 +1533,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); @@ -1540,6 +1542,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; } @@ -3921,27 +3924,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.23/arch/sparc64/solaris/timod.c linux-2.5/arch/sparc64/solaris/timod.c --- linux-2.5.23/arch/sparc64/solaris/timod.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/arch/sparc64/solaris/timod.c Wed Jun 12 03:01:49 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)); @@ -851,7 +865,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; @@ -918,7 +934,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.23/arch/x86_64/ia32/ia32_ioctl.c linux-2.5/arch/x86_64/ia32/ia32_ioctl.c --- linux-2.5.23/arch/x86_64/ia32/ia32_ioctl.c Wed Jun 19 03:11:44 2002 +++ linux-2.5/arch/x86_64/ia32/ia32_ioctl.c Mon Jun 17 22:52:25 2002 @@ -1631,6 +1631,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) @@ -1665,6 +1666,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; @@ -1687,7 +1690,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; @@ -1697,7 +1700,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; @@ -1720,9 +1723,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; @@ -1732,8 +1736,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))) @@ -1748,6 +1751,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); @@ -1757,12 +1762,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.23/arch/x86_64/kernel/apic.c linux-2.5/arch/x86_64/kernel/apic.c --- linux-2.5.23/arch/x86_64/kernel/apic.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/arch/x86_64/kernel/apic.c Sun May 26 01:40:46 2002 @@ -1044,7 +1044,6 @@ * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -unsigned int apic_timer_irqs [NR_CPUS]; void smp_apic_timer_interrupt(struct pt_regs *regs) { @@ -1053,7 +1052,7 @@ /* * the NMI deadlock-detector uses this. */ - apic_timer_irqs[cpu]++; + cpu_pda[cpu].apic_timer_irqs++; /* * NOTE! We'd better ACK the irq immediately, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/x86_64/kernel/irq.c linux-2.5/arch/x86_64/kernel/irq.c --- linux-2.5.23/arch/x86_64/kernel/irq.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/arch/x86_64/kernel/irq.c Mon Jun 17 22:52:25 2002 @@ -168,7 +168,7 @@ #if CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) - seq_printf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]); + seq_printf(p, "%10u ", cpu_pda[cpu_logical_map(j)].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/x86_64/kernel/mtrr.c linux-2.5/arch/x86_64/kernel/mtrr.c --- linux-2.5.23/arch/x86_64/kernel/mtrr.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/arch/x86_64/kernel/mtrr.c Wed Jun 19 06:16:04 2002 @@ -1,26 +1,26 @@ /* 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) v2.00 September 2001 Dave Jones - Initial rewrite for x86-64. + Initial rewrite for x86-64. Removal of non-Intel style MTRR code. v2.01 June 2002 Dave Jones Removal of redundant abstraction layer. @@ -74,13 +74,13 @@ #define NUM_FIXED_RANGES 88 -#define MTRR_CHANGE_MASK_FIXED 0x01 -#define MTRR_CHANGE_MASK_VARIABLE 0x02 -#define MTRR_CHANGE_MASK_DEFTYPE 0x04 +#define MTRR_CHANGE_MASK_FIXED 0x01 +#define MTRR_CHANGE_MASK_VARIABLE 0x02 +#define MTRR_CHANGE_MASK_DEFTYPE 0x04 typedef u8 mtrr_type; -#define LINE_SIZE 80 +#define LINE_SIZE 80 #ifdef CONFIG_SMP #define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type) @@ -120,42 +120,42 @@ __save_flags(ctxt->flags); __cli(); - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if (cpu_has_pge) { - ctxt->cr4val = read_cr4(); + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability)) { + ctxt->cr4val = read_cr4(); write_cr4(ctxt->cr4val & ~(1UL << 7)); - } + } - /* Disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect */ + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ cr0 = read_cr0() | 0x40000000; - wbinvd(); + wbinvd(); write_cr0(cr0); - wbinvd(); + wbinvd(); - /* Disable MTRRs, and set the default type to uncached */ + /* Disable MTRRs, and set the default type to uncached */ rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); wrmsr(MSR_MTRRdefType, 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(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); - /* Enable caches */ + /* Enable caches */ write_cr0(read_cr0() & 0xbfffffff); - /* Restore value of CR4 */ - if (cpu_has_pge) + /* 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); } @@ -189,21 +189,21 @@ rdmsr (MSR_MTRRphysMask(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 (MSR_MTRRphysBase(reg), base_lo, base_hi); - /* Work out the shifted address mask. */ + /* Work out the shifted address mask. */ newsize = (u64) mask_hi << 32 | (mask_lo & ~0x800); newsize = ~newsize+1; *size = (u32) newsize >> PAGE_SHIFT; - *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; - *type = base_lo & 0xff; + *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; + *type = base_lo & 0xff; } @@ -220,21 +220,21 @@ static void set_mtrr_up (unsigned int reg, u64 base, u32 size, mtrr_type type, int do_safe) { - struct set_mtrr_context ctxt; + struct set_mtrr_context ctxt; if (do_safe) set_mtrr_prepare (&ctxt); if (size == 0) { - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ wrmsr (MSR_MTRRphysMask(reg), 0, 0); } else { wrmsr (MSR_MTRRphysBase(reg), base << PAGE_SHIFT | type, - (base & size_and_mask) >> (32 - PAGE_SHIFT)); + (base & size_and_mask) >> (32 - PAGE_SHIFT)); wrmsr (MSR_MTRRphysMask(reg), (-size-1) << PAGE_SHIFT | 0x800, - ((-size-1) & size_and_mask) >> (32 - PAGE_SHIFT)); - } + ((-size-1) & size_and_mask) >> (32 - PAGE_SHIFT)); + } if (do_safe) set_mtrr_done (&ctxt); } @@ -251,7 +251,7 @@ /* 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 (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi); rdmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi); @@ -264,35 +264,35 @@ struct mtrr_var_range *vr) { u32 lo, hi; - int changed = FALSE; + int changed = FALSE; rdmsr (MSR_MTRRphysBase(index), lo, hi); - if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) - || (vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) { + if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) || + (vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) { wrmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi); - changed = TRUE; - } + changed = TRUE; + } rdmsr (MSR_MTRRphysMask(index), lo, hi); - if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) - || (vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) { + if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) || + (vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) { wrmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi); - changed = TRUE; - } - return changed; + changed = TRUE; + } + return changed; } static void __init get_fixed_ranges (mtrr_type * frs) { u32 *p = (u32 *) frs; - int i; + int i; rdmsr (MSR_MTRRfix64K_00000, p[0], p[1]); - for (i = 0; i < 2; i++) + for (i = 0; i < 2; i++) rdmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) rdmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]); } @@ -300,8 +300,8 @@ static int __init set_fixed_ranges_testing (mtrr_type * frs) { u32 *p = (u32 *) frs; - int changed = FALSE; - int i; + int changed = FALSE; + int i; u32 lo, hi; printk (KERN_INFO "mtrr: rdmsr 64K_00000\n"); @@ -309,8 +309,8 @@ if (p[0] != lo || p[1] != hi) { printk (KERN_INFO "mtrr: Writing %x:%x to 64K MSR. lohi were %x:%x\n", p[0], p[1], lo, hi); wrmsr (MSR_MTRRfix64K_00000, p[0], p[1]); - changed = TRUE; - } + changed = TRUE; + } printk (KERN_INFO "mtrr: rdmsr 16K_80000\n"); for (i = 0; i < 2; i++) { @@ -318,9 +318,9 @@ if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) { printk (KERN_INFO "mtrr: Writing %x:%x to 16K MSR%d. lohi were %x:%x\n", p[2 + i * 2], p[3 + i * 2], i, lo, hi ); wrmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]); - changed = TRUE; + changed = TRUE; + } } - } printk (KERN_INFO "mtrr: rdmsr 4K_C0000\n"); for (i = 0; i < 8; i++) { @@ -329,18 +329,18 @@ if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) { printk (KERN_INFO "mtrr: Writing %x:%x to 4K MSR%d. lohi were %x:%x\n", p[6 + i * 2], p[7 + i * 2], i, lo, hi); wrmsr (MSR_MTRRfix4K_C0000 + 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]; - mtrr_type def_type; + unsigned int num_var_ranges; + struct mtrr_var_range *var_ranges; + mtrr_type fixed_ranges[NUM_FIXED_RANGES]; + mtrr_type def_type; unsigned char enabled; }; @@ -348,23 +348,23 @@ /* 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 int nvrs, i; + struct mtrr_var_range *vrs; u32 lo, dummy; nvrs = state->num_var_ranges = get_num_var_ranges(); - vrs = state->var_ranges - = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); - if (vrs == NULL) - nvrs = state->num_var_ranges = 0; - - for (i = 0; i < nvrs; i++) - get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges (state->fixed_ranges); + 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 (MSR_MTRRdefType, lo, dummy); - state->def_type = (lo & 0xff); - state->enabled = (lo & 0xc00) >> 10; + state->def_type = (lo & 0xff); + state->enabled = (lo & 0xc00) >> 10; } @@ -384,26 +384,26 @@ * [RETURNS] 0 if no changes made, else a mask indication what was changed. */ static u64 __init set_mtrr_state (struct mtrr_state *state, - struct set_mtrr_context *ctxt) + struct set_mtrr_context *ctxt) { - unsigned int i; + unsigned int i; u64 change_mask = 0; - for (i = 0; i < state->num_var_ranges; i++) + for (i = 0; i < state->num_var_ranges; i++) if (set_mtrr_var_range_testing (i, &state->var_ranges[i])) - change_mask |= MTRR_CHANGE_MASK_VARIABLE; + change_mask |= MTRR_CHANGE_MASK_VARIABLE; if (set_fixed_ranges_testing (state->fixed_ranges)) - change_mask |= MTRR_CHANGE_MASK_FIXED; - /* Set_mtrr_restore restores the old value of MTRRdefType, - so to set it we fiddle with the saved value */ + change_mask |= MTRR_CHANGE_MASK_FIXED; + /* Set_mtrr_restore restores the old value of MTRRdefType, + so to set it we fiddle with the saved value */ if ((ctxt->deftype_lo & 0xff) != state->def_type || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) { - ctxt->deftype_lo |= (state->def_type | state->enabled << 10); - change_mask |= MTRR_CHANGE_MASK_DEFTYPE; - } + ctxt->deftype_lo |= (state->def_type | state->enabled << 10); + change_mask |= MTRR_CHANGE_MASK_DEFTYPE; + } - return change_mask; + return change_mask; } @@ -414,8 +414,8 @@ struct set_mtrr_data { u64 smp_base; u32 smp_size; - unsigned int smp_reg; - mtrr_type smp_type; + unsigned int smp_reg; + mtrr_type smp_type; }; /* @@ -423,67 +423,67 @@ */ static void ipi_handler (void *info) { - 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 */ + /* The master has cleared me to execute */ set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, - data->smp_type, FALSE); + 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, u64 base, u32 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; + 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); } @@ -492,44 +492,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 inline char * attrib_to_str (int x) { - return (x <= 6) ? mtrr_strings[x] : "?"; + return (x <= 6) ? mtrr_strings[x] : "?"; } static void __init init_table (void) { - int i, max; + int i, max; - max = get_num_var_ranges (); + max = get_num_var_ranges (); if ((usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL))==NULL) { - printk ("mtrr: could not allocate\n"); - return; - } + printk ("mtrr: could not allocate\n"); + return; + } for (i = 0; i < max; i++) usage_table[i] = 1; #ifdef USERSPACE_INTERFACE if ((ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL)) == NULL) { - printk ("mtrr: could not allocate\n"); - return; - } - ascii_buf_bytes = 0; - compute_ascii (); + printk ("mtrr: could not allocate\n"); + return; + } + ascii_buf_bytes = 0; + compute_ascii (); #endif } @@ -540,18 +540,18 @@ */ static int get_free_region(void) { - int i, max; - mtrr_type ltype; + int i, max; + mtrr_type ltype; u64 lbase; u32 lsize; - max = get_num_var_ranges (); + max = get_num_var_ranges (); for (i = 0; i < max; ++i) { get_mtrr (i, &lbase, &lsize, <ype); if (lsize == 0) return i; - } - return -ENOSPC; + } + return -ENOSPC; } @@ -589,20 +589,20 @@ int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment) { - int i, max; - mtrr_type ltype; + int i, max; + mtrr_type ltype; u64 lbase, last; u32 lsize; if (base + size < 0x100) { printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%x000)\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) ; @@ -611,29 +611,29 @@ printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%x000) 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 (&mtrr_lock); for (i = 0; i < max; ++i) { get_mtrr (i, &lbase, &lsize, <ype); @@ -642,15 +642,15 @@ 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 (&mtrr_lock); printk (KERN_WARNING "mtrr: 0x%lx000,0x%x000 overlaps existing" " 0x%lx000,0x%x000\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; @@ -660,26 +660,26 @@ base, size, attrib_to_str (ltype), attrib_to_str (type)); - return -EINVAL; - } + return -EINVAL; + } if (increment) ++usage_table[i]; - compute_ascii (); + compute_ascii (); up (&mtrr_lock); - return i; - } - /* Search for an empty MTRR */ + return i; + } + /* Search for an empty MTRR */ i = get_free_region(); if (i < 0) { up (&mtrr_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 (&mtrr_lock); - return i; + return i; } @@ -719,10 +719,10 @@ int mtrr_add (u64 base, u32 size, unsigned int type, char increment) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); - return -EINVAL; - } + return -EINVAL; + } return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment); } @@ -742,56 +742,56 @@ * On success the register is returned, on failure a negative error * code. */ - + int mtrr_del_page (int reg, u64 base, u32 size) { - int i, max; - mtrr_type ltype; + int i, max; + mtrr_type ltype; u64 lbase; u32 lsize; - max = get_num_var_ranges (); + max = get_num_var_ranges (); down (&mtrr_lock); if (reg < 0) { - /* Search for existing MTRR */ + /* Search for existing MTRR */ for (i = 0; i < max; ++i) { get_mtrr (i, &lbase, &lsize, <ype); if (lbase == base && lsize == size) { - reg = i; - break; - } - } + reg = i; + break; + } + } if (reg < 0) { up (&mtrr_lock); printk ("mtrr: no MTRR for %lx000,%x000 found\n", base, size); - return -EINVAL; + return -EINVAL; + } } - } if (reg >= max) { up (&mtrr_lock); - printk ("mtrr: register: %d too big\n", reg); - return -EINVAL; - } + printk ("mtrr: register: %d too big\n", reg); + return -EINVAL; + } get_mtrr (reg, &lbase, &lsize, <ype); if (lsize < 1) { up (&mtrr_lock); - printk ("mtrr: MTRR %d not used\n", reg); - return -EINVAL; - } + printk ("mtrr: MTRR %d not used\n", reg); + return -EINVAL; + } if (usage_table[reg] < 1) { up (&mtrr_lock); - printk ("mtrr: reg: %d has count=0\n", reg); - return -EINVAL; - } + printk ("mtrr: reg: %d has count=0\n", reg); + return -EINVAL; + } if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); - compute_ascii (); + compute_ascii (); up (&mtrr_lock); - return reg; + return reg; } @@ -809,14 +809,14 @@ * On success the register is returned, on failure a negative error * code. */ - + int mtrr_del (int reg, u64 base, u32 size) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); - return -EINVAL; - } + return -EINVAL; + } return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); } @@ -826,64 +826,64 @@ static int mtrr_file_add (u64 base, u32 size, unsigned int type, struct file *file, int page) { - int reg, max; - unsigned int *fcount = file->private_data; + int reg, max; + unsigned int *fcount = file->private_data; - max = get_num_var_ranges (); + max = get_num_var_ranges (); if (fcount == NULL) { if ((fcount = kmalloc (max * sizeof *fcount, GFP_KERNEL)) == NULL) { - printk ("mtrr: could not allocate\n"); - return -ENOMEM; + printk ("mtrr: could not allocate\n"); + return -ENOMEM; + } + memset (fcount, 0, max * sizeof *fcount); + file->private_data = fcount; } - memset (fcount, 0, max * sizeof *fcount); - file->private_data = fcount; - } - if (!page) { + if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); - return -EINVAL; + 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 (u64 base, u32 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%x base: 0x%lx\n", size, base); - return -EINVAL; + 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; } @@ -899,8 +899,8 @@ if (copy_to_user (buf, ascii_buffer + *ppos, len)) return -EFAULT; - *ppos += len; - return len; + *ppos += len; + return len; } @@ -914,242 +914,241 @@ int i, err, reg; u64 base; u32 size; - char *ptr; - char line[LINE_SIZE]; + char *ptr; + char line[LINE_SIZE]; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - /* Can't seek (pwrite) on this device */ + /* Can't seek (pwrite) on this device */ if (ppos != &file->f_pos) return -ESPIPE; - memset (line, 0, LINE_SIZE); + memset (line, 0, LINE_SIZE); if (len > LINE_SIZE) len = LINE_SIZE; if (copy_from_user (line, buf, len - 1)) return -EFAULT; - ptr = line + strlen (line) - 1; + ptr = line + strlen (line) - 1; if (*ptr == '\n') *ptr = '\0'; if (!strncmp (line, "disable=", 8)) { - reg = simple_strtoul (line + 8, &ptr, 0); - err = mtrr_del_page (reg, 0, 0); + reg = simple_strtoul (line + 8, &ptr, 0); + err = mtrr_del_page (reg, 0, 0); if (err < 0) return err; - return len; - } + return len; + } if (strncmp (line, "base=", 5)) { - printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); - return -EINVAL; - } + printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); + return -EINVAL; + } - base = simple_strtoull (line + 5, &ptr, 0); + base = simple_strtoull (line + 5, &ptr, 0); for (; isspace (*ptr); ++ptr) ; if (strncmp (ptr, "size=", 5)) { - printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); - return -EINVAL; - } + printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); + return -EINVAL; + } - size = simple_strtoull (ptr + 5, &ptr, 0); + size = simple_strtoull (ptr + 5, &ptr, 0); if ((base & 0xfff) || (size & 0xfff)) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); - return -EINVAL; - } + 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 ((u64) base, 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 (!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, + return -EFAULT; + err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_SET_ENTRY: + case MTRRIOC_SET_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); + return -EFAULT; + err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_DEL_ENTRY: + case MTRRIOC_DEL_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file, 0); + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_KILL_ENTRY: + case MTRRIOC_KILL_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_del (-1, sentry.base, sentry.size); + return -EFAULT; + err = mtrr_del (-1, sentry.base, sentry.size); if (err < 0) return err; - break; + break; - case MTRRIOC_GET_ENTRY: + case MTRRIOC_GET_ENTRY: if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) - return -EFAULT; + return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type); - /* 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 (!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, - file, 1); + return -EFAULT; + err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 1); if (err < 0) return err; - break; + break; - case MTRRIOC_SET_PAGE_ENTRY: + case MTRRIOC_SET_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); + return -EFAULT; + err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_DEL_PAGE_ENTRY: + case MTRRIOC_DEL_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file, 1); + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 1); if (err < 0) return err; - break; + break; - case MTRRIOC_KILL_PAGE_ENTRY: + case MTRRIOC_KILL_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_del_page (-1, sentry.base, sentry.size); + return -EFAULT; + err = mtrr_del_page (-1, sentry.base, sentry.size); if (err < 0) return err; - break; + break; - case MTRRIOC_GET_PAGE_ENTRY: + case MTRRIOC_GET_PAGE_ENTRY: if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) - return -EFAULT; + return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type); - gentry.type = type; + 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; - max = get_num_var_ranges (); + lock_kernel (); + 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]; + } } - } - kfree (fcount); - file->private_data = NULL; - return 0; + unlock_kernel (); + 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, }; @@ -1161,39 +1160,38 @@ static void compute_ascii (void) { - char factor; - int i, max; - mtrr_type type; + char factor; + int i, max; + mtrr_type type; u64 base; u32 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); 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=%4i%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=%4i%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 } @@ -1202,22 +1200,22 @@ EXPORT_SYMBOL (mtrr_add); EXPORT_SYMBOL (mtrr_del); - + static void __init mtrr_setup (void) { printk ("mtrr: v%s)\n", MTRR_VERSION); - if (cpu_has_mtrr) { - /* Query the width (in bits) of the physical + 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 & 0xfffffffffff00000; - } + } printk ("mtrr: detected mtrr type: x86-64\n"); - } + } } #ifdef CONFIG_SMP @@ -1236,30 +1234,30 @@ { u64 mask; int count; - struct set_mtrr_context ctxt; + 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); @@ -1268,17 +1266,17 @@ #endif #ifdef CONFIG_PROC_FS - proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); - if (proc_root_mtrr) { - proc_root_mtrr->owner = THIS_MODULE; - proc_root_mtrr->proc_fops = &mtrr_fops; - } + proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); + if (proc_root_mtrr) { + proc_root_mtrr->owner = THIS_MODULE; + proc_root_mtrr->proc_fops = &mtrr_fops; + } #endif #ifdef CONFIG_DEVFS_FS - devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, - S_IFREG | S_IRUGO | S_IWUSR, - &mtrr_fops, NULL); + devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, + S_IFREG | S_IRUGO | S_IWUSR, + &mtrr_fops, NULL); #endif - init_table (); - return 0; + init_table (); + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/x86_64/kernel/nmi.c linux-2.5/arch/x86_64/kernel/nmi.c --- linux-2.5.23/arch/x86_64/kernel/nmi.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/arch/x86_64/kernel/nmi.c Mon Jun 17 22:52:25 2002 @@ -244,7 +244,7 @@ */ int sum, cpu = smp_processor_id(); - sum = apic_timer_irqs[cpu]; + sum = cpu_pda[cpu].apic_timer_irqs; if (last_irq_sums[cpu] == sum) { /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/arch/x86_64/kernel/setup.c linux-2.5/arch/x86_64/kernel/setup.c --- linux-2.5.23/arch/x86_64/kernel/setup.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/arch/x86_64/kernel/setup.c Mon Jun 17 22:52:25 2002 @@ -1028,7 +1028,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.23/drivers/atm/Config.help linux-2.5/drivers/atm/Config.help --- linux-2.5.23/drivers/atm/Config.help Wed Jun 19 03:11:58 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.23/drivers/atm/idt77252.h linux-2.5/drivers/atm/idt77252.h --- linux-2.5.23/drivers/atm/idt77252.h Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/atm/idt77252.h Wed Jun 19 20:15:26 2002 @@ -36,6 +36,7 @@ #include #include +#include /*****************************************************************************/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/atm/iphase.c linux-2.5/drivers/atm/iphase.c --- linux-2.5.23/drivers/atm/iphase.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/atm/iphase.c Wed Jun 19 20:21:54 2002 @@ -2001,6 +2001,10 @@ } iadev->desc_tbl = kmalloc(iadev->num_tx_desc * sizeof(struct desc_tbl_t), GFP_KERNEL); + if (!iadev->desc_tbl) { + printk(KERN_ERR DEV_LABEL " couldn't get mem\n"); + return -EAGAIN; + } /* Communication Queues base address */ i = TX_COMP_Q * iadev->memSize; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/base/bus.c linux-2.5/drivers/base/bus.c --- linux-2.5.23/drivers/base/bus.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/base/bus.c Wed Jun 19 11:01:09 2002 @@ -61,6 +61,7 @@ dev = next; if ((error = callback(dev,data))) { put_device(dev); + read_lock(&bus->lock); break; } read_lock(&bus->lock); @@ -96,6 +97,7 @@ drv = next; if ((error = callback(drv,data))) { put_driver(drv); + read_lock(&bus->lock); break; } read_lock(&bus->lock); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/base/driver.c linux-2.5/drivers/base/driver.c --- linux-2.5.23/drivers/base/driver.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/base/driver.c Wed Jun 19 11:00:41 2002 @@ -31,6 +31,7 @@ dev = next; if ((error = callback(dev,data))) { put_device(dev); + read_lock(&drv->lock); break; } read_lock(&drv->lock); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/block/DAC960.c linux-2.5/drivers/block/DAC960.c --- linux-2.5.23/drivers/block/DAC960.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/block/DAC960.c Tue Jun 18 20:00:13 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. */ @@ -2406,10 +2407,9 @@ break; case DAC960_PD_Controller: if (!request_region(Controller->IO_Address, 0x80, - Controller->FullModelName)) { - DAC960_Error("IO port 0x%d busy for Controller at\n", - Controller, Controller->IO_Address); - goto Failure; + Controller->FullModelName)) { + DAC960_Error("Unable request region at 0x%x\n", Controller->IO_Address); + goto Failure; } DAC960_PD_DisableInterrupts(BaseAddress); DAC960_PD_AcknowledgeStatus(BaseAddress); @@ -2436,10 +2436,9 @@ break; case DAC960_P_Controller: if (!request_region(Controller->IO_Address, 0x80, - Controller->FullModelName)){ - DAC960_Error("IO port 0x%d busy for Controller at\n", - Controller, Controller->IO_Address); - goto Failure; + Controller->FullModelName)) { + DAC960_Error("Unable request region at 0x%x\n", Controller->IO_Address); + goto Failure; } DAC960_PD_DisableInterrupts(BaseAddress); DAC960_PD_AcknowledgeStatus(BaseAddress); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/block/DAC960.h linux-2.5/drivers/block/DAC960.h --- linux-2.5.23/drivers/block/DAC960.h Wed Jun 19 03:11:57 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.23/drivers/block/floppy.c linux-2.5/drivers/block/floppy.c --- linux-2.5.23/drivers/block/floppy.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/drivers/block/floppy.c Tue Jun 18 20:00:13 2002 @@ -3705,6 +3705,10 @@ UDRS->fd_ref = 0; } floppy_release_irq_and_dma(); + + /* undo ++bd_openers in floppy_open() */ + --inode->i_bdev->bd_openers; + return 0; } @@ -3797,6 +3801,35 @@ invalidate_buffers(mk_kdev(FLOPPY_MAJOR,old_dev)); } + /* Problems: + * 1. floppy_open() triggers a call to submit_bio(), but + * bdev->bd_queue may be NULL since it is not set up until + * after floppy_open() has returned. Prior to 2.5.18, NULL + * queues were initialised when needed. + * 2. fs/block_dev.c:do_open() changes bdev's block size + * after floppy_open() has returned. For some reason, this + * causes data corruption durings writes. + * Workarounds: + * 1. bdev->bd_queue is initialised here. + * 2. a) Set bdev block size equal to the hardsect/queue size; + * this seems to cure the data corruption problem. + * b) ++bdev->bd_openers to bypass do_open()'s block size + * change. floppy_release() does a --bdev->bd_openers. + */ + { + struct block_device *bdev = inode->i_bdev; + kdev_t dev = inode->i_rdev; + struct blk_dev_struct *p = blk_dev + major(dev); + + if (p->queue) + bdev->bd_queue = p->queue(dev); + else + bdev->bd_queue = &p->request_queue; + bdev->bd_block_size = bdev_hardsect_size(bdev); + bdev->bd_inode->i_blkbits = blksize_bits(block_size(bdev)); + ++bdev->bd_openers; + } + /* Allow ioctls if we have write-permissions even if read-only open. * Needed so that programs such as fdrawcmd still can work on write * protected disks */ @@ -4234,8 +4267,6 @@ { int i,unit,drive; - register_sys_device(&device_floppy); - raw_cmd = NULL; devfs_handle = devfs_mk_dir (NULL, "floppy", NULL); @@ -4260,9 +4291,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 } @@ -4359,6 +4393,9 @@ register_disk(NULL, mk_kdev(MAJOR_NR,TOMINOR(drive)+i*4), 1, &floppy_fops, 0); } + + register_sys_device(&device_floppy); + return have_no_fdc; } @@ -4541,6 +4578,7 @@ { int dummy; + unregister_sys_device(&device_floppy); devfs_unregister (devfs_handle); devfs_unregister_blkdev(MAJOR_NR, "fd"); @@ -4561,3 +4599,5 @@ __setup ("floppy=", floppy_setup); module_init(floppy_init) #endif + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/block/genhd.c linux-2.5/drivers/block/genhd.c --- linux-2.5.23/drivers/block/genhd.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/block/genhd.c Mon Jun 17 22:52:26 2002 @@ -31,6 +31,7 @@ * Global kernel list of partitioning information. */ static struct gendisk *gendisk_head; +static struct gendisk *gendisk_array[MAX_BLKDEV]; /** * add_gendisk - add partitioning information to kernel list @@ -60,6 +61,7 @@ goto out; } } + gendisk_array[gp->major] = gp; gp->next = gendisk_head; gendisk_head = gp; out: @@ -82,6 +84,7 @@ struct gendisk **gpp; write_lock(&gendisk_lock); + gendisk_array[gp->major] = NULL; for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next)) if (*gpp == gp) break; @@ -107,11 +110,15 @@ int maj = major(dev); read_lock(&gendisk_lock); + if ((gp = gendisk_array[maj])) + goto out; + + /* This is needed for early 2.4 source compatiblity. --hch */ for (gp = gendisk_head; gp; gp = gp->next) if (gp->major == maj) break; +out: read_unlock(&gendisk_lock); - return gp; } @@ -207,7 +214,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) { @@ -223,9 +229,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.23/drivers/block/ida_ioctl.h linux-2.5/drivers/block/ida_ioctl.h --- linux-2.5.23/drivers/block/ida_ioctl.h Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/block/ida_ioctl.h Mon May 6 16:41:36 2002 @@ -31,6 +31,9 @@ #define IDAREVALIDATEVOLS 0x30303131 #define IDADRIVERVERSION 0x31313232 #define IDAGETPCIINFO 0x32323333 +#define IDADEREGDISK 0x33333434 +#define IDAREGNEWDISK 0x34343535 +#define IDAGETLOGINFO 0x35353636 typedef struct _ida_pci_info_struct { @@ -38,6 +41,13 @@ unsigned char dev_fn; __u32 board_id; } ida_pci_info_struct; + +typedef struct _idaLogvolInfo_struct{ +int LogVolID; +int num_opens; /* number of opens on the logical volume */ +int num_parts; /* number of partitions configured on logvol */ +} idaLogvolInfo_struct; + /* * Normally, the ioctl determines the logical unit for this command by * the major,minor number of the fd passed to ioctl. If you need to send diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/block/paride/bpck6.c linux-2.5/drivers/block/paride/bpck6.c --- linux-2.5.23/drivers/block/paride/bpck6.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/block/paride/bpck6.c Fri May 10 16:02:58 2002 @@ -17,13 +17,15 @@ Version 2.0.0 is the first to have source released Version 2.0.1 is the "Cox-ified" source code Version 2.0.2 - fixed version string usage, and made ppc functions static + Version 2.0.2ac - additional cleanup (privptr now not private to fix 64bit + platforms), use memset, rename clashing PPC define. */ /* PARAMETERS */ int verbose=0; /* set this to 1 to see debugging messages and whatnot */ -#define BACKPACK_VERSION "2.0.2" +#define BACKPACK_VERSION "2.0.2ac" #include #include @@ -40,7 +42,7 @@ -#define PPCSTRUCT(pi) ((PPC *)(pi->private)) +#define PPCSTRUCT(pi) ((PPC_STORAGE *)(pi->privptr)) /****************************************************************/ /* @@ -223,12 +225,10 @@ static void bpck6_init_proto(PIA *pi) { - int i; - /* allocate a state structure for this item */ - pi->private=(int)kmalloc(sizeof(PPC),GFP_KERNEL); + pi->privptr=kmalloc(sizeof(PPC_STORAGE),GFP_KERNEL); - if(pi->private==(int)NULL) + if(pi->privptr==NULL) { printk(KERN_ERR "%s: ERROR COULDN'T ALLOCATE MEMORY\n",pi->device); return; @@ -238,10 +238,7 @@ MOD_INC_USE_COUNT; } - for(i=0;iprivate))[i]=0; - } + memset(pi->privptr, 0, sizeof(PPC_STORAGE)); } static void bpck6_release_proto(PIA *pi) @@ -249,7 +246,7 @@ MOD_DEC_USE_COUNT; /* free after use count decremented so that we aren't using it when it is decremented */ - kfree((void *)(pi->private)); + kfree(pi->privptr); } struct pi_protocol bpck6 = { "bpck6", /* name for proto*/ @@ -290,7 +287,7 @@ #ifdef MODULE /*module information*/ -static int init_module(void) +int init_module(void) { printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n"); printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n"); @@ -303,7 +300,7 @@ return pi_register(&bpck6) - 1; } -void cleanup_module(void) +void cleanup_module(void) { pi_unregister(&bpck6); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/block/paride/paride.h linux-2.5/drivers/block/paride/paride.h --- linux-2.5.23/drivers/block/paride/paride.h Wed Jun 19 03:11:51 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.23/drivers/block/paride/pd.c linux-2.5/drivers/block/paride/pd.c --- linux-2.5.23/drivers/block/paride/pd.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/block/paride/pd.c Mon Jun 17 22:52:26 2002 @@ -380,8 +380,8 @@ } int pd_init (void) -{ - request_queue_t * q; +{ + request_queue_t * q; if (disable) return -1; if (devfs_register_blkdev(MAJOR_NR,name,&pd_fops)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/block/paride/ppc6lnx.c linux-2.5/drivers/block/paride/ppc6lnx.c --- linux-2.5.23/drivers/block/paride/ppc6lnx.c Wed Jun 19 03:11:45 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.23/drivers/block/rd.c linux-2.5/drivers/block/rd.c --- linux-2.5.23/drivers/block/rd.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/block/rd.c Tue Jun 18 20:00:13 2002 @@ -89,7 +89,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 @@ -106,26 +106,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; } @@ -162,30 +184,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) { @@ -210,8 +222,7 @@ } else { SetPageDirty(page); } - if (unlock) - unlock_page(page); + unlock_page(page); __free_page(page); } while (size); @@ -302,9 +313,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.23/drivers/block/z2ram.c linux-2.5/drivers/block/z2ram.c --- linux-2.5.23/drivers/block/z2ram.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/block/z2ram.c Mon Jun 17 22:52:27 2002 @@ -86,7 +86,7 @@ if ( ( start + len ) > z2ram_size ) { - printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n", + printk( KERN_ERR DEVICE_NAME ": bad access: block=%ld, count=%ld\n", CURRENT->sector, CURRENT->current_nr_sectors); end_request(CURRENT, FALSE); @@ -95,7 +95,7 @@ if ( ( rq_data_dir(CURRENT) != READ ) && ( rq_data_dir(CURRENT) != WRITE ) ) { - printk( KERN_ERR DEVICE_NAME ": bad command: %ld\n", rq_data_dir(CURRENT) ); + printk( KERN_ERR DEVICE_NAME ": bad command: %d\n", CURRENT->cmd ); end_request(CURRENT, FALSE); continue; } @@ -109,7 +109,7 @@ addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ]; - if ( rq_data_dir(CURRENT) == READ ) + if ( CURRENT->cmd == READ ) memcpy( CURRENT->buffer, (char *)addr, size ); else memcpy( (char *)addr, CURRENT->buffer, size ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/bluetooth/bluecard_cs.c linux-2.5/drivers/bluetooth/bluecard_cs.c --- linux-2.5.23/drivers/bluetooth/bluecard_cs.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/bluetooth/bluecard_cs.c Sat May 25 19:52:00 2002 @@ -98,7 +98,7 @@ dev_link_t *bluecard_attach(void); void bluecard_detach(dev_link_t *); -dev_link_t *dev_list = NULL; +static dev_link_t *dev_list = NULL; /* Default baud rate: 57600, 115200, 230400 or 460800 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/bluetooth/hci_uart.c linux-2.5/drivers/bluetooth/hci_uart.c --- linux-2.5.23/drivers/bluetooth/hci_uart.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/hci_uart.c Wed May 1 21:12:18 2002 @@ -0,0 +1,580 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * BlueZ HCI UART driver. + * + * $Id: hci_uart.c,v 1.5 2001/07/05 18:42:44 maxk Exp $ + */ +#define VERSION "1.0" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef HCI_UART_DEBUG +#undef DBG +#define DBG( A... ) +#undef DMP +#define DMP( A... ) +#endif + +/* ------- Interface to HCI layer ------ */ +/* Initialize device */ +int n_hci_open(struct hci_dev *hdev) +{ + DBG("%s %p", hdev->name, hdev); + + /* Nothing to do for UART driver */ + + hdev->flags |= HCI_RUNNING; + + return 0; +} + +/* Reset device */ +int n_hci_flush(struct hci_dev *hdev) +{ + struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; + struct tty_struct *tty = n_hci->tty; + + DBG("hdev %p tty %p", hdev, tty); + + /* Drop TX queue */ + skb_queue_purge(&n_hci->txq); + + /* Flush any pending characters in the driver and discipline. */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + return 0; +} + +/* Close device */ +int n_hci_close(struct hci_dev *hdev) +{ + DBG("hdev %p", hdev); + + hdev->flags &= ~HCI_RUNNING; + + n_hci_flush(hdev); + + return 0; +} + +int n_hci_tx_wakeup(struct n_hci *n_hci) +{ + register struct tty_struct *tty = n_hci->tty; + + if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) { + set_bit(TRANS_WAKEUP, &n_hci->tx_state); + return 0; + } + + DBG(""); + do { + register struct sk_buff *skb; + register int len; + + clear_bit(TRANS_WAKEUP, &n_hci->tx_state); + + if (!(skb = skb_dequeue(&n_hci->txq))) + break; + + DMP(skb->data, skb->len); + + /* Send frame to TTY driver */ + tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + len = tty->driver.write(tty, 0, skb->data, skb->len); + + n_hci->hdev.stat.byte_tx += len; + + DBG("sent %d", len); + + if (len == skb->len) { + /* Full frame was sent */ + kfree_skb(skb); + } else { + /* Subtract sent part and requeue */ + skb_pull(skb, len); + skb_queue_head(&n_hci->txq, skb); + } + } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state)); + clear_bit(TRANS_SENDING, &n_hci->tx_state); + + return 0; +} + +/* Send frames from HCI layer */ +int n_hci_send_frame(struct sk_buff *skb) +{ + struct hci_dev* hdev = (struct hci_dev *) skb->dev; + struct tty_struct *tty; + struct n_hci *n_hci; + + if (!hdev) { + ERR("Frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + + if (!(hdev->flags & HCI_RUNNING)) + return -EBUSY; + + n_hci = (struct n_hci *) hdev->driver_data; + tty = n_hci2tty(n_hci); + + DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + hdev->stat.cmd_tx++; + break; + }; + + /* Prepend skb with frame type and queue */ + memcpy(skb_push(skb, 1), &skb->pkt_type, 1); + skb_queue_tail(&n_hci->txq, skb); + + n_hci_tx_wakeup(n_hci); + + return 0; +} + +/* ------ LDISC part ------ */ + +/* n_hci_tty_open + * + * Called when line discipline changed to N_HCI. + * + * Arguments: + * tty pointer to tty info structure + * Return Value: + * 0 if success, otherwise error code + */ +static int n_hci_tty_open(struct tty_struct *tty) +{ + struct n_hci *n_hci = tty2n_hci(tty); + struct hci_dev *hdev; + + DBG("tty %p", tty); + + if (n_hci) + return -EEXIST; + + if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { + ERR("Can't allocate controll structure"); + return -ENFILE; + } + memset(n_hci, 0, sizeof(struct n_hci)); + + /* Initialize and register HCI device */ + hdev = &n_hci->hdev; + + hdev->type = HCI_UART; + hdev->driver_data = n_hci; + + hdev->open = n_hci_open; + hdev->close = n_hci_close; + hdev->flush = n_hci_flush; + hdev->send = n_hci_send_frame; + + if (hci_register_dev(hdev) < 0) { + ERR("Can't register HCI device %s", hdev->name); + kfree(n_hci); + return -ENODEV; + } + + tty->disc_data = n_hci; + n_hci->tty = tty; + + spin_lock_init(&n_hci->rx_lock); + n_hci->rx_state = WAIT_PACKET_TYPE; + + skb_queue_head_init(&n_hci->txq); + + MOD_INC_USE_COUNT; + + /* Flush any pending characters in the driver and discipline. */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + return 0; +} + +/* n_hci_tty_close() + * + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. + */ +static void n_hci_tty_close(struct tty_struct *tty) +{ + struct n_hci *n_hci = tty2n_hci(tty); + struct hci_dev *hdev = &n_hci->hdev; + + DBG("tty %p hdev %p", tty, hdev); + + if (n_hci != NULL) { + n_hci_close(hdev); + + if (hci_unregister_dev(hdev) < 0) { + ERR("Can't unregister HCI device %s",hdev->name); + } + + hdev->driver_data = NULL; + tty->disc_data = NULL; + kfree(n_hci); + + MOD_DEC_USE_COUNT; + } +} + +/* n_hci_tty_wakeup() + * + * Callback for transmit wakeup. Called when low level + * device driver can accept more send data. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: None + */ +static void n_hci_tty_wakeup( struct tty_struct *tty ) +{ + struct n_hci *n_hci = tty2n_hci(tty); + + DBG(""); + + if (!n_hci) + return; + + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + + if (tty != n_hci->tty) + return; + + n_hci_tx_wakeup(n_hci); +} + +/* n_hci_tty_room() + * + * Callback function from tty driver. Return the amount of + * space left in the receiver's buffer to decide if remote + * transmitter is to be throttled. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: number of bytes left in receive buffer + */ +static int n_hci_tty_room (struct tty_struct *tty) +{ + return 65536; +} + +static inline int n_hci_check_data_len(struct n_hci *n_hci, int len) +{ + register int room = skb_tailroom(n_hci->rx_skb); + + DBG("len %d room %d", len, room); + if (!len) { + DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); + hci_recv_frame(n_hci->rx_skb); + } else if (len > room) { + ERR("Data length is to large"); + kfree_skb(n_hci->rx_skb); + n_hci->hdev.stat.err_rx++; + } else { + n_hci->rx_state = WAIT_DATA; + n_hci->rx_count = len; + return len; + } + + n_hci->rx_state = WAIT_PACKET_TYPE; + n_hci->rx_skb = NULL; + n_hci->rx_count = 0; + return 0; +} + +static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count) +{ + register const char *ptr; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + register int len, type, dlen; + + DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count); + + n_hci->hdev.stat.byte_rx += count; + + ptr = data; + while (count) { + if (n_hci->rx_count) { + len = MIN(n_hci->rx_count, count); + memcpy(skb_put(n_hci->rx_skb, len), ptr, len); + n_hci->rx_count -= len; count -= len; ptr += len; + + if (n_hci->rx_count) + continue; + + switch (n_hci->rx_state) { + case WAIT_DATA: + DBG("Complete data"); + + DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); + + hci_recv_frame(n_hci->rx_skb); + + n_hci->rx_state = WAIT_PACKET_TYPE; + n_hci->rx_skb = NULL; + continue; + + case WAIT_EVENT_HDR: + eh = (hci_event_hdr *) n_hci->rx_skb->data; + + DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); + + n_hci_check_data_len(n_hci, eh->plen); + continue; + + case WAIT_ACL_HDR: + ah = (hci_acl_hdr *) n_hci->rx_skb->data; + dlen = __le16_to_cpu(ah->dlen); + + DBG("ACL header: dlen %d", dlen); + + n_hci_check_data_len(n_hci, dlen); + continue; + + case WAIT_SCO_HDR: + sh = (hci_sco_hdr *) n_hci->rx_skb->data; + + DBG("SCO header: dlen %d", sh->dlen); + + n_hci_check_data_len(n_hci, sh->dlen); + continue; + }; + } + + /* WAIT_PACKET_TYPE */ + switch (*ptr) { + case HCI_EVENT_PKT: + DBG("Event packet"); + n_hci->rx_state = WAIT_EVENT_HDR; + n_hci->rx_count = HCI_EVENT_HDR_SIZE; + type = HCI_EVENT_PKT; + break; + + case HCI_ACLDATA_PKT: + DBG("ACL packet"); + n_hci->rx_state = WAIT_ACL_HDR; + n_hci->rx_count = HCI_ACL_HDR_SIZE; + type = HCI_ACLDATA_PKT; + break; + + case HCI_SCODATA_PKT: + DBG("SCO packet"); + n_hci->rx_state = WAIT_SCO_HDR; + n_hci->rx_count = HCI_SCO_HDR_SIZE; + type = HCI_SCODATA_PKT; + break; + + default: + ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); + n_hci->hdev.stat.err_rx++; + ptr++; count--; + continue; + }; + ptr++; count--; + + /* Allocate packet */ + if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + ERR("Can't allocate mem for new packet"); + + n_hci->rx_state = WAIT_PACKET_TYPE; + n_hci->rx_count = 0; + return; + } + n_hci->rx_skb->dev = (void *) &n_hci->hdev; + n_hci->rx_skb->pkt_type = type; + } +} + +/* n_hci_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) +{ + struct n_hci *n_hci = tty2n_hci(tty); + + if (!n_hci || tty != n_hci->tty) + return; + + spin_lock(&n_hci->rx_lock); + n_hci_rx(n_hci, data, flags, count); + spin_unlock(&n_hci->rx_lock); + + if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) + tty->driver.unthrottle(tty); +} + +/* n_hci_tty_ioctl() + * + * Process IOCTL system call for the tty device. + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to open file object for device + * cmd IOCTL command code + * arg argument for IOCTL call (cmd dependent) + * + * Return Value: Command dependent + */ +static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct n_hci *n_hci = tty2n_hci(tty); + int error = 0; + + DBG(""); + + /* Verify the status of the device */ + if (!n_hci) + return -EBADF; + + switch (cmd) { + default: + error = n_tty_ioctl(tty, file, cmd, arg); + break; + }; + + return error; +} + +/* + * We don't provide read/write/poll interface for user space. + */ +static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) +{ + return 0; +} +static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) +{ + return 0; +} +static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +{ + return 0; +} + +int __init n_hci_init(void) +{ + static struct tty_ldisc n_hci_ldisc; + int err; + + INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); + INF("Written 2000,2001 by Maxim Krasnyansky "); + + /* Register the tty discipline */ + + memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); + n_hci_ldisc.magic = TTY_LDISC_MAGIC; + n_hci_ldisc.name = "n_hci"; + n_hci_ldisc.open = n_hci_tty_open; + n_hci_ldisc.close = n_hci_tty_close; + n_hci_ldisc.read = n_hci_tty_read; + n_hci_ldisc.write = n_hci_tty_write; + n_hci_ldisc.ioctl = n_hci_tty_ioctl; + n_hci_ldisc.poll = n_hci_tty_poll; + n_hci_ldisc.receive_room= n_hci_tty_room; + n_hci_ldisc.receive_buf = n_hci_tty_receive; + n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; + + if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { + ERR("Can't register HCI line discipline (%d)", err); + return err; + } + + return 0; +} + +void n_hci_cleanup(void) +{ + int err; + + /* Release tty registration of line discipline */ + if ((err = tty_register_ldisc(N_HCI, NULL))) + ERR("Can't unregister HCI line discipline (%d)", err); +} + +module_init(n_hci_init); +module_exit(n_hci_cleanup); + +MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/cdrom/cdrom.c linux-2.5/drivers/cdrom/cdrom.c --- linux-2.5.23/drivers/cdrom/cdrom.c Wed Jun 19 03:11:48 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.23/drivers/cdrom/gscd.c linux-2.5/drivers/cdrom/gscd.c --- linux-2.5.23/drivers/cdrom/gscd.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/cdrom/gscd.c Mon Jun 17 22:52:27 2002 @@ -291,7 +291,7 @@ goto out; if (CURRENT->cmd != READ) { - printk("GSCD: bad cmd %p\n", CURRENT->cmd); + printk("GSCD: bad cmd %d\n", CURRENT->cmd); end_request(CURRENT, 0); goto repeat; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/cdrom/sbpcd.c linux-2.5/drivers/cdrom/sbpcd.c --- linux-2.5.23/drivers/cdrom/sbpcd.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/cdrom/sbpcd.c Mon Jun 17 22:52:27 2002 @@ -346,7 +346,7 @@ * * Thu May 30 14:14:47 CEST 2002: * - * I have presumably found the reson for the above - there was a bogous + * have presumably found the reson for the above - there was a bogous * end_request substitute, which was manipulating the request queues * incorrectly. If someone has access to the actual hardware, and it's * still operations - well please free to test it. @@ -354,6 +354,13 @@ * Marcin Dalecki */ +/* + * Add bio/kdev_t changes for 2.5.x required to make it work again. + * Still room for improvement in the request handling here if anyone + * actually cares. Bring your own chainsaw. Paul G. 02/2002 + */ + + #include #include @@ -462,6 +469,8 @@ #define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) +static spinlock_t sbpcd_lock = SPIN_LOCK_UNLOCKED; + /*==========================================================================*/ #define INLINE inline @@ -4856,21 +4865,19 @@ printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n", xnr, CURRENT, CURRENT->sector, CURRENT->nr_sectors, current->pid, jiffies); #endif - if (blk_queue_empty(QUEUE)) return; - req = CURRENT; /* take out our request so no other */ - blkdev_dequeue_request(req); /* task can fuck it up GTL */ + req = CURRENT; if (req -> sector == -1) end_request(CURRENT, 0); spin_unlock_irq(q->queue_lock); down(&ioctl_read_sem); - if (req->cmd != READ) + if (rq_data_dir(CURRENT) != READ) { - msg(DBG_INF, "bad cmd %d\n", req->cmd); + msg(DBG_INF, "bad cmd %d\n", req->cmd[0]); goto err_done; } i = minor(req->rq_dev); @@ -5761,6 +5768,12 @@ i=SetSpeed(); if (i>=0) D_S[j].CD_changed=1; } + + if (!request_region(CDo_command,4,major_name)) + { + printk(KERN_WARNING "sbpcd: Unable to request region 0x%x\n", CDo_command); + return -EIO; + } /* * Turn on the CD audio channels. @@ -5782,9 +5795,8 @@ } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sbpcd_request, &sbpcd_lock); - request_region(CDo_command,4,major_name); - devfs_handle = devfs_mk_dir (NULL, "sbp", NULL); + for (j=0;j. +CONFIG_INDYDOG + Hardware driver for the Indy's/I2's watchdog. This is a + watchdog timer that will reboot the machine after a 60 second + timer expired and no process has written to /dev/watchdog during + that time. + CONFIG_60XX_WDT This driver can be used with the watchdog timer found on some single board computers, namely the 6010 PII based computer. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/Config.in linux-2.5/drivers/char/Config.in --- linux-2.5.23/drivers/char/Config.in Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/char/Config.in Mon Jun 17 22:52:27 2002 @@ -7,6 +7,9 @@ bool 'Virtual terminal' CONFIG_VT if [ "$CONFIG_VT" = "y" ]; then bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE + if [ "$CONFIG_IA64" = "y" ]; then + bool 'Support for serial console port described by EFI HCDP table' CONFIG_SERIAL_HCDP + fi fi tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then @@ -16,9 +19,6 @@ tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL fi fi -if [ "$CONFIG_ACPI" = "y" -a "$CONFIG_IA64" = "y" ]; then - bool ' Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI -fi dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS @@ -64,6 +64,41 @@ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi if [ "$CONFIG_MIPS" = "y" ]; then + bool ' TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912 + dep_bool ' Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912 + bool ' Enable Au1000 UART Support' CONFIG_AU1000_UART + if [ "$CONFIG_AU1000_UART" = "y" ]; then + bool ' Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE + fi + bool 'TXx927 SIO support' CONFIG_TXX927_SERIAL + if [ "$CONFIG_TXX927_SERIAL" = "y" ]; then + bool 'TXx927 SIO Console support' CONFIG_TXX927_SERIAL_CONSOLE + fi + if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + bool ' Support for sb1250 onchip DUART' CONFIG_SIBYTE_SB1250_DUART + if [ "$CONFIG_SIBYTE_SB1250_DUART" = "y" ]; then + bool ' Console on SB1250 DUART' CONFIG_SIBYTE_SB1250_DUART_CONSOLE + if [ "$CONFIG_SIBYTE_SB1250_DUART_CONSOLE" = "y" ]; then + define_bool CONFIG_SERIAL_CONSOLE y + fi + int ' Output buffers size (in bytes)' CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE 1024 + bool ' Leave port 1 alone (for kgdb or audio)' CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + fi + fi + fi +fi +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then + tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 +fi +if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'DC21285 serial port support' CONFIG_SERIAL_21285 + if [ "$CONFIG_SERIAL_21285" = "y" ]; then + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD + fi + bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE + fi + if [ "$CONFIG_MIPS" = "y" ]; then bool ' TMPTX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912 dep_bool ' Console on TMPTX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912 bool ' Enable Au1000 UART Support' CONFIG_AU1000_UART @@ -72,7 +107,7 @@ fi fi fi -if [ "$CONFIG_IT8712" = "y" ]; then +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then define_bool CONFIG_IT8172_CIR y @@ -82,17 +117,12 @@ bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 bool 'Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1 fi -if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then - tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 -fi -if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'DC21285 serial port support' CONFIG_SERIAL_21285 - if [ "$CONFIG_SERIAL_21285" = "y" ]; then - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD - fi - bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE +if [ "$CONFIG_MIPS_IVR" = "y" ]; then + bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD + if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then + define_bool CONFIG_IT8172_CIR y fi + bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -111,26 +141,6 @@ source drivers/i2c/Config.in -mainmenu_option next_comment -comment 'Mice' -tristate 'Bus Mouse Support' CONFIG_BUSMOUSE -if [ "$CONFIG_BUSMOUSE" != "n" ]; then - dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE - dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE - dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE - if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then - dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE - fi -fi - -tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE -if [ "$CONFIG_MOUSE" != "n" ]; then - bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE - tristate ' C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE - tristate ' PC110 digitizer pad support' CONFIG_PC110_PAD -fi -endmenu - tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE if [ "$CONFIG_QIC02_TAPE" != "n" ]; then bool ' Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF @@ -148,18 +158,11 @@ bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT - tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG - tristate ' WDT Watchdog timer' CONFIG_WDT - tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI - if [ "$CONFIG_WDT" != "n" ]; then - bool ' WDT501 features' CONFIG_WDT_501 - if [ "$CONFIG_WDT_501" = "y" ]; then - bool ' Fan Tachometer' CONFIG_WDT_501_FAN - fi - fi - tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT + tristate ' ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT + tristate ' AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT + tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then @@ -171,8 +174,12 @@ tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT + tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT + if [ "$CONFIG_MIPS" = "y" ]; then + dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22 + fi fi endmenu @@ -185,7 +192,12 @@ tristate 'NetWinder flash support' CONFIG_NWFLASH fi -dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI +if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86_64" = "y" ]; then + dep_tristate 'AMD 768 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI +fi +if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then + dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI +fi tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_IA64" = "y" ]; then @@ -229,6 +241,13 @@ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then source drivers/char/pcmcia/Config.in +fi +if [ "$CONFIG_MIPS_AU1000" = "y" ]; then + tristate ' Alchemy Au1000 GPIO device support' CONFIG_AU1000_GPIO + tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1000_ADS7846 +fi +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then + tristate ' ITE GPIO' CONFIG_ITE_GPIO fi if [ "$CONFIG_X86" = "y" ]; then diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/Makefile linux-2.5/drivers/char/Makefile --- linux-2.5.23/drivers/char/Makefile Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/char/Makefile Mon Jun 17 21:50:21 2002 @@ -12,20 +12,18 @@ # 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 KEYMAP =defkeymap.o KEYBD =pc_keyb.o -CONSOLE =console.o SERIAL =serial.o ifeq ($(ARCH),s390) KEYMAP = KEYBD = - CONSOLE = SERIAL = endif @@ -38,7 +36,6 @@ ifeq ($(ARCH),s390x) KEYMAP = KEYBD = - CONSOLE = SERIAL = endif @@ -46,11 +43,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 = @@ -63,28 +67,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 @@ -112,12 +111,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) @@ -135,6 +139,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 @@ -154,9 +159,8 @@ obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o +obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o -obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o -obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_BUSMOUSE) += busmouse.o @@ -164,12 +168,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),) @@ -179,6 +178,12 @@ obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o +obj-$(CONFIG_AMD_RNG) += amd768_rng.o + +obj-$(CONFIG_ITE_GPIO) += ite_gpio.o +obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o +obj-$(CONFIG_COBALT_LCD) += lcd.o + obj-$(CONFIG_QIC02_TAPE) += tpqic02.o obj-$(CONFIG_FTAPE) += ftape/ obj-$(CONFIG_H8) += h8.o @@ -198,6 +203,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 @@ -206,6 +213,10 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_SH_WDT) += shwdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o +obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o +obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/adbmouse.c linux-2.5/drivers/char/adbmouse.c --- linux-2.5.23/drivers/char/adbmouse.c Wed Jun 19 03:11:54 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.23/drivers/char/agp/Makefile linux-2.5/drivers/char/agp/Makefile --- linux-2.5.23/drivers/char/agp/Makefile Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/char/agp/Makefile Wed Jun 19 16:04:27 2002 @@ -7,6 +7,16 @@ agpgart-objs := agpgart_fe.o agpgart_be.o +obj-$(CONFIG_AGP_INTEL) += agpgart_be-i8x0.o +obj-$(CONFIG_AGP_I810) += agpgart_be-i810.o +obj-$(CONFIG_AGP_VIA) += agpgart_be-via.o +obj-$(CONFIG_AGP_AMD) += agpgart_be-amd.o +obj-$(CONFIG_AGP_SIS) += agpgart_be-sis.o +obj-$(CONFIG_AGP_ALI) += agpgart_be-ali.o +obj-$(CONFIG_AGP_SWORKS) += agpgart_be-sworks.o +obj-$(CONFIG_AGP_I460) += agpgart_be-i460.o +obj-$(CONFIG_AGP_HP_ZX1) += agpgart_be-hp.o + obj-$(CONFIG_AGP) += agpgart.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agp.h linux-2.5/drivers/char/agp/agp.h --- linux-2.5.23/drivers/char/agp/agp.h Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/char/agp/agp.h Wed Jun 19 17:54:48 2002 @@ -27,6 +27,63 @@ #ifndef _AGP_BACKEND_PRIV_H #define _AGP_BACKEND_PRIV_H 1 +#include /* for flush_agp_cache() */ + +extern struct agp_bridge_data agp_bridge; + +/* Generic routines. */ +void agp_generic_agp_enable(u32 mode); +int agp_generic_create_gatt_table(void); +int agp_generic_free_gatt_table(void); +agp_memory *agp_create_memory(int scratch_pages); +int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type); +int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, int type); +agp_memory *agp_generic_alloc_by_type(size_t page_count, int type); +void agp_generic_free_by_type(agp_memory * curr); +void *agp_generic_alloc_page(void); +void agp_generic_destroy_page(void *addr); +int agp_generic_suspend(void); +void agp_generic_resume(void); +void agp_free_key(int key); + +/* chipset specific init routines. */ +int __init ali_generic_setup (struct pci_dev *pdev); +int __init amd_irongate_setup (struct pci_dev *pdev); +int __init hp_zx1_setup (struct pci_dev *pdev); +int __init intel_i460_setup (struct pci_dev *pdev); +int __init intel_generic_setup (struct pci_dev *pdev); +int __init intel_i810_setup(struct pci_dev *i810_dev); +int __init intel_i830_setup(struct pci_dev *i830_dev); +int __init intel_820_setup (struct pci_dev *pdev); +int __init intel_830mp_setup (struct pci_dev *pdev); +int __init intel_840_setup (struct pci_dev *pdev); +int __init intel_845_setup (struct pci_dev *pdev); +int __init intel_850_setup (struct pci_dev *pdev); +int __init intel_860_setup (struct pci_dev *pdev); +int __init serverworks_setup (struct pci_dev *pdev); +int __init sis_generic_setup (struct pci_dev *pdev); +int __init via_generic_setup (struct pci_dev *pdev); + + +#ifdef CONFIG_SMP +static void ipi_handler(void *null) +{ + flush_agp_cache(); +} + +static void global_cache_flush(void) +{ + if (smp_call_function(ipi_handler, NULL, 1, 1) != 0) + panic(PFX "timed out waiting for the other CPUs!\n"); + flush_agp_cache(); +} +#else +static void global_cache_flush(void) +{ + flush_agp_cache(); +} +#endif /* !CONFIG_SMP */ + enum aper_size_type { U8_APER_SIZE, U16_APER_SIZE, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-ali.c linux-2.5/drivers/char/agp/agpgart_be-ali.c --- linux-2.5.23/drivers/char/agp/agpgart_be-ali.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-ali.c Wed Jun 19 17:32:52 2002 @@ -0,0 +1,282 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +static int ali_fetch_size(void) +{ + int i; + u32 temp; + aper_size_info_32 *values; + + pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp); + temp &= ~(0xfffffff0); + values = A_SIZE_32(agp_bridge.aperture_sizes); + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static void ali_tlbflush(agp_memory * mem) +{ + u32 temp; + + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); +// clear tag + pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL, + ((temp & 0xfffffff0) | 0x00000001|0x00000002)); +} + +static void ali_cleanup(void) +{ + aper_size_info_32 *previous_size; + u32 temp; + + previous_size = A_SIZE_32(agp_bridge.previous_size); + + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); +// clear tag + pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL, + ((temp & 0xffffff00) | 0x00000001|0x00000002)); + + pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, + ((temp & 0x00000ff0) | previous_size->size_value)); +} + +static int ali_configure(void) +{ + u32 temp; + aper_size_info_32 *current_size; + + current_size = A_SIZE_32(agp_bridge.current_size); + + /* aperture size and gatt addr */ + pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp); + temp = (((temp & 0x00000ff0) | (agp_bridge.gatt_bus_addr & 0xfffff000)) + | (current_size->size_value & 0xf)); + pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, temp); + + /* tlb control */ + + /* + * Question: Jeff, ALi's patch deletes this: + * + * pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); + * pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + * ((temp & 0xffffff00) | 0x00000010)); + * + * and replaces it with the following, which seems to duplicate the + * next couple of lines below it. I suspect this was an oversight, + * but you might want to check up on this? + */ + + pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + +#if 0 + if (agp_bridge.type == ALI_M1541) { + u32 nlvm_addr = 0; + + switch (current_size->size_value) { + case 0: break; + case 1: nlvm_addr = 0x100000;break; + case 2: nlvm_addr = 0x200000;break; + case 3: nlvm_addr = 0x400000;break; + case 4: nlvm_addr = 0x800000;break; + case 6: nlvm_addr = 0x1000000;break; + case 7: nlvm_addr = 0x2000000;break; + case 8: nlvm_addr = 0x4000000;break; + case 9: nlvm_addr = 0x8000000;break; + case 10: nlvm_addr = 0x10000000;break; + default: break; + } + nlvm_addr--; + nlvm_addr&=0xfff00000; + + nlvm_addr+= agp_bridge.gart_bus_addr; + nlvm_addr|=(agp_bridge.gart_bus_addr>>12); + printk(KERN_INFO PFX "nlvm top &base = %8x\n",nlvm_addr); + } +#endif + + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); + temp &= 0xffffff7f; //enable TLB + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, temp); + + return 0; +} + +static unsigned long ali_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + +static void ali_cache_flush(void) +{ + global_cache_flush(); + + if (agp_bridge.type == ALI_M1541) { + int i, page_count; + u32 temp; + + page_count = 1 << A_SIZE_32(agp_bridge.current_size)->page_order; + for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) { + pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, + (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | + (agp_bridge.gatt_bus_addr + i)) | + ALI_CACHE_FLUSH_EN)); + } + } +} + +static void *ali_alloc_page(void) +{ + void *adr = agp_generic_alloc_page(); + unsigned temp; + + if (adr == 0) + return 0; + + if (agp_bridge.type == ALI_M1541) { + pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, + (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | + virt_to_phys(adr)) | + ALI_CACHE_FLUSH_EN )); + } + return adr; +} + +static void ali_destroy_page(void * addr) +{ + u32 temp; + + if (addr == NULL) + return; + + global_cache_flush(); + + if (agp_bridge.type == ALI_M1541) { + pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, + (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | + virt_to_phys(addr)) | + ALI_CACHE_FLUSH_EN)); + } + + agp_generic_destroy_page(addr); +} + +/* Setup function */ +static gatt_mask ali_generic_masks[] = +{ + {0x00000000, 0} +}; + +static aper_size_info_32 ali_generic_sizes[7] = +{ + {256, 65536, 6, 10}, + {128, 32768, 5, 9}, + {64, 16384, 4, 8}, + {32, 8192, 3, 7}, + {16, 4096, 2, 6}, + {8, 2048, 1, 4}, + {4, 1024, 0, 3} +}; + +int __init ali_generic_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = ali_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) ali_generic_sizes; + agp_bridge.size_type = U32_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = ali_configure; + agp_bridge.fetch_size = ali_fetch_size; + agp_bridge.cleanup = ali_cleanup; + agp_bridge.tlb_flush = ali_tlbflush; + agp_bridge.mask_memory = ali_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = ali_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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 = ali_alloc_page; + agp_bridge.agp_destroy_page = ali_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-amd.c linux-2.5/drivers/char/agp/agpgart_be-amd.c --- linux-2.5.23/drivers/char/agp/agpgart_be-amd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-amd.c Wed Jun 19 17:54:38 2002 @@ -0,0 +1,426 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +typedef struct _amd_page_map { + unsigned long *real; + unsigned long *remapped; +} amd_page_map; + +static struct _amd_irongate_private { + volatile u8 *registers; + amd_page_map **gatt_pages; + int num_tables; +} amd_irongate_private; + +static int amd_create_page_map(amd_page_map *page_map) +{ + int i; + + page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); + if (page_map->real == NULL) { + return -ENOMEM; + } + SetPageReserved(virt_to_page(page_map->real)); + CACHE_FLUSH(); + page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + PAGE_SIZE); + if (page_map->remapped == NULL) { + ClearPageReserved(virt_to_page(page_map->real)); + free_page((unsigned long) page_map->real); + page_map->real = NULL; + return -ENOMEM; + } + CACHE_FLUSH(); + + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { + page_map->remapped[i] = agp_bridge.scratch_page; + } + + return 0; +} + +static void amd_free_page_map(amd_page_map *page_map) +{ + iounmap(page_map->remapped); + ClearPageReserved(virt_to_page(page_map->real)); + free_page((unsigned long) page_map->real); +} + +static void amd_free_gatt_pages(void) +{ + int i; + amd_page_map **tables; + amd_page_map *entry; + + tables = amd_irongate_private.gatt_pages; + for(i = 0; i < amd_irongate_private.num_tables; i++) { + entry = tables[i]; + if (entry != NULL) { + if (entry->real != NULL) { + amd_free_page_map(entry); + } + kfree(entry); + } + } + kfree(tables); +} + +static int amd_create_gatt_pages(int nr_tables) +{ + amd_page_map **tables; + amd_page_map *entry; + int retval = 0; + int i; + + tables = kmalloc((nr_tables + 1) * sizeof(amd_page_map *), + GFP_KERNEL); + if (tables == NULL) { + return -ENOMEM; + } + memset(tables, 0, sizeof(amd_page_map *) * (nr_tables + 1)); + for (i = 0; i < nr_tables; i++) { + entry = kmalloc(sizeof(amd_page_map), GFP_KERNEL); + if (entry == NULL) { + retval = -ENOMEM; + break; + } + memset(entry, 0, sizeof(amd_page_map)); + tables[i] = entry; + retval = amd_create_page_map(entry); + if (retval != 0) break; + } + amd_irongate_private.num_tables = nr_tables; + amd_irongate_private.gatt_pages = tables; + + if (retval != 0) amd_free_gatt_pages(); + + return retval; +} + +/* Since we don't need contigious memory we just try + * to get the gatt table once + */ + +#define GET_PAGE_DIR_OFF(addr) (addr >> 22) +#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ + GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) +#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) +#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\ + GET_PAGE_DIR_IDX(addr)]->remapped) + +static int amd_create_gatt_table(void) +{ + aper_size_info_lvl2 *value; + amd_page_map page_dir; + unsigned long addr; + int retval; + u32 temp; + int i; + + value = A_SIZE_LVL2(agp_bridge.current_size); + retval = amd_create_page_map(&page_dir); + if (retval != 0) { + return retval; + } + + retval = amd_create_gatt_pages(value->num_entries / 1024); + if (retval != 0) { + amd_free_page_map(&page_dir); + return retval; + } + + agp_bridge.gatt_table_real = page_dir.real; + agp_bridge.gatt_table = page_dir.remapped; + agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real); + + /* Get the address for the gart region. + * This is a bus address even on the alpha, b/c its + * used to program the agp master not the cpu + */ + + pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); + addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + agp_bridge.gart_bus_addr = addr; + + /* Calculate the agp offset */ + for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { + page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = + virt_to_phys(amd_irongate_private.gatt_pages[i]->real); + page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; + } + + return 0; +} + +static int amd_free_gatt_table(void) +{ + amd_page_map page_dir; + + page_dir.real = agp_bridge.gatt_table_real; + page_dir.remapped = agp_bridge.gatt_table; + + amd_free_gatt_pages(); + amd_free_page_map(&page_dir); + return 0; +} + +static int amd_irongate_fetch_size(void) +{ + int i; + u32 temp; + aper_size_info_lvl2 *values; + + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = (temp & 0x0000000e); + values = A_SIZE_LVL2(agp_bridge.aperture_sizes); + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static int amd_irongate_configure(void) +{ + aper_size_info_lvl2 *current_size; + u32 temp; + u16 enable_reg; + + current_size = A_SIZE_LVL2(agp_bridge.current_size); + + /* Get the memory mapped registers */ + pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp); + temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); + amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096); + + /* Write out the address of the gatt table */ + OUTREG32(amd_irongate_private.registers, AMD_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* Write the Sync register */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); + + /* Set indexing mode */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00); + + /* Write the enable register */ + enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); + enable_reg = (enable_reg | 0x0004); + OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); + + /* Write out the size register */ + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = (((temp & ~(0x0000000e)) | current_size->size_value) + | 0x00000001); + pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp); + + /* Flush the tlb */ + OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); + + return 0; +} + +static void amd_irongate_cleanup(void) +{ + aper_size_info_lvl2 *previous_size; + u32 temp; + u16 enable_reg; + + previous_size = A_SIZE_LVL2(agp_bridge.previous_size); + + enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); + enable_reg = (enable_reg & ~(0x0004)); + OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); + + /* Write back the previous size and disable gart translation */ + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = ((temp & ~(0x0000000f)) | previous_size->size_value); + pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp); + iounmap((void *) amd_irongate_private.registers); +} + +/* + * This routine could be implemented by taking the addresses + * written to the GATT, and flushing them individually. However + * currently it just flushes the whole table. Which is probably + * more efficent, since agp_memory blocks can be a large number of + * entries. + */ + +static void amd_irongate_tlbflush(agp_memory * temp) +{ + OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); +} + +static unsigned long amd_irongate_mask_memory(unsigned long addr, int type) +{ + /* Only type 0 is supported by the irongate */ + + return addr | agp_bridge.masks[0].mask; +} + +static int amd_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + unsigned long *cur_gatt; + unsigned long addr; + + num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + mem->page_count)) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + } + agp_bridge.tlb_flush(mem); + return 0; +} + +static int amd_remove_memory(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + unsigned long *cur_gatt; + unsigned long addr; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = + (unsigned long) agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static aper_size_info_lvl2 amd_irongate_sizes[7] = +{ + {2048, 524288, 0x0000000c}, + {1024, 262144, 0x0000000a}, + {512, 131072, 0x00000008}, + {256, 65536, 0x00000006}, + {128, 32768, 0x00000004}, + {64, 16384, 0x00000002}, + {32, 8192, 0x00000000} +}; + +static gatt_mask amd_irongate_masks[] = +{ + {0x00000001, 0} +}; + +int __init amd_irongate_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = amd_irongate_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; + agp_bridge.size_type = LVL2_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = (void *) &amd_irongate_private; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = amd_irongate_configure; + agp_bridge.fetch_size = amd_irongate_fetch_size; + agp_bridge.cleanup = amd_irongate_cleanup; + agp_bridge.tlb_flush = amd_irongate_tlbflush; + agp_bridge.mask_memory = amd_irongate_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = amd_create_gatt_table; + agp_bridge.free_gatt_table = amd_free_gatt_table; + agp_bridge.insert_memory = amd_insert_memory; + agp_bridge.remove_memory = amd_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-hp.c linux-2.5/drivers/char/agp/agpgart_be-hp.c --- linux-2.5.23/drivers/char/agp/agpgart_be-hp.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-hp.c Wed Jun 19 17:33:11 2002 @@ -0,0 +1,412 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + + +#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); +} + +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 */ +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-i460.c linux-2.5/drivers/char/agp/agpgart_be-i460.c --- linux-2.5.23/drivers/char/agp/agpgart_be-i460.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-i460.c Wed Jun 19 17:33:20 2002 @@ -0,0 +1,613 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +/* BIOS configures the chipset so that one of two apbase registers are used */ +static u8 intel_i460_dynamic_apbase = 0x10; + +/* 460 supports multiple GART page sizes, so GART pageshift is dynamic */ +static u8 intel_i460_pageshift = 12; +static u32 intel_i460_pagesize; + +/* Keep track of which is larger, chipset or kernel page size. */ +static u32 intel_i460_cpk = 1; + +/* Structure for tracking partial use of 4MB GART pages */ +static u32 **i460_pg_detail = NULL; +static u32 *i460_pg_count = NULL; + +#define I460_CPAGES_PER_KPAGE (PAGE_SIZE >> intel_i460_pageshift) +#define I460_KPAGES_PER_CPAGE ((1 << intel_i460_pageshift) >> PAGE_SHIFT) + +#define I460_SRAM_IO_DISABLE (1 << 4) +#define I460_BAPBASE_ENABLE (1 << 3) +#define I460_AGPSIZ_MASK 0x7 +#define I460_4M_PS (1 << 1) + +#define log2(x) ffz(~(x)) + +static inline void intel_i460_read_back (volatile u32 *entry) +{ + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + *entry; +} + +static int intel_i460_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + /* Determine the GART page size */ + pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &temp); + intel_i460_pageshift = (temp & I460_4M_PS) ? 22 : 12; + intel_i460_pagesize = 1UL << intel_i460_pageshift; + + values = A_SIZE_8(agp_bridge.aperture_sizes); + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp); + + /* Exit now if the IO drivers for the GART SRAMS are turned off */ + if (temp & I460_SRAM_IO_DISABLE) { + printk(KERN_ERR PFX "GART SRAMS disabled on 460GX chipset\n"); + printk(KERN_ERR PFX "AGPGART operation not possible\n"); + return 0; + } + + /* Make sure we don't try to create an 2 ^ 23 entry GATT */ + if ((intel_i460_pageshift == 0) && ((temp & I460_AGPSIZ_MASK) == 4)) { + printk(KERN_ERR PFX "We can't have a 32GB aperture with 4KB GART pages\n"); + return 0; + } + + /* Determine the proper APBASE register */ + if (temp & I460_BAPBASE_ENABLE) + intel_i460_dynamic_apbase = INTEL_I460_BAPBASE; + else + intel_i460_dynamic_apbase = INTEL_I460_APBASE; + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + /* + * Dynamically calculate the proper num_entries and page_order values for + * the define aperture sizes. Take care not to shift off the end of + * values[i].size. + */ + values[i].num_entries = (values[i].size << 8) >> (intel_i460_pageshift - 12); + values[i].page_order = log2((sizeof(u32)*values[i].num_entries) >> PAGE_SHIFT); + } + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + /* Neglect control bits when matching up size_value */ + if ((temp & I460_AGPSIZ_MASK) == values[i].size_value) { + agp_bridge.previous_size = agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +/* There isn't anything to do here since 460 has no GART TLB. */ +static void intel_i460_tlb_flush(agp_memory * mem) +{ + return; +} + +/* + * This utility function is needed to prevent corruption of the control bits + * which are stored along with the aperture size in 460's AGPSIZ register + */ +static void intel_i460_write_agpsiz(u8 size_value) +{ + u8 temp; + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp); + pci_write_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, + ((temp & ~I460_AGPSIZ_MASK) | size_value)); +} + +static void intel_i460_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + intel_i460_write_agpsiz(previous_size->size_value); + + if (intel_i460_cpk == 0) { + vfree(i460_pg_detail); + vfree(i460_pg_count); + } +} + + +/* Control bits for Out-Of-GART coherency and Burst Write Combining */ +#define I460_GXBCTL_OOG (1UL << 0) +#define I460_GXBCTL_BWC (1UL << 2) + +static int intel_i460_configure(void) +{ + union { + u32 small[2]; + u64 large; + } temp; + u8 scratch; + int i; + + aper_size_info_8 *current_size; + + temp.large = 0; + + current_size = A_SIZE_8(agp_bridge.current_size); + intel_i460_write_agpsiz(current_size->size_value); + + /* + * Do the necessary rigmarole to read all eight bytes of APBASE. + * This has to be done since the AGP aperture can be above 4GB on + * 460 based systems. + */ + pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase, &(temp.small[0])); + pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase + 4, &(temp.small[1])); + + /* Clear BAR control bits */ + agp_bridge.gart_bus_addr = temp.large & ~((1UL << 3) - 1); + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &scratch); + pci_write_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, + (scratch & 0x02) | I460_GXBCTL_OOG | I460_GXBCTL_BWC); + + /* + * Initialize partial allocation trackers if a GART page is bigger than + * a kernel page. + */ + if (I460_CPAGES_PER_KPAGE >= 1) { + intel_i460_cpk = 1; + } else { + intel_i460_cpk = 0; + + i460_pg_detail = vmalloc(sizeof(*i460_pg_detail) * current_size->num_entries); + i460_pg_count = vmalloc(sizeof(*i460_pg_count) * current_size->num_entries); + + for (i = 0; i < current_size->num_entries; i++) { + i460_pg_count[i] = 0; + i460_pg_detail[i] = NULL; + } + } + return 0; +} + +static int intel_i460_create_gatt_table(void) +{ + char *table; + int i; + int page_order; + int num_entries; + void *temp; + + /* + * Load up the fixed address of the GART SRAMS which hold our + * GATT table. + */ + table = (char *) __va(INTEL_I460_ATTBASE); + + temp = agp_bridge.current_size; + page_order = A_SIZE_8(temp)->page_order; + num_entries = A_SIZE_8(temp)->num_entries; + + agp_bridge.gatt_table_real = (u32 *) table; + agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table), + (PAGE_SIZE * (1 << page_order))); + agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real); + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = 0; + } + + intel_i460_read_back(agp_bridge.gatt_table + i - 1); + return 0; +} + +static int intel_i460_free_gatt_table(void) +{ + int num_entries; + int i; + void *temp; + + temp = agp_bridge.current_size; + + num_entries = A_SIZE_8(temp)->num_entries; + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = 0; + } + + intel_i460_read_back(agp_bridge.gatt_table + i - 1); + + iounmap(agp_bridge.gatt_table); + return 0; +} + +/* These functions are called when PAGE_SIZE exceeds the GART page size */ + +static int intel_i460_insert_memory_cpk(agp_memory * mem, off_t pg_start, int type) +{ + int i, j, k, num_entries; + void *temp; + unsigned long paddr; + + /* + * The rest of the kernel will compute page offsets in terms of + * PAGE_SIZE. + */ + pg_start = I460_CPAGES_PER_KPAGE * pg_start; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + if ((pg_start + I460_CPAGES_PER_KPAGE * mem->page_count) > num_entries) { + printk(KERN_ERR PFX "Looks like we're out of AGP memory\n"); + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count)) { + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { + return -EBUSY; + } + j++; + } + +#if 0 + /* not necessary since 460 GART is operated in coherent mode... */ + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } +#endif + + for (i = 0, j = pg_start; i < mem->page_count; i++) { + paddr = mem->memory[i]; + for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, paddr += intel_i460_pagesize) + agp_bridge.gatt_table[j] = (u32) agp_bridge.mask_memory(paddr, mem->type); + } + + intel_i460_read_back(agp_bridge.gatt_table + j - 1); + return 0; +} + +static int intel_i460_remove_memory_cpk(agp_memory * mem, off_t pg_start, int type) +{ + int i; + + pg_start = I460_CPAGES_PER_KPAGE * pg_start; + + for (i = pg_start; i < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count); i++) + agp_bridge.gatt_table[i] = 0; + + intel_i460_read_back(agp_bridge.gatt_table + i - 1); + return 0; +} + +/* + * These functions are called when the GART page size exceeds PAGE_SIZE. + * + * This situation is interesting since AGP memory allocations that are + * smaller than a single GART page are possible. The structures i460_pg_count + * and i460_pg_detail track partial allocation of the large GART pages to + * work around this issue. + * + * i460_pg_count[pg_num] tracks the number of kernel pages in use within + * GART page pg_num. i460_pg_detail[pg_num] is an array containing a + * psuedo-GART entry for each of the aforementioned kernel pages. The whole + * of i460_pg_detail is equivalent to a giant GATT with page size equal to + * that of the kernel. + */ + +static void *intel_i460_alloc_large_page(int pg_num) +{ + int i; + void *bp, *bp_end; + struct page *page; + + i460_pg_detail[pg_num] = (void *) vmalloc(sizeof(u32) * I460_KPAGES_PER_CPAGE); + if (i460_pg_detail[pg_num] == NULL) { + printk(KERN_ERR PFX "Out of memory, we're in trouble...\n"); + return NULL; + } + + for (i = 0; i < I460_KPAGES_PER_CPAGE; i++) + i460_pg_detail[pg_num][i] = 0; + + bp = (void *) __get_free_pages(GFP_KERNEL, intel_i460_pageshift - PAGE_SHIFT); + if (bp == NULL) { + printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n"); + return NULL; + } + + bp_end = bp + ((PAGE_SIZE * (1 << (intel_i460_pageshift - PAGE_SHIFT))) - 1); + + for (page = virt_to_page(bp); page <= virt_to_page(bp_end); page++) { + atomic_inc(&agp_bridge.current_memory_agp); + } + return bp; +} + +static void intel_i460_free_large_page(int pg_num, unsigned long addr) +{ + struct page *page; + void *bp, *bp_end; + + bp = (void *) __va(addr); + bp_end = bp + (PAGE_SIZE * (1 << (intel_i460_pageshift - PAGE_SHIFT))); + + vfree(i460_pg_detail[pg_num]); + i460_pg_detail[pg_num] = NULL; + + for (page = virt_to_page(bp); page < virt_to_page(bp_end); page++) { + atomic_dec(&agp_bridge.current_memory_agp); + } + + free_pages((unsigned long) bp, intel_i460_pageshift - PAGE_SHIFT); +} + +static int intel_i460_insert_memory_kpc(agp_memory * mem, off_t pg_start, int type) +{ + int i, pg, start_pg, end_pg, start_offset, end_offset, idx; + int num_entries; + void *temp; + unsigned long paddr; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + /* Figure out what pg_start means in terms of our large GART pages */ + start_pg = pg_start / I460_KPAGES_PER_CPAGE; + start_offset = pg_start % I460_KPAGES_PER_CPAGE; + end_pg = (pg_start + mem->page_count - 1) / I460_KPAGES_PER_CPAGE; + end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_CPAGE; + + if (end_pg > num_entries) { + printk(KERN_ERR PFX "Looks like we're out of AGP memory\n"); + return -EINVAL; + } + + /* Check if the requested region of the aperture is free */ + for (pg = start_pg; pg <= end_pg; pg++) { + /* Allocate new GART pages if necessary */ + if (i460_pg_detail[pg] == NULL) { + temp = intel_i460_alloc_large_page(pg); + if (temp == NULL) + return -ENOMEM; + agp_bridge.gatt_table[pg] = agp_bridge.mask_memory((unsigned long) temp, + 0); + intel_i460_read_back(agp_bridge.gatt_table + pg); + } + + for (idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE); + idx++) + { + if (i460_pg_detail[pg][idx] != 0) + return -EBUSY; + } + } + +#if 0 + /* not necessary since 460 GART is operated in coherent mode... */ + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } +#endif + + for (pg = start_pg, i = 0; pg <= end_pg; pg++) { + paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]); + for (idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE); + idx++, i++) + { + mem->memory[i] = paddr + (idx * PAGE_SIZE); + i460_pg_detail[pg][idx] = agp_bridge.mask_memory(mem->memory[i], + mem->type); + i460_pg_count[pg]++; + } + } + + return 0; +} + +static int intel_i460_remove_memory_kpc(agp_memory * mem, off_t pg_start, int type) +{ + int i, pg, start_pg, end_pg, start_offset, end_offset, idx; + int num_entries; + void *temp; + unsigned long paddr; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + /* Figure out what pg_start means in terms of our large GART pages */ + start_pg = pg_start / I460_KPAGES_PER_CPAGE; + start_offset = pg_start % I460_KPAGES_PER_CPAGE; + end_pg = (pg_start + mem->page_count - 1) / I460_KPAGES_PER_CPAGE; + end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_CPAGE; + + for (i = 0, pg = start_pg; pg <= end_pg; pg++) { + for (idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE); + idx++, i++) + { + mem->memory[i] = 0; + i460_pg_detail[pg][idx] = 0; + i460_pg_count[pg]--; + } + + /* Free GART pages if they are unused */ + if (i460_pg_count[pg] == 0) { + paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]); + agp_bridge.gatt_table[pg] = agp_bridge.scratch_page; + intel_i460_read_back(agp_bridge.gatt_table + pg); + intel_i460_free_large_page(pg, paddr); + } + } + return 0; +} + +/* Dummy routines to call the approriate {cpk,kpc} function */ + +static int intel_i460_insert_memory(agp_memory * mem, off_t pg_start, int type) +{ + if (intel_i460_cpk) + return intel_i460_insert_memory_cpk(mem, pg_start, type); + else + return intel_i460_insert_memory_kpc(mem, pg_start, type); +} + +static int intel_i460_remove_memory(agp_memory * mem, off_t pg_start, int type) +{ + if (intel_i460_cpk) + return intel_i460_remove_memory_cpk(mem, pg_start, type); + else + return intel_i460_remove_memory_kpc(mem, pg_start, type); +} + +/* + * If the kernel page size is smaller that the chipset page size, we don't + * want to allocate memory until we know where it is to be bound in the + * aperture (a multi-kernel-page alloc might fit inside of an already + * allocated GART page). Consequently, don't allocate or free anything + * if i460_cpk (meaning chipset pages per kernel page) isn't set. + * + * Let's just hope nobody counts on the allocated AGP memory being there + * before bind time (I don't think current drivers do)... + */ +static void * intel_i460_alloc_page(void) +{ + if (intel_i460_cpk) + return agp_generic_alloc_page(); + + /* Returning NULL would cause problems */ + /* AK: really dubious code. */ + return (void *)~0UL; +} + +static void intel_i460_destroy_page(void *page) +{ + if (intel_i460_cpk) + agp_generic_destroy_page(page); +} + +static gatt_mask intel_i460_masks[] = +{ + { + INTEL_I460_GATT_VALID | INTEL_I460_GATT_COHERENT, + 0 + } +}; + +static unsigned long intel_i460_mask_memory(unsigned long addr, int type) +{ + /* Make sure the returned address is a valid GATT entry */ + return (agp_bridge.masks[0].mask + | (((addr & ~((1 << intel_i460_pageshift) - 1)) & 0xffffff000) >> 12)); +} + +static unsigned long intel_i460_unmask_memory(unsigned long addr) +{ + /* Turn a GATT entry into a physical address */ + return ((addr & 0xffffff) << 12); +} + +static aper_size_info_8 intel_i460_sizes[3] = +{ + /* + * The 32GB aperture is only available with a 4M GART page size. + * Due to the dynamic GART page size, we can't figure out page_order + * or num_entries until runtime. + */ + {32768, 0, 0, 4}, + {1024, 0, 0, 2}, + {256, 0, 0, 1} +}; + +int __init intel_i460_setup (struct pci_dev *pdev __attribute__((unused))) +{ + agp_bridge.masks = intel_i460_masks; + agp_bridge.aperture_sizes = (void *) intel_i460_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 3; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_i460_configure; + agp_bridge.fetch_size = intel_i460_fetch_size; + agp_bridge.cleanup = intel_i460_cleanup; + agp_bridge.tlb_flush = intel_i460_tlb_flush; + agp_bridge.mask_memory = intel_i460_mask_memory; + agp_bridge.unmask_memory = intel_i460_unmask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = intel_i460_create_gatt_table; + agp_bridge.free_gatt_table = intel_i460_free_gatt_table; + agp_bridge.insert_memory = intel_i460_insert_memory; + agp_bridge.remove_memory = intel_i460_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 = intel_i460_alloc_page; + agp_bridge.agp_destroy_page = intel_i460_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 1; + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-i810.c linux-2.5/drivers/char/agp/agpgart_be-i810.c --- linux-2.5.23/drivers/char/agp/agpgart_be-i810.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-i810.c Wed Jun 19 17:36:39 2002 @@ -0,0 +1,611 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +static aper_size_info_fixed intel_i810_sizes[] = +{ + {64, 16384, 4}, + /* The 32M mode still requires a 64k gatt */ + {32, 8192, 4} +}; + +#define AGP_DCACHE_MEMORY 1 +#define AGP_PHYS_MEMORY 2 + +static gatt_mask intel_i810_masks[] = +{ + {I810_PTE_VALID, 0}, + {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY}, + {I810_PTE_VALID, 0} +}; + +static struct _intel_i810_private { + struct pci_dev *i810_dev; /* device one */ + volatile u8 *registers; + int num_dcache_entries; +} intel_i810_private; + +static int intel_i810_fetch_size(void) +{ + u32 smram_miscc; + aper_size_info_fixed *values; + + pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc); + values = A_SIZE_FIX(agp_bridge.aperture_sizes); + + if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { + printk(KERN_WARNING PFX "i810 is disabled\n"); + return 0; + } + if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + 1); + agp_bridge.aperture_size_idx = 1; + return values[1].size; + } else { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values); + agp_bridge.aperture_size_idx = 0; + return values[0].size; + } + + return 0; +} + +static int intel_i810_configure(void) +{ + aper_size_info_fixed *current_size; + u32 temp; + int i; + + current_size = A_SIZE_FIX(agp_bridge.current_size); + + pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); + temp &= 0xfff80000; + + intel_i810_private.registers = + (volatile u8 *) ioremap(temp, 128 * 4096); + + if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL) + & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { + /* This will need to be dynamically assigned */ + printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); + intel_i810_private.num_dcache_entries = 1024; + } + pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, + agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED); + CACHE_FLUSH(); + + if (agp_bridge.needs_scratch_page == TRUE) { + for (i = 0; i < current_size->num_entries; i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + agp_bridge.scratch_page); + } + } + return 0; +} + +static void intel_i810_cleanup(void) +{ + OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0); + iounmap((void *) intel_i810_private.registers); +} + +static void intel_i810_tlbflush(agp_memory * mem) +{ + return; +} + +static void intel_i810_agp_enable(u32 mode) +{ + return; +} + +static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start, + int type) +{ + int i, j, num_entries; + void *temp; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_FIX(temp)->num_entries; + + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + for (j = pg_start; j < (pg_start + mem->page_count); j++) { + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { + return -EBUSY; + } + } + + if (type != 0 || mem->type != 0) { + if ((type == AGP_DCACHE_MEMORY) && + (mem->type == AGP_DCACHE_MEMORY)) { + /* special insert */ + CACHE_FLUSH(); + for (i = pg_start; + i < (pg_start + mem->page_count); i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + (i * 4096) | I810_PTE_LOCAL | + I810_PTE_VALID); + } + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + return 0; + } + if((type == AGP_PHYS_MEMORY) && + (mem->type == AGP_PHYS_MEMORY)) { + goto insert; + } + return -EINVAL; + } + +insert: + CACHE_FLUSH(); + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (j * 4), mem->memory[i]); + } + CACHE_FLUSH(); + + agp_bridge.tlb_flush(mem); + return 0; +} + +static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + agp_bridge.scratch_page); + } + + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + return 0; +} + +static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) +{ + agp_memory *new; + + if (type == AGP_DCACHE_MEMORY) { + if (pg_count != intel_i810_private.num_dcache_entries) { + return NULL; + } + new = agp_create_memory(1); + + if (new == NULL) { + return NULL; + } + new->type = AGP_DCACHE_MEMORY; + new->page_count = pg_count; + new->num_scratch_pages = 0; + vfree(new->memory); + MOD_INC_USE_COUNT; + return new; + } + if(type == AGP_PHYS_MEMORY) { + void *addr; + /* The I810 requires a physical address to program + * it's mouse pointer into hardware. However the + * Xserver still writes to it through the agp + * aperture + */ + if (pg_count != 1) { + return NULL; + } + new = agp_create_memory(1); + + if (new == NULL) { + return NULL; + } + MOD_INC_USE_COUNT; + addr = agp_bridge.agp_alloc_page(); + + if (addr == NULL) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr), type); + new->page_count = 1; + new->num_scratch_pages = 1; + new->type = AGP_PHYS_MEMORY; + new->physical = virt_to_phys((void *) new->memory[0]); + return new; + } + + return NULL; +} + +static void intel_i810_free_by_type(agp_memory * curr) +{ + agp_free_key(curr->key); + if(curr->type == AGP_PHYS_MEMORY) { + agp_bridge.agp_destroy_page( + phys_to_virt(curr->memory[0])); + vfree(curr->memory); + } + kfree(curr); + MOD_DEC_USE_COUNT; +} + +static unsigned long intel_i810_mask_memory(unsigned long addr, int type) +{ + /* Type checking must be done elsewhere */ + return addr | agp_bridge.masks[type].mask; +} + +int __init intel_i810_setup(struct pci_dev *i810_dev) +{ + intel_i810_private.i810_dev = i810_dev; + + agp_bridge.masks = intel_i810_masks; + agp_bridge.num_of_masks = 2; + agp_bridge.aperture_sizes = (void *) intel_i810_sizes; + agp_bridge.size_type = FIXED_APER_SIZE; + agp_bridge.num_aperture_sizes = 2; + agp_bridge.dev_private_data = (void *) &intel_i810_private; + agp_bridge.needs_scratch_page = TRUE; + agp_bridge.configure = intel_i810_configure; + agp_bridge.fetch_size = intel_i810_fetch_size; + agp_bridge.cleanup = intel_i810_cleanup; + agp_bridge.tlb_flush = intel_i810_tlbflush; + agp_bridge.mask_memory = intel_i810_mask_memory; + agp_bridge.agp_enable = intel_i810_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = intel_i810_insert_entries; + agp_bridge.remove_memory = intel_i810_remove_entries; + agp_bridge.alloc_by_type = intel_i810_alloc_by_type; + agp_bridge.free_by_type = intel_i810_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; +} + +static aper_size_info_fixed intel_i830_sizes[] = +{ + {128, 32768, 5}, + /* The 64M mode still requires a 128k gatt */ + {64, 16384, 5} +}; + +static struct _intel_i830_private { + struct pci_dev *i830_dev; /* device one */ + volatile u8 *registers; + int gtt_entries; +} intel_i830_private; + +static void intel_i830_init_gtt_entries(void) { + u16 gmch_ctrl; + int gtt_entries; + u8 rdct; + static const int ddt[4] = { 0, 16, 32, 64 }; + + pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); + + switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + case I830_GMCH_GMS_STOLEN_512: + gtt_entries = KB(512); + printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1)); + break; + case I830_GMCH_GMS_STOLEN_1024: + gtt_entries = MB(1); + printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1)); + break; + case I830_GMCH_GMS_STOLEN_8192: + gtt_entries = MB(8); + printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1)); + break; + case I830_GMCH_GMS_LOCAL: + rdct = INREG8(intel_i830_private.registers,I830_RDRAM_CHANNEL_TYPE); + gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); + printk(KERN_INFO PFX "detected %dK local memory.\n",gtt_entries / KB(1)); + break; + default: + printk(KERN_INFO PFX "no video memory detected.\n"); + gtt_entries = 0; + break; + } + + gtt_entries /= KB(4); + + intel_i830_private.gtt_entries = gtt_entries; +} + +/* The intel i830 automatically initializes the agp aperture during POST. + * Use the memory already set aside for in the GTT. + */ +static int intel_i830_create_gatt_table(void) +{ + int page_order; + aper_size_info_fixed *size; + int num_entries; + u32 temp; + + size = agp_bridge.current_size; + page_order = size->page_order; + num_entries = size->num_entries; + agp_bridge.gatt_table_real = 0; + + pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); + temp &= 0xfff80000; + + intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + if (!intel_i830_private.registers) return (-ENOMEM); + + temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000; + CACHE_FLUSH(); + + /* we have to call this as early as possible after the MMIO base address is known */ + intel_i830_init_gtt_entries(); + + agp_bridge.gatt_table = NULL; + + agp_bridge.gatt_bus_addr = temp; + + return(0); +} + +/* Return the gatt table to a sane state. Use the top of stolen + * memory for the GTT. + */ +static int intel_i830_free_gatt_table(void) +{ + return(0); +} + +static int intel_i830_fetch_size(void) +{ + u16 gmch_ctrl; + aper_size_info_fixed *values; + + pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); + values = A_SIZE_FIX(agp_bridge.aperture_sizes); + + if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { + agp_bridge.previous_size = agp_bridge.current_size = (void *) values; + agp_bridge.aperture_size_idx = 0; + return(values[0].size); + } else { + agp_bridge.previous_size = agp_bridge.current_size = (void *) values; + agp_bridge.aperture_size_idx = 1; + return(values[1].size); + } + + return(0); +} + +static int intel_i830_configure(void) +{ + aper_size_info_fixed *current_size; + u32 temp; + u16 gmch_ctrl; + int i; + + current_size = A_SIZE_FIX(agp_bridge.current_size); + + pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); + gmch_ctrl |= I830_GMCH_ENABLED; + pci_write_config_word(agp_bridge.dev,I830_GMCH_CTRL,gmch_ctrl); + + OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED); + CACHE_FLUSH(); + + if (agp_bridge.needs_scratch_page == TRUE) + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + + return (0); +} + +static void intel_i830_cleanup(void) +{ + iounmap((void *) intel_i830_private.registers); +} + +static int intel_i830_insert_entries(agp_memory *mem,off_t pg_start,int type) +{ + int i,j,num_entries; + void *temp; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_FIX(temp)->num_entries; + + if (pg_start < intel_i830_private.gtt_entries) { + printk (KERN_DEBUG "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n", + pg_start,intel_i830_private.gtt_entries); + + printk ("Trying to insert into local/stolen memory\n"); + return (-EINVAL); + } + + if ((pg_start + mem->page_count) > num_entries) + return (-EINVAL); + + /* The i830 can't check the GTT for entries since its read only, + * depend on the caller to make the correct offset decisions. + */ + + if ((type != 0 && type != AGP_PHYS_MEMORY) || + (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) + return (-EINVAL); + + CACHE_FLUSH(); + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]); + + CACHE_FLUSH(); + + agp_bridge.tlb_flush(mem); + + return(0); +} + +static int intel_i830_remove_entries(agp_memory *mem,off_t pg_start,int type) +{ + int i; + + CACHE_FLUSH (); + + if (pg_start < intel_i830_private.gtt_entries) { + printk ("Trying to disable local/stolen memory\n"); + return (-EINVAL); + } + + for (i = pg_start; i < (mem->page_count + pg_start); i++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + + CACHE_FLUSH(); + + agp_bridge.tlb_flush(mem); + + return (0); +} + +static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) +{ + agp_memory *nw; + + /* always return NULL for now */ + if (type == AGP_DCACHE_MEMORY) return(NULL); + + if (type == AGP_PHYS_MEMORY) { + void *addr; + + /* The i830 requires a physical address to program + * it's mouse pointer into hardware. However the + * Xserver still writes to it through the agp + * aperture + */ + + if (pg_count != 1) return(NULL); + + nw = agp_create_memory(1); + + if (nw == NULL) return(NULL); + + MOD_INC_USE_COUNT; + addr = agp_bridge.agp_alloc_page(); + if (addr == NULL) { + /* free this structure */ + agp_free_memory(nw); + return(NULL); + } + + nw->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr),type); + nw->page_count = 1; + nw->num_scratch_pages = 1; + nw->type = AGP_PHYS_MEMORY; + nw->physical = virt_to_phys(addr); + return(nw); + } + + return(NULL); +} + +int __init intel_i830_setup(struct pci_dev *i830_dev) +{ + intel_i830_private.i830_dev = i830_dev; + + agp_bridge.masks = intel_i810_masks; + agp_bridge.num_of_masks = 3; + agp_bridge.aperture_sizes = (void *) intel_i830_sizes; + agp_bridge.size_type = FIXED_APER_SIZE; + agp_bridge.num_aperture_sizes = 2; + + agp_bridge.dev_private_data = (void *) &intel_i830_private; + agp_bridge.needs_scratch_page = TRUE; + + agp_bridge.configure = intel_i830_configure; + agp_bridge.fetch_size = intel_i830_fetch_size; + agp_bridge.cleanup = intel_i830_cleanup; + agp_bridge.tlb_flush = intel_i810_tlbflush; + agp_bridge.mask_memory = intel_i810_mask_memory; + agp_bridge.agp_enable = intel_i810_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + + agp_bridge.create_gatt_table = intel_i830_create_gatt_table; + agp_bridge.free_gatt_table = intel_i830_free_gatt_table; + + agp_bridge.insert_memory = intel_i830_insert_entries; + agp_bridge.remove_memory = intel_i830_remove_entries; + agp_bridge.alloc_by_type = intel_i830_alloc_by_type; + agp_bridge.free_by_type = intel_i810_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return(0); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-i8x0.c linux-2.5/drivers/char/agp/agpgart_be-i8x0.c --- linux-2.5.23/drivers/char/agp/agpgart_be-i8x0.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-i8x0.c Wed Jun 19 17:38:44 2002 @@ -0,0 +1,664 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + + + +static int intel_fetch_size(void) +{ + int i; + u16 temp; + aper_size_info_16 *values; + + pci_read_config_word(agp_bridge.dev, INTEL_APSIZE, &temp); + values = A_SIZE_16(agp_bridge.aperture_sizes); + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static int intel_8xx_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + pci_read_config_byte(agp_bridge.dev, INTEL_APSIZE, &temp); + values = A_SIZE_8(agp_bridge.aperture_sizes); + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + return 0; +} + + +static void intel_tlbflush(agp_memory * mem) +{ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); +} + + +static void intel_8xx_tlbflush(agp_memory * mem) +{ + u32 temp; + pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp & ~(1 << 7)); + pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp | (1 << 7)); +} + + +static void intel_cleanup(void) +{ + u16 temp; + aper_size_info_16 *previous_size; + + previous_size = A_SIZE_16(agp_bridge.previous_size); + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); + pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + + +static void intel_8xx_cleanup(void) +{ + u16 temp; + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + + +static int intel_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_16 *current_size; + + current_size = A_SIZE_16(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); + + /* paccfg/nbxcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, + (temp2 & ~(1 << 10)) | (1 << 9)); + /* clear any possible error conditions */ + pci_write_config_byte(agp_bridge.dev, INTEL_ERRSTS + 1, 7); + return 0; +} + +static void intel_820_tlbflush(agp_memory * mem) +{ + return; +} + +static void intel_820_cleanup(void) +{ + u8 temp; + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp); + pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, + temp & ~(1 << 1)); + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + + +static int intel_820_configure(void) +{ + u32 temp; + u8 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* global enable aperture access */ + /* This flag is not accessed through MCHCFG register as in */ + /* i850 chipset. */ + pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp2); + pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, + temp2 | (1 << 1)); + /* clear any possible AGP-related error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I820_ERRSTS, 0x001c); + return 0; +} + +static int intel_840_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* mcgcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, + temp2 | (1 << 9)); + /* clear any possible error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000); + return 0; +} + +static int intel_845_configure(void) +{ + u32 temp; + u8 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* agpm */ + pci_read_config_byte(agp_bridge.dev, INTEL_I845_AGPM, &temp2); + pci_write_config_byte(agp_bridge.dev, INTEL_I845_AGPM, + temp2 | (1 << 1)); + /* clear any possible error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I845_ERRSTS, 0x001c); + return 0; +} + +static int intel_850_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* mcgcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, + temp2 | (1 << 9)); + /* clear any possible AGP-related error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I850_ERRSTS, 0x001c); + return 0; +} + +static int intel_860_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* mcgcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, + temp2 | (1 << 9)); + /* clear any possible AGP-related error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I860_ERRSTS, 0xf700); + return 0; +} + +static int intel_830mp_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* gmch */ + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, + temp2 | (1 << 9)); + /* clear any possible AGP-related error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I830_ERRSTS, 0x1c); + return 0; +} + +static unsigned long intel_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + +static void intel_resume(void) +{ + intel_configure(); +} + +/* Setup function */ +static gatt_mask intel_generic_masks[] = +{ + {0x00000017, 0} +}; + +static aper_size_info_8 intel_8xx_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 32}, + {64, 16384, 4, 48}, + {32, 8192, 3, 56}, + {16, 4096, 2, 60}, + {8, 2048, 1, 62}, + {4, 1024, 0, 63} +}; + +static aper_size_info_16 intel_generic_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 32}, + {64, 16384, 4, 48}, + {32, 8192, 3, 56}, + {16, 4096, 2, 60}, + {8, 2048, 1, 62}, + {4, 1024, 0, 63} +}; + +static aper_size_info_8 intel_830mp_sizes[4] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 32}, + {64, 16384, 4, 48}, + {32, 8192, 3, 56} +}; + +int __init intel_generic_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_generic_sizes; + agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_configure; + agp_bridge.fetch_size = intel_fetch_size; + agp_bridge.cleanup = intel_cleanup; + agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = intel_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + + +int __init intel_820_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_820_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_820_cleanup; + agp_bridge.tlb_flush = intel_820_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + +int __init intel_830mp_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_830mp_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 4; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_830mp_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + +int __init intel_840_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_840_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + +int __init intel_845_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_845_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + +int __init intel_850_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_850_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + +int __init intel_860_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_860_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-serverworks.c linux-2.5/drivers/char/agp/agpgart_be-serverworks.c --- linux-2.5.23/drivers/char/agp/agpgart_be-serverworks.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-serverworks.c Wed Jun 19 15:38:43 2002 @@ -0,0 +1,644 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +typedef struct _serverworks_page_map { + unsigned long *real; + unsigned long *remapped; +} serverworks_page_map; + +static struct _serverworks_private { + struct pci_dev *svrwrks_dev; /* device one */ + volatile u8 *registers; + serverworks_page_map **gatt_pages; + int num_tables; + serverworks_page_map scratch_dir; + + int gart_addr_ofs; + int mm_addr_ofs; +} serverworks_private; + +static int serverworks_create_page_map(serverworks_page_map *page_map) +{ + int i; + + page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); + if (page_map->real == NULL) { + return -ENOMEM; + } + SetPageReserved(virt_to_page(page_map->real)); + CACHE_FLUSH(); + page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + PAGE_SIZE); + if (page_map->remapped == NULL) { + ClearPageReserved(virt_to_page(page_map->real)); + free_page((unsigned long) page_map->real); + page_map->real = NULL; + return -ENOMEM; + } + CACHE_FLUSH(); + + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { + page_map->remapped[i] = agp_bridge.scratch_page; + } + + return 0; +} + +static void serverworks_free_page_map(serverworks_page_map *page_map) +{ + iounmap(page_map->remapped); + ClearPageReserved(virt_to_page(page_map->real)); + free_page((unsigned long) page_map->real); +} + +static void serverworks_free_gatt_pages(void) +{ + int i; + serverworks_page_map **tables; + serverworks_page_map *entry; + + tables = serverworks_private.gatt_pages; + for(i = 0; i < serverworks_private.num_tables; i++) { + entry = tables[i]; + if (entry != NULL) { + if (entry->real != NULL) { + serverworks_free_page_map(entry); + } + kfree(entry); + } + } + kfree(tables); +} + +static int serverworks_create_gatt_pages(int nr_tables) +{ + serverworks_page_map **tables; + serverworks_page_map *entry; + int retval = 0; + int i; + + tables = kmalloc((nr_tables + 1) * sizeof(serverworks_page_map *), + GFP_KERNEL); + if (tables == NULL) { + return -ENOMEM; + } + memset(tables, 0, sizeof(serverworks_page_map *) * (nr_tables + 1)); + for (i = 0; i < nr_tables; i++) { + entry = kmalloc(sizeof(serverworks_page_map), GFP_KERNEL); + if (entry == NULL) { + retval = -ENOMEM; + break; + } + memset(entry, 0, sizeof(serverworks_page_map)); + tables[i] = entry; + retval = serverworks_create_page_map(entry); + if (retval != 0) break; + } + serverworks_private.num_tables = nr_tables; + serverworks_private.gatt_pages = tables; + + if (retval != 0) serverworks_free_gatt_pages(); + + return retval; +} + +#define SVRWRKS_GET_GATT(addr) (serverworks_private.gatt_pages[\ + GET_PAGE_DIR_IDX(addr)]->remapped) + +#ifndef GET_PAGE_DIR_OFF +#define GET_PAGE_DIR_OFF(addr) (addr >> 22) +#endif + +#ifndef GET_PAGE_DIR_IDX +#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ + GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) +#endif + +#ifndef GET_GATT_OFF +#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) +#endif + +static int serverworks_create_gatt_table(void) +{ + aper_size_info_lvl2 *value; + serverworks_page_map page_dir; + int retval; + u32 temp; + int i; + + value = A_SIZE_LVL2(agp_bridge.current_size); + retval = serverworks_create_page_map(&page_dir); + if (retval != 0) { + return retval; + } + retval = serverworks_create_page_map(&serverworks_private.scratch_dir); + if (retval != 0) { + serverworks_free_page_map(&page_dir); + return retval; + } + /* Create a fake scratch directory */ + for(i = 0; i < 1024; i++) { + serverworks_private.scratch_dir.remapped[i] = (unsigned long) agp_bridge.scratch_page; + page_dir.remapped[i] = + virt_to_phys(serverworks_private.scratch_dir.real); + page_dir.remapped[i] |= 0x00000001; + } + + retval = serverworks_create_gatt_pages(value->num_entries / 1024); + if (retval != 0) { + serverworks_free_page_map(&page_dir); + serverworks_free_page_map(&serverworks_private.scratch_dir); + return retval; + } + + agp_bridge.gatt_table_real = page_dir.real; + agp_bridge.gatt_table = page_dir.remapped; + agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real); + + /* Get the address for the gart region. + * This is a bus address even on the alpha, b/c its + * used to program the agp master not the cpu + */ + + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* Calculate the agp offset */ + + for(i = 0; i < value->num_entries / 1024; i++) { + page_dir.remapped[i] = + virt_to_phys(serverworks_private.gatt_pages[i]->real); + page_dir.remapped[i] |= 0x00000001; + } + + return 0; +} + +static int serverworks_free_gatt_table(void) +{ + serverworks_page_map page_dir; + + page_dir.real = agp_bridge.gatt_table_real; + page_dir.remapped = agp_bridge.gatt_table; + + serverworks_free_gatt_pages(); + serverworks_free_page_map(&page_dir); + serverworks_free_page_map(&serverworks_private.scratch_dir); + return 0; +} + +static int serverworks_fetch_size(void) +{ + int i; + u32 temp; + u32 temp2; + aper_size_info_lvl2 *values; + + values = A_SIZE_LVL2(agp_bridge.aperture_sizes); + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp); + pci_write_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + SVWRKS_SIZE_MASK); + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp2); + pci_write_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + temp); + temp2 &= SVWRKS_SIZE_MASK; + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp2 == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static int serverworks_configure(void) +{ + aper_size_info_lvl2 *current_size; + u32 temp; + u8 enable_reg; + u8 cap_ptr; + u32 cap_id; + u16 cap_reg; + + current_size = A_SIZE_LVL2(agp_bridge.current_size); + + /* Get the memory mapped registers */ + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs, + &temp); + temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); + serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096); + + OUTREG8(serverworks_private.registers, SVWRKS_GART_CACHE, 0x0a); + + OUTREG32(serverworks_private.registers, SVWRKS_GATTBASE, + agp_bridge.gatt_bus_addr); + + cap_reg = INREG16(serverworks_private.registers, SVWRKS_COMMAND); + cap_reg &= ~0x0007; + cap_reg |= 0x4; + OUTREG16(serverworks_private.registers, SVWRKS_COMMAND, cap_reg); + + pci_read_config_byte(serverworks_private.svrwrks_dev, + SVWRKS_AGP_ENABLE, &enable_reg); + enable_reg |= 0x1; /* Agp Enable bit */ + pci_write_config_byte(serverworks_private.svrwrks_dev, + SVWRKS_AGP_ENABLE, enable_reg); + agp_bridge.tlb_flush(NULL); + + pci_read_config_byte(serverworks_private.svrwrks_dev, 0x34, &cap_ptr); + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(serverworks_private.svrwrks_dev, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + agp_bridge.capndx = cap_ptr; + + /* Fill in the mode register */ + pci_read_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 4, + &agp_bridge.mode); + + pci_read_config_byte(agp_bridge.dev, + SVWRKS_CACHING, + &enable_reg); + enable_reg &= ~0x3; + pci_write_config_byte(agp_bridge.dev, + SVWRKS_CACHING, + enable_reg); + + pci_read_config_byte(agp_bridge.dev, + SVWRKS_FEATURE, + &enable_reg); + enable_reg |= (1<<6); + pci_write_config_byte(agp_bridge.dev, + SVWRKS_FEATURE, + enable_reg); + + return 0; +} + +static void serverworks_cleanup(void) +{ + iounmap((void *) serverworks_private.registers); +} + +/* + * This routine could be implemented by taking the addresses + * written to the GATT, and flushing them individually. However + * currently it just flushes the whole table. Which is probably + * more efficent, since agp_memory blocks can be a large number of + * entries. + */ + +static void serverworks_tlbflush(agp_memory * temp) +{ + unsigned long end; + + OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01); + end = jiffies + 3*HZ; + while(INREG8(serverworks_private.registers, + SVWRKS_POSTFLUSH) == 0x01) { + if((signed)(end - jiffies) <= 0) { + printk(KERN_ERR "Posted write buffer flush took more" + "then 3 seconds\n"); + } + } + OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001); + end = jiffies + 3*HZ; + while(INREG32(serverworks_private.registers, + SVWRKS_DIRFLUSH) == 0x00000001) { + if((signed)(end - jiffies) <= 0) { + printk(KERN_ERR "TLB flush took more" + "then 3 seconds\n"); + } + } +} + +static unsigned long serverworks_mask_memory(unsigned long addr, int type) +{ + /* Only type 0 is supported by the serverworks chipsets */ + + return addr | agp_bridge.masks[0].mask; +} + +static int serverworks_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + unsigned long *cur_gatt; + unsigned long addr; + + num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + mem->page_count)) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + } + agp_bridge.tlb_flush(mem); + return 0; +} + +static int serverworks_remove_memory(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + unsigned long *cur_gatt; + unsigned long addr; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = + (unsigned long) agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static gatt_mask serverworks_masks[] = +{ + {0x00000001, 0} +}; + +static aper_size_info_lvl2 serverworks_sizes[7] = +{ + {2048, 524288, 0x80000000}, + {1024, 262144, 0xc0000000}, + {512, 131072, 0xe0000000}, + {256, 65536, 0xf0000000}, + {128, 32768, 0xf8000000}, + {64, 16384, 0xfc000000}, + {32, 8192, 0xfe000000} +}; + +static void serverworks_agp_enable(u32 mode) +{ + struct pci_dev *device = NULL; + u32 command, scratch, cap_id; + u8 cap_ptr; + + pci_read_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 4, + &command); + + /* + * PASS1: go throu all devices that claim to be + * AGP devices and collect their data. + */ + + + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(device, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr != 0x00) { + /* + * Ok, here we have a AGP device. Disable impossible + * settings, and adjust the readqueue to the minimum. + */ + + pci_read_config_dword(device, cap_ptr + 4, &scratch); + + /* adjust RQ depth */ + command = + ((command & ~0xff000000) | + min_t(u32, (mode & 0xff000000), + min_t(u32, (command & 0xff000000), + (scratch & 0xff000000)))); + + /* disable SBA if it's not supported */ + if (!((command & 0x00000200) && + (scratch & 0x00000200) && + (mode & 0x00000200))) + command &= ~0x00000200; + + /* disable FW */ + command &= ~0x00000010; + + command &= ~0x00000008; + + if (!((command & 4) && + (scratch & 4) && + (mode & 4))) + command &= ~0x00000004; + + if (!((command & 2) && + (scratch & 2) && + (mode & 2))) + command &= ~0x00000002; + + if (!((command & 1) && + (scratch & 1) && + (mode & 1))) + command &= ~0x00000001; + } + } + /* + * PASS2: Figure out the 4X/2X/1X setting and enable the + * target (our motherboard chipset). + */ + + if (command & 4) { + command &= ~3; /* 4X */ + } + if (command & 2) { + command &= ~5; /* 2X */ + } + if (command & 1) { + command &= ~6; /* 1X */ + } + command |= 0x00000100; + + pci_write_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 8, + command); + + /* + * PASS3: Go throu all AGP devices and update the + * command registers. + */ + + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); + if (cap_ptr != 0x00) + pci_write_config_dword(device, cap_ptr + 8, command); + } +} + +static int __init serverworks_setup (struct pci_dev *pdev) +{ + u32 temp; + u32 temp2; + + serverworks_private.svrwrks_dev = pdev; + + agp_bridge.masks = serverworks_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) serverworks_sizes; + agp_bridge.size_type = LVL2_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = (void *) &serverworks_private; + agp_bridge.needs_scratch_page = TRUE; + agp_bridge.configure = serverworks_configure; + agp_bridge.fetch_size = serverworks_fetch_size; + agp_bridge.cleanup = serverworks_cleanup; + agp_bridge.tlb_flush = serverworks_tlbflush; + agp_bridge.mask_memory = serverworks_mask_memory; + agp_bridge.agp_enable = serverworks_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = serverworks_create_gatt_table; + agp_bridge.free_gatt_table = serverworks_free_gatt_table; + agp_bridge.insert_memory = serverworks_insert_memory; + agp_bridge.remove_memory = serverworks_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + pci_read_config_dword(agp_bridge.dev, + SVWRKS_APSIZE, + &temp); + + serverworks_private.gart_addr_ofs = 0x10; + + if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(agp_bridge.dev, + SVWRKS_APSIZE + 4, + &temp2); + if(temp2 != 0) { + printk("Detected 64 bit aperture address, but top " + "bits are not zero. Disabling agp\n"); + return -ENODEV; + } + serverworks_private.mm_addr_ofs = 0x18; + } else { + serverworks_private.mm_addr_ofs = 0x14; + } + + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs, + &temp); + if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs + 4, + &temp2); + if(temp2 != 0) { + printk("Detected 64 bit MMIO address, but top " + "bits are not zero. Disabling agp\n"); + return -ENODEV; + } + } + + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-sis.c linux-2.5/drivers/char/agp/agpgart_be-sis.c --- linux-2.5.23/drivers/char/agp/agpgart_be-sis.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-sis.c Wed Jun 19 17:52:31 2002 @@ -0,0 +1,160 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +static int sis_fetch_size(void) +{ + u8 temp_size; + int i; + aper_size_info_8 *values; + + pci_read_config_byte(agp_bridge.dev, SIS_APSIZE, &temp_size); + values = A_SIZE_8(agp_bridge.aperture_sizes); + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if ((temp_size == values[i].size_value) || + ((temp_size & ~(0x03)) == + (values[i].size_value & ~(0x03)))) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + + +static void sis_tlbflush(agp_memory * mem) +{ + pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02); +} + +static int sis_configure(void) +{ + u32 temp; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + pci_write_config_byte(agp_bridge.dev, SIS_TLBCNTRL, 0x05); + pci_read_config_dword(agp_bridge.dev, SIS_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + pci_write_config_dword(agp_bridge.dev, SIS_ATTBASE, + agp_bridge.gatt_bus_addr); + pci_write_config_byte(agp_bridge.dev, SIS_APSIZE, + current_size->size_value); + return 0; +} + +static void sis_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_write_config_byte(agp_bridge.dev, SIS_APSIZE, + (previous_size->size_value & ~(0x03))); +} + +static unsigned long sis_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + +static aper_size_info_8 sis_generic_sizes[7] = +{ + {256, 65536, 6, 99}, + {128, 32768, 5, 83}, + {64, 16384, 4, 67}, + {32, 8192, 3, 51}, + {16, 4096, 2, 35}, + {8, 2048, 1, 19}, + {4, 1024, 0, 3} +}; + +static gatt_mask sis_generic_masks[] = +{ + {0x00000000, 0} +}; + +int __init sis_generic_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = sis_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) sis_generic_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = sis_configure; + agp_bridge.fetch_size = sis_fetch_size; + agp_bridge.cleanup = sis_cleanup; + agp_bridge.tlb_flush = sis_tlbflush; + agp_bridge.mask_memory = sis_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-sworks.c linux-2.5/drivers/char/agp/agpgart_be-sworks.c --- linux-2.5.23/drivers/char/agp/agpgart_be-sworks.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-sworks.c Wed Jun 19 17:34:21 2002 @@ -0,0 +1,644 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +typedef struct _serverworks_page_map { + unsigned long *real; + unsigned long *remapped; +} serverworks_page_map; + +static struct _serverworks_private { + struct pci_dev *svrwrks_dev; /* device one */ + volatile u8 *registers; + serverworks_page_map **gatt_pages; + int num_tables; + serverworks_page_map scratch_dir; + + int gart_addr_ofs; + int mm_addr_ofs; +} serverworks_private; + +static int serverworks_create_page_map(serverworks_page_map *page_map) +{ + int i; + + page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); + if (page_map->real == NULL) { + return -ENOMEM; + } + SetPageReserved(virt_to_page(page_map->real)); + CACHE_FLUSH(); + page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + PAGE_SIZE); + if (page_map->remapped == NULL) { + ClearPageReserved(virt_to_page(page_map->real)); + free_page((unsigned long) page_map->real); + page_map->real = NULL; + return -ENOMEM; + } + CACHE_FLUSH(); + + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { + page_map->remapped[i] = agp_bridge.scratch_page; + } + + return 0; +} + +static void serverworks_free_page_map(serverworks_page_map *page_map) +{ + iounmap(page_map->remapped); + ClearPageReserved(virt_to_page(page_map->real)); + free_page((unsigned long) page_map->real); +} + +static void serverworks_free_gatt_pages(void) +{ + int i; + serverworks_page_map **tables; + serverworks_page_map *entry; + + tables = serverworks_private.gatt_pages; + for(i = 0; i < serverworks_private.num_tables; i++) { + entry = tables[i]; + if (entry != NULL) { + if (entry->real != NULL) { + serverworks_free_page_map(entry); + } + kfree(entry); + } + } + kfree(tables); +} + +static int serverworks_create_gatt_pages(int nr_tables) +{ + serverworks_page_map **tables; + serverworks_page_map *entry; + int retval = 0; + int i; + + tables = kmalloc((nr_tables + 1) * sizeof(serverworks_page_map *), + GFP_KERNEL); + if (tables == NULL) { + return -ENOMEM; + } + memset(tables, 0, sizeof(serverworks_page_map *) * (nr_tables + 1)); + for (i = 0; i < nr_tables; i++) { + entry = kmalloc(sizeof(serverworks_page_map), GFP_KERNEL); + if (entry == NULL) { + retval = -ENOMEM; + break; + } + memset(entry, 0, sizeof(serverworks_page_map)); + tables[i] = entry; + retval = serverworks_create_page_map(entry); + if (retval != 0) break; + } + serverworks_private.num_tables = nr_tables; + serverworks_private.gatt_pages = tables; + + if (retval != 0) serverworks_free_gatt_pages(); + + return retval; +} + +#define SVRWRKS_GET_GATT(addr) (serverworks_private.gatt_pages[\ + GET_PAGE_DIR_IDX(addr)]->remapped) + +#ifndef GET_PAGE_DIR_OFF +#define GET_PAGE_DIR_OFF(addr) (addr >> 22) +#endif + +#ifndef GET_PAGE_DIR_IDX +#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ + GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) +#endif + +#ifndef GET_GATT_OFF +#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) +#endif + +static int serverworks_create_gatt_table(void) +{ + aper_size_info_lvl2 *value; + serverworks_page_map page_dir; + int retval; + u32 temp; + int i; + + value = A_SIZE_LVL2(agp_bridge.current_size); + retval = serverworks_create_page_map(&page_dir); + if (retval != 0) { + return retval; + } + retval = serverworks_create_page_map(&serverworks_private.scratch_dir); + if (retval != 0) { + serverworks_free_page_map(&page_dir); + return retval; + } + /* Create a fake scratch directory */ + for(i = 0; i < 1024; i++) { + serverworks_private.scratch_dir.remapped[i] = (unsigned long) agp_bridge.scratch_page; + page_dir.remapped[i] = + virt_to_phys(serverworks_private.scratch_dir.real); + page_dir.remapped[i] |= 0x00000001; + } + + retval = serverworks_create_gatt_pages(value->num_entries / 1024); + if (retval != 0) { + serverworks_free_page_map(&page_dir); + serverworks_free_page_map(&serverworks_private.scratch_dir); + return retval; + } + + agp_bridge.gatt_table_real = page_dir.real; + agp_bridge.gatt_table = page_dir.remapped; + agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real); + + /* Get the address for the gart region. + * This is a bus address even on the alpha, b/c its + * used to program the agp master not the cpu + */ + + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* Calculate the agp offset */ + + for(i = 0; i < value->num_entries / 1024; i++) { + page_dir.remapped[i] = + virt_to_phys(serverworks_private.gatt_pages[i]->real); + page_dir.remapped[i] |= 0x00000001; + } + + return 0; +} + +static int serverworks_free_gatt_table(void) +{ + serverworks_page_map page_dir; + + page_dir.real = agp_bridge.gatt_table_real; + page_dir.remapped = agp_bridge.gatt_table; + + serverworks_free_gatt_pages(); + serverworks_free_page_map(&page_dir); + serverworks_free_page_map(&serverworks_private.scratch_dir); + return 0; +} + +static int serverworks_fetch_size(void) +{ + int i; + u32 temp; + u32 temp2; + aper_size_info_lvl2 *values; + + values = A_SIZE_LVL2(agp_bridge.aperture_sizes); + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp); + pci_write_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + SVWRKS_SIZE_MASK); + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp2); + pci_write_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + temp); + temp2 &= SVWRKS_SIZE_MASK; + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp2 == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static int serverworks_configure(void) +{ + aper_size_info_lvl2 *current_size; + u32 temp; + u8 enable_reg; + u8 cap_ptr; + u32 cap_id; + u16 cap_reg; + + current_size = A_SIZE_LVL2(agp_bridge.current_size); + + /* Get the memory mapped registers */ + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs, + &temp); + temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); + serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096); + + OUTREG8(serverworks_private.registers, SVWRKS_GART_CACHE, 0x0a); + + OUTREG32(serverworks_private.registers, SVWRKS_GATTBASE, + agp_bridge.gatt_bus_addr); + + cap_reg = INREG16(serverworks_private.registers, SVWRKS_COMMAND); + cap_reg &= ~0x0007; + cap_reg |= 0x4; + OUTREG16(serverworks_private.registers, SVWRKS_COMMAND, cap_reg); + + pci_read_config_byte(serverworks_private.svrwrks_dev, + SVWRKS_AGP_ENABLE, &enable_reg); + enable_reg |= 0x1; /* Agp Enable bit */ + pci_write_config_byte(serverworks_private.svrwrks_dev, + SVWRKS_AGP_ENABLE, enable_reg); + agp_bridge.tlb_flush(NULL); + + pci_read_config_byte(serverworks_private.svrwrks_dev, 0x34, &cap_ptr); + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(serverworks_private.svrwrks_dev, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + agp_bridge.capndx = cap_ptr; + + /* Fill in the mode register */ + pci_read_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 4, + &agp_bridge.mode); + + pci_read_config_byte(agp_bridge.dev, + SVWRKS_CACHING, + &enable_reg); + enable_reg &= ~0x3; + pci_write_config_byte(agp_bridge.dev, + SVWRKS_CACHING, + enable_reg); + + pci_read_config_byte(agp_bridge.dev, + SVWRKS_FEATURE, + &enable_reg); + enable_reg |= (1<<6); + pci_write_config_byte(agp_bridge.dev, + SVWRKS_FEATURE, + enable_reg); + + return 0; +} + +static void serverworks_cleanup(void) +{ + iounmap((void *) serverworks_private.registers); +} + +/* + * This routine could be implemented by taking the addresses + * written to the GATT, and flushing them individually. However + * currently it just flushes the whole table. Which is probably + * more efficent, since agp_memory blocks can be a large number of + * entries. + */ + +static void serverworks_tlbflush(agp_memory * temp) +{ + unsigned long end; + + OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01); + end = jiffies + 3*HZ; + while(INREG8(serverworks_private.registers, + SVWRKS_POSTFLUSH) == 0x01) { + if((signed)(end - jiffies) <= 0) { + printk(KERN_ERR "Posted write buffer flush took more" + "then 3 seconds\n"); + } + } + OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001); + end = jiffies + 3*HZ; + while(INREG32(serverworks_private.registers, + SVWRKS_DIRFLUSH) == 0x00000001) { + if((signed)(end - jiffies) <= 0) { + printk(KERN_ERR "TLB flush took more" + "then 3 seconds\n"); + } + } +} + +static unsigned long serverworks_mask_memory(unsigned long addr, int type) +{ + /* Only type 0 is supported by the serverworks chipsets */ + + return addr | agp_bridge.masks[0].mask; +} + +static int serverworks_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + unsigned long *cur_gatt; + unsigned long addr; + + num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + mem->page_count)) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + } + agp_bridge.tlb_flush(mem); + return 0; +} + +static int serverworks_remove_memory(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + unsigned long *cur_gatt; + unsigned long addr; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = + (unsigned long) agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static gatt_mask serverworks_masks[] = +{ + {0x00000001, 0} +}; + +static aper_size_info_lvl2 serverworks_sizes[7] = +{ + {2048, 524288, 0x80000000}, + {1024, 262144, 0xc0000000}, + {512, 131072, 0xe0000000}, + {256, 65536, 0xf0000000}, + {128, 32768, 0xf8000000}, + {64, 16384, 0xfc000000}, + {32, 8192, 0xfe000000} +}; + +static void serverworks_agp_enable(u32 mode) +{ + struct pci_dev *device = NULL; + u32 command, scratch, cap_id; + u8 cap_ptr; + + pci_read_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 4, + &command); + + /* + * PASS1: go throu all devices that claim to be + * AGP devices and collect their data. + */ + + + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(device, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr != 0x00) { + /* + * Ok, here we have a AGP device. Disable impossible + * settings, and adjust the readqueue to the minimum. + */ + + pci_read_config_dword(device, cap_ptr + 4, &scratch); + + /* adjust RQ depth */ + command = + ((command & ~0xff000000) | + min_t(u32, (mode & 0xff000000), + min_t(u32, (command & 0xff000000), + (scratch & 0xff000000)))); + + /* disable SBA if it's not supported */ + if (!((command & 0x00000200) && + (scratch & 0x00000200) && + (mode & 0x00000200))) + command &= ~0x00000200; + + /* disable FW */ + command &= ~0x00000010; + + command &= ~0x00000008; + + if (!((command & 4) && + (scratch & 4) && + (mode & 4))) + command &= ~0x00000004; + + if (!((command & 2) && + (scratch & 2) && + (mode & 2))) + command &= ~0x00000002; + + if (!((command & 1) && + (scratch & 1) && + (mode & 1))) + command &= ~0x00000001; + } + } + /* + * PASS2: Figure out the 4X/2X/1X setting and enable the + * target (our motherboard chipset). + */ + + if (command & 4) { + command &= ~3; /* 4X */ + } + if (command & 2) { + command &= ~5; /* 2X */ + } + if (command & 1) { + command &= ~6; /* 1X */ + } + command |= 0x00000100; + + pci_write_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 8, + command); + + /* + * PASS3: Go throu all AGP devices and update the + * command registers. + */ + + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); + if (cap_ptr != 0x00) + pci_write_config_dword(device, cap_ptr + 8, command); + } +} + +int __init serverworks_setup (struct pci_dev *pdev) +{ + u32 temp; + u32 temp2; + + serverworks_private.svrwrks_dev = pdev; + + agp_bridge.masks = serverworks_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) serverworks_sizes; + agp_bridge.size_type = LVL2_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = (void *) &serverworks_private; + agp_bridge.needs_scratch_page = TRUE; + agp_bridge.configure = serverworks_configure; + agp_bridge.fetch_size = serverworks_fetch_size; + agp_bridge.cleanup = serverworks_cleanup; + agp_bridge.tlb_flush = serverworks_tlbflush; + agp_bridge.mask_memory = serverworks_mask_memory; + agp_bridge.agp_enable = serverworks_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = serverworks_create_gatt_table; + agp_bridge.free_gatt_table = serverworks_free_gatt_table; + agp_bridge.insert_memory = serverworks_insert_memory; + agp_bridge.remove_memory = serverworks_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + pci_read_config_dword(agp_bridge.dev, + SVWRKS_APSIZE, + &temp); + + serverworks_private.gart_addr_ofs = 0x10; + + if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(agp_bridge.dev, + SVWRKS_APSIZE + 4, + &temp2); + if(temp2 != 0) { + printk("Detected 64 bit aperture address, but top " + "bits are not zero. Disabling agp\n"); + return -ENODEV; + } + serverworks_private.mm_addr_ofs = 0x18; + } else { + serverworks_private.mm_addr_ofs = 0x14; + } + + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs, + &temp); + if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs + 4, + &temp2); + if(temp2 != 0) { + printk("Detected 64 bit MMIO address, but top " + "bits are not zero. Disabling agp\n"); + return -ENODEV; + } + } + + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be-via.c linux-2.5/drivers/char/agp/agpgart_be-via.c --- linux-2.5.23/drivers/char/agp/agpgart_be-via.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/agp/agpgart_be-via.c Wed Jun 19 17:22:56 2002 @@ -0,0 +1,168 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 + * JEFF HARTMANN, 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. + * + * TODO: + * - Allocate more than order 0 pages to avoid too much linear map splitting. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + + +static int via_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + values = A_SIZE_8(agp_bridge.aperture_sizes); + pci_read_config_byte(agp_bridge.dev, VIA_APSIZE, &temp); + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static int via_configure(void) +{ + u32 temp; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, + current_size->size_value); + /* address to map too */ + pci_read_config_dword(agp_bridge.dev, VIA_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* GART control register */ + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f); + + /* attbase - aperture GATT base */ + pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE, + (agp_bridge.gatt_bus_addr & 0xfffff000) | 3); + return 0; +} + +static void via_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, + previous_size->size_value); + /* Do not disable by writing 0 to VIA_ATTBASE, it screws things up + * during reinitialization. + */ +} + +static void via_tlbflush(agp_memory * mem) +{ + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000008f); + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f); +} + +static unsigned long via_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + +static aper_size_info_8 via_generic_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 128}, + {64, 16384, 4, 192}, + {32, 8192, 3, 224}, + {16, 4096, 2, 240}, + {8, 2048, 1, 248}, + {4, 1024, 0, 252} +}; + +static gatt_mask via_generic_masks[] = +{ + {0x00000000, 0} +}; + +int __init via_generic_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = via_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) via_generic_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = via_configure; + agp_bridge.fetch_size = via_fetch_size; + agp_bridge.cleanup = via_cleanup; + agp_bridge.tlb_flush = via_tlbflush; + agp_bridge.mask_memory = via_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/agp/agpgart_be.c linux-2.5/drivers/char/agp/agpgart_be.c --- linux-2.5.23/drivers/char/agp/agpgart_be.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/drivers/char/agp/agpgart_be.c Wed Jun 19 17:51:17 2002 @@ -62,29 +62,9 @@ EXPORT_SYMBOL(agp_backend_acquire); EXPORT_SYMBOL(agp_backend_release); -static struct agp_bridge_data agp_bridge; +struct agp_bridge_data agp_bridge; static int agp_try_unsupported __initdata = 0; -#ifdef CONFIG_SMP -static void ipi_handler(void *null) -{ - flush_agp_cache(); -} - -static void smp_flush_cache(void) -{ - if (smp_call_function(ipi_handler, NULL, 1, 1) != 0) - panic(PFX "timed out waiting for the other CPUs!\n"); - flush_agp_cache(); -} -#define global_cache_flush smp_flush_cache -#else /* CONFIG_SMP */ -static void global_cache_flush(void) -{ - flush_agp_cache(); -} -#endif /* !CONFIG_SMP */ - int agp_backend_acquire(void) { if (agp_bridge.type == NOT_SUPPORTED) { @@ -116,7 +96,7 @@ */ -static void agp_free_key(int key) +void agp_free_key(int key) { if (key < 0) { @@ -139,7 +119,7 @@ return -1; } -static agp_memory *agp_create_memory(int scratch_pages) +agp_memory *agp_create_memory(int scratch_pages) { agp_memory *new; @@ -369,7 +349,7 @@ /* Generic Agp routines - Start */ -static void agp_generic_agp_enable(u32 mode) +void agp_generic_agp_enable(u32 mode) { struct pci_dev *device = NULL; u32 command, scratch; @@ -462,7 +442,7 @@ } } -static int agp_generic_create_gatt_table(void) +int agp_generic_create_gatt_table(void) { char *table; char *table_end; @@ -581,17 +561,17 @@ return 0; } -static int agp_generic_suspend(void) +int agp_generic_suspend(void) { return 0; } -static void agp_generic_resume(void) +void agp_generic_resume(void) { return; } -static int agp_generic_free_gatt_table(void) +int agp_generic_free_gatt_table(void) { int page_order; char *table, *table_end; @@ -638,8 +618,7 @@ return 0; } -static int agp_generic_insert_memory(agp_memory * mem, - off_t pg_start, int type) +int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type) { int i, j, num_entries; void *temp; @@ -696,8 +675,7 @@ return 0; } -static int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, - int type) +int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, int type) { int i; @@ -714,12 +692,12 @@ return 0; } -static agp_memory *agp_generic_alloc_by_type(size_t page_count, int type) +agp_memory *agp_generic_alloc_by_type(size_t page_count, int type) { return NULL; } -static void agp_generic_free_by_type(agp_memory * curr) +void agp_generic_free_by_type(agp_memory * curr) { if (curr->memory != NULL) { vfree(curr->memory); @@ -737,7 +715,7 @@ * against a maximum value. */ -static void *agp_generic_alloc_page(void) +void *agp_generic_alloc_page(void) { struct page * page; @@ -753,7 +731,7 @@ return page_address(page); } -static void agp_generic_destroy_page(void *addr) +void agp_generic_destroy_page(void *addr) { struct page *page; @@ -778,3727 +756,184 @@ /* End - Generic Agp routines */ -#ifdef CONFIG_AGP_I810 -static aper_size_info_fixed intel_i810_sizes[] = -{ - {64, 16384, 4}, - /* The 32M mode still requires a 64k gatt */ - {32, 8192, 4} -}; - -#define AGP_DCACHE_MEMORY 1 -#define AGP_PHYS_MEMORY 2 - -static gatt_mask intel_i810_masks[] = -{ - {I810_PTE_VALID, 0}, - {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY}, - {I810_PTE_VALID, 0} -}; - -static struct _intel_i810_private { - struct pci_dev *i810_dev; /* device one */ - volatile u8 *registers; - int num_dcache_entries; -} intel_i810_private; - -static int intel_i810_fetch_size(void) -{ - u32 smram_miscc; - aper_size_info_fixed *values; - - pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc); - values = A_SIZE_FIX(agp_bridge.aperture_sizes); - - if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { - printk(KERN_WARNING PFX "i810 is disabled\n"); - return 0; - } - if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values + 1); - agp_bridge.aperture_size_idx = 1; - return values[1].size; - } else { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values); - agp_bridge.aperture_size_idx = 0; - return values[0].size; - } - - return 0; -} - -static int intel_i810_configure(void) -{ - aper_size_info_fixed *current_size; - u32 temp; - int i; - - current_size = A_SIZE_FIX(agp_bridge.current_size); - - pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); - temp &= 0xfff80000; - - intel_i810_private.registers = - (volatile u8 *) ioremap(temp, 128 * 4096); - - if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL) - & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { - /* This will need to be dynamically assigned */ - printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); - intel_i810_private.num_dcache_entries = 1024; - } - pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, - agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED); - CACHE_FLUSH(); - - if (agp_bridge.needs_scratch_page == TRUE) { - for (i = 0; i < current_size->num_entries; i++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - agp_bridge.scratch_page); - } - } - return 0; -} - -static void intel_i810_cleanup(void) -{ - OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0); - iounmap((void *) intel_i810_private.registers); -} - -static void intel_i810_tlbflush(agp_memory * mem) -{ - return; -} - -static void intel_i810_agp_enable(u32 mode) -{ - return; -} - -static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start, - int type) -{ - int i, j, num_entries; - void *temp; - - temp = agp_bridge.current_size; - num_entries = A_SIZE_FIX(temp)->num_entries; - - if ((pg_start + mem->page_count) > num_entries) { - return -EINVAL; - } - for (j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { - return -EBUSY; - } - } - - if (type != 0 || mem->type != 0) { - if ((type == AGP_DCACHE_MEMORY) && - (mem->type == AGP_DCACHE_MEMORY)) { - /* special insert */ - CACHE_FLUSH(); - for (i = pg_start; - i < (pg_start + mem->page_count); i++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - (i * 4096) | I810_PTE_LOCAL | - I810_PTE_VALID); - } - CACHE_FLUSH(); - agp_bridge.tlb_flush(mem); - return 0; - } - if((type == AGP_PHYS_MEMORY) && - (mem->type == AGP_PHYS_MEMORY)) { - goto insert; - } - return -EINVAL; - } -insert: - CACHE_FLUSH(); - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (j * 4), mem->memory[i]); - } - CACHE_FLUSH(); +/* per-chipset initialization data. + * note -- all chipsets for a single vendor MUST be grouped together + */ +static struct { + unsigned short device_id; /* first, to make table easier to read */ + unsigned short vendor_id; + enum chipset_type chipset; + const char *vendor_name; + const char *chipset_name; + int (*chipset_setup) (struct pci_dev *pdev); +} agp_bridge_info[] __initdata = { - agp_bridge.tlb_flush(mem); - return 0; -} +#ifdef CONFIG_AGP_ALI + { PCI_DEVICE_ID_AL_M1541_0, + PCI_VENDOR_ID_AL, + ALI_M1541, + "Ali", + "M1541", + ali_generic_setup }, + { PCI_DEVICE_ID_AL_M1621_0, + PCI_VENDOR_ID_AL, + ALI_M1621, + "Ali", + "M1621", + ali_generic_setup }, + { PCI_DEVICE_ID_AL_M1631_0, + PCI_VENDOR_ID_AL, + ALI_M1631, + "Ali", + "M1631", + ali_generic_setup }, + { PCI_DEVICE_ID_AL_M1632_0, + PCI_VENDOR_ID_AL, + ALI_M1632, + "Ali", + "M1632", + ali_generic_setup }, + { PCI_DEVICE_ID_AL_M1641_0, + PCI_VENDOR_ID_AL, + ALI_M1641, + "Ali", + "M1641", + ali_generic_setup }, + { PCI_DEVICE_ID_AL_M1644_0, + PCI_VENDOR_ID_AL, + ALI_M1644, + "Ali", + "M1644", + ali_generic_setup }, + { PCI_DEVICE_ID_AL_M1647_0, + PCI_VENDOR_ID_AL, + ALI_M1647, + "Ali", + "M1647", + ali_generic_setup }, + { PCI_DEVICE_ID_AL_M1651_0, + PCI_VENDOR_ID_AL, + ALI_M1651, + "Ali", + "M1651", + ali_generic_setup }, + { 0, + PCI_VENDOR_ID_AL, + ALI_GENERIC, + "Ali", + "Generic", + ali_generic_setup }, +#endif /* CONFIG_AGP_ALI */ -static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start, - int type) -{ - int i; +#ifdef CONFIG_AGP_AMD + { PCI_DEVICE_ID_AMD_IRONGATE_0, + PCI_VENDOR_ID_AMD, + AMD_IRONGATE, + "AMD", + "Irongate", + amd_irongate_setup }, + { PCI_DEVICE_ID_AMD_761_0, + PCI_VENDOR_ID_AMD, + AMD_761, + "AMD", + "761", + amd_irongate_setup }, + { PCI_DEVICE_ID_AMD_762_0, + PCI_VENDOR_ID_AMD, + AMD_762, + "AMD", + "760MP", + amd_irongate_setup }, + { 0, + PCI_VENDOR_ID_AMD, + AMD_GENERIC, + "AMD", + "Generic", + amd_irongate_setup }, +#endif /* CONFIG_AGP_AMD */ - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - agp_bridge.scratch_page); - } +#ifdef CONFIG_AGP_INTEL + { PCI_DEVICE_ID_INTEL_82443LX_0, + PCI_VENDOR_ID_INTEL, + INTEL_LX, + "Intel", + "440LX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_82443BX_0, + PCI_VENDOR_ID_INTEL, + INTEL_BX, + "Intel", + "440BX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_82443GX_0, + PCI_VENDOR_ID_INTEL, + INTEL_GX, + "Intel", + "440GX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_815_0, + PCI_VENDOR_ID_INTEL, + INTEL_I815, + "Intel", + "i815", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_820_0, + PCI_VENDOR_ID_INTEL, + INTEL_I820, + "Intel", + "i820", + intel_820_setup }, + { PCI_DEVICE_ID_INTEL_820_UP_0, + PCI_VENDOR_ID_INTEL, + INTEL_I820, + "Intel", + "i820", + intel_820_setup }, + { PCI_DEVICE_ID_INTEL_830_M_0, + PCI_VENDOR_ID_INTEL, + INTEL_I830_M, + "Intel", + "i830M", + intel_830mp_setup }, + { PCI_DEVICE_ID_INTEL_845_G_0, + PCI_VENDOR_ID_INTEL, + INTEL_I845_G, + "Intel", + "i845G", + intel_830mp_setup }, + { PCI_DEVICE_ID_INTEL_840_0, + PCI_VENDOR_ID_INTEL, + INTEL_I840, + "Intel", + "i840", + intel_840_setup }, + { PCI_DEVICE_ID_INTEL_845_0, + PCI_VENDOR_ID_INTEL, + INTEL_I845, + "Intel", + "i845", + intel_845_setup }, + { PCI_DEVICE_ID_INTEL_850_0, + PCI_VENDOR_ID_INTEL, + INTEL_I850, + "Intel", + "i850", +intel_850_setup }, + { PCI_DEVICE_ID_INTEL_860_0, + PCI_VENDOR_ID_INTEL, + INTEL_I860, + "Intel", + "i860", + intel_860_setup }, + { 0, + PCI_VENDOR_ID_INTEL, + INTEL_GENERIC, + "Intel", + "Generic", + intel_generic_setup }, - CACHE_FLUSH(); - agp_bridge.tlb_flush(mem); - return 0; -} - -static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) -{ - agp_memory *new; - - if (type == AGP_DCACHE_MEMORY) { - if (pg_count != intel_i810_private.num_dcache_entries) { - return NULL; - } - new = agp_create_memory(1); - - if (new == NULL) { - return NULL; - } - new->type = AGP_DCACHE_MEMORY; - new->page_count = pg_count; - new->num_scratch_pages = 0; - vfree(new->memory); - MOD_INC_USE_COUNT; - return new; - } - if(type == AGP_PHYS_MEMORY) { - void *addr; - /* The I810 requires a physical address to program - * it's mouse pointer into hardware. However the - * Xserver still writes to it through the agp - * aperture - */ - if (pg_count != 1) { - return NULL; - } - new = agp_create_memory(1); - - if (new == NULL) { - return NULL; - } - MOD_INC_USE_COUNT; - addr = agp_bridge.agp_alloc_page(); - - if (addr == NULL) { - /* Free this structure */ - agp_free_memory(new); - return NULL; - } - new->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr), type); - new->page_count = 1; - new->num_scratch_pages = 1; - new->type = AGP_PHYS_MEMORY; - new->physical = virt_to_phys((void *) new->memory[0]); - return new; - } - - return NULL; -} - -static void intel_i810_free_by_type(agp_memory * curr) -{ - agp_free_key(curr->key); - if(curr->type == AGP_PHYS_MEMORY) { - agp_bridge.agp_destroy_page( - phys_to_virt(curr->memory[0])); - vfree(curr->memory); - } - kfree(curr); - MOD_DEC_USE_COUNT; -} - -static unsigned long intel_i810_mask_memory(unsigned long addr, int type) -{ - /* Type checking must be done elsewhere */ - return addr | agp_bridge.masks[type].mask; -} - -static int __init intel_i810_setup(struct pci_dev *i810_dev) -{ - intel_i810_private.i810_dev = i810_dev; - - agp_bridge.masks = intel_i810_masks; - agp_bridge.num_of_masks = 2; - agp_bridge.aperture_sizes = (void *) intel_i810_sizes; - agp_bridge.size_type = FIXED_APER_SIZE; - agp_bridge.num_aperture_sizes = 2; - agp_bridge.dev_private_data = (void *) &intel_i810_private; - agp_bridge.needs_scratch_page = TRUE; - agp_bridge.configure = intel_i810_configure; - agp_bridge.fetch_size = intel_i810_fetch_size; - agp_bridge.cleanup = intel_i810_cleanup; - agp_bridge.tlb_flush = intel_i810_tlbflush; - agp_bridge.mask_memory = intel_i810_mask_memory; - agp_bridge.agp_enable = intel_i810_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = intel_i810_insert_entries; - agp_bridge.remove_memory = intel_i810_remove_entries; - agp_bridge.alloc_by_type = intel_i810_alloc_by_type; - agp_bridge.free_by_type = intel_i810_free_by_type; - agp_bridge.agp_alloc_page = agp_generic_alloc_page; - agp_bridge.agp_destroy_page = agp_generic_destroy_page; - agp_bridge.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; -} - -static aper_size_info_fixed intel_i830_sizes[] = -{ - {128, 32768, 5}, - /* The 64M mode still requires a 128k gatt */ - {64, 16384, 5} -}; - -static struct _intel_i830_private { - struct pci_dev *i830_dev; /* device one */ - volatile u8 *registers; - int gtt_entries; -} intel_i830_private; - -static void intel_i830_init_gtt_entries(void) { - u16 gmch_ctrl; - int gtt_entries; - u8 rdct; - static const int ddt[4] = { 0, 16, 32, 64 }; - - pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); - - switch (gmch_ctrl & I830_GMCH_GMS_MASK) { - case I830_GMCH_GMS_STOLEN_512: - gtt_entries = KB(512); - printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1)); - break; - case I830_GMCH_GMS_STOLEN_1024: - gtt_entries = MB(1); - printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1)); - break; - case I830_GMCH_GMS_STOLEN_8192: - gtt_entries = MB(8); - printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1)); - break; - case I830_GMCH_GMS_LOCAL: - rdct = INREG8(intel_i830_private.registers,I830_RDRAM_CHANNEL_TYPE); - gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); - printk(KERN_INFO PFX "detected %dK local memory.\n",gtt_entries / KB(1)); - break; - default: - printk(KERN_INFO PFX "no video memory detected.\n"); - gtt_entries = 0; - break; - } - - gtt_entries /= KB(4); - - intel_i830_private.gtt_entries = gtt_entries; -} - -/* The intel i830 automatically initializes the agp aperture during POST. - * Use the memory already set aside for in the GTT. - */ -static int intel_i830_create_gatt_table(void) -{ - int page_order; - aper_size_info_fixed *size; - int num_entries; - u32 temp; - - size = agp_bridge.current_size; - page_order = size->page_order; - num_entries = size->num_entries; - agp_bridge.gatt_table_real = 0; - - pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); - temp &= 0xfff80000; - - intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); - if (!intel_i830_private.registers) return (-ENOMEM); - - temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000; - CACHE_FLUSH(); - - /* we have to call this as early as possible after the MMIO base address is known */ - intel_i830_init_gtt_entries(); - - agp_bridge.gatt_table = NULL; - - agp_bridge.gatt_bus_addr = temp; - - return(0); -} - -/* Return the gatt table to a sane state. Use the top of stolen - * memory for the GTT. - */ -static int intel_i830_free_gatt_table(void) -{ - return(0); -} - -static int intel_i830_fetch_size(void) -{ - u16 gmch_ctrl; - aper_size_info_fixed *values; - - pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); - values = A_SIZE_FIX(agp_bridge.aperture_sizes); - - if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { - agp_bridge.previous_size = agp_bridge.current_size = (void *) values; - agp_bridge.aperture_size_idx = 0; - return(values[0].size); - } else { - agp_bridge.previous_size = agp_bridge.current_size = (void *) values; - agp_bridge.aperture_size_idx = 1; - return(values[1].size); - } - - return(0); -} - -static int intel_i830_configure(void) -{ - aper_size_info_fixed *current_size; - u32 temp; - u16 gmch_ctrl; - int i; - - current_size = A_SIZE_FIX(agp_bridge.current_size); - - pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); - gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(agp_bridge.dev,I830_GMCH_CTRL,gmch_ctrl); - - OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED); - CACHE_FLUSH(); - - if (agp_bridge.needs_scratch_page == TRUE) - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); - - return (0); -} - -static void intel_i830_cleanup(void) -{ - iounmap((void *) intel_i830_private.registers); -} - -static int intel_i830_insert_entries(agp_memory *mem,off_t pg_start,int type) -{ - int i,j,num_entries; - void *temp; - - temp = agp_bridge.current_size; - num_entries = A_SIZE_FIX(temp)->num_entries; - - if (pg_start < intel_i830_private.gtt_entries) { - printk (KERN_DEBUG "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n", - pg_start,intel_i830_private.gtt_entries); - - printk ("Trying to insert into local/stolen memory\n"); - return (-EINVAL); - } - - if ((pg_start + mem->page_count) > num_entries) - return (-EINVAL); - - /* The i830 can't check the GTT for entries since its read only, - * depend on the caller to make the correct offset decisions. - */ - - if ((type != 0 && type != AGP_PHYS_MEMORY) || - (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return (-EINVAL); - - CACHE_FLUSH(); - - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]); - - CACHE_FLUSH(); - - agp_bridge.tlb_flush(mem); - - return(0); -} - -static int intel_i830_remove_entries(agp_memory *mem,off_t pg_start,int type) -{ - int i; - - CACHE_FLUSH (); - - if (pg_start < intel_i830_private.gtt_entries) { - printk ("Trying to disable local/stolen memory\n"); - return (-EINVAL); - } - - for (i = pg_start; i < (mem->page_count + pg_start); i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); - - CACHE_FLUSH(); - - agp_bridge.tlb_flush(mem); - - return (0); -} - -static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) -{ - agp_memory *nw; - - /* always return NULL for now */ - if (type == AGP_DCACHE_MEMORY) return(NULL); - - if (type == AGP_PHYS_MEMORY) { - void *addr; - - /* The i830 requires a physical address to program - * it's mouse pointer into hardware. However the - * Xserver still writes to it through the agp - * aperture - */ - - if (pg_count != 1) return(NULL); - - nw = agp_create_memory(1); - - if (nw == NULL) return(NULL); - - MOD_INC_USE_COUNT; - addr = agp_bridge.agp_alloc_page(); - if (addr == NULL) { - /* free this structure */ - agp_free_memory(nw); - return(NULL); - } - - nw->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr),type); - nw->page_count = 1; - nw->num_scratch_pages = 1; - nw->type = AGP_PHYS_MEMORY; - nw->physical = virt_to_phys(addr); - return(nw); - } - - return(NULL); -} - -static int __init intel_i830_setup(struct pci_dev *i830_dev) -{ - intel_i830_private.i830_dev = i830_dev; - - agp_bridge.masks = intel_i810_masks; - agp_bridge.num_of_masks = 3; - agp_bridge.aperture_sizes = (void *) intel_i830_sizes; - agp_bridge.size_type = FIXED_APER_SIZE; - agp_bridge.num_aperture_sizes = 2; - - agp_bridge.dev_private_data = (void *) &intel_i830_private; - agp_bridge.needs_scratch_page = TRUE; - - agp_bridge.configure = intel_i830_configure; - agp_bridge.fetch_size = intel_i830_fetch_size; - agp_bridge.cleanup = intel_i830_cleanup; - agp_bridge.tlb_flush = intel_i810_tlbflush; - agp_bridge.mask_memory = intel_i810_mask_memory; - agp_bridge.agp_enable = intel_i810_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - - agp_bridge.create_gatt_table = intel_i830_create_gatt_table; - agp_bridge.free_gatt_table = intel_i830_free_gatt_table; - - agp_bridge.insert_memory = intel_i830_insert_entries; - agp_bridge.remove_memory = intel_i830_remove_entries; - agp_bridge.alloc_by_type = intel_i830_alloc_by_type; - agp_bridge.free_by_type = intel_i810_free_by_type; - agp_bridge.agp_alloc_page = agp_generic_alloc_page; - agp_bridge.agp_destroy_page = agp_generic_destroy_page; - - agp_bridge.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return(0); -} - -#endif /* CONFIG_AGP_I810 */ - -#ifdef CONFIG_AGP_I460 - -/* BIOS configures the chipset so that one of two apbase registers are used */ -static u8 intel_i460_dynamic_apbase = 0x10; - -/* 460 supports multiple GART page sizes, so GART pageshift is dynamic */ -static u8 intel_i460_pageshift = 12; -static u32 intel_i460_pagesize; - -/* Keep track of which is larger, chipset or kernel page size. */ -static u32 intel_i460_cpk = 1; - -/* Structure for tracking partial use of 4MB GART pages */ -static u32 **i460_pg_detail = NULL; -static u32 *i460_pg_count = NULL; - -#define I460_CPAGES_PER_KPAGE (PAGE_SIZE >> intel_i460_pageshift) -#define I460_KPAGES_PER_CPAGE ((1 << intel_i460_pageshift) >> PAGE_SHIFT) - -#define I460_SRAM_IO_DISABLE (1 << 4) -#define I460_BAPBASE_ENABLE (1 << 3) -#define I460_AGPSIZ_MASK 0x7 -#define I460_4M_PS (1 << 1) - -#define log2(x) ffz(~(x)) - -static inline void intel_i460_read_back (volatile u32 *entry) -{ - /* - * The 460 spec says we have to read the last location written to - * make sure that all writes have taken effect - */ - *entry; -} - -static int intel_i460_fetch_size(void) -{ - int i; - u8 temp; - aper_size_info_8 *values; - - /* Determine the GART page size */ - pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &temp); - intel_i460_pageshift = (temp & I460_4M_PS) ? 22 : 12; - intel_i460_pagesize = 1UL << intel_i460_pageshift; - - values = A_SIZE_8(agp_bridge.aperture_sizes); - - pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp); - - /* Exit now if the IO drivers for the GART SRAMS are turned off */ - if (temp & I460_SRAM_IO_DISABLE) { - printk(KERN_ERR PFX "GART SRAMS disabled on 460GX chipset\n"); - printk(KERN_ERR PFX "AGPGART operation not possible\n"); - return 0; - } - - /* Make sure we don't try to create an 2 ^ 23 entry GATT */ - if ((intel_i460_pageshift == 0) && ((temp & I460_AGPSIZ_MASK) == 4)) { - printk(KERN_ERR PFX "We can't have a 32GB aperture with 4KB GART pages\n"); - return 0; - } - - /* Determine the proper APBASE register */ - if (temp & I460_BAPBASE_ENABLE) - intel_i460_dynamic_apbase = INTEL_I460_BAPBASE; - else - intel_i460_dynamic_apbase = INTEL_I460_APBASE; - - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - /* - * Dynamically calculate the proper num_entries and page_order values for - * the define aperture sizes. Take care not to shift off the end of - * values[i].size. - */ - values[i].num_entries = (values[i].size << 8) >> (intel_i460_pageshift - 12); - values[i].page_order = log2((sizeof(u32)*values[i].num_entries) >> PAGE_SHIFT); - } - - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - /* Neglect control bits when matching up size_value */ - if ((temp & I460_AGPSIZ_MASK) == values[i].size_value) { - agp_bridge.previous_size = agp_bridge.current_size = (void *) (values + i); - agp_bridge.aperture_size_idx = i; - return values[i].size; - } - } - - return 0; -} - -/* There isn't anything to do here since 460 has no GART TLB. */ -static void intel_i460_tlb_flush(agp_memory * mem) -{ - return; -} - -/* - * This utility function is needed to prevent corruption of the control bits - * which are stored along with the aperture size in 460's AGPSIZ register - */ -static void intel_i460_write_agpsiz(u8 size_value) -{ - u8 temp; - - pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp); - pci_write_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, - ((temp & ~I460_AGPSIZ_MASK) | size_value)); -} - -static void intel_i460_cleanup(void) -{ - aper_size_info_8 *previous_size; - - previous_size = A_SIZE_8(agp_bridge.previous_size); - intel_i460_write_agpsiz(previous_size->size_value); - - if (intel_i460_cpk == 0) { - vfree(i460_pg_detail); - vfree(i460_pg_count); - } -} - - -/* Control bits for Out-Of-GART coherency and Burst Write Combining */ -#define I460_GXBCTL_OOG (1UL << 0) -#define I460_GXBCTL_BWC (1UL << 2) - -static int intel_i460_configure(void) -{ - union { - u32 small[2]; - u64 large; - } temp; - u8 scratch; - int i; - - aper_size_info_8 *current_size; - - temp.large = 0; - - current_size = A_SIZE_8(agp_bridge.current_size); - intel_i460_write_agpsiz(current_size->size_value); - - /* - * Do the necessary rigmarole to read all eight bytes of APBASE. - * This has to be done since the AGP aperture can be above 4GB on - * 460 based systems. - */ - pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase, &(temp.small[0])); - pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase + 4, &(temp.small[1])); - - /* Clear BAR control bits */ - agp_bridge.gart_bus_addr = temp.large & ~((1UL << 3) - 1); - - pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &scratch); - pci_write_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, - (scratch & 0x02) | I460_GXBCTL_OOG | I460_GXBCTL_BWC); - - /* - * Initialize partial allocation trackers if a GART page is bigger than - * a kernel page. - */ - if (I460_CPAGES_PER_KPAGE >= 1) { - intel_i460_cpk = 1; - } else { - intel_i460_cpk = 0; - - i460_pg_detail = vmalloc(sizeof(*i460_pg_detail) * current_size->num_entries); - i460_pg_count = vmalloc(sizeof(*i460_pg_count) * current_size->num_entries); - - for (i = 0; i < current_size->num_entries; i++) { - i460_pg_count[i] = 0; - i460_pg_detail[i] = NULL; - } - } - return 0; -} - -static int intel_i460_create_gatt_table(void) -{ - char *table; - int i; - int page_order; - int num_entries; - void *temp; - - /* - * Load up the fixed address of the GART SRAMS which hold our - * GATT table. - */ - table = (char *) __va(INTEL_I460_ATTBASE); - - temp = agp_bridge.current_size; - page_order = A_SIZE_8(temp)->page_order; - num_entries = A_SIZE_8(temp)->num_entries; - - agp_bridge.gatt_table_real = (u32 *) table; - agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table), - (PAGE_SIZE * (1 << page_order))); - agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real); - - for (i = 0; i < num_entries; i++) { - agp_bridge.gatt_table[i] = 0; - } - - intel_i460_read_back(agp_bridge.gatt_table + i - 1); - return 0; -} - -static int intel_i460_free_gatt_table(void) -{ - int num_entries; - int i; - void *temp; - - temp = agp_bridge.current_size; - - num_entries = A_SIZE_8(temp)->num_entries; - - for (i = 0; i < num_entries; i++) { - agp_bridge.gatt_table[i] = 0; - } - - intel_i460_read_back(agp_bridge.gatt_table + i - 1); - - iounmap(agp_bridge.gatt_table); - return 0; -} - -/* These functions are called when PAGE_SIZE exceeds the GART page size */ - -static int intel_i460_insert_memory_cpk(agp_memory * mem, off_t pg_start, int type) -{ - int i, j, k, num_entries; - void *temp; - unsigned long paddr; - - /* - * The rest of the kernel will compute page offsets in terms of - * PAGE_SIZE. - */ - pg_start = I460_CPAGES_PER_KPAGE * pg_start; - - temp = agp_bridge.current_size; - num_entries = A_SIZE_8(temp)->num_entries; - - if ((pg_start + I460_CPAGES_PER_KPAGE * mem->page_count) > num_entries) { - printk(KERN_ERR PFX "Looks like we're out of AGP memory\n"); - return -EINVAL; - } - - j = pg_start; - while (j < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count)) { - if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { - return -EBUSY; - } - j++; - } - -#if 0 - /* not necessary since 460 GART is operated in coherent mode... */ - if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); - mem->is_flushed = TRUE; - } -#endif - - for (i = 0, j = pg_start; i < mem->page_count; i++) { - paddr = mem->memory[i]; - for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, paddr += intel_i460_pagesize) - agp_bridge.gatt_table[j] = (u32) agp_bridge.mask_memory(paddr, mem->type); - } - - intel_i460_read_back(agp_bridge.gatt_table + j - 1); - return 0; -} - -static int intel_i460_remove_memory_cpk(agp_memory * mem, off_t pg_start, int type) -{ - int i; - - pg_start = I460_CPAGES_PER_KPAGE * pg_start; - - for (i = pg_start; i < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count); i++) - agp_bridge.gatt_table[i] = 0; - - intel_i460_read_back(agp_bridge.gatt_table + i - 1); - return 0; -} - -/* - * These functions are called when the GART page size exceeds PAGE_SIZE. - * - * This situation is interesting since AGP memory allocations that are - * smaller than a single GART page are possible. The structures i460_pg_count - * and i460_pg_detail track partial allocation of the large GART pages to - * work around this issue. - * - * i460_pg_count[pg_num] tracks the number of kernel pages in use within - * GART page pg_num. i460_pg_detail[pg_num] is an array containing a - * psuedo-GART entry for each of the aforementioned kernel pages. The whole - * of i460_pg_detail is equivalent to a giant GATT with page size equal to - * that of the kernel. - */ - -static void *intel_i460_alloc_large_page(int pg_num) -{ - int i; - void *bp, *bp_end; - struct page *page; - - i460_pg_detail[pg_num] = (void *) vmalloc(sizeof(u32) * I460_KPAGES_PER_CPAGE); - if (i460_pg_detail[pg_num] == NULL) { - printk(KERN_ERR PFX "Out of memory, we're in trouble...\n"); - return NULL; - } - - for (i = 0; i < I460_KPAGES_PER_CPAGE; i++) - i460_pg_detail[pg_num][i] = 0; - - bp = (void *) __get_free_pages(GFP_KERNEL, intel_i460_pageshift - PAGE_SHIFT); - if (bp == NULL) { - printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n"); - return NULL; - } - - bp_end = bp + ((PAGE_SIZE * (1 << (intel_i460_pageshift - PAGE_SHIFT))) - 1); - - for (page = virt_to_page(bp); page <= virt_to_page(bp_end); page++) { - atomic_inc(&agp_bridge.current_memory_agp); - } - return bp; -} - -static void intel_i460_free_large_page(int pg_num, unsigned long addr) -{ - struct page *page; - void *bp, *bp_end; - - bp = (void *) __va(addr); - bp_end = bp + (PAGE_SIZE * (1 << (intel_i460_pageshift - PAGE_SHIFT))); - - vfree(i460_pg_detail[pg_num]); - i460_pg_detail[pg_num] = NULL; - - for (page = virt_to_page(bp); page < virt_to_page(bp_end); page++) { - atomic_dec(&agp_bridge.current_memory_agp); - } - - free_pages((unsigned long) bp, intel_i460_pageshift - PAGE_SHIFT); -} - -static int intel_i460_insert_memory_kpc(agp_memory * mem, off_t pg_start, int type) -{ - int i, pg, start_pg, end_pg, start_offset, end_offset, idx; - int num_entries; - void *temp; - unsigned long paddr; - - temp = agp_bridge.current_size; - num_entries = A_SIZE_8(temp)->num_entries; - - /* Figure out what pg_start means in terms of our large GART pages */ - start_pg = pg_start / I460_KPAGES_PER_CPAGE; - start_offset = pg_start % I460_KPAGES_PER_CPAGE; - end_pg = (pg_start + mem->page_count - 1) / I460_KPAGES_PER_CPAGE; - end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_CPAGE; - - if (end_pg > num_entries) { - printk(KERN_ERR PFX "Looks like we're out of AGP memory\n"); - return -EINVAL; - } - - /* Check if the requested region of the aperture is free */ - for (pg = start_pg; pg <= end_pg; pg++) { - /* Allocate new GART pages if necessary */ - if (i460_pg_detail[pg] == NULL) { - temp = intel_i460_alloc_large_page(pg); - if (temp == NULL) - return -ENOMEM; - agp_bridge.gatt_table[pg] = agp_bridge.mask_memory((unsigned long) temp, - 0); - intel_i460_read_back(agp_bridge.gatt_table + pg); - } - - for (idx = ((pg == start_pg) ? start_offset : 0); - idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE); - idx++) - { - if (i460_pg_detail[pg][idx] != 0) - return -EBUSY; - } - } - -#if 0 - /* not necessary since 460 GART is operated in coherent mode... */ - if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); - mem->is_flushed = TRUE; - } -#endif - - for (pg = start_pg, i = 0; pg <= end_pg; pg++) { - paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]); - for (idx = ((pg == start_pg) ? start_offset : 0); - idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE); - idx++, i++) - { - mem->memory[i] = paddr + (idx * PAGE_SIZE); - i460_pg_detail[pg][idx] = agp_bridge.mask_memory(mem->memory[i], - mem->type); - i460_pg_count[pg]++; - } - } - - return 0; -} - -static int intel_i460_remove_memory_kpc(agp_memory * mem, off_t pg_start, int type) -{ - int i, pg, start_pg, end_pg, start_offset, end_offset, idx; - int num_entries; - void *temp; - unsigned long paddr; - - temp = agp_bridge.current_size; - num_entries = A_SIZE_8(temp)->num_entries; - - /* Figure out what pg_start means in terms of our large GART pages */ - start_pg = pg_start / I460_KPAGES_PER_CPAGE; - start_offset = pg_start % I460_KPAGES_PER_CPAGE; - end_pg = (pg_start + mem->page_count - 1) / I460_KPAGES_PER_CPAGE; - end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_CPAGE; - - for (i = 0, pg = start_pg; pg <= end_pg; pg++) { - for (idx = ((pg == start_pg) ? start_offset : 0); - idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE); - idx++, i++) - { - mem->memory[i] = 0; - i460_pg_detail[pg][idx] = 0; - i460_pg_count[pg]--; - } - - /* Free GART pages if they are unused */ - if (i460_pg_count[pg] == 0) { - paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]); - agp_bridge.gatt_table[pg] = agp_bridge.scratch_page; - intel_i460_read_back(agp_bridge.gatt_table + pg); - intel_i460_free_large_page(pg, paddr); - } - } - return 0; -} - -/* Dummy routines to call the approriate {cpk,kpc} function */ - -static int intel_i460_insert_memory(agp_memory * mem, off_t pg_start, int type) -{ - if (intel_i460_cpk) - return intel_i460_insert_memory_cpk(mem, pg_start, type); - else - return intel_i460_insert_memory_kpc(mem, pg_start, type); -} - -static int intel_i460_remove_memory(agp_memory * mem, off_t pg_start, int type) -{ - if (intel_i460_cpk) - return intel_i460_remove_memory_cpk(mem, pg_start, type); - else - return intel_i460_remove_memory_kpc(mem, pg_start, type); -} - -/* - * If the kernel page size is smaller that the chipset page size, we don't - * want to allocate memory until we know where it is to be bound in the - * aperture (a multi-kernel-page alloc might fit inside of an already - * allocated GART page). Consequently, don't allocate or free anything - * if i460_cpk (meaning chipset pages per kernel page) isn't set. - * - * Let's just hope nobody counts on the allocated AGP memory being there - * before bind time (I don't think current drivers do)... - */ -static void * intel_i460_alloc_page(void) -{ - if (intel_i460_cpk) - return agp_generic_alloc_page(); - - /* Returning NULL would cause problems */ - /* AK: really dubious code. */ - return (void *)~0UL; -} - -static void intel_i460_destroy_page(void *page) -{ - if (intel_i460_cpk) - agp_generic_destroy_page(page); -} - -static gatt_mask intel_i460_masks[] = -{ - { - INTEL_I460_GATT_VALID | INTEL_I460_GATT_COHERENT, - 0 - } -}; - -static unsigned long intel_i460_mask_memory(unsigned long addr, int type) -{ - /* Make sure the returned address is a valid GATT entry */ - return (agp_bridge.masks[0].mask - | (((addr & ~((1 << intel_i460_pageshift) - 1)) & 0xffffff000) >> 12)); -} - -static unsigned long intel_i460_unmask_memory(unsigned long addr) -{ - /* Turn a GATT entry into a physical address */ - return ((addr & 0xffffff) << 12); -} - -static aper_size_info_8 intel_i460_sizes[3] = -{ - /* - * The 32GB aperture is only available with a 4M GART page size. - * Due to the dynamic GART page size, we can't figure out page_order - * or num_entries until runtime. - */ - {32768, 0, 0, 4}, - {1024, 0, 0, 2}, - {256, 0, 0, 1} -}; - -static int __init intel_i460_setup (struct pci_dev *pdev __attribute__((unused))) -{ - agp_bridge.masks = intel_i460_masks; - agp_bridge.aperture_sizes = (void *) intel_i460_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 3; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = intel_i460_configure; - agp_bridge.fetch_size = intel_i460_fetch_size; - agp_bridge.cleanup = intel_i460_cleanup; - agp_bridge.tlb_flush = intel_i460_tlb_flush; - agp_bridge.mask_memory = intel_i460_mask_memory; - agp_bridge.unmask_memory = intel_i460_unmask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = intel_i460_create_gatt_table; - agp_bridge.free_gatt_table = intel_i460_free_gatt_table; - agp_bridge.insert_memory = intel_i460_insert_memory; - agp_bridge.remove_memory = intel_i460_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 = intel_i460_alloc_page; - agp_bridge.agp_destroy_page = intel_i460_destroy_page; - agp_bridge.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 1; - return 0; -} - -#endif /* CONFIG_AGP_I460 */ - -#ifdef CONFIG_AGP_INTEL - -static int intel_fetch_size(void) -{ - int i; - u16 temp; - aper_size_info_16 *values; - - pci_read_config_word(agp_bridge.dev, INTEL_APSIZE, &temp); - values = A_SIZE_16(agp_bridge.aperture_sizes); - - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - if (temp == values[i].size_value) { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values + i); - agp_bridge.aperture_size_idx = i; - return values[i].size; - } - } - - return 0; -} - - -static int intel_8xx_fetch_size(void) -{ - int i; - u8 temp; - aper_size_info_8 *values; - - pci_read_config_byte(agp_bridge.dev, INTEL_APSIZE, &temp); - values = A_SIZE_8(agp_bridge.aperture_sizes); - - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - if (temp == values[i].size_value) { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values + i); - agp_bridge.aperture_size_idx = i; - return values[i].size; - } - } - - return 0; -} - -static void intel_tlbflush(agp_memory * mem) -{ - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200); - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); -} - - -static void intel_8xx_tlbflush(agp_memory * mem) -{ - u32 temp; - pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp); - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp & ~(1 << 7)); - pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp); - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp | (1 << 7)); -} - - -static void intel_cleanup(void) -{ - u16 temp; - aper_size_info_16 *previous_size; - - previous_size = A_SIZE_16(agp_bridge.previous_size); - pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); - pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); - pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, - previous_size->size_value); -} - - -static void intel_8xx_cleanup(void) -{ - u16 temp; - aper_size_info_8 *previous_size; - - previous_size = A_SIZE_8(agp_bridge.previous_size); - pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); - pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); - pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - previous_size->size_value); -} - - -static int intel_configure(void) -{ - u32 temp; - u16 temp2; - aper_size_info_16 *current_size; - - current_size = A_SIZE_16(agp_bridge.current_size); - - /* aperture size */ - pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, - current_size->size_value); - - /* address to map to */ - pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* attbase - aperture base */ - pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, - agp_bridge.gatt_bus_addr); - - /* agpctrl */ - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); - - /* paccfg/nbxcfg */ - pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2); - pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, - (temp2 & ~(1 << 10)) | (1 << 9)); - /* clear any possible error conditions */ - pci_write_config_byte(agp_bridge.dev, INTEL_ERRSTS + 1, 7); - return 0; -} - -static void intel_820_tlbflush(agp_memory * mem) -{ - return; -} - -static void intel_820_cleanup(void) -{ - u8 temp; - aper_size_info_8 *previous_size; - - previous_size = A_SIZE_8(agp_bridge.previous_size); - pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp); - pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, - temp & ~(1 << 1)); - pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - previous_size->size_value); -} - - -static int intel_820_configure(void) -{ - u32 temp; - u8 temp2; - aper_size_info_8 *current_size; - - current_size = A_SIZE_8(agp_bridge.current_size); - - /* aperture size */ - pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - current_size->size_value); - - /* address to map to */ - pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* attbase - aperture base */ - pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, - agp_bridge.gatt_bus_addr); - - /* agpctrl */ - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); - - /* global enable aperture access */ - /* This flag is not accessed through MCHCFG register as in */ - /* i850 chipset. */ - pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp2); - pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, - temp2 | (1 << 1)); - /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge.dev, INTEL_I820_ERRSTS, 0x001c); - return 0; -} - -static int intel_840_configure(void) -{ - u32 temp; - u16 temp2; - aper_size_info_8 *current_size; - - current_size = A_SIZE_8(agp_bridge.current_size); - - /* aperture size */ - pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - current_size->size_value); - - /* address to map to */ - pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* attbase - aperture base */ - pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, - agp_bridge.gatt_bus_addr); - - /* agpctrl */ - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); - - /* mcgcfg */ - pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2); - pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, - temp2 | (1 << 9)); - /* clear any possible error conditions */ - pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000); - return 0; -} - -static int intel_845_configure(void) -{ - u32 temp; - u8 temp2; - aper_size_info_8 *current_size; - - current_size = A_SIZE_8(agp_bridge.current_size); - - /* aperture size */ - pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - current_size->size_value); - - /* address to map to */ - pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* attbase - aperture base */ - pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, - agp_bridge.gatt_bus_addr); - - /* agpctrl */ - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); - - /* agpm */ - pci_read_config_byte(agp_bridge.dev, INTEL_I845_AGPM, &temp2); - pci_write_config_byte(agp_bridge.dev, INTEL_I845_AGPM, - temp2 | (1 << 1)); - /* clear any possible error conditions */ - pci_write_config_word(agp_bridge.dev, INTEL_I845_ERRSTS, 0x001c); - return 0; -} - -static int intel_850_configure(void) -{ - u32 temp; - u16 temp2; - aper_size_info_8 *current_size; - - current_size = A_SIZE_8(agp_bridge.current_size); - - /* aperture size */ - pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - current_size->size_value); - - /* address to map to */ - pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* attbase - aperture base */ - pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, - agp_bridge.gatt_bus_addr); - - /* agpctrl */ - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); - - /* mcgcfg */ - pci_read_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, &temp2); - pci_write_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, - temp2 | (1 << 9)); - /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge.dev, INTEL_I850_ERRSTS, 0x001c); - return 0; -} - -static int intel_860_configure(void) -{ - u32 temp; - u16 temp2; - aper_size_info_8 *current_size; - - current_size = A_SIZE_8(agp_bridge.current_size); - - /* aperture size */ - pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - current_size->size_value); - - /* address to map to */ - pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* attbase - aperture base */ - pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, - agp_bridge.gatt_bus_addr); - - /* agpctrl */ - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); - - /* mcgcfg */ - pci_read_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, &temp2); - pci_write_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, - temp2 | (1 << 9)); - /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge.dev, INTEL_I860_ERRSTS, 0xf700); - return 0; -} - -static int intel_830mp_configure(void) -{ - u32 temp; - u16 temp2; - aper_size_info_8 *current_size; - - current_size = A_SIZE_8(agp_bridge.current_size); - - /* aperture size */ - pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - current_size->size_value); - - /* address to map to */ - pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* attbase - aperture base */ - pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, - agp_bridge.gatt_bus_addr); - - /* agpctrl */ - pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); - - /* gmch */ - pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2); - pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, - temp2 | (1 << 9)); - /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge.dev, INTEL_I830_ERRSTS, 0x1c); - return 0; -} - -static unsigned long intel_mask_memory(unsigned long addr, int type) -{ - /* Memory type is ignored */ - - return addr | agp_bridge.masks[0].mask; -} - -static void intel_resume(void) -{ - intel_configure(); -} - -/* Setup function */ -static gatt_mask intel_generic_masks[] = -{ - {0x00000017, 0} -}; - -static aper_size_info_8 intel_8xx_sizes[7] = -{ - {256, 65536, 6, 0}, - {128, 32768, 5, 32}, - {64, 16384, 4, 48}, - {32, 8192, 3, 56}, - {16, 4096, 2, 60}, - {8, 2048, 1, 62}, - {4, 1024, 0, 63} -}; - -static aper_size_info_16 intel_generic_sizes[7] = -{ - {256, 65536, 6, 0}, - {128, 32768, 5, 32}, - {64, 16384, 4, 48}, - {32, 8192, 3, 56}, - {16, 4096, 2, 60}, - {8, 2048, 1, 62}, - {4, 1024, 0, 63} -}; - -static aper_size_info_8 intel_830mp_sizes[4] = -{ - {256, 65536, 6, 0}, - {128, 32768, 5, 32}, - {64, 16384, 4, 48}, - {32, 8192, 3, 56} -}; - -static int __init intel_generic_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_generic_sizes; - agp_bridge.size_type = U16_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = intel_configure; - agp_bridge.fetch_size = intel_fetch_size; - agp_bridge.cleanup = intel_cleanup; - agp_bridge.tlb_flush = intel_tlbflush; - agp_bridge.mask_memory = intel_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = intel_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - - -static int __init intel_820_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = intel_820_configure; - agp_bridge.fetch_size = intel_8xx_fetch_size; - agp_bridge.cleanup = intel_820_cleanup; - agp_bridge.tlb_flush = intel_820_tlbflush; - agp_bridge.mask_memory = intel_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -static int __init intel_830mp_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_830mp_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 4; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = intel_830mp_configure; - agp_bridge.fetch_size = intel_8xx_fetch_size; - agp_bridge.cleanup = intel_8xx_cleanup; - agp_bridge.tlb_flush = intel_8xx_tlbflush; - agp_bridge.mask_memory = intel_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -static int __init intel_840_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = intel_840_configure; - agp_bridge.fetch_size = intel_8xx_fetch_size; - agp_bridge.cleanup = intel_8xx_cleanup; - agp_bridge.tlb_flush = intel_8xx_tlbflush; - agp_bridge.mask_memory = intel_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -static int __init intel_845_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = intel_845_configure; - agp_bridge.fetch_size = intel_8xx_fetch_size; - agp_bridge.cleanup = intel_8xx_cleanup; - agp_bridge.tlb_flush = intel_8xx_tlbflush; - agp_bridge.mask_memory = intel_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -static int __init intel_850_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = intel_850_configure; - agp_bridge.fetch_size = intel_8xx_fetch_size; - agp_bridge.cleanup = intel_8xx_cleanup; - agp_bridge.tlb_flush = intel_8xx_tlbflush; - agp_bridge.mask_memory = intel_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -static int __init intel_860_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = intel_860_configure; - agp_bridge.fetch_size = intel_8xx_fetch_size; - agp_bridge.cleanup = intel_8xx_cleanup; - agp_bridge.tlb_flush = intel_8xx_tlbflush; - agp_bridge.mask_memory = intel_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -#endif /* CONFIG_AGP_INTEL */ - -#ifdef CONFIG_AGP_VIA - -static int via_fetch_size(void) -{ - int i; - u8 temp; - aper_size_info_8 *values; - - values = A_SIZE_8(agp_bridge.aperture_sizes); - pci_read_config_byte(agp_bridge.dev, VIA_APSIZE, &temp); - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - if (temp == values[i].size_value) { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values + i); - agp_bridge.aperture_size_idx = i; - return values[i].size; - } - } - - return 0; -} - -static int via_configure(void) -{ - u32 temp; - aper_size_info_8 *current_size; - - current_size = A_SIZE_8(agp_bridge.current_size); - /* aperture size */ - pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, - current_size->size_value); - /* address to map too */ - pci_read_config_dword(agp_bridge.dev, VIA_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* GART control register */ - pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f); - - /* attbase - aperture GATT base */ - pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE, - (agp_bridge.gatt_bus_addr & 0xfffff000) | 3); - return 0; -} - -static void via_cleanup(void) -{ - aper_size_info_8 *previous_size; - - previous_size = A_SIZE_8(agp_bridge.previous_size); - pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, - previous_size->size_value); - /* Do not disable by writing 0 to VIA_ATTBASE, it screws things up - * during reinitialization. - */ -} - -static void via_tlbflush(agp_memory * mem) -{ - pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000008f); - pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f); -} - -static unsigned long via_mask_memory(unsigned long addr, int type) -{ - /* Memory type is ignored */ - - return addr | agp_bridge.masks[0].mask; -} - -static aper_size_info_8 via_generic_sizes[7] = -{ - {256, 65536, 6, 0}, - {128, 32768, 5, 128}, - {64, 16384, 4, 192}, - {32, 8192, 3, 224}, - {16, 4096, 2, 240}, - {8, 2048, 1, 248}, - {4, 1024, 0, 252} -}; - -static gatt_mask via_generic_masks[] = -{ - {0x00000000, 0} -}; - -static int __init via_generic_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = via_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) via_generic_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = via_configure; - agp_bridge.fetch_size = via_fetch_size; - agp_bridge.cleanup = via_cleanup; - agp_bridge.tlb_flush = via_tlbflush; - agp_bridge.mask_memory = via_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -#endif /* CONFIG_AGP_VIA */ - -#ifdef CONFIG_AGP_SIS - -static int sis_fetch_size(void) -{ - u8 temp_size; - int i; - aper_size_info_8 *values; - - pci_read_config_byte(agp_bridge.dev, SIS_APSIZE, &temp_size); - values = A_SIZE_8(agp_bridge.aperture_sizes); - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - if ((temp_size == values[i].size_value) || - ((temp_size & ~(0x03)) == - (values[i].size_value & ~(0x03)))) { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values + i); - - agp_bridge.aperture_size_idx = i; - return values[i].size; - } - } - - return 0; -} - - -static void sis_tlbflush(agp_memory * mem) -{ - pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02); -} - -static int sis_configure(void) -{ - u32 temp; - aper_size_info_8 *current_size; - - current_size = A_SIZE_8(agp_bridge.current_size); - pci_write_config_byte(agp_bridge.dev, SIS_TLBCNTRL, 0x05); - pci_read_config_dword(agp_bridge.dev, SIS_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - pci_write_config_dword(agp_bridge.dev, SIS_ATTBASE, - agp_bridge.gatt_bus_addr); - pci_write_config_byte(agp_bridge.dev, SIS_APSIZE, - current_size->size_value); - return 0; -} - -static void sis_cleanup(void) -{ - aper_size_info_8 *previous_size; - - previous_size = A_SIZE_8(agp_bridge.previous_size); - pci_write_config_byte(agp_bridge.dev, SIS_APSIZE, - (previous_size->size_value & ~(0x03))); -} - -static unsigned long sis_mask_memory(unsigned long addr, int type) -{ - /* Memory type is ignored */ - - return addr | agp_bridge.masks[0].mask; -} - -static aper_size_info_8 sis_generic_sizes[7] = -{ - {256, 65536, 6, 99}, - {128, 32768, 5, 83}, - {64, 16384, 4, 67}, - {32, 8192, 3, 51}, - {16, 4096, 2, 35}, - {8, 2048, 1, 19}, - {4, 1024, 0, 3} -}; - -static gatt_mask sis_generic_masks[] = -{ - {0x00000000, 0} -}; - -static int __init sis_generic_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = sis_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) sis_generic_sizes; - agp_bridge.size_type = U8_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = sis_configure; - agp_bridge.fetch_size = sis_fetch_size; - agp_bridge.cleanup = sis_cleanup; - agp_bridge.tlb_flush = sis_tlbflush; - agp_bridge.mask_memory = sis_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; -} - -#endif /* CONFIG_AGP_SIS */ - -#ifdef CONFIG_AGP_AMD - -typedef struct _amd_page_map { - unsigned long *real; - unsigned long *remapped; -} amd_page_map; - -static struct _amd_irongate_private { - volatile u8 *registers; - amd_page_map **gatt_pages; - int num_tables; -} amd_irongate_private; - -static int amd_create_page_map(amd_page_map *page_map) -{ - int i; - - page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); - if (page_map->real == NULL) { - return -ENOMEM; - } - SetPageReserved(virt_to_page(page_map->real)); - CACHE_FLUSH(); - page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), - PAGE_SIZE); - if (page_map->remapped == NULL) { - ClearPageReserved(virt_to_page(page_map->real)); - free_page((unsigned long) page_map->real); - page_map->real = NULL; - return -ENOMEM; - } - CACHE_FLUSH(); - - for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { - page_map->remapped[i] = agp_bridge.scratch_page; - } - - return 0; -} - -static void amd_free_page_map(amd_page_map *page_map) -{ - iounmap(page_map->remapped); - ClearPageReserved(virt_to_page(page_map->real)); - free_page((unsigned long) page_map->real); -} - -static void amd_free_gatt_pages(void) -{ - int i; - amd_page_map **tables; - amd_page_map *entry; - - tables = amd_irongate_private.gatt_pages; - for(i = 0; i < amd_irongate_private.num_tables; i++) { - entry = tables[i]; - if (entry != NULL) { - if (entry->real != NULL) { - amd_free_page_map(entry); - } - kfree(entry); - } - } - kfree(tables); -} - -static int amd_create_gatt_pages(int nr_tables) -{ - amd_page_map **tables; - amd_page_map *entry; - int retval = 0; - int i; - - tables = kmalloc((nr_tables + 1) * sizeof(amd_page_map *), - GFP_KERNEL); - if (tables == NULL) { - return -ENOMEM; - } - memset(tables, 0, sizeof(amd_page_map *) * (nr_tables + 1)); - for (i = 0; i < nr_tables; i++) { - entry = kmalloc(sizeof(amd_page_map), GFP_KERNEL); - if (entry == NULL) { - retval = -ENOMEM; - break; - } - memset(entry, 0, sizeof(amd_page_map)); - tables[i] = entry; - retval = amd_create_page_map(entry); - if (retval != 0) break; - } - amd_irongate_private.num_tables = nr_tables; - amd_irongate_private.gatt_pages = tables; - - if (retval != 0) amd_free_gatt_pages(); - - return retval; -} - -/* Since we don't need contigious memory we just try - * to get the gatt table once - */ - -#define GET_PAGE_DIR_OFF(addr) (addr >> 22) -#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ - GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) -#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) -#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\ - GET_PAGE_DIR_IDX(addr)]->remapped) - -static int amd_create_gatt_table(void) -{ - aper_size_info_lvl2 *value; - amd_page_map page_dir; - unsigned long addr; - int retval; - u32 temp; - int i; - - value = A_SIZE_LVL2(agp_bridge.current_size); - retval = amd_create_page_map(&page_dir); - if (retval != 0) { - return retval; - } - - retval = amd_create_gatt_pages(value->num_entries / 1024); - if (retval != 0) { - amd_free_page_map(&page_dir); - return retval; - } - - agp_bridge.gatt_table_real = page_dir.real; - agp_bridge.gatt_table = page_dir.remapped; - agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real); - - /* Get the address for the gart region. - * This is a bus address even on the alpha, b/c its - * used to program the agp master not the cpu - */ - - pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); - addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - agp_bridge.gart_bus_addr = addr; - - /* Calculate the agp offset */ - for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = - virt_to_phys(amd_irongate_private.gatt_pages[i]->real); - page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; - } - - return 0; -} - -static int amd_free_gatt_table(void) -{ - amd_page_map page_dir; - - page_dir.real = agp_bridge.gatt_table_real; - page_dir.remapped = agp_bridge.gatt_table; - - amd_free_gatt_pages(); - amd_free_page_map(&page_dir); - return 0; -} - -static int amd_irongate_fetch_size(void) -{ - int i; - u32 temp; - aper_size_info_lvl2 *values; - - pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); - temp = (temp & 0x0000000e); - values = A_SIZE_LVL2(agp_bridge.aperture_sizes); - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - if (temp == values[i].size_value) { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values + i); - - agp_bridge.aperture_size_idx = i; - return values[i].size; - } - } - - return 0; -} - -static int amd_irongate_configure(void) -{ - aper_size_info_lvl2 *current_size; - u32 temp; - u16 enable_reg; - - current_size = A_SIZE_LVL2(agp_bridge.current_size); - - /* Get the memory mapped registers */ - pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp); - temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); - amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096); - - /* Write out the address of the gatt table */ - OUTREG32(amd_irongate_private.registers, AMD_ATTBASE, - agp_bridge.gatt_bus_addr); - - /* Write the Sync register */ - pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); - - /* Set indexing mode */ - pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00); - - /* Write the enable register */ - enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); - enable_reg = (enable_reg | 0x0004); - OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); - - /* Write out the size register */ - pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); - temp = (((temp & ~(0x0000000e)) | current_size->size_value) - | 0x00000001); - pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp); - - /* Flush the tlb */ - OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); - - return 0; -} - -static void amd_irongate_cleanup(void) -{ - aper_size_info_lvl2 *previous_size; - u32 temp; - u16 enable_reg; - - previous_size = A_SIZE_LVL2(agp_bridge.previous_size); - - enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); - enable_reg = (enable_reg & ~(0x0004)); - OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); - - /* Write back the previous size and disable gart translation */ - pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); - temp = ((temp & ~(0x0000000f)) | previous_size->size_value); - pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp); - iounmap((void *) amd_irongate_private.registers); -} - -/* - * This routine could be implemented by taking the addresses - * written to the GATT, and flushing them individually. However - * currently it just flushes the whole table. Which is probably - * more efficent, since agp_memory blocks can be a large number of - * entries. - */ - -static void amd_irongate_tlbflush(agp_memory * temp) -{ - OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); -} - -static unsigned long amd_irongate_mask_memory(unsigned long addr, int type) -{ - /* Only type 0 is supported by the irongate */ - - return addr | agp_bridge.masks[0].mask; -} - -static int amd_insert_memory(agp_memory * mem, - off_t pg_start, int type) -{ - int i, j, num_entries; - unsigned long *cur_gatt; - unsigned long addr; - - num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; - - if (type != 0 || mem->type != 0) { - return -EINVAL; - } - if ((pg_start + mem->page_count) > num_entries) { - return -EINVAL; - } - - j = pg_start; - while (j < (pg_start + mem->page_count)) { - addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; - cur_gatt = GET_GATT(addr); - if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { - return -EBUSY; - } - j++; - } - - if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); - mem->is_flushed = TRUE; - } - - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; - cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; - } - agp_bridge.tlb_flush(mem); - return 0; -} - -static int amd_remove_memory(agp_memory * mem, off_t pg_start, - int type) -{ - int i; - unsigned long *cur_gatt; - unsigned long addr; - - if (type != 0 || mem->type != 0) { - return -EINVAL; - } - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; - cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - (unsigned long) agp_bridge.scratch_page; - } - - agp_bridge.tlb_flush(mem); - return 0; -} - -static aper_size_info_lvl2 amd_irongate_sizes[7] = -{ - {2048, 524288, 0x0000000c}, - {1024, 262144, 0x0000000a}, - {512, 131072, 0x00000008}, - {256, 65536, 0x00000006}, - {128, 32768, 0x00000004}, - {64, 16384, 0x00000002}, - {32, 8192, 0x00000000} -}; - -static gatt_mask amd_irongate_masks[] = -{ - {0x00000001, 0} -}; - -static int __init amd_irongate_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = amd_irongate_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; - agp_bridge.size_type = LVL2_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = (void *) &amd_irongate_private; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = amd_irongate_configure; - agp_bridge.fetch_size = amd_irongate_fetch_size; - agp_bridge.cleanup = amd_irongate_cleanup; - agp_bridge.tlb_flush = amd_irongate_tlbflush; - agp_bridge.mask_memory = amd_irongate_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = amd_create_gatt_table; - agp_bridge.free_gatt_table = amd_free_gatt_table; - agp_bridge.insert_memory = amd_insert_memory; - agp_bridge.remove_memory = amd_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -#endif /* CONFIG_AGP_AMD */ - -#ifdef CONFIG_AGP_ALI - -static int ali_fetch_size(void) -{ - int i; - u32 temp; - aper_size_info_32 *values; - - pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp); - temp &= ~(0xfffffff0); - values = A_SIZE_32(agp_bridge.aperture_sizes); - - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - if (temp == values[i].size_value) { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values + i); - agp_bridge.aperture_size_idx = i; - return values[i].size; - } - } - - return 0; -} - -static void ali_tlbflush(agp_memory * mem) -{ - u32 temp; - - pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); -// clear tag - pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL, - ((temp & 0xfffffff0) | 0x00000001|0x00000002)); -} - -static void ali_cleanup(void) -{ - aper_size_info_32 *previous_size; - u32 temp; - - previous_size = A_SIZE_32(agp_bridge.previous_size); - - pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); -// clear tag - pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL, - ((temp & 0xffffff00) | 0x00000001|0x00000002)); - - pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp); - pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, - ((temp & 0x00000ff0) | previous_size->size_value)); -} - -static int ali_configure(void) -{ - u32 temp; - aper_size_info_32 *current_size; - - current_size = A_SIZE_32(agp_bridge.current_size); - - /* aperture size and gatt addr */ - pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp); - temp = (((temp & 0x00000ff0) | (agp_bridge.gatt_bus_addr & 0xfffff000)) - | (current_size->size_value & 0xf)); - pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, temp); - - /* tlb control */ - - /* - * Question: Jeff, ALi's patch deletes this: - * - * pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); - * pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, - * ((temp & 0xffffff00) | 0x00000010)); - * - * and replaces it with the following, which seems to duplicate the - * next couple of lines below it. I suspect this was an oversight, - * but you might want to check up on this? - */ - - pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* address to map to */ - pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - -#if 0 - if (agp_bridge.type == ALI_M1541) { - u32 nlvm_addr = 0; - - switch (current_size->size_value) { - case 0: break; - case 1: nlvm_addr = 0x100000;break; - case 2: nlvm_addr = 0x200000;break; - case 3: nlvm_addr = 0x400000;break; - case 4: nlvm_addr = 0x800000;break; - case 6: nlvm_addr = 0x1000000;break; - case 7: nlvm_addr = 0x2000000;break; - case 8: nlvm_addr = 0x4000000;break; - case 9: nlvm_addr = 0x8000000;break; - case 10: nlvm_addr = 0x10000000;break; - default: break; - } - nlvm_addr--; - nlvm_addr&=0xfff00000; - - nlvm_addr+= agp_bridge.gart_bus_addr; - nlvm_addr|=(agp_bridge.gart_bus_addr>>12); - printk(KERN_INFO PFX "nlvm top &base = %8x\n",nlvm_addr); - } -#endif - - pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); - temp &= 0xffffff7f; //enable TLB - pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, temp); - - return 0; -} - -static unsigned long ali_mask_memory(unsigned long addr, int type) -{ - /* Memory type is ignored */ - - return addr | agp_bridge.masks[0].mask; -} - -static void ali_cache_flush(void) -{ - global_cache_flush(); - - if (agp_bridge.type == ALI_M1541) { - int i, page_count; - u32 temp; - - page_count = 1 << A_SIZE_32(agp_bridge.current_size)->page_order; - for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) { - pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp); - pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, - (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - (agp_bridge.gatt_bus_addr + i)) | - ALI_CACHE_FLUSH_EN)); - } - } -} - -static void *ali_alloc_page(void) -{ - void *adr = agp_generic_alloc_page(); - unsigned temp; - - if (adr == 0) - return 0; - - if (agp_bridge.type == ALI_M1541) { - pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp); - pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, - (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_phys(adr)) | - ALI_CACHE_FLUSH_EN )); - } - return adr; -} - -static void ali_destroy_page(void * addr) -{ - u32 temp; - - if (addr == NULL) - return; - - global_cache_flush(); - - if (agp_bridge.type == ALI_M1541) { - pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp); - pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, - (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_phys(addr)) | - ALI_CACHE_FLUSH_EN)); - } - - agp_generic_destroy_page(addr); -} - -/* Setup function */ -static gatt_mask ali_generic_masks[] = -{ - {0x00000000, 0} -}; - -static aper_size_info_32 ali_generic_sizes[7] = -{ - {256, 65536, 6, 10}, - {128, 32768, 5, 9}, - {64, 16384, 4, 8}, - {32, 8192, 3, 7}, - {16, 4096, 2, 6}, - {8, 2048, 1, 4}, - {4, 1024, 0, 3} -}; - -static int __init ali_generic_setup (struct pci_dev *pdev) -{ - agp_bridge.masks = ali_generic_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) ali_generic_sizes; - agp_bridge.size_type = U32_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = NULL; - agp_bridge.needs_scratch_page = FALSE; - agp_bridge.configure = ali_configure; - agp_bridge.fetch_size = ali_fetch_size; - agp_bridge.cleanup = ali_cleanup; - agp_bridge.tlb_flush = ali_tlbflush; - agp_bridge.mask_memory = ali_mask_memory; - agp_bridge.agp_enable = agp_generic_agp_enable; - agp_bridge.cache_flush = ali_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_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 = ali_alloc_page; - agp_bridge.agp_destroy_page = ali_destroy_page; - agp_bridge.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - return 0; - - (void) pdev; /* unused */ -} - -#endif /* CONFIG_AGP_ALI */ - -#ifdef CONFIG_AGP_SWORKS -typedef struct _serverworks_page_map { - unsigned long *real; - unsigned long *remapped; -} serverworks_page_map; - -static struct _serverworks_private { - struct pci_dev *svrwrks_dev; /* device one */ - volatile u8 *registers; - serverworks_page_map **gatt_pages; - int num_tables; - serverworks_page_map scratch_dir; - - int gart_addr_ofs; - int mm_addr_ofs; -} serverworks_private; - -static int serverworks_create_page_map(serverworks_page_map *page_map) -{ - int i; - - page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); - if (page_map->real == NULL) { - return -ENOMEM; - } - SetPageReserved(virt_to_page(page_map->real)); - CACHE_FLUSH(); - page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), - PAGE_SIZE); - if (page_map->remapped == NULL) { - ClearPageReserved(virt_to_page(page_map->real)); - free_page((unsigned long) page_map->real); - page_map->real = NULL; - return -ENOMEM; - } - CACHE_FLUSH(); - - for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { - page_map->remapped[i] = agp_bridge.scratch_page; - } - - return 0; -} - -static void serverworks_free_page_map(serverworks_page_map *page_map) -{ - iounmap(page_map->remapped); - ClearPageReserved(virt_to_page(page_map->real)); - free_page((unsigned long) page_map->real); -} - -static void serverworks_free_gatt_pages(void) -{ - int i; - serverworks_page_map **tables; - serverworks_page_map *entry; - - tables = serverworks_private.gatt_pages; - for(i = 0; i < serverworks_private.num_tables; i++) { - entry = tables[i]; - if (entry != NULL) { - if (entry->real != NULL) { - serverworks_free_page_map(entry); - } - kfree(entry); - } - } - kfree(tables); -} - -static int serverworks_create_gatt_pages(int nr_tables) -{ - serverworks_page_map **tables; - serverworks_page_map *entry; - int retval = 0; - int i; - - tables = kmalloc((nr_tables + 1) * sizeof(serverworks_page_map *), - GFP_KERNEL); - if (tables == NULL) { - return -ENOMEM; - } - memset(tables, 0, sizeof(serverworks_page_map *) * (nr_tables + 1)); - for (i = 0; i < nr_tables; i++) { - entry = kmalloc(sizeof(serverworks_page_map), GFP_KERNEL); - if (entry == NULL) { - retval = -ENOMEM; - break; - } - memset(entry, 0, sizeof(serverworks_page_map)); - tables[i] = entry; - retval = serverworks_create_page_map(entry); - if (retval != 0) break; - } - serverworks_private.num_tables = nr_tables; - serverworks_private.gatt_pages = tables; - - if (retval != 0) serverworks_free_gatt_pages(); - - return retval; -} - -#define SVRWRKS_GET_GATT(addr) (serverworks_private.gatt_pages[\ - GET_PAGE_DIR_IDX(addr)]->remapped) - -#ifndef GET_PAGE_DIR_OFF -#define GET_PAGE_DIR_OFF(addr) (addr >> 22) -#endif - -#ifndef GET_PAGE_DIR_IDX -#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ - GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) -#endif - -#ifndef GET_GATT_OFF -#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) -#endif - -static int serverworks_create_gatt_table(void) -{ - aper_size_info_lvl2 *value; - serverworks_page_map page_dir; - int retval; - u32 temp; - int i; - - value = A_SIZE_LVL2(agp_bridge.current_size); - retval = serverworks_create_page_map(&page_dir); - if (retval != 0) { - return retval; - } - retval = serverworks_create_page_map(&serverworks_private.scratch_dir); - if (retval != 0) { - serverworks_free_page_map(&page_dir); - return retval; - } - /* Create a fake scratch directory */ - for(i = 0; i < 1024; i++) { - serverworks_private.scratch_dir.remapped[i] = (unsigned long) agp_bridge.scratch_page; - page_dir.remapped[i] = - virt_to_phys(serverworks_private.scratch_dir.real); - page_dir.remapped[i] |= 0x00000001; - } - - retval = serverworks_create_gatt_pages(value->num_entries / 1024); - if (retval != 0) { - serverworks_free_page_map(&page_dir); - serverworks_free_page_map(&serverworks_private.scratch_dir); - return retval; - } - - agp_bridge.gatt_table_real = page_dir.real; - agp_bridge.gatt_table = page_dir.remapped; - agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real); - - /* Get the address for the gart region. - * This is a bus address even on the alpha, b/c its - * used to program the agp master not the cpu - */ - - pci_read_config_dword(agp_bridge.dev, - serverworks_private.gart_addr_ofs, - &temp); - agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* Calculate the agp offset */ - - for(i = 0; i < value->num_entries / 1024; i++) { - page_dir.remapped[i] = - virt_to_phys(serverworks_private.gatt_pages[i]->real); - page_dir.remapped[i] |= 0x00000001; - } - - return 0; -} - -static int serverworks_free_gatt_table(void) -{ - serverworks_page_map page_dir; - - page_dir.real = agp_bridge.gatt_table_real; - page_dir.remapped = agp_bridge.gatt_table; - - serverworks_free_gatt_pages(); - serverworks_free_page_map(&page_dir); - serverworks_free_page_map(&serverworks_private.scratch_dir); - return 0; -} - -static int serverworks_fetch_size(void) -{ - int i; - u32 temp; - u32 temp2; - aper_size_info_lvl2 *values; - - values = A_SIZE_LVL2(agp_bridge.aperture_sizes); - pci_read_config_dword(agp_bridge.dev, - serverworks_private.gart_addr_ofs, - &temp); - pci_write_config_dword(agp_bridge.dev, - serverworks_private.gart_addr_ofs, - SVWRKS_SIZE_MASK); - pci_read_config_dword(agp_bridge.dev, - serverworks_private.gart_addr_ofs, - &temp2); - pci_write_config_dword(agp_bridge.dev, - serverworks_private.gart_addr_ofs, - temp); - temp2 &= SVWRKS_SIZE_MASK; - - for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { - if (temp2 == values[i].size_value) { - agp_bridge.previous_size = - agp_bridge.current_size = (void *) (values + i); - - agp_bridge.aperture_size_idx = i; - return values[i].size; - } - } - - return 0; -} - -static int serverworks_configure(void) -{ - aper_size_info_lvl2 *current_size; - u32 temp; - u8 enable_reg; - u8 cap_ptr; - u32 cap_id; - u16 cap_reg; - - current_size = A_SIZE_LVL2(agp_bridge.current_size); - - /* Get the memory mapped registers */ - pci_read_config_dword(agp_bridge.dev, - serverworks_private.mm_addr_ofs, - &temp); - temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); - serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096); - - OUTREG8(serverworks_private.registers, SVWRKS_GART_CACHE, 0x0a); - - OUTREG32(serverworks_private.registers, SVWRKS_GATTBASE, - agp_bridge.gatt_bus_addr); - - cap_reg = INREG16(serverworks_private.registers, SVWRKS_COMMAND); - cap_reg &= ~0x0007; - cap_reg |= 0x4; - OUTREG16(serverworks_private.registers, SVWRKS_COMMAND, cap_reg); - - pci_read_config_byte(serverworks_private.svrwrks_dev, - SVWRKS_AGP_ENABLE, &enable_reg); - enable_reg |= 0x1; /* Agp Enable bit */ - pci_write_config_byte(serverworks_private.svrwrks_dev, - SVWRKS_AGP_ENABLE, enable_reg); - agp_bridge.tlb_flush(NULL); - - pci_read_config_byte(serverworks_private.svrwrks_dev, 0x34, &cap_ptr); - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(serverworks_private.svrwrks_dev, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } - agp_bridge.capndx = cap_ptr; - - /* Fill in the mode register */ - pci_read_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 4, - &agp_bridge.mode); - - pci_read_config_byte(agp_bridge.dev, - SVWRKS_CACHING, - &enable_reg); - enable_reg &= ~0x3; - pci_write_config_byte(agp_bridge.dev, - SVWRKS_CACHING, - enable_reg); - - pci_read_config_byte(agp_bridge.dev, - SVWRKS_FEATURE, - &enable_reg); - enable_reg |= (1<<6); - pci_write_config_byte(agp_bridge.dev, - SVWRKS_FEATURE, - enable_reg); - - return 0; -} - -static void serverworks_cleanup(void) -{ - iounmap((void *) serverworks_private.registers); -} - -/* - * This routine could be implemented by taking the addresses - * written to the GATT, and flushing them individually. However - * currently it just flushes the whole table. Which is probably - * more efficent, since agp_memory blocks can be a large number of - * entries. - */ - -static void serverworks_tlbflush(agp_memory * temp) -{ - unsigned long end; - - OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01); - end = jiffies + 3*HZ; - while(INREG8(serverworks_private.registers, - SVWRKS_POSTFLUSH) == 0x01) { - if((signed)(end - jiffies) <= 0) { - printk(KERN_ERR "Posted write buffer flush took more" - "then 3 seconds\n"); - } - } - OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001); - end = jiffies + 3*HZ; - while(INREG32(serverworks_private.registers, - SVWRKS_DIRFLUSH) == 0x00000001) { - if((signed)(end - jiffies) <= 0) { - printk(KERN_ERR "TLB flush took more" - "then 3 seconds\n"); - } - } -} - -static unsigned long serverworks_mask_memory(unsigned long addr, int type) -{ - /* Only type 0 is supported by the serverworks chipsets */ - - return addr | agp_bridge.masks[0].mask; -} - -static int serverworks_insert_memory(agp_memory * mem, - off_t pg_start, int type) -{ - int i, j, num_entries; - unsigned long *cur_gatt; - unsigned long addr; - - num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; - - if (type != 0 || mem->type != 0) { - return -EINVAL; - } - if ((pg_start + mem->page_count) > num_entries) { - return -EINVAL; - } - - j = pg_start; - while (j < (pg_start + mem->page_count)) { - addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; - cur_gatt = SVRWRKS_GET_GATT(addr); - if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { - return -EBUSY; - } - j++; - } - - if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); - mem->is_flushed = TRUE; - } - - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; - cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; - } - agp_bridge.tlb_flush(mem); - return 0; -} - -static int serverworks_remove_memory(agp_memory * mem, off_t pg_start, - int type) -{ - int i; - unsigned long *cur_gatt; - unsigned long addr; - - if (type != 0 || mem->type != 0) { - return -EINVAL; - } - - CACHE_FLUSH(); - agp_bridge.tlb_flush(mem); - - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; - cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = - (unsigned long) agp_bridge.scratch_page; - } - - agp_bridge.tlb_flush(mem); - return 0; -} - -static gatt_mask serverworks_masks[] = -{ - {0x00000001, 0} -}; - -static aper_size_info_lvl2 serverworks_sizes[7] = -{ - {2048, 524288, 0x80000000}, - {1024, 262144, 0xc0000000}, - {512, 131072, 0xe0000000}, - {256, 65536, 0xf0000000}, - {128, 32768, 0xf8000000}, - {64, 16384, 0xfc000000}, - {32, 8192, 0xfe000000} -}; - -static void serverworks_agp_enable(u32 mode) -{ - struct pci_dev *device = NULL; - u32 command, scratch, cap_id; - u8 cap_ptr; - - pci_read_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 4, - &command); - - /* - * PASS1: go throu all devices that claim to be - * AGP devices and collect their data. - */ - - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } - if (cap_ptr != 0x00) { - /* - * Ok, here we have a AGP device. Disable impossible - * settings, and adjust the readqueue to the minimum. - */ - - pci_read_config_dword(device, cap_ptr + 4, &scratch); - - /* adjust RQ depth */ - command = - ((command & ~0xff000000) | - min_t(u32, (mode & 0xff000000), - min_t(u32, (command & 0xff000000), - (scratch & 0xff000000)))); - - /* disable SBA if it's not supported */ - if (!((command & 0x00000200) && - (scratch & 0x00000200) && - (mode & 0x00000200))) - command &= ~0x00000200; - - /* disable FW */ - command &= ~0x00000010; - - command &= ~0x00000008; - - if (!((command & 4) && - (scratch & 4) && - (mode & 4))) - command &= ~0x00000004; - - if (!((command & 2) && - (scratch & 2) && - (mode & 2))) - command &= ~0x00000002; - - if (!((command & 1) && - (scratch & 1) && - (mode & 1))) - command &= ~0x00000001; - } - } - /* - * PASS2: Figure out the 4X/2X/1X setting and enable the - * target (our motherboard chipset). - */ - - if (command & 4) { - command &= ~3; /* 4X */ - } - if (command & 2) { - command &= ~5; /* 2X */ - } - if (command & 1) { - command &= ~6; /* 1X */ - } - command |= 0x00000100; - - pci_write_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 8, - command); - - /* - * PASS3: Go throu all AGP devices and update the - * command registers. - */ - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) - pci_write_config_dword(device, cap_ptr + 8, command); - } -} - -static int __init serverworks_setup (struct pci_dev *pdev) -{ - u32 temp; - u32 temp2; - - serverworks_private.svrwrks_dev = pdev; - - agp_bridge.masks = serverworks_masks; - agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) serverworks_sizes; - agp_bridge.size_type = LVL2_APER_SIZE; - agp_bridge.num_aperture_sizes = 7; - agp_bridge.dev_private_data = (void *) &serverworks_private; - agp_bridge.needs_scratch_page = TRUE; - agp_bridge.configure = serverworks_configure; - agp_bridge.fetch_size = serverworks_fetch_size; - agp_bridge.cleanup = serverworks_cleanup; - agp_bridge.tlb_flush = serverworks_tlbflush; - agp_bridge.mask_memory = serverworks_mask_memory; - agp_bridge.agp_enable = serverworks_agp_enable; - agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = serverworks_create_gatt_table; - agp_bridge.free_gatt_table = serverworks_free_gatt_table; - agp_bridge.insert_memory = serverworks_insert_memory; - agp_bridge.remove_memory = serverworks_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.suspend = agp_generic_suspend; - agp_bridge.resume = agp_generic_resume; - agp_bridge.cant_use_aperture = 0; - - pci_read_config_dword(agp_bridge.dev, - SVWRKS_APSIZE, - &temp); - - serverworks_private.gart_addr_ofs = 0x10; - - if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_read_config_dword(agp_bridge.dev, - SVWRKS_APSIZE + 4, - &temp2); - if(temp2 != 0) { - printk("Detected 64 bit aperture address, but top " - "bits are not zero. Disabling agp\n"); - return -ENODEV; - } - serverworks_private.mm_addr_ofs = 0x18; - } else { - serverworks_private.mm_addr_ofs = 0x14; - } - - pci_read_config_dword(agp_bridge.dev, - serverworks_private.mm_addr_ofs, - &temp); - if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_read_config_dword(agp_bridge.dev, - serverworks_private.mm_addr_ofs + 4, - &temp2); - if(temp2 != 0) { - printk("Detected 64 bit MMIO address, but top " - "bits are not zero. Disabling agp\n"); - return -ENODEV; - } - } - - return 0; -} - -#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 - */ -static struct { - unsigned short device_id; /* first, to make table easier to read */ - unsigned short vendor_id; - enum chipset_type chipset; - const char *vendor_name; - const char *chipset_name; - int (*chipset_setup) (struct pci_dev *pdev); -} agp_bridge_info[] __initdata = { - -#ifdef CONFIG_AGP_ALI - { PCI_DEVICE_ID_AL_M1541_0, - PCI_VENDOR_ID_AL, - ALI_M1541, - "Ali", - "M1541", - ali_generic_setup }, - { PCI_DEVICE_ID_AL_M1621_0, - PCI_VENDOR_ID_AL, - ALI_M1621, - "Ali", - "M1621", - ali_generic_setup }, - { PCI_DEVICE_ID_AL_M1631_0, - PCI_VENDOR_ID_AL, - ALI_M1631, - "Ali", - "M1631", - ali_generic_setup }, - { PCI_DEVICE_ID_AL_M1632_0, - PCI_VENDOR_ID_AL, - ALI_M1632, - "Ali", - "M1632", - ali_generic_setup }, - { PCI_DEVICE_ID_AL_M1641_0, - PCI_VENDOR_ID_AL, - ALI_M1641, - "Ali", - "M1641", - ali_generic_setup }, - { PCI_DEVICE_ID_AL_M1644_0, - PCI_VENDOR_ID_AL, - ALI_M1644, - "Ali", - "M1644", - ali_generic_setup }, - { PCI_DEVICE_ID_AL_M1647_0, - PCI_VENDOR_ID_AL, - ALI_M1647, - "Ali", - "M1647", - ali_generic_setup }, - { PCI_DEVICE_ID_AL_M1651_0, - PCI_VENDOR_ID_AL, - ALI_M1651, - "Ali", - "M1651", - ali_generic_setup }, - { 0, - PCI_VENDOR_ID_AL, - ALI_GENERIC, - "Ali", - "Generic", - ali_generic_setup }, -#endif /* CONFIG_AGP_ALI */ - -#ifdef CONFIG_AGP_AMD - { PCI_DEVICE_ID_AMD_IRONGATE_0, - PCI_VENDOR_ID_AMD, - AMD_IRONGATE, - "AMD", - "Irongate", - amd_irongate_setup }, - { PCI_DEVICE_ID_AMD_761_0, - PCI_VENDOR_ID_AMD, - AMD_761, - "AMD", - "761", - amd_irongate_setup }, - { PCI_DEVICE_ID_AMD_762_0, - PCI_VENDOR_ID_AMD, - AMD_762, - "AMD", - "760MP", - amd_irongate_setup }, - { 0, - PCI_VENDOR_ID_AMD, - AMD_GENERIC, - "AMD", - "Generic", - amd_irongate_setup }, -#endif /* CONFIG_AGP_AMD */ - -#ifdef CONFIG_AGP_INTEL - { PCI_DEVICE_ID_INTEL_82443LX_0, - PCI_VENDOR_ID_INTEL, - INTEL_LX, - "Intel", - "440LX", - intel_generic_setup }, - { PCI_DEVICE_ID_INTEL_82443BX_0, - PCI_VENDOR_ID_INTEL, - INTEL_BX, - "Intel", - "440BX", - intel_generic_setup }, - { PCI_DEVICE_ID_INTEL_82443GX_0, - PCI_VENDOR_ID_INTEL, - INTEL_GX, - "Intel", - "440GX", - intel_generic_setup }, - { PCI_DEVICE_ID_INTEL_815_0, - PCI_VENDOR_ID_INTEL, - INTEL_I815, - "Intel", - "i815", - intel_generic_setup }, - { PCI_DEVICE_ID_INTEL_820_0, - PCI_VENDOR_ID_INTEL, - INTEL_I820, - "Intel", - "i820", - intel_820_setup }, - { PCI_DEVICE_ID_INTEL_820_UP_0, - PCI_VENDOR_ID_INTEL, - INTEL_I820, - "Intel", - "i820", - intel_820_setup }, - { PCI_DEVICE_ID_INTEL_830_M_0, - PCI_VENDOR_ID_INTEL, - INTEL_I830_M, - "Intel", - "i830M", - intel_830mp_setup }, - { PCI_DEVICE_ID_INTEL_845_G_0, - PCI_VENDOR_ID_INTEL, - INTEL_I845_G, - "Intel", - "i845G", - intel_830mp_setup }, - { PCI_DEVICE_ID_INTEL_840_0, - PCI_VENDOR_ID_INTEL, - INTEL_I840, - "Intel", - "i840", - intel_840_setup }, - { PCI_DEVICE_ID_INTEL_845_0, - PCI_VENDOR_ID_INTEL, - INTEL_I845, - "Intel", - "i845", - intel_845_setup }, - { PCI_DEVICE_ID_INTEL_850_0, - PCI_VENDOR_ID_INTEL, - INTEL_I850, - "Intel", - "i850", -intel_850_setup }, - { PCI_DEVICE_ID_INTEL_860_0, - PCI_VENDOR_ID_INTEL, - INTEL_I860, - "Intel", - "i860", - intel_860_setup }, - { 0, - PCI_VENDOR_ID_INTEL, - INTEL_GENERIC, - "Intel", - "Generic", - intel_generic_setup }, - -#endif /* CONFIG_AGP_INTEL */ +#endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_SIS { PCI_DEVICE_ID_SI_740, @@ -4524,6 +959,12 @@ SIS_GENERIC, "SiS", "735", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_745, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "745", sis_generic_setup }, { PCI_DEVICE_ID_SI_730, PCI_VENDOR_ID_SI, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/alim7101_wdt.c linux-2.5/drivers/char/alim7101_wdt.c --- linux-2.5.23/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.23/drivers/char/amd768_rng.c linux-2.5/drivers/char/amd768_rng.c --- linux-2.5.23/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.23/drivers/char/amigamouse.c linux-2.5/drivers/char/amigamouse.c --- linux-2.5.23/drivers/char/amigamouse.c Wed Jun 19 03:11:55 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.23/drivers/char/amiserial.c linux-2.5/drivers/char/amiserial.c --- linux-2.5.23/drivers/char/amiserial.c Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/char/amiserial.c Wed Mar 27 13:07:16 2002 @@ -2143,7 +2143,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/atixlmouse.c linux-2.5/drivers/char/atixlmouse.c --- linux-2.5.23/drivers/char/atixlmouse.c Wed Jun 19 03:11:59 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.23/drivers/char/au1000_gpio.c linux-2.5/drivers/char/au1000_gpio.c --- linux-2.5.23/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.23/drivers/char/busmouse.c linux-2.5/drivers/char/busmouse.c --- linux-2.5.23/drivers/char/busmouse.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/char/busmouse.c Mon May 6 16:17:50 2002 @@ -157,9 +157,12 @@ struct busmouse_data *mse = (struct busmouse_data *)filp->private_data; int retval; + lock_kernel(); retval = fasync_helper(fd, filp, on, &mse->fasyncptr); if (retval < 0) + unlock_kernel(); return retval; + unlock_kernel(); return 0; } @@ -168,7 +171,6 @@ struct busmouse_data *mse = (struct busmouse_data *)file->private_data; int ret = 0; - lock_kernel(); busmouse_fasync(-1, file, 0); down(&mouse_sem); /* to protect mse->active */ @@ -179,7 +181,6 @@ __MOD_DEC_USE_COUNT(mse->ops->owner); mse->ready = 0; } - unlock_kernel(); up( &mouse_sem); return ret; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/console.c linux-2.5/drivers/char/console.c --- linux-2.5.23/drivers/char/console.c Wed Jun 19 03:11:58 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.23/drivers/char/console_macros.h linux-2.5/drivers/char/console_macros.h --- linux-2.5.23/drivers/char/console_macros.h Wed Jun 19 03:11:49 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.23/drivers/char/consolemap.c linux-2.5/drivers/char/consolemap.c --- linux-2.5.23/drivers/char/consolemap.c Wed Jun 19 03:11:49 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.23/drivers/char/decvte.c linux-2.5/drivers/char/decvte.c --- linux-2.5.23/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.23/drivers/char/drm/Config.help linux-2.5/drivers/char/drm/Config.help --- linux-2.5.23/drivers/char/drm/Config.help Wed Jun 19 03:11:54 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.23/drivers/char/drm/Config.in linux-2.5/drivers/char/drm/Config.in --- linux-2.5.23/drivers/char/drm/Config.in Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/char/drm/Config.in Sat May 25 19:52:00 2002 @@ -12,6 +12,7 @@ tristate ' ATI Rage 128' CONFIG_DRM_R128 dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP - dep_tristate ' Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP + dep_tristate ' Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP + dep_tristate ' SiS' CONFIG_DRM_SIS $CONFIG_AGP fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/dummy_keyb.c linux-2.5/drivers/char/dummy_keyb.c --- linux-2.5.23/drivers/char/dummy_keyb.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/dummy_keyb.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,60 @@ +/* + * linux/drivers/char/dummy_keyb.c + * + * Allows CONFIG_VT on hardware without keyboards. + * + * Copyright (C) 1999, 2001 Bradley D. LaRonde + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * What is this for? + * + * Not all systems have keyboards. Some don't even have a keyboard + * port. However, some of those systems have video support and can + * use the virtual terminal support for display. However, the virtual + * terminal code expects a keyboard of some kind. This driver keeps + * the virtual terminal code happy by providing it a "keyboard", albeit + * a very quiet one. + * + * If you want to use the virtual terminal support but your system + * does not support a keyboard, define CONFIG_DUMMY_KEYB along with + * CONFIG_VT. + * + */ +#include +#include +#include + +void kbd_leds(unsigned char leds) +{ +} + +int kbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + return (scancode == keycode) ? 0 : -EINVAL; +} + +int kbd_getkeycode(unsigned int scancode) +{ + return scancode; +} + +int kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + *keycode = scancode; + + return 1; +} + +char kbd_unexpected_up(unsigned char keycode) +{ + return 0x80; +} + +void __init kbd_init_hw(void) +{ + printk("Dummy keyboard driver installed.\n"); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/dz.h linux-2.5/drivers/char/dz.h --- linux-2.5.23/drivers/char/dz.h Wed Jun 19 03:11:49 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.23/drivers/char/ftape/lowlevel/fdc-io.c linux-2.5/drivers/char/ftape/lowlevel/fdc-io.c --- linux-2.5.23/drivers/char/ftape/lowlevel/fdc-io.c Wed Jun 19 03:11:50 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.23/drivers/char/ftape/lowlevel/ftape-calibr.c linux-2.5/drivers/char/ftape/lowlevel/ftape-calibr.c --- linux-2.5.23/drivers/char/ftape/lowlevel/ftape-calibr.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/char/ftape/lowlevel/ftape-calibr.c Tue Jun 4 15:21:35 2002 @@ -31,7 +31,10 @@ #include #if defined(__alpha__) # include -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__x86_64__) +# include +# include +#elif defined(__i386__) # include #endif #include @@ -45,10 +48,14 @@ # error Ftape is not implemented for this architecture! #endif -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) static unsigned long ps_per_cycle = 0; #endif +#if defined(__i386__) +extern spinlock_t i8253_lock; +#endif + /* * Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is * too slow for certain timeouts (and that clock doesn't even tick @@ -67,48 +74,58 @@ { #if defined(__alpha__) unsigned long r; - asm volatile ("rpcc %0" : "=r" (r)); return r; -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__x86_64__) + unsigned long r; + rdtscl(r); + return r; +#elif defined(__i386__) + +/* + * Note that there is some time between counter underflowing and jiffies + * increasing, so the code below won't always give correct output. + * -Vojtech + */ + unsigned long flags; __u16 lo; __u16 hi; - save_flags(flags); - cli(); + spin_lock_irqsave(&i8253_lock, flags); outb_p(0x00, 0x43); /* latch the count ASAP */ lo = inb_p(0x40); /* read the latched count */ lo |= inb(0x40) << 8; hi = jiffies; - restore_flags(flags); + spin_unlock_irqrestore(&i8253_lock, flags); + return ((hi + 1) * (unsigned int) LATCH) - lo; /* downcounter ! */ #endif } static unsigned int short_ftape_timestamp(void) { -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) return ftape_timestamp(); -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) unsigned int count; unsigned long flags; - - save_flags(flags); - cli(); + + spin_lock_irqsave(&i8253_lock, flags); outb_p(0x00, 0x43); /* latch the count ASAP */ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; - restore_flags(flags); + spin_unlock_irqrestore(&i8253_lock, flags); + return (LATCH - count); /* normal: downcounter */ #endif } static unsigned int diff(unsigned int t0, unsigned int t1) { -#if defined(__alpha__) - return (t1 <= t0) ? t1 + (1UL << 32) - t0 : t1 - t0; -#elif defined(__i386__) || defined(__x86_64__) +#if defined(__alpha__) || defined(__x86_64__) + return (t1 - t0); +#elif defined(__i386__) /* * This is tricky: to work for both short and full ftape_timestamps * we'll have to discriminate between these. @@ -122,9 +139,9 @@ static unsigned int usecs(unsigned int count) { -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) return (ps_per_cycle * count) / 1000000UL; -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100); #endif } @@ -153,49 +170,24 @@ save_flags(flags); cli(); t0 = short_ftape_timestamp(); - for (i = 0; i < 1000; ++i) { + for (i = 0; i < 1000; ++i) status = inb(fdc.msr); - } t1 = short_ftape_timestamp(); restore_flags(flags); + TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1)); TRACE_EXIT; } static void init_clock(void) { -#if defined(__i386__) || defined(__x86_64__) - unsigned int t; - int i; TRACE_FUN(ft_t_any); - /* Haven't studied on why, but there sometimes is a problem - * with the tick timer readout. The two bytes get swapped. - * This hack solves that problem by doing one extra input. - */ - for (i = 0; i < 1000; ++i) { - t = short_ftape_timestamp(); - if (t > LATCH) { - inb_p(0x40); /* get in sync again */ - TRACE(ft_t_warn, "clock counter fixed"); - break; - } - } +#if defined(__x86_64__) + ps_per_cycle = 1000000000UL / cpu_khz; #elif defined(__alpha__) -#if CONFIG_FT_ALPHA_CLOCK == 0 -#error You must define and set CONFIG_FT_ALPHA_CLOCK in 'make config' ! -#endif extern struct hwrpb_struct *hwrpb; - TRACE_FUN(ft_t_any); - - if (hwrpb->cycle_freq != 0) { - ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; - } else { - /* - * HELP: Linux 2.0.x doesn't set cycle_freq on my noname ! - */ - ps_per_cycle = (1000*1000*1000*1000UL) / CONFIG_FT_ALPHA_CLOCK; - } + ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; #endif TRACE_EXIT; } @@ -214,7 +206,7 @@ unsigned int tc = 0; unsigned int count; unsigned int time; -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) unsigned int old_tc = 0; unsigned int old_count = 1; unsigned int old_time = 1; @@ -257,15 +249,14 @@ tc = (1000 * time) / (count - 1); TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns", usecs(once), count - 1, usecs(multiple), tc); -#if defined(__alpha__) +#if defined(__alpha__) || defined(__x86_64__) /* * Increase the calibration count exponentially until the * calibration time exceeds 100 ms. */ - if (time >= 100*1000) { + if (time >= 100*1000) break; - } -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__i386__) /* * increase the count until the resulting time nears 2/HZ, * then the tc will drop sharply because we lose LATCH counts. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/ftape/zftape/zftape-init.c linux-2.5/drivers/char/ftape/zftape/zftape-init.c --- linux-2.5.23/drivers/char/ftape/zftape/zftape-init.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/char/ftape/zftape/zftape-init.c Fri May 10 16:35:15 2002 @@ -28,6 +28,7 @@ #include #include #include +#include #include #ifdef CONFIG_KMOD #include @@ -67,7 +68,7 @@ /* Local vars. */ -static int busy_flag; +static unsigned long busy_flag; static sigset_t orig_sigmask; @@ -203,6 +204,7 @@ static struct vm_operations_struct dummy = { NULL, }; vma->vm_ops = &dummy; #endif + vma->vm_flags &= ~VM_IO; } current->blocked = old_sigmask; /* restore mask */ TRACE_EXIT result; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/generic_serial.c linux-2.5/drivers/char/generic_serial.c --- linux-2.5.23/drivers/char/generic_serial.c Wed Jun 19 03:11:55 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.23/drivers/char/hcdp_serial.c linux-2.5/drivers/char/hcdp_serial.c --- linux-2.5.23/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.23/drivers/char/hvc_console.c linux-2.5/drivers/char/hvc_console.c --- linux-2.5.23/drivers/char/hvc_console.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/char/hvc_console.c Tue Jun 4 15:53:12 2002 @@ -209,7 +209,6 @@ int i; daemonize(); - reparent_to_init(); strcpy(current->comm, "khvcd"); sigfillset(¤t->blocked); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/indydog.c linux-2.5/drivers/char/indydog.c --- linux-2.5.23/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.23/drivers/char/ip2/i2cmd.c linux-2.5/drivers/char/ip2/i2cmd.c --- linux-2.5.23/drivers/char/ip2/i2cmd.c Wed Jun 19 03:11:52 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.23/drivers/char/ip2.c linux-2.5/drivers/char/ip2.c --- linux-2.5.23/drivers/char/ip2.c Wed Jun 19 03:11:54 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.23/drivers/char/keyboard.c linux-2.5/drivers/char/keyboard.c --- linux-2.5.23/drivers/char/keyboard.c Wed Jun 19 03:11:53 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.23/drivers/char/lcd.c linux-2.5/drivers/char/lcd.c --- linux-2.5.23/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.23/drivers/char/lcd.h linux-2.5/drivers/char/lcd.h --- linux-2.5.23/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.23/drivers/char/logibusmouse.c linux-2.5/drivers/char/logibusmouse.c --- linux-2.5.23/drivers/char/logibusmouse.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/char/logibusmouse.c Thu Jan 1 01:00:00 1970 @@ -1,165 +0,0 @@ -/* - * Logitech Bus Mouse Driver for Linux - * by James Banks - * - * Mods by Matthew Dillon - * calls verify_area() - * tracks better when X is busy or paging - * - * Heavily modified by David Giller - * changed from queue- to counter- driven - * hacked out a (probably incorrect) mouse_select - * - * Modified again by Nathan Laredo to interface with - * 0.96c-pl1 IRQ handling changes (13JUL92) - * didn't bother touching select code. - * - * Modified the select() code blindly to conform to the VFS - * requirements. 92.07.14 - Linus. Somebody should test it out. - * - * Modified by Johan Myreen to make room for other mice (9AUG92) - * removed assignment chr_fops[10] = &mouse_fops; see mouse.c - * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. - * renamed this file mouse.c => busmouse.c - * - * Minor addition by Cliff Matthews - * added fasync support - * - * Modularised 6-Sep-95 Philip Blundell - * - * Replaced dumb busy loop with udelay() 16 Nov 95 - * Nathan Laredo - * - * Track I/O ports with request_region(). 12 Dec 95 Philip Blundell - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "busmouse.h" - -static int msedev; -static int mouse_irq = MOUSE_IRQ; - -MODULE_PARM(mouse_irq, "i"); - -#ifndef MODULE - -static int __init bmouse_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - mouse_irq=ints[1]; - - return 1; -} - -__setup("logi_busmouse=", bmouse_setup); - -#endif /* !MODULE */ - -static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - char dx, dy; - unsigned char buttons; - - outb(MSE_READ_X_LOW, MSE_CONTROL_PORT); - dx = (inb(MSE_DATA_PORT) & 0xf); - outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT); - dx |= (inb(MSE_DATA_PORT) & 0xf) << 4; - outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT ); - dy = (inb(MSE_DATA_PORT) & 0xf); - outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT); - buttons = inb(MSE_DATA_PORT); - dy |= (buttons & 0xf) << 4; - buttons = ((buttons >> 5) & 0x07); - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); - MSE_INT_ON(); -} - -/* - * close access to the mouse - */ -static int close_mouse(struct inode * inode, struct file * file) -{ - MSE_INT_OFF(); - free_irq(mouse_irq, NULL); - return 0; -} - -/* - * open access to the mouse - */ - -static int open_mouse(struct inode * inode, struct file * file) -{ - if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL)) - return -EBUSY; - MSE_INT_ON(); - return 0; -} - -static struct busmouse busmouse = { - LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7 -}; - -static int __init logi_busmouse_init(void) -{ - if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse")) - return -EIO; - - outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT); - outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT); - udelay(100L); /* wait for reply from mouse */ - if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) { - release_region(LOGIBM_BASE, LOGIBM_EXTENT); - return -EIO; - } - - outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT); - MSE_INT_OFF(); - - msedev = register_busmouse(&busmouse); - if (msedev < 0) { - release_region(LOGIBM_BASE, LOGIBM_EXTENT); - printk(KERN_WARNING "Unable to register busmouse driver.\n"); - } - else - printk(KERN_INFO "Logitech busmouse installed.\n"); - - return msedev < 0 ? msedev : 0; -} - -static void __exit logi_busmouse_cleanup (void) -{ - unregister_busmouse(msedev); - release_region(LOGIBM_BASE, LOGIBM_EXTENT); -} - -module_init(logi_busmouse_init); -module_exit(logi_busmouse_cleanup); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/mem.c linux-2.5/drivers/char/mem.c --- linux-2.5.23/drivers/char/mem.c Wed Jun 19 03:11:55 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.23/drivers/char/misc.c linux-2.5/drivers/char/misc.c --- linux-2.5.23/drivers/char/misc.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/char/misc.c Fri May 3 03:49:06 2002 @@ -48,7 +48,6 @@ #include #include -#include #include #include "busmouse.h" @@ -76,6 +75,7 @@ extern int pmu_device_init(void); extern int tosh_init(void); extern int i8k_init(void); +extern int lcd_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) @@ -277,6 +277,9 @@ #endif #ifdef CONFIG_TOSHIBA tosh_init(); +#endif +#ifdef CONFIG_COBALT_LCD + lcd_init(); #endif #ifdef CONFIG_I8K i8k_init(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/mk712.c linux-2.5/drivers/char/mk712.c --- linux-2.5.23/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.23/drivers/char/msbusmouse.c linux-2.5/drivers/char/msbusmouse.c --- linux-2.5.23/drivers/char/msbusmouse.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/char/msbusmouse.c Thu Jan 1 01:00:00 1970 @@ -1,175 +0,0 @@ -/* - * Microsoft busmouse driver based on Logitech driver (see busmouse.c) - * - * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92) - * - * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net) - * 8/28/92 - * - * Microsoft Bus Mouse support folded into 0.97pl4 code - * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) - * Changes: Logitech and Microsoft support in the same kernel. - * Defined new constants in busmouse.h for MS mice. - * Added int mse_busmouse_type to distinguish busmouse types - * Added a couple of new functions to handle differences in using - * MS vs. Logitech (where the int variable wasn't appropriate). - * - * Modified by Peter Cervasio (address above) (26SEP92) - * Changes: Included code to (properly?) detect when a Microsoft mouse is - * really attached to the machine. Don't know what this does to - * Logitech bus mice, but all it does is read ports. - * - * Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de) - * Changes: Better interrupt-handler (like in busmouse.c). - * Some changes to reduce code-size. - * Changed detection code to use inb_p() instead of doing empty - * loops to delay i/o. - * - * Modularised 8-Sep-95 Philip Blundell - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - * - * version 0.3b - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "busmouse.h" - -static int msedev; -static int mouse_irq = MOUSE_IRQ; - -MODULE_PARM(mouse_irq, "i"); - -#ifndef MODULE - -static int __init msmouse_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - mouse_irq=ints[1]; - - return 1; -} - -__setup("msmouse=",msmouse_setup); - -#endif /* !MODULE */ - -static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - char dx, dy; - unsigned char buttons; - - outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); - outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT); - dx = inb(MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT); - dy = inb(MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT); - buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07; - - outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); - outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT); - - /* why did the original have: - * if (dx != 0 || dy != 0 || buttons != mouse.buttons || - * ((~buttons) & 0x07)) - * ^^^^^^^^^^^^^^^^^^^ this? - */ - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); -} - -static int release_mouse(struct inode * inode, struct file * file) -{ - MS_MSE_INT_OFF(); - free_irq(mouse_irq, NULL); - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL)) - return -EBUSY; - - outb(MS_MSE_START, MS_MSE_CONTROL_PORT); - MS_MSE_INT_ON(); - return 0; -} - -static struct busmouse msbusmouse = { - MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0 -}; - -static int __init ms_bus_mouse_init(void) -{ - int present = 0; - int mse_byte, i; - - if (check_region(MS_MSE_CONTROL_PORT, 0x04)) - return -ENODEV; - - if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) { - - mse_byte = inb_p(MS_MSE_SIGNATURE_PORT); - - for (i = 0; i < 4; i++) { - if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) { - if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte) - present = 1; - else - present = 0; - } else - present = 0; - } - } - if (present == 0) - return -EIO; - if (!request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse")) - return -EIO; - - MS_MSE_INT_OFF(); - msedev = register_busmouse(&msbusmouse); - if (msedev < 0) { - printk(KERN_WARNING "Unable to register msbusmouse driver.\n"); - release_region(MS_MSE_CONTROL_PORT, 0x04); - } - else - printk(KERN_INFO "Microsoft BusMouse detected and installed.\n"); - return msedev < 0 ? msedev : 0; -} - -static void __exit ms_bus_mouse_exit(void) -{ - unregister_busmouse(msedev); - release_region(MS_MSE_CONTROL_PORT, 0x04); -} - -module_init(ms_bus_mouse_init) -module_exit(ms_bus_mouse_exit) - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/n_tty.c linux-2.5/drivers/char/n_tty.c --- linux-2.5.23/drivers/char/n_tty.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/char/n_tty.c Fri Jun 7 02:36:08 2002 @@ -23,6 +23,11 @@ * 2000/01/20 Fixed SMP locking on put_tty_queue using bits of * the patch by Andrew J. Kroll * who actually finally proved there really was a race. + * + * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to + * waiting writing processes-Sapan Bhatia . + * Also fixed a bug in BLOCKING mode where write_chan returns + * EAGAIN */ #include @@ -711,6 +716,22 @@ return 0; } +/* + * Required for the ptys, serial driver etc. since processes + * that attach themselves to the master and rely on ASYNC + * IO must be woken up + */ + +static void n_tty_write_wakeup(struct tty_struct *tty) +{ + if (tty->fasync) + { + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + kill_fasync(&tty->fasync, SIGIO, POLL_OUT); + } + return; +} + static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { @@ -1157,6 +1178,8 @@ while (nr > 0) { ssize_t num = opost_block(tty, b, nr); if (num < 0) { + if (num == -EAGAIN) + break; retval = num; goto break_out; } @@ -1236,6 +1259,6 @@ normal_poll, /* poll */ n_tty_receive_buf, /* receive_buf */ n_tty_receive_room, /* receive_room */ - 0 /* write_wakeup */ + n_tty_write_wakeup /* write_wakeup */ }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/nvram.c linux-2.5/drivers/char/nvram.c --- linux-2.5.23/drivers/char/nvram.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/char/nvram.c Sat May 25 19:52:01 2002 @@ -214,7 +214,7 @@ * The are the file operation function for user access to /dev/nvram */ -static long long nvram_llseek(struct file *file,loff_t offset, int origin ) +static loff_t nvram_llseek(struct file *file,loff_t offset, int origin ) { lock_kernel(); switch( origin ) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/nwflash.c linux-2.5/drivers/char/nwflash.c --- linux-2.5.23/drivers/char/nwflash.c Wed Jun 19 03:11:55 2002 +++ linux-2.5/drivers/char/nwflash.c Sat May 25 19:52:01 2002 @@ -47,7 +47,7 @@ static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg); static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos); static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos); -static long long flash_llseek(struct file *file, long long offset, int orig); +static loff_t flash_llseek(struct file *file, loff_t offset, int orig); #define KFLASH_SIZE 1024*1024 //1 Meg #define KFLASH_SIZE4 4*1024*1024 //4 Meg @@ -301,9 +301,9 @@ * also note that seeking relative to the "end of file" isn't supported: * it has no meaning, so it returns -EINVAL. */ -static long long flash_llseek(struct file *file, long long offset, int orig) +static loff_t flash_llseek(struct file *file, loff_t offset, int orig) { - long long ret; + loff_t ret; lock_kernel(); if (flashdebug) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/pc110pad.c linux-2.5/drivers/char/pc110pad.c --- linux-2.5.23/drivers/char/pc110pad.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/char/pc110pad.c Thu Jan 1 01:00:00 1970 @@ -1,851 +0,0 @@ -/* - * Linux driver for the PC110 pad - */ - -/** - * DOC: PC110 Digitizer Hardware - * - * The pad provides triples of data. The first byte has - * 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down - * The second byte is bits 0-6 X - * The third is bits 0-6 Y - * - * This is read internally and used to synthesize a stream of - * triples in the form expected from a PS/2 device. Specialist - * applications can choose to obtain the pad data in other formats - * including a debugging mode. - * - * It would be good to add a joystick driver mode to this pad so - * that doom and other game playing are better. One possible approach - * would be to deactive the mouse mode while the joystick port is opened. - */ - -/* - * History - * - * 0.0 1997-05-16 Alan Cox - Pad reader - * 0.1 1997-05-19 Robin O'Leary - PS/2 emulation - * 0.2 1997-06-03 Robin O'Leary - tap gesture - * 0.3 1997-06-27 Alan Cox - 2.1 commit - * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes - * 0.5 2000-02-10 Alan Cox - 2.3.x cleanup, documentation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "pc110pad.h" - - -static struct pc110pad_params default_params = { - mode: PC110PAD_PS2, - bounce_interval: 50 MS, - tap_interval: 200 MS, - irq: 10, - io: 0x15E0, -}; - -static struct pc110pad_params current_params; - - -/* driver/filesystem interface management */ -static wait_queue_head_t queue; -static struct fasync_struct *asyncptr; -static int active_count = 0; /* number of concurrent open()s */ -static spinlock_t pc110_lock = SPIN_LOCK_UNLOCKED; -/* this lock should be held when referencing active_count */ -static struct semaphore reader_lock; - -/** - * wake_readers: - * - * Take care of letting any waiting processes know that - * now would be a good time to do a read(). Called - * whenever a state transition occurs, real or synthetic. Also - * issue any SIGIO's to programs that use SIGIO on mice (eg - * Executor) - */ - -static void wake_readers(void) -{ - wake_up_interruptible(&queue); - kill_fasync(&asyncptr, SIGIO, POLL_IN); -} - - -/*****************************************************************************/ -/* - * Deal with the messy business of synthesizing button tap and drag - * events. - * - * Exports: - * notify_pad_up_down() - * Must be called whenever debounced pad up/down state changes. - * button_pending - * Flag is set whenever read_button() has new values - * to return. - * read_button() - * Obtains the current synthetic mouse button state. - */ - -/* - * These keep track of up/down transitions needed to generate the - * synthetic mouse button events. While recent_transition is set, - * up/down events cause transition_count to increment. tap_timer - * turns off the recent_transition flag and may cause some synthetic - * up/down mouse events to be created by incrementing synthesize_tap. - */ - -static int button_pending; -static int recent_transition; -static int transition_count; -static int synthesize_tap; -static void tap_timeout(unsigned long data); -static struct timer_list tap_timer = { function: tap_timeout }; - - -/** - * tap_timeout: - * @data: Unused - * - * This callback goes off a short time after an up/down transition; - * before it goes off, transitions will be considered part of a - * single PS/2 event and counted in transition_count. Once the - * timeout occurs the recent_transition flag is cleared and - * any synthetic mouse up/down events are generated. - */ - -static void tap_timeout(unsigned long data) -{ - if(!recent_transition) - { - printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!\n"); - } - if( transition_count==2 || transition_count==4 || transition_count==6 ) - { - synthesize_tap+=transition_count; - button_pending = 1; - wake_readers(); - } - recent_transition=0; -} - - -/** - * notify_pad_up_down: - * - * Called by the raw pad read routines when a (debounced) up/down - * transition is detected. - */ - -void notify_pad_up_down(void) -{ - if(recent_transition) - { - transition_count++; - } - else - { - transition_count=1; - recent_transition=1; - } - mod_timer(&tap_timer, jiffies + current_params.tap_interval); - - /* changes to transition_count can cause reported button to change */ - button_pending = 1; - wake_readers(); -} - -/** - * read_button: - * @b: pointer to the button status. - * - * The actual button state depends on what we are seeing. We have to check - * for the tap gesture and also for dragging. - */ - -static void read_button(int *b) -{ - if(synthesize_tap) - { - *b=--synthesize_tap & 1; - } - else - { - *b=(!recent_transition && transition_count==3); /* drag */ - } - button_pending=(synthesize_tap>0); -} - - -/*****************************************************************************/ -/* - * Read pad absolute co-ordinates and debounced up/down state. - * - * Exports: - * pad_irq() - * Function to be called whenever the pad signals - * that it has new data available. - * read_raw_pad() - * Returns the most current pad state. - * xy_pending - * Flag is set whenever read_raw_pad() has new values - * to return. - * Imports: - * wake_readers() - * Called when movement occurs. - * notify_pad_up_down() - * Called when debounced up/down status changes. - */ - -/* - * These are up/down state and absolute co-ords read directly from pad - */ - -static int raw_data[3]; -static int raw_data_count; -static int raw_x, raw_y; /* most recent absolute co-ords read */ -static int raw_down; /* raw up/down state */ -static int debounced_down; /* up/down state after debounce processing */ -static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE; - /* set just after an up/down transition */ -static int xy_pending; /* set if new data have not yet been read */ - -/* - * Timer goes off a short while after an up/down transition and copies - * the value of raw_down to debounced_down. - */ - -static void bounce_timeout(unsigned long data); -static struct timer_list bounce_timer = { function: bounce_timeout }; - - - -/** - * bounce_timeout: - * @data: Unused - * - * No further up/down transitions happened within the - * bounce period, so treat this as a genuine transition. - */ - -static void bounce_timeout(unsigned long data) -{ - switch(bounce) - { - case NO_BOUNCE: - { - /* - * Strange; the timer callback should only go off if - * we were expecting to do bounce processing! - */ - printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n"); - break; - } - case JUST_GONE_UP: - { - /* - * The last up we spotted really was an up, so set - * debounced state the same as raw state. - */ - bounce=NO_BOUNCE; - if(debounced_down==raw_down) - { - printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n"); - } - debounced_down=raw_down; - - notify_pad_up_down(); - break; - } - case JUST_GONE_DOWN: - { - /* - * We don't debounce down events, but we still time - * out soon after one occurs so we can avoid the (x,y) - * skittering that sometimes happens. - */ - bounce=NO_BOUNCE; - break; - } - } -} - - -/** - * pad_irq: - * @irq: Interrupt number - * @ptr: Unused - * @regs: Unused - * - * Callback when pad's irq goes off; copies values in to raw_* globals; - * initiates debounce processing. This isn't SMP safe however there are - * no SMP machines with a PC110 touchpad on them. - */ - -static void pad_irq(int irq, void *ptr, struct pt_regs *regs) -{ - - /* Obtain byte from pad and prime for next byte */ - { - int value=inb_p(current_params.io); - int handshake=inb_p(current_params.io+2); - outb_p(handshake | 1, current_params.io+2); - outb_p(handshake &~1, current_params.io+2); - inb_p(0x64); - - raw_data[raw_data_count++]=value; - } - - if(raw_data_count==3) - { - int new_down=raw_data[0]&0x01; - int new_x=raw_data[1]; - int new_y=raw_data[2]; - if(raw_data[0]&0x10) new_x+=128; - if(raw_data[0]&0x80) new_x+=256; - if(raw_data[0]&0x08) new_y+=128; - - if( (raw_x!=new_x) || (raw_y!=new_y) ) - { - raw_x=new_x; - raw_y=new_y; - xy_pending=1; - } - - if(new_down != raw_down) - { - /* Down state has changed. raw_down always holds - * the most recently observed state. - */ - raw_down=new_down; - - /* Forget any earlier bounce processing */ - if(bounce) - { - del_timer(&bounce_timer); - bounce=NO_BOUNCE; - } - - if(new_down) - { - if(debounced_down) - { - /* pad gone down, but we were reporting - * it down anyway because we suspected - * (correctly) that the last up was just - * a bounce - */ - } - else - { - bounce=JUST_GONE_DOWN; - mod_timer(&bounce_timer, - jiffies+current_params.bounce_interval); - /* start new stroke/tap */ - debounced_down=new_down; - notify_pad_up_down(); - } - } - else /* just gone up */ - { - if(recent_transition) - { - /* early bounces are probably part of - * a multi-tap gesture, so process - * immediately - */ - debounced_down=new_down; - notify_pad_up_down(); - } - else - { - /* don't trust it yet */ - bounce=JUST_GONE_UP; - mod_timer(&bounce_timer, - jiffies+current_params.bounce_interval); - } - } - } - wake_readers(); - raw_data_count=0; - } -} - -/** - * read_raw_pad: - * @down: set if the pen is down - * @debounced: set if the debounced pen position is down - * @x: X position - * @y: Y position - * - * Retrieve the data saved by the interrupt handler and indicate we - * have no more pending XY to do. - * - * FIXME: We should switch to a spinlock for this. - */ - -static void read_raw_pad(int *down, int *debounced, int *x, int *y) -{ - disable_irq(current_params.irq); - { - *down=raw_down; - *debounced=debounced_down; - *x=raw_x; - *y=raw_y; - xy_pending = 0; - } - enable_irq(current_params.irq); -} - -/*****************************************************************************/ -/* - * Filesystem interface - */ - -/* - * Read returns byte triples, so we need to keep track of - * how much of a triple has been read. This is shared across - * all processes which have this device open---not that anything - * will make much sense in that case. - */ -static int read_bytes[3]; -static int read_byte_count; - -/** - * sample_raw: - * @d: sample buffer - * - * Retrieve a triple of sample data. - */ - - -static void sample_raw(int d[3]) -{ - d[0]=raw_data[0]; - d[1]=raw_data[1]; - d[2]=raw_data[2]; -} - -/** - * sample_rare: - * @d: sample buffer - * - * Retrieve a triple of sample data and sanitize it. We do the needed - * scaling and masking to get the current status. - */ - - -static void sample_rare(int d[3]) -{ - int thisd, thisdd, thisx, thisy; - - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - - d[0]=(thisd?0x80:0) - | (thisx/256)<<4 - | (thisdd?0x08:0) - | (thisy/256) - ; - d[1]=thisx%256; - d[2]=thisy%256; -} - -/** - * sample_debug: - * @d: sample buffer - * - * Retrieve a triple of sample data and mix it up with the state - * information in the gesture parser. Not useful for normal users but - * handy when debugging - */ - -static void sample_debug(int d[3]) -{ - int thisd, thisdd, thisx, thisy; - int b; - unsigned long flags; - - spin_lock_irqsave(&pc110_lock, flags); - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce; - d[1]=(recent_transition?0x80:0)+transition_count; - read_button(&b); - d[2]=(synthesize_tap<<4) | (b?0x01:0); - spin_unlock_irqrestore(&pc110_lock, flags); -} - -/** - * sample_ps2: - * @d: sample buffer - * - * Retrieve a triple of sample data and turn the debounced tap and - * stroke information into what appears to be a PS/2 mouse. This means - * the PC110 pad needs no funny application side support. - */ - - -static void sample_ps2(int d[3]) -{ - static int lastx, lasty, lastd; - - int thisd, thisdd, thisx, thisy; - int dx, dy, b; - - /* - * Obtain the current mouse parameters and limit as appropriate for - * the return data format. Interrupts are only disabled while - * obtaining the parameters, NOT during the puts_fs_byte() calls, - * so paging in put_user() does not affect mouse tracking. - */ - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - read_button(&b); - - /* Now compare with previous readings. Note that we use the - * raw down flag rather than the debounced one. - */ - if( (thisd && !lastd) /* new stroke */ - || (bounce!=NO_BOUNCE) ) - { - dx=0; - dy=0; - } - else - { - dx = (thisx-lastx); - dy = -(thisy-lasty); - } - lastx=thisx; - lasty=thisy; - lastd=thisd; - -/* - d[0]= ((dy<0)?0x20:0) - | ((dx<0)?0x10:0) - | 0x08 - | (b? 0x01:0x00) - ; -*/ - d[0]= ((dy<0)?0x20:0) - | ((dx<0)?0x10:0) - | (b? 0x00:0x08) - ; - d[1]=dx; - d[2]=dy; -} - - -/** - * fasync_pad: - * @fd: file number for the file - * @filp: file handle - * @on: 1 to add, 0 to remove a notifier - * - * Update the queue of asynchronous event notifiers. We can use the - * same helper the mice do and that does almost everything we need. - */ - -static int fasync_pad(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &asyncptr); - if (retval < 0) - return retval; - return 0; -} - - -/** - * close_pad: - * @inode: inode of pad - * @file: file handle to pad - * - * Close access to the pad. We turn the pad power off if this is the - * last user of the pad. I've not actually measured the power draw but - * the DOS driver is careful to do this so we follow suit. - */ - -static int close_pad(struct inode * inode, struct file * file) -{ - unsigned long flags; - fasync_pad(-1, file, 0); - spin_lock_irqsave(&pc110_lock, flags); - if (!--active_count) - outb(0x30, current_params.io+2); /* switch off digitiser */ - spin_unlock_irqrestore(&pc110_lock, flags); - return 0; -} - - -/** - * open_pad: - * @inode: inode of pad - * @file: file handle to pad - * - * Open access to the pad. We turn the pad off first (we turned it off - * on close but if this is the first open after a crash the state is - * indeterminate). The device has a small fifo so we empty that before - * we kick it back into action. - */ - -static int open_pad(struct inode * inode, struct file * file) -{ - unsigned long flags; - - spin_lock_irqsave(&pc110_lock, flags); - if (active_count++) - { - spin_unlock_irqrestore(&pc110_lock, flags); - return 0; - } - - outb(0x30, current_params.io+2); /* switch off digitiser */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - outb(0x38, current_params.io+2); /* switch on digitiser */ - current_params = default_params; - raw_data_count=0; /* re-sync input byte counter */ - read_byte_count=0; /* re-sync output byte counter */ - button_pending=0; - recent_transition=0; - transition_count=0; - synthesize_tap=0; - del_timer(&bounce_timer); - del_timer(&tap_timer); - spin_unlock_irqrestore(&pc110_lock, flags); - - return 0; -} - - -/** - * write_pad: - * @file: File handle to the pad - * @buffer: Unused - * @count: Unused - * @ppos: Unused - * - * Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone - * seems happy with this and not faking the write modes. - */ - -static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - - -/* - * new_sample: - * @d: sample buffer - * - * Fetch a new sample according the current mouse mode the pad is - * using. - */ - -void new_sample(int d[3]) -{ - switch(current_params.mode) - { - case PC110PAD_RAW: sample_raw(d); break; - case PC110PAD_RARE: sample_rare(d); break; - case PC110PAD_DEBUG: sample_debug(d); break; - case PC110PAD_PS2: sample_ps2(d); break; - } -} - - -/** - * read_pad: - * @file: File handle to pad - * @buffer: Target for the mouse data - * @count: Buffer length - * @ppos: Offset (unused) - * - * Read data from the pad. We use the reader_lock to avoid mess when there are - * two readers. This shouldnt be happening anyway but we play safe. - */ - -static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos) -{ - int r; - - down(&reader_lock); - for(r=0; rPC110PAD_PS2) - || (new.bounce_interval<0) - || (new.tap_interval<0) - ) - return -EINVAL; - - current_params.mode = new.mode; - current_params.bounce_interval = new.bounce_interval; - current_params.tap_interval = new.tap_interval; - return 0; - } - return -ENOTTY; -} - - -static struct file_operations pad_fops = { - owner: THIS_MODULE, - read: read_pad, - write: write_pad, - poll: pad_poll, - ioctl: pad_ioctl, - open: open_pad, - release: close_pad, - fasync: fasync_pad, -}; - - -static struct miscdevice pc110_pad = { - minor: PC110PAD_MINOR, - name: "pc110 pad", - fops: &pad_fops, -}; - - -/** - * pc110pad_init_driver: - * - * We configure the pad with the default parameters (that is PS/2 - * emulation mode. We then claim the needed I/O and interrupt resources. - * Finally as a matter of paranoia we turn the pad off until we are - * asked to open it by an application. - */ - -static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.\n"; - -static int __init pc110pad_init_driver(void) -{ - init_MUTEX(&reader_lock); - current_params = default_params; - - if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) { - printk(KERN_ERR "pc110pad: Unable to get IRQ.\n"); - return -EBUSY; - } - if (!request_region(current_params.io, 4, "pc110pad")) { - printk(KERN_ERR "pc110pad: I/O area in use.\n"); - free_irq(current_params.irq,0); - return -EBUSY; - } - init_waitqueue_head(&queue); - printk(banner, current_params.io, current_params.irq); - misc_register(&pc110_pad); - outb(0x30, current_params.io+2); /* switch off digitiser */ - return 0; -} - -/* - * pc110pad_exit_driver: - * - * Free the resources we acquired when the module was loaded. We also - * turn the pad off to be sure we don't leave it using power. - */ - -static void __exit pc110pad_exit_driver(void) -{ - outb(0x30, current_params.io+2); /* switch off digitiser */ - if (current_params.irq) - free_irq(current_params.irq, 0); - current_params.irq = 0; - release_region(current_params.io, 4); - misc_deregister(&pc110_pad); -} - -module_init(pc110pad_init_driver); -module_exit(pc110pad_exit_driver); - -MODULE_AUTHOR("Alan Cox, Robin O'Leary"); -MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop"); -MODULE_LICENSE("GPL"); - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/pc110pad.h linux-2.5/drivers/char/pc110pad.h --- linux-2.5.23/drivers/char/pc110pad.h Wed Jun 19 03:11:49 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.23/drivers/char/pc_keyb.c linux-2.5/drivers/char/pc_keyb.c --- linux-2.5.23/drivers/char/pc_keyb.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/char/pc_keyb.c Sun Jan 20 17:11:45 2002 @@ -61,79 +61,6 @@ "\r\000/"; /* 0x60 - 0x6f */ #endif -static void kbd_write_command_w(int data); -static void kbd_write_output_w(int data); -#ifdef CONFIG_PSMOUSE -static void aux_write_ack(int val); -static void __aux_write_ack(int val); -static int aux_reconnect = 0; -#endif - -static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; -static unsigned char handle_kbd_event(void); - -/* used only by send_data - set by keyboard_interrupt */ -static volatile unsigned char reply_expected; -static volatile unsigned char acknowledge; -static volatile unsigned char resend; - - -#if defined CONFIG_PSMOUSE -/* - * PS/2 Auxiliary Device - */ - -static int __init psaux_init(void); - -#define AUX_RECONNECT1 0xaa /* scancode1 when ps2 device is plugged (back) in */ -#define AUX_RECONNECT2 0x00 /* scancode2 when ps2 device is plugged (back) in */ - -static struct aux_queue *queue; /* Mouse data buffer. */ -static int aux_count; -static spinlock_t aux_count_lock = SPIN_LOCK_UNLOCKED; -/* used when we send commands to the mouse that expect an ACK. */ -static unsigned char mouse_reply_expected; - -#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) -#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) - -#define MAX_RETRIES 60 /* some aux operations take long time*/ -#endif /* CONFIG_PSMOUSE */ - -/* - * Wait for keyboard controller input buffer to drain. - * - * Don't use 'jiffies' so that we don't depend on - * interrupts.. - * - * Quote from PS/2 System Reference Manual: - * - * "Address hex 0060 and address hex 0064 should be written only when - * the input-buffer-full bit and output-buffer-full bit in the - * Controller Status register are set 0." - */ - -static void kb_wait(void) -{ - unsigned long timeout = KBC_TIMEOUT; - - do { - /* - * "handle_kbd_event()" will handle any incoming events - * while we wait - keypresses or mouse movement. - */ - unsigned char status = handle_kbd_event(); - - if (! (status & KBD_STAT_IBF)) - return; - mdelay(1); - timeout--; - } while (timeout); -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "Keyboard timed out[1]\n"); -#endif -} - /* * Translation of escaped scancodes to keycodes. * This is now user-settable. @@ -268,32 +195,6 @@ e0_keys[scancode - 128]; } -static int do_acknowledge(unsigned char scancode) -{ - if (reply_expected) { - /* Unfortunately, we must recognise these codes only if we know they - * are known to be valid (i.e., after sending a command), because there - * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have - * keys with such codes :( - */ - if (scancode == KBD_REPLY_ACK) { - acknowledge = 1; - reply_expected = 0; - return 0; - } else if (scancode == KBD_REPLY_RESEND) { - resend = 1; - reply_expected = 0; - return 0; - } - /* Should not happen... */ -#if 0 - printk(KERN_DEBUG "keyboard reply expected - got %02x\n", - scancode); -#endif - } - return 1; -} - int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) { @@ -401,848 +302,8 @@ int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data) { -#if defined CONFIG_PSMOUSE - unsigned long flags; - - if (rqst == PM_RESUME) { - if (queue) { /* Aux port detected */ - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count == 0) { /* Mouse not in use */ - spin_lock(&kbd_controller_lock); - /* - * Dell Lat. C600 A06 enables mouse after resume. - * When user touches the pad, it posts IRQ 12 - * (which we do not process), thus holding keyboard. - */ - kbd_write_command(KBD_CCMD_MOUSE_DISABLE); - /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MODE); - kb_wait(); - kbd_write_output(AUX_INTS_OFF); - spin_unlock(&kbd_controller_lock); - } - spin_unlock_irqrestore(&aux_count_lock, flags); - } - } -#endif return 0; } - -static inline void handle_mouse_event(unsigned char scancode) -{ -#ifdef CONFIG_PSMOUSE - unsigned long flags; - static unsigned char prev_code; - if (mouse_reply_expected) { - if (scancode == AUX_ACK) { - mouse_reply_expected--; - return; - } - mouse_reply_expected = 0; - } - else if(scancode == AUX_RECONNECT2 && prev_code == AUX_RECONNECT1 - && aux_reconnect) { - printk (KERN_INFO "PS/2 mouse reconnect detected\n"); - queue->head = queue->tail = 0; /* Flush input queue */ - __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ - return; - } - - prev_code = scancode; - add_mouse_randomness(scancode); - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count ) { - int head = queue->head; - - queue->buf[head] = scancode; - head = (head + 1) & (AUX_BUF_SIZE-1); - if (head != queue->tail) { - queue->head = head; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); - } - } - spin_unlock_irqrestore(&aux_count_lock, flags); -#endif -} - -static unsigned char kbd_exists = 1; - -static inline void handle_keyboard_event(unsigned char scancode) -{ -#ifdef CONFIG_VT - kbd_exists = 1; - if (do_acknowledge(scancode)) - handle_scancode(scancode, !(scancode & 0x80)); -#endif - tasklet_schedule(&keyboard_tasklet); -} - -/* - * This reads the keyboard status port, and does the - * appropriate action. - * - * It requires that we hold the keyboard controller - * spinlock. - */ -static unsigned char handle_kbd_event(void) -{ - unsigned char status = kbd_read_status(); - unsigned int work = 10000; - - while ((--work > 0) && (status & KBD_STAT_OBF)) { - unsigned char scancode; - - scancode = kbd_read_input(); - - /* Error bytes must be ignored to make the - Synaptics touchpads compaq use work */ -#if 1 - /* Ignore error bytes */ - if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) -#endif - { - if (status & KBD_STAT_MOUSE_OBF) - handle_mouse_event(scancode); - else - handle_keyboard_event(scancode); - } - - status = kbd_read_status(); - } - - if (!work) - printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status); - - return status; -} - - -static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ -#ifdef CONFIG_VT - kbd_pt_regs = regs; -#endif - - spin_lock_irq(&kbd_controller_lock); - handle_kbd_event(); - spin_unlock_irq(&kbd_controller_lock); -} - -/* - * send_data sends a character to the keyboard and waits - * for an acknowledge, possibly retrying if asked to. Returns - * the success status. - * - * Don't use 'jiffies', so that we don't depend on interrupts - */ -static int send_data(unsigned char data) -{ - int retries = 3; - - do { - unsigned long timeout = KBD_TIMEOUT; - - acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ - resend = 0; - reply_expected = 1; - kbd_write_output_w(data); - for (;;) { - if (acknowledge) - return 1; - if (resend) - break; - mdelay(1); - if (!--timeout) { -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?(%02x)\n", data); -#endif - return 0; - } - } - } while (retries-- > 0); -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n"); -#endif - return 0; -} - -void pckbd_leds(unsigned char leds) -{ - if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) { - send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ - kbd_exists = 0; - } -} - -#define DEFAULT_KEYB_REP_DELAY 250 -#define DEFAULT_KEYB_REP_RATE 30 /* cps */ - -static struct kbd_repeat kbdrate={ - DEFAULT_KEYB_REP_DELAY, - DEFAULT_KEYB_REP_RATE -}; - -static unsigned char parse_kbd_rate(struct kbd_repeat *r) -{ - static struct r2v{ - int rate; - unsigned char val; - } kbd_rates[]={ {5,0x14}, - {7,0x10}, - {10,0x0c}, - {15,0x08}, - {20,0x04}, - {25,0x02}, - {30,0x00} - }; - static struct d2v{ - int delay; - unsigned char val; - } kbd_delays[]={{250,0}, - {500,1}, - {750,2}, - {1000,3} - }; - int rate=0,delay=0; - if (r != NULL){ - int i,new_rate=30,new_delay=250; - if (r->rate <= 0) - r->rate=kbdrate.rate; - if (r->delay <= 0) - r->delay=kbdrate.delay; - for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++) - if (kbd_rates[i].rate == r->rate){ - new_rate=kbd_rates[i].rate; - rate=kbd_rates[i].val; - break; - } - for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++) - if (kbd_delays[i].delay == r->delay){ - new_delay=kbd_delays[i].delay; - delay=kbd_delays[i].val; - break; - } - r->rate=new_rate; - r->delay=new_delay; - } - return (delay << 5) | rate; -} - -static int write_kbd_rate(unsigned char r) -{ - if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)){ - send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ - return 0; - }else - return 1; -} - -static int pckbd_rate(struct kbd_repeat *rep) -{ - if (rep == NULL) - return -EINVAL; - else{ - unsigned char r=parse_kbd_rate(rep); - struct kbd_repeat old_rep; - memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat)); - if (write_kbd_rate(r)){ - memcpy(&kbdrate,rep,sizeof(struct kbd_repeat)); - memcpy(rep,&old_rep,sizeof(struct kbd_repeat)); - return 0; - } - } - return -EIO; -} - -/* - * In case we run on a non-x86 hardware we need to initialize both the - * keyboard controller and the keyboard. On a x86, the BIOS will - * already have initialized them. - * - * Some x86 BIOSes do not correctly initialize the keyboard, so the - * "kbd-reset" command line options can be given to force a reset. - * [Ranger] - */ -#ifdef __i386__ - int kbd_startup_reset __initdata = 0; -#else - int kbd_startup_reset __initdata = 1; -#endif - -/* for "kbd-reset" cmdline param */ -static int __init kbd_reset_setup(char *str) -{ - kbd_startup_reset = 1; - return 1; -} - -__setup("kbd-reset", kbd_reset_setup); - -#define KBD_NO_DATA (-1) /* No data */ -#define KBD_BAD_DATA (-2) /* Parity or other error */ - -static int __init kbd_read_data(void) -{ - int retval = KBD_NO_DATA; - unsigned char status; - - status = kbd_read_status(); - if (status & KBD_STAT_OBF) { - unsigned char data = kbd_read_input(); - - retval = data; - if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) - retval = KBD_BAD_DATA; - } - return retval; -} - -static void __init kbd_clear_input(void) -{ - int maxread = 100; /* Random number */ - - do { - if (kbd_read_data() == KBD_NO_DATA) - break; - } while (--maxread); -} - -static int __init kbd_wait_for_input(void) -{ - long timeout = KBD_INIT_TIMEOUT; - - do { - int retval = kbd_read_data(); - if (retval >= 0) - return retval; - mdelay(1); - } while (--timeout); - return -1; -} - -static void kbd_write_command_w(int data) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(data); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -static void kbd_write_output_w(int data) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_output(data); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -#if defined(__alpha__) -/* - * Some Alphas cannot mask some/all interrupts, so we have to - * make sure not to allow interrupts AT ALL when polling for - * specific return values from the keyboard. - * - * I think this should work on any architecture, but for now, only Alpha. - */ -static int kbd_write_command_w_and_wait(int data) -{ - unsigned long flags; - int input; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(data); - input = kbd_wait_for_input(); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return input; -} - -static int kbd_write_output_w_and_wait(int data) -{ - unsigned long flags; - int input; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_output(data); - input = kbd_wait_for_input(); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return input; -} -#else -static int kbd_write_command_w_and_wait(int data) -{ - kbd_write_command_w(data); - return kbd_wait_for_input(); -} - -static int kbd_write_output_w_and_wait(int data) -{ - kbd_write_output_w(data); - return kbd_wait_for_input(); -} -#endif /* __alpha__ */ - -#if defined CONFIG_PSMOUSE -static void kbd_write_cmd(int cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MODE); - kb_wait(); - kbd_write_output(cmd); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} -#endif /* CONFIG_PSMOUSE */ - -static char * __init initialize_kbd(void) -{ - int status; - -#ifdef CONFIG_IA64 - /* - * This is not really IA-64 specific. Probably ought to be done on all platforms - * that are (potentially) legacy-free. - */ - if (kbd_read_status() == 0xff && kbd_read_input() == 0xff) { - kbd_exists = 0; - return "No keyboard controller preset"; - } -#endif - - /* - * Test the keyboard interface. - * This seems to be the only way to get it going. - * If the test is successful a x55 is placed in the input buffer. - */ - kbd_write_command_w(KBD_CCMD_SELF_TEST); - if (kbd_wait_for_input() != 0x55) - return "Keyboard failed self test"; - - /* - * Perform a keyboard interface test. This causes the controller - * to test the keyboard clock and data lines. The results of the - * test are placed in the input buffer. - */ - kbd_write_command_w(KBD_CCMD_KBD_TEST); - if (kbd_wait_for_input() != 0x00) - return "Keyboard interface failed self test"; - - /* - * Enable the keyboard by allowing the keyboard clock to run. - */ - kbd_write_command_w(KBD_CCMD_KBD_ENABLE); - - /* - * Reset keyboard. If the read times out - * then the assumption is that no keyboard is - * plugged into the machine. - * This defaults the keyboard to scan-code set 2. - * - * Set up to try again if the keyboard asks for RESEND. - */ - do { - kbd_write_output_w(KBD_CMD_RESET); - status = kbd_wait_for_input(); - if (status == KBD_REPLY_ACK) - break; - if (status != KBD_REPLY_RESEND) - return "Keyboard reset failed, no ACK"; - } while (1); - - if (kbd_wait_for_input() != KBD_REPLY_POR) - return "Keyboard reset failed, no POR"; - - /* - * Set keyboard controller mode. During this, the keyboard should be - * in the disabled state. - * - * Set up to try again if the keyboard asks for RESEND. - */ - do { - kbd_write_output_w(KBD_CMD_DISABLE); - status = kbd_wait_for_input(); - if (status == KBD_REPLY_ACK) - break; - if (status != KBD_REPLY_RESEND) - return "Disable keyboard: no ACK"; - } while (1); - - kbd_write_command_w(KBD_CCMD_WRITE_MODE); - kbd_write_output_w(KBD_MODE_KBD_INT - | KBD_MODE_SYS - | KBD_MODE_DISABLE_MOUSE - | KBD_MODE_KCC); - - /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ - if (!(kbd_write_command_w_and_wait(KBD_CCMD_READ_MODE) & KBD_MODE_KCC)) - { - /* - * If the controller does not support conversion, - * Set the keyboard to scan-code set 1. - */ - kbd_write_output_w(0xF0); - kbd_wait_for_input(); - kbd_write_output_w(0x01); - kbd_wait_for_input(); - } - - if (kbd_write_output_w_and_wait(KBD_CMD_ENABLE) != KBD_REPLY_ACK) - return "Enable keyboard: no ACK"; - - /* - * Finally, set the typematic rate to maximum. - */ - if (kbd_write_output_w_and_wait(KBD_CMD_SET_RATE) != KBD_REPLY_ACK) - return "Set rate: no ACK"; - if (kbd_write_output_w_and_wait(0x00) != KBD_REPLY_ACK) - return "Set rate: no 2nd ACK"; - - return NULL; -} - -void __init pckbd_init_hw(void) -{ - kbd_request_region(); - - /* Flush any pending input. */ - kbd_clear_input(); - - if (kbd_startup_reset) { - char *msg = initialize_kbd(); - if (msg) - printk(KERN_WARNING "initialize_kbd: %s\n", msg); -#ifdef CONFIG_IA64 - if (!kbd_exists) - return; -#endif - } - -#if defined CONFIG_PSMOUSE - psaux_init(); -#endif - - kbd_rate = pckbd_rate; - - /* Ok, finally allocate the IRQ, and off we go.. */ - kbd_request_irq(keyboard_interrupt); -} - -#if defined CONFIG_PSMOUSE - -static int __init aux_reconnect_setup (char *str) -{ - aux_reconnect = 1; - return 1; -} - -__setup("psaux-reconnect", aux_reconnect_setup); - -/* - * Check if this is a dual port controller. - */ -static int __init detect_auxiliary_port(void) -{ - unsigned long flags; - int loops = 10; - int retval = 0; - - /* Check if the BIOS detected a device on the auxiliary port. */ - if (aux_device_present == 0xaa) - return 1; - - spin_lock_irqsave(&kbd_controller_lock, flags); - - /* Put the value 0x5A in the output buffer using the "Write - * Auxiliary Device Output Buffer" command (0xD3). Poll the - * Status Register for a while to see if the value really - * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF - * bit is also set to 1 in the Status Register, we assume this - * controller has an Auxiliary Port (a.k.a. Mouse Port). - */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); - - kb_wait(); - kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ - - do { - unsigned char status = kbd_read_status(); - - if (status & KBD_STAT_OBF) { - (void) kbd_read_input(); - if (status & KBD_STAT_MOUSE_OBF) { - printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); - retval = 1; - } - break; - } - mdelay(1); - } while (--loops); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - - return retval; -} - -/* - * Send a byte to the mouse. - */ -static void aux_write_dev(int val) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MOUSE); - kb_wait(); - kbd_write_output(val); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -/* - * Send a byte to the mouse & handle returned ack - */ -static void __aux_write_ack(int val) -{ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MOUSE); - kb_wait(); - kbd_write_output(val); - /* we expect an ACK in response. */ - mouse_reply_expected++; - kb_wait(); -} - -static void aux_write_ack(int val) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - __aux_write_ack(val); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -static unsigned char get_from_queue(void) -{ - unsigned char result; - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return result; -} - - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_aux(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - - -/* - * Random magic cookie for the aux device - */ -#define AUX_DEV ((void *)queue) - -static int release_aux(struct inode * inode, struct file * file) -{ - unsigned long flags; - fasync_aux(-1, file, 0); - spin_lock_irqsave(&aux_count_lock, flags); - if ( --aux_count ) { - spin_unlock_irqrestore(&aux_count_lock, flags); - return 0; - } - spin_unlock_irqrestore(&aux_count_lock, flags); - kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ - kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); - aux_free_irq(AUX_DEV); - return 0; -} - -/* - * Install interrupt handler. - * Enable auxiliary device. - */ - -static int open_aux(struct inode * inode, struct file * file) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count++ ) { - spin_unlock_irqrestore(&aux_count_lock, flags); - return 0; - } - queue->head = queue->tail = 0; /* Flush input queue */ - spin_unlock_irqrestore(&aux_count_lock, flags); - ret = aux_request_irq(keyboard_interrupt, AUX_DEV); - spin_lock_irqsave(&aux_count_lock, flags); - if (ret) { - aux_count--; - spin_unlock_irqrestore(&aux_count_lock, flags); - return -EBUSY; - } - spin_unlock_irqrestore(&aux_count_lock, flags); - kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the - auxiliary port on - controller. */ - aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ - kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ - - mdelay(2); /* Ensure we follow the kbc access delay rules.. */ - - send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ - return 0; -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_aux(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* - * Write to the aux device. - */ - -static ssize_t write_aux(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t retval = 0; - - if (count) { - ssize_t written = 0; - - if (count > 32) - count = 32; /* Limit to 32 bytes. */ - do { - char c; - get_user(c, buffer++); - aux_write_dev(c); - written++; - } while (--count); - retval = -EIO; - if (written) { - retval = written; - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - } - } - - return retval; -} - -/* No kernel lock held - fine */ -static unsigned int aux_poll(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations psaux_fops = { - read: read_aux, - write: write_aux, - poll: aux_poll, - open: open_aux, - release: release_aux, - fasync: fasync_aux, -}; - -/* - * Initialize driver. - */ -static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "psaux", &psaux_fops -}; - -static int __init psaux_init(void) -{ - int retval; - - if (!detect_auxiliary_port()) - return -EIO; - - if ((retval = misc_register(&psaux_mouse))) - return retval; - - queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (queue == NULL) { - printk(KERN_ERR "psaux_init(): out of memory\n"); - misc_deregister(&psaux_mouse); - return -ENOMEM; - } - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - -#ifdef INITIALIZE_MOUSE - kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ - aux_write_ack(AUX_SET_SAMPLE); - aux_write_ack(100); /* 100 samples/sec */ - aux_write_ack(AUX_SET_RES); - aux_write_ack(3); /* 8 counts per mm */ - aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ -#endif /* INITIALIZE_MOUSE */ - kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ - kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ - - return 0; -} - -#endif /* CONFIG_PSMOUSE */ +void pckbd_leds(unsigned char leds) { } +void __init pckbd_init_hw(void) { } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/pcmcia/serial_cs.c linux-2.5/drivers/char/pcmcia/serial_cs.c --- linux-2.5.23/drivers/char/pcmcia/serial_cs.c Wed Jun 19 03:11:55 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.23/drivers/char/pcwd.c linux-2.5/drivers/char/pcwd.c --- linux-2.5.23/drivers/char/pcwd.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/char/pcwd.c Sat May 25 19:52:01 2002 @@ -40,6 +40,8 @@ * fairly useless proc entry. * 990610 removed said useless proc code for the merge * 000403 Removed last traces of proc code. + * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default */ #include @@ -76,7 +78,7 @@ */ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; -#define WD_VER "1.10 (06/05/99)" +#define WD_VER "1.12 (12/14/2001)" /* * It should be noted that PCWD_REVISION_B was removed because A and B @@ -88,7 +90,22 @@ #define PCWD_REVISION_A 1 #define PCWD_REVISION_C 2 -#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */ +#define WD_TIMEOUT 4 /* 2 seconds for a timeout */ +static int timeout_val = WD_TIMEOUT; +static int timeout = 2; + +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=2)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * These are the defines for the PC Watchdog card, revision A. @@ -121,7 +138,7 @@ if (prev_card_dat == 0xFF) return 0; - while(count < WD_TIMEOUT) { + while(count < timeout_val) { /* Read the raw card data from the port, and strip off the first 4 bits */ @@ -450,16 +467,16 @@ { if (minor(ino->i_rdev)==WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - /* Disable the board */ - if (revision == PCWD_REVISION_C) { - spin_lock(&io_lock); - outb_p(0xA5, current_readport + 3); - outb_p(0xA5, current_readport + 3); - spin_unlock(&io_lock); + if (!nowayout) { + /* Disable the board */ + if (revision == PCWD_REVISION_C) { + spin_lock(&io_lock); + outb_p(0xA5, current_readport + 3); + outb_p(0xA5, current_readport + 3); + spin_unlock(&io_lock); + } + atomic_inc( &open_allowed ); } - atomic_inc( &open_allowed ); -#endif } return 0; } @@ -559,10 +576,16 @@ "temperature", &pcwd_fops }; + +static void __init pcwd_validate_timeout(void) +{ + timeout_val = timeout * 2; +} static int __init pcwatchdog_init(void) { int i, found = 0; + pcwd_validate_timeout(); spin_lock_init(&io_lock); revision = PCWD_REVISION_A; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/pty.c linux-2.5/drivers/char/pty.c --- linux-2.5.23/drivers/char/pty.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/char/pty.c Fri Jun 7 02:36:08 2002 @@ -5,6 +5,10 @@ * * Added support for a Unix98-style ptmx device. * -- C. Scott Ananian , 14-Jan-1998 + * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to + * waiting writers -- Sapan Bhatia + * + * */ #include @@ -331,6 +335,8 @@ clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&pty->open_wait); set_bit(TTY_THROTTLED, &tty->flags); + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + /* Register a slave for the master */ if (tty->driver.major == PTY_MASTER_MAJOR) tty_register_devfs(&tty->link->driver, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/q40_keyb.c linux-2.5/drivers/char/q40_keyb.c --- linux-2.5.23/drivers/char/q40_keyb.c Wed Jun 19 03:11:55 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.23/drivers/char/qpmouse.c linux-2.5/drivers/char/qpmouse.c --- linux-2.5.23/drivers/char/qpmouse.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/char/qpmouse.c Thu Jan 1 01:00:00 1970 @@ -1,381 +0,0 @@ -/* - * linux/drivers/char/qpmouse.c - * - * Driver for a 82C710 C&T mouse interface chip. - * - * Based on the PS/2 driver by Johan Myreen. - * - * Corrections in device setup for some laptop mice & trackballs. - * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca) - * - * Modified by Johan Myreen (jem@iki.fi) 04Aug93 - * to include support for QuickPort mouse. - * - * Changed references to "QuickPort" with "82C710" since "QuickPort" - * is not what this driver is all about -- QuickPort is just a - * connector type, and this driver is for the mouse port on the Chips - * & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi - * - * Added support for SIGIO. 28Jul95 jem@iki.fi - * - * Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com - * - * Modularised 8-Sep-95 Philip Blundell - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include /* mouse enable command.. */ - - -/* - * We use the same minor number as the PS/2 mouse for (bad) historical - * reasons.. - */ -#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */ -#define QP_BUF_SIZE 2048 - -struct qp_queue { - unsigned long head; - unsigned long tail; - wait_queue_head_t proc_list; - struct fasync_struct *fasync; - unsigned char buf[QP_BUF_SIZE]; -}; - -static struct qp_queue *queue; - -static unsigned int get_from_queue(void) -{ - unsigned int result; - unsigned long flags; - - save_flags(flags); - cli(); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (QP_BUF_SIZE-1); - restore_flags(flags); - return result; -} - - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_qp(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - -/* - * 82C710 Interface - */ - -#define QP_DATA 0x310 /* Data Port I/O Address */ -#define QP_STATUS 0x311 /* Status Port I/O Address */ - -#define QP_DEV_IDLE 0x01 /* Device Idle */ -#define QP_RX_FULL 0x02 /* Device Char received */ -#define QP_TX_IDLE 0x04 /* Device XMIT Idle */ -#define QP_RESET 0x08 /* Device Reset */ -#define QP_INTS_ON 0x10 /* Device Interrupt On */ -#define QP_ERROR_FLAG 0x20 /* Device Error */ -#define QP_CLEAR 0x40 /* Device Clear */ -#define QP_ENABLE 0x80 /* Device Enable */ - -#define QP_IRQ 12 - -static int qp_present; -static int qp_count; -static spinlock_t qp_count_lock = SPIN_LOCK_UNLOCKED; -static int qp_data = QP_DATA; -static int qp_status = QP_STATUS; - -static int poll_qp_status(void); -static int probe_qp(void); - -/* - * Interrupt handler for the 82C710 mouse port. A character - * is waiting in the 82C710. - */ - -static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs) -{ - int head = queue->head; - int maxhead = (queue->tail-1) & (QP_BUF_SIZE-1); - - add_mouse_randomness(queue->buf[head] = inb(qp_data)); - if (head != maxhead) { - head++; - head &= QP_BUF_SIZE-1; - } - queue->head = head; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); -} - -static int release_qp(struct inode * inode, struct file * file) -{ - unsigned char status; - - fasync_qp(-1, file, 0); - spin_lock( &qp_count_lock ); - if (!--qp_count) { - if (!poll_qp_status()) - printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); - status = inb_p(qp_status); - outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status); - if (!poll_qp_status()) - printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); - free_irq(QP_IRQ, NULL); - } - spin_unlock( &qp_count_lock ); - return 0; -} - -/* - * Install interrupt handler. - * Enable the device, enable interrupts. - */ - -static int open_qp(struct inode * inode, struct file * file) -{ - unsigned char status; - - if (!qp_present) - return -EINVAL; - - spin_lock( &qp_count_lock ); - if (qp_count++) - { - spin_unlock( &qp_count_lock ); - return 0; - } - spin_unlock( &qp_count_lock ); - - if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) { - qp_count--; - return -EBUSY; - } - - status = inb_p(qp_status); - status |= (QP_ENABLE|QP_RESET); - outb_p(status, qp_status); - status &= ~(QP_RESET); - outb_p(status, qp_status); - - queue->head = queue->tail = 0; /* Flush input queue */ - status |= QP_INTS_ON; - outb_p(status, qp_status); /* Enable interrupts */ - - while (!poll_qp_status()) { - printk(KERN_ERR "Error: Mouse device busy in open_qp()\n"); - qp_count--; - status &= ~(QP_ENABLE|QP_INTS_ON); - outb_p(status, qp_status); - free_irq(QP_IRQ, NULL); - return -EBUSY; - } - - outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */ - return 0; -} - -/* - * Write to the 82C710 mouse device. - */ - -static ssize_t write_qp(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t i = count; - - while (i--) { - char c; - if (!poll_qp_status()) - return -EIO; - get_user(c, buffer++); - outb_p(c, qp_data); - } - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - return count; -} - -static unsigned int poll_qp(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -/* - * Wait for device to send output char and flush any input char. - */ - -#define MAX_RETRIES (60) - -static int poll_qp_status(void) -{ - int retries=0; - - while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE)) - != (QP_DEV_IDLE|QP_TX_IDLE) - && retries < MAX_RETRIES) { - - if (inb_p(qp_status)&(QP_RX_FULL)) - inb_p(qp_data); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((5*HZ + 99) / 100); - retries++; - } - return !(retries==MAX_RETRIES); -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_qp(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -struct file_operations qp_fops = { - owner: THIS_MODULE, - read: read_qp, - write: write_qp, - poll: poll_qp, - open: open_qp, - release: release_qp, - fasync: fasync_qp, -}; - -/* - * Initialize driver. - */ -static struct miscdevice qp_mouse = { - minor: PSMOUSE_MINOR, - name: "QPmouse", - fops: &qp_fops, -}; - -/* - * Function to read register in 82C710. - */ - -static inline unsigned char read_710(unsigned char index) -{ - outb_p(index, 0x390); /* Write index */ - return inb_p(0x391); /* Read the data */ -} - - -/* - * See if we can find a 82C710 device. Read mouse address. - */ - -static int __init probe_qp(void) -{ - outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ - outb_p(0xaa, 0x3fa); /* Inverse of 55 */ - outb_p(0x36, 0x3fa); /* Address the chip */ - outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ - outb_p(0x1b, 0x2fa); /* Inverse of e4 */ - if (read_710(0x0f) != 0xe4) /* Config address found? */ - return 0; /* No: no 82C710 here */ - qp_data = read_710(0x0d)*4; /* Get mouse I/O address */ - qp_status = qp_data+1; - outb_p(0x0f, 0x390); - outb_p(0x0f, 0x391); /* Close config mode */ - return 1; -} - -static char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n"; -static char msg_nomem[] __initdata = KERN_ERR "qpmouse: no queue memory.\n"; - -static int __init qpmouse_init_driver(void) -{ - if (!probe_qp()) - return -EIO; - - printk(msg_banner); - -/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ - queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (queue == NULL) { - printk(msg_nomem); - return -ENOMEM; - } - qp_present = 1; - misc_register(&qp_mouse); - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - return 0; -} - -static void __exit qpmouse_exit_driver(void) -{ - misc_deregister(&qp_mouse); - kfree(queue); -} - -module_init(qpmouse_init_driver); -module_exit(qpmouse_exit_driver); - - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/qtronix.c linux-2.5/drivers/char/qtronix.c --- linux-2.5.23/drivers/char/qtronix.c Wed Jun 19 03:11:52 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.23/drivers/char/rocket.c linux-2.5/drivers/char/rocket.c --- linux-2.5.23/drivers/char/rocket.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/drivers/char/rocket.c Tue Apr 16 03:44:35 2002 @@ -454,11 +454,9 @@ continue; ctlp= sCtlNumToCtlPtr(ctrl); -#ifdef CONFIG_PCI if(ctlp->BusType == isPCI) CtlMask= sPCIGetControllerIntStatus(ctlp); else -#endif CtlMask= sGetControllerIntStatus(ctlp); for (aiop=0; CtlMask; CtlMask >>= 1, aiop++) { if (CtlMask & 1) { @@ -1330,7 +1328,7 @@ { if (tty) sprintf(buf, "%s%d", tty->driver.name, - MINOR(tty->device) - tty->driver.minor_start + + minor(tty->device) - tty->driver.minor_start + tty->driver.name_base); else strcpy(buf, "NULL tty"); @@ -1794,6 +1792,10 @@ str = "8-port Modem"; max_num_aiops = 1; break; + case 0x8: + str = "mysterious 8 port"; + max_num_aiops = 1; + break; default: str = "(unknown/unsupported)"; max_num_aiops = 0; @@ -1872,6 +1874,10 @@ PCI_DEVICE_ID_RP8M, i, &bus, &device_fn)) if(register_PCI(count+boards_found, bus, device_fn)) count++; + if(!pcibios_find_device(PCI_VENDOR_ID_RP, + 0x8, i, &bus, &device_fn)) + if(register_PCI(count+boards_found, bus, device_fn)) + count++; } return(count); } @@ -1916,11 +1922,13 @@ num_aiops); if (rcktpt_io_addr[i] + 0x40 == controller) { *reserved_controller = 1; - request_region(rcktpt_io_addr[i], 68, - "Comtrol Rocketport"); + if (!request_region(rcktpt_io_addr[i], 68, + "Comtrol Rocketport")) + return 0; } else { - request_region(rcktpt_io_addr[i], 64, - "Comtrol Rocketport"); + if (!request_region(rcktpt_io_addr[i], 64, + "Comtrol Rocketport")) + return 0; } return(1); } @@ -2008,7 +2016,11 @@ } if (reserved_controller == 0) - request_region(controller, 4, "Comtrol Rocketport"); + if (!request_region(controller, 4, "Comtrol Rocketport")) + { + rocket_timer.function = 0; + return -EIO; + } /* * Set up the tty driver structure and then register this @@ -2071,6 +2083,7 @@ if (retval < 0) { printk("Couldn't install Rocketport callout driver " "(error %d)\n", -retval); + release_region(controller, 4); return -1; } @@ -2078,6 +2091,7 @@ if (retval < 0) { printk("Couldn't install tty Rocketport driver " "(error %d)\n", -retval); + release_region(controller, 4); return -1; } #ifdef ROCKET_DEBUG_OPEN diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/sc1200wdt.c linux-2.5/drivers/char/sc1200wdt.c --- linux-2.5.23/drivers/char/sc1200wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/sc1200wdt.c Fri Jun 7 02:36:08 2002 @@ -0,0 +1,463 @@ +/* + * National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver + * (c) Copyright 2002 Zwane Mwaikambo , + * All Rights Reserved. + * Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + * Changelog: + * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware. + * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox. + * 20020222 Zwane Mwaikambo Added probing. + * 20020225 Zwane Mwaikambo Added ISAPNP support. + * 20020412 Rob Radez Broke out start/stop functions + * Return proper status instead of temperature warning + * Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls + * Fix CONFIG_WATCHDOG_NOWAYOUT + */ + +#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 */ + +/* 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 char expect_close; +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; + +MODULE_PARM(isapnp, "i"); +MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled"); +#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"); + + + +/* 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); +} + + +static void sc1200wdt_start(void) +{ + unsigned char reg; + + 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); +} + + +static void sc1200wdt_stop(void) +{ + sc1200wdt_write_data(WDTO, 0); +} + + +/* This returns the status of the WDO signal, inactive high. */ +static inline int sc1200wdt_status(void) +{ + unsigned char ret; + + sc1200wdt_read_data(WDST, &ret); + /* If the bit is inactive, the watchdog is enabled, so return + * KEEPALIVEPING which is a bit of a kludge because there's nothing + * else for enabled/disabled status + */ + return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; /* bits 1 - 7 are undefined */ +} + + +static int sc1200wdt_open(struct inode *inode, struct file *file) +{ + /* allow one at a time */ + if (down_trylock(&open_sem)) + return -EBUSY; + + if (timeout > MAX_TIMEOUT) + timeout = MAX_TIMEOUT; + + sc1200wdt_start(); + 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_KEEPALIVEPING | WDIOF_SETTIMEOUT, + firmware_version: 0, + 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_GETBOOTSTATUS: + return put_user(0, (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); + + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; + + if (get_user(options, (int *)arg)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + sc1200wdt_stop(); + retval = 0; + } + + if (options & WDIOS_ENABLECARD) { + sc1200wdt_start(); + retval = 0; + } + + return retval; + } + } +} + + +static int sc1200wdt_release(struct inode *inode, struct file *file) +{ + if (expect_close == 42) { + sc1200wdt_stop(); + 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); + } + up(&open_sem); + expect_close = 0; + + 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 = 42; + } +#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_stop(); + + 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.23/drivers/char/sc520_wdt.c linux-2.5/drivers/char/sc520_wdt.c --- linux-2.5.23/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.23/drivers/char/selection.c linux-2.5/drivers/char/selection.c --- linux-2.5.23/drivers/char/selection.c Wed Jun 19 03:11:53 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.23/drivers/char/serial.c linux-2.5/drivers/char/serial.c --- linux-2.5.23/drivers/char/serial.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/char/serial.c Thu Jun 6 20:09:37 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,11 @@ 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_b0_bt_2_921600, pbn_b1_1_115200, pbn_b1_2_115200, @@ -4340,8 +4373,11 @@ { 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_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ @@ -4467,6 +4503,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 +4523,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" @@ -4677,7 +4720,7 @@ pbn_b0_4_115200 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_2_115200 }, + pbn_b0_bt_2_921600 }, /* Digitan DS560-558, from jimd@esoft.com */ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, @@ -4724,15 +4767,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 +4776,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 +4794,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 +4803,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 +4847,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 +4865,11 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, + /* AFAVLAB serial card, from Harald Welte */ + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, + /* EKF addition for i960 Boards form EKF with serial port */ { PCI_VENDOR_ID_INTEL, 0x1960, 0xE4BF, PCI_ANY_ID, 0, 0, @@ -5414,6 +5423,7 @@ #endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; + serial_driver.name_base = SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; @@ -5425,7 +5435,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -5639,6 +5651,7 @@ info->io_type = req->io_type; info->iomem_base = req->iomem_base; info->iomem_reg_shift = req->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; } autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -5946,6 +5959,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.23/drivers/char/serial167.c linux-2.5/drivers/char/serial167.c --- linux-2.5.23/drivers/char/serial167.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/char/serial167.c Mon Apr 15 02:54:27 2002 @@ -102,6 +102,7 @@ DECLARE_TASK_QUEUE(tq_cyclades); struct tty_driver cy_serial_driver, cy_callout_driver; +static struct console sercons; extern int serial_console; static struct cyclades_port *serial_console_info = NULL; static unsigned int serial_console_cflag = 0; @@ -1261,7 +1262,7 @@ break; } - cli(); + save_flags(flags); cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); @@ -1276,7 +1277,7 @@ up(&tmp_buf_sem); } else { while (1) { - cli(); + save_flags(flags); cli(); c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { @@ -1376,7 +1377,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); printk("cy_throttle ttyS%d\n", info->line); #endif @@ -1412,7 +1413,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); printk("cy_unthrottle ttyS%d\n", info->line); #endif @@ -2394,7 +2395,11 @@ memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); cy_serial_driver.magic = TTY_DRIVER_MAGIC; +#ifdef CONFIG_DEVFS_FS + cy_serial_driver.name = "tts/%d"; +#else cy_serial_driver.name = "ttyS"; +#endif cy_serial_driver.major = TTY_MAJOR; cy_serial_driver.minor_start = 64; cy_serial_driver.num = NR_PORTS; @@ -2408,6 +2413,7 @@ cy_serial_driver.table = serial_table; cy_serial_driver.termios = serial_termios; cy_serial_driver.termios_locked = serial_termios_locked; + cy_serial_driver.console = &sercons; cy_serial_driver.open = cy_open; cy_serial_driver.close = cy_close; cy_serial_driver.write = cy_write; @@ -2429,7 +2435,11 @@ * major number and the subtype code. */ cy_callout_driver = cy_serial_driver; +#ifdef CONFIG_DEVFS_FS + cy_callout_driver.name = "cua/%d"; +#else cy_callout_driver.name = "cua"; +#endif cy_callout_driver.major = TTYAUX_MAJOR; cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/serial_21285.c linux-2.5/drivers/char/serial_21285.c --- linux-2.5.23/drivers/char/serial_21285.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/char/serial_21285.c Sat May 25 19:52:01 2002 @@ -45,6 +45,7 @@ static struct termios *rs285_termios[1]; static struct termios *rs285_termios_locked[1]; +static struct console rs285_cons; static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; static struct tty_struct *rs285_tty; @@ -312,7 +313,9 @@ rs285_driver.table = rs285_table; rs285_driver.termios = rs285_termios; rs285_driver.termios_locked = rs285_termios_locked; - +#ifdef CONFIG_SERIAL_21285_CONSOLE + rs285_driver.console = &rs285_cons; +#endif rs285_driver.open = rs285_open; rs285_driver.close = rs285_close; rs285_driver.write = rs285_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/serial_amba.c linux-2.5/drivers/char/serial_amba.c --- linux-2.5.23/drivers/char/serial_amba.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/char/serial_amba.c Sat May 25 19:52:01 2002 @@ -356,7 +356,7 @@ #ifdef SUPPORT_SYSRQ if (info->sysrq) { if (ch && time_before(jiffies, info->sysrq)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); info->sysrq = 0; goto ignore_char; } @@ -1789,7 +1789,9 @@ ambanormal_driver.table = ambauart_table; ambanormal_driver.termios = ambauart_termios; ambanormal_driver.termios_locked = ambauart_termios_locked; - +#ifdef CONFIG_SERIAL_AMBA_CONSOLE + ambanormal_driver.console = &ambauart_cons; +#endif ambanormal_driver.open = ambauart_open; ambanormal_driver.close = ambauart_close; ambanormal_driver.write = ambauart_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/serial_tx3912.c linux-2.5/drivers/char/serial_tx3912.c --- linux-2.5.23/drivers/char/serial_tx3912.c Wed Jun 19 03:11:55 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.23/drivers/char/serial_tx3912.h linux-2.5/drivers/char/serial_tx3912.h --- linux-2.5.23/drivers/char/serial_tx3912.h Wed Jun 19 03:11:49 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.23/drivers/char/serial_txx927.c linux-2.5/drivers/char/serial_txx927.c --- linux-2.5.23/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.23/drivers/char/sh-sci.c linux-2.5/drivers/char/sh-sci.c --- linux-2.5.23/drivers/char/sh-sci.c Wed Jun 19 03:11:53 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.23/drivers/char/stallion.c linux-2.5/drivers/char/stallion.c --- linux-2.5.23/drivers/char/stallion.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/char/stallion.c Mon Jun 17 22:52:27 2002 @@ -188,14 +188,6 @@ */ static char stl_unwanted[SC26198_RXFIFOSIZE]; -/* - * Keep track of what interrupts we have requested for us. - * We don't need to request an interrupt twice if it is being - * shared with another Stallion board. - */ -static int stl_gotintrs[STL_MAXBRDS]; -static int stl_numintrs; - /*****************************************************************************/ static stlbrd_t *stl_brds[STL_MAXBRDS]; @@ -520,8 +512,7 @@ static int stl_brdinit(stlbrd_t *brdp); static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); -static int stl_mapirq(int irq, char *name); -static int stl_getserial(stlport_t *portp, struct serial_struct *sp); +static int stl_getserial(stlport_t *portp, struct serial_struct *sp); static int stl_setserial(stlport_t *portp, struct serial_struct *sp); static int stl_getbrdstats(combrd_t *bp); static int stl_getportstats(stlport_t *portp, comstats_t *cp); @@ -836,6 +827,7 @@ } kfree(panelp); } + free_irq(brdp->irq, brdp); release_region(brdp->ioaddr1, brdp->iosize1); if (brdp->iosize2 > 0) @@ -844,10 +836,6 @@ kfree(brdp); stl_brds[i] = (stlbrd_t *) NULL; } - - for (i = 0; (i < stl_numintrs); i++) - free_irq(stl_gotintrs[i], NULL); - restore_flags(flags); } @@ -2085,19 +2073,12 @@ static void stl_intr(int irq, void *dev_id, struct pt_regs *regs) { stlbrd_t *brdp; - int i; #if DEBUG printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); #endif - - for (i = 0; (i < stl_nrbrds); i++) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) - continue; - if (brdp->state == 0) - continue; - (* brdp->isr)(brdp); - } + brdp = (stlbrd_t *) dev_id; + (* brdp->isr)(brdp); } /*****************************************************************************/ @@ -2272,39 +2253,6 @@ /*****************************************************************************/ /* - * Map in interrupt vector to this driver. Check that we don't - * already have this vector mapped, we might be sharing this - * interrupt across multiple boards. - */ - -static int __init stl_mapirq(int irq, char *name) -{ - int rc, i; - -#if DEBUG - printk("stl_mapirq(irq=%d,name=%s)\n", irq, name); -#endif - - rc = 0; - for (i = 0; (i < stl_numintrs); i++) { - if (stl_gotintrs[i] == irq) - break; - } - if (i >= stl_numintrs) { - if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) { - printk("STALLION: failed to register interrupt " - "routine for %s irq=%d\n", name, irq); - rc = -ENODEV; - } else { - stl_gotintrs[stl_numintrs++] = irq; - } - } - return(rc); -} - -/*****************************************************************************/ - -/* * Initialize all the ports on a panel. */ @@ -2490,7 +2438,12 @@ brdp->nrpanels = 1; brdp->state |= BRD_FOUND; brdp->hwid = status; - rc = stl_mapirq(brdp->irq, name); + if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) { + printk("STALLION: failed to register interrupt " + "routine for %s irq=%d\n", name, brdp->irq); + rc = -ENODEV; + } + return(rc); } @@ -2695,7 +2648,12 @@ outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); brdp->state |= BRD_FOUND; - i = stl_mapirq(brdp->irq, name); + if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) { + printk("STALLION: failed to register interrupt " + "routine for %s irq=%d\n", name, brdp->irq); + i = -ENODEV; + } + return(i); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/sx.c linux-2.5/drivers/char/sx.c --- linux-2.5.23/drivers/char/sx.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/char/sx.c Tue May 21 22:20:45 2002 @@ -353,9 +353,11 @@ 0xc8000, 0xd8000, 0xe8000}; static int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, 0xc8000, 0xd8000, 0xe8000, 0xa0000}; +static int si1_probe_addrs[]= { 0xd0000}; #define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int)) #define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int)) +#define NR_SI1_ADDRS (sizeof(si1_probe_addrs)/sizeof (int)) /* Set the mask to all-ones. This alas, only supports 32 interrupts. @@ -582,6 +584,8 @@ } } else if (IS_EISA_BOARD(board)) { outb(board->irq<<4, board->eisa_base+0xc02); + } else if (IS_SI1_BOARD(board)) { + write_sx_byte (board, SI1_ISA_RESET, 0); // value does not matter } else { /* Gory details of the SI/ISA board */ write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_SET); @@ -656,6 +660,9 @@ } else if (IS_EISA_BOARD(board)) { write_sx_byte(board, SI2_EISA_OFF, SI2_EISA_VAL); outb((board->irq<<4)|4, board->eisa_base+0xc02); + } else if (IS_SI1_BOARD(board)) { + write_sx_byte (board, SI1_ISA_RESET_CLEAR, 0); + write_sx_byte (board, SI1_ISA_INTCL, 0); } else { /* Don't bug me about the clear_set. I haven't the foggiest idea what it's about -- REW */ @@ -681,6 +688,9 @@ SX_CONF_HOSTIRQ); } else if (IS_EISA_BOARD(board)) { inb(board->eisa_base+0xc03); + } else if (IS_SI1_BOARD(board)) { + write_sx_byte (board, SI1_ISA_INTCL,0); + write_sx_byte (board, SI1_ISA_INTCL_CLEAR,0); } else { switch (board->irq) { case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break; @@ -1690,6 +1700,7 @@ if (IS_SX_BOARD (board)) rc = SX_TYPE_SX; if (IS_CF_BOARD (board)) rc = SX_TYPE_CF; if (IS_SI_BOARD (board)) rc = SX_TYPE_SI; + if (IS_SI1_BOARD (board)) rc = SX_TYPE_SI; if (IS_EISA_BOARD (board)) rc = SX_TYPE_SI; sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc); break; @@ -2184,13 +2195,20 @@ int i; func_enter(); - sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %lx.\n", + sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at %lx.\n", board->hw_base, board->base + SI2_ISA_ID_BASE); if (sx_debug & SX_DEBUG_PROBE) my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8); - if (!IS_EISA_BOARD(board)) { + if (!IS_EISA_BOARD(board) ) { + if( IS_SI1_BOARD(board) ) + { + for (i=0;i<8;i++) { + write_sx_byte (board, SI2_ISA_ID_BASE+7-i,i); + + } + } for (i=0;i<8;i++) { if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) { return 0; @@ -2206,7 +2224,7 @@ board->nports = -1; - /* This resets the processor, and keeps it off the bus. */ + /* This resets the processor, and keeps it off the bus. */ if (!sx_reset (board)) return 0; sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); @@ -2554,6 +2572,21 @@ board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN); board->flags &= ~SX_BOARD_TYPE; board->flags |= SI_ISA_BOARD; + board->irq = sx_irqmask ?-1:0; + + if (probe_si (board)) { + found++; + } else { + my_iounmap (board->hw_base, board->base); + } + } + for (i=0;ihw_base = si1_probe_addrs[i]; + board->base2 = + board->base = (ulong) ioremap(board->hw_base, SI1_ISA_WINDOW_LEN); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SI1_ISA_BOARD; board->irq = sx_irqmask ?-1:0; if (probe_si (board)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/sx.h linux-2.5/drivers/char/sx.h --- linux-2.5.23/drivers/char/sx.h Wed Jun 19 03:11:49 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.23/drivers/char/sxboards.h linux-2.5/drivers/char/sxboards.h --- linux-2.5.23/drivers/char/sxboards.h Wed Jun 19 03:11:45 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.23/drivers/char/sysrq.c linux-2.5/drivers/char/sysrq.c --- linux-2.5.23/drivers/char/sysrq.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/char/sysrq.c Mon Jun 17 22:52:27 2002 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -34,7 +34,6 @@ #include -extern void reset_vc(unsigned int); extern struct list_head super_blocks; /* Whether we react on sysrq keys or just ignore them */ @@ -45,7 +44,8 @@ /* Loglevel sysrq handler */ static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ int i; i = key - '0'; console_loglevel = 7; @@ -62,10 +62,14 @@ /* SAK sysrq handler */ #ifdef CONFIG_VT static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + if (tty) do_SAK(tty); - reset_vc(fg_console); + if ((tty->driver.subtype == SYSTEM_TYPE_CONSOLE) && vc) + reset_vc(vc->display_fg->vc_cons[fg_console]); } static struct sysrq_key_op sysrq_SAK_op = { handler: sysrq_handle_SAK, @@ -77,9 +81,12 @@ /* unraw sysrq handler */ static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { - if (kbd) - kbd->kbdmode = VC_XLATE; + struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + if ((tty->driver.subtype == SYSTEM_TYPE_CONSOLE) && vc) + vc->kbd_table.kbdmode = VC_XLATE; } static struct sysrq_key_op sysrq_unraw_op = { handler: sysrq_handle_unraw, @@ -90,7 +97,8 @@ /* reboot sysrq handler */ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ machine_restart(NULL); } static struct sysrq_key_op sysrq_reboot_op = { @@ -99,8 +107,6 @@ action_msg: "Resetting", }; - - /* SYNC SYSRQ HANDLERS BLOCK */ /* do_emergency_sync helper function */ @@ -186,7 +192,7 @@ * block devices and malfunctional network filesystems. */ -int emergency_sync_scheduled; +volatile int emergency_sync_scheduled; void do_emergency_sync(void) { struct super_block *sb; @@ -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.23/drivers/char/tty_io.c linux-2.5/drivers/char/tty_io.c --- linux-2.5.23/drivers/char/tty_io.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/char/tty_io.c Fri May 3 03:49:06 2002 @@ -156,7 +156,8 @@ extern void sci_console_init(void); extern void tx3912_console_init(void); extern void tx3912_rs_init(void); -extern void hvc_console_init(void); +extern void txx927_console_init(void); +extern void sb1250_serial_console_init(void); #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -692,8 +693,13 @@ { ssize_t ret = 0, written = 0; - if (down_interruptible(&tty->atomic_write)) { - return -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&tty->atomic_write)) + return -EAGAIN; + } + else { + if (down_interruptible(&tty->atomic_write)) + return -ERESTARTSYS; } if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) { lock_kernel(); @@ -1836,9 +1842,6 @@ for_each_task(p) { if ((p->tty == tty) || ((session > 0) && (p->session == session))) { - printk(KERN_NOTICE "SAK: killed process %d" - " (%s): p->session==tty->session\n", - p->pid, p->comm); send_sig(SIGKILL, p, 1); continue; } @@ -1849,9 +1852,6 @@ filp = fcheck_files(p->files, i); if (filp && (filp->f_op == &tty_fops) && (filp->private_data == tty)) { - printk(KERN_NOTICE "SAK: killed process %d" - " (%s): fd#%d opened to the tty\n", - p->pid, p->comm, i); send_sig(SIGKILL, p, 1); break; } @@ -2180,14 +2180,19 @@ * inform about problems etc.. */ #ifdef CONFIG_VT - con_init(); + vt_console_init(); #endif #ifdef CONFIG_AU1000_SERIAL_CONSOLE - au1000_serial_console_init(); +// au1000_serial_console_init(); #endif #ifdef CONFIG_SERIAL_CONSOLE #if (defined(CONFIG_8xx) || defined(CONFIG_8260)) console_8xx_init(); +#elif defined(CONFIG_MAC_SERIAL) && defined(CONFIG_SERIAL) + if (_machine == _MACH_Pmac) + mac_scc_console_init(); + else + serial_console_init(); #elif defined(CONFIG_MAC_SERIAL) mac_scc_console_init(); #elif defined(CONFIG_PARISC) @@ -2235,8 +2240,11 @@ #ifdef CONFIG_SERIAL_TX3912_CONSOLE tx3912_console_init(); #endif -#ifdef CONFIG_HVC_CONSOLE - hvc_console_init(); +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + txx927_console_init(); +#endif +#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE + sb1250_serial_console_init(); #endif } @@ -2245,9 +2253,8 @@ static struct tty_driver dev_ptmx_driver; #endif #ifdef CONFIG_VT -extern void con_init_devfs (void); -extern void console_map_init(void); static struct tty_driver dev_console_driver; +extern int vty_init(void); #endif /* @@ -2287,13 +2294,6 @@ if (tty_register_driver(&dev_syscons_driver)) panic("Couldn't register /dev/console driver\n"); - /* console calls tty_register_driver() before kmalloc() works. - * Thus, we can't devfs_register() then. Do so now, instead. - */ -#ifdef CONFIG_VT - con_init_devfs(); -#endif - #ifdef CONFIG_UNIX98_PTYS dev_ptmx_driver = dev_tty_driver; dev_ptmx_driver.driver_name = "/dev/ptmx"; @@ -2317,10 +2317,7 @@ if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/tty0 driver\n"); - - vcs_init(); - kbd_init(); - console_map_init(); + vty_init(); #endif #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/vc_screen.c linux-2.5/drivers/char/vc_screen.c --- linux-2.5.23/drivers/char/vc_screen.c Wed Jun 19 03:11:51 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.23/drivers/char/vme_scc.c linux-2.5/drivers/char/vme_scc.c --- linux-2.5.23/drivers/char/vme_scc.c Wed Jun 19 03:11:45 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.23/drivers/char/vt.c linux-2.5/drivers/char/vt.c --- linux-2.5.23/drivers/char/vt.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/char/vt.c Tue Jun 4 15:21:35 2002 @@ -1,1316 +1,1896 @@ /* - * linux/drivers/char/vt.c + * vt.c - Built-in console device * - * Copyright (C) 1992 obz under the linux copyright + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + * + * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics + * Chars, and VT100 enhancements by Peter MacDonald. + * + * Copy and paste function by Andrew Haylett, + * some enhancements by Alessandro Rubini. + * + * Code to check for different video-cards mostly by Galen Hunt, + * + * + * Rudimentary ISO 10646/Unicode/UTF-8 character set support by + * Markus Kuhn, . + * + * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 + * Resizing of consoles, aeb, 940926 + * + * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 + * + * + * User-defined bell sound, new setterm control sequences and printk + * redirection by Martin Mares 19-Nov-95 + * + * APM screenblank bug fixed Takashi Manabe + * + * Merge with the abstract console driver by Geert Uytterhoeven + * , Jan 1997. + * + * Original m68k console driver modifications by + * + * - Arno Griffioen + * - David Carter + * + * Note that the abstract console driver allows all consoles to be of + * potentially different sizes, so the following variables depend on the + * current console (currcons): * - * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 - * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 - * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 - * Some code moved for less code duplication - Andi Kleen - Mar 1997 - * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 + * - video_num_columns + * - video_num_lines + * - video_size_row + * - can_do_color + * + * The abstract console driver provides a generic interface for a text + * console. It supports VGA text mode, frame buffer based graphical consoles + * and special graphics processors that are only accessible through some + * registers (e.g. a TMS340x0 GSP). + * + * The interface to the hardware is specified using a special structure + * (struct consw) which contains function pointers to console operations + * (see for more information). + * + * Support for changeable cursor shape + * by Pavel Machek , August 1997 + * + * Ported to i386 and con_scrolldelta fixed + * by Emmanuel Marty , April 1998 + * + * Resurrected character buffers in videoram plus lots of other trickery + * by Martin Mares , July 1998 + * + * Removed old-style timers, introduced console_timer, made timer + * deletion SMP-safe. 17Jun00, Andrew Morton + * + * Removed console_lock, enabled interrupts across all console operations + * 13 March 2001, Andrew Morton */ -#include -#include -#include +#include #include #include -#include +#include #include -#include -#include #include +#include +#include #include #include -#include +#include #include - -#include -#include - -#include +#include +#include #include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_FB_COMPAT_XPMAC -#include -#endif /* CONFIG_FB_COMPAT_XPMAC */ +#include +#include +#include +#include -char vt_dont_switch; -extern struct tty_driver console_driver; +#include "console_macros.h" -#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) -#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) +const struct consw *conswitchp; -/* - * Console (vt and kd) routines, as defined by USL SVR4 manual, and by - * experimentation and study of X386 SYSV handling. - * - * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and - * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, - * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will - * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to - * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using - * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing - * to the current console is done by the main ioctl code. +/* A bitmap for codes <32. A bit of 1 indicates that the code + * corresponding to that bit number invokes some special action + * (such as cursor movement) and should not be displayed as a + * glyph unless the disp_ctrl mode is explicitly enabled. */ +#define CTRL_ACTION 0x0d00ff81 +#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ -struct vt_struct *vt_cons[MAX_NR_CONSOLES]; +extern void vcs_make_devfs (unsigned int index, int unregister); +extern void console_map_init(void); -/* Keyboard type: Default is KB_101, but can be set by machine - * specific code. - */ -unsigned char keyboard_type = KB_101; +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +static struct tty_struct *console_table[MAX_NR_CONSOLES]; +static struct termios *console_termios[MAX_NR_CONSOLES]; +static struct termios *console_termios_locked[MAX_NR_CONSOLES]; -#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); +#ifndef VT_SINGLE_DRIVER +static const struct consw *con_driver_map[MAX_NR_CONSOLES]; #endif -unsigned int video_font_height; -unsigned int default_font_height; -unsigned int video_scan_lines; +static void con_flush_chars(struct tty_struct *tty); +static void unblank_screen_t(unsigned long private); + +static int printable; /* Is console ready for printing? */ + +/* + * the default colour table, for VGA+ colour systems + */ +int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, + 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; +int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, + 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; +int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, + 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; + +unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 }; +int do_poke_blanked_console; /* - * these are the valid i/o ports we're allowed to change. they map all the - * video ports + * fg_console is the current virtual console, + * kmsg_redirect is the console for kernel messages, */ -#define GPFIRST 0x3b4 -#define GPLAST 0x3df -#define GPNUM (GPLAST - GPFIRST + 1) +int fg_console; +int kmsg_redirect; /* - * Generates sound of some frequency for some number of clock ticks - * - * If freq is 0, will turn off sound, else will turn it on for that time. - * If msec is 0, will return immediately, else will sleep for msec time, then - * turn sound off. - * - * We also return immediately, which is what was implied within the X - * comments - KDMKTONE doesn't put the process to sleep. + * Hook so that the power management routines can (un)blank + * the console on our behalf. + */ +int (*console_blank_hook)(int); + +/* + * Low-Level Functions */ +#ifdef VT_BUF_VRAM_ONLY +#define DO_UPDATE 0 +#else +#define DO_UPDATE IS_VISIBLE +#endif -#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ - || (defined(__mips__) && defined(CONFIG_ISA)) \ - || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ - || defined(__x86_64__) +static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data); +static struct pm_dev *pm_con; -static void -kd_nosound(unsigned long ignored) + +void respond_string(const char * p, struct tty_struct * tty) { - /* disable counter 2 */ - outb(inb_p(0x61)&0xFC, 0x61); - return; + while (*p) { + tty_insert_flip_char(tty, *p, 0); + p++; + } + con_schedule_flip(tty); } -void -_kd_mksound(unsigned int hz, unsigned int ticks) +/* + * Console cursor handling + */ +void add_softcursor(struct vc_data *vc) { - static struct timer_list sound_timer = { function: kd_nosound }; - unsigned int count = 0; - unsigned long flags; + int i = scr_readw((u16 *) pos); u32 type = cursor_type; - if (hz > 20 && hz < 32767) - count = 1193180 / hz; - - save_flags(flags); - cli(); - del_timer(&sound_timer); - if (count) { - /* enable counter 2 */ - outb_p(inb_p(0x61)|3, 0x61); - /* set command for counter 2, 2 byte write */ - outb_p(0xB6, 0x43); - /* select desired HZ */ - outb_p(count & 0xff, 0x42); - outb((count >> 8) & 0xff, 0x42); - - if (ticks) { - sound_timer.expires = jiffies+ticks; - add_timer(&sound_timer); - } - } else - kd_nosound(0); - restore_flags(flags); - return; + if (!(type & 0x10)) return; + if (softcursor_original != -1) return; + softcursor_original = i; + i |= ((type >> 8) & 0xff00 ); + i ^= ((type) & 0xff00 ); + if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) + i ^= 0x7000; + if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; + scr_writew(i, (u16 *) pos); + if (DO_UPDATE) + sw->con_putc(vc, i, y, x); } -#else +void hide_cursor(struct vc_data *vc) +{ + if (cons_num == sel_cons) + clear_selection(); + if (softcursor_original != -1) { + scr_writew(softcursor_original,(u16 *) pos); + if (DO_UPDATE) + sw->con_putc(vc, softcursor_original, y, x); + softcursor_original = -1; + } + sw->con_cursor(vc, CM_ERASE); +} -void -_kd_mksound(unsigned int hz, unsigned int ticks) +void set_cursor(struct vc_data *vc) { + if (!IS_VISIBLE || vc->display_fg->vt_blanked || vcmode == KD_GRAPHICS) + return; + if (dectcem) { + if (cons_num == sel_cons) + clear_selection(); + add_softcursor(vc); + if ((cursor_type & 0x0f) != 1) + sw->con_cursor(vc, CM_DRAW); + } else + hide_cursor(vc); } -#endif +/* + * gotoxy() must verify all boundaries, because the arguments + * might also be negative. If the given position is out of + * bounds, the cursor is placed at the nearest margin. + */ +void gotoxy(struct vc_data *vc, int new_x, int new_y) +{ + int min_y, max_y; + + if (new_x < 0) + x = 0; else + if (new_x >= video_num_columns) + x = video_num_columns - 1; + else + x = new_x; + if (decom) { + min_y = top; + max_y = bottom; + } else { + min_y = 0; + max_y = video_num_lines; + } + if (new_y < min_y) + y = min_y; + else if (new_y >= max_y) + y = max_y - 1; + else + y = new_y; + pos = origin + y*video_size_row + (x<<1); + need_wrap = 0; +} -int _kbd_rate(struct kbd_repeat *rep) +/* for absolute user moves, when decom is set */ +void gotoxay(struct vc_data *vc, int new_x, int new_y) { - return -EINVAL; + gotoxy(vc, new_x, decom ? (top+new_y) : new_y); } -void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; -int (*kbd_rate)(struct kbd_repeat *rep) = _kbd_rate; +/* + * Palettes + */ -#define i (tmp.kb_index) -#define s (tmp.kb_table) -#define v (tmp.kb_value) -static inline int -do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd) +void set_palette(struct vc_data *vc) { - struct kbentry tmp; - ushort *key_map, val, ov; + if (vcmode != KD_GRAPHICS) + sw->con_set_palette(vc, color_table); +} - if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) - return -EFAULT; - if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS) - return -EINVAL; +void reset_palette(struct vc_data *vc) +{ + int j, k; - switch (cmd) { - case KDGKBENT: - key_map = key_maps[s]; - if (key_map) { - val = U(key_map[i]); - if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) - val = K_HOLE; - } else - val = (i ? K_HOLE : K_NOSUCHMAP); - return put_user(val, &user_kbe->kb_value); - case KDSKBENT: - if (!perm) - return -EPERM; - if (!i && v == K_NOSUCHMAP) { - /* disallocate map */ - key_map = key_maps[s]; - if (s && key_map) { - key_maps[s] = 0; - if (key_map[0] == U(K_ALLOCATED)) { - kfree(key_map); - keymap_count--; - } - } - break; - } + for (j=k=0; j<16; j++) { + palette[k++] = default_red[j]; + palette[k++] = default_grn[j]; + palette[k++] = default_blu[j]; + } + set_palette(vc); +} - if (KTYP(v) < NR_TYPES) { - if (KVAL(v) > max_vals[KTYP(v)]) - return -EINVAL; - } else - if (kbd->kbdmode != VC_UNICODE) - return -EINVAL; - - /* ++Geert: non-PC keyboards may generate keycode zero */ -#if !defined(__mc68000__) && !defined(__powerpc__) - /* assignment to entry 0 only tests validity of args */ - if (!i) - break; -#endif +/* + * Load palette into the DAC registers. arg points to a colour + * map, 3 bytes per colour, 16 colours, range from 0 to 255. + */ - if (!(key_map = key_maps[s])) { - int j; +static int set_get_cmap(unsigned char *arg, int set) +{ + struct vc_data *vc; + int i, j, k; - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && - !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - key_map = (ushort *) kmalloc(sizeof(plain_map), - GFP_KERNEL); - if (!key_map) - return -ENOMEM; - key_maps[s] = key_map; - key_map[0] = U(K_ALLOCATED); - for (j = 1; j < NR_KEYS; j++) - key_map[j] = U(K_HOLE); - keymap_count++; + for (i = 0; i < 16; i++) + if (set) { + get_user(default_red[i], arg++); + get_user(default_grn[i], arg++); + get_user(default_blu[i], arg++); + } else { + put_user(default_red[i], arg++); + put_user(default_grn[i], arg++); + put_user(default_blu[i], arg++); + } + if (set) { + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc = vt_cons->vc_cons[i]; + if (vc) { + for (j = k = 0; j < 16; j++) { + palette[k++] = default_red[j]; + palette[k++] = default_grn[j]; + palette[k++] = default_blu[j]; + } + set_palette(vc); + } } - ov = U(key_map[i]); - if (v == ov) - break; /* nothing to do */ - /* - * Attention Key. - */ - if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - key_map[i] = U(v); - if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) - compute_shiftstate(); - break; } return 0; } -#undef i -#undef s -#undef v -static inline int -do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm) +int con_set_cmap(unsigned char *arg) { - struct kbkeycode tmp; - int kc = 0; + return set_get_cmap (arg,1); +} - if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) - return -EFAULT; - switch (cmd) { - case KDGETKEYCODE: - kc = getkeycode(tmp.scancode); - if (kc >= 0) - kc = put_user(kc, &user_kbkc->keycode); - break; - case KDSETKEYCODE: - if (!perm) - return -EPERM; - kc = setkeycode(tmp.scancode, tmp.keycode); - break; - } - return kc; -} - -static inline int -do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm) -{ - struct kbsentry tmp; - char *p; - u_char *q; - int sz; - int delta; - char *first_free, *fj, *fnw; - int i, j, k; +int con_get_cmap(unsigned char *arg) +{ + return set_get_cmap (arg,0); +} - /* we mostly copy too much here (512bytes), but who cares ;) */ - if (copy_from_user(&tmp, user_kdgkb, sizeof(struct kbsentry))) - return -EFAULT; - tmp.kb_string[sizeof(tmp.kb_string)-1] = '\0'; - if (tmp.kb_func >= MAX_NR_FUNC) - return -EINVAL; - i = tmp.kb_func; +/* + * Functions to handle console scrolling. + */ +static inline void scrolldelta(struct vt_struct *vt, int lines) +{ + vt->scrollback_delta += lines; + + schedule_task(&vt->vt_tq); +} - switch (cmd) { - case KDGKBSENT: - sz = sizeof(tmp.kb_string) - 1; /* sz should have been - a struct member */ - q = user_kdgkb->kb_string; - p = func_table[i]; - if(p) - for ( ; *p && sz; p++, sz--) - if (put_user(*p, q++)) - return -EFAULT; - if (put_user('\0', q)) - return -EFAULT; - return ((p && *p) ? -EOVERFLOW : 0); - case KDSKBSENT: - if (!perm) - return -EPERM; - - q = func_table[i]; - first_free = funcbufptr + (funcbufsize - funcbufleft); - for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) - ; - if (j < MAX_NR_FUNC) - fj = func_table[j]; - else - fj = first_free; - - delta = (q ? -strlen(q) : 1) + strlen(tmp.kb_string); - if (delta <= funcbufleft) { /* it fits in current buf */ - if (j < MAX_NR_FUNC) { - memmove(fj + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] += delta; - } - if (!q) - func_table[i] = fj; - funcbufleft -= delta; - } else { /* allocate a larger buffer */ - sz = 256; - while (sz < funcbufsize - funcbufleft + delta) - sz <<= 1; - fnw = (char *) kmalloc(sz, GFP_KERNEL); - if(!fnw) - return -ENOMEM; - - if (!q) - func_table[i] = fj; - if (fj > funcbufptr) - memmove(fnw, funcbufptr, fj - funcbufptr); - for (k = 0; k < j; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr); - - if (first_free > fj) { - memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; - } - if (funcbufptr != func_buf) - kfree(funcbufptr); - funcbufptr = fnw; - funcbufleft = funcbufleft - delta + sz - funcbufsize; - funcbufsize = sz; - } - strcpy(func_table[i], tmp.kb_string); - break; - } - return 0; +void scrollback(struct vc_data *vc, int lines) +{ + if (!lines) + lines = video_num_lines/2; + scrolldelta(vc->display_fg, -lines); } -static inline int -do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm) +void scrollfront(struct vc_data *vc, int lines) { - struct consolefontdesc cfdarg; - struct console_font_op op; - int i; + if (!lines) + lines = video_num_lines/2; + scrolldelta(vc->display_fg, lines); +} - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) - return -EFAULT; - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); - case GIO_FONTX: { - op.op = KD_FONT_OP_GET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); - if (i) - return i; - cfdarg.charheight = op.height; - cfdarg.charcount = op.charcount; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) - return -EFAULT; - return 0; - } - } - return -EINVAL; +void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) +{ + unsigned short *d, *s; + + if (t+nr >= b) + nr = b - t; + if (b > video_num_lines || t >= b || nr < 1) + return; + if (IS_VISIBLE && sw->con_scroll(vc, t, b, SM_UP, nr)) + return; + d = (unsigned short *) (origin+video_size_row*t); + s = (unsigned short *) (origin+video_size_row*(t+nr)); + scr_memcpyw(d, s, (b-t-nr) * video_size_row); + scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr); } -static inline int -do_unimap_ioctl(int cmd, struct unimapdesc *user_ud,int perm) +void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) { - struct unimapdesc tmp; - int i = 0; + unsigned short *s; + unsigned int step; - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - if (tmp.entries) { - i = verify_area(VERIFY_WRITE, tmp.entries, - tmp.entry_ct*sizeof(struct unipair)); - if (i) return i; - } - switch (cmd) { - case PIO_UNIMAP: - if (!perm) - return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries); - case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); - } - return 0; + if (t+nr >= b) + nr = b - t; + if (b > video_num_lines || t >= b || nr < 1) + return; + if (IS_VISIBLE && sw->con_scroll(vc, t, b, SM_DOWN, nr)) + return; + s = (unsigned short *) (origin+video_size_row*t); + step = video_num_columns * nr; + scr_memmovew(s + step, s, (b-t-nr)*video_size_row); + scr_memsetw(s, video_erase_char, 2*step); +} + +/* + * Console attribute handling. Structure of attributes is hardware-dependent + */ +void default_attr(struct vc_data *vc) +{ + intensity = 1; + underline = 0; + reverse = 0; + blink = 0; + color = def_color; } /* - * We handle the console-specific ioctl's here. We allow the - * capability to modify any console, not just the fg_console. + * ++roman: I completely changed the attribute format for monochrome + * mode (!can_do_color). The formerly used MDA (monochrome display + * adapter) format didn't allow the combination of certain effects. + * Now the attribute is just a bit vector: + * Bit 0..1: intensity (0..2) + * Bit 2 : underline + * Bit 3 : reverse + * Bit 7 : blink */ -int vt_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) { - int i, perm; - unsigned int console; - unsigned char ucval; - struct kbd_struct * kbd; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; + if (sw->con_build_attr) + return sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse); - console = vt->vc_num; +#ifndef VT_BUF_VRAM_ONLY + { + u8 a = color; + if (!can_do_color) + return _intensity | + (_underline ? 4 : 0) | + (_reverse ? 8 : 0) | + (_blink ? 0x80 : 0); + if (_underline) + a = (a & 0xf0) | ulcolor; + else if (_intensity == 0) + a = (a & 0xf0) | halfcolor; + if (_reverse) + a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); + if (_blink) + a ^= 0x80; + if (_intensity == 2) + a ^= 0x08; + if (hi_font_mask == 0x100) + a <<= 1; + return a; + } +#else + return 0; +#endif +} - if (!vc_cons_allocated(console)) /* impossible? */ - return -ENOIOCTLCMD; +void update_attr(struct vc_data *vc) +{ + attr = build_attr(vc, color, intensity, blink, underline, reverse ^ decscnm); + video_erase_char = (build_attr(vc, color, intensity, 0, 0, decscnm) << 8) | ' '; +} - /* - * To have permissions to do most of the vt ioctls, we either have - * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. - */ - perm = 0; - if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) - perm = 1; - - kbd = kbd_table + console; - switch (cmd) { - case KIOCSOUND: - if (!perm) - return -EPERM; - if (arg) - arg = 1193180 / arg; - kd_mksound(arg, 0); - return 0; +/* + * Character management + */ +void insert_char(struct vc_data *vc, unsigned int nr) +{ + unsigned short *p, *q = (unsigned short *) pos; - case KDMKTONE: - if (!perm) - return -EPERM; - { - unsigned int ticks, count; - - /* - * Generate the tone for the appropriate number of ticks. - * If the time is zero, turn off sound ourselves. - */ - ticks = HZ * ((arg >> 16) & 0xffff) / 1000; - count = ticks ? (arg & 0xffff) : 0; - if (count) - count = 1193180 / count; - kd_mksound(count, ticks); - return 0; + p = q + video_num_columns - nr - x; + while (--p >= q) + scr_writew(scr_readw(p), p + nr); + scr_memsetw(q, video_erase_char, nr*2); + need_wrap = 0; + if (DO_UPDATE) { + unsigned short oldattr = attr; + + sw->con_bmove(vc, y, x, y, x+nr, 1, video_num_columns-x-nr); + attr = video_erase_char >> 8; + while (nr--) + sw->con_putc(vc, video_erase_char, y, x+nr); + attr = oldattr; } +} - case KDGKBTYPE: - /* - * this is naive. - */ - ucval = keyboard_type; - goto setchar; +void delete_char(struct vc_data *vc, unsigned int nr) +{ + unsigned int i = x; + unsigned short *p = (unsigned short *) pos; -#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) - /* - * These cannot be implemented on any machine that implements - * ioperm() in user level (such as Alpha PCs). - */ - case KDADDIO: - case KDDELIO: - /* - * KDADDIO and KDDELIO may be able to add ports beyond what - * we reject here, but to be safe... - */ - if (arg < GPFIRST || arg > GPLAST) - return -EINVAL; - return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; - - case KDENABIO: - case KDDISABIO: - return sys_ioperm(GPFIRST, GPNUM, - (cmd == KDENABIO)) ? -ENXIO : 0; -#endif + while (++i <= video_num_columns - nr) { + scr_writew(scr_readw(p+nr), p); + p++; + } + scr_memsetw(p, video_erase_char, nr*2); + need_wrap = 0; + if (DO_UPDATE) { + unsigned short oldattr = attr; + sw->con_bmove(vc, y, x+nr, y, x, 1, + video_num_columns-x-nr); + attr = video_erase_char >> 8; + while (nr--) + sw->con_putc(vc, video_erase_char, y, + video_num_columns-1-nr); + attr = oldattr; + } +} - /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ - - case KDKBDREP: - { - struct kbd_repeat kbrep; - - if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; +void insert_line(struct vc_data *vc, unsigned int nr) +{ + scrdown(vc, y, bottom, nr); + need_wrap = 0; +} - if (copy_from_user(&kbrep, (void *)arg, - sizeof(struct kbd_repeat))) - return -EFAULT; - if ((i = kbd_rate( &kbrep ))) - return i; - if (copy_to_user((void *)arg, &kbrep, - sizeof(struct kbd_repeat))) - return -EFAULT; - return 0; - } +void delete_line(struct vc_data *vc, unsigned int nr) +{ + scrup(vc, y, bottom, nr); + need_wrap = 0; +} - case KDSETMODE: - /* - * currently, setting the mode from KD_TEXT to KD_GRAPHICS - * doesn't do a whole lot. i'm not sure if it should do any - * restoration of modes or what... - */ - if (!perm) - return -EPERM; - switch (arg) { - case KD_GRAPHICS: - break; - case KD_TEXT0: - case KD_TEXT1: - arg = KD_TEXT; - case KD_TEXT: - break; - default: - return -EINVAL; - } - if (vt_cons[console]->vc_mode == (unsigned char) arg) - return 0; - vt_cons[console]->vc_mode = (unsigned char) arg; - if (console != fg_console) - return 0; - /* - * explicitly blank/unblank the screen if switching modes - */ - if (arg == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); - return 0; +/* + * Functions that manage whats displayed on the screen + */ +void set_origin(struct vc_data *vc) +{ + if (!IS_VISIBLE || !sw->con_set_origin || !sw->con_set_origin(vc)) + origin = (unsigned long) screenbuf; + visible_origin = origin; + scr_end = origin + screenbuf_size; + pos = origin + video_size_row*y + 2*x; +} - case KDGETMODE: - ucval = vt_cons[console]->vc_mode; - goto setint; - - case KDMAPDISP: - case KDUNMAPDISP: - /* - * these work like a combination of mmap and KDENABIO. - * this could be easily finished. - */ - return -EINVAL; +inline void clear_region(struct vc_data *vc,int sx,int sy,int width,int height) +{ + /* Clears the video memory, not the screen buffer */ + if (DO_UPDATE && sw->con_clear) + return sw->con_clear(vc, sy, sx, height, width); +} - case KDSKBMODE: - if (!perm) - return -EPERM; - switch(arg) { - case K_RAW: - kbd->kbdmode = VC_RAW; - break; - case K_MEDIUMRAW: - kbd->kbdmode = VC_MEDIUMRAW; - break; - case K_XLATE: - kbd->kbdmode = VC_XLATE; - compute_shiftstate(); - break; - case K_UNICODE: - kbd->kbdmode = VC_UNICODE; - compute_shiftstate(); - break; - default: - return -EINVAL; - } - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - return 0; +inline void save_screen(struct vc_data *vc) +{ + if (sw->con_save_screen) + sw->con_save_screen(vc); +} - case KDGKBMODE: - ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : - (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : - (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : - K_XLATE); - goto setint; - - /* this could be folded into KDSKBMODE, but for compatibility - reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ - case KDSKBMETA: - switch(arg) { - case K_METABIT: - clr_vc_kbd_mode(kbd, VC_META); - break; - case K_ESCPREFIX: - set_vc_kbd_mode(kbd, VC_META); +void do_update_region(struct vc_data *vc, unsigned long start, int count) +{ +#ifndef VT_BUF_VRAM_ONLY + unsigned int xx, yy, offset; + u16 *p; + + p = (u16 *) start; + if (!sw->con_getxy) { + offset = (start - origin) / 2; + xx = offset % video_num_columns; + yy = offset / video_num_columns; + } else { + int nxx, nyy; + start = sw->con_getxy(vc, start, &nxx, &nyy); + xx = nxx; yy = nyy; + } + for(;;) { + u16 attrib = scr_readw(p) & 0xff00; + int startx = xx; + u16 *q = p; + while (xx < video_num_columns && count) { + if (attrib != (scr_readw(p) & 0xff00)) { + if (p > q) + sw->con_putcs(vc, q, p-q, yy, startx); + startx = xx; + q = p; + attrib = scr_readw(p) & 0xff00; + } + p++; + xx++; + count--; + } + if (p > q) + sw->con_putcs(vc, q, p-q, yy, startx); + if (!count) break; - default: - return -EINVAL; + xx = 0; + yy++; + if (sw->con_getxy) { + p = (u16 *)start; + start = sw->con_getxy(vc, start, NULL, NULL); } - return 0; + } +#endif +} - case KDGKBMETA: - ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); - setint: - return put_user(ucval, (int *)arg); - - case KDGETKEYCODE: - case KDSETKEYCODE: - if(!capable(CAP_SYS_TTY_CONFIG)) - perm=0; - return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); - - case KDGKBENT: - case KDSKBENT: - return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); - - case KDGKBSENT: - case KDSKBSENT: - return do_kdgkb_ioctl(cmd, (struct kbsentry *)arg, perm); +void update_region(struct vc_data *vc, unsigned long start, int count) +{ + if (DO_UPDATE) { + hide_cursor(vc); + do_update_region(vc, start, count); + set_cursor(vc); + } +} - case KDGKBDIACR: - { - struct kbdiacrs *a = (struct kbdiacrs *)arg; +inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) +{ + unsigned short *p; - if (put_user(accent_table_size, &a->kb_cnt)) - return -EFAULT; - if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) - return -EFAULT; - return 0; - } + if (!viewed) + p = (unsigned short *)(origin + offset); + else if (!sw->con_screen_pos) + p = (unsigned short *)(visible_origin + offset); + else + p = sw->con_screen_pos(vc, offset); + return p; +} - case KDSKBDIACR: - { - struct kbdiacrs *a = (struct kbdiacrs *)arg; - unsigned int ct; +/* Note: inverting the screen twice should revert to the original state */ +void invert_screen(struct vc_data *vc, int offset, int count, int viewed) +{ + unsigned short *p; - if (!perm) - return -EPERM; - if (get_user(ct,&a->kb_cnt)) - return -EFAULT; - if (ct >= MAX_DIACR) - return -EINVAL; - accent_table_size = ct; - if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) - return -EFAULT; - return 0; + count /= 2; + p = screenpos(vc, offset, viewed); + if (sw->con_invert_region) + sw->con_invert_region(vc, p, count); +#ifndef VT_BUF_VRAM_ONLY + else { + u16 *q = p; + int cnt = count; + u16 a; + + if (!can_do_color) { + while (cnt--) { + a = scr_readw(q); + a ^= 0x0800; + scr_writew(a, q); + q++; + } + } else if (hi_font_mask == 0x100) { + while (cnt--) { + a = scr_readw(q); + a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); + scr_writew(a, q); + q++; + } + } else { + while (cnt--) { + a = scr_readw(q); + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); + scr_writew(a, q); + q++; + } + } } +#endif + if (DO_UPDATE) + do_update_region(vc, (unsigned long) p, count); +} - /* the ioctls below read/set the flags usually shown in the leds */ - /* don't use them - they will go away without warning */ - case KDGKBLED: - ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); - goto setchar; - - case KDSKBLED: - if (!perm) - return -EPERM; - if (arg & ~0x77) - return -EINVAL; - kbd->ledflagstate = (arg & 7); - kbd->default_ledflagstate = ((arg >> 4) & 7); - set_leds(); - return 0; - - /* the ioctls below only set the lights, not the functions */ - /* for those, see KDGKBLED and KDSKBLED above */ - case KDGETLED: - ucval = getledstate(); - setchar: - return put_user(ucval, (char*)arg); - - case KDSETLED: - if (!perm) - return -EPERM; - setledstate(kbd, arg); - return 0; +/* Redrawing of screen */ +void update_screen(struct vc_data *vc) +{ + int update; - /* - * A process can indicate its willingness to accept signals - * generated by pressing an appropriate key combination. - * Thus, one can have a daemon that e.g. spawns a new console - * upon a keypress and then changes to it. - * Probably init should be changed to do this (and have a - * field ks (`keyboard signal') in inittab describing the - * desired action), so that the number of background daemons - * does not increase. - */ - case KDSIGACCEPT: - { - extern int spawnpid, spawnsig; - if (!perm || !capable(CAP_KILL)) - return -EPERM; - if (arg < 1 || arg > _NSIG || arg == SIGKILL) - return -EINVAL; - spawnpid = current->pid; - spawnsig = arg; - return 0; - } + if (!vc) return; - case VT_SETMODE: - { - struct vt_mode tmp; + hide_cursor(vc); + set_origin(vc); - if (!perm) - return -EPERM; - if (copy_from_user(&tmp, (void*)arg, sizeof(struct vt_mode))) - return -EFAULT; - if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) - return -EINVAL; - vt_cons[console]->vt_mode = tmp; - /* the frsig is ignored, so we set it to 0 */ - vt_cons[console]->vt_mode.frsig = 0; - vt_cons[console]->vt_pid = current->pid; - /* no switch is required -- saw@shade.msu.ru */ - vt_cons[console]->vt_newvt = -1; - return 0; - } + update = sw->con_switch(vc); + set_palette(vc); - case VT_GETMODE: - return copy_to_user((void*)arg, &(vt_cons[console]->vt_mode), - sizeof(struct vt_mode)) ? -EFAULT : 0; + if (update && vcmode != KD_GRAPHICS) + do_update_region(vc, origin, screenbuf_size/2); - /* - * Returns global vt state. Note that VT 0 is always open, since - * it's an alias for the current VT, and people can't use it here. - * We cannot return state for more than 16 VTs, since v_state is short. - */ - case VT_GETSTATE: - { - struct vt_stat *vtstat = (struct vt_stat *)arg; - unsigned short state, mask; + set_cursor(vc); +} - if (put_user(fg_console + 1, &vtstat->v_active)) - return -EFAULT; - state = 1; /* /dev/tty0 is always open */ - for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) - if (VT_IS_IN_USE(i)) - state |= mask; - return put_user(state, &vtstat->v_state); +/* used by selection: complement pointer position */ +void complement_pos(struct vc_data *vc, int offset) +{ + static unsigned short *p; + static unsigned short old; + static unsigned short oldx, oldy; + + if (p) { + scr_writew(old, p); + if (DO_UPDATE) + sw->con_putc(vc, old, oldy, oldx); + } + if (offset == -1) + p = NULL; + else { + unsigned short new; + p = screenpos(vc, offset, 1); + old = scr_readw(p); + new = old ^ complement_mask; + scr_writew(new, p); + if (DO_UPDATE) { + oldx = (offset >> 1) % video_num_columns; + oldy = (offset >> 1) / video_num_columns; + sw->con_putc(vc, new, oldy, oldx); + } } +} - /* - * Returns the first available (non-opened) console. - */ - case VT_OPENQRY: - for (i = 0; i < MAX_NR_CONSOLES; ++i) - if (! VT_IS_IN_USE(i)) - break; - ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; - goto setint; +/* + * Screen blanking + */ - /* - * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, - * with num >= 1 (switches to vt 0, our console, are not allowed, just - * to preserve sanity). - */ - case VT_ACTIVATE: - if (!perm) - return -EPERM; - if (arg == 0 || arg > MAX_NR_CONSOLES) - return -ENXIO; - arg--; - i = vc_allocate(arg); - if (i) - return i; - set_console(arg); - return 0; +/* This is a timer handler */ +static void powerdown_screen(unsigned long private) +{ + struct vt_struct *vt = (struct vt_struct *) private; + struct vc_data *vc = vt->vc_cons[fg_console]; - /* - * wait until the specified VT has been activated - */ - case VT_WAITACTIVE: - if (!perm) - return -EPERM; - if (arg == 0 || arg > MAX_NR_CONSOLES) - return -ENXIO; - return vt_waitactive(arg-1); + vt->timer.function = unblank_screen_t; /* - * If a vt is under process control, the kernel will not switch to it - * immediately, but postpone the operation until the process calls this - * ioctl, allowing the switch to complete. - * - * According to the X sources this is the behavior: - * 0: pending switch-from not OK - * 1: pending switch-from OK - * 2: completed switch-to OK + * Power down if currently suspended (1 or 2), + * suspend if currently blanked (0), + * else do nothing (i.e. already powered down (3)). + * Called only if powerdown features are allowed. */ - case VT_RELDISP: - if (!perm) - return -EPERM; - if (vt_cons[console]->vt_mode.mode != VT_PROCESS) - return -EINVAL; - - /* - * Switching-from response - */ - if (vt_cons[console]->vt_newvt >= 0) - { - if (arg == 0) - /* - * Switch disallowed, so forget we were trying - * to do it. - */ - vt_cons[console]->vt_newvt = -1; - - else - { - /* - * The current vt has been released, so - * complete the switch. - */ - int newvt = vt_cons[console]->vt_newvt; - vt_cons[console]->vt_newvt = -1; - i = vc_allocate(newvt); - if (i) - return i; - /* - * When we actually do the console switch, - * make sure we are atomic with respect to - * other console switches.. - */ - acquire_console_sem(); - complete_change_console(newvt); - release_console_sem(); - } - } + switch (vt->blank_mode) { + case VESA_NO_BLANKING: + vt->vt_sw->con_blank(vc, VESA_VSYNC_SUSPEND+1); + break; + case VESA_VSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: + vt->vt_sw->con_blank(vc, VESA_POWERDOWN+1); + break; + } +} - /* - * Switched-to response - */ - else - { - /* - * If it's just an ACK, ignore it - */ - if (arg != VT_ACKACQ) - return -EINVAL; - } +static void timer_do_blank_screen(struct vt_struct *vt, int entering_gfx, + int from_timer_handler) +{ + struct vc_data *vc = vt->vc_cons[fg_console]; + int i; - return 0; + if (vt->vt_blanked) + return; - /* - * Disallocate memory associated to VT (but leave VT1) - */ - case VT_DISALLOCATE: - if (arg > MAX_NR_CONSOLES) - return -ENXIO; - if (arg == 0) { - /* disallocate all unused consoles, but leave 0 */ - for (i=1; icon_blank(vc, -1); + vt->vt_blanked = fg_console + 1; + set_origin(vc); + return; + } - case VT_RESIZE: - { - struct vt_sizes *vtsizes = (struct vt_sizes *) arg; - ushort ll,cc; - if (!perm) - return -EPERM; - if (get_user(ll, &vtsizes->v_rows) || - get_user(cc, &vtsizes->v_cols)) - return -EFAULT; - return vc_resize_all(ll, cc); + /* don't blank graphics */ + if (vcmode != KD_TEXT) { + vt->vt_blanked = fg_console + 1; + return; } - case VT_RESIZEX: - { - struct vt_consize *vtconsize = (struct vt_consize *) arg; - ushort ll,cc,vlin,clin,vcol,ccol; - if (!perm) - return -EPERM; - if (verify_area(VERIFY_READ, (void *)vtconsize, - sizeof(struct vt_consize))) - return -EFAULT; - __get_user(ll, &vtconsize->v_rows); - __get_user(cc, &vtconsize->v_cols); - __get_user(vlin, &vtconsize->v_vlin); - __get_user(clin, &vtconsize->v_clin); - __get_user(vcol, &vtconsize->v_vcol); - __get_user(ccol, &vtconsize->v_ccol); - vlin = vlin ? vlin : video_scan_lines; - if ( clin ) - { - if ( ll ) - { - if ( ll != vlin/clin ) - return -EINVAL; /* Parameters don't add up */ - } - else - ll = vlin/clin; - } - if ( vcol && ccol ) - { - if ( cc ) - { - if ( cc != vcol/ccol ) - return -EINVAL; - } - else - cc = vcol/ccol; - } - - if ( clin > 32 ) - return -EINVAL; - - if ( vlin ) - video_scan_lines = vlin; - if ( clin ) - video_font_height = clin; - - return vc_resize_all(ll, cc); - } + hide_cursor(vc); + if (!from_timer_handler) + del_timer_sync(&vt->timer); + if (vt->off_interval) { + vt->timer.function = powerdown_screen; + mod_timer(&vt->timer, jiffies + vt->off_interval); + } else { + if (!from_timer_handler) + del_timer_sync(&vt->timer); + vt->timer.function = unblank_screen_t; + } + + save_screen(vc); + /* In case we need to reset origin, blanking hook returns 1 */ + i = sw->con_blank(vc, 1); + vt->vt_blanked = fg_console + 1; + if (i) + set_origin(vc); - case PIO_FONT: { - struct console_font_op op; - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ - op.width = 8; - op.height = 0; - op.charcount = 256; - op.data = (char *) arg; - return con_font_op(fg_console, &op); - } - - case GIO_FONT: { - struct console_font_op op; - op.op = KD_FONT_OP_GET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = 32; - op.charcount = 256; - op.data = (char *) arg; - return con_font_op(fg_console, &op); - } - - case PIO_CMAP: - if (!perm) - return -EPERM; - return con_set_cmap((char *)arg); - - case GIO_CMAP: - return con_get_cmap((char *)arg); - - case PIO_FONTX: - case GIO_FONTX: - return do_fontx_ioctl(cmd, (struct consolefontdesc *)arg, perm); + if (console_blank_hook && console_blank_hook(1)) + return; + if (vt->blank_mode) + sw->con_blank(vc, vt->blank_mode + 1); +} - case PIO_FONTRESET: - { - if (!perm) - return -EPERM; +void do_blank_screen(struct vt_struct *vt, int entering_gfx) +{ + timer_do_blank_screen(vt, entering_gfx, 0); +} -#ifdef BROKEN_GRAPHICS_PROGRAMS - /* With BROKEN_GRAPHICS_PROGRAMS defined, the default - font is not saved. */ - return -ENOSYS; -#else - { - struct console_font_op op; - op.op = KD_FONT_OP_SET_DEFAULT; - op.data = NULL; - i = con_font_op(fg_console, &op); - if (i) return i; - con_set_default_unimap(fg_console); - return 0; +/* This is both a user-level callable and a timer handler */ +static void blank_screen(unsigned long private) +{ + struct vt_struct *vt = (struct vt_struct *) private; + + timer_do_blank_screen(vt, 0, 1); +} + +/* This is a timer handler */ +static void unblank_screen_t(unsigned long private) +{ + unblank_screen(); +} + +/* Called by timer as well as from vt_console_driver */ +void unblank_screen(void) +{ + struct vt_struct *vt = vt_cons; + struct vc_data *vc = vt->vc_cons[fg_console]; + + if (!vt->vt_blanked) + return; + if (!vc) { + /* impossible */ + printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); + return; + } + if (vcmode != KD_TEXT) + return; /* but leave console_blanked != 0 */ + + vt->timer.function = blank_screen; + if (vt->blank_interval) + mod_timer(&vt->timer, jiffies + vt->blank_interval); + + vt->vt_blanked = 0; + if (console_blank_hook) + console_blank_hook(0); + if (sw->con_blank(vc, 0)) + /* Low-level driver cannot restore -> do it ourselves */ + update_screen(vc); + set_cursor(vc); +} + +void poke_blanked_console(struct vt_struct *vt) +{ + del_timer(&vt->timer); + if (!vt->vc_cons[fg_console] || vt->vc_cons[fg_console]->vc_mode == KD_GRAPHICS) + return; + if (vt->vt_blanked) { + vt->timer.function = unblank_screen_t; + mod_timer(&vt->timer, jiffies); /* Now */ + } else if (vt->blank_interval) { + mod_timer(&vt->timer, jiffies + vt->blank_interval); + } +} + +/* + * Power management for the console system. + */ +static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct vt_struct *vt = dev->data; + + if (vt) { + switch (rqst) { + case PM_RESUME: + unblank_screen(); + break; + case PM_SUSPEND: + do_blank_screen(vt, 0); + break; } + } + return 0; +} + +/* + * Allocation, freeing and resizing of VCs. + */ + +int vc_cons_allocated(unsigned int i) +{ + return (i < MAX_NR_CONSOLES && vt_cons->vc_cons[i]); +} + +void set_console(int nr) +{ + struct vt_struct *vt = vt_cons; + + vt->want_vc = vt->vc_cons[nr]; + schedule_task(&vt->vt_tq); +} + +static void visual_init(struct vc_data *vc, int init) +{ + /* ++Geert: sw->con_init determines console size */ + int currcons = cons_num; + + sw = conswitchp; +#ifndef VT_SINGLE_DRIVER + if (con_driver_map[currcons]) + sw = con_driver_map[currcons]; #endif + vc->display_fg->vc_cons[currcons] = vc; + vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; + vc->vc_uni_pagedir = 0; + hi_font_mask = 0; + complement_mask = 0; + can_do_color = 0; + sw->con_init(vc, init); + if (!complement_mask) + complement_mask = can_do_color ? 0x7700 : 0x0800; + s_complement_mask = complement_mask; + video_size_row = video_num_columns<<1; + screenbuf_size = video_num_lines*video_size_row; +} + +static void vc_init(struct vc_data *vc, int do_clear) +{ + set_origin(vc); + pos = origin; + reset_vc(vc); + def_color = 0x07; /* white */ + ulcolor = 0x0f; /* bold white */ + halfcolor = 0x08; /* grey */ + init_waitqueue_head(&vc->paste_wait); + vte_ris(vc, do_clear); +} + +int vc_allocate(unsigned int currcons) /* return 0 on success */ +{ + struct vc_data *vc; + + if (currcons >= MAX_NR_CONSOLES) + return -ENXIO; + if (!vt_cons->vc_cons[currcons]) { + long p, q; + + /* prevent users from taking too much memory */ + if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + /* due to the granularity of kmalloc, we waste some memory here */ + /* the alloc is done in two steps, to optimize the common situation + of a 25x80 console (structsize=216, screenbuf_size=4000) */ + /* although the numbers above are not valid since long ago, the + point is still up-to-date and the comment still has its value + even if only as a historical artifact. --mj, July 1998 */ + p = (long) kmalloc(sizeof(struct vc_data), GFP_KERNEL); + if (!p) + return -ENOMEM; + vc = (struct vc_data *)p; + cons_num = currcons; + vc->display_fg = vt_cons; + visual_init(vc, 1); + if (!*vc->vc_uni_pagedir_loc) + con_set_default_unimap(vc); + q = (long)kmalloc(screenbuf_size, GFP_KERNEL); + if (!q) { + kfree((char *) p); + vc->display_fg->vc_cons[currcons] = NULL; + return -ENOMEM; + } + screenbuf = (unsigned short *) q; + kmalloced = 1; + vc_init(vc, 1); + + if (!pm_con) { + pm_con = pm_register(PM_SYS_DEV, PM_SYS_VGA, + pm_con_request); + if (pm_con) + pm_con->data = vt_cons; + } } + return 0; +} - case KDFONTOP: { - struct console_font_op op; - if (copy_from_user(&op, (void *) arg, sizeof(op))) - return -EFAULT; - if (!perm && op.op != KD_FONT_OP_GET) - return -EPERM; - i = con_font_op(console, &op); - if (i) return i; - if (copy_to_user((void *) arg, &op, sizeof(op))) - return -EFAULT; +/* + * Change # of rows and columns (0 means unchanged/the size of fg_console) + * [this is to be used together with some user program + * like resize that changes the hardware videomode] + */ +int vc_resize(unsigned int lines, unsigned int cols, + unsigned int first, unsigned int last) +{ + unsigned int cc, ll, ss, sr, todo = 0; + unsigned int currcons = fg_console, i; + unsigned short *newscreens[MAX_NR_CONSOLES]; + struct vc_data *vc = vt_cons->vc_cons[currcons]; + + cc = (cols ? cols : video_num_columns); + ll = (lines ? lines : video_num_lines); + sr = cc << 1; + ss = sr * ll; + + for (currcons = first; currcons <= last; currcons++) { + if (!vc_cons_allocated(currcons) || + (cc == video_num_columns && ll == video_num_lines)) + newscreens[currcons] = NULL; + else { + unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER); + if (!p) { + for (i = first; i < currcons; i++) + if (newscreens[i]) + kfree(newscreens[i]); + return -ENOMEM; + } + newscreens[currcons] = p; + todo++; + } + } + if (!todo) return 0; + + for (currcons = first; currcons <= last; currcons++) { + unsigned int occ, oll, oss, osr; + unsigned long ol, nl, nlend, rlth, rrem; + struct vc_data *vc = vt_cons->vc_cons[currcons]; + + if (!newscreens[currcons] || !vc) + continue; + + oll = video_num_lines; + occ = video_num_columns; + osr = video_size_row; + oss = screenbuf_size; + + video_num_lines = ll; + video_num_columns = cc; + video_size_row = sr; + screenbuf_size = ss; + + rlth = MIN(osr, sr); + rrem = sr - rlth; + ol = origin; + nl = (long) newscreens[currcons]; + nlend = nl + ss; + if (ll < oll) + ol += (oll - ll) * osr; + + update_attr(vc); + + while (ol < scr_end) { + scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); + if (rrem) + scr_memsetw((void *)(nl + rlth), video_erase_char, rrem); + ol += osr; + nl += sr; + } + if (nlend > nl) + scr_memsetw((void *) nl, video_erase_char, nlend - nl); + if (kmalloced) + kfree(screenbuf); + screenbuf = newscreens[currcons]; + kmalloced = 1; + screenbuf_size = ss; + set_origin(vc); + + /* do part of a vte_ris() */ + top = 0; + bottom = video_num_lines; + gotoxy(vc, x, y); + vte_decsc(vc); + + if (console_table[currcons]) { + struct winsize ws, *cws = &console_table[currcons]->winsize; + memset(&ws, 0, sizeof(ws)); + ws.ws_row = video_num_lines; + ws.ws_col = video_num_columns; + if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && + console_table[currcons]->pgrp > 0) + kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); + *cws = ws; + } + + if (IS_VISIBLE) + update_screen(vc); } + return 0; +} - case PIO_SCRNMAP: - if (!perm) - return -EPERM; - return con_set_trans_old((unsigned char *)arg); - - case GIO_SCRNMAP: - return con_get_trans_old((unsigned char *)arg); - - case PIO_UNISCRNMAP: - if (!perm) - return -EPERM; - return con_set_trans_new((unsigned short *)arg); - - case GIO_UNISCRNMAP: - return con_get_trans_new((unsigned short *)arg); - - case PIO_UNIMAPCLR: - { struct unimapinit ui; - if (!perm) - return -EPERM; - i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit)); - if (i) return -EFAULT; - con_clear_unimap(fg_console, &ui); - return 0; - } +void vc_disallocate(unsigned int currcons) +{ + struct vc_data *vc = vt_cons->vc_cons[currcons]; - case PIO_UNIMAP: - case GIO_UNIMAP: - return do_unimap_ioctl(cmd, (struct unimapdesc *)arg, perm); - - case VT_LOCKSWITCH: - if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; - vt_dont_switch = 1; - return 0; - case VT_UNLOCKSWITCH: - if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; - vt_dont_switch = 0; - return 0; -#ifdef CONFIG_FB_COMPAT_XPMAC - case VC_GETMODE: - { - struct vc_mode mode; - - i = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct vc_mode)); - if (i == 0) - i = console_getmode(&mode); - if (i) - return i; - if (copy_to_user((void *) arg, &mode, sizeof(mode))) - return -EFAULT; - return 0; + acquire_console_sem(); + if (vc) { + sw->con_deinit(vc); + if (kmalloced) + kfree(screenbuf); + if (currcons >= MIN_NR_CONSOLES) + kfree(vt_cons->vc_cons[currcons]); + vt_cons->vc_cons[currcons] = NULL; + } + release_console_sem(); +} + +/* + * Selection stuff for GPM. + */ +void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) +{ + char buf[8]; + + sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), + (char)('!' + mry)); + respond_string(buf, tty); +} + +/* invoked via ioctl(TIOCLINUX) and through set_selection */ +int mouse_reporting(struct vc_data *vc) +{ + return report_mouse; +} + +/* This is a temporary buffer used to prepare a tty console write + * so that we can easily avoid touching user space while holding the + * console spinlock. It is allocated in vt_console_init and is shared by + * this code and the vc_screen read/write tty calls. + * + * We have to allocate this statically in the kernel data section + * since console_init (and thus vt_console_init) are called before any + * kernel memory allocation is available. + */ +char con_buf[PAGE_SIZE]; +#define CON_BUF_SIZE PAGE_SIZE +DECLARE_MUTEX(con_buf_sem); + +static int do_con_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ +#ifdef VT_BUF_VRAM_ONLY +#define FLUSH do { } while(0); +#else +#define FLUSH if (draw_x >= 0) { \ + sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \ + draw_x = -1; \ + } +#endif + + int c, tc, ok, n = 0, draw_x = -1; + unsigned long draw_from = 0, draw_to = 0; + struct vc_data *vc = (struct vc_data *)tty->driver_data; + u16 himask, charmask; + const unsigned char *orig_buf = NULL; + int orig_count; + + if (in_interrupt()) + return count; + + if (!vc) { + /* could this happen? */ + static int error = 0; + if (!error) { + error = 1; + printk("con_write: tty %d not allocated\n", minor(tty->device)); + } + return 0; + } + + orig_buf = buf; + orig_count = count; + + if (from_user) { + down(&con_buf_sem); + +again: + if (count > CON_BUF_SIZE) + count = CON_BUF_SIZE; + console_conditional_schedule(); + if (copy_from_user(con_buf, buf, count)) { + n = 0; /* ?? are error codes legal here ?? */ + goto out; } - case VC_SETMODE: - case VC_INQMODE: - { - struct vc_mode mode; - - if (!perm) - return -EPERM; - if (copy_from_user(&mode, (void *) arg, sizeof(mode))) - return -EFAULT; - return console_setmode(&mode, cmd == VC_SETMODE); + + buf = con_buf; + } + + /* At this point 'buf' is guarenteed to be a kernel buffer + * and therefore no access to userspace (and therefore sleeping) + * will be needed. The con_buf_sem serializes all tty based + * console rendering and vcs write/read operations. We hold + * the console spinlock during the entire write. + */ + + acquire_console_sem(); + + himask = hi_font_mask; + charmask = himask ? 0x1ff : 0xff; + + /* undraw cursor first */ + if (IS_VISIBLE) + hide_cursor(vc); + + while (!tty->stopped && count) { + c = *buf; + buf++; + n++; + count--; + + if (utf) { + /* Combine UTF-8 into Unicode */ + /* Incomplete characters silently ignored */ + if(c > 0x7f) { + if (utf_count > 0 && (c & 0xc0) == 0x80) { + utf_char = (utf_char << 6) | (c & 0x3f); + utf_count--; + if (utf_count == 0) + tc = c = utf_char; + else continue; + } else { + if ((c & 0xe0) == 0xc0) { + utf_count = 1; + utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + utf_count = 2; + utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + utf_count = 3; + utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + utf_count = 4; + utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + utf_count = 5; + utf_char = (c & 0x01); + } else + utf_count = 0; + continue; + } + } else { + tc = c; + utf_count = 0; + } + } else { /* no utf */ + tc = translate[toggle_meta ? (c|0x80) : c]; } - case VC_SETCMAP: - { - unsigned char cmap[3][256], *p; - int n_entries, cmap_size, i, j; - - if (!perm) - return -EPERM; - if (arg == (unsigned long) VC_POWERMODE_INQUIRY - || arg <= VESA_POWERDOWN) { - /* compatibility hack: VC_POWERMODE - was changed from 0x766a to 0x766c */ - return console_powermode((int) arg); + + /* If the original code was a control character we + * only allow a glyph to be displayed if the code is + * not normally used (such as for cursor movement) or + * if the disp_ctrl mode has been explicitly enabled. + * Certain characters (as given by the CTRL_ALWAYS + * bitmap) are always displayed as control characters, + * as the console would be pretty useless without + * them; to display an arbitrary font position use the + * direct-to-font zone in UTF-8 mode. + */ + ok = tc && (c >= 32 || + (!utf && !(((disp_ctrl ? CTRL_ALWAYS + : CTRL_ACTION) >> c) & 1))) + && (c != 127 || disp_ctrl) + && (c != 128+27); + + if (!vc_state && ok) { + /* Now try to find out how to display it */ + tc = conv_uni_to_pc(vc, tc); + if ( tc == -4 ) { + /* If we got -4 (not found) then see if we have + defined a replacement character (U+FFFD) */ + tc = conv_uni_to_pc(vc, 0xfffd); + + /* One reason for the -4 can be that we just + did a clear_unimap(); + try at least to show something. */ + if (tc == -4) + tc = c; + } else if ( tc == -3 ) { + /* Bad hash table -- hope for the best */ + tc = c; + } + if (tc & ~charmask) + continue; /* Conversion failed */ + + if (need_wrap || irm) + FLUSH + if (need_wrap) { + vte_cr(vc); + vte_lf(vc); } - if (get_user(cmap_size, (int *) arg)) - return -EFAULT; - if (cmap_size % 3) - return -EINVAL; - n_entries = cmap_size / 3; - if ((unsigned) n_entries > 256) - return -EINVAL; - p = (unsigned char *) (arg + sizeof(int)); - for (j = 0; j < n_entries; ++j) - for (i = 0; i < 3; ++i) - if (get_user(cmap[i][j], p++)) - return -EFAULT; - return console_setcmap(n_entries, cmap[0], - cmap[1], cmap[2]); + if (irm) + insert_char(vc, 1); + scr_writew(himask ? + ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : + (attr << 8) + tc, + (u16 *) pos); + if (DO_UPDATE && draw_x < 0) { + draw_x = x; + draw_from = pos; + } + if (x == video_num_columns - 1) { + need_wrap = decawm; + draw_to = pos+2; + } else { + x++; + draw_to = (pos+=2); + } + continue; } - case VC_GETCMAP: - /* not implemented yet */ - return -ENOIOCTLCMD; - case VC_POWERMODE: - if (!perm) - return -EPERM; - return console_powermode((int) arg); -#endif /* CONFIG_FB_COMPAT_XPMAC */ - default: - return -ENOIOCTLCMD; + FLUSH + terminal_emulation(tty, c); } + FLUSH + console_conditional_schedule(); + release_console_sem(); + +out: + if (from_user) { + /* If the user requested something larger than + * the CON_BUF_SIZE, and the tty is not stopped, + * keep going. + */ + if ((orig_count > CON_BUF_SIZE) && !tty->stopped) { + orig_count -= CON_BUF_SIZE; + orig_buf += CON_BUF_SIZE; + count = orig_count; + buf = orig_buf; + goto again; + } + + up(&con_buf_sem); + } + + return n; +#undef FLUSH } /* - * Sometimes we want to wait until a particular VT has been activated. We - * do it in a very simple manner. Everybody waits on a single queue and - * get woken up at once. Those that are satisfied go on with their business, - * while those not ready go back to sleep. Seems overkill to add a wait - * to each vt just for this - usually this does nothing! + * This is the console switching callback. + * + * Doing console switching in a process context allows + * us to do the switches asynchronously (needed when we want + * to switch due to a keyboard interrupt). Synchronization + * with other console code and prevention of re-entrancy is + * ensured with console_sem. */ -static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); +static void vt_callback(void *private) +{ + struct vt_struct *vt = (struct vt_struct *) private; + + if (!vt || !vt->want_vc || !vt->want_vc->vc_tty) + return; + + acquire_console_sem(); + + if (vt->want_vc->vc_num != fg_console) { + hide_cursor(vt->vc_cons[fg_console]); + change_console(vt->want_vc, vt->vc_cons[fg_console]); + /* we only changed when the console had already + been allocated - a new console is not created + in an interrupt routine */ + } + /* do not unblank for a LED change */ + if (do_poke_blanked_console) { + do_poke_blanked_console = 0; + poke_blanked_console(vt); + } + if (vt->scrollback_delta) { + int currcons = fg_console; + struct vc_data *vc = vt->vc_cons[currcons]; + + clear_selection(); + if (vcmode == KD_TEXT) + sw->con_scrolldelta(vc, vt->scrollback_delta); + vt->scrollback_delta = 0; + } + release_console_sem(); +} /* - * Sleeps until a vt is activated, or the task is interrupted. Returns - * 0 if activation, -EINTR if interrupted. + * Handling of Linux-specific VC ioctls */ -int vt_waitactive(int vt) + +int tioclinux(struct tty_struct *tty, unsigned long arg) { - int retval; - DECLARE_WAITQUEUE(wait, current); + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char type, data; + int ret; - add_wait_queue(&vt_activate_queue, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - retval = 0; - if (vt == fg_console) + if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) + return -EINVAL; + if (current->tty != tty && !capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(type, (char *)arg)) + return -EFAULT; + ret = 0; + switch (type) + { + case 2: + acquire_console_sem(); + ret = set_selection(arg, tty, 1); + release_console_sem(); + break; + case 3: + ret = paste_selection(tty); + break; + case 4: + unblank_screen(); + break; + case 5: + ret = sel_loadlut(arg); + break; + case 6: + + /* + * Make it possible to react to Shift+Mousebutton. + * Note that 'shift_state' is an undocumented + * kernel-internal variable; programs not closely + * related to the kernel should not use this. + */ + data = shift_state; + ret = __put_user(data, (char *) arg); break; - retval = -EINTR; - if (signal_pending(current)) + case 7: + data = mouse_reporting(vc); + ret = __put_user(data, (char *) arg); break; - schedule(); + case 10: + if (get_user(data, (char *)arg+1)) + return -EFAULT; + vc->display_fg->blank_mode = (data < 4) ? data : 0; + break; + case 11: /* set kmsg redirect */ + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + } else { + if (get_user(data, (char *)arg+1)) + ret = -EFAULT; + else + kmsg_redirect = data; + } + break; + case 12: /* get fg_console */ + ret = fg_console; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +/* + * /dev/ttyN handling + */ + +/* Allocate the console screen memory. */ +static int con_open(struct tty_struct *tty, struct file * filp) +{ + struct vc_data *vc; + unsigned int currcons; + int i; + + currcons = minor(tty->device) - tty->driver.minor_start; + + i = vc_allocate(currcons); + if (i) + return i; + + vc = vt_cons->vc_cons[currcons]; + tty->driver_data = vc; + vc->vc_tty = tty; + + if (!tty->winsize.ws_row && !tty->winsize.ws_col) { + tty->winsize.ws_row = video_num_lines; + tty->winsize.ws_col = video_num_columns; } - remove_wait_queue(&vt_activate_queue, &wait); - current->state = TASK_RUNNING; + if (tty->count == 1) + vcs_make_devfs(currcons, 0); + return 0; +} + +static void con_close(struct tty_struct *tty, struct file * filp) +{ + if (!tty || tty->count != 1) + return; + + vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1); + tty->driver_data = 0; +} + +static int con_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int retval; + + pm_access(pm_con); + retval = do_con_write(tty, from_user, buf, count); + con_flush_chars(tty); + return retval; } -#define vt_wake_waitactive() wake_up(&vt_activate_queue) +static void con_put_char(struct tty_struct *tty, unsigned char ch) +{ + if (in_interrupt()) + return; /* n_r3964 calls put_char() from interrupt context */ + pm_access(pm_con); + do_con_write(tty, 0, &ch, 1); +} + +static int con_write_room(struct tty_struct *tty) +{ + if (tty->stopped) + return 0; + return 4096; /* No limit, really; we're not buffering */ +} + +static void con_flush_chars(struct tty_struct *tty) +{ + struct vc_data *vc; + + if (in_interrupt()) /* from flush_to_ldisc */ + return; + + pm_access(pm_con); + lock_kernel(); + acquire_console_sem(); + vc = (struct vc_data *)tty->driver_data; + if (vc) + set_cursor(vc); + release_console_sem(); + unlock_kernel(); +} -void reset_vc(unsigned int new_console) +static int con_chars_in_buffer(struct tty_struct *tty) { - vt_cons[new_console]->vc_mode = KD_TEXT; - kbd_table[new_console].kbdmode = VC_XLATE; - vt_cons[new_console]->vt_mode.mode = VT_AUTO; - vt_cons[new_console]->vt_mode.waitv = 0; - vt_cons[new_console]->vt_mode.relsig = 0; - vt_cons[new_console]->vt_mode.acqsig = 0; - vt_cons[new_console]->vt_mode.frsig = 0; - vt_cons[new_console]->vt_pid = -1; - vt_cons[new_console]->vt_newvt = -1; - if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ - reset_palette(new_console) ; + return 0; /* we're not buffering */ } /* - * Performs the back end of a vt switch + * Turn the Scroll-Lock LED on when the tty is stopped */ -void complete_change_console(unsigned int new_console) +static void con_stop(struct tty_struct *tty) { - unsigned char old_vc_mode; + struct vc_data *vc = (struct vc_data *) tty->driver_data; - last_console = fg_console; + if (!tty || !vc) + return; + set_kbd_led(&vc->kbd_table, VC_SCROLLOCK); + set_leds(); +} - /* - * If we're switching, we could be going from KD_GRAPHICS to - * KD_TEXT mode or vice versa, which means we need to blank or - * unblank the screen later. - */ - old_vc_mode = vt_cons[fg_console]->vc_mode; - switch_screen(new_console); +/* + * Turn the Scroll-Lock LED off when the console is started + */ +static void con_start(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + if (!tty || !vc) + return; + clr_kbd_led(&vc->kbd_table, VC_SCROLLOCK); + set_leds(); +} - /* - * This can't appear below a successful kill_proc(). If it did, - * then the *blank_screen operation could occur while X, having - * received acqsig, is waking up on another processor. This - * condition can lead to overlapping accesses to the VGA range - * and the framebuffer (causing system lockups). - * - * To account for this we duplicate this code below only if the - * controlling process is gone and we've called reset_vc. - */ - if (old_vc_mode != vt_cons[new_console]->vc_mode) - { - if (vt_cons[new_console]->vc_mode == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); - } +/* + * con_throttle and con_unthrottle are only used for + * paste_selection(), which has to stuff in a large number of + * characters... + */ +static void con_throttle(struct tty_struct *tty) +{ +} - /* - * If this new console is under process control, send it a signal - * telling it that it has acquired. Also check if it has died and - * clean up (similar to logic employed in change_console()) - */ - if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS) - { - /* - * Send the signal as privileged - kill_proc() will - * tell us if the process has gone or something else - * is awry - */ - if (kill_proc(vt_cons[new_console]->vt_pid, - vt_cons[new_console]->vt_mode.acqsig, - 1) != 0) - { - /* - * The controlling process has died, so we revert back to - * normal operation. In this case, we'll also change back - * to KD_TEXT mode. I'm not sure if this is strictly correct - * but it saves the agony when the X server dies and the screen - * remains blanked due to KD_GRAPHICS! It would be nice to do - * this outside of VT_PROCESS but there is no single process - * to account for and tracking tty count may be undesirable. - */ - reset_vc(new_console); +static void con_unthrottle(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; - if (old_vc_mode != vt_cons[new_console]->vc_mode) - { - if (vt_cons[new_console]->vc_mode == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); + wake_up_interruptible(&vc->paste_wait); +} + +#ifdef CONFIG_VT_CONSOLE + +/* + * Console on virtual terminal + * + * The console_lock must be held when we get here. + */ + +void vt_console_print(struct console *co, const char * b, unsigned count) +{ + int currcons = fg_console; + unsigned char c; + static unsigned long printing = 0; + struct vc_data *vc; + const ushort *start; + ushort cnt = 0; + ushort myx; + + /* console busy or not yet initialized */ + if (!printable || test_and_set_bit(0, &printing)) + return; + + pm_access(pm_con); + + if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) + currcons = kmsg_redirect - 1; + + vc = vt_cons->vc_cons[currcons]; + + /* read `x' only after setting currecons properly (otherwise + the `x' macro will read the x of the foreground console). */ + myx = x; + + if (!vc) { + /* impossible */ + /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ + goto quit; + } + + if (vcmode != KD_TEXT) + goto quit; + + /* undraw cursor first */ + if (IS_VISIBLE) + hide_cursor(vc); + + start = (ushort *)pos; + + /* Contrived structure to try to emulate original need_wrap behaviour + * Problems caused when we have need_wrap set on '\n' character */ + while (count--) { + c = *b++; + if (c == 10 || c == 13 || c == 8 || need_wrap) { + if (cnt > 0) { + if (IS_VISIBLE) + sw->con_putcs(vc, start, cnt, y, x); + x += cnt; + if (need_wrap) + x--; + cnt = 0; + } + if (c == 8) { /* backspace */ + vte_bs(vc); + start = (ushort *)pos; + myx = x; + continue; } + if (c != 13) + vte_lf(vc); + vte_cr(vc); + start = (ushort *)pos; + myx = x; + if (c == 10 || c == 13) + continue; + } + scr_writew((attr << 8) + c, (unsigned short *) pos); + cnt++; + if (myx == video_num_columns - 1) { + need_wrap = 1; + continue; + } + pos+=2; + myx++; + } + if (cnt > 0) { + if (IS_VISIBLE) + sw->con_putcs(vc, start, cnt, y, x); + x += cnt; + if (x == video_num_columns) { + x--; + need_wrap = 1; } } + set_cursor(vc); + + if (!oops_in_progress) + poke_blanked_console(vc->display_fg); + +quit: + clear_bit(0, &printing); +} + +static kdev_t vt_console_device(struct console *c) +{ + return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1); +} + +struct console vt_console_driver = { + name: "tty", + write: vt_console_print, + device: vt_console_device, + unblank: unblank_screen, + flags: CON_PRINTBUFFER, + index: -1, +}; +#endif + +/* + * Mapping and unmapping displays to a VT + */ +const char *vt_map_display(struct vt_struct *vt, int init) +{ + const char *display_desc = NULL; + struct vc_data *vc; + unsigned int currcons = 0; + + if (conswitchp) + display_desc = conswitchp->con_startup(); + + if (!display_desc) { + fg_console = 0; + return NULL; + } + + vt->vt_blanked = 0; + vt->blank_interval = 10*60*HZ; + vt->off_interval = 0; + init_timer(&vt->timer); + vt->timer.data = (long) vt; + vt->timer.function = blank_screen; + mod_timer(&vt->timer, jiffies + vt->blank_interval); + INIT_TQUEUE(&vt->vt_tq, vt_callback, vt); /* - * Wake anyone waiting for their VT to activate + * kmalloc is not running yet - we use the bootmem allocator. */ - vt_wake_waitactive(); - return; + for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { + vc = (struct vc_data *) + alloc_bootmem(sizeof(struct vc_data)); + cons_num = currcons; + vc->display_fg = vt_cons; + visual_init(vc, 1); + screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size); + kmalloced = 0; + vc_init(vc, currcons || !sw->con_save_screen); + } +#ifdef CONFIG_VT_CONSOLE + register_console(&vt_console_driver); +#endif + fg_console = 0; + vc = vt->want_vc = vt->last_console = vt->vc_cons[fg_console]; + set_origin(vc); + save_screen(vc); + gotoxy(vc, x, y); + vte_ed(vc, 0); + update_screen(vc); + return display_desc; } /* - * Performs the front-end of a vt switch + * This routine initializes console interrupts, and does nothing + * else. If you want the screen to clear, call tty_write with + * the appropriate escape-sequence. */ -void change_console(unsigned int new_console) + +struct tty_driver console_driver; +static int console_refcount; + +void __init vt_console_init(void) { - if ((new_console == fg_console) || (vt_dont_switch)) - return; - if (!vc_cons_allocated(new_console)) + const char *display_desc = NULL; + struct vc_data *vc; + + vt_cons = (struct vt_struct *) alloc_bootmem(sizeof(struct vt_struct)); + + display_desc = vt_map_display(vt_cons, 0); + + if (!display_desc) { + fg_console = 0; return; + } + vc = vt_cons->vc_cons[fg_console]; - /* - * If this vt is in process mode, then we need to handshake with - * that process before switching. Essentially, we store where that - * vt wants to switch to and wait for it to tell us when it's done - * (via VT_RELDISP ioctl). - * - * We also check to see if the controlling process still exists. - * If it doesn't, we reset this vt to auto mode and continue. - * This is a cheap way to track process control. The worst thing - * that can happen is: we send a signal to a process, it dies, and - * the switch gets "lost" waiting for a response; hopefully, the - * user will try again, we'll detect the process is gone (unless - * the user waits just the right amount of time :-) and revert the - * vt to auto control. - */ - if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS) - { - /* - * Send the signal as privileged - kill_proc() will - * tell us if the process has gone or something else - * is awry - */ - if (kill_proc(vt_cons[fg_console]->vt_pid, - vt_cons[fg_console]->vt_mode.relsig, - 1) == 0) - { - /* - * It worked. Mark the vt to switch to and - * return. The process needs to send us a - * VT_RELDISP ioctl to complete the switch. - */ - vt_cons[fg_console]->vt_newvt = new_console; - return; - } + printk("Console: %s %s %dx%d", + can_do_color ? "colour" : "mono", + display_desc, video_num_columns, video_num_lines); + printable = 1; + printk("\n"); +} - /* - * The controlling process has died, so we revert back to - * normal operation. In this case, we'll also change back - * to KD_TEXT mode. I'm not sure if this is strictly correct - * but it saves the agony when the X server dies and the screen - * remains blanked due to KD_GRAPHICS! It would be nice to do - * this outside of VT_PROCESS but there is no single process - * to account for and tracking tty count may be undesirable. - */ - reset_vc(fg_console); +int __init vty_init(void) +{ + memset(&console_driver, 0, sizeof(struct tty_driver)); + console_driver.magic = TTY_DRIVER_MAGIC; + console_driver.name = "vc/%d"; + console_driver.name_base = 1; + console_driver.major = TTY_MAJOR; + console_driver.minor_start = 1; + console_driver.num = MAX_NR_CONSOLES; + console_driver.type = TTY_DRIVER_TYPE_CONSOLE; + console_driver.init_termios = tty_std_termios; + console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; + console_driver.refcount = &console_refcount; + console_driver.table = console_table; + console_driver.termios = console_termios; + console_driver.termios_locked = console_termios_locked; +#ifdef CONFIG_VT_CONSOLE + console_driver.console = &vt_console_driver; +#endif + console_driver.open = con_open; + console_driver.close = con_close; + console_driver.write = con_write; + console_driver.write_room = con_write_room; + console_driver.put_char = con_put_char; + console_driver.flush_chars = con_flush_chars; + console_driver.chars_in_buffer = con_chars_in_buffer; + console_driver.ioctl = vt_ioctl; + console_driver.stop = con_stop; + console_driver.start = con_start; + console_driver.throttle = con_throttle; + console_driver.unthrottle = con_unthrottle; + + if (tty_register_driver(&console_driver)) + panic("Couldn't register console driver\n"); + + kbd_init(); + console_map_init(); + vcs_init(); + return 0; +} + +#ifndef VT_SINGLE_DRIVER - /* - * Fall through to normal (VT_AUTO) handling of the switch... +static void clear_buffer_attributes(struct vc_data *vc) +{ + unsigned short *p = (unsigned short *) origin; + int count = screenbuf_size/2; + int mask = hi_font_mask | 0xff; + + for (; count > 0; count--, p++) { + scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); + } +} + +/* + * If we support more console drivers, this function is used + * when a driver wants to take over some existing consoles + * and become default driver for newly opened ones. + */ + +void take_over_console(const struct consw *csw, int first, int last, int deflt) +{ + struct vc_data *vc; + const char *desc; + int i, j = -1; + + desc = csw->con_startup(); + if (!desc) return; + if (deflt) + conswitchp = csw; + + for (i = first; i <= last; i++) { + int old_was_color; + + vc = vt_cons->vc_cons[i]; + con_driver_map[i] = csw; + + if (!vc || !sw) + continue; + + j = i; + if (IS_VISIBLE) + save_screen(vc); + old_was_color = can_do_color; + vc->display_fg->vt_sw->con_deinit(vc); + visual_init(vc, 0); + update_attr(vc); + + /* If the console changed between mono <-> color, then + * the attributes in the screenbuf will be wrong. The + * following resets all attributes to something sane. */ + if (old_was_color != can_do_color) + clear_buffer_attributes(vc); + + if (IS_VISIBLE) + update_screen(vc); } + printk("Console: switching "); + if (!deflt) + printk("consoles %d-%d ", first+1, last+1); + if (j >= 0) { + vc = vt_cons->vc_cons[j]; + printk("to %s %s %dx%d\n", can_do_color ? "colour" : "mono", + desc, video_num_columns, video_num_lines); + } else + printk("to %s\n", desc); +} - /* - * Ignore all switches in KD_GRAPHICS+VT_AUTO mode - */ - if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) - return; +void give_up_console(const struct consw *csw) +{ + int i; - complete_change_console(new_console); + for(i = 0; i < MAX_NR_CONSOLES; i++) + if (con_driver_map[i] == csw) + con_driver_map[i] = NULL; } +#endif + +/* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(color_table); +EXPORT_SYMBOL(default_red); +EXPORT_SYMBOL(default_grn); +EXPORT_SYMBOL(default_blu); +EXPORT_SYMBOL(video_font_height); +EXPORT_SYMBOL(video_scan_lines); +EXPORT_SYMBOL(vc_resize); +EXPORT_SYMBOL(fg_console); +EXPORT_SYMBOL(console_blank_hook); +#ifdef CONFIG_VT +EXPORT_SYMBOL(vt_cons); +#endif +#ifndef VT_SINGLE_DRIVER +EXPORT_SYMBOL(take_over_console); +EXPORT_SYMBOL(give_up_console); +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/char/vt_ioctl.c linux-2.5/drivers/char/vt_ioctl.c --- linux-2.5.23/drivers/char/vt_ioctl.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/vt_ioctl.c Tue Jun 4 23:57:19 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 || capable(CAP_SYS_ADMIN)) + 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 (!capable(CAP_SYS_ADMIN)) + return -EPERM; + vt_dont_switch = 1; + return 0; + case VT_UNLOCKSWITCH: + if (!capable(CAP_SYS_ADMIN)) + 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.23/drivers/char/wafer5823wdt.c linux-2.5/drivers/char/wafer5823wdt.c --- linux-2.5.23/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.23/drivers/hotplug/cpqphp_ctrl.c linux-2.5/drivers/hotplug/cpqphp_ctrl.c --- linux-2.5.23/drivers/hotplug/cpqphp_ctrl.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/hotplug/cpqphp_ctrl.c Tue Jun 4 15:53:20 2002 @@ -1707,7 +1707,7 @@ struct controller *ctrl; lock_kernel(); daemonize(); - + // New name strcpy(current->comm, "phpd_event"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/hotplug/ibmphp_hpc.c linux-2.5/drivers/hotplug/ibmphp_hpc.c --- linux-2.5.23/drivers/hotplug/ibmphp_hpc.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/hotplug/ibmphp_hpc.c Wed Jun 12 03:01:50 2002 @@ -1025,7 +1025,6 @@ debug ("%s - Entry\n", __FUNCTION__); lock_kernel (); daemonize (); - reparent_to_init (); // New name strcpy (current->comm, "hpc_poll"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/hotplug/pci_hotplug_core.c linux-2.5/drivers/hotplug/pci_hotplug_core.c --- linux-2.5.23/drivers/hotplug/pci_hotplug_core.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/hotplug/pci_hotplug_core.c Wed Jun 19 18:46:55 2002 @@ -48,7 +48,7 @@ #define MY_NAME THIS_MODULE->name #endif -#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt, MY_NAME, __FUNCTION__, ## arg); } while (0) +#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/i2c/Config.help linux-2.5/drivers/i2c/Config.help --- linux-2.5.23/drivers/i2c/Config.help Wed Jun 19 03:11:49 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.23/drivers/i2c/Config.in linux-2.5/drivers/i2c/Config.in --- linux-2.5.23/drivers/i2c/Config.in Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/i2c/Config.in Tue Jun 4 18:53:30 2002 @@ -39,11 +39,15 @@ 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 dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C - dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C + dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C $CONFIG_SYSCTL fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/i2c/Makefile linux-2.5/drivers/i2c/Makefile --- linux-2.5.23/drivers/i2c/Makefile Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/i2c/Makefile Sat Jun 1 00:34:34 2002 @@ -16,6 +16,7 @@ obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o obj-$(CONFIG_I2C_PROC) += i2c-proc.o +obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/i2c/i2c-core.c linux-2.5/drivers/i2c/i2c-core.c --- linux-2.5.23/drivers/i2c/i2c-core.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/drivers/i2c/i2c-core.c Mon Jun 17 21:58:33 2002 @@ -20,7 +20,7 @@ /* With some changes from Kyösti Mälkki . All SMBus-related things are written by Frodo Looijaard */ -/* $Id: i2c-core.c,v 1.64 2001/08/13 01:35:56 mds Exp $ */ +/* $Id: i2c-core.c,v 1.73 2002/03/03 17:37:44 mds Exp $ */ #include #include @@ -28,7 +28,6 @@ #include #include #include - #include /* ----- compatibility stuff ----------------------------------------------- */ @@ -158,7 +157,7 @@ proc_entry = create_proc_entry(name,0,proc_bus); if (! proc_entry) { - printk("i2c-core.o: Could not create /proc/bus/%s\n", + printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n", name); res = -ENOENT; goto ERROR1; @@ -188,7 +187,7 @@ drivers[j]->attach_adapter(adap); DRV_UNLOCK(); - DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n", + DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n", adap->name,i)); return 0; @@ -214,7 +213,7 @@ if (adap == adapters[i]) break; if (I2C_ADAP_MAX == i) { - printk( "i2c-core.o: unregister_adapter adap [%s] not found.\n", + printk( KERN_WARNING "i2c-core.o: unregister_adapter adap [%s] not found.\n", adap->name); res = -ENODEV; goto ERROR0; @@ -229,7 +228,7 @@ for (j = 0; j < I2C_DRIVER_MAX; j++) if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY)) if ((res = drivers[j]->attach_adapter(adap))) { - printk("i2c-core.o: can't detach adapter %s " + printk(KERN_WARNING "i2c-core.o: can't detach adapter %s " "while detaching driver %s: driver not " "detached!",adap->name,drivers[j]->name); goto ERROR1; @@ -247,7 +246,7 @@ * must be deleted, as this would cause invalid states. */ if ((res=client->driver->detach_client(client))) { - printk("i2c-core.o: adapter %s not " + printk(KERN_ERR "i2c-core.o: adapter %s not " "unregistered, because client at " "address %02x can't be detached. ", adap->name, client->addr); @@ -266,7 +265,7 @@ adap_count--; ADAP_UNLOCK(); - DEB(printk("i2c-core.o: adapter unregistered: %s\n",adap->name)); + DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name)); return 0; ERROR0: @@ -305,7 +304,7 @@ DRV_UNLOCK(); /* driver was successfully added */ - DEB(printk("i2c-core.o: driver %s registered.\n",driver->name)); + DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); ADAP_LOCK(); @@ -340,7 +339,7 @@ * attached. If so, detach them to be able to kill the driver * afterwards. */ - DEB2(printk("i2c-core.o: unregister_driver - looking for clients.\n")); + DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n")); /* removing clients does not depend on the notify flag, else * invalid operation might (will!) result, when using stale client * pointers. @@ -350,7 +349,7 @@ struct i2c_adapter *adap = adapters[k]; if (adap == NULL) /* skip empty entries. */ continue; - DEB2(printk("i2c-core.o: examining adapter %s:\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: examining adapter %s:\n", adap->name)); if (driver->flags & I2C_DF_DUMMY) { /* DUMMY drivers do not register their clients, so we have to @@ -359,7 +358,7 @@ * this or hell will break loose... */ if ((res = driver->attach_adapter(adap))) { - printk("i2c-core.o: while unregistering " + printk(KERN_WARNING "i2c-core.o: while unregistering " "dummy driver %s, adapter %s could " "not be detached properly; driver " "not unloaded!",driver->name, @@ -372,13 +371,13 @@ struct i2c_client *client = adap->clients[j]; if (client != NULL && client->driver == driver) { - DEB2(printk("i2c-core.o: " + DEB2(printk(KERN_DEBUG "i2c-core.o: " "detaching client %s:\n", client->name)); if ((res = driver-> detach_client(client))) { - printk("i2c-core.o: while " + printk(KERN_ERR "i2c-core.o: while " "unregistering driver " "`%s', the client at " "address %02x of " @@ -400,7 +399,7 @@ driver_count--; DRV_UNLOCK(); - DEB(printk("i2c-core.o: driver unregistered: %s\n",driver->name)); + DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name)); return 0; } @@ -436,10 +435,10 @@ if (adapter->client_register) if (adapter->client_register(client)) - printk("i2c-core.o: warning: client_register seems " + printk(KERN_DEBUG "i2c-core.o: warning: client_register seems " "to have failed for client %02x at adapter %s\n", client->addr,adapter->name); - DEB(printk("i2c-core.o: client [%s] registered to adapter [%s](pos. %d).\n", + DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] registered to adapter [%s](pos. %d).\n", client->name, adapter->name,i)); if(client->flags & I2C_CLIENT_ALLOW_USE) @@ -470,7 +469,7 @@ if (adapter->client_unregister != NULL) if ((res = adapter->client_unregister(client))) { - printk("i2c-core.o: client_unregister [%s] failed, " + printk(KERN_ERR "i2c-core.o: client_unregister [%s] failed, " "client not detached",client->name); return res; } @@ -478,7 +477,7 @@ adapter->clients[i] = NULL; adapter->client_count--; - DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name)); + DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] unregistered.\n",client->name)); return 0; } @@ -659,12 +658,12 @@ int i,j,k,order_nr,len=0,len_total; int order[I2C_CLIENT_MAX]; - if (count > 4000) + if (count > 4096) return -EINVAL; len_total = file->f_pos + count; /* Too bad if this gets longer (unlikely) */ - if (len_total > 4000) - len_total = 4000; + if (len_total > 4096) + len_total = 4096; for (i = 0; i < I2C_ADAP_MAX; i++) if (adapters[i]->inode == inode->i_ino) { /* We need a bit of slack in the kernel buffer; this makes the @@ -720,13 +719,13 @@ i2cproc_initialized = 0; if (! proc_bus) { - printk("i2c-core.o: /proc/bus/ does not exist"); + printk(KERN_ERR "i2c-core.o: /proc/bus/ does not exist"); i2cproc_cleanup(); return -ENOENT; } proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); if (!proc_bus_i2c) { - printk("i2c-core.o: Could not create /proc/bus/i2c"); + printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c"); i2cproc_cleanup(); return -ENOENT; } @@ -763,7 +762,7 @@ int ret; if (adap->algo->master_xfer) { - DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with %d msgs.\n", adap->name,num)); I2C_LOCK(adap); @@ -772,7 +771,7 @@ return ret; } else { - printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", adap->id); return -ENOSYS; } @@ -790,7 +789,7 @@ msg.len = count; (const char *)msg.buf = buf; - DEB2(printk("i2c-core.o: master_send: writing %d bytes on %s.\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n", count,client->adapter->name)); I2C_LOCK(adap); @@ -802,7 +801,7 @@ */ return (ret == 1 )? count : ret; } else { - printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", client->adapter->id); return -ENOSYS; } @@ -820,14 +819,14 @@ msg.len = count; msg.buf = buf; - DEB2(printk("i2c-core.o: master_recv: reading %d bytes on %s.\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n", count,client->adapter->name)); I2C_LOCK(adap); ret = adap->algo->master_xfer(adap,&msg,1); I2C_UNLOCK(adap); - DEB2(printk("i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", ret, count, client->addr)); /* if everything went ok (i.e. 1 msg transmitted), return #bytes @@ -835,7 +834,7 @@ */ return (ret == 1 )? count : ret; } else { - printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + printk(KERN_DEBUG "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", client->adapter->id); return -ENOSYS; } @@ -848,7 +847,7 @@ int ret = 0; struct i2c_adapter *adap = client->adapter; - DEB2(printk("i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg)); + DEB2(printk(KERN_DEBUG "i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg)); switch ( cmd ) { case I2C_RETRIES: adap->retries = arg; @@ -893,7 +892,7 @@ if (((adap_id == address_data->force[i]) || (address_data->force[i] == ANY_I2C_BUS)) && (addr == address_data->force[i+1])) { - DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: found force parameter for adapter %d, addr %04x\n", adap_id,addr)); if ((err = found_proc(adapter,addr,0,0))) return err; @@ -911,7 +910,7 @@ if (((adap_id == address_data->ignore[i]) || ((address_data->ignore[i] == ANY_I2C_BUS))) && (addr == address_data->ignore[i+1])) { - DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore parameter for adapter %d, " "addr %04x\n", adap_id ,addr)); found = 1; } @@ -923,7 +922,7 @@ ((address_data->ignore_range[i]==ANY_I2C_BUS))) && (addr >= address_data->ignore_range[i+1]) && (addr <= address_data->ignore_range[i+2])) { - DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore_range parameter for adapter %d, " "addr %04x\n", adap_id,addr)); found = 1; } @@ -938,7 +937,7 @@ i += 1) { if (addr == address_data->normal_i2c[i]) { found = 1; - DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c entry for adapter %d, " "addr %02x", adap_id,addr)); } } @@ -949,7 +948,7 @@ if ((addr >= address_data->normal_i2c_range[i]) && (addr <= address_data->normal_i2c_range[i+1])) { found = 1; - DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c_range entry for adapter %d, " "addr %04x\n", adap_id,addr)); } } @@ -961,7 +960,7 @@ ((address_data->probe[i] == ANY_I2C_BUS))) && (addr == address_data->probe[i+1])) { found = 1; - DEB2(printk("i2c-core.o: found probe parameter for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found probe parameter for adapter %d, " "addr %04x\n", adap_id,addr)); } } @@ -973,7 +972,7 @@ (addr >= address_data->probe_range[i+1]) && (addr <= address_data->probe_range[i+2])) { found = 1; - DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found probe_range parameter for adapter %d, " "addr %04x\n", adap_id,addr)); } } @@ -1110,6 +1109,23 @@ I2C_SMBUS_BLOCK_DATA,&data); } +/* Returns the number of read bytes */ +extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, + u8 command, u8 *values) +{ + union i2c_smbus_data data; + int i; + if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_READ,command, + I2C_SMBUS_I2C_BLOCK_DATA,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values) { @@ -1185,23 +1201,38 @@ break; case I2C_SMBUS_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { - printk("i2c-core.o: Block read not supported under " + printk(KERN_ERR "i2c-core.o: Block read not supported under " "I2C emulation!\n"); return -1; } else { msg[0].len = data->block[0] + 2; if (msg[0].len > 34) { - printk("i2c-core.o: smbus_access called with " + printk(KERN_ERR "i2c-core.o: smbus_access called with " "invalid block write size (%d)\n", - msg[0].len); + data->block[0]); return -1; } for (i = 1; i <= msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + msg[1].len = 32; + } else { + msg[0].len = data->block[0] + 2; + if (msg[0].len > 34) { + printk("i2c-core.o: i2c_smbus_xfer_emulated called with " + "invalid block write size (%d)\n", + data->block[0]); + return -1; + } + for (i = 0; i < data->block[0]; i++) + msgbuf0[i] = data->block[i+1]; + } + break; default: - printk("i2c-core.o: smbus_access called with invalid size (%d)\n", + printk(KERN_ERR "i2c-core.o: smbus_access called with invalid size (%d)\n", size); return -1; } @@ -1221,6 +1252,12 @@ case I2C_SMBUS_PROC_CALL: data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* fixed at 32 for now */ + data->block[0] = 32; + for (i = 0; i < 32; i++) + data->block[i+1] = msgbuf1[i]; + break; } return 0; } @@ -1263,7 +1300,7 @@ static int __init i2c_init(void) { - printk("i2c-core.o: i2c core module\n"); + printk(KERN_INFO "i2c-core.o: i2c core module version %s (%s)\n", I2C_VERSION, I2C_DATE); memset(adapters,0,sizeof(adapters)); memset(drivers,0,sizeof(drivers)); adap_count=0; @@ -1401,6 +1438,8 @@ EXPORT_SYMBOL(i2c_smbus_process_call); EXPORT_SYMBOL(i2c_smbus_read_block_data); EXPORT_SYMBOL(i2c_smbus_write_block_data); +EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); +EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); EXPORT_SYMBOL(i2c_get_functionality); EXPORT_SYMBOL(i2c_check_functionality); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/i2c/i2c-dev.c linux-2.5/drivers/i2c/i2c-dev.c --- linux-2.5.23/drivers/i2c/i2c-dev.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/i2c/i2c-dev.c Tue Jun 4 18:58:21 2002 @@ -28,7 +28,7 @@ /* The devfs code is contributed by Philipp Matthias Hahn */ -/* $Id: i2c-dev.c,v 1.40 2001/08/25 01:28:01 mds Exp $ */ +/* $Id: i2c-dev.c,v 1.44 2001/11/19 18:45:02 mds Exp $ */ #include #include @@ -49,7 +49,6 @@ #include #include - #include #include @@ -140,7 +139,7 @@ { #ifdef DEBUG struct inode *inode = file->f_dentry->d_inode; - printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n", + printk(KERN_DEBUG "i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n", minor(inode->i_rdev),(long) offset,origin); #endif /* DEBUG */ return -ESPIPE; @@ -165,7 +164,7 @@ return -ENOMEM; #ifdef DEBUG - printk("i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev), + printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev), count); #endif @@ -197,7 +196,7 @@ } #ifdef DEBUG - printk("i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev), + printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev), count); #endif ret = i2c_master_send(client,tmp,count); @@ -217,7 +216,7 @@ unsigned long funcs; #ifdef DEBUG - printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", + printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", minor(inode->i_rdev),cmd, arg); #endif /* DEBUG */ @@ -315,7 +314,7 @@ (data_arg.size != I2C_SMBUS_BLOCK_DATA) && (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) { #ifdef DEBUG - printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", + printk(KERN_DEBUG "i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", data_arg.size); #endif return -EINVAL; @@ -325,7 +324,7 @@ if ((data_arg.read_write != I2C_SMBUS_READ) && (data_arg.read_write != I2C_SMBUS_WRITE)) { #ifdef DEBUG - printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", + printk(KERN_DEBUG "i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", data_arg.read_write); #endif return -EINVAL; @@ -345,7 +344,7 @@ if (data_arg.data == NULL) { #ifdef DEBUG - printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n"); + printk(KERN_DEBUG "i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n"); #endif return -EINVAL; } @@ -387,7 +386,7 @@ if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) { #ifdef DEBUG - printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n", + printk(KERN_DEBUG "i2c-dev.o: Trying to open unattached adapter i2c-%d\n", minor); #endif return -ENODEV; @@ -408,7 +407,7 @@ #endif /* LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) */ #ifdef DEBUG - printk("i2c-dev.o: opened i2c-%d\n",minor); + printk(KERN_DEBUG "i2c-dev.o: opened i2c-%d\n",minor); #endif return 0; } @@ -419,13 +418,18 @@ kfree(file->private_data); file->private_data=NULL; #ifdef DEBUG - printk("i2c-dev.o: Closed: i2c-%d\n", minor); + printk(KERN_DEBUG "i2c-dev.o: Closed: i2c-%d\n", minor); #endif #if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) MOD_DEC_USE_COUNT; +#else /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */ + lock_kernel(); #endif /* LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) */ if (i2cdev_adaps[minor]->dec_use) i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]); +#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) + unlock_kernel(); +#endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */ return 0; } @@ -435,11 +439,11 @@ char name[8]; if ((i = i2c_adapter_id(adap)) < 0) { - printk("i2c-dev.o: Unknown adapter ?!?\n"); + printk(KERN_DEBUG "i2c-dev.o: Unknown adapter ?!?\n"); return -ENODEV; } if (i >= I2CDEV_ADAPS_MAX) { - printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i); + printk(KERN_DEBUG "i2c-dev.o: Adapter number too large?!? (%d)\n",i); return -ENODEV; } @@ -452,7 +456,7 @@ S_IFCHR | S_IRUSR | S_IWUSR, &i2cdev_fops, NULL); #endif - printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); + printk(KERN_DEBUG "i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); } else { /* This is actually a detach_adapter call! */ #ifdef CONFIG_DEVFS_FS @@ -460,7 +464,7 @@ #endif i2cdev_adaps[i] = NULL; #ifdef DEBUG - printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name); + printk(KERN_DEBUG "i2c-dev.o: Adapter unregistered: %s\n",adap->name); #endif } @@ -482,7 +486,7 @@ { int res; - printk("i2c-dev.o: i2c /dev entries driver module\n"); + printk(KERN_INFO "i2c-dev.o: i2c /dev entries driver module version %s (%s)\n", I2C_VERSION, I2C_DATE); i2cdev_initialized = 0; #ifdef CONFIG_DEVFS_FS @@ -490,7 +494,7 @@ #else if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) { #endif - printk("i2c-dev.o: unable to get major %d for i2c bus\n", + printk(KERN_ERR "i2c-dev.o: unable to get major %d for i2c bus\n", I2C_MAJOR); return -EIO; } @@ -500,7 +504,7 @@ i2cdev_initialized ++; if ((res = i2c_add_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver registration failed, module not inserted.\n"); + printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n"); i2cdev_cleanup(); return res; } @@ -514,7 +518,7 @@ if (i2cdev_initialized >= 2) { if ((res = i2c_del_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver deregistration failed, " + printk(KERN_ERR "i2c-dev.o: Driver deregistration failed, " "module not removed.\n"); return res; } @@ -528,7 +532,7 @@ #else if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { #endif - printk("i2c-dev.o: unable to release major %d for i2c bus\n", + printk(KERN_ERR "i2c-dev.o: unable to release major %d for i2c bus\n", I2C_MAJOR); return res; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/i2c/i2c-keywest.c linux-2.5/drivers/i2c/i2c-keywest.c --- linux-2.5.23/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.23/drivers/i2c/i2c-keywest.h linux-2.5/drivers/i2c/i2c-keywest.h --- linux-2.5.23/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.23/drivers/i2c/i2c-proc.c linux-2.5/drivers/i2c/i2c-proc.c --- linux-2.5.23/drivers/i2c/i2c-proc.c Wed Jun 19 03:11:55 2002 +++ linux-2.5/drivers/i2c/i2c-proc.c Tue Jun 4 18:58:21 2002 @@ -32,16 +32,10 @@ #include #include #include - #include #include - #include -/* FIXME need i2c versioning */ -#define LM_DATE "20010825" -#define LM_VERSION "2.6.1" - #ifndef THIS_MODULE #define THIS_MODULE NULL #endif @@ -175,6 +169,7 @@ new_table[i].extra2 = client; if (!(new_header = register_sysctl_table(new_table, 0))) { + printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); kfree(new_table); kfree(name); return -ENOMEM; @@ -189,7 +184,7 @@ !new_header->ctl_table->child->child || !new_header->ctl_table->child->child->de) { printk - ("i2c-proc.o: NULL pointer when trying to install fill_inode fix!\n"); + (KERN_ERR "i2c-proc.o: NULL pointer when trying to install fill_inode fix!\n"); return id; } #endif /* DEBUG */ @@ -629,7 +624,7 @@ && (addr == this_force->force[j + 1])) { #ifdef DEBUG printk - ("i2c-proc.o: found force parameter for adapter %d, addr %04x\n", + (KERN_DEBUG "i2c-proc.o: found force parameter for adapter %d, addr %04x\n", adapter_id, addr); #endif if ( @@ -659,7 +654,7 @@ && (addr == address_data->ignore[i + 1])) { #ifdef DEBUG printk - ("i2c-proc.o: found ignore parameter for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found ignore parameter for adapter %d, " "addr %04x\n", adapter_id, addr); #endif found = 1; @@ -679,7 +674,7 @@ && (addr <= address_data->ignore_range[i + 2])) { #ifdef DEBUG printk - ("i2c-proc.o: found ignore_range parameter for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found ignore_range parameter for adapter %d, " "addr %04x\n", adapter_id, addr); #endif found = 1; @@ -698,7 +693,7 @@ if (addr == address_data->normal_isa[i]) { #ifdef DEBUG printk - ("i2c-proc.o: found normal isa entry for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found normal isa entry for adapter %d, " "addr %04x\n", adapter_id, addr); #endif @@ -720,7 +715,7 @@ 0)) { #ifdef DEBUG printk - ("i2c-proc.o: found normal isa_range entry for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found normal isa_range entry for adapter %d, " "addr %04x", adapter_id, addr); #endif found = 1; @@ -734,7 +729,7 @@ found = 1; #ifdef DEBUG printk - ("i2c-proc.o: found normal i2c entry for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found normal i2c entry for adapter %d, " "addr %02x", adapter_id, addr); #endif } @@ -750,7 +745,7 @@ { #ifdef DEBUG printk - ("i2c-proc.o: found normal i2c_range entry for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found normal i2c_range entry for adapter %d, " "addr %04x\n", adapter_id, addr); #endif found = 1; @@ -767,7 +762,7 @@ && (addr == address_data->probe[i + 1])) { #ifdef DEBUG printk - ("i2c-proc.o: found probe parameter for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found probe parameter for adapter %d, " "addr %04x\n", adapter_id, addr); #endif found = 1; @@ -786,7 +781,7 @@ found = 1; #ifdef DEBUG printk - ("i2c-proc.o: found probe_range parameter for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found probe_range parameter for adapter %d, " "addr %04x\n", adapter_id, addr); #endif } @@ -807,11 +802,14 @@ int __init sensors_init(void) { - printk("i2c-proc.o version %s (%s)\n", LM_VERSION, LM_DATE); + printk(KERN_INFO "i2c-proc.o version %s (%s)\n", I2C_VERSION, I2C_DATE); i2c_initialized = 0; if (! (i2c_proc_header = - register_sysctl_table(i2c_proc, 0))) return -ENOMEM; + register_sysctl_table(i2c_proc, 0))) { + printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); + return -EPERM; + } i2c_proc_header->ctl_table->child->de->owner = THIS_MODULE; i2c_initialized++; return 0; @@ -847,4 +845,5 @@ { return i2c_cleanup(); } + #endif /* MODULE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/ide/Config.help linux-2.5/drivers/ide/Config.help --- linux-2.5.23/drivers/ide/Config.help Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/ide/Config.help Mon Jun 17 22:52:27 2002 @@ -282,7 +282,7 @@ motherboard uses a VIA VP2 chipset, in which case you should say N. CONFIG_IDEDMA_IVB - There are unclear terms is ATA-4 and ATA-5 standards how certain + There are unclear terms in ATA-4 and ATA-5 standards how certain hardware (an 80c ribbon) should be detected. Different interpretations of the standards have been released in hardware. This causes problems: for example, a host with Ultra Mode 4 (or higher) will not run diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/ide/hd.c linux-2.5/drivers/ide/hd.c --- linux-2.5.23/drivers/ide/hd.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/drivers/ide/hd.c Mon Jun 17 22:52:27 2002 @@ -132,16 +132,16 @@ unsigned long read_timer(void) { + extern spinlock_t i8253_lock; unsigned long t, flags; int i; - save_flags(flags); - cli(); + spin_lock_irqsave(&i8253_lock, flags); t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); i |= inb(0x40) << 8; - restore_flags(flags); + spin_unlock_irqrestore(&i8253_lock, flags); return(t - i); } #endif @@ -817,8 +817,19 @@ NR_HD = 0; return; } - request_region(HD_DATA, 8, "hd"); - request_region(HD_CMD, 1, "hd(cmd)"); + if (!request_region(HD_DATA, 8, "hd")) { + printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA); + NR_HD = 0; + free_irq(HD_IRQ, NULL); + return; + } + if (!request_region(HD_CMD, 1, "hd(cmd)")) { + printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD); + NR_HD = 0; + free_irq(HD_IRQ, NULL); + release_region(HD_DATA, 8); + return; + } hd_gendisk.nr_real = NR_HD; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/ide/ide-floppy.c linux-2.5/drivers/ide/ide-floppy.c --- linux-2.5.23/drivers/ide/ide-floppy.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/ide/ide-floppy.c Wed Jun 19 11:46:47 2002 @@ -96,6 +96,7 @@ #include #include #include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/ide/ide-tape.c linux-2.5/drivers/ide/ide-tape.c --- linux-2.5.23/drivers/ide/ide-tape.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/ide/ide-tape.c Mon Jun 17 22:52:28 2002 @@ -417,6 +417,7 @@ #include #include #include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/ide/umc8672.c linux-2.5/drivers/ide/umc8672.c --- linux-2.5.23/drivers/ide/umc8672.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/ide/umc8672.c Tue Jun 4 15:30:55 2002 @@ -129,7 +129,7 @@ __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ - if (check_region(0x108, 2)) { + if (!request_region(0x108, 2, "umc8672")) { __restore_flags(flags); printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n"); return; @@ -138,6 +138,7 @@ if (in_umc (0xd5) != 0xa0) { __restore_flags(flags); /* local CPU only */ + release_region(0x108, 2); printk ("umc8672: not found\n"); return; } @@ -146,7 +147,6 @@ umc_set_speeds (current_speeds); __restore_flags(flags); /* local CPU only */ - request_region(0x108, 2, "umc8672"); ide_hwifs[0].chipset = ide_umc8672; ide_hwifs[1].chipset = ide_umc8672; ide_hwifs[0].tuneproc = &tune_umc; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/ieee1394/ieee1394_syms.c linux-2.5/drivers/ieee1394/ieee1394_syms.c --- linux-2.5.23/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.23/drivers/input/Config.help linux-2.5/drivers/input/Config.help --- linux-2.5.23/drivers/input/Config.help Wed Jun 19 03:11:51 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.23/drivers/input/Config.in linux-2.5/drivers/input/Config.in --- linux-2.5.23/drivers/input/Config.in Wed Jun 19 03:11:54 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.23/drivers/input/Makefile linux-2.5/drivers/input/Makefile --- linux-2.5.23/drivers/input/Makefile Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/input/Makefile Mon Jun 17 21:59:23 2002 @@ -13,8 +13,27 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o +obj-$(CONFIG_INPUT_TSDEV) += tsdev.o +obj-$(CONFIG_INPUT_POWER) += power.o +obj-$(CONFIG_INPUT_EVBUG) += evbug.o -obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ +subdir-$(CONFIG_INPUT_KEYBOARD) += keyboard +subdir-$(CONFIG_INPUT_MOUSE) += mouse +subdir-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen + +ifeq ($(CONFIG_INPUT_KEYBOARD),y) + obj-y += keyboard/keybdrv.o +endif + +ifeq ($(CONFIG_INPUT_MOUSE),y) + obj-y += mouse/mousedrv.o +endif + +obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ + +ifeq ($(CONFIG_INPUT_TOUCHSCREEN),y) + obj-y += touchscreen/tsdrv.o +endif # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/input/evbug.c linux-2.5/drivers/input/evbug.c --- linux-2.5.23/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.23/drivers/input/gameport/Config.help linux-2.5/drivers/input/gameport/Config.help --- linux-2.5.23/drivers/input/gameport/Config.help Wed Jun 19 03:11:49 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.23/drivers/input/gameport/Config.in linux-2.5/drivers/input/gameport/Config.in --- linux-2.5.23/drivers/input/gameport/Config.in Wed Jun 19 03:11:45 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.23/drivers/input/gameport/Makefile linux-2.5/drivers/input/gameport/Makefile --- linux-2.5.23/drivers/input/gameport/Makefile Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/input/gameport/Makefile Sat Jun 1 00:34:35 2002 @@ -11,9 +11,10 @@ obj-$(CONFIG_GAMEPORT) += gameport.o obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o +obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o obj-$(CONFIG_GAMEPORT_L4) += lightning.o obj-$(CONFIG_GAMEPORT_NS558) += ns558.o -obj-$(CONFIG_GAMEPORT_PCIGAME) += pcigame.o +obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/input/gameport/fm801-gp.c linux-2.5/drivers/input/gameport/fm801-gp.c --- linux-2.5.23/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.23/drivers/input/gameport/gameport.c linux-2.5/drivers/input/gameport/gameport.c --- linux-2.5.23/drivers/input/gameport/gameport.c Wed Jun 19 03:11:55 2002 +++ linux-2.5/drivers/input/gameport/gameport.c Tue Jun 4 15:21:35 2002 @@ -54,16 +54,36 @@ static struct gameport *gameport_list; static struct gameport_dev *gameport_dev; + +#ifdef __i386__ + +#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180/HZ:0)) +#define GET_TIME(x) do { x = get_time_pit(); } while (0) + +static unsigned int get_time_pit(void) +{ + extern spinlock_t i8253_lock; + unsigned long flags; + unsigned int count; + + spin_lock_irqsave(&i8253_lock, flags); + outb_p(0x00, 0x43); + count = inb_p(0x40); + count |= inb_p(0x40) << 8; + spin_unlock_irqrestore(&i8253_lock, flags); + + return count; +} + +#endif + /* * gameport_measure_speed() measures the gameport i/o speed. */ static int gameport_measure_speed(struct gameport *gameport) { -#if defined(__i386__) || defined(__x86_64__) - -#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0) -#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0)) +#ifdef __i386__ unsigned int i, t, t1, t2, t3, tx; unsigned long flags; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/input/gameport/ns558.c linux-2.5/drivers/input/gameport/ns558.c --- linux-2.5.23/drivers/input/gameport/ns558.c Wed Jun 19 03:11:51 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.23/drivers/input/gameport/pcigame.c linux-2.5/drivers/input/gameport/pcigame.c --- linux-2.5.23/drivers/input/gameport/pcigame.c Wed Jun 19 03:11:48 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.23/drivers/input/gameport/vortex.c linux-2.5/drivers/input/gameport/vortex.c --- linux-2.5.23/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.23/drivers/input/input.c linux-2.5/drivers/input/input.c --- linux-2.5.23/drivers/input/input.c Wed Jun 19 03:11:56 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.23/drivers/input/joystick/Config.help linux-2.5/drivers/input/joystick/Config.help --- linux-2.5.23/drivers/input/joystick/Config.help Wed Jun 19 03:11:47 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.23/drivers/input/joystick/Config.in linux-2.5/drivers/input/joystick/Config.in --- linux-2.5.23/drivers/input/joystick/Config.in Wed Jun 19 03:11:58 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.23/drivers/input/joystick/Makefile linux-2.5/drivers/input/joystick/Makefile --- linux-2.5.23/drivers/input/joystick/Makefile Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/input/joystick/Makefile Sat May 25 19:03:28 2002 @@ -2,24 +2,6 @@ # Makefile for the input core drivers. # -# I-Force may need both USB and RS-232 - -CONFIG_JOYSTICK_IFORCE := n - -ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) - ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) - CONFIG_JOYSTICK_IFORCE := y - endif -endif - -ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m) - CONFIG_JOYSTICK_IFORCE := m -endif - -ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m) - CONFIG_JOYSTICK_IFORCE := m -endif - # Each configuration option enables a list of files. obj-$(CONFIG_JOYSTICK_A3D) += a3d.o @@ -31,8 +13,9 @@ obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o obj-$(CONFIG_JOYSTICK_GRIP) += grip.o -obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o +obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o +obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o @@ -40,7 +23,32 @@ obj-$(CONFIG_JOYSTICK_STINGER) += stinger.o obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o +obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o + +# I-Force may need both USB and RS-232 + +CONFIG_JOYSTICK_IFORCE := n + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) + ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) + CONFIG_JOYSTICK_IFORCE := y + endif +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +subdir-$(CONFIG_JOYSTICK_IFORCE) += iforce + +ifeq ($(CONFIG_JOYSTICK_IFORCE),y) + obj-y += iforce/iforce-drv.o +endif # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/input/joystick/guillemot.c linux-2.5/drivers/input/joystick/guillemot.c --- linux-2.5.23/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.23/drivers/input/joystick/iforce/Makefile linux-2.5/drivers/input/joystick/iforce/Makefile --- linux-2.5.23/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.23/drivers/input/joystick/iforce/iforce-ff.c linux-2.5/drivers/input/joystick/iforce/iforce-ff.c --- linux-2.5.23/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.23/drivers/input/joystick/iforce/iforce-main.c linux-2.5/drivers/input/joystick/iforce/iforce-main.c --- linux-2.5.23/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.23/drivers/input/joystick/iforce/iforce-packets.c linux-2.5/drivers/input/joystick/iforce/iforce-packets.c --- linux-2.5.23/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.23/drivers/input/joystick/iforce/iforce-serio.c linux-2.5/drivers/input/joystick/iforce/iforce-serio.c --- linux-2.5.23/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.23/drivers/input/joystick/iforce/iforce-usb.c linux-2.5/drivers/input/joystick/iforce/iforce-usb.c --- linux-2.5.23/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.23/drivers/input/joystick/iforce/iforce.h linux-2.5/drivers/input/joystick/iforce/iforce.h --- linux-2.5.23/drivers/input/joystick/iforce/iforce.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce.h Mon May 6 17:56:45 2002 @@ -0,0 +1,195 @@ +/* + * $Id: iforce.h,v 1.3 2001/10/23 21:20:54 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* FF: This module provides arbitrary resource management routines. + * I use it to manage the device's memory. + * Despite the name of this module, I am *not* going to access the ioports. + */ +#include + +#define IFORCE_MAX_LENGTH 16 + +#if defined(CONFIG_JOYSTICK_IFORCE_232) || defined(CONFIG_JOYSTICK_IFORCE_232_MODULE) +#define IFORCE_232 1 +#endif +#if defined(CONFIG_JOYSTICK_IFORCE_USB) || defined(CONFIG_JOYSTICK_IFORCE_USB_MODULE) +#define IFORCE_USB 2 +#endif + +#define FALSE 0 +#define TRUE 1 + +#define FF_EFFECTS_MAX 32 + +/* Each force feedback effect is made of one core effect, which can be + * associated to at most to effect modifiers + */ +#define FF_MOD1_IS_USED 0 +#define FF_MOD2_IS_USED 1 +#define FF_CORE_IS_USED 2 +#define FF_CORE_IS_PLAYED 3 /* Effect is actually being played */ +#define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */ +#define FF_CORE_UPDATE 5 /* Effect is being updated */ +#define FF_MODCORE_MAX 5 + +#define CHECK_OWNERSHIP(i, iforce) \ + ((i) < FF_EFFECTS_MAX && i >= 0 && \ + test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \ + (current->pid == 0 || \ + (iforce)->core_effects[(i)].owner == current->pid)) + +struct iforce_core_effect { + /* Information about where modifiers are stored in the device's memory */ + struct resource mod1_chunk; + struct resource mod2_chunk; + unsigned long flags[NBITS(FF_MODCORE_MAX)]; + pid_t owner; + /* Used to keep track of parameters of an effect. They are needed + * to know what parts of an effect changed in an update operation. + * We try to send only parameter packets if possible, as sending + * effect parameter requires the effect to be stoped and restarted + */ + struct ff_effect effect; +}; + +#define FF_CMD_EFFECT 0x010e +#define FF_CMD_SHAPE 0x0208 +#define FF_CMD_MAGNITUDE 0x0303 +#define FF_CMD_PERIOD 0x0407 +#define FF_CMD_INTERACT 0x050a + +#define FF_CMD_AUTOCENTER 0x4002 +#define FF_CMD_PLAY 0x4103 +#define FF_CMD_ENABLE 0x4201 +#define FF_CMD_GAIN 0x4301 + +#define FF_CMD_QUERY 0xff01 + +/* Buffer for async write */ +#define XMIT_SIZE 256 +#define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1 +/* iforce::xmit_flags */ +#define IFORCE_XMIT_RUNNING 0 +#define IFORCE_XMIT_AGAIN 1 + +struct iforce_device { + u16 idvendor; + u16 idproduct; + char *name; + signed short *btn; + signed short *abs; + signed short *ff; +}; + +struct iforce { + struct input_dev dev; /* Input device interface */ + struct iforce_device *type; + char name[64]; + char phys[64]; + int open; + int bus; + + unsigned char data[IFORCE_MAX_LENGTH]; + unsigned char edata[IFORCE_MAX_LENGTH]; + u16 ecmd; + u16 expect_packet; + +#ifdef IFORCE_232 + struct serio *serio; /* RS232 transfer */ + int idx, pkt, len, id; + unsigned char csum; +#endif +#ifdef IFORCE_USB + struct usb_device *usbdev; /* USB transfer */ + struct urb irq, out, ctrl; + struct usb_ctrlrequest cr; +#endif + spinlock_t xmit_lock; + /* Buffer used for asynchronous sending of bytes to the device */ + struct circ_buf xmit; + unsigned char xmit_data[XMIT_SIZE]; + long xmit_flags[1]; + + /* Force Feedback */ + wait_queue_head_t wait; + struct resource device_memory; + struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; + struct semaphore mem_mutex; +}; + +/* Get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +/* For many parameters, it seems that 0x80 is a special value that should + * be avoided. Instead, we replace this value by 0x7f + */ +#define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8)) + +/* Encode a time value */ +#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256) + + +/* Public functions */ +/* iforce-serio.c */ +void iforce_serial_xmit(struct iforce *iforce); + +/* iforce-usb.c */ +void iforce_usb_xmit(struct iforce *iforce); + +/* iforce-main.c */ +int iforce_init_device(struct iforce *iforce); + +/* iforce-packets.c */ +int iforce_control_playback(struct iforce*, u16 id, unsigned int); +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; +int iforce_get_id_packet(struct iforce *iforce, char *packet); + +/* iforce-ff.c */ +int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); +int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); +int iforce_upload_interactive(struct iforce*, struct ff_effect*, int is_update); + +/* Public variables */ +extern struct serio_dev iforce_serio_dev; +extern struct usb_driver iforce_usb_driver; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/input/joystick/iforce.c linux-2.5/drivers/input/joystick/iforce.c --- linux-2.5.23/drivers/input/joystick/iforce.c Wed Jun 19 03:11:57 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.23/drivers/input/joystick/joydump.c linux-2.5/drivers/input/joystick/joydump.c --- linux-2.5.23/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.23/drivers/input/joystick/twidjoy.c linux-2.5/drivers/input/joystick/twidjoy.c --- linux-2.5.23/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.23/drivers/input/keybdev.c linux-2.5/drivers/input/keybdev.c --- linux-2.5.23/drivers/input/keybdev.c Wed Jun 19 03:11:57 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.23/drivers/input/keyboard/Config.help linux-2.5/drivers/input/keyboard/Config.help --- linux-2.5.23/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.23/drivers/input/keyboard/Config.in linux-2.5/drivers/input/keyboard/Config.in --- linux-2.5.23/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.23/drivers/input/keyboard/Makefile linux-2.5/drivers/input/keyboard/Makefile --- linux-2.5.23/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.23/drivers/input/keyboard/amikbd.c linux-2.5/drivers/input/keyboard/amikbd.c --- linux-2.5.23/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.23/drivers/input/keyboard/atkbd.c linux-2.5/drivers/input/keyboard/atkbd.c --- linux-2.5.23/drivers/input/keyboard/atkbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/atkbd.c Wed Jun 19 08:08:32 2002 @@ -0,0 +1,552 @@ +/* + * $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 +#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.23/drivers/input/keyboard/maple_keyb.c linux-2.5/drivers/input/keyboard/maple_keyb.c --- linux-2.5.23/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.23/drivers/input/keyboard/ps2serkbd.c linux-2.5/drivers/input/keyboard/ps2serkbd.c --- linux-2.5.23/drivers/input/keyboard/ps2serkbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/ps2serkbd.c Wed Jun 19 20:13:11 2002 @@ -0,0 +1,298 @@ +/* + * 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 +#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.23/drivers/input/keyboard/sunkbd.c linux-2.5/drivers/input/keyboard/sunkbd.c --- linux-2.5.23/drivers/input/keyboard/sunkbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/sunkbd.c Wed Jun 19 20:13:11 2002 @@ -0,0 +1,318 @@ +/* + * $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 +#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.23/drivers/input/keyboard/xtkbd.c linux-2.5/drivers/input/keyboard/xtkbd.c --- linux-2.5.23/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.23/drivers/input/mouse/Config.help linux-2.5/drivers/input/mouse/Config.help --- linux-2.5.23/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.23/drivers/input/mouse/Config.in linux-2.5/drivers/input/mouse/Config.in --- linux-2.5.23/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.23/drivers/input/mouse/Makefile linux-2.5/drivers/input/mouse/Makefile --- linux-2.5.23/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.23/drivers/input/mouse/amimouse.c linux-2.5/drivers/input/mouse/amimouse.c --- linux-2.5.23/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.23/drivers/input/mouse/inport.c linux-2.5/drivers/input/mouse/inport.c --- linux-2.5.23/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.23/drivers/input/mouse/logibm.c linux-2.5/drivers/input/mouse/logibm.c --- linux-2.5.23/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.23/drivers/input/mouse/maplemouse.c linux-2.5/drivers/input/mouse/maplemouse.c --- linux-2.5.23/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.23/drivers/input/mouse/pc110pad.c linux-2.5/drivers/input/mouse/pc110pad.c --- linux-2.5.23/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.23/drivers/input/mouse/psmouse.c linux-2.5/drivers/input/mouse/psmouse.c --- linux-2.5.23/drivers/input/mouse/psmouse.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/psmouse.c Wed Jun 19 08:24:43 2002 @@ -0,0 +1,652 @@ +/* + * $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 +#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.23/drivers/input/mouse/rpcmouse.c linux-2.5/drivers/input/mouse/rpcmouse.c --- linux-2.5.23/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.23/drivers/input/mouse/sermouse.c linux-2.5/drivers/input/mouse/sermouse.c --- linux-2.5.23/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.23/drivers/input/power.c linux-2.5/drivers/input/power.c --- linux-2.5.23/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.23/drivers/input/serio/Config.help linux-2.5/drivers/input/serio/Config.help --- linux-2.5.23/drivers/input/serio/Config.help Wed Jun 19 03:11:45 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.23/drivers/input/serio/Config.in linux-2.5/drivers/input/serio/Config.in --- linux-2.5.23/drivers/input/serio/Config.in Wed Jun 19 03:11:56 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.23/drivers/input/serio/Makefile linux-2.5/drivers/input/serio/Makefile --- linux-2.5.23/drivers/input/serio/Makefile Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/input/serio/Makefile Sat Jun 1 00:34:35 2002 @@ -9,7 +9,11 @@ # Each configuration option enables a list of files. obj-$(CONFIG_SERIO) += serio.o +obj-$(CONFIG_SERIO_I8042) += i8042.o +obj-$(CONFIG_SERIO_PARKBD) += parkbd.o obj-$(CONFIG_SERIO_SERPORT) += serport.o +obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o +obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/input/serio/ct82c710.c linux-2.5/drivers/input/serio/ct82c710.c --- linux-2.5.23/drivers/input/serio/ct82c710.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/ct82c710.c Wed Jun 19 20:12:57 2002 @@ -0,0 +1,212 @@ +/* + * $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 +#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.23/drivers/input/serio/i8042.c linux-2.5/drivers/input/serio/i8042.c --- linux-2.5.23/drivers/input/serio/i8042.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/i8042.c Tue Jun 18 02:27:54 2002 @@ -0,0 +1,708 @@ +/* + * $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 /* request/free_irq */ + +#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.23/drivers/input/serio/i8042.h linux-2.5/drivers/input/serio/i8042.h --- linux-2.5.23/drivers/input/serio/i8042.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/i8042.h Mon May 6 17:57:35 2002 @@ -0,0 +1,128 @@ +#ifndef _I8042_H +#define _I8042_H + +/* + * $Id: i8042.h,v 1.6 2001/10/05 22:48:09 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +/* + * If you want to reset your i8042 upon boot, define this. + */ + +#undef I8042_RESET + +/* + * If you want to trace all the i/o the i8042 module does for + * debugging purposes, define this. + */ + +#undef I8042_DEBUG_IO + +/* + * On most PC based systems the keyboard IRQ is 1. + */ + +#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ + +/* + * On most PC based systems the aux port IRQ is 12. There are exceptions, + * though. Unfortunately IRQ probing is not possible without touching + * the device attached to the port. + */ + +#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ + +/* + * This is in 50us units, the time we wait for the i8042 to react. This + * has to be long enough for the i8042 itself to timeout on sending a byte + * to a non-existent mouse. + */ + +#define I8042_CTL_TIMEOUT 10000 + +/* + * Register numbers. + */ + +#define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4 +#define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4 +#define I8042_DATA_REG CONFIG_I8042_REG_BASE + +/* + * Status register bits. + */ + +#define I8042_STR_PARITY 0x80 +#define I8042_STR_TIMEOUT 0x40 +#define I8042_STR_AUXDATA 0x20 +#define I8042_STR_KEYLOCK 0x10 +#define I8042_STR_CMDDAT 0x08 +#define I8042_STR_IBF 0x02 +#define I8042_STR_OBF 0x01 + +/* + * Control register bits. + */ + +#define I8042_CTR_KBDINT 0x01 +#define I8042_CTR_AUXINT 0x02 +#define I8042_CTR_IGNKEYLOCK 0x08 +#define I8042_CTR_KBDDIS 0x10 +#define I8042_CTR_AUXDIS 0x20 +#define I8042_CTR_XLATE 0x40 + +/* + * Commands. + */ + +#define I8042_CMD_CTL_RCTR 0x0120 +#define I8042_CMD_CTL_WCTR 0x1060 +#define I8042_CMD_CTL_TEST 0x01aa + +#define I8042_CMD_KBD_DISABLE 0x00ad +#define I8042_CMD_KBD_ENABLE 0x00ae +#define I8042_CMD_KBD_TEST 0x01ab +#define I8042_CMD_KBD_LOOP 0x11d2 + +#define I8042_CMD_AUX_DISABLE 0x00a7 +#define I8042_CMD_AUX_ENABLE 0x00a8 +#define I8042_CMD_AUX_TEST 0x01a9 +#define I8042_CMD_AUX_SEND 0x10d4 +#define I8042_CMD_AUX_LOOP 0x11d3 + +/* + * Return codes. + */ + +#define I8042_RET_CTL_TEST 0x55 + +/* + * Expected maximum internal i8042 buffer size. This is used for flushing + * the i8042 buffers. 32 should be more than enough. + */ + +#define I8042_BUFFER_SIZE 32 + +#endif /* _I8042_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/input/serio/parkbd.c linux-2.5/drivers/input/serio/parkbd.c --- linux-2.5.23/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.23/drivers/input/serio/rpckbd.c linux-2.5/drivers/input/serio/rpckbd.c --- linux-2.5.23/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.23/drivers/input/touchscreen/Config.help linux-2.5/drivers/input/touchscreen/Config.help --- linux-2.5.23/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.23/drivers/input/touchscreen/Config.in linux-2.5/drivers/input/touchscreen/Config.in --- linux-2.5.23/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.23/drivers/input/touchscreen/Makefile linux-2.5/drivers/input/touchscreen/Makefile --- linux-2.5.23/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.23/drivers/input/touchscreen/gunze.c linux-2.5/drivers/input/touchscreen/gunze.c --- linux-2.5.23/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.23/drivers/input/tsdev.c linux-2.5/drivers/input/tsdev.c --- linux-2.5.23/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.23/drivers/isdn/eicon/eicon_idi.c linux-2.5/drivers/isdn/eicon/eicon_idi.c --- linux-2.5.23/drivers/isdn/eicon/eicon_idi.c Wed Jun 19 03:11:44 2002 +++ linux-2.5/drivers/isdn/eicon/eicon_idi.c Tue Jun 4 21:11:17 2002 @@ -2972,7 +2972,7 @@ spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No); if (xmit_skb) - dev_kfree_skb(skb); + dev_kfree_skb(xmit_skb); if (skb2) dev_kfree_skb(skb2); return -ENOMEM; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/isdn/hardware/avm/b1.c linux-2.5/drivers/isdn/hardware/avm/b1.c --- linux-2.5.23/drivers/isdn/hardware/avm/b1.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/isdn/hardware/avm/b1.c Sat Jun 1 00:34:35 2002 @@ -59,6 +59,21 @@ /* ------------------------------------------------------------- */ +void b1_set_revision(struct capi_driver *driver, char *rev) +{ + char *p; + + if ((p = strchr(rev, ':')) != 0 && p[1]) { + strncpy(driver->revision, p + 2, sizeof(driver->revision)); + driver->revision[sizeof(driver->revision)-1] = 0; + if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) + *(p-1) = 0; + } + printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); +} + +/* ------------------------------------------------------------- */ + avmcard *b1_alloc_card(int nr_controllers) { avmcard *card; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/macintosh/via-pmu.c linux-2.5/drivers/macintosh/via-pmu.c --- linux-2.5.23/drivers/macintosh/via-pmu.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/macintosh/via-pmu.c Fri Jun 7 02:36:08 2002 @@ -2575,7 +2575,7 @@ disable_kernel_backlight--; spin_unlock_irqrestore(&pmu_lock, flags); } -#endif defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) +#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ kfree(pp); } unlock_kernel(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/md/Config.in linux-2.5/drivers/md/Config.in --- linux-2.5.23/drivers/md/Config.in Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/md/Config.in Sun May 26 01:10:56 2002 @@ -13,6 +13,6 @@ dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD -dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD +dep_tristate ' Logical volume manager (LVM) support (EXPERIMENTAL)' CONFIG_BLK_DEV_LVM $CONFIG_MD $CONFIG_EXPERIMENTAL endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/md/lvm-fs.c linux-2.5/drivers/md/lvm-fs.c --- linux-2.5.23/drivers/md/lvm-fs.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/md/lvm-fs.c Sun May 26 01:12:46 2002 @@ -59,9 +59,9 @@ static int _proc_read_global(char *page, char **start, off_t off, int count, int *eof, void *data); -static int _vg_info(vg_t *vg_ptr, char *buf); -static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf); -static int _pv_info(pv_t *pv_ptr, char *buf); +static int _vg_info(kern_vg_t *vg_ptr, char *buf); +static int _lv_info(kern_vg_t *vg_ptr, kern_lv_t *lv_ptr, char *buf); +static int _pv_info(kern_pv_t *pv_ptr, char *buf); static void _show_uuid(const char *src, char *b, char *e); @@ -102,11 +102,16 @@ remove_proc_entry(LVM_DIR, &proc_root); } -void lvm_fs_create_vg(vg_t *vg_ptr) { +void lvm_fs_create_vg(kern_vg_t *vg_ptr) { struct proc_dir_entry *pde; + devfs_handle_t th; - vg_devfs_handle[vg_ptr->vg_number] = - devfs_mk_dir(0, vg_ptr->vg_name, NULL); + th=devfs_get_handle(NULL,vg_ptr->vg_name,0,0,0,0); + + if(th==NULL){ + th=devfs_mk_dir(0, vg_ptr->vg_name, NULL); + } + vg_devfs_handle[vg_ptr->vg_number] = th; ch_devfs_handle[vg_ptr->vg_number] = devfs_register( vg_devfs_handle[vg_ptr->vg_number] , "group", @@ -129,7 +134,7 @@ create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde); } -void lvm_fs_remove_vg(vg_t *vg_ptr) { +void lvm_fs_remove_vg(kern_vg_t *vg_ptr) { int i; devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]); @@ -168,13 +173,13 @@ return name; } -devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv) { +devfs_handle_t lvm_fs_create_lv(kern_vg_t *vg_ptr, kern_lv_t *lv) { struct proc_dir_entry *pde; - const char *name = _basename(lv->u.lv_name); + const char *name = _basename(lv->lv_name); - lv_devfs_handle[minor(lv->u.lv_dev)] = devfs_register( + lv_devfs_handle[minor(lv->lv_kdev)] = devfs_register( vg_devfs_handle[vg_ptr->vg_number], name, - DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, minor(lv->u.lv_dev), + DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, minor(lv->lv_kdev), S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_blk_dops, NULL); @@ -183,15 +188,15 @@ pde->read_proc = _proc_read_lv; pde->data = lv; } - return lv_devfs_handle[minor(lv->u.lv_dev)]; + return lv_devfs_handle[minor(lv->lv_kdev)]; } -void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) { - devfs_unregister(lv_devfs_handle[minor(lv->u.lv_dev)]); - lv_devfs_handle[minor(lv->u.lv_dev)] = NULL; +void lvm_fs_remove_lv(kern_vg_t *vg_ptr, kern_lv_t *lv) { + devfs_unregister(lv_devfs_handle[minor(lv->lv_kdev)]); + lv_devfs_handle[minor(lv->lv_kdev)] = NULL; if(vg_ptr->lv_subdir_pde) { - const char *name = _basename(lv->u.lv_name); + const char *name = _basename(lv->lv_name); remove_proc_entry(name, vg_ptr->lv_subdir_pde); } } @@ -211,7 +216,7 @@ *b = '\0'; } -void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv) { +void lvm_fs_create_pv(kern_vg_t *vg_ptr, kern_pv_t *pv) { struct proc_dir_entry *pde; char name[NAME_LEN]; @@ -225,7 +230,7 @@ } } -void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv) { +void lvm_fs_remove_pv(kern_vg_t *vg_ptr, kern_pv_t *pv) { char name[NAME_LEN]; if(!vg_ptr->pv_subdir_pde) @@ -239,7 +244,7 @@ static int _proc_read_vg(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; - vg_t *vg_ptr = data; + kern_vg_t *vg_ptr = data; char uuid[NAME_LEN]; sz += sprintf(page + sz, "name: %s\n", vg_ptr->vg_name); @@ -267,23 +272,23 @@ static int _proc_read_lv(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; - lv_t *lv = data; + kern_lv_t *lv = data; - sz += sprintf(page + sz, "name: %s\n", lv->u.lv_name); - sz += sprintf(page + sz, "size: %u\n", lv->u.lv_size); - sz += sprintf(page + sz, "access: %u\n", lv->u.lv_access); - sz += sprintf(page + sz, "status: %u\n", lv->u.lv_status); - sz += sprintf(page + sz, "number: %u\n", lv->u.lv_number); - sz += sprintf(page + sz, "open: %u\n", lv->u.lv_open); - sz += sprintf(page + sz, "allocation: %u\n", lv->u.lv_allocation); - if(lv->u.lv_stripes > 1) { - sz += sprintf(page + sz, "stripes: %u\n", - lv->u.lv_stripes); - sz += sprintf(page + sz, "stripesize: %u\n", - lv->u.lv_stripesize); - } + sz += sprintf(page + sz, "name: %s\n", lv->lv_name); + sz += sprintf(page + sz, "size: %u\n", lv->lv_size); + sz += sprintf(page + sz, "access: %u\n", lv->lv_access); + sz += sprintf(page + sz, "status: %u\n", lv->lv_status); + sz += sprintf(page + sz, "number: %u\n", lv->lv_number); + sz += sprintf(page + sz, "open: %u\n", lv->lv_open); + sz += sprintf(page + sz, "allocation: %u\n", lv->lv_allocation); + if(lv->lv_stripes > 1) { + sz += sprintf(page + sz, "stripes: %u\n", + lv->lv_stripes); + sz += sprintf(page + sz, "stripesize: %u\n", + lv->lv_stripesize); + } sz += sprintf(page + sz, "device: %02u:%02u\n", - major(lv->u.lv_dev), minor(lv->u.lv_dev)); + major(lv->lv_kdev), minor(lv->lv_kdev)); return sz; } @@ -291,7 +296,7 @@ static int _proc_read_pv(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; - pv_t *pv = data; + kern_pv_t *pv = data; char uuid[NAME_LEN]; sz += sprintf(page + sz, "name: %s\n", pv->pv_name); @@ -304,7 +309,7 @@ sz += sprintf(page + sz, "PE total: %u\n", pv->pe_total); sz += sprintf(page + sz, "PE allocated: %u\n", pv->pe_allocated); sz += sprintf(page + sz, "device: %02u:%02u\n", - major(pv->pv_dev), minor(pv->pv_dev)); + major(pv->pv_kdev), minor(pv->pv_kdev)); _show_uuid(pv->pv_uuid, uuid, uuid + sizeof(uuid)); sz += sprintf(page + sz, "uuid: %s\n", uuid); @@ -323,9 +328,9 @@ off_t sz_last; static char *buf = NULL; static char dummy_buf[160]; /* sized for 2 lines */ - vg_t *vg_ptr; - lv_t *lv_ptr; - pv_t *pv_ptr; + kern_vg_t *vg_ptr; + kern_lv_t *lv_ptr; + kern_pv_t *pv_ptr; #ifdef DEBUG_LVM_PROC_GET_INFO @@ -350,13 +355,13 @@ if (vg_ptr->lv_cur > 0) { for (l = 0; l < vg[v]->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL) { - pe_t_bytes += lv_ptr->u.lv_allocated_le; + pe_t_bytes += lv_ptr->lv_allocated_le; hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size; - if (lv_ptr->u.lv_block_exception != NULL) - lv_block_exception_t_bytes += lv_ptr->u.lv_remap_end; - if (lv_ptr->u.lv_open > 0) { + if (lv_ptr->lv_block_exception != NULL) + lv_block_exception_t_bytes += lv_ptr->lv_remap_end; + if (lv_ptr->lv_open > 0) { lv_open_counter++; - lv_open_total += lv_ptr->u.lv_open; + lv_open_total += lv_ptr->lv_open; } } } @@ -364,7 +369,7 @@ } } - pe_t_bytes *= sizeof(pe_t); + pe_t_bytes *= sizeof(kern_pe_t); lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); if (buf != NULL) { @@ -403,9 +408,9 @@ sz += sprintf(LVM_PROC_BUF, ")"); sz += sprintf(LVM_PROC_BUF, "\nGlobal: %lu bytes malloced IOP version: %d ", - vg_counter * sizeof(vg_t) + - pv_counter * sizeof(pv_t) + - lv_counter * sizeof(lv_t) + + vg_counter * sizeof(kern_vg_t) + + pv_counter * sizeof(kern_pv_t) + + lv_counter * sizeof(kern_lv_t) + pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last, lvm_iop_version); @@ -497,7 +502,7 @@ /* * provide VG info for proc filesystem use (global) */ -static int _vg_info(vg_t *vg_ptr, char *buf) { +static int _vg_info(kern_vg_t *vg_ptr, char *buf) { int sz = 0; char inactive_flag = ' '; @@ -527,21 +532,21 @@ /* * provide LV info for proc filesystem use (global) */ -static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) { +static int _lv_info(kern_vg_t *vg_ptr, kern_lv_t *lv_ptr, char *buf) { int sz = 0; char inactive_flag = 'A', allocation_flag = ' ', stripes_flag = ' ', rw_flag = ' ', *basename; - if (!(lv_ptr->u.lv_status & LV_ACTIVE)) + if (!(lv_ptr->lv_status & LV_ACTIVE)) inactive_flag = 'I'; rw_flag = 'R'; - if (lv_ptr->u.lv_access & LV_WRITE) + if (lv_ptr->lv_access & LV_WRITE) rw_flag = 'W'; allocation_flag = 'D'; - if (lv_ptr->u.lv_allocation & LV_CONTIGUOUS) + if (lv_ptr->lv_allocation & LV_CONTIGUOUS) allocation_flag = 'C'; stripes_flag = 'L'; - if (lv_ptr->u.lv_stripes > 1) + if (lv_ptr->lv_stripes > 1) stripes_flag = 'S'; sz += sprintf(buf+sz, "[%c%c%c%c", @@ -549,29 +554,29 @@ rw_flag, allocation_flag, stripes_flag); - if (lv_ptr->u.lv_stripes > 1) + if (lv_ptr->lv_stripes > 1) sz += sprintf(buf+sz, "%-2d", - lv_ptr->u.lv_stripes); + lv_ptr->lv_stripes); else sz += sprintf(buf+sz, " "); /* FIXME: use _basename */ - basename = strrchr(lv_ptr->u.lv_name, '/'); - if ( basename == 0) basename = lv_ptr->u.lv_name; + basename = strrchr(lv_ptr->lv_name, '/'); + if ( basename == 0) basename = lv_ptr->lv_name; else basename++; sz += sprintf(buf+sz, "] %-25s", basename); if (strlen(basename) > 25) sz += sprintf(buf+sz, "\n "); sz += sprintf(buf+sz, "%9d /%-6d ", - lv_ptr->u.lv_size >> 1, - lv_ptr->u.lv_size / vg_ptr->pe_size); + lv_ptr->lv_size >> 1, + lv_ptr->lv_size / vg_ptr->pe_size); - if (lv_ptr->u.lv_open == 0) + if (lv_ptr->lv_open == 0) sz += sprintf(buf+sz, "close"); else sz += sprintf(buf+sz, "%dx open", - lv_ptr->u.lv_open); + lv_ptr->lv_open); return sz; } @@ -580,7 +585,7 @@ /* * provide PV info for proc filesystem use (global) */ -static int _pv_info(pv_t *pv, char *buf) { +static int _pv_info(kern_pv_t *pv, char *buf) { int sz = 0; char inactive_flag = 'A', allocation_flag = ' '; char *pv_name = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/md/lvm-internal.h linux-2.5/drivers/md/lvm-internal.h --- linux-2.5.23/drivers/md/lvm-internal.h Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/md/lvm-internal.h Sun May 26 01:10:56 2002 @@ -42,7 +42,7 @@ extern const char *const lvm_name; -extern vg_t *vg[]; +extern kern_vg_t *vg[]; extern struct file_operations lvm_chr_fops; extern struct block_device_operations lvm_blk_dops; @@ -73,29 +73,29 @@ #define P_DEV(fmt, args...) #endif - +#ifdef BROKEN /* lvm-snap.c */ int lvm_get_blksize(kdev_t); -int lvm_snapshot_alloc(lv_t *); -int lvm_snapshot_fill_COW_page(vg_t *, lv_t *); -int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, vg_t *vg, lv_t *); -int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *); -void lvm_snapshot_release(lv_t *); -int lvm_write_COW_table_block(vg_t *, lv_t *); -void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, lv_t *); -int lvm_snapshot_alloc_hash_table(lv_t *); -void lvm_drop_snapshot(vg_t *vg, lv_t *, const char *); - +int lvm_snapshot_alloc(kern_lv_t *); +int lvm_snapshot_fill_COW_page(kern_vg_t *, kern_lv_t *); +int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, kern_vg_t *vg, kern_lv_t *); +int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, kern_lv_t *); +void lvm_snapshot_release(kern_lv_t *); +int lvm_write_COW_table_block(kern_vg_t *, kern_lv_t *); +void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, kern_lv_t *); +int lvm_snapshot_alloc_hash_table(kern_lv_t *); +void lvm_drop_snapshot(kern_vg_t *vg, kern_lv_t *, const char *); +#endif /* lvm_fs.c */ void lvm_init_fs(void); void lvm_fin_fs(void); -void lvm_fs_create_vg(vg_t *vg_ptr); -void lvm_fs_remove_vg(vg_t *vg_ptr); -devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv); -void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv); -void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv); -void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv); +void lvm_fs_create_vg(kern_vg_t *vg_ptr); +void lvm_fs_remove_vg(kern_vg_t *vg_ptr); +devfs_handle_t lvm_fs_create_lv(kern_vg_t *vg_ptr, kern_lv_t *lv); +void lvm_fs_remove_lv(kern_vg_t *vg_ptr, kern_lv_t *lv); +void lvm_fs_create_pv(kern_vg_t *vg_ptr, kern_pv_t *pv); +void lvm_fs_remove_pv(kern_vg_t *vg_ptr, kern_pv_t *pv); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/md/lvm-snap.c linux-2.5/drivers/md/lvm-snap.c --- linux-2.5.23/drivers/md/lvm-snap.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/md/lvm-snap.c Wed Jun 19 07:35:18 2002 @@ -1,3 +1,4 @@ +#ifdef BROKEN /* * kernel/lvm-snap.c * @@ -698,3 +699,4 @@ } MODULE_LICENSE("GPL"); +#endif /* broken */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/md/lvm.c linux-2.5/drivers/md/lvm.c --- linux-2.5.23/drivers/md/lvm.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/md/lvm.c Wed Jun 19 06:20:44 2002 @@ -1,4 +1,10 @@ +#define IGNORE_AL_VIRO + + +#ifndef IGNORE_AL_VIRO #error Broken until maintainers will sanitize kdev_t handling +#endif + /* * kernel/lvm.c * @@ -208,8 +214,9 @@ #include #include -#include + #include +#include #include #include #include @@ -244,8 +251,8 @@ static int lvm_blk_open(struct inode *, struct file *); static int lvm_blk_close(struct inode *, struct file *); -static int lvm_get_snapshot_use_rate(lv_t *lv_ptr, void *arg); -static int lvm_user_bmap(struct inode *, struct lv_bmap *); +static int lvm_get_snapshot_use_rate(kern_lv_t *lv_ptr, void *arg); +/*static int lvm_user_bmap(struct inode *, struct lv_bmap *);*/ static int lvm_chr_open(struct inode *, struct file *); static int lvm_chr_close(struct inode *, struct file *); @@ -266,39 +273,49 @@ #endif static int lvm_map(struct bio *); static int lvm_do_lock_lvm(void); -static int lvm_do_le_remap(vg_t *, void *); +//static int lvm_do_le_remap(vg_t *, void *); -static int lvm_do_pv_create(pv_t *, vg_t *, ulong); -static int lvm_do_pv_remove(vg_t *, ulong); -static int lvm_do_lv_create(int, char *, userlv_t *); -static int lvm_do_lv_extend_reduce(int, char *, userlv_t *); +static int lvm_do_pv_create(user_pv_t *, kern_vg_t *, ulong); +static int lvm_do_pv_remove(kern_vg_t *, ulong); +static int lvm_do_lv_create(int, char *, user_lv_t *); +//static int lvm_do_lv_extend_reduce(int, char *, user_lv_t *); static int lvm_do_lv_remove(int, char *, int); -static int lvm_do_lv_rename(vg_t *, lv_req_t *, userlv_t *); -static int lvm_do_lv_status_byname(vg_t *r, void *); -static int lvm_do_lv_status_byindex(vg_t *, void *); -static int lvm_do_lv_status_bydev(vg_t *, void *); +static int lvm_do_lv_rename(kern_vg_t *, lv_req_t *, user_lv_t *); +static int lvm_do_lv_status_byname(kern_vg_t *r, void *); +static int lvm_do_lv_status_byindex(kern_vg_t *, void *); +static int lvm_do_lv_status_bydev(kern_vg_t *, void *); -static int lvm_do_pe_lock_unlock(vg_t *r, void *); +static int lvm_do_pe_lock_unlock(kern_vg_t *r, void *); -static int lvm_do_pv_change(vg_t*, void*); -static int lvm_do_pv_status(vg_t *, void *); +static int lvm_do_pv_change(kern_vg_t*, void*); +static int lvm_do_pv_status(kern_vg_t *, void *); static int lvm_do_pv_flush(void *); static int lvm_do_vg_create(void *, int minor); -static int lvm_do_vg_extend(vg_t *, void *); -static int lvm_do_vg_reduce(vg_t *, void *); -static int lvm_do_vg_rename(vg_t *, void *); +static int lvm_do_vg_extend(kern_vg_t *, void *); +static int lvm_do_vg_reduce(kern_vg_t *, void *); +static int lvm_do_vg_rename(kern_vg_t *, void *); static int lvm_do_vg_remove(int); static void lvm_geninit(struct gendisk *); -static void __update_hardsectsize(lv_t *lv); +static void __update_hardsectsize(kern_lv_t *lv); static void _queue_io(struct bio *bh, int rw); static struct bio *_dequeue_io(void); static void _flush_io(struct bio *bh); -static int _open_pv(pv_t *pv); -static void _close_pv(pv_t *pv); +static int _open_pv(kern_pv_t *pv); +static void _close_pv(kern_pv_t *pv); + +/* function for converting between kernelspace and + userspace versions of structures */ +static void kernpv_to_userpv(const kern_pv_t *const kpv,user_pv_t *const upv); +static void userpv_to_kernpv(const user_pv_t *const upv,kern_pv_t *const kpv); +static void kernvg_to_uservg(const kern_vg_t *const kvg,user_vg_t *const uvg); +static void uservg_to_kernvg(const user_vg_t *const uvg,kern_vg_t *const kvg); +static void kernlv_to_userlv(const kern_lv_t *const klv,user_lv_t *const ulv); +static void userlv_to_kernlv(const user_lv_t *const ulv,kern_lv_t *const klv); + static unsigned long _sectors_to_k(unsigned long sect); @@ -316,7 +333,7 @@ /* volume group descriptor area pointers */ -vg_t *vg[ABS_MAX_VG]; +kern_vg_t *vg[ABS_MAX_VG]; /* map from block minor number to VG and LV numbers */ typedef struct { @@ -327,10 +344,10 @@ /* Request structures (lvm_chr_ioctl()) */ -static pv_change_req_t pv_change_req; +/* static pv_change_req_t pv_change_req; */ static pv_status_req_t pv_status_req; volatile static pe_lock_req_t pe_lock_req; -static le_remap_req_t le_remap_req; +/* static le_remap_req_t le_remap_req; */ static lv_req_t lv_req; #ifdef LVM_TOTAL_RESET @@ -338,7 +355,6 @@ #endif static char pv_name[NAME_LEN]; -/* static char rootvg[NAME_LEN] = { 0, }; */ static int lock = 0; static int _lock_open_count = 0; static uint vg_count = 0; @@ -513,25 +529,25 @@ static int lvm_chr_open(struct inode *inode, struct file *file) { unsigned int minor = minor(inode->i_rdev); - + P_DEV("chr_open MINOR: %d VG#: %d mode: %s%s lock: %d\n", minor, VG_CHR(minor), MODE_TO_STR(file->f_mode), lock); - + /* super user validation */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - + /* Group special file open */ if (VG_CHR(minor) > MAX_VG) return -ENXIO; - - spin_lock(&lvm_lock); - if(lock == current->pid) - _lock_open_count++; - spin_unlock(&lvm_lock); - + + spin_lock(&lvm_lock); + if(lock == current->pid) + _lock_open_count++; + spin_unlock(&lvm_lock); + lvm_chr_open_count++; - + MOD_INC_USE_COUNT; - + return 0; } /* lvm_chr_open() */ @@ -544,13 +560,13 @@ * */ static int lvm_chr_ioctl(struct inode *inode, struct file *file, - uint command, ulong a) + uint command, ulong a) { int minor = minor(inode->i_rdev); uint extendable, l, v; void *arg = (void *) a; - userlv_t ulv; - vg_t* vg_ptr = vg[VG_CHR(minor)]; + user_lv_t ulv; + kern_vg_t* vg_ptr = vg[VG_CHR(minor)]; /* otherwise cc will complain about unused variables */ (void) lvm_lock; @@ -597,7 +613,8 @@ case LE_REMAP: /* remap a logical extent (after moving the physical extent) */ - return lvm_do_le_remap(vg_ptr,arg); + return -ENOSYS; +// return lvm_do_le_remap(vg_ptr,arg); case PE_LOCK_UNLOCK: /* lock/unlock i/o to a physical extent to move it to another @@ -608,10 +625,10 @@ /* create a VGDA */ return lvm_do_vg_create(arg, minor); - case VG_CREATE: - /* create a VGDA, assume VG number is filled in */ + case VG_CREATE: + /* create a VGDA, assume VG number is filled in */ return lvm_do_vg_create(arg, -1); - + case VG_EXTEND: /* extend a volume group */ return lvm_do_vg_extend(vg_ptr, arg); @@ -645,14 +662,23 @@ return 0; - case VG_STATUS: + case VG_STATUS:{ + user_vg_t *tmpuvg; /* get volume group data (only the vg_t struct) */ if (vg_ptr == NULL) return -ENXIO; - if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0) + + tmpuvg=kmalloc(sizeof(user_vg_t),GFP_KERNEL); + if(tmpuvg==NULL){ + return -ENOMEM; + } + kernvg_to_uservg(vg_ptr,tmpuvg); + if(copy_to_user(arg,tmpuvg,sizeof(user_vg_t))!=0){ return -EFAULT; + } + kfree(tmpuvg); return 0; - + } case VG_STATUS_GET_COUNT: /* get volume group count */ if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0) @@ -685,7 +711,7 @@ return -EFAULT; if (command != LV_REMOVE) { - if (copy_from_user(&ulv, lv_req.lv, sizeof(userlv_t)) != 0) + if (copy_from_user(&ulv, lv_req.lv, sizeof(user_lv_t)) != 0) return -EFAULT; } switch (command) { @@ -694,7 +720,7 @@ case LV_EXTEND: case LV_REDUCE: - return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &ulv); + return -ENOSYS;//lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &ulv); case LV_REMOVE: return lvm_do_lv_remove(minor, lv_req.lv_name, -1); @@ -793,8 +819,8 @@ static int lvm_blk_open(struct inode *inode, struct file *file) { int minor = minor(inode->i_rdev); - lv_t *lv_ptr; - vg_t *vg_ptr = vg[VG_BLK(minor)]; + kern_lv_t *lv_ptr; + kern_vg_t *vg_ptr = vg[VG_BLK(minor)]; P_DEV("blk_open MINOR: %d VG#: %d LV#: %d mode: %s%s\n", minor, VG_BLK(minor), LV_BLK(minor), MODE_TO_STR(file->f_mode)); @@ -811,23 +837,23 @@ LV_BLK(minor) < vg_ptr->lv_max) { /* Check parallel LV spindown (LV remove) */ - if (lv_ptr->u.lv_status & LV_SPINDOWN) return -EPERM; + if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; /* Check inactive LV and open for read/write */ /* We need to be able to "read" an inactive LV to re-activate it again */ if ((file->f_mode & FMODE_WRITE) && - (!(lv_ptr->u.lv_status & LV_ACTIVE))) + (!(lv_ptr->lv_status & LV_ACTIVE))) return -EPERM; - if (!(lv_ptr->u.lv_access & LV_WRITE) && + if (!(lv_ptr->lv_access & LV_WRITE) && (file->f_mode & FMODE_WRITE)) return -EACCES; /* be sure to increment VG counter */ - if (lv_ptr->u.lv_open == 0) vg_ptr->lv_open++; - lv_ptr->u.lv_open++; + if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; + lv_ptr->lv_open++; MOD_INC_USE_COUNT; @@ -846,8 +872,8 @@ uint command, ulong a) { int minor = minor(inode->i_rdev); - vg_t *vg_ptr = vg[VG_BLK(minor)]; - lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; + kern_vg_t *vg_ptr = vg[VG_BLK(minor)]; + kern_lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; void *arg = (void *) a; struct hd_geometry *hd = (struct hd_geometry *) a; @@ -862,13 +888,13 @@ case BLKGETSIZE: /* return device size */ - P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->u.lv_size); - if (put_user(lv_ptr->u.lv_size, (unsigned long *)arg)) + P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->lv_size); + if (put_user(lv_ptr->lv_size, (unsigned long *)arg)) return -EFAULT; break; case BLKGETSIZE64: - if (put_user((u64)lv_ptr->u.lv_size << 9, (u64 *)arg)) + if (put_user((u64)lv_ptr->lv_size << 9, (u64 *)arg)) return -EFAULT; break; @@ -880,7 +906,7 @@ P_IOCTL("BLKFLSBUF\n"); fsync_bdev(inode->i_bdev); - invalidate_buffers(inode->i_rdev); + invalidate_bdev(inode->i_bdev,0); break; case HDIO_GETGEO: @@ -892,7 +918,7 @@ unsigned char heads = 64; unsigned char sectors = 32; long start = 0; - short cylinders = lv_ptr->u.lv_size / heads / sectors; + short cylinders = lv_ptr->lv_size / heads / sectors; if (copy_to_user((char *) &hd->heads, &heads, sizeof(heads)) != 0 || @@ -913,34 +939,36 @@ case LV_SET_ACCESS: /* set access flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lv_ptr->u.lv_access = (ulong) arg; - if ( lv_ptr->u.lv_access & LV_WRITE) - set_device_ro(lv_ptr->u.lv_dev, 0); + lv_ptr->lv_access = (ulong) arg; + if ( lv_ptr->lv_access & LV_WRITE) + set_device_ro(lv_ptr->lv_kdev, 0); else - set_device_ro(lv_ptr->u.lv_dev, 1); + set_device_ro(lv_ptr->lv_kdev, 1); break; case LV_SET_STATUS: /* set status flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!((ulong) arg & LV_ACTIVE) && lv_ptr->u.lv_open > 1) + if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1) return -EPERM; - lv_ptr->u.lv_status = (ulong) arg; + lv_ptr->lv_status = (ulong) arg; break; case LV_BMAP: + /* BROKEN */ + return -ENOSYS; /*lvm_user_bmap(inode, (struct lv_bmap *) arg);*/ + + /* turn logical block into (dev_t, block). non privileged. */ /* don't bmap a snapshot, since the mapping can change */ - if(lv_ptr->u.lv_access & LV_SNAPSHOT) + if(lv_ptr->lv_access & LV_SNAPSHOT) return -EPERM; - return lvm_user_bmap(inode, (struct lv_bmap *) arg); - case LV_SET_ALLOCATION: /* set allocation flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lv_ptr->u.lv_allocation = (ulong) arg; + lv_ptr->lv_allocation = (ulong) arg; break; case LV_SNAPSHOT_USE_RATE: @@ -963,26 +991,26 @@ static int lvm_blk_close(struct inode *inode, struct file *file) { int minor = minor(inode->i_rdev); - vg_t *vg_ptr = vg[VG_BLK(minor)]; - lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; + kern_vg_t *vg_ptr = vg[VG_BLK(minor)]; + kern_lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; P_DEV("blk_close MINOR: %d VG#: %d LV#: %d\n", minor, VG_BLK(minor), LV_BLK(minor)); - if (lv_ptr->u.lv_open == 1) vg_ptr->lv_open--; - lv_ptr->u.lv_open--; + if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; + lv_ptr->lv_open--; MOD_DEC_USE_COUNT; return 0; } /* lvm_blk_close() */ -static int lvm_get_snapshot_use_rate(lv_t *lv, void *arg) +static int lvm_get_snapshot_use_rate(kern_lv_t *lv, void *arg) { lv_snapshot_use_rate_req_t lv_rate_req; - if (!(lv->u.lv_access & LV_SNAPSHOT)) - return -EPERM; + if (!(lv->lv_access & LV_SNAPSHOT)) + return -EPERM; /* PERM?? INVAL*/ if (copy_from_user(&lv_rate_req, arg, sizeof(lv_rate_req))) return -EFAULT; @@ -993,7 +1021,7 @@ switch (lv_rate_req.block) { case 0: lv->lv_snapshot_use_rate = lv_rate_req.rate; - if (lv->u.lv_remap_ptr * 100 / lv->u.lv_remap_end < + if (lv->lv_remap_ptr * 100 / lv->lv_remap_end < lv->lv_snapshot_use_rate) interruptible_sleep_on(&lv->lv_snapshot_wait); break; @@ -1004,12 +1032,12 @@ default: return -EINVAL; } - lv_rate_req.rate = lv->u.lv_remap_ptr * 100 / lv->u.lv_remap_end; + lv_rate_req.rate = lv->lv_remap_ptr * 100 / lv->lv_remap_end; return copy_to_user(arg, &lv_rate_req, sizeof(lv_rate_req)) ? -EFAULT : 0; } - +/* static int lvm_user_bmap(struct inode *inode, struct lv_bmap *user_result) { struct bio bio; @@ -1020,8 +1048,8 @@ return -EFAULT; memset(&bio,0,sizeof(bio)); - bio.bi_dev = inode->i_rdev; - bio.bi_size = block_size(bio.bi_dev); /* NEEDED by bio_sectors */ + bio.bi_bdev = inode->i_bdev; + bio.bi_size = block_size(bio.bi_bdev); / NEEDED by bio_sectors / bio.bi_sector = block * bio_sectors(&bio); bio.bi_rw = READ; if ((err=lvm_map(&bio)) < 0) { @@ -1029,12 +1057,12 @@ return -EINVAL; } - return put_user(kdev_t_to_nr(bio.bi_dev), &user_result->lv_dev) || + return put_user(kdev_t_to_nr(bio.bi_bdev), &user_result->lv_dev) || put_user(bio.bi_sector/bio_sectors(&bio), &user_result->lv_block) ? -EFAULT : 0; } - - +*/ +#ifdef BROKEN /* * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c * (see init_module/lvm_init) @@ -1067,20 +1095,20 @@ /* we haven't yet copied this block to the snapshot */ __remap_snapshot(rdev, rsector, pe_start, lv, vg); } - +#endif /* * extents destined for a pe that is on the move should be deferred */ -static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size) { +static inline int _should_defer(struct block_device *pv, ulong sector, uint32_t pe_size) { return ((pe_lock_req.lock == LOCK_PE) && - kdev_same(pv, pe_lock_req.data.pv_dev) && + kdev_same(to_kdev_t(pv->bd_dev), pe_lock_req.data.pv_dev) && (sector >= pe_lock_req.data.pv_offset) && (sector < (pe_lock_req.data.pv_offset + pe_size))); } static inline int _defer_extent(struct bio *bh, int rw, - kdev_t pv, ulong sector, uint32_t pe_size) + struct block_device *pv, ulong sector, uint32_t pe_size) { if (pe_lock_req.lock == LOCK_PE) { down_read(&_pe_lock); @@ -1097,32 +1125,31 @@ return 0; } -static int lvm_map(struct bio *bi) -{ - int minor = minor(bi->bi_dev); +static int lvm_map(struct bio *bi){ + int minor = minor(to_kdev_t(bi->bi_bdev->bd_dev)); ulong index; ulong pe_start; ulong size = bio_sectors(bi); ulong rsector_org = bi->bi_sector; ulong rsector_map; - kdev_t rdev_map; - vg_t *vg_this = vg[VG_BLK(minor)]; - lv_t *lv = vg_this->lv[LV_BLK(minor)]; + struct block_device *rbd_map; + kern_vg_t *vg_this = vg[VG_BLK(minor)]; + kern_lv_t *lv = vg_this->lv[LV_BLK(minor)]; int rw = bio_rw(bi); down_read(&lv->lv_lock); - if (!(lv->u.lv_status & LV_ACTIVE)) { + if (!(lv->lv_status & LV_ACTIVE)) { printk(KERN_ALERT "%s - lvm_map: ll_rw_blk for inactive LV %s\n", - lvm_name, lv->u.lv_name); + lvm_name, lv->lv_name); goto bad; } if ((rw == WRITE || rw == WRITEA) && - !(lv->u.lv_access & LV_WRITE)) { + !(lv->lv_access & LV_WRITE)) { printk(KERN_CRIT "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", - lvm_name, lv->u.lv_name); + lvm_name, lv->lv_name); goto bad; } @@ -1131,7 +1158,7 @@ kdevname(bi->bi_dev), rsector_org, size); - if (rsector_org + size > lv->u.lv_size) { + if (rsector_org + size > lv->lv_size) { printk(KERN_ALERT "%s - lvm_map access beyond end of device; *rsector: " "%lu or size: %lu wrong for minor: %2d\n", @@ -1140,39 +1167,39 @@ } - if (lv->u.lv_stripes < 2) { /* linear mapping */ + if (lv->lv_stripes < 2) { /* linear mapping */ /* get the index */ index = rsector_org / vg_this->pe_size; - pe_start = lv->u.lv_current_pe[index].pe; - rsector_map = lv->u.lv_current_pe[index].pe + + pe_start = lv->lv_current_pe[index].pe; + rsector_map = lv->lv_current_pe[index].pe + (rsector_org % vg_this->pe_size); - rdev_map = lv->u.lv_current_pe[index].dev; + rbd_map = lv->lv_current_pe[index].bdev; P_MAP("u.lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n", - index, lv->u.lv_current_pe[index].pe, + index, lv->lv_current_pe[index].pe, kdevname(rdev_map), rsector_map); } else { /* striped mapping */ ulong stripe_index; ulong stripe_length; - stripe_length = vg_this->pe_size * lv->u.lv_stripes; + stripe_length = vg_this->pe_size * lv->lv_stripes; stripe_index = (rsector_org % stripe_length) / - lv->u.lv_stripesize; + lv->lv_stripesize; index = rsector_org / stripe_length + - (stripe_index % lv->u.lv_stripes) * - (lv->u.lv_allocated_le / lv->u.lv_stripes); - pe_start = lv->u.lv_current_pe[index].pe; - rsector_map = lv->u.lv_current_pe[index].pe + + (stripe_index % lv->lv_stripes) * + (lv->lv_allocated_le / lv->lv_stripes); + pe_start = lv->lv_current_pe[index].pe; + rsector_map = lv->lv_current_pe[index].pe + (rsector_org % stripe_length) - - (stripe_index % lv->u.lv_stripes) * lv->u.lv_stripesize - - stripe_index / lv->u.lv_stripes * - (lv->u.lv_stripes - 1) * lv->u.lv_stripesize; - rdev_map = lv->u.lv_current_pe[index].dev; + (stripe_index % lv->lv_stripes) * lv->lv_stripesize - + stripe_index / lv->lv_stripes * + (lv->lv_stripes - 1) * lv->lv_stripesize; + rbd_map = lv->lv_current_pe[index].bdev; P_MAP("u.lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n" "stripe_length: %ld stripe_index: %ld\n", - index, lv->u.lv_current_pe[index].pe, kdevname(rdev_map), + index, lv->lv_current_pe[index].pe, kdevname(rdev_map), rsector_map, stripe_length, stripe_index); } @@ -1182,24 +1209,24 @@ * we need to queue this request, because this is in the fast path. */ if (rw == WRITE || rw == WRITEA) { - if(_defer_extent(bi, rw, rdev_map, + if(_defer_extent(bi, rw, rbd_map, rsector_map, vg_this->pe_size)) { up_read(&lv->lv_lock); return 0; } - lv->u.lv_current_pe[index].writes++; /* statistic */ + lv->lv_current_pe[index].writes++; /* statistic */ } else - lv->u.lv_current_pe[index].reads++; /* statistic */ + lv->lv_current_pe[index].reads++; /* statistic */ /* snapshot volume exception handling on physical device address base */ - if (!(lv->u.lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) + if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) goto out; - +#ifdef BROKEN if (lv->u.lv_access & LV_SNAPSHOT) { /* remap snapshot */ if (lv->u.lv_block_exception) - lvm_snapshot_remap_block(&rdev_map, &rsector_map, + lvm_snapshot_remap_block(&rbd_map, &rsector_map, pe_start, lv); else goto bad; @@ -1217,13 +1244,13 @@ /* Serializes the COW with the accesses to the snapshot device */ - _remap_snapshot(rdev_map, rsector_map, + _remap_snapshot(rbd_map, rsector_map, pe_start, snap, vg_this); } } - +#endif out: - bi->bi_dev = rdev_map; + bi->bi_bdev = rbd_map; bi->bi_sector = rsector_map; up_read(&lv->lv_lock); return 1; @@ -1302,7 +1329,7 @@ /* * character device support function lock/unlock physical extend */ -static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg) +static int lvm_do_pe_lock_unlock(kern_vg_t *vg_ptr, void *arg) { pe_lock_req_t new_lock; struct bio *bh; @@ -1317,7 +1344,7 @@ for (p = 0; p < vg_ptr->pv_max; p++) { if (vg_ptr->pv[p] != NULL && kdev_same(new_lock.data.pv_dev, - vg_ptr->pv[p]->pv_dev)) + vg_ptr->pv[p]->pv_kdev)) break; } if (p == vg_ptr->pv_max) return -ENXIO; @@ -1367,14 +1394,14 @@ return 0; } - +#ifdef BROKEN /* * character device support function logical extend remap */ -static int lvm_do_le_remap(vg_t *vg_ptr, void *arg) +static int lvm_do_le_remap(kern_vg_t *vg_ptr, void *arg) { uint l, le; - lv_t *lv_ptr; + kern_lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&le_remap_req, arg, @@ -1387,7 +1414,7 @@ strcmp(lv_ptr->u.lv_name, le_remap_req.lv_name) == 0) { for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { - if (kdev_same(lv_ptr->u.lv_current_pe[le].dev, + if (kdev_same(lv_ptr->u.lv_current_pe[le].bdev, le_remap_req.old_dev) && lv_ptr->u.lv_current_pe[le].pe == le_remap_req.old_pe) { @@ -1405,6 +1432,172 @@ } return -ENXIO; } /* lvm_do_le_remap() */ +#endif + +static void userlv_to_kernlv(const user_lv_t *const ulv,kern_lv_t *const klv){ + memcpy(klv->vg_name,ulv->vg_name,NAME_LEN); + memcpy(klv->lv_name,ulv->lv_name,NAME_LEN); + klv->lv_access=ulv->lv_access; + klv->lv_status=ulv->lv_status; + klv->lv_open=ulv->lv_open; + klv->lv_kdev=to_kdev_t(ulv->lv_dev); + klv->lv_number=ulv->lv_number; + klv->lv_size=ulv->lv_size; + klv->lv_current_pe=NULL; + klv->lv_allocated_le=ulv->lv_allocated_le; + klv->lv_current_le=ulv->lv_current_le; + klv->lv_stripes=ulv->lv_stripes; + klv->lv_stripesize=ulv->lv_stripesize; + klv->lv_iobuf=NULL; + klv->lv_COW_table_iobuf=NULL; + init_rwsem(&klv->lv_lock); + klv->lv_snapshot_hash_table=NULL; + klv->lv_snapshot_hash_table_size=0; + klv->lv_snapshot_hash_mask=0; +/* + klv->lv_snapshot_wait=NULL; */ + klv->lv_snapshot_use_rate=0; + klv->vg=NULL; + klv->lv_allocated_snapshot_le=0; + klv->lv_snapshot_org=NULL; + klv->lv_snapshot_prev=NULL; + klv->lv_snapshot_next=NULL; + klv->lv_block_exception=NULL; + klv->lv_remap_ptr=0; + klv->lv_remap_end=0; + klv->lv_chunk_size=0; +} + +static void kernlv_to_userlv(const kern_lv_t *const klv,user_lv_t *const ulv){ + memcpy(ulv->vg_name,klv->vg_name,NAME_LEN); + memcpy(ulv->lv_name,klv->lv_name,NAME_LEN); + ulv->lv_access=klv->lv_access; + ulv->lv_status=klv->lv_status; + ulv->lv_open=klv->lv_open; + ulv->lv_dev=kdev_t_to_nr(klv->lv_kdev); + ulv->lv_number=klv->lv_number; + ulv->lv_size=klv->lv_size; + ulv->lv_allocated_le=klv->lv_allocated_le; + ulv->lv_current_le=klv->lv_current_le; + ulv->lv_stripes=klv->lv_stripes; + ulv->lv_stripesize=klv->lv_stripesize; +} + +static void uservg_to_kernvg(const user_vg_t *const uvg,kern_vg_t *const kvg){ + int i; + memcpy(kvg->vg_name,uvg->vg_name,NAME_LEN); + kvg->vg_number=uvg->vg_number; + kvg->vg_access=uvg->vg_access; + kvg->vg_status=uvg->vg_status; + kvg->lv_max=uvg->lv_max; + kvg->lv_cur=uvg->lv_cur; + kvg->lv_open=uvg->lv_open; + kvg->pv_max=uvg->pv_max; + kvg->pv_cur=uvg->pv_cur; + kvg->pv_act=uvg->pv_act; + kvg->dummy=0; + kvg->vgda=uvg->vgda; + kvg->pe_size=uvg->pe_size; + kvg->pe_total=uvg->pe_total; + kvg->pe_allocated=uvg->pe_allocated; + kvg->pvg_total=uvg->pvg_total; + kvg->proc=NULL; + for(i=0;ipv[i]=NULL; + } + for(i=0;ilv[i]=NULL; + } + memcpy(kvg->vg_uuid,uvg->vg_uuid,UUID_LEN+1); + + kvg->vg_dir_pde=NULL; + kvg->lv_subdir_pde=NULL; + kvg->pv_subdir_pde=NULL; + +} + + +static void kernvg_to_uservg(const kern_vg_t *const kvg,user_vg_t *const uvg){ + int i; + memcpy(uvg->vg_name,kvg->vg_name,NAME_LEN); + uvg->vg_number=kvg->vg_number; + uvg->vg_access=kvg->vg_access; + uvg->vg_status=kvg->vg_status; + uvg->lv_max=kvg->lv_max; + uvg->lv_cur=kvg->lv_cur; + uvg->lv_open=kvg->lv_open; + uvg->pv_max=kvg->pv_max; + uvg->pv_cur=kvg->pv_cur; + uvg->pv_act=kvg->pv_act; + uvg->dummy=0; + uvg->vgda=kvg->vgda; + uvg->pe_size=kvg->pe_size; + uvg->pe_total=kvg->pe_total; + uvg->pe_allocated=kvg->pe_allocated; + uvg->pvg_total=kvg->pvg_total; + for(i=0;ilv[i]=(user_lv_t *)0xDEADBEEF; + } + for(i=0;ipv[i]=(user_pv_t *)0xDEADC0DE; + } + + memcpy(uvg->vg_uuid,kvg->vg_uuid,UUID_LEN+1); +} + +static void userpv_to_kernpv(const user_pv_t *const upv,kern_pv_t *const kpv){ + kpv->id[0]=upv->id[0]; + kpv->id[1]=upv->id[1]; + kpv->version=upv->version; + memcpy(&kpv->pv_on_disk,&upv->pv_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&kpv->vg_on_disk,&upv->vg_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&kpv->pv_uuidlist_on_disk,&upv->pv_uuidlist_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&kpv->lv_on_disk,&upv->lv_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&kpv->pe_on_disk,&upv->pe_on_disk,sizeof(lvm_disk_data_t)); + + memcpy(&kpv->pv_name,&upv->pv_name,NAME_LEN); + memcpy(&kpv->vg_name,&upv->vg_name,NAME_LEN); + memcpy(&kpv->system_id,&upv->system_id,NAME_LEN); + kpv->pv_kdev=to_kdev_t(upv->pv_dev); + kpv->pv_number=upv->pv_number; + kpv->pv_status =upv->pv_status; + kpv->pv_allocatable =upv->pv_allocatable; + kpv->pv_size =upv->pv_size; + kpv->lv_cur =upv->lv_cur; + kpv->pe_size =upv->pe_size; + kpv->pe_total =upv->pe_total; + kpv->pe_allocated =upv->pe_allocated; + kpv->pe_stale =upv->pe_stale; + kpv->pe=NULL; + kpv->bd=NULL; + memcpy(kpv->pv_uuid,upv->pv_uuid,UUID_LEN+1); +} + +static void kernpv_to_userpv(const kern_pv_t *const kpv, user_pv_t *const upv){ + upv->id[0]=kpv->id[0]; + upv->id[1]=kpv->id[1]; + upv->version=kpv->version; + memcpy(&upv->pv_on_disk,&kpv->pv_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&upv->vg_on_disk,&kpv->vg_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&upv->pv_uuidlist_on_disk,&kpv->pv_uuidlist_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&upv->lv_on_disk,&kpv->lv_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&upv->pe_on_disk,&kpv->pe_on_disk,sizeof(lvm_disk_data_t)); + + memcpy(&upv->pv_name,&kpv->pv_name,NAME_LEN); + memcpy(&upv->vg_name,&kpv->vg_name,NAME_LEN); + memcpy(&upv->system_id,&kpv->system_id,NAME_LEN); + upv->pv_dev=kdev_t_to_nr(kpv->pv_kdev); + upv->pv_number=kpv->pv_number; + upv->pv_status =kpv->pv_status; + upv->pv_allocatable =kpv->pv_allocatable; + upv->pv_size =kpv->pv_size; + upv->lv_cur =kpv->lv_cur; + upv->pe_size =kpv->pe_size; + upv->pe_total =kpv->pe_total; + upv->pe_allocated =kpv->pe_allocated; + upv->pe_stale =kpv->pe_stale; + memcpy(upv->pv_uuid,kpv->pv_uuid,UUID_LEN+1); +} /* @@ -1414,26 +1607,31 @@ { int ret = 0; ulong l, ls = 0, p, size; - vg_t *vg_ptr; - lv_t **snap_lv_ptr; - lv_t *tmplv; + kern_vg_t *vg_ptr; + kern_lv_t **snap_lv_ptr; + user_vg_t *tmpuvg; + user_lv_t *tmpulv; - if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { + tmpuvg=kmalloc(sizeof(user_vg_t),GFP_KERNEL); + + /* this will be our new vg */ + if ((vg_ptr = kmalloc(sizeof(kern_vg_t),GFP_KERNEL)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: kmalloc error VG at line %d\n", lvm_name, __LINE__); return -ENOMEM; } - /* get the volume group structure */ - if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) { + /* copy userdata into kernspace */ + if (copy_from_user(tmpuvg, arg, sizeof(user_vg_t)) != 0) { P_IOCTL("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n", arg, sizeof(vg_t)); kfree(vg_ptr); return -EFAULT; } - + /* set up as much as possible from user_vg_t */ + uservg_to_kernvg(tmpuvg,vg_ptr); /* VG_CREATE now uses minor number in VG structure */ if (minor == -1) minor = vg_ptr->vg_number; @@ -1473,10 +1671,16 @@ /* get the physical volume structures */ vg_ptr->pv_act = vg_ptr->pv_cur = 0; for (p = 0; p < vg_ptr->pv_max; p++) { - pv_t *pvp; + user_pv_t tmpupv; + /* user space address */ - if ((pvp = vg_ptr->pv[p]) != NULL) { - ret = lvm_do_pv_create(pvp, vg_ptr, p); + if(tmpuvg->pv[p]!=NULL){ + if (copy_from_user(&tmpupv, tmpuvg->pv[p], sizeof(user_pv_t)) != 0) { + P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n", + tmpuvg->pv[p], sizeof(user_pv_t)); + return -EFAULT; + } + ret = lvm_do_pv_create(&tmpupv, vg_ptr, p); if ( ret != 0) { lvm_do_vg_remove(minor); return ret; @@ -1484,7 +1688,7 @@ } } - size = vg_ptr->lv_max * sizeof(lv_t *); + size = vg_ptr->lv_max * sizeof(kern_lv_t *); if ((snap_lv_ptr = vmalloc ( size)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: vmalloc error snapshot LVs at line %d\n", @@ -1494,7 +1698,7 @@ } memset(snap_lv_ptr, 0, size); - if ((tmplv = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) { + if ((tmpulv = kmalloc(sizeof(user_lv_t),GFP_KERNEL)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: kmalloc error LV at line %d\n", lvm_name, __LINE__); @@ -1505,30 +1709,32 @@ /* get the logical volume structures */ vg_ptr->lv_cur = 0; for (l = 0; l < vg_ptr->lv_max; l++) { - lv_t *lvp; - - /* user space address */ - if ((lvp = vg_ptr->lv[l]) != NULL) { - if (copy_from_user(tmplv, lvp, sizeof(userlv_t)) != 0) { + void *lvp; /* user space address */ + + if ((lvp = tmpuvg->lv[l]) != NULL) { + + if (copy_from_user(tmpulv, lvp, sizeof(user_lv_t)) != 0) { P_IOCTL("ERROR: copying LV ptr %p (%d bytes)\n", lvp, sizeof(lv_t)); lvm_do_vg_remove(minor); vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); return -EFAULT; } - if ( tmplv->u.lv_access & LV_SNAPSHOT) { + + if ( tmpulv->lv_access & LV_SNAPSHOT) { snap_lv_ptr[ls] = lvp; vg_ptr->lv[l] = NULL; ls++; continue; } vg_ptr->lv[l] = NULL; + /* only create original logical volumes for now */ - if (lvm_do_lv_create(minor, tmplv->u.lv_name, &tmplv->u) != 0) { + if (lvm_do_lv_create(minor, tmpulv->lv_name, tmpulv) != 0) { lvm_do_vg_remove(minor); vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); return -EFAULT; } } @@ -1536,24 +1742,25 @@ /* Second path to correct snapshot logical volumes which are not in place during first path above */ +#ifdef BROKEN for (l = 0; l < ls; l++) { lv_t *lvp = snap_lv_ptr[l]; - if (copy_from_user(tmplv, lvp, sizeof(userlv_t)) != 0) { + if (copy_from_user(tmpulv, lvp, sizeof(user_lv_t)) != 0) { lvm_do_vg_remove(minor); vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); return -EFAULT; } - if (lvm_do_lv_create(minor, tmplv->u.lv_name, &tmplv->u) != 0) { + if (lvm_do_lv_create(minor, tmpulv->lv_name, tmpulv) != 0) { lvm_do_vg_remove(minor); vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); return -EFAULT; } } - +#endif vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); vg_count++; @@ -1569,17 +1776,26 @@ /* * character device support function VGDA extend */ -static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg) +static int lvm_do_vg_extend(kern_vg_t *vg_ptr, void *arg) { int ret = 0; uint p; - pv_t *pv_ptr; + kern_pv_t *pv_ptr; if (vg_ptr == NULL) return -ENXIO; if (vg_ptr->pv_cur < vg_ptr->pv_max) { for (p = 0; p < vg_ptr->pv_max; p++) { if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) { - ret = lvm_do_pv_create(arg, vg_ptr, p); + user_pv_t tmpupv; + + /* user space address */ + if (copy_from_user(&tmpupv, arg, sizeof(user_pv_t)) != 0) { + P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n", + arg, sizeof(user_pv_t)); + return -EFAULT; + } + + ret = lvm_do_pv_create(&tmpupv, vg_ptr, p); if ( ret != 0) return ret; pv_ptr = vg_ptr->pv[p]; vg_ptr->pe_total += pv_ptr->pe_total; @@ -1594,9 +1810,9 @@ /* * character device support function VGDA reduce */ -static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) { +static int lvm_do_vg_reduce(kern_vg_t *vg_ptr, void *arg) { uint p; - pv_t *pv_ptr; + kern_pv_t *pv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0) @@ -1623,9 +1839,10 @@ /* * character device support function VG rename */ -static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg) +static int lvm_do_vg_rename(kern_vg_t *vg_ptr, void *arg) { - int l = 0, p = 0, len = 0; + return -ENOSYS; +/* int l = 0, p = 0, len = 0; char vg_name[NAME_LEN] = { 0,}; char lv_name[NAME_LEN] = { 0,}; char *ptr = NULL; @@ -1643,15 +1860,15 @@ for ( l = 0; l < vg_ptr->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) == NULL) continue; - strncpy(lv_ptr->u.vg_name, vg_name, sizeof ( vg_name)); - ptr = strrchr(lv_ptr->u.lv_name, '/'); - if (ptr == NULL) ptr = lv_ptr->u.lv_name; + strncpy(lv_ptr->vg_name, vg_name, sizeof ( vg_name)); + ptr = strrchr(lv_ptr->lv_name, '/'); + if (ptr == NULL) ptr = lv_ptr->lv_name; strncpy(lv_name, ptr, sizeof ( lv_name)); len = sizeof(LVM_DIR_PREFIX); - strcpy(lv_ptr->u.lv_name, LVM_DIR_PREFIX); - strncat(lv_ptr->u.lv_name, vg_name, NAME_LEN - len); + strcpy(lv_ptr->lv_name, LVM_DIR_PREFIX); + strncat(lv_ptr->lv_name, vg_name, NAME_LEN - len); len += strlen ( vg_name); - strncat(lv_ptr->u.lv_name, lv_name, NAME_LEN - len); + strncat(lv_ptr->lv_name, lv_name, NAME_LEN - len); } for ( p = 0; p < vg_ptr->pv_max; p++) { @@ -1661,7 +1878,7 @@ lvm_fs_create_vg(vg_ptr); - return 0; + return 0;*/ } /* lvm_do_vg_rename */ @@ -1671,8 +1888,8 @@ static int lvm_do_vg_remove(int minor) { int i; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - pv_t *pv_ptr; + kern_vg_t *vg_ptr = vg[VG_CHR(minor)]; + kern_pv_t *pv_ptr; if (vg_ptr == NULL) return -ENXIO; @@ -1693,7 +1910,7 @@ /* first free snapshot logical volumes */ for (i = 0; i < vg_ptr->lv_max; i++) { if (vg_ptr->lv[i] != NULL && - vg_ptr->lv[i]->u.lv_access & LV_SNAPSHOT) { + vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) { lvm_do_lv_remove(minor, NULL, i); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(1); @@ -1731,11 +1948,11 @@ /* * character device support function physical volume create */ -static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) { - pv_t *pv; +static int lvm_do_pv_create(user_pv_t *upv, kern_vg_t *vg_ptr, ulong p) { + kern_pv_t *pv; int err; - pv = kmalloc(sizeof(pv_t),GFP_KERNEL); + pv = kmalloc(sizeof(kern_pv_t),GFP_KERNEL); if (pv == NULL) { printk(KERN_CRIT "%s -- PV_CREATE: kmalloc error PV at line %d\n", @@ -1745,12 +1962,7 @@ memset(pv, 0, sizeof(*pv)); - if (copy_from_user(pv, pvp, sizeof(pv_t)) != 0) { - P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n", - pvp, sizeof(pv_t)); - kfree(pv); - return -EFAULT; - } + userpv_to_kernpv(upv,pv); if ((err = _open_pv(pv))) { kfree(pv); @@ -1774,8 +1986,8 @@ /* * character device support function physical volume remove */ -static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) { - pv_t *pv = vg_ptr->pv[p]; +static int lvm_do_pv_remove(kern_vg_t *vg_ptr, ulong p) { + kern_pv_t *pv = vg_ptr->pv[p]; lvm_fs_remove_pv(vg_ptr, pv); @@ -1792,44 +2004,45 @@ } -static void __update_hardsectsize(lv_t *lv) { - int le, e; +static void __update_hardsectsize(kern_lv_t *lv) { + int le; /*, e;*/ int max_hardsectsize = 0, hardsectsize; - for (le = 0; le < lv->u.lv_allocated_le; le++) { - hardsectsize = get_hardsect_size(lv->u.lv_current_pe[le].dev); + for (le = 0; le < lv->lv_allocated_le; le++) { + hardsectsize = bdev_hardsect_size(lv->lv_current_pe[le].bdev); if (hardsectsize == 0) hardsectsize = 512; if (hardsectsize > max_hardsectsize) max_hardsectsize = hardsectsize; } +#ifdef BROKEN /* snapshotting broken */ /* only perform this operation on active snapshots */ - if ((lv->u.lv_access & LV_SNAPSHOT) && - (lv->u.lv_status & LV_ACTIVE)) { - for (e = 0; e < lv->u.lv_remap_end; e++) { - hardsectsize = get_hardsect_size( lv->u.lv_block_exception[e].rdev_new); + if ((lv->lv_access & LV_SNAPSHOT) && + (lv->lv_status & LV_ACTIVE)) { + for (e = 0; e < lv->lv_remap_end; e++) { + hardsectsize = get_hardsect_size( lv->lv_block_exception[e].rdev_new); if (hardsectsize == 0) hardsectsize = 512; if (hardsectsize > max_hardsectsize) max_hardsectsize = hardsectsize; } } +#endif } /* * character device support function logical volume create */ -static int lvm_do_lv_create(int minor, char *lv_name, userlv_t *ulv) +static int lvm_do_lv_create(int minor, char *lv_name, user_lv_t *ulv) { - int e, ret, l, le, l_new, p, size, activate = 1; + int l, le, l_new, p, size, activate = 1; ulong lv_status_save; - lv_block_exception_t *lvbe = ulv->lv_block_exception; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *lv_ptr = NULL; - pe_t *pep; + kern_vg_t *vg_ptr = vg[VG_CHR(minor)]; + kern_lv_t *lv_ptr = NULL; + void *user_pep; - if (!(pep = ulv->lv_current_pe)) + if (!(user_pep = ulv->lv_current_pe)) return -EINVAL; if (_sectors_to_k(ulv->lv_chunk_size) > LVM_SNAPSHOT_MAX_CHUNK) @@ -1837,7 +2050,7 @@ for (l = 0; l < vg_ptr->lv_cur; l++) { if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->u.lv_name, lv_name) == 0) + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) return -EEXIST; } @@ -1854,37 +2067,28 @@ if (l_new == -1) return -EPERM; else l = l_new; - if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {; + if ((lv_ptr = kmalloc(sizeof(kern_lv_t),GFP_KERNEL)) == NULL) {; printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n", lvm_name, __LINE__); return -ENOMEM; } - /* copy preloaded LV */ - memcpy((char *) lv_ptr, (char *) ulv, sizeof(userlv_t)); - lv_status_save = lv_ptr->u.lv_status; - lv_ptr->u.lv_status &= ~LV_ACTIVE; - lv_ptr->u.lv_snapshot_org = NULL; - lv_ptr->u.lv_snapshot_prev = NULL; - lv_ptr->u.lv_snapshot_next = NULL; - lv_ptr->u.lv_block_exception = NULL; - lv_ptr->lv_iobuf = NULL; - lv_ptr->lv_COW_table_iobuf = NULL; - lv_ptr->lv_snapshot_hash_table = NULL; - lv_ptr->lv_snapshot_hash_table_size = 0; - lv_ptr->lv_snapshot_hash_mask = 0; - init_rwsem(&lv_ptr->lv_lock); - lv_ptr->lv_snapshot_use_rate = 0; + userlv_to_kernlv(ulv,lv_ptr); + + lv_status_save = lv_ptr->lv_status; + lv_ptr->lv_status &= ~LV_ACTIVE; vg_ptr->lv[l] = lv_ptr; /* get the PE structures from user space if this is not a snapshot logical volume */ - if (!(lv_ptr->u.lv_access & LV_SNAPSHOT)) { - size = lv_ptr->u.lv_allocated_le * sizeof(pe_t); + if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { + user_pe_t tmpupe; + + size = lv_ptr->lv_allocated_le * sizeof(kern_pe_t); - if ((lv_ptr->u.lv_current_pe = vmalloc(size)) == NULL) { + if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte " "at line %d\n", @@ -1894,24 +2098,53 @@ vg_ptr->lv[l] = NULL; return -ENOMEM; } - if (copy_from_user(lv_ptr->u.lv_current_pe, pep, size)) { - P_IOCTL("ERROR: copying PE ptr %p (%d bytes)\n", - pep, sizeof(size)); - vfree(lv_ptr->u.lv_current_pe); - kfree(lv_ptr); - vg_ptr->lv[l] = NULL; - return -EFAULT; + + /* just to be sure */ + memset(lv_ptr->lv_current_pe,0,size); + + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + /* copy the pe's one by one */ + if (copy_from_user(&tmpupe, user_pep+(le*sizeof(user_pe_t)), sizeof(user_pe_t))) { + P_IOCTL("ERROR: copying PE(%d) ptr %p (%d bytes)\n", + le,user_pep+(le*sizeof(user_pe_t)), + sizeof(user_lv_t)); + vfree(lv_ptr->lv_current_pe); + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EFAULT; + } + + lv_ptr->lv_current_pe[le].bdev = + bdget(tmpupe.dev); + lv_ptr->lv_current_pe[le].pe = + tmpupe.pe; + lv_ptr->lv_current_pe[le].reads = + tmpupe.reads; + lv_ptr->lv_current_pe[le].writes = + tmpupe.writes; + if(lv_ptr->lv_current_pe[le].bdev==NULL){ + printk(KERN_CRIT "%s bdget failed\n",lvm_name); + vfree(lv_ptr->lv_current_pe); + kfree(lv_ptr); + return -EINVAL; + } } + + /* correct the PE count in PVs */ - for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { vg_ptr->pe_allocated++; for (p = 0; p < vg_ptr->pv_cur; p++) { - if (kdev_same(vg_ptr->pv[p]->pv_dev, - lv_ptr->u.lv_current_pe[le].dev)) + if (kdev_same(vg_ptr->pv[p]->pv_kdev, + to_kdev_t(lv_ptr->lv_current_pe[le].bdev->bd_dev))) vg_ptr->pv[p]->pe_allocated++; } } - } else { + } else { /* snapshot */ + return -ENOSYS; +#ifdef BROKEN +/* + void *lvbe = ulv->lv_block_exception; */ /* Get snapshot exception data and block list */ if (lvbe != NULL) { lv_ptr->u.lv_snapshot_org = @@ -2004,22 +2237,25 @@ vg_ptr->lv[l] = NULL; return -EINVAL; } +#endif /* BROKEN */ } /* if ( vg[VG_CHR(minor)]->lv[l]->u.lv_access & LV_SNAPSHOT) */ + lv_ptr = vg_ptr->lv[l]; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].start_sect = 0; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].nr_sects = lv_ptr->u.lv_size; - lvm_size[minor(lv_ptr->u.lv_dev)] = lv_ptr->u.lv_size >> 1; - vg_lv_map[minor(lv_ptr->u.lv_dev)].vg_number = vg_ptr->vg_number; - vg_lv_map[minor(lv_ptr->u.lv_dev)].lv_number = lv_ptr->u.lv_number; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].start_sect = 0; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].nr_sects = lv_ptr->lv_size; + lvm_size[minor(lv_ptr->lv_kdev)] = lv_ptr->lv_size >> 1; + vg_lv_map[minor(lv_ptr->lv_kdev)].vg_number = vg_ptr->vg_number; + vg_lv_map[minor(lv_ptr->lv_kdev)].lv_number = lv_ptr->lv_number; vg_ptr->lv_cur++; - lv_ptr->u.lv_status = lv_status_save; + lv_ptr->lv_status = lv_status_save; __update_hardsectsize(lv_ptr); /* optionally add our new snapshot LV */ - if (lv_ptr->u.lv_access & LV_SNAPSHOT) { - lv_t *org = lv_ptr->u.lv_snapshot_org, *last; + if (lv_ptr->lv_access & LV_SNAPSHOT) { +#ifdef BROKEN + lv_t *org = lv_ptr->lv_snapshot_org, *last; /* sync the original logical volume */ fsync_dev(org->u.lv_dev); @@ -2037,28 +2273,30 @@ lv_ptr->u.lv_snapshot_prev = last; last->u.lv_snapshot_next = lv_ptr; up_write(&org->lv_lock); +#endif /* BROKEN */ } /* activate the logical volume */ if(activate) - lv_ptr->u.lv_status |= LV_ACTIVE; + lv_ptr->lv_status |= LV_ACTIVE; else - lv_ptr->u.lv_status &= ~LV_ACTIVE; + lv_ptr->lv_status &= ~LV_ACTIVE; - if ( lv_ptr->u.lv_access & LV_WRITE) - set_device_ro(lv_ptr->u.lv_dev, 0); + if ( lv_ptr->lv_access & LV_WRITE) + set_device_ro(lv_ptr->lv_kdev, 0); else - set_device_ro(lv_ptr->u.lv_dev, 1); + set_device_ro(lv_ptr->lv_kdev, 1); + #ifdef LVM_VFS_ENHANCEMENT /* VFS function call to unlock the filesystem */ - if (lv_ptr->u.lv_access & LV_SNAPSHOT) - unlockfs(lv_ptr->u.lv_snapshot_org->u.lv_dev); + if (lv_ptr->lv_access & LV_SNAPSHOT) + unlockfs(lv_ptr->lv_snapshot_org->lv_kdev); #endif lv_ptr->vg = vg_ptr; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].de = + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].de = lvm_fs_create_lv(vg_ptr, lv_ptr); return 0; @@ -2071,13 +2309,13 @@ static int lvm_do_lv_remove(int minor, char *lv_name, int l) { uint le, p; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *lv_ptr; + kern_vg_t *vg_ptr = vg[VG_CHR(minor)]; + kern_lv_t *lv_ptr; if (l == -1) { for (l = 0; l < vg_ptr->lv_max; l++) { if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->u.lv_name, lv_name) == 0) { + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) { break; } } @@ -2086,21 +2324,23 @@ lv_ptr = vg_ptr->lv[l]; #ifdef LVM_TOTAL_RESET - if (lv_ptr->u.lv_open > 0 && lvm_reset_spindown == 0) + if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0) #else - if (lv_ptr->u.lv_open > 0) + if (lv_ptr->lv_open > 0) #endif return -EBUSY; /* check for deletion of snapshot source while snapshot volume still exists */ - if ((lv_ptr->u.lv_access & LV_SNAPSHOT_ORG) && - lv_ptr->u.lv_snapshot_next != NULL) + if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) && + lv_ptr->lv_snapshot_next != NULL) return -EPERM; lvm_fs_remove_lv(vg_ptr, lv_ptr); - if (lv_ptr->u.lv_access & LV_SNAPSHOT) { + if (lv_ptr->lv_access & LV_SNAPSHOT) { + return -ENOSYS; +#ifdef BROKEN /* * Atomically make the the snapshot invisible * to the original lv before playing with it. @@ -2125,43 +2365,50 @@ /* Update the VG PE(s) used by snapshot reserve space. */ vg_ptr->pe_allocated -= lv_ptr->lv_allocated_snapshot_le; +#endif } - lv_ptr->u.lv_status |= LV_SPINDOWN; + lv_ptr->lv_status |= LV_SPINDOWN; /* sync the buffers */ - fsync_dev(lv_ptr->u.lv_dev); + fsync_dev(lv_ptr->lv_kdev); - lv_ptr->u.lv_status &= ~LV_ACTIVE; + lv_ptr->lv_status &= ~LV_ACTIVE; - /* invalidate the buffers */ - invalidate_buffers(lv_ptr->u.lv_dev); + /* invalidate the buffers - FIXME! we might want the bdev in the lv */ + { + struct block_device *bdev = bdget(kdev_t_to_nr(lv_ptr->lv_kdev)); + if (bdev) { + invalidate_bdev(bdev,0); + bdput(bdev); + } + } /* reset generic hd */ - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].start_sect = -1; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].nr_sects = 0; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].de = 0; - lvm_size[minor(lv_ptr->u.lv_dev)] = 0; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].start_sect = -1; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].nr_sects = 0; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].de = 0; + lvm_size[minor(lv_ptr->lv_kdev)] = 0; /* reset VG/LV mapping */ - vg_lv_map[minor(lv_ptr->u.lv_dev)].vg_number = ABS_MAX_VG; - vg_lv_map[minor(lv_ptr->u.lv_dev)].lv_number = -1; + vg_lv_map[minor(lv_ptr->lv_kdev)].vg_number = ABS_MAX_VG; + vg_lv_map[minor(lv_ptr->lv_kdev)].lv_number = -1; /* correct the PE count in PVs if this is not a snapshot logical volume */ - if (!(lv_ptr->u.lv_access & LV_SNAPSHOT)) { + if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { /* only if this is no snapshot logical volume because we share the u.lv_current_pe[] structs with the original logical volume */ - for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { vg_ptr->pe_allocated--; for (p = 0; p < vg_ptr->pv_cur; p++) { - if (kdev_same(vg_ptr->pv[p]->pv_dev, - lv_ptr->u.lv_current_pe[le].dev)) + if (kdev_same(vg_ptr->pv[p]->pv_kdev, + to_kdev_t(lv_ptr->lv_current_pe[le].bdev->bd_dev))) vg_ptr->pv[p]->pe_allocated--; } } - vfree(lv_ptr->u.lv_current_pe); + vfree(lv_ptr->lv_current_pe); } P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); @@ -2171,11 +2418,11 @@ return 0; } /* lvm_do_lv_remove() */ - +#ifdef BROKEN /* * logical volume extend / reduce */ -static int __extend_reduce_snapshot(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { +static int __extend_reduce_snapshot(kern_vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { ulong size; lv_block_exception_t *lvbe; @@ -2206,12 +2453,12 @@ return 0; } -static int __extend_reduce(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { +static int __extend_reduce(kern_vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { ulong size, l, p, end; pe_t *pe; /* allocate space for new pe structures */ - size = new_lv->u.lv_current_le * sizeof(pe_t); + size = new_lv->lv_current_le * sizeof(pe_t); if ((pe = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- lvm_do_lv_extend_reduce: " @@ -2221,7 +2468,7 @@ } /* get the PE structures from user space */ - if (copy_from_user(pe, new_lv->u.lv_current_pe, size)) { + if (copy_from_user(pe, new_lv->lv_current_pe, size)) { if(old_lv->u.lv_access & LV_SNAPSHOT) vfree(new_lv->lv_snapshot_hash_table); vfree(pe); @@ -2235,7 +2482,7 @@ vg_ptr->pe_allocated--; for (p = 0; p < vg_ptr->pv_cur; p++) { if (kdev_same(vg_ptr->pv[p]->pv_dev, - old_lv->u.lv_current_pe[l].dev)) { + to_kdev_t(old_lv->u.lv_current_pe[l].bdev->bd_dev))) { vg_ptr->pv[p]->pe_allocated--; break; } @@ -2247,7 +2494,7 @@ vg_ptr->pe_allocated++; for (p = 0; p < vg_ptr->pv_cur; p++) { if (kdev_same(vg_ptr->pv[p]->pv_dev, - new_lv->u.lv_current_pe[l].dev)) { + to_kdev_t(new_lv->u.lv_current_pe[l].bdev->bd_dev))) { vg_ptr->pv[p]->pe_allocated++; break; } @@ -2288,13 +2535,13 @@ return 0; } -static int lvm_do_lv_extend_reduce(int minor, char *lv_name, userlv_t *ulv) +static int lvm_do_lv_extend_reduce(int minor, char *lv_name, user_lv_t *ulv) { int r; ulong l, e, size; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *old_lv; - lv_t *new_lv; + kern_vg_t *vg_ptr = vg[VG_CHR(minor)]; + kern_lv_t *old_lv; + kern_lv_t *new_lv; pe_t *pe; if((new_lv = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL){ @@ -2304,7 +2551,7 @@ return -ENOMEM; } memset(new_lv,0,sizeof(lv_t)); - memcpy(&new_lv->u,ulv,sizeof(userlv_t)); + memcpy(&new_lv->u,ulv,sizeof(user_lv_t)); if ((pe = new_lv->u.lv_current_pe) == NULL) return -EINVAL; @@ -2319,11 +2566,13 @@ old_lv = vg_ptr->lv[l]; if (old_lv->u.lv_access & LV_SNAPSHOT) { + return -ENOSYS; /* only perform this operation on active snapshots */ - if (old_lv->u.lv_status & LV_ACTIVE) +/* if (old_lv->u.lv_status & LV_ACTIVE) r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv); - else - r = -EPERM; + else + r = -EPERM; +*/ } else r = __extend_reduce(vg_ptr, old_lv, new_lv); @@ -2335,6 +2584,9 @@ down_write(&old_lv->lv_lock); if(new_lv->u.lv_access & LV_SNAPSHOT) { + return -ENOSYS; + +/* size = (new_lv->u.lv_remap_end > old_lv->u.lv_remap_end) ? old_lv->u.lv_remap_ptr : new_lv->u.lv_remap_end; size *= sizeof(lv_block_exception_t); @@ -2354,10 +2606,9 @@ lvm_hash_link(new_lv->u.lv_block_exception + e, new_lv->u.lv_block_exception[e].rdev_org, new_lv->u.lv_block_exception[e].rsector_org, - new_lv); + new_lv);*/ } else { - vfree(old_lv->u.lv_current_pe); vfree(old_lv->lv_snapshot_hash_table); @@ -2395,18 +2646,19 @@ return 0; } /* lvm_do_lv_extend_reduce() */ - +#endif /* * character device support function logical volume status by name */ -static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg) +static int lvm_do_lv_status_byname(kern_vg_t *vg_ptr, void *arg) { uint l; lv_status_byname_req_t lv_status_byname_req; void *saved_ptr1; void *saved_ptr2; - lv_t *lv_ptr; + kern_lv_t *lv_ptr; + user_lv_t tmpulv; /* we're rather heavy on stack here */ if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_byname_req, arg, @@ -2415,30 +2667,74 @@ if (lv_status_byname_req.lv == NULL) return -EINVAL; + if (copy_from_user(&tmpulv, lv_status_byname_req.lv, + sizeof(user_lv_t)) != 0) + return -EFAULT; + for (l = 0; l < vg_ptr->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL && - strcmp(lv_ptr->u.lv_name, + strcmp(lv_ptr->lv_name, lv_status_byname_req.lv_name) == 0) { + /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_byname_req.lv->u.lv_current_pe, sizeof(void*)) != 0) - return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_byname_req.lv->u.lv_block_exception, sizeof(void*)) != 0) - return -EFAULT; + saved_ptr1=tmpulv.lv_current_pe; + saved_ptr2=tmpulv.lv_block_exception; + + kernlv_to_userlv(lv_ptr,&tmpulv); + + /* Restore usermode pointers */ + tmpulv.lv_current_pe=saved_ptr1; + tmpulv.lv_block_exception=saved_ptr2; + if (copy_to_user(lv_status_byname_req.lv, - lv_ptr, - sizeof(userlv_t)) != 0) + &tmpulv, + sizeof(user_lv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { + + +/* REVERSED IS: + + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + if (copy_from_user(&tmpupe, user_pep+(le*sizeof(user_pe_t)), sizeof(user_pe_t))) { + P_IOCTL("ERROR: copying PE(%d) ptr %p (%d bytes)\n", + le,user_pep+(le*sizeof(user_pe_t)), + sizeof(user_lv_t)); + printk(KERN_CRIT "err doin le %d\n",le); + + vfree(lv_ptr->lv_current_pe); + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EFAULT; + } + + lv_ptr->lv_current_pe[le].bdev = + bdget(tmpupe.dev); + lv_ptr->lv_current_pe[le].pe = + tmpupe.pe; + lv_ptr->lv_current_pe[le].reads = + tmpupe.reads; + lv_ptr->lv_current_pe[le].writes = + tmpupe.writes; + if(lv_ptr->lv_current_pe[le].bdev==NULL){ + printk(KERN_CRIT " bdget failed\n"); + return -EINVAL; + } + } + + + + + + // DO CORRECT COPYING! kern vs us pe_t if (copy_to_user(saved_ptr1, - lv_ptr->u.lv_current_pe, - lv_ptr->u.lv_allocated_le * - sizeof(pe_t)) != 0) - return -EFAULT; + lv_ptr->lv_current_pe, + lv_ptr->lv_allocated_le * + sizeof(kern_pe_t)) != 0) + return -EFAULT;*/ } - /* Restore usermode pointers */ - if (copy_to_user(&lv_status_byname_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void*)) != 0) - return -EFAULT; + return 0; } } @@ -2449,12 +2745,12 @@ /* * character device support function logical volume status by index */ -static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg) +static int lvm_do_lv_status_byindex(kern_vg_t *vg_ptr,void *arg) { lv_status_byindex_req_t lv_status_byindex_req; void *saved_ptr1; void *saved_ptr2; - lv_t *lv_ptr; + kern_lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_byindex_req, arg, @@ -2470,23 +2766,23 @@ return -ENXIO; /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->u.lv_current_pe, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe, sizeof(void*)) != 0) return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->u.lv_block_exception, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception, sizeof(void*)) != 0) return -EFAULT; - if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(userlv_t)) != 0) + if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(user_lv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, - lv_ptr->u.lv_current_pe, - lv_ptr->u.lv_allocated_le * - sizeof(pe_t)) != 0) + lv_ptr->lv_current_pe, + lv_ptr->lv_allocated_le * + sizeof(kern_pe_t)) != 0) //FIXME!! return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_byindex_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) + if (copy_to_user(&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; return 0; @@ -2496,12 +2792,18 @@ /* * character device support function logical volume status by device number */ -static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) { + + +/* rewrite this to do proper coping */ +static int lvm_do_lv_status_bydev(kern_vg_t * vg_ptr, void * arg) { + + return -ENOSYS; +#ifdef BROKEN int l; lv_status_bydev_req_t lv_status_bydev_req; void *saved_ptr1; void *saved_ptr2; - lv_t *lv_ptr; + kern_lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_bydev_req, arg, @@ -2510,7 +2812,7 @@ for ( l = 0; l < vg_ptr->lv_max; l++) { if ( vg_ptr->lv[l] == NULL) continue; - if ( kdev_same(vg_ptr->lv[l]->u.lv_dev, + if ( kdev_same(vg_ptr->lv[l]->lv_kdev, to_kdev_t(lv_status_bydev_req.dev))) break; } @@ -2519,44 +2821,50 @@ lv_ptr = vg_ptr->lv[l]; /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->u.lv_current_pe, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe, sizeof(void*)) != 0) return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->u.lv_block_exception, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception, sizeof(void*)) != 0) return -EFAULT; - if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != 0) +/* FIXME! if (copy_kernlv_to_userlv(lv_ptr,lv_status_bydev_req.lv) != 0) + kernlv_to_userlv() + copy_to_user + + */ + if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(user_lv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, - lv_ptr->u.lv_current_pe, - lv_ptr->u.lv_allocated_le * - sizeof(pe_t)) != 0) + lv_ptr->lv_current_pe, + lv_ptr->lv_allocated_le * + sizeof(kern_pe_t)) != 0) // BROKEN! return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_bydev_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) + if (copy_to_user(&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; return 0; +#endif } /* lvm_do_lv_status_bydev() */ /* * character device support function rename a logical volume */ -static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, userlv_t *ulv) +static int lvm_do_lv_rename(kern_vg_t *vg_ptr, lv_req_t *lv_req, user_lv_t *ulv) { int l = 0; int ret = 0; - lv_t *lv_ptr = NULL; + kern_lv_t *lv_ptr = NULL; for (l = 0; l < vg_ptr->lv_max; l++) { if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue; - if (kdev_same(lv_ptr->u.lv_dev, ulv->lv_dev)) + if (kdev_same(lv_ptr->lv_kdev, to_kdev_t(ulv->lv_dev))) { lvm_fs_remove_lv(vg_ptr, lv_ptr); - strncpy(lv_ptr->u.lv_name, + strncpy(lv_ptr->lv_name, lv_req->lv_name, NAME_LEN); lvm_fs_create_lv(vg_ptr, lv_ptr); @@ -2572,8 +2880,10 @@ /* * character device support function physical volume change */ -static int lvm_do_pv_change(vg_t *vg_ptr, void *arg) +static int lvm_do_pv_change(kern_vg_t *vg_ptr, void *arg) { + return -ENOSYS; +#ifdef BROKEN uint p; pv_t *pv_ptr; struct block_device *bd; @@ -2603,15 +2913,17 @@ } } return -ENXIO; +#endif } /* lvm_do_pv_change() */ /* * character device support function get physical volume status */ -static int lvm_do_pv_status(vg_t *vg_ptr, void *arg) +static int lvm_do_pv_status(kern_vg_t *vg_ptr, void *arg) { uint p; - pv_t *pv_ptr; + kern_pv_t *pv_ptr; + user_pv_t tmpupv; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&pv_status_req, arg, @@ -2623,9 +2935,10 @@ if (pv_ptr != NULL && strcmp(pv_ptr->pv_name, pv_status_req.pv_name) == 0) { + kernpv_to_userpv(pv_ptr,&tmpupv); if (copy_to_user(pv_status_req.pv, - pv_ptr, - sizeof(pv_t)) != 0) + &tmpupv, + sizeof(user_pv_t)) != 0) return -EFAULT; return 0; } @@ -2644,8 +2957,21 @@ sizeof(pv_flush_req)) != 0) return -EFAULT; - fsync_dev(pv_flush_req.pv_dev); - invalidate_buffers(pv_flush_req.pv_dev); + /* FIXME! should we really be allowed to flush any device here? */ + + fsync_dev(to_kdev_t(pv_flush_req.pv_dev)); + + /* invalidate the buffers */ + { + struct block_device *bdev = bdget(pv_flush_req.pv_dev); + if (bdev) { + invalidate_bdev(bdev,0); + bdput(bdev); + } + } + +// fsync_dev(to_kdev_t(pv_flush_req.pv_dev)); +// invalidate_buffers(to_kdev_t(pv_flush_req.pv_dev)); return 0; } @@ -2668,7 +2994,7 @@ } blk_size[MAJOR_NR] = lvm_size; - blksize_size[MAJOR_NR] = lvm_blocksizes; +/* blksize_size[MAJOR_NR] = lvm_blocksizes;*/ return; } /* lvm_gen_init() */ @@ -2715,11 +3041,11 @@ /* * we must open the pv's before we use them */ -static int _open_pv(pv_t *pv) { +static int _open_pv(kern_pv_t *pv) { int err; struct block_device *bd; - if (!(bd = bdget(kdev_t_to_nr(pv->pv_dev)))) + if (!(bd = bdget(kdev_t_to_nr(pv->pv_kdev)))) return -ENOMEM; err = blkdev_get(bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE); @@ -2730,7 +3056,7 @@ return 0; } -static void _close_pv(pv_t *pv) { +static void _close_pv(kern_pv_t *pv) { if (pv) { struct block_device *bdev = pv->bd; pv->bd = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/media/video/Config.help linux-2.5/drivers/media/video/Config.help --- linux-2.5.23/drivers/media/video/Config.help Wed Jun 19 03:11:51 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.23/drivers/media/video/planb.c linux-2.5/drivers/media/video/planb.c --- linux-2.5.23/drivers/media/video/planb.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/media/video/planb.c Fri Jun 7 02:36:08 2002 @@ -1,14 +1,17 @@ /* - planb - PlanB frame grabber driver + planb - v4l-compatible frame grabber driver for the PlanB hardware PlanB is used in the 7x00/8x00 series of PowerMacintosh Computers as video input DMA controller. - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) + Copyright (C) 1998 - 2002 Michel Lanners - Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) + Based largely on the old bttv driver by Ralph Metzler + + Additional debugging and coding by Takashi Oe + + For more information, see - Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) 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 @@ -25,7 +28,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */ +/* $Id: planb.c,v 2.11 2002/04/03 15:57:57 mlan Exp mlan $ */ #include #include @@ -40,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -52,37 +56,41 @@ #include #include -#include "planb.h" -#include "saa7196.h" +/* Define these to get general / interrupt debugging */ +#undef DEBUG +#undef IDEBUG -/* Would you mind for some ugly debugging? */ -#if 0 -#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */ +//#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(KERN_DEBUG ## x) #else -#define DEBUG(x...) /* Don't debug driver */ +#define DBG(x...) #endif - -#if 0 -#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */ +#ifdef IDEBUG +#define IDBG(x...) printk(KERN_DEBUG ## x) #else -#define IDEBUG(x...) /* Don't debug interrupt part */ +#define IDBG(x...) #endif -/* Ever seen a Mac with more than 1 of these? */ -#define PLANB_MAX 1 +#include "planb.h" +#include "saa7196.h" -static int planb_num; -static struct planb planbs[PLANB_MAX]; +static struct planb planbs; static volatile struct planb_registers *planb_regs; static int def_norm = PLANB_DEF_NORM; /* default norm */ static int video_nr = -1; +static int vbi_nr = -1; MODULE_PARM(def_norm, "i"); MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)"); MODULE_PARM(video_nr,"i"); -MODULE_LICENSE("GPL"); +MODULE_PARM(vbi_nr,"i"); +MODULE_DESCRIPTION("planb - v4l driver module for Apple PlanB video in"); +MODULE_AUTHOR("Michel Lanners & Takashi Oe - see: http://www.cpu.lu/planb.html"); +MODULE_LICENSE("GPL"); /* ------------------ PlanB Exported Functions ------------------ */ static long planb_write(struct video_device *, const char *, unsigned long, int); @@ -90,15 +98,25 @@ 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 int planb_vbi_open(struct video_device *, int); +static void planb_vbi_close(struct video_device *); +static long planb_vbi_read(struct video_device *, char *, unsigned long, int); +static unsigned int planb_vbi_poll(struct video_device *, struct file *, + poll_table *); +static int planb_vbi_ioctl(struct video_device *, unsigned int, void *); static void release_planb(void); -int init_planbs(struct video_init *); +static int __init init_planbs(void); +static void __exit exit_planbs(void); /* ------------------ PlanB Internal Functions ------------------ */ static int planb_prepare_open(struct planb *); +static int planb_prepare_vbi(struct planb *); +static int planb_prepare_video(struct planb *); static void planb_prepare_close(struct planb *); +static void planb_close_vbi(struct planb *); +static void planb_close_video(struct planb *); static void saa_write_reg(unsigned char, unsigned char); static unsigned char saa_status(int, struct planb *); static void saa_set(unsigned char, unsigned char, struct planb *); @@ -108,28 +126,41 @@ static void add_clip(struct planb *, struct video_clip *); static void fill_cmd_buff(struct planb *); static void cmd_buff(struct planb *); -static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *); +static dbdma_cmd_ptr setup_grab_cmd(int, struct planb *); static void overlay_start(struct planb *); static void overlay_stop(struct planb *); -static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short, - unsigned int); -static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int, - unsigned int); -static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short, - unsigned short, unsigned int, unsigned int); +static inline void tab_cmd_dbdma(dbdma_cmd_ptr, unsigned short, unsigned int); +static inline void tab_cmd_store(dbdma_cmd_ptr, unsigned int, unsigned int); +static inline void tab_cmd_gen(dbdma_cmd_ptr, unsigned short, unsigned short, + unsigned int, unsigned int); static int init_planb(struct planb *); static int find_planb(void); -static void planb_pre_capture(int, int, struct planb *); -static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *, - int, int, int, int, int, struct planb *); -static inline void planb_dbdma_stop(volatile struct dbdma_regs *); -static unsigned int saa_geo_setup(int, int, int, int, struct planb *); +static void planb_pre_capture(int, struct planb *); +static dbdma_cmd_ptr cmd_geo_setup(dbdma_cmd_ptr, int, int, int, int, int, + struct planb *); +static inline void planb_dbdma_stop(dbdma_regs_ptr); +static inline void planb_dbdma_restart(dbdma_regs_ptr); +static void saa_geo_setup(int, int, int, int, struct planb *); static inline int overlay_is_active(struct planb *); /*******************************/ /* Memory management functions */ /*******************************/ +/* I know this is not the right way to allocate memory. Whoever knows + * the right way to allocate a huge buffer for DMA that can be mapped + * to user space, please tell me... or better, fix the code and send + * patches. + * + * Michel Lanners (mlan@cpu.lu) + */ +/* FIXME: As subsequent calls to __get_free_pages don't necessarily return + * contiguous pages, we need to do horrible things later on when setting + * up DMA, to make sure a single DMA transfer doesn't cross a page boundary. + * At least, I hope it's done right later on ;-) ...... + * Anyway, there should be a way to get hold of a large buffer of contiguous + * pages for DMA.... + */ static int grabbuf_alloc(struct planb *pb) { int i, npage; @@ -143,14 +174,14 @@ * sizeof(unsigned long), GFP_KERNEL)) == 0) return -ENOMEM; for (i = 0; i < npage; i++) { - pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL - |GFP_DMA, 0); + pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL | + GFP_DMA, 0); if (!pb->rawbuf[i]) break; mem_map_reserve(virt_to_page(pb->rawbuf[i])); } if (i-- < npage) { - printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n"); + DBG("PlanB: init_grab: grab buffer not allocated\n"); for (; i > 0; i--) { mem_map_unreserve(virt_to_page(pb->rawbuf[i])); free_pages((unsigned long)pb->rawbuf[i], 0); @@ -158,7 +189,7 @@ kfree(pb->rawbuf); return -ENOBUFS; } - pb->rawbuf_size = npage; + pb->rawbuf_nchunks = npage; return 0; } @@ -182,12 +213,7 @@ /* Let's wait 30msec for this one */ current->state = TASK_INTERRUPTIBLE; -#if LINUX_VERSION_CODE >= 0x02017F schedule_timeout(30 * HZ / 1000); -#else - current->timeout = jiffies + 30 * HZ / 1000; /* 30 ms */; - schedule(); -#endif return (unsigned char)in_8 (&planb_regs->saa_status); } @@ -209,25 +235,15 @@ saa_write_reg (i, saa_regs[pb->win.norm][i]); } -static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp, - struct planb *pb) +static void saa_geo_setup(int width, int height, int interlace, + int fmt, struct planb *pb) { int ht, norm = pb->win.norm; - switch(bpp) { - case 2: - /* RGB555+a 1x16-bit + 16-bit transparent */ - saa_regs[norm][SAA7196_FMTS] &= ~0x3; - break; - case 1: - case 4: - /* RGB888 1x24-bit + 8-bit transparent */ - saa_regs[norm][SAA7196_FMTS] &= ~0x1; - saa_regs[norm][SAA7196_FMTS] |= 0x2; - break; - default: - return -EINVAL; - } + /* bits FS0, FS1 according to format spec */ + saa_regs[norm][SAA7196_FMTS] &= ~0x3; + saa_regs[norm][SAA7196_FMTS] |= (palette2fmt[fmt].saa_fmt & 0x3); + ht = (interlace ? height / 2 : height); saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff); saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3) @@ -241,93 +257,99 @@ : (saa_regs[norm][SAA7196_FMTS] | 0x60); /* transparent mode; extended format enabled */ saa_regs[norm][SAA7196_DPATH] |= 0x3; - - return 0; + /* bits LLV, MCT according to format spec */ + saa_regs[norm][SAA7196_DPATH] &= ~0x30; + saa_regs[norm][SAA7196_DPATH] |= (palette2fmt[fmt].saa_fmt & 0x30); } /***************************/ /* DBDMA support functions */ /***************************/ -static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch) +static inline void planb_dbdma_restart(dbdma_regs_ptr ch) { - out_le32(&ch->control, PLANB_CLR(RUN)); - out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE)); + writel(PLANB_CLR(RUN), &ch->control); + writel(PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE), &ch->control); } -static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch) +static inline void planb_dbdma_stop(dbdma_regs_ptr ch) { int i = 0; - out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH)); - while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) { - IDEBUG("PlanB: waiting for DMA to stop\n"); + writel(PLANB_CLR(RUN) | PLANB_SET(FLUSH), &ch->control); + while((readl(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) { + IDBG("PlanB: waiting for DMA to stop\n"); i++; } } -static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch, - unsigned short command, unsigned int cmd_dep) +static inline void tab_cmd_dbdma(dbdma_cmd_ptr ch, unsigned short command, + unsigned int cmd_dep) { st_le16(&ch->command, command); + st_le16(&ch->req_count, 0); + st_le32(&ch->phy_addr, 0); st_le32(&ch->cmd_dep, cmd_dep); + /* really clears res_count & xfer_status */ + st_le32((unsigned int *)&ch->res_count, 0); } -static inline void tab_cmd_store(volatile struct dbdma_cmd *ch, - unsigned int phy_addr, unsigned int cmd_dep) +static inline void tab_cmd_store(dbdma_cmd_ptr ch, unsigned int phy_addr, + unsigned int cmd_dep) { st_le16(&ch->command, STORE_WORD | KEY_SYSTEM); st_le16(&ch->req_count, 4); st_le32(&ch->phy_addr, phy_addr); st_le32(&ch->cmd_dep, cmd_dep); + st_le32((unsigned int *)&ch->res_count, 0); } -static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch, - unsigned short command, unsigned short req_count, - unsigned int phy_addr, unsigned int cmd_dep) +static inline void tab_cmd_gen(dbdma_cmd_ptr ch, unsigned short command, + unsigned short req_count, unsigned int phy_addr, unsigned int cmd_dep) { st_le16(&ch->command, command); st_le16(&ch->req_count, req_count); st_le32(&ch->phy_addr, phy_addr); st_le32(&ch->cmd_dep, cmd_dep); + st_le32((unsigned int *)&ch->res_count, 0); } -static volatile struct dbdma_cmd *cmd_geo_setup( - volatile struct dbdma_cmd *c1, int width, int height, int interlace, - int bpp, int clip, struct planb *pb) +static dbdma_cmd_ptr cmd_geo_setup(dbdma_cmd_ptr c1, int width, int height, + int interlace, int fmt, int clip, struct planb *pb) { int norm = pb->win.norm; - if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0) - return (volatile struct dbdma_cmd *)NULL; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_FMTS); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_FMTS]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_DPATH); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_DPATH]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even), - bpp | ((clip)? PLANB_CLIPMASK: 0)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd), - bpp | ((clip)? PLANB_CLIPMASK: 0)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_OUTPIX); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_OUTPIX]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_HFILT); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_HFILT]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + saa_geo_setup(width, height, interlace, fmt, pb); + /* if the number of DBDMA commands here (14) changes, lots of + * things need to be corrected accordingly... */ + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr), + SAA7196_FMTS); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval), + saa_regs[norm][SAA7196_FMTS]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr), + SAA7196_DPATH); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval), + saa_regs[norm][SAA7196_DPATH]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->even), + palette2fmt[fmt].pb_fmt | ((clip)? PLANB_CLIPMASK: 0)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->odd), + palette2fmt[fmt].pb_fmt | ((clip)? PLANB_CLIPMASK: 0)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr), + SAA7196_OUTPIX); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval), + saa_regs[norm][SAA7196_OUTPIX]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr), + SAA7196_HFILT); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval), + saa_regs[norm][SAA7196_HFILT]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr), SAA7196_OUTLINE); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval), saa_regs[norm][SAA7196_OUTLINE]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_VYP); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_VYP]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr), + SAA7196_VYP); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval), + saa_regs[norm][SAA7196_VYP]); return c1; } @@ -337,11 +359,13 @@ static inline void planb_lock(struct planb *pb) { + DBG("PlanB: planb_lock\n"); down(&pb->lock); } static inline void planb_unlock(struct planb *pb) { + DBG("PlanB: planb_unlock\n"); up(&pb->lock); } @@ -349,47 +373,116 @@ /* Driver Core */ /***************/ +/* number of entries in the circular DBDMA command buffer + * initial stop, odd/even vbi, odd/even video, branch back */ +#define NUMJUMPS 6 static int planb_prepare_open(struct planb *pb) { + dbdma_cmd_ptr c; + int size, i; + + size = (NUMJUMPS + 1) * sizeof(struct dbdma_cmd); + + if((pb->jump_raw = kmalloc (size, GFP_KERNEL|GFP_DMA)) == 0) + return -ENOMEM; + memset(pb->jump_raw, 0, size); + c = pb->jumpbuf = (dbdma_cmd_ptr) DBDMA_ALIGN (pb->jump_raw); + + /* circular DBDMA command buffer, to hold jumps to transfer commands */ + tab_cmd_dbdma(c++, DBDMA_STOP, 0); + for (i=1; ijumpbuf); + + DBG("PlanB: planb_prepare_open, jumpbuffer at 0x%08x, length %d.\n", + (unsigned int)pb->jumpbuf, size); + return 0; +} + +#define VBIDUMMY 40 /* must be even !! */ +static int planb_prepare_vbi(struct planb *pb) +{ + int size; + + /* allocate VBI comand buffer memory + (2 fields * VBI_MAXLINES + 40 handling + alignment) */ + size = (2*VBI_MAXLINES + VBIDUMMY + 1) * sizeof(struct dbdma_cmd); + + if ((pb->vbi_raw = kmalloc (size, GFP_KERNEL|GFP_DMA)) == 0) + return -ENOMEM; + memset (pb->vbi_raw, 0, size); + size = (VBI_MAXLINES + VBIDUMMY/2) * sizeof(struct dbdma_cmd); + pb->vbi_cbo.start = (dbdma_cmd_ptr) DBDMA_ALIGN (pb->vbi_raw); + pb->vbi_cbo.size = pb->vbi_cbe.size = size; + pb->vbi_cbe.start = pb->vbi_cbo.start + pb->vbi_cbo.size; + pb->vbi_cbo.jumpaddr = pb->jumpbuf + 1; + pb->vbi_cbe.jumpaddr = pb->jumpbuf + 3; + + DBG("PlanB: planb_prepare_vbi, dbdma cmd_buf at 0x%08x, length %d.\n", + (unsigned int)pb->vbi_cbo.start, 2*size); + return 0; +} + +static int planb_prepare_video(struct planb *pb) +{ int i, size; + /* FIXME: This is stressing kmalloc to its limits... + We really should allocate smaller chunks. */ + /* allocate memory for two plus alpha command buffers (size: max lines, plus 40 commands handling, plus 1 alignment), plus dummy command buf, plus clipmask buffer, plus frame grabbing status */ - size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS - * PLANB_DUMMY)*sizeof(struct dbdma_cmd) - +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8 - +MAX_GBUFFERS*sizeof(unsigned int); - if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0) + size = (pb->tab_size * (2 + MAX_GBUFFERS * TAB_FACTOR) + + MAX_GBUFFERS * PLANB_DUMMY + 1) * sizeof(struct dbdma_cmd) + + (PLANB_MAXLINES * ((PLANB_MAXPIXELS + 7) & ~7)) / 8 + + MAX_GBUFFERS * sizeof(unsigned int); + if ((pb->vid_raw = kmalloc (size, GFP_KERNEL|GFP_DMA)) == 0) return -ENOMEM; - memset ((void *) pb->priv_space, 0, size); - pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *) - DBDMA_ALIGN (pb->priv_space); - pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size; - pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd); - pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size; - pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR; + memset (pb->vid_raw, 0, size); + pb->vid_cbo.start = (dbdma_cmd_ptr) DBDMA_ALIGN (pb->vid_raw); + pb->vid_cbo.size = pb->vid_cbe.size = pb->tab_size/2; + pb->vid_cbe.start = pb->vid_cbo.start + pb->vid_cbo.size; + pb->vid_cbo.jumpaddr = pb->jumpbuf + 2; + pb->vid_cbe.jumpaddr = pb->jumpbuf + 4; + pb->overlay_last1 = pb->vid_cbo.start; + pb->vid_cbo.bus = virt_to_bus(pb->vid_cbo.start); + pb->vid_cbe.bus = virt_to_bus(pb->vid_cbe.start); + pb->clip_cbo.start = pb->vid_cbe.start + pb->vid_cbe.size; + pb->clip_cbo.size = pb->clip_cbe.size = pb->tab_size/2; + pb->clip_cbe.start = pb->clip_cbo.start + pb->clip_cbo.size; + pb->overlay_last2 = pb->clip_cbo.start; + pb->clip_cbo.bus = virt_to_bus(pb->clip_cbo.start); + pb->clip_cbe.bus = virt_to_bus(pb->clip_cbe.start); + pb->gbuf[0].cap_cmd = pb->clip_cbe.start + pb->clip_cbe.size; + pb->gbuf[0].pre_cmd = pb->gbuf[0].cap_cmd + pb->tab_size * TAB_FACTOR; for (i = 1; i < MAX_GBUFFERS; i++) { - pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY; - pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR; - } - pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1] - + PLANB_DUMMY); - pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS); + pb->gbuf[i].cap_cmd = pb->gbuf[i-1].pre_cmd + PLANB_DUMMY; + pb->gbuf[i].pre_cmd = pb->gbuf[i].cap_cmd + + pb->tab_size * TAB_FACTOR; + } + pb->gbuf[0].status = (volatile unsigned int *) + (pb->gbuf[MAX_GBUFFERS-1].pre_cmd + PLANB_DUMMY); + for (i = 1; i < MAX_GBUFFERS; i++) + pb->gbuf[i].status = pb->gbuf[i-1].status; + pb->mask = (unsigned char *)(pb->gbuf[MAX_GBUFFERS-1].status + 1); pb->rawbuf = NULL; - pb->rawbuf_size = 0; + pb->rawbuf_nchunks = 0; pb->grabbing = 0; for (i = 0; i < MAX_GBUFFERS; i++) { - pb->frame_stat[i] = GBUFFER_UNUSED; - pb->gwidth[i] = 0; - pb->gheight[i] = 0; - pb->gfmt[i] = 0; - pb->gnorm_switch[i] = 0; + gbuf_ptr gbuf = &pb->gbuf[i]; + + *gbuf->status = GBUFFER_UNUSED; + gbuf->width = 0; + gbuf->height = 0; + gbuf->fmt = 0; + gbuf->norm_switch = 0; #ifndef PLANB_GSCANLINE - pb->lsize[i] = 0; - pb->lnum[i] = 0; -#endif /* PLANB_GSCANLINE */ + gbuf->lsize = 0; + gbuf->lnum = 0; +#endif } pb->gcount = 0; pb->suspend = 0; @@ -400,30 +493,74 @@ planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); + DBG("PlanB: planb_prepare_video, dbdma cmd_buf at 0x%08x, " + "length %d.\n", (unsigned int)pb->vid_cbo.start, 2*size); return 0; } static void planb_prepare_close(struct planb *pb) { - int i; - /* make sure the dma's are idle */ planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); - /* free kernel memory of command buffers */ - if(pb->priv_space != 0) { - kfree (pb->priv_space); - pb->priv_space = 0; + + if(pb->jump_raw != 0) { + kfree(pb->jump_raw); + pb->jump_raw = 0; + } + return; +} + +static void planb_close_vbi(struct planb *pb) +{ + /* FIXME: stop running DMA */ + + /* Make sure the DMA controller doesn't jump here anymore */ + tab_cmd_dbdma(pb->vbi_cbo.jumpaddr, DBDMA_NOP, 0); + tab_cmd_dbdma(pb->vbi_cbe.jumpaddr, DBDMA_NOP, 0); + + if(pb->vbi_raw != 0) { + kfree (pb->vbi_raw); + pb->vbi_raw = 0; + } + + /* FIXME: deallocate VBI data buffer */ + + /* FIXME: restart running DMA if app. */ + return; +} + +static void planb_close_video(struct planb *pb) +{ + int i; + + /* FIXME: stop running DMA */ + + /* Make sure the DMA controller doesn't jump here anymore */ + tab_cmd_dbdma(pb->vid_cbo.jumpaddr, DBDMA_NOP, 0); + tab_cmd_dbdma(pb->vid_cbe.jumpaddr, DBDMA_NOP, 0); +/* No clipmask jumpbuffer yet */ +#if 0 + tab_cmd_dbdma(pb->clip_cbo.jumpaddr, DBDMA_NOP, 0); + tab_cmd_dbdma(pb->clip_cbe.jumpaddr, DBDMA_NOP, 0); +#endif + + if(pb->vid_raw != 0) { + kfree (pb->vid_raw); + pb->vid_raw = 0; pb->cmd_buff_inited = 0; } if(pb->rawbuf) { - for (i = 0; i < pb->rawbuf_size; i++) { + for (i = 0; i < pb->rawbuf_nchunks; i++) { mem_map_unreserve(virt_to_page(pb->rawbuf[i])); free_pages((unsigned long)pb->rawbuf[i], 0); } kfree(pb->rawbuf); } pb->rawbuf = NULL; + + /* FIXME: restart running DMA if app. */ + return; } /*****************************/ @@ -432,43 +569,37 @@ static void overlay_start(struct planb *pb) { + DBG("PlanB: overlay_start()\n"); - DEBUG("PlanB: overlay_start()\n"); + if(ACTIVE & readl(&pb->planb_base->ch1.status)) { - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - - DEBUG("PlanB: presumably, grabbing is in progress...\n"); + DBG("PlanB: presumably, grabbing is in progress...\n"); planb_dbdma_stop(&pb->planb_base->ch2); - out_le32 (&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->ch2_cmd)); + writel(pb->clip_cbo.bus, &pb->planb_base->ch2.cmdptr); planb_dbdma_restart(&pb->planb_base->ch2); - st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); + st_le16 (&pb->vid_cbo.start->command, DBDMA_NOP); + tab_cmd_dbdma(pb->gbuf[pb->last_fr].last_cmd, + DBDMA_NOP | BR_ALWAYS, pb->vid_cbo.bus); eieio(); pb->prev_last_fr = pb->last_fr; pb->last_fr = -2; - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - IDEBUG("PlanB: became inactive " + if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) { + IDBG("PlanB: became inactive " "in the mean time... reactivating\n"); planb_dbdma_stop(&pb->planb_base->ch1); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->ch1_cmd)); + writel(pb->vid_cbo.bus, &pb->planb_base->ch1.cmdptr); planb_dbdma_restart(&pb->planb_base->ch1); } } else { - DEBUG("PlanB: currently idle, so can do whatever\n"); + DBG("PlanB: currently idle, so can do whatever\n"); planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); - st_le32 (&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->ch2_cmd)); - st_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->ch1_cmd)); - out_le16 (&pb->ch1_cmd->command, DBDMA_NOP); + st_le32(&pb->planb_base->ch2.cmdptr, pb->clip_cbo.bus); + st_le32(&pb->planb_base->ch1.cmdptr, pb->vid_cbo.bus); + writew(DBDMA_NOP, &pb->vid_cbo.start->command); planb_dbdma_restart(&pb->planb_base->ch2); planb_dbdma_restart(&pb->planb_base->ch1); pb->last_fr = -1; @@ -478,29 +609,29 @@ static void overlay_stop(struct planb *pb) { - DEBUG("PlanB: overlay_stop()\n"); + DBG("PlanB: overlay_stop()\n"); if(pb->last_fr == -1) { - DEBUG("PlanB: no grabbing, it seems...\n"); + DBG("PlanB: no grabbing, it seems...\n"); planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); pb->last_fr = -999; } else if(pb->last_fr == -2) { unsigned int cmd_dep; - tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0); + tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].cap_cmd, DBDMA_STOP, 0); eieio(); - cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep); + cmd_dep = (unsigned int)readl(&pb->overlay_last1->cmd_dep); if(overlay_is_active(pb)) { - DEBUG("PlanB: overlay is currently active\n"); + DBG("PlanB: overlay is currently active\n"); planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); - if(cmd_dep != pb->ch1_cmd_phys) { - out_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->overlay_last1)); + if(cmd_dep != pb->vid_cbo.bus) { + writel(virt_to_bus(pb->overlay_last1), + &pb->planb_base->ch1.cmdptr); planb_dbdma_restart(&pb->planb_base->ch1); } } @@ -515,15 +646,15 @@ int fr = -1; struct dbdma_cmd last; - DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend); + DBG("PlanB: suspend_overlay: %d\n", pb->suspend); if(pb->suspend++) return; - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { + if(ACTIVE & readl(&pb->planb_base->ch1.status)) { if(pb->last_fr == -2) { fr = pb->prev_last_fr; - memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last)); - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); + memcpy(&last, (void*)pb->gbuf[fr].last_cmd, sizeof(last)); + tab_cmd_dbdma(pb->gbuf[fr].last_cmd, DBDMA_STOP, 0); } if(overlay_is_active(pb)) { planb_dbdma_stop(&pb->planb_base->ch2); @@ -543,38 +674,38 @@ static void resume_overlay(struct planb *pb) { - DEBUG("PlanB: resume_overlay: %d\n", pb->suspend); + DBG("PlanB: resume_overlay: %d\n", pb->suspend); if(pb->suspend > 1) return; if(pb->suspended.frame != -1) { - memcpy((void*)pb->last_cmd[pb->suspended.frame], - &pb->suspended.cmd, sizeof(pb->suspended.cmd)); + memcpy((void*)pb->gbuf[pb->suspended.frame].last_cmd, + &pb->suspended.cmd, sizeof(pb->suspended.cmd)); } - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { + if(ACTIVE & readl(&pb->planb_base->ch1.status)) { goto finish; } if(pb->suspended.overlay) { - DEBUG("PlanB: overlay being resumed\n"); + DBG("PlanB: overlay being resumed\n"); - st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - st_le16 (&pb->ch2_cmd->command, DBDMA_NOP); + st_le16 (&pb->vid_cbo.start->command, DBDMA_NOP); + st_le16 (&pb->clip_cbo.start->command, DBDMA_NOP); /* Set command buffer addresses */ - st_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->overlay_last1)); - out_le32(&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->overlay_last2)); + writel(virt_to_bus(pb->overlay_last1), + &pb->planb_base->ch1.cmdptr); + writel(virt_to_bus(pb->overlay_last2), + &pb->planb_base->ch2.cmdptr); /* Start the DMA controller */ - out_le32 (&pb->planb_base->ch2.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - out_le32 (&pb->planb_base->ch1.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); + writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE), + &pb->planb_base->ch2.control); + writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE), + &pb->planb_base->ch1.control); } else if(pb->suspended.frame != -1) { - out_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->last_cmd[pb->suspended.frame])); - out_le32 (&pb->planb_base->ch1.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); + writel(virt_to_bus(pb->gbuf[pb->suspended.frame].last_cmd), + &pb->planb_base->ch1.cmdptr); + writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE), + &pb->planb_base->ch1.control); } finish: @@ -590,7 +721,7 @@ int ww = pb->win.width, hw = pb->win.height; int x, y, xtmp1, xtmp2; - DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc); + DBG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc); if(xc < 0) { wc += xc; @@ -627,47 +758,48 @@ static void fill_cmd_buff(struct planb *pb) { - int restore = 0; - volatile struct dbdma_cmd last; + int restore = 0; + dbdma_cmd_t last; - DEBUG("PlanB: fill_cmd_buff()\n"); + DBG("PlanB: fill_cmd_buff()\n"); - if(pb->overlay_last1 != pb->ch1_cmd) { + if(pb->overlay_last1 != pb->vid_cbo.start) { restore = 1; last = *(pb->overlay_last1); } - memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size + memset ((void *) pb->vid_cbo.start, 0, 2 * pb->tab_size * sizeof(struct dbdma_cmd)); cmd_buff (pb); if(restore) *(pb->overlay_last1) = last; if(pb->suspended.overlay) { - unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep); - if(jump_addr != pb->ch1_cmd_phys) { + unsigned long jump_addr = readl(&pb->overlay_last1->cmd_dep); + if(jump_addr != pb->vid_cbo.bus) { int i; - DEBUG("PlanB: adjusting ch1's jump address\n"); + DBG("PlanB: adjusting ch1's jump address\n"); for(i = 0; i < MAX_GBUFFERS; i++) { - if(pb->need_pre_capture[i]) { - if(jump_addr == virt_to_bus(pb->pre_cmd[i])) + if(pb->gbuf[i].need_pre_capture) { + if(jump_addr == virt_to_bus(pb->gbuf[i].pre_cmd)) goto found; } else { - if(jump_addr == virt_to_bus(pb->cap_cmd[i])) + if(jump_addr == + virt_to_bus(pb->gbuf[i].cap_cmd)) goto found; } } - DEBUG("PlanB: not found...\n"); + DBG(" not found!\n"); goto out; found: - if(pb->need_pre_capture[i]) - out_le32(&pb->pre_cmd[i]->phy_addr, - virt_to_bus(pb->overlay_last1)); + if(pb->gbuf[i].need_pre_capture) + writel(virt_to_bus(pb->overlay_last1), + &pb->gbuf[i].pre_cmd->phy_addr); else - out_le32(&pb->cap_cmd[i]->phy_addr, - virt_to_bus(pb->overlay_last1)); + writel(virt_to_bus(pb->overlay_last1), + &pb->gbuf[i].cap_cmd->phy_addr); } } out: @@ -680,8 +812,8 @@ { int i, bpp, count, nlines, stepsize, interlace; unsigned long base, jump, addr_com, addr_dep; - volatile struct dbdma_cmd *c1 = pb->ch1_cmd; - volatile struct dbdma_cmd *c2 = pb->ch2_cmd; + dbdma_cmd_ptr c1 = pb->vid_cbo.start; + dbdma_cmd_ptr c2 = pb->clip_cbo.start; interlace = pb->win.interlace; bpp = pb->win.bpp; @@ -697,33 +829,28 @@ addr_dep = virt_to_bus(&c1->cmd_dep); tab_cmd_dbdma(c1++, DBDMA_NOP, 0); jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */ - if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, - bpp, 1, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered serious problems\n"); - tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0); - tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0); - return; - } + c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, + pb->win.color_fmt, 1, pb); tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16); tab_cmd_store(c1++, addr_dep, jump); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel), PLANB_SET(FIELD_SYNC)); /* (1) wait for field sync to be set */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(ODD_FIELD)); /* wait for field sync to be cleared */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); /* if not odd field, wait until field sync is set again */ tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; /* assert ch_sync to ch2 */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch2.control), PLANB_SET(CH_SYNC)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT)); - base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl - + pb->win.pad) + pb->win.x * bpp); + base = (pb->fb.phys + pb->fb.offset + pb->win.y * (pb->win.bpl + + pb->win.pad) + pb->win.x * bpp); if (interlace) { stepsize = 2; @@ -745,16 +872,16 @@ /* Resync to odd field */ /* (2) wait for field sync to be set */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(ODD_FIELD)); /* wait for field sync to be cleared */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); /* if not odd field, wait until field sync is set again */ tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; /* assert ch_sync to ch2 */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch2.control), PLANB_SET(CH_SYNC)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT)); /* odd field data: */ @@ -766,22 +893,22 @@ /* And jump back to the start */ cmd_tab_data_end: pb->overlay_last1 = c1; /* keep a pointer to the last command */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd)); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, pb->vid_cbo.bus); /* Clipmask command buffer */ /* Preamble commands: */ tab_cmd_dbdma(c2++, DBDMA_NOP, 0); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.wait_sel), PLANB_SET(CH_SYNC)); /* wait until ch1 asserts ch_sync */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); /* clear ch_sync asserted by ch1 */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control), + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.control), PLANB_CLR(CH_SYNC)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.wait_sel), PLANB_SET(FIELD_SYNC)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel), PLANB_SET(ODD_FIELD)); /* jump to end of even field if appropriate */ @@ -792,7 +919,7 @@ tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump); /* even field mask: */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel), PLANB_SET(DMA_ABORT)); /* this points to pos. B */ jump = (interlace) ? virt_to_bus(c2 + nlines + 1): @@ -807,7 +934,7 @@ goto cmd_tab_mask_end; /* odd field mask: */ -/* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), +/* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel), PLANB_SET(DMA_ABORT)); /* this points to pos. B */ jump = virt_to_bus(c2 + nlines / 2); @@ -825,13 +952,13 @@ /* corresponds to fsync (1) of ch1 */ /* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); /* restart ch1, meant to clear any dead bit or something */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch1.control), PLANB_CLR(RUN)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch1.control), PLANB_SET(RUN)); pb->overlay_last2 = c2; /* keep a pointer to the last command */ /* start over even field clipmasking */ - tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd)); + tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, pb->clip_cbo.bus); eieio(); return; @@ -841,40 +968,22 @@ /* grabdisplay support functions */ /*********************************/ -static int palette2fmt[] = { - 0, - PLANB_GRAY, - 0, - 0, - 0, - PLANB_COLOUR32, - PLANB_COLOUR15, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -}; - -#define PLANB_PALETTE_MAX 15 - static inline int overlay_is_active(struct planb *pb) { unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd); - unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr); + unsigned int caddr = (unsigned)readl(&pb->planb_base->ch1.cmdptr); - return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys) - && (caddr < (pb->ch1_cmd_phys + size)) - && (caddr >= (unsigned)pb->ch1_cmd_phys); + return (readl(&pb->overlay_last1->cmd_dep) == pb->vid_cbo.bus) + && (caddr < (pb->vid_cbo.bus + size)) + && (caddr >= (unsigned)pb->vid_cbo.bus); } static int vgrab(struct planb *pb, struct video_mmap *mp) { - unsigned int fr = mp->frame; - unsigned int format; + unsigned int fr = mp->frame; + unsigned int fmt = mp->format; + unsigned int bpp = palette2fmt[fmt].bpp; + gbuf_ptr gbuf = &pb->gbuf[fr]; if(pb->rawbuf==NULL) { int err; @@ -882,211 +991,225 @@ return err; } - IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, - mp->width, mp->height, fr); + DBG("PlanB: grab %d: %dx%d fmt %d (%u)\n", pb->grabbing, mp->width, + mp->height, fmt, fr); - if(pb->grabbing >= MAX_GBUFFERS) + if(pb->grabbing >= MAX_GBUFFERS) { + DBG(" no buffer\n"); return -ENOBUFS; - if(fr > (MAX_GBUFFERS - 1) || fr < 0) + } + if(fr > (MAX_GBUFFERS - 1) || fr < 0) { + DBG(" invalid buffer\n"); return -EINVAL; - if(mp->height <= 0 || mp->width <= 0) + } + if(mp->height <= 0 || mp->width <= 0) { + DBG(" negative height or width\n"); return -EINVAL; - if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) + } + if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) { + DBG(" format out of range\n"); return -EINVAL; - if((format = palette2fmt[mp->format]) == 0) + } + if(bpp == 0) { + DBG(" unsupported format %d\n", mp->format); return -EINVAL; - if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */ + } + if (mp->height * mp->width * bpp > PLANB_MAX_FBUF) { + DBG(" grab bigger than buffer\n"); return -EINVAL; + } planb_lock(pb); - if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || - format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { + if(mp->width != gbuf->width || mp->height != gbuf->height || + fmt != gbuf->fmt || (gbuf->norm_switch)) { int i; #ifndef PLANB_GSCANLINE - unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] - * pb->gfmt[fr]; - unsigned int nsize = mp->width * mp->height * format; + unsigned int osize = gbuf->width * gbuf->height * + palette2fmt[gbuf->fmt].bpp; + unsigned int nsize = mp->width * mp->height * bpp; #endif - IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n", - mp->width, mp->height, mp->format); + DBG("PlanB: changed gwidth = %d, gheight = %d, format = %u, " + "osize = %d, nsize = %d\n", mp->width, mp->height, fmt, + osize, nsize); +/* Do we _really_ need to clear the grab buffers?? */ +#if 0 #ifndef PLANB_GSCANLINE - if(pb->gnorm_switch[fr]) + if(gbuf->norm_switch) nsize = 0; if (nsize < osize) { - for(i = pb->gbuf_idx[fr]; osize > 0; i++) { + for(i = gbuf->idx; osize > 0; i++) { memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); osize -= PAGE_SIZE; } } - for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr] - + pb->lnum[fr]; i++) + for(i = gbuf->l_fr_addr_idx; i < + gbuf->l_fr_addr_idx + gbuf->lnum; i++) memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); #else /* XXX TODO */ /* - if(pb->gnorm_switch[fr]) + if(gbuf->norm_switch) memset((void *)pb->gbuffer[fr], 0, - pb->gbytes_per_line * pb->gheight[fr]); + pb->gbytes_per_line * gbuf->height); else { if(mp-> - for(i = 0; i < pb->gheight[fr]; i++) { + for(i = 0; i < gbuf->height; i++) { memset((void *)(pb->gbuffer[fr] + pb->gbytes_per_line * i } } */ #endif - pb->gwidth[fr] = mp->width; - pb->gheight[fr] = mp->height; - pb->gfmt[fr] = format; - pb->last_cmd[fr] = setup_grab_cmd(fr, pb); - planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */ - pb->need_pre_capture[fr] = 1; - pb->gnorm_switch[fr] = 0; +#endif /* if 0 */ + gbuf->width = mp->width; + gbuf->height = mp->height; + gbuf->fmt = fmt; + gbuf->last_cmd = setup_grab_cmd(fr, pb); + planb_pre_capture(fr, pb); + gbuf->need_pre_capture = 1; + gbuf->norm_switch = 0; } else - pb->need_pre_capture[fr] = 0; - pb->frame_stat[fr] = GBUFFER_GRABBING; - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { + gbuf->need_pre_capture = 0; - IDEBUG("PlanB: ch1 inactive, initiating grabbing\n"); + *gbuf->status = GBUFFER_GRABBING; + if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) { + + IDBG("PlanB: ch1 inactive, initiating grabbing\n"); planb_dbdma_stop(&pb->planb_base->ch1); - if(pb->need_pre_capture[fr]) { + if(gbuf->need_pre_capture) { - IDEBUG("PlanB: padding pre-capture sequence\n"); + DBG("PlanB: padding pre-capture sequence\n"); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->pre_cmd[fr])); + writel(virt_to_bus(gbuf->pre_cmd), + &pb->planb_base->ch1.cmdptr); } else { - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); + tab_cmd_dbdma(gbuf->last_cmd, DBDMA_STOP, 0); + tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0); /* let's be on the safe side. here is not timing critical. */ - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->cap_cmd[fr])); + tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0); + writel(virt_to_bus(gbuf->cap_cmd), + &pb->planb_base->ch1.cmdptr); } planb_dbdma_restart(&pb->planb_base->ch1); pb->last_fr = fr; } else { int i; - IDEBUG("PlanB: ch1 active, grabbing being queued\n"); + DBG("PlanB: ch1 active, grabbing being queued\n"); if((pb->last_fr == -1) || ((pb->last_fr == -2) && overlay_is_active(pb))) { - IDEBUG("PlanB: overlay is active, grabbing defered\n"); + DBG("PlanB: overlay is active, grabbing defered\n"); - tab_cmd_dbdma(pb->last_cmd[fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - if(pb->need_pre_capture[fr]) { + tab_cmd_dbdma(gbuf->last_cmd, DBDMA_NOP | BR_ALWAYS, + pb->vid_cbo.bus); + if(gbuf->need_pre_capture) { - IDEBUG("PlanB: padding pre-capture sequence\n"); + DBG("PlanB: padding pre-capture sequence\n"); - tab_cmd_store(pb->pre_cmd[fr], + tab_cmd_store(gbuf->pre_cmd, virt_to_bus(&pb->overlay_last1->cmd_dep), - virt_to_bus(pb->ch1_cmd)); + pb->vid_cbo.bus); eieio(); - out_le32 (&pb->overlay_last1->cmd_dep, - virt_to_bus(pb->pre_cmd[fr])); + writel(virt_to_bus(gbuf->pre_cmd), + &pb->overlay_last1->cmd_dep); } else { - tab_cmd_store(pb->cap_cmd[fr], + tab_cmd_store(gbuf->cap_cmd, virt_to_bus(&pb->overlay_last1->cmd_dep), - virt_to_bus(pb->ch1_cmd)); - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + pb->vid_cbo.bus); + tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0); eieio(); - out_le32 (&pb->overlay_last1->cmd_dep, - virt_to_bus(pb->cap_cmd[fr])); + writel(virt_to_bus(gbuf->cap_cmd), + &pb->overlay_last1->cmd_dep); } for(i = 0; overlay_is_active(pb) && i < 999; i++) - IDEBUG("PlanB: waiting for overlay done\n"); - tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); + DBG("PlanB: waiting for overlay done\n"); + tab_cmd_dbdma(pb->vid_cbo.start, DBDMA_NOP, 0); pb->prev_last_fr = fr; pb->last_fr = -2; } else if(pb->last_fr == -2) { - IDEBUG("PlanB: mixed mode detected, grabbing" + DBG("PlanB: mixed mode detected, grabbing" " will be done before activating overlay\n"); - tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); - if(pb->need_pre_capture[fr]) { + tab_cmd_dbdma(pb->vid_cbo.start, DBDMA_NOP, 0); + if(gbuf->need_pre_capture) { - IDEBUG("PlanB: padding pre-capture sequence\n"); + DBG("PlanB: padding pre-capture sequence\n"); - tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], + tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].last_cmd, DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->pre_cmd[fr])); + virt_to_bus(gbuf->pre_cmd)); eieio(); } else { - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - if(pb->gwidth[pb->prev_last_fr] != - pb->gwidth[fr] - || pb->gheight[pb->prev_last_fr] != - pb->gheight[fr] - || pb->gfmt[pb->prev_last_fr] != - pb->gfmt[fr]) - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0); + if(pb->gbuf[pb->prev_last_fr].width != + gbuf->width + || pb->gbuf[pb->prev_last_fr].height != + gbuf->height + || pb->gbuf[pb->prev_last_fr].fmt != + gbuf->fmt) + tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0); else - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr] + 16)); - tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], + virt_to_bus(gbuf->cap_cmd + 16)); + tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].last_cmd, DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr])); + virt_to_bus(gbuf->cap_cmd)); eieio(); } - tab_cmd_dbdma(pb->last_cmd[fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); + tab_cmd_dbdma(gbuf->last_cmd, DBDMA_NOP | BR_ALWAYS, + pb->vid_cbo.bus); eieio(); pb->prev_last_fr = fr; pb->last_fr = -2; } else { + gbuf_ptr lastgbuf = &pb->gbuf[pb->last_fr]; - IDEBUG("PlanB: active grabbing session detected\n"); + DBG("PlanB: active grabbing session detected\n"); - if(pb->need_pre_capture[fr]) { + if(gbuf->need_pre_capture) { - IDEBUG("PlanB: padding pre-capture sequence\n"); + DBG("PlanB: padding pre-capture sequence\n"); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], + tab_cmd_dbdma(lastgbuf->last_cmd, DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->pre_cmd[fr])); + virt_to_bus(gbuf->pre_cmd)); eieio(); } else { - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - if(pb->gwidth[pb->last_fr] != pb->gwidth[fr] - || pb->gheight[pb->last_fr] != - pb->gheight[fr] - || pb->gfmt[pb->last_fr] != - pb->gfmt[fr]) - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + tab_cmd_dbdma(gbuf->last_cmd, DBDMA_STOP, 0); + tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0); + if(lastgbuf->width != gbuf->width + || lastgbuf->height != gbuf->height + || lastgbuf->fmt != gbuf->fmt) + tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0); else - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr] + 16)); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], + virt_to_bus(gbuf->cap_cmd + 16)); + tab_cmd_dbdma(lastgbuf->last_cmd, DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr])); + virt_to_bus(gbuf->cap_cmd)); eieio(); } pb->last_fr = fr; } - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { + if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) { - IDEBUG("PlanB: became inactive in the mean time..." + DBG("PlanB: became inactive in the mean time... " "reactivating\n"); planb_dbdma_stop(&pb->planb_base->ch1); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->cap_cmd[fr])); + writel(virt_to_bus(gbuf->cap_cmd), + &pb->planb_base->ch1.cmdptr); planb_dbdma_restart(&pb->planb_base->ch1); } } @@ -1096,49 +1219,58 @@ return 0; } -static void planb_pre_capture(int fr, int bpp, struct planb *pb) +static void planb_pre_capture(int fr, struct planb *pb) { - volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr]; - int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; + gbuf_ptr gbuf = &pb->gbuf[fr]; + dbdma_cmd_ptr c1 = gbuf->pre_cmd; + int height = gbuf->height; + int interlace = (height > pb->maxlines/2)? 1: 0; tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, - bpp, 0, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered some problems\n"); - tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0); - return; - } + c1 = cmd_geo_setup(c1, gbuf->width, height, interlace, gbuf->fmt, + 0, pb); /* Sync to even field */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel), + PLANB_SET(FIELD_SYNC)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), + PLANB_SET(ODD_FIELD)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), + PLANB_SET(DMA_ABORT)); /* For non-interlaced, we use even fields only */ - if (pb->gheight[fr] <= pb->maxlines/2) + if (interlace == 0) goto cmd_tab_data_end; /* Sync to odd field */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), + PLANB_SET(ODD_FIELD)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), + PLANB_SET(DMA_ABORT)); cmd_tab_data_end: - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr])); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->cap_cmd)); eieio(); } -static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) +/* This needs some explanation. + * What we do here is write the DBDMA commands to fill the grab buffer. + * Since the grab buffer is made up of physically non-contiguous chunks, + * we need to make sure to not make the DMA engine write across a chunk + * boundary: the DMA engine needs a physically contiguous memory chunk for + * a single scan line. + * So all those scan lines that cross a chunk boundary are written do spare + * scratch buffers, and we keep track of this fact. + * Later, in the interrupt routine, we copy those scan lines (in two pieces) + * back to where they belong in the right sequence in the grab buffer. + */ +static dbdma_cmd_ptr setup_grab_cmd(int fr, struct planb *pb) { - int i, bpp, count, nlines, stepsize, interlace; + int i, count, nlines, stepsize, interlace; #ifdef PLANB_GSCANLINE int scanline; #else @@ -1147,19 +1279,20 @@ #endif unsigned long jump; int pagei; - volatile struct dbdma_cmd *c1; - volatile struct dbdma_cmd *jump_addr; - - c1 = pb->cap_cmd[fr]; - interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; - bpp = pb->gfmt[fr]; /* gfmt = bpp */ - count = bpp * pb->gwidth[fr]; - nlines = pb->gheight[fr]; + dbdma_cmd_ptr c1; + dbdma_cmd_ptr jump_addr; + gbuf_ptr gbuf = &pb->gbuf[fr]; + int fmt = gbuf->fmt; + + c1 = gbuf->cap_cmd; + nlines = gbuf->height; + interlace = (nlines > pb->maxlines/2) ? 1 : 0; + count = palette2fmt[fmt].bpp * gbuf->width; #ifdef PLANB_GSCANLINE scanline = pb->gbytes_per_line; #else - pb->lsize[fr] = count; - pb->lnum[fr] = 0; + gbuf->lsize = count; + gbuf->lnum = 0; #endif /* Do video in: */ @@ -1167,22 +1300,17 @@ /* Preamble commands: */ tab_cmd_dbdma(c1++, DBDMA_NOP, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++; - if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, - bpp, 0, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered serious problems\n"); - tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0); - return (pb->cap_cmd[fr] + 2); - } - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); + c1 = cmd_geo_setup(c1, gbuf->width, nlines, interlace, fmt, 0, pb); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel), + PLANB_SET(FIELD_SYNC)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), + PLANB_SET(ODD_FIELD)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), + PLANB_SET(DMA_ABORT)); if (interlace) { stepsize = 2; @@ -1195,12 +1323,12 @@ /* even field data: */ - pagei = pb->gbuf_idx[fr]; + pagei = gbuf->idx; #ifdef PLANB_GSCANLINE for (i = 0; i < nlines; i += stepsize) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pagei - + i * scanline / PAGE_SIZE]), jump); + tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, + virt_to_bus(pb->rawbuf[pagei + i * scanline / PAGE_SIZE]), + jump); } #else i = 0; @@ -1220,18 +1348,25 @@ leftover1 = 0; else { if(lov0 >= count) { + /* can happen only when interlacing; then other field + * uses up leftover space (lov0 - count). */ tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base + count * nlpp * stepsize + leftover1, jump); } else { - pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] + /* start of free space at end of page: */ + pb->l_to_addr[fr][gbuf->lnum] = pb->rawbuf[pagei] + count * nlpp * stepsize + leftover1; - pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; - pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0; + /* index where continuation is: */ + pb->l_to_next_idx[fr][gbuf->lnum] = pagei + 1; + /* How much is left to do in next page: */ + pb->l_to_next_size[fr][gbuf->lnum] = count - lov0; tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] - + pb->lnum[fr]]), jump); - if(++pb->lnum[fr] > MAX_LNUM) - pb->lnum[fr]--; + virt_to_bus(pb->rawbuf[gbuf->l_fr_addr_idx + + gbuf->lnum]), jump); + if(++gbuf->lnum > MAX_LNUM) { + /* FIXME: error condition! */ + gbuf->lnum--; + } } leftover1 = count * stepsize - lov0; i += stepsize; @@ -1249,11 +1384,11 @@ /* Sync to odd field */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(ODD_FIELD)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT)); /* odd field data: */ @@ -1261,14 +1396,14 @@ jump = virt_to_bus(jump_addr); #ifdef PLANB_GSCANLINE for (i = 1; i < nlines; i += stepsize) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, virt_to_bus(pb->rawbuf[pagei + i * scanline / PAGE_SIZE]), jump); } #else i = 1; leftover1 = 0; - pagei = pb->gbuf_idx[fr]; + pagei = gbuf->idx; if(nlines <= 1) goto skip; do { @@ -1291,16 +1426,18 @@ leftover1 = 0; else { if(lov0 > count) { - pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] + pb->l_to_addr[fr][gbuf->lnum] = pb->rawbuf[pagei] + count * (nlpp * stepsize + 1) + leftover1; - pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; - pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize + pb->l_to_next_idx[fr][gbuf->lnum] = pagei + 1; + pb->l_to_next_size[fr][gbuf->lnum] = count * stepsize - lov0; tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] - + pb->lnum[fr]]), jump); - if(++pb->lnum[fr] > MAX_LNUM) - pb->lnum[fr]--; + virt_to_bus(pb->rawbuf[gbuf->l_fr_addr_idx + + gbuf->lnum]), jump); + if(++gbuf->lnum > MAX_LNUM) { + /* FIXME: error condition! */ + gbuf->lnum--; + } i += stepsize; } leftover1 = count * stepsize - lov0; @@ -1314,7 +1451,7 @@ #endif /* PLANB_GSCANLINE */ cmd_tab_data_end: - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat), + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->intr_stat), (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); /* stop it */ tab_cmd_dbdma(c1, DBDMA_STOP, 0); @@ -1328,50 +1465,54 @@ unsigned int stat, astat; struct planb *pb = (struct planb *)dev_id; - IDEBUG("PlanB: planb_irq()\n"); + IDBG("PlanB: planb_irq()\n"); /* get/clear interrupt status bits */ eieio(); - stat = in_le32(&pb->planb_base->intr_stat); + stat = readl(&pb->planb_base->intr_stat); astat = stat & pb->intr_mask; - out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ - & ~astat & stat & ~PLANB_GEN_IRQ); - IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat); + writel(PLANB_FRM_IRQ & ~astat & stat & ~PLANB_GEN_IRQ, + &pb->planb_base->intr_stat); + IDBG("PlanB: stat = %X, astat = %X\n", stat, astat); if(astat & PLANB_FRM_IRQ) { - unsigned int fr = stat >> 9; + unsigned int fr = stat >> 9; + gbuf_ptr gbuf = &pb->gbuf[fr]; #ifndef PLANB_GSCANLINE - int i; + int i; #endif - IDEBUG("PlanB: PLANB_FRM_IRQ\n"); + IDBG("PlanB: PLANB_FRM_IRQ\n"); pb->gcount++; - IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n", + IDBG("PlanB: grab %d: fr = %d, gcount = %d\n", pb->grabbing, fr, pb->gcount); #ifndef PLANB_GSCANLINE - IDEBUG("PlanB: %d * %d bytes are being copied over\n", - pb->lnum[fr], pb->lsize[fr]); - for(i = 0; i < pb->lnum[fr]; i++) { - int first = pb->lsize[fr] - pb->l_to_next_size[fr][i]; + /* Now that the buffer is full, copy those lines that fell + * on a page boundary from the spare buffers back to where + * they belong. */ + IDBG("PlanB: %d * %d bytes are being copied over\n", + gbuf->lnum, gbuf->lsize); + for(i = 0; i < gbuf->lnum; i++) { + int first = gbuf->lsize - pb->l_to_next_size[fr][i]; memcpy(pb->l_to_addr[fr][i], - pb->rawbuf[pb->l_fr_addr_idx[fr] + i], + pb->rawbuf[gbuf->l_fr_addr_idx + i], first); memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]], - pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first, + pb->rawbuf[gbuf->l_fr_addr_idx + i] + first, pb->l_to_next_size[fr][i]); } #endif - pb->frame_stat[fr] = GBUFFER_DONE; + *gbuf->status = GBUFFER_DONE; pb->grabbing--; wake_up_interruptible(&pb->capq); return; } /* incorrect interrupts? */ pb->intr_mask = PLANB_CLR_IRQ; - out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts" + writel(PLANB_CLR_IRQ, &pb->planb_base->intr_stat); + printk(KERN_ERR "PlanB: IRQ lockup, cleared interrupts" " unconditionally\n"); } @@ -1381,16 +1522,22 @@ static int planb_open(struct video_device *dev, int mode) { - struct planb *pb = (struct planb *)dev; + struct planb *pb = (struct planb *)dev->priv; + int err; - if (pb->user == 0) { - int err; + /* first open on driver? */ + if(pb->vid_user + pb->vbi_user == 0) { if((err = planb_prepare_open(pb)) != 0) return err; } - pb->user++; + /* first open on video dev? */ + if(pb->vid_user == 0) { + if((err = planb_prepare_video(pb)) != 0) + return err; + } + pb->vid_user++; - DEBUG("PlanB: device opened\n"); + DBG("PlanB: device opened\n"); MOD_INC_USE_COUNT; return 0; @@ -1398,44 +1545,46 @@ static void planb_close(struct video_device *dev) { - struct planb *pb = (struct planb *)dev; + struct planb *pb = (struct planb *)dev->priv; - if(pb->user < 1) /* ??? */ - return; planb_lock(pb); - if (pb->user == 1) { - if (pb->overlay) { + /* last close? then stop everything... */ + if(--pb->vid_user == 0) { + if(pb->overlay) { planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); pb->overlay = 0; } - planb_prepare_close(pb); + planb_close_video(pb); } - pb->user--; + /* last open on PlanB hardware? */ + if(pb->vid_user + pb->vbi_user == 0) + planb_prepare_close(pb); planb_unlock(pb); - DEBUG("PlanB: device closed\n"); + DBG("PlanB: device closed\n"); - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; + return; } static long planb_read(struct video_device *v, char *buf, unsigned long count, int nonblock) { - DEBUG("planb: read request\n"); + DBG("planb: read request\n"); return -EINVAL; } static long planb_write(struct video_device *v, const char *buf, unsigned long count, int nonblock) { - DEBUG("planb: write request\n"); + DBG("planb: write request\n"); return -EINVAL; } static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { - struct planb *pb=(struct planb *)dev; + struct planb *pb=(struct planb *)dev->priv; switch (cmd) { @@ -1443,7 +1592,7 @@ { struct video_capability b; - DEBUG("PlanB: IOCTL VIDIOCGCAP\n"); + DBG("PlanB: IOCTL VIDIOCGCAP\n"); strcpy (b.name, pb->video_dev.name); b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | @@ -1462,50 +1611,48 @@ case VIDIOCSFBUF: { struct video_buffer v; - unsigned short bpp; unsigned int fmt; - DEBUG("PlanB: IOCTL VIDIOCSFBUF\n"); + DBG("PlanB: IOCTL VIDIOCSFBUF\n"); - if (!capable(CAP_SYS_ADMIN) - || !capable(CAP_SYS_RAWIO)) + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; - if (copy_from_user(&v, arg,sizeof(v))) + if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; planb_lock(pb); switch(v.depth) { - case 8: - bpp = 1; - fmt = PLANB_GRAY; + /* xawtv only asks for 8 bit in static grey, but + * there is no way to know what it really means.. */ + case 8: + fmt = VIDEO_PALETTE_GREY; break; - case 15: - case 16: - bpp = 2; - fmt = PLANB_COLOUR15; + case 15: + fmt = VIDEO_PALETTE_RGB555; break; - case 24: - case 32: - bpp = 4; - fmt = PLANB_COLOUR32; + case 32: + fmt = VIDEO_PALETTE_RGB32; break; - default: + /* We don't deliver these two... */ + case 16: + case 24: + default: planb_unlock(pb); return -EINVAL; } - if (bpp * v.width > v.bytesperline) { + if (palette2fmt[fmt].bpp * v.width > v.bytesperline) { planb_unlock(pb); return -EINVAL; } - pb->win.bpp = bpp; + pb->win.bpp = palette2fmt[fmt].bpp; pb->win.color_fmt = fmt; - pb->frame_buffer_phys = (unsigned long) v.base; + pb->fb.phys = (unsigned long) v.base; pb->win.sheight = v.height; pb->win.swidth = v.width; pb->picture.depth = pb->win.depth = v.depth; pb->win.bpl = pb->win.bpp * pb->win.swidth; pb->win.pad = v.bytesperline - pb->win.bpl; - DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d," + DBG("PlanB: Display at %p is %d by %d, bytedepth %d," " bpl %d (+ %d)\n", v.base, v.width,v.height, pb->win.bpp, pb->win.bpl, pb->win.pad); @@ -1522,9 +1669,9 @@ { struct video_buffer v; - DEBUG("PlanB: IOCTL VIDIOCGFBUF\n"); + DBG("PlanB: IOCTL VIDIOCGFBUF\n"); - v.base = (void *)pb->frame_buffer_phys; + v.base = (void *)pb->fb.phys; v.height = pb->win.sheight; v.width = pb->win.swidth; v.depth = pb->win.depth; @@ -1540,7 +1687,7 @@ if(copy_from_user(&i, arg, sizeof(i))) return -EFAULT; if(i==0) { - DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n"); + DBG("PlanB: IOCTL VIDIOCCAPTURE Stop\n"); if (!(pb->overlay)) return 0; @@ -1549,9 +1696,9 @@ overlay_stop(pb); planb_unlock(pb); } else { - DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n"); + DBG("PlanB: IOCTL VIDIOCCAPTURE Start\n"); - if (pb->frame_buffer_phys == 0 || + if (pb->fb.phys == 0 || pb->win.width == 0 || pb->win.height == 0) return -EINVAL; @@ -1570,7 +1717,7 @@ { struct video_channel v; - DEBUG("PlanB: IOCTL VIDIOCGCHAN\n"); + DBG("PlanB: IOCTL VIDIOCGCHAN\n"); if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; @@ -1599,7 +1746,7 @@ { struct video_channel v; - DEBUG("PlanB: IOCTL VIDIOCSCHAN\n"); + DBG("PlanB: IOCTL VIDIOCSCHAN\n"); if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; @@ -1617,6 +1764,7 @@ maxlines = PLANB_NTSC_MAXLINES; break; default: + DBG(" invalid norm %d.\n", v.norm); return -EINVAL; break; } @@ -1629,7 +1777,7 @@ /* Stop overlay if running */ suspend_overlay(pb); for(i = 0; i < MAX_GBUFFERS; i++) - pb->gnorm_switch[i] = 1; + pb->gbuf[i].norm_switch = 1; /* I know it's an overkill, but.... */ fill_cmd_buff(pb); /* ok, now init it accordingly */ @@ -1652,6 +1800,7 @@ ~7) | 4), pb); break; default: + DBG(" invalid channel %d.\n", v.channel); return -EINVAL; break; } @@ -1662,22 +1811,9 @@ { struct video_picture vp = pb->picture; - DEBUG("PlanB: IOCTL VIDIOCGPICT\n"); - - switch(pb->win.color_fmt) { - case PLANB_GRAY: - vp.palette = VIDEO_PALETTE_GREY; - case PLANB_COLOUR15: - vp.palette = VIDEO_PALETTE_RGB555; - break; - case PLANB_COLOUR32: - vp.palette = VIDEO_PALETTE_RGB32; - break; - default: - vp.palette = 0; - break; - } + DBG("PlanB: IOCTL VIDIOCGPICT\n"); + vp.palette = pb->win.color_fmt; if(copy_to_user(arg,&vp,sizeof(vp))) return -EFAULT; return 0; @@ -1686,12 +1822,13 @@ { struct video_picture vp; - DEBUG("PlanB: IOCTL VIDIOCSPICT\n"); + DBG("PlanB: IOCTL VIDIOCSPICT\n"); if(copy_from_user(&vp,arg,sizeof(vp))) return -EFAULT; pb->picture = vp; /* Should we do sanity checks here? */ + planb_lock(pb); saa_set (SAA7196_BRIG, (unsigned char) ((pb->picture.brightness) >> 8), pb); saa_set (SAA7196_HUEC, (unsigned char) @@ -1700,6 +1837,7 @@ ((pb->picture.colour) >> 9), pb); saa_set (SAA7196_CONT, (unsigned char) ((pb->picture.contrast) >> 9), pb); + planb_unlock(pb); return 0; } @@ -1709,7 +1847,7 @@ struct video_clip clip; int i; - DEBUG("PlanB: IOCTL VIDIOCSWIN\n"); + DBG("PlanB: IOCTL VIDIOCSWIN\n"); if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; @@ -1729,6 +1867,9 @@ pb->win.height = vw.height; fill_cmd_buff(pb); } + DBG("PlanB: Window at (%d,%d) size %dx%d\n", vw.x, vw.y, vw.width, + vw.height); + /* Reset clip mask */ memset ((void *) pb->mask, 0xff, (pb->maxlines * ((PLANB_MAXPIXELS + 7) & ~7)) / 8); @@ -1748,7 +1889,7 @@ { struct video_window vw; - DEBUG("PlanB: IOCTL VIDIOCGWIN\n"); + DBG("PlanB: IOCTL VIDIOCGWIN\n"); vw.x=pb->win.x; vw.y=pb->win.y; @@ -1763,30 +1904,32 @@ return 0; } case VIDIOCSYNC: { - int i; + int i; + gbuf_ptr gbuf; - IDEBUG("PlanB: IOCTL VIDIOCSYNC\n"); + DBG("PlanB: IOCTL VIDIOCSYNC\n"); if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; - IDEBUG("PlanB: sync to frame %d\n", i); + DBG("PlanB: sync to frame %d\n", i); if(i > (MAX_GBUFFERS - 1) || i < 0) return -EINVAL; + gbuf = &pb->gbuf[i]; chk_grab: - switch (pb->frame_stat[i]) { + switch (*gbuf->status) { case GBUFFER_UNUSED: return -EINVAL; case GBUFFER_GRABBING: - IDEBUG("PlanB: waiting for grab" + DBG("PlanB: waiting for grab" " done (%d)\n", i); interruptible_sleep_on(&pb->capq); if(signal_pending(current)) return -EINTR; goto chk_grab; case GBUFFER_DONE: - pb->frame_stat[i] = GBUFFER_UNUSED; + *gbuf->status = GBUFFER_UNUSED; break; } return 0; @@ -1795,17 +1938,19 @@ case VIDIOCMCAPTURE: { struct video_mmap vm; - volatile unsigned int status; + int fr; - IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n"); + DBG("PlanB: IOCTL VIDIOCMCAPTURE\n"); if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm))) return -EFAULT; - status = pb->frame_stat[vm.frame]; - if (status != GBUFFER_UNUSED) - return -EBUSY; + fr = vm.frame; + if(fr > (MAX_GBUFFERS - 1) || fr < 0) + return -EINVAL; + if (*pb->gbuf[fr].status != GBUFFER_UNUSED) + return -EBUSY; - return vgrab(pb, &vm); + return vgrab(pb, &vm); } case VIDIOCGMBUF: @@ -1813,7 +1958,7 @@ int i; struct video_mbuf vm; - DEBUG("PlanB: IOCTL VIDIOCGMBUF\n"); + DBG("PlanB: IOCTL VIDIOCGMBUF\n"); memset(&vm, 0 , sizeof(vm)); vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS; @@ -1825,11 +1970,27 @@ return 0; } + case VIDIOCGUNIT: + { + struct video_unit vu; + + DBG("PlanB: IOCTL VIDIOCGUNIT\n"); + + vu.video=pb->video_dev.minor; + vu.vbi=pb->vbi_dev.minor; + vu.radio=VIDEO_NO_UNIT; + vu.audio=VIDEO_NO_UNIT; + vu.teletext=VIDEO_NO_UNIT; + if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) + return -EFAULT; + return 0; + } + case PLANBIOCGSAAREGS: { struct planb_saa_regs preg; - DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n"); + DBG("PlanB: IOCTL PLANBIOCGSAAREGS\n"); if(copy_from_user(&preg, arg, sizeof(preg))) return -EFAULT; @@ -1846,7 +2007,7 @@ { struct planb_saa_regs preg; - DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n"); + DBG("PlanB: IOCTL PLANBIOCSSAAREGS\n"); if(copy_from_user(&preg, arg, sizeof(preg))) return -EFAULT; @@ -1860,10 +2021,14 @@ { struct planb_stat_regs pstat; - DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n"); + DBG("PlanB: IOCTL PLANBIOCGSTAT\n"); - pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status); - pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status); + pstat.ch1_stat = readl(&pb->planb_base->ch1.status); + pstat.ch2_stat = readl(&pb->planb_base->ch2.status); + pstat.ch1_cmdbase = (unsigned long)pb->vid_cbo.start; + pstat.ch2_cmdbase = (unsigned long)pb->clip_cbo.start; + pstat.ch1_cmdptr = readl(&pb->planb_base->ch1.cmdptr); + pstat.ch2_cmdptr = readl(&pb->planb_base->ch2.cmdptr); pstat.saa_stat0 = saa_status(0, pb); pstat.saa_stat1 = saa_status(1, pb); @@ -1872,11 +2037,11 @@ return -EFAULT; return 0; } - + case PLANBIOCSMODE: { int v; - DEBUG("PlanB: IOCTL PLANBIOCSMODE\n"); + DBG("PlanB: IOCTL PLANBIOCSMODE\n"); if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; @@ -1903,7 +2068,7 @@ case PLANBIOCGMODE: { int v=pb->win.mode; - DEBUG("PlanB: IOCTL PLANBIOCGMODE\n"); + DBG("PlanB: IOCTL PLANBIOCGMODE\n"); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; @@ -1913,25 +2078,28 @@ case PLANBG_GRAB_BPL: { int v=pb->gbytes_per_line; - DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); + DBG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; } #endif /* PLANB_GSCANLINE */ + +/* These serve only for debugging... */ +#ifdef DEBUG case PLANB_INTR_DEBUG: { int i; - DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); + DBG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); if(copy_from_user(&i, arg, sizeof(i))) return -EFAULT; /* avoid hang ups all together */ for (i = 0; i < MAX_GBUFFERS; i++) { - if(pb->frame_stat[i] == GBUFFER_GRABBING) { - pb->frame_stat[i] = GBUFFER_DONE; + if(*pb->gbuf[i].status == GBUFFER_GRABBING) { + *pb->gbuf[i].status = GBUFFER_DONE; } } if(pb->grabbing) @@ -1943,7 +2111,7 @@ int i; struct planb_any_regs any; - DEBUG("PlanB: IOCTL PLANB_INV_REGS\n"); + DBG("PlanB: IOCTL PLANB_INV_REGS\n"); if(copy_from_user(&any, arg, sizeof(any))) return -EFAULT; @@ -1953,42 +2121,70 @@ return -EINVAL; for (i = 0; i < any.bytes; i++) { any.data[i] = - in_8((unsigned char *)pb->planb_base + readb((unsigned char *)pb->planb_base + any.offset + i); } if(copy_to_user(arg,&any,sizeof(any))) return -EFAULT; return 0; } + case PLANBIOCGDBDMABUF: + { + struct planb_buf_regs buf; + dbdma_cmd_ptr dc; + int i; + + DBG("PlanB: IOCTL PLANBIOCGDBDMABUF\n"); + + if(copy_from_user(&buf, arg, sizeof(buf))) + return -EFAULT; + buf.end &= ~0xf; + if( (buf.start < 0) || (buf.end < 0x10) || + (buf.end < buf.start+0x10) || + (buf.end > 2*pb->tab_size) ) + return -EINVAL; + + printk ("PlanB DBDMA command buffer:\n"); + for (i=(buf.start>>4); i<=(buf.end>>4); i++) { + printk(" 0x%04x:", i<<4); + dc = pb->vid_cbo.start + i; + printk (" %04x %04x %08x %08x %04x %04x\n", + dc->req_count, dc->command, dc->phy_addr, + dc->cmd_dep, dc->res_count, dc->xfer_status); + } + return 0; + } +#endif /* DEBUG */ + default: { - DEBUG("PlanB: Unimplemented IOCTL\n"); + DBG("PlanB: Unimplemented IOCTL: %d (0x%x)\n", cmd, cmd); return -ENOIOCTLCMD; } /* Some IOCTLs are currently unsupported on PlanB */ case VIDIOCGTUNER: { - DEBUG("PlanB: IOCTL VIDIOCGTUNER\n"); + DBG("PlanB: IOCTL VIDIOCGTUNER\n"); goto unimplemented; } case VIDIOCSTUNER: { - DEBUG("PlanB: IOCTL VIDIOCSTUNER\n"); + DBG("PlanB: IOCTL VIDIOCSTUNER\n"); goto unimplemented; } case VIDIOCSFREQ: { - DEBUG("PlanB: IOCTL VIDIOCSFREQ\n"); + DBG("PlanB: IOCTL VIDIOCSFREQ\n"); goto unimplemented; } case VIDIOCGFREQ: { - DEBUG("PlanB: IOCTL VIDIOCGFREQ\n"); + DBG("PlanB: IOCTL VIDIOCGFREQ\n"); goto unimplemented; } case VIDIOCKEY: { - DEBUG("PlanB: IOCTL VIDIOCKEY\n"); + DBG("PlanB: IOCTL VIDIOCKEY\n"); goto unimplemented; } case VIDIOCSAUDIO: { - DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n"); + DBG("PlanB: IOCTL VIDIOCSAUDIO\n"); goto unimplemented; } case VIDIOCGAUDIO: { - DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n"); + DBG("PlanB: IOCTL VIDIOCGAUDIO\n"); goto unimplemented; } unimplemented: - DEBUG(" Unimplemented\n"); + DBG(" Unimplemented\n"); return -ENOIOCTLCMD; } return 0; @@ -1996,9 +2192,9 @@ static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size) { + struct planb *pb = (struct planb *)dev->priv; + unsigned long start = (unsigned long)adr; int i; - struct planb *pb = (struct planb *)dev; - unsigned long start = (unsigned long)adr; if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) return -EINVAL; @@ -2007,7 +2203,7 @@ if((err=grabbuf_alloc(pb))) return err; } - for (i = 0; i < pb->rawbuf_size; i++) { + for (i = 0; i < pb->rawbuf_nchunks; i++) { if (remap_page_range(vma, start, virt_to_phys((void *)pb->rawbuf[i]), PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; @@ -2019,77 +2215,223 @@ return 0; } +/********************************** + * VBI device operation functions * + **********************************/ + +static long planb_vbi_read(struct video_device *dev, char *buf, + unsigned long count, int nonblock) +{ + struct planb *pb = (struct planb *)dev->priv; + int q,todo; + DECLARE_WAITQUEUE(wait, current); + +/* Dummy for now */ + printk ("PlanB: VBI read %li bytes.\n", count); + return (0); + + todo=count; + while (todo && todo>(q=VBIBUF_SIZE-pb->vbip)) + { + if(copy_to_user((void *) buf, (void *) pb->vbibuf+pb->vbip, q)) + return -EFAULT; + todo-=q; + buf+=q; + + add_wait_queue(&pb->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; + if (todo && q==VBIBUF_SIZE-pb->vbip) { + if(nonblock) { + remove_wait_queue(&pb->vbiq, &wait); + current->state = TASK_RUNNING; + if(count==todo) + return -EWOULDBLOCK; + return count-todo; + } + schedule(); + if(signal_pending(current)) { + remove_wait_queue(&pb->vbiq, &wait); + current->state = TASK_RUNNING; + if(todo==count) + return -EINTR; + else + return count-todo; + } + } + remove_wait_queue(&pb->vbiq, &wait); + current->state = TASK_RUNNING; + } + if (todo) { + if(copy_to_user((void *) buf, (void *) pb->vbibuf+pb->vbip, + todo)) + return -EFAULT; + pb->vbip+=todo; + } + return count; +} + +static unsigned int planb_vbi_poll(struct video_device *dev, + struct file *file, poll_table *wait) +{ + struct planb *pb = (struct planb *)dev->priv; + unsigned int mask = 0; + + printk ("PlanB: VBI poll.\n"); + poll_wait(file, &pb->vbiq, wait); + + if (pb->vbip < VBIBUF_SIZE) + mask |= (POLLIN | POLLRDNORM); + + return mask; +} + +static int planb_vbi_open(struct video_device *dev, int flags) +{ + struct planb *pb = (struct planb *)dev->priv; + int err; + + /* first open on the driver? */ + if(pb->vid_user + pb->vbi_user == 0) { + if((err = planb_prepare_open(pb)) != 0) + return err; + } + /* first open on the vbi device? */ + if(pb->vbi_user == 1) { + if((err = planb_prepare_vbi(pb)) != 0) + return err; + } + ++pb->vbi_user; + + DBG("PlanB: VBI open\n"); + + MOD_INC_USE_COUNT; + return 0; +} + +static void planb_vbi_close(struct video_device *dev) +{ + struct planb *pb = (struct planb *)dev->priv; + + /* last close on vbi device? */ + if(--pb->vbi_user == 0) { + planb_close_vbi(pb); + } + /* last close on any planb device? */ + if(pb->vid_user + pb->vbi_user == 0) { + planb_prepare_close(pb); + } + + DBG("PlanB: VBI close\n"); + + MOD_DEC_USE_COUNT; + return; +} + +static int planb_vbi_ioctl(struct video_device *dev, unsigned int cmd, + void *arg) +{ + switch (cmd) { + /* This is only for alevt */ + case BTTV_VBISIZE: + DBG("PlanB: IOCTL BTTV_VBISIZE.\n"); + return VBIBUF_SIZE; + default: + DBG("PlanB: Unimplemented VBI IOCTL no. %i.\n", cmd); + return -EINVAL; + } +} + static struct video_device planb_template= { owner: THIS_MODULE, name: PLANB_DEVICE_NAME, - type: VID_TYPE_OVERLAY, + type: VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, hardware: VID_HARDWARE_PLANB, open: planb_open, close: planb_close, read: planb_read, - write: planb_write, + write: planb_write, /* not implemented */ ioctl: planb_ioctl, mmap: planb_mmap, /* mmap? */ }; -static int init_planb(struct planb *pb) +static struct video_device planb_vbi_template= +{ + owner: THIS_MODULE, + name: PLANB_VBI_NAME, + type: VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, + hardware: VID_HARDWARE_PLANB, + open: planb_vbi_open, + close: planb_vbi_close, + read: planb_vbi_read, + write: planb_write, /* not implemented */ + poll: planb_vbi_poll, + ioctl: planb_vbi_ioctl, +}; + +static int __devinit init_planb(struct planb *pb) { unsigned char saa_rev; int i, result; unsigned long flags; - memset ((void *) &pb->win, 0, sizeof (struct planb_window)); + printk(KERN_INFO "PlanB: PowerMacintosh video input driver rev. %s\n", PLANB_REV); + + pb->video_dev.minor = -1; + pb->vid_user = 0; + /* Simple sanity check */ if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) { printk(KERN_ERR "PlanB: Option(s) invalid\n"); return -2; } + memset ((void *) &pb->win, 0, sizeof (struct planb_window)); pb->win.norm = def_norm; pb->win.mode = PLANB_TV_MODE; /* TV mode */ - pb->win.interlace=1; - pb->win.x=0; - pb->win.y=0; - pb->win.width=768; /* 640 */ - pb->win.height=576; /* 480 */ - pb->maxlines=576; -#if 0 - btv->win.cropwidth=768; /* 640 */ - btv->win.cropheight=576; /* 480 */ - btv->win.cropx=0; - btv->win.cropy=0; -#endif - pb->win.pad=0; - pb->win.bpp=4; - pb->win.depth=32; - pb->win.color_fmt=PLANB_COLOUR32; - pb->win.bpl=1024*pb->win.bpp; - pb->win.swidth=1024; - pb->win.sheight=768; + pb->win.interlace = 1; + pb->win.x = 0; + pb->win.y = 0; + pb->win.width = 768; /* 640 */ + pb->win.height = 576; /* 480 */ + pb->win.pad = 0; + pb->win.bpp = 4; + pb->win.depth = 32; + pb->win.color_fmt = VIDEO_PALETTE_RGB32; + pb->win.bpl = 1024 * pb->win.bpp; + pb->win.swidth = 1024; + pb->win.sheight = 768; + pb->maxlines = 576; #ifdef PLANB_GSCANLINE if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE || (pb->gbytes_per_line <= 0)) return -3; else { /* page align pb->gbytes_per_line for DMA purpose */ - for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);) - i>>=1; + for(i = PAGE_SIZE; pb->gbytes_per_line < (i >> 1);) + i >>= 1; pb->gbytes_per_line = i; } #endif pb->tab_size = PLANB_MAXLINES + 40; pb->suspend = 0; init_MUTEX(&pb->lock); - pb->ch1_cmd = 0; - pb->ch2_cmd = 0; + pb->vid_cbo.start = 0; + pb->clip_cbo.start = 0; pb->mask = 0; - pb->priv_space = 0; - pb->offset = 0; - pb->user = 0; + pb->vid_raw = 0; pb->overlay = 0; init_waitqueue_head(&pb->suspendq); pb->cmd_buff_inited = 0; - pb->frame_buffer_phys = 0; + pb->fb.phys = 0; + pb->fb.offset = 0; + + /* VBI stuff: */ + pb->vbi_dev.minor = -1; + pb->vbi_user = 0; + pb->vbirunning = 0; + pb->vbip = 0; + pb->vbibuf = 0; + init_waitqueue_head(&pb->vbiq); /* Reset DMA controllers */ planb_dbdma_stop(&pb->planb_base->ch2); @@ -2118,9 +2460,6 @@ disable_irq(pb->irq); restore_flags(flags); - /* Now add the template and register the device unit. */ - memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); - pb->picture.brightness=0x90<<8; pb->picture.contrast = 0x70 << 8; pb->picture.colour = 0x70<<8; @@ -2128,170 +2467,131 @@ pb->picture.whiteness = 0; pb->picture.depth = pb->win.depth; - pb->frame_stat=NULL; init_waitqueue_head(&pb->capq); for(i=0; igbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE; - pb->gwidth[i]=0; - pb->gheight[i]=0; - pb->gfmt[i]=0; - pb->cap_cmd[i]=NULL; + gbuf_ptr gbuf = &pb->gbuf[i]; + + gbuf->idx = PLANB_MAX_FBUF * i / PAGE_SIZE; + gbuf->width=0; + gbuf->height=0; + gbuf->fmt=0; + gbuf->cap_cmd=NULL; #ifndef PLANB_GSCANLINE - pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF + gbuf->l_fr_addr_idx = MAX_GBUFFERS * (PLANB_MAX_FBUF / PAGE_SIZE + 1) + MAX_LNUM * i; - pb->lsize[i] = 0; - pb->lnum[i] = 0; + gbuf->lsize = 0; + gbuf->lnum = 0; #endif } pb->rawbuf=NULL; pb->grabbing=0; /* enable interrupts */ - out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); + writel(PLANB_CLR_IRQ, &pb->planb_base->intr_stat); pb->intr_mask = PLANB_FRM_IRQ; enable_irq(pb->irq); + /* Now add the templates and register the device units. */ + memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); + pb->video_dev.priv = pb; + memcpy(&pb->vbi_dev,&planb_vbi_template,sizeof(planb_vbi_template)); + if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0) return -1; + if(video_register_device(&pb->vbi_dev, VFL_TYPE_VBI, vbi_nr)<0) { + video_unregister_device(&pb->video_dev); + return -1; + } return 0; } /* - * Scan for a PlanB controller, request the irq and map the io memory + * Scan for a PlanB controller and map the io memory */ - static int find_planb(void) { struct planb *pb; - struct device_node *planb_devices; - unsigned char dev_fn, confreg, bus; - unsigned int old_base, new_base; - unsigned int irq; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; + unsigned long base; + int planb_num = 0; if (_machine != _MACH_Pmac) return 0; - planb_devices = find_devices("planb"); - if (planb_devices == 0) { - planb_num=0; + pdev = pci_find_device(APPLE_VENDOR_ID, PLANB_DEV_ID, pdev); + if (pdev == NULL) { printk(KERN_WARNING "PlanB: no device found!\n"); return planb_num; } - if (planb_devices->next != NULL) - printk(KERN_ERR "Warning: only using first PlanB device!\n"); - pb = &planbs[0]; + pb = &planbs; planb_num = 1; + base = pdev->resource[0].start; - if (planb_devices->n_addrs != 1) { - printk (KERN_WARNING "PlanB: expecting 1 address for planb " - "(got %d)", planb_devices->n_addrs); - return 0; - } - - if (planb_devices->n_intrs == 0) { - printk(KERN_WARNING "PlanB: no intrs for device %s\n", - planb_devices->full_name); - return 0; - } else { - irq = planb_devices->intrs[0].line; - } - - /* Initialize PlanB's PCI registers */ - - /* There is a bug with the way OF assigns addresses - to the devices behind the chaos bridge. - control needs only 0x1000 of space, but decodes only - the upper 16 bits. It therefore occupies a full 64K. - OF assigns the planb controller memory within this space; - so we need to change that here in order to access planb. */ - - /* We remap to 0xf1000000 in hope that nobody uses it ! */ - - bus = (planb_devices->addrs[0].space >> 16) & 0xff; - dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff; - confreg = planb_devices->addrs[0].space & 0xff; - old_base = planb_devices->addrs[0].address; - new_base = 0xf1000000; - - DEBUG("PlanB: Found on bus %d, dev %d, func %d, " - "membase 0x%x (base reg. 0x%x)\n", - bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); - - pdev = pci_find_slot (bus, dev_fn); - if (!pdev) { - printk(KERN_ERR "cannot find slot\n"); - /* XXX handle error */ - } + DBG("PlanB: Found device %s, membase 0x%lx, irq %d\n", + pdev->slot_name, base, pdev->irq); /* Enable response in memory space, bus mastering, use memory write and invalidate */ - pci_write_config_word (pdev, PCI_COMMAND, - PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | - PCI_COMMAND_INVALIDATE); - /* Set PCI Cache line size & latency timer */ - pci_write_config_byte (pdev, PCI_CACHE_LINE_SIZE, 0x8); + pci_enable_device (pdev); + pci_set_master (pdev); + pci_set_mwi(pdev); + /* value copied from MacOS... */ pci_write_config_byte (pdev, PCI_LATENCY_TIMER, 0x40); - /* Set the new base address */ - pci_write_config_dword (pdev, confreg, new_base); - planb_regs = (volatile struct planb_registers *) - ioremap (new_base, 0x400); + ioremap (base, 0x400); pb->planb_base = planb_regs; - pb->planb_base_phys = (struct planb_registers *)new_base; - pb->irq = irq; + pb->planb_base_bus = (struct planb_registers *)base; + pb->irq = pdev->irq; return planb_num; } static void release_planb(void) { - int i; struct planb *pb; - for (i=0;iplanb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); + /* stop and flush DMAs unconditionally */ + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); - /* clear and free interrupts */ - pb->intr_mask = PLANB_CLR_IRQ; - out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - free_irq(pb->irq, pb); + /* clear and free interrupts */ + pb->intr_mask = PLANB_CLR_IRQ; + writel(PLANB_CLR_IRQ, &pb->planb_base->intr_stat); + free_irq(pb->irq, pb); - /* make sure all allocated memory are freed */ - planb_prepare_close(pb); + /* make sure all allocated memory are freed */ + planb_prepare_close(pb); - printk(KERN_INFO "PlanB: unregistering with v4l\n"); - video_unregister_device(&pb->video_dev); + printk(KERN_INFO "PlanB: unregistering with v4l\n"); + video_unregister_device(&pb->video_dev); + video_unregister_device(&pb->vbi_dev); - /* note that iounmap() does nothing on the PPC right now */ - iounmap ((void *)pb->planb_base); - } + /* note that iounmap() does nothing on the PPC right now */ + iounmap ((void *)pb->planb_base); } static int __init init_planbs(void) { - int i; - - if (find_planb()<=0) + int planb_num; + + planb_num=find_planb(); + + if (planb_num < 0) return -EIO; + if (planb_num == 0) + return -ENXIO; - for (i=0; i - Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) + Based largely on the old bttv driver by Ralph Metzler - Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) + Additional debugging and coding by Takashi Oe + + For more information, see This program is free software; you can redistribute it and/or modify @@ -26,18 +28,17 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: planb.h,v 1.13 1999/05/03 19:28:56 mlan Exp $ */ +/* $Id: planb.h,v 2.9 2002/04/03 15:57:57 mlan Exp mlan $ */ #ifndef _PLANB_H_ #define _PLANB_H_ -#ifdef __KERNEL__ -#include -#include "saa7196.h" -#endif /* __KERNEL__ */ - #define PLANB_DEVICE_NAME "Apple PlanB Video-In" -#define PLANB_REV "1.0" +#define PLANB_VBI_NAME "Apple PlanB VBI" +#define PLANB_REV "2.11" + +#define APPLE_VENDOR_ID 0x106b +#define PLANB_DEV_ID 0x0004 #ifdef __KERNEL__ //#define PLANB_GSCANLINE /* use this if apps have the notion of */ @@ -47,15 +48,24 @@ #define PLANB_MAXLINES 576 #define PLANB_NTSC_MAXLINES 480 +/* Max VBI data buffer size */ +#define VBI_LINESIZE 1024 /* on SAA7196, a line can be max. 1024 pixels */ +#define VBI_START 7 /* VBI starts at line 7 */ +#define VBI_MAXLINES 16 /* 16 lines per field */ +/* We have 2 of these, but return them one at a time */ +#define VBIBUF_SIZE (VBI_LINESIZE * VBI_MAXLINES) + +#define LINE_OFFSET 1 /* between line 1 and SAA's first valid line */ + /* Uncomment your preferred norm ;-) */ #define PLANB_DEF_NORM VIDEO_MODE_PAL //#define PLANB_DEF_NORM VIDEO_MODE_NTSC //#define PLANB_DEF_NORM VIDEO_MODE_SECAM /* fields settings */ -#define PLANB_GRAY 0x1 /* 8-bit mono? */ -#define PLANB_COLOUR15 0x2 /* 16-bit mode */ -#define PLANB_COLOUR32 0x4 /* 32-bit mode */ +#define PLANB_SIZE8 0x1 /* 8-bit mono? */ +#define PLANB_SIZE16 0x2 /* 16-bit mode */ +#define PLANB_SIZE32 0x4 /* 32-bit mode */ #define PLANB_CLIPMASK 0x8 /* hardware clipmasking */ /* misc. flags for PlanB DMA operation */ @@ -67,6 +77,41 @@ #define DMA_ABORT 0x2 /* error or just out of sync if set */ #define ODD_FIELD 0x4 /* odd field is detected if set */ +/* format info and correspondance */ +struct fmts { + int bpp; /* bytes per pixel */ + int pb_fmt; /* planb format (DMA engine sub 0x40/0x44 ) */ + int saa_fmt; /* saa format: bit + SAA7196 sub 0x20: bits FS0 0 + FS1 1 + sub 0x30: bit MCT 4 + LLV 5 */ +}; + +/* This is supposed to match the VIDEO_PALETTE_* defines in + * struct video_picture in videodev.h */ +static struct fmts palette2fmt[] = { + { 0, 0, 0 }, + { 1, PLANB_SIZE8, 0x33 }, /* VIDEO_PALETTE_GREY */ + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 4, PLANB_SIZE32, 2 }, /* VIDEO_PALETTE_RGB32 */ + { 2, PLANB_SIZE16, 0 }, /* VIDEO_PALETTE_RGB555 */ + { 2, PLANB_SIZE16, 0x21 }, /* VIDEO_PALETTE_YUV422 */ + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, +}; + +#define PLANB_PALETTE_MAX (sizeof palette2fmt / sizeof (struct fmts)) + /* for capture operations */ #define MAX_GBUFFERS 2 /* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */ @@ -87,6 +132,10 @@ struct planb_stat_regs { unsigned int ch1_stat; unsigned int ch2_stat; + unsigned long ch1_cmdbase; + unsigned long ch2_cmdbase; + unsigned int ch1_cmdptr; + unsigned int ch2_cmdptr; unsigned char saa_stat0; unsigned char saa_stat1; }; @@ -97,23 +146,43 @@ unsigned char data[128]; }; +struct planb_buf_regs { + unsigned int start; + unsigned int end; +}; + /* planb private ioctls */ -#define PLANBIOCGSAAREGS _IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs) /* Read a saa7196 reg value */ -#define PLANBIOCSSAAREGS _IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs) /* Set a saa7196 reg value */ -#define PLANBIOCGSTAT _IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs) /* Read planb status */ +/* Read a saa7196 reg value */ +#define PLANBIOCGSAAREGS _IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs) +/* Set a saa7196 reg value */ +#define PLANBIOCSSAAREGS _IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs) +/* Read planb status */ +#define PLANBIOCGSTAT _IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs) +/* Get TV/VTR mode */ #define PLANB_TV_MODE 1 #define PLANB_VTR_MODE 2 -#define PLANBIOCGMODE _IOR('v', BASE_VIDIOCPRIVATE + 3, int) /* Get TV/VTR mode */ -#define PLANBIOCSMODE _IOW('v', BASE_VIDIOCPRIVATE + 4, int) /* Set TV/VTR mode */ +#define PLANBIOCGMODE _IOR('v', BASE_VIDIOCPRIVATE + 3, int) +/* Set TV/VTR mode */ +#define PLANBIOCSMODE _IOW('v', BASE_VIDIOCPRIVATE + 4, int) #ifdef PLANB_GSCANLINE -#define PLANBG_GRAB_BPL _IOR('v', BASE_VIDIOCPRIVATE + 5, int) /* # of bytes per scanline in grab buffer */ +/* # of bytes per scanline in grab buffer */ +#define PLANBG_GRAB_BPL _IOR('v', BASE_VIDIOCPRIVATE + 5, int) #endif +/* This doesn't really belong here, but until someone cleans up (or defines + in the first place ;-) the VBI API, it helps alevt... */ +#define BTTV_VBISIZE _IOR('v', BASE_VIDIOCPRIVATE + 8, int) + +/* Various debugging IOCTLs */ +#ifdef DEBUG /* call wake_up_interruptible() with appropriate actions */ #define PLANB_INTR_DEBUG _IOW('v', BASE_VIDIOCPRIVATE + 20, int) /* investigate which reg does what */ #define PLANB_INV_REGS _IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs) +/* Dump DBDMA command buffer from (int) to (int) */ +#define PLANBIOCGDBDMABUF _IOW('v', BASE_VIDIOCPRIVATE + 22, struct planb_buf_regs) +#endif /* DEBUG */ #ifdef __KERNEL__ @@ -121,27 +190,44 @@ #define PLANB_SET(x) ((x) << 16 | (x)) #define PLANB_CLR(x) ((x) << 16) -/* This represents the physical register layout */ -struct planb_registers { - volatile struct dbdma_regs ch1; /* 0x00: video in */ - volatile unsigned int even; /* 0x40: even field setting */ - volatile unsigned int odd; /* 0x44; odd field setting */ - unsigned int pad1[14]; /* empty? */ - volatile struct dbdma_regs ch2; /* 0x80: clipmask out */ - unsigned int pad2[16]; /* 0xc0: empty? */ - volatile unsigned int reg3; /* 0x100: ???? */ - volatile unsigned int intr_stat; /* 0x104: irq status */ +typedef volatile struct dbdma_cmd dbdma_cmd_t; +typedef volatile struct dbdma_cmd *dbdma_cmd_ptr; +typedef volatile struct dbdma_regs dbdma_regs_t; +typedef volatile struct dbdma_regs *dbdma_regs_ptr; + +typedef struct gbuffer gbuf_t; +typedef struct gbuffer *gbuf_ptr; + +/* grab buffer status */ +#define GBUFFER_UNUSED 0x00U +#define GBUFFER_GRABBING 0x01U +#define GBUFFER_DONE 0x02U + +/* planb interrupt status values (0x104: irq status) */ #define PLANB_CLR_IRQ 0x00 /* clear Plan B interrupt */ #define PLANB_GEN_IRQ 0x01 /* assert Plan B interrupt */ #define PLANB_FRM_IRQ 0x0100 /* end of frame */ - unsigned int pad3[1]; /* empty? */ - volatile unsigned int reg5; /* 0x10c: ??? */ - unsigned int pad4[60]; /* empty? */ - volatile unsigned char saa_addr; /* 0x200: SAA subadr */ - char pad5[3]; - volatile unsigned char saa_regval; /* SAA7196 write reg. val */ - char pad6[3]; - volatile unsigned char saa_status; /* SAA7196 status byte */ + +#define PLANB_DUMMY 40 /* # of command buf's allocated for pre-capture seq. */ + +/* This represents the physical register layout */ +struct planb_registers { + dbdma_regs_t ch1; /* 0x00: video in */ + volatile u32 even; /* 0x40: even field setting */ + volatile u32 odd; /* 0x44; odd field setting */ + u32 pad1[14]; /* empty? */ + dbdma_regs_t ch2; /* 0x80: clipmask out */ + u32 pad2[16]; /* 0xc0: empty? */ + volatile u32 reg3; /* 0x100: ???? */ + volatile u32 intr_stat; /* 0x104: irq status */ + u32 pad3[1]; /* empty? */ + volatile u32 reg5; /* 0x10c: ??? */ + u32 pad4[60]; /* empty? */ + volatile u8 saa_addr; /* 0x200: SAA subadr */ + u8 pad5[3]; + volatile u8 saa_regval; /* SAA7196 write reg. val */ + u8 pad6[3]; + volatile u8 saa_status; /* SAA7196 status byte */ /* There is more unused stuff here */ }; @@ -163,67 +249,105 @@ struct dbdma_cmd cmd; }; +/* Framebuffer info */ +struct planb_fb { + unsigned long phys; /* Framebuffer phys. base address */ + int offset; /* offset of pixel 1 */ +}; + +/* DBDMA command buffer descriptor */ +struct dbdma_cmd_buf { + dbdma_cmd_ptr start; + dbdma_cmd_ptr jumpaddr; /* where are we called from? */ + unsigned int size; + unsigned long bus; /* start address as seen from the bus */ +}; + +/* grab buffer descriptor */ +struct gbuffer { + dbdma_cmd_ptr cap_cmd; + dbdma_cmd_ptr last_cmd; + dbdma_cmd_ptr pre_cmd; + int idx; + int need_pre_capture; + int width; + int height; + unsigned int fmt; + int norm_switch; +#ifndef PLANB_GSCANLINE + int l_fr_addr_idx; + int lsize; + int lnum; +#endif + volatile unsigned int *status; /* ptr to status value */ +}; + struct planb { - struct video_device video_dev; - struct video_picture picture; /* Current picture params */ - struct video_audio audio_dev; /* Current audio params */ +/* the video device: */ + struct video_device video_dev; + struct video_picture picture; /* Current picture params */ + int vid_user; /* Users on video device */ + void *vid_raw; /* Org. alloc. mem for kfree */ + struct dbdma_cmd_buf vid_cbo; /* odd video dbdma cmd buf */ + struct dbdma_cmd_buf vid_cbe; /* even */ + void *clip_raw; + struct dbdma_cmd_buf clip_cbo; /* odd clip dbdma cmd buf */ + struct dbdma_cmd_buf clip_cbe; /* even */ + dbdma_cmd_ptr overlay_last1; + dbdma_cmd_ptr overlay_last2; - volatile struct planb_registers *planb_base; /* virt base of planb */ - struct planb_registers *planb_base_phys; /* phys base of planb */ - void *priv_space; /* Org. alloc. mem for kfree */ - int user; - unsigned int tab_size; - int maxlines; - struct semaphore lock; - unsigned int irq; /* interrupt number */ - volatile unsigned int intr_mask; - - int overlay; /* overlay running? */ - struct planb_window win; - unsigned long frame_buffer_phys; /* We need phys for DMA */ - int offset; /* offset of pixel 1 */ - volatile struct dbdma_cmd *ch1_cmd; /* Video In DMA cmd buffer */ - volatile struct dbdma_cmd *ch2_cmd; /* Clip Out DMA cmd buffer */ - volatile struct dbdma_cmd *overlay_last1; - volatile struct dbdma_cmd *overlay_last2; - unsigned long ch1_cmd_phys; - volatile unsigned char *mask; /* Clipmask buffer */ - int suspend; - wait_queue_head_t suspendq; - struct planb_suspend suspended; - int cmd_buff_inited; /* cmd buffer inited? */ - - int grabbing; - unsigned int gcount; - wait_queue_head_t capq; - int last_fr; - int prev_last_fr; - unsigned char **rawbuf; - int rawbuf_size; - int gbuf_idx[MAX_GBUFFERS]; - volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS]; - volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS]; - volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS]; - int need_pre_capture[MAX_GBUFFERS]; -#define PLANB_DUMMY 40 /* # of command buf's allocated for pre-capture seq. */ - int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS]; - unsigned int gfmt[MAX_GBUFFERS]; - int gnorm_switch[MAX_GBUFFERS]; - volatile unsigned int *frame_stat; -#define GBUFFER_UNUSED 0x00U -#define GBUFFER_GRABBING 0x01U -#define GBUFFER_DONE 0x02U +/* the hardware: */ + volatile struct planb_registers + *planb_base; /* virt base of planb */ + struct planb_registers *planb_base_bus; /* phys base of planb */ + unsigned int tab_size; + int maxlines; + unsigned int irq; /* interrupt number */ + volatile unsigned int intr_mask; + struct planb_fb fb; /* Framebuffer info */ + +/* generic stuff: */ + void *jump_raw; /* jump buffer raw space */ + dbdma_cmd_ptr jumpbuf; /* same, DBDMA_ALIGN'ed */ + struct semaphore lock; + int overlay; /* overlay running? */ + struct planb_window win; + volatile unsigned char *mask; /* Clipmask buffer */ + int suspend; + wait_queue_head_t suspendq; + struct planb_suspend suspended; + int cmd_buff_inited; /* cmd buffer inited? */ + +/* grabbing stuff: */ + int grabbing; + unsigned int gcount; + wait_queue_head_t capq; + int last_fr; + int prev_last_fr; + unsigned char **rawbuf; + int rawbuf_nchunks; + struct gbuffer gbuf[MAX_GBUFFERS]; + #ifdef PLANB_GSCANLINE - int gbytes_per_line; + int gbytes_per_line; #else -#define MAX_LNUM 431 /* change this if PLANB_MAXLINES or */ +#define MAX_LNUM 576 /* change this if PLANB_MAXLINES or */ /* PLANB_MAXPIXELS changes */ - int l_fr_addr_idx[MAX_GBUFFERS]; - unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; - int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM]; - int l_to_next_size[MAX_GBUFFERS][MAX_LNUM]; - int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS]; -#endif + unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; + int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM]; + int l_to_next_size[MAX_GBUFFERS][MAX_LNUM]; +#endif /* PLANB_GSCANLINE */ + +/* VBI stuff: */ + struct video_device vbi_dev; /* VBI data device */ + int vbi_user; /* Users on vbi device */ + void *vbi_raw; + struct dbdma_cmd_buf vbi_cbo; /* odd VBI dbdma cmd buf */ + struct dbdma_cmd_buf vbi_cbe; /* even */ + int vbirunning; + int vbip; /* pointer into VBI buffer */ + unsigned char *vbibuf; /* buffer for VBI data */ + wait_queue_head_t vbiq; }; #endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/media/video/saa7110.c linux-2.5/drivers/media/video/saa7110.c --- linux-2.5.23/drivers/media/video/saa7110.c Wed Jun 19 03:11:44 2002 +++ linux-2.5/drivers/media/video/saa7110.c Wed Jun 19 20:50:06 2002 @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "linux/video_decoder.h" @@ -37,10 +37,28 @@ #define I2C_SAA7110 0x9C /* or 0x9E */ +#define IF_NAME "saa7110" #define I2C_DELAY 10 /* 10 us or 100khz */ +static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +static struct i2c_client client_template; + struct saa7110 { - struct i2c_bus *bus; + struct i2c_client *client; int addr; unsigned char reg[36]; @@ -114,7 +132,7 @@ /* SAA7110 functions */ /* ----------------------------------------------------------------------- */ static -int saa7110_selmux(struct i2c_device *device, int chan) +int saa7110_selmux(struct i2c_client *client, int chan) { static const unsigned char modes[9][8] = { /* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, @@ -126,7 +144,7 @@ /* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, /* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, /* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } }; - struct saa7110* decoder = device->data; + struct saa7110* decoder = client->data; const unsigned char* ptr = modes[chan]; saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */ @@ -142,9 +160,9 @@ } static -int determine_norm(struct i2c_device* dev) +int determine_norm(struct i2c_client* client) { - struct saa7110* decoder = dev->data; + struct saa7110* decoder = client->data; int status; /* mode changed, start automatic detection */ @@ -152,18 +170,18 @@ if ((status & 3) == 0) { saa7110_write(decoder,0x06,0x80); if (status & 0x20) { - DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name)); + DEBUG(printk(KERN_INFO "%s: norm=bw60\n",adp->name)); saa7110_write(decoder,0x2E,0x81); return VIDEO_MODE_NTSC; } - DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name)); + DEBUG(printk(KERN_INFO "%s: norm=bw50\n",adp->name)); saa7110_write(decoder,0x2E,0x9A); return VIDEO_MODE_PAL; } saa7110_write(decoder,0x06,0x00); if (status & 0x20) { /* 60Hz */ - DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name)); + DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",adp->name)); saa7110_write(decoder,0x0D,0x06); saa7110_write(decoder,0x11,0x2C); saa7110_write(decoder,0x2E,0x81); @@ -188,7 +206,7 @@ } static -int saa7110_attach(struct i2c_device *device) +int saa7110_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) { static const unsigned char initseq[] = { 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, @@ -198,20 +216,27 @@ 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, 0x40, 0x75, 0x01, 0x8C, 0x03}; - struct saa7110* decoder; + struct saa7110 *decoder; + struct i2c_client *client; int rv; - - device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); - if (device->data == 0) + client=kmalloc(sizeof(*client), GPF_KERNEL); + if(client == NULL) return -ENOMEM; - - MOD_INC_USE_COUNT; + client_template.adapter = adap; + client_template.addr = addr; + memcpy(client, &client_template, sizeof(*client)); + + decoder = kmalloc(sizeof(*decoder), GFP_KERNEL); + if (decoder == NULL) { + kfree(client); + return -ENOMEM; + } /* clear our private data */ - memset(decoder, 0, sizeof(struct saa7110)); - strcpy(device->name, "saa7110"); - decoder->bus = device->bus; - decoder->addr = device->addr; + memset(decoder, 0, sizeof(*decoder)); + strcpy(client->name, IF_NAME); + decoder->client = client; + decoder->addr = addr; decoder->norm = VIDEO_MODE_PAL; decoder->input = 0; decoder->enable = 1; @@ -230,28 +255,39 @@ saa7110_write(decoder,0x0D,0x06); } + i2c_attach_client(client); + MOD_INC_USE_COUNT; /* setup and implicit mode 0 select has been performed */ return 0; } +static +int saa_7110_probe(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, saa7110_attach); +} + static -int saa7110_detach(struct i2c_device *device) +int saa7110_detach(struct i2c_client *client) { - struct saa7110* decoder = device->data; + struct saa7110* decoder = client->data; - DEBUG(printk(KERN_INFO "%s_detach\n",device->name)); + i2c_detach_client(client); + + DEBUG(printk(KERN_INFO "%s_detach\n",client->name)); /* stop further output */ saa7110_write(decoder,0x0E,0x00); - kfree(device->data); + kfree(decoder); + kfree(client); MOD_DEC_USE_COUNT; return 0; } static -int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg) +int saa7110_command(struct i2c_client *device, unsigned int cmd, void *arg) { struct saa7110* decoder = device->data; int v; @@ -402,24 +438,30 @@ static struct i2c_driver i2c_driver_saa7110 = { - "saa7110", /* name */ - + IF_NAME, /* name */ I2C_DRIVERID_VIDEODECODER, /* in i2c.h */ - I2C_SAA7110, I2C_SAA7110+1, /* Addr range */ - - saa7110_attach, + I2C_DF_NOTIFY, /* Addr range */ + saa7110_probe, saa7110_detach, saa7110_command }; +static struct i2c_client client_template = { + "saa7110_client", + -1, + 0, + 0, + NULL, + &i2c_driver_saa7110 +}; static int saa7110_init(void) { - return i2c_register_driver(&i2c_driver_saa7110); + return i2c_add_driver(&i2c_driver_saa7110); } static void saa7110_exit(void) { - i2c_unregister_driver(&i2c_driver_saa7110); + i2c_del_driver(&i2c_driver_saa7110); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/media/video/saa7196.h linux-2.5/drivers/media/video/saa7196.h --- linux-2.5.23/drivers/media/video/saa7196.h Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/media/video/saa7196.h Fri Jun 7 02:36:08 2002 @@ -3,19 +3,17 @@ scaler, and clock generator circuit (DESCpro), as used in the PlanB video input of the Powermac 7x00/8x00 series. - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) + Copyright (C) 1998 - 2002 Michel Lanners The register defines are shamelessly copied from the meteor - driver out of NetBSD (with permission), + driver out of FreeBSD (with permission), and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe (Thanks !) - Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) - The default values used for PlanB are my mistakes. */ -/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */ +/* $Id: saa7196.h,v 2.3 2002/04/03 15:57:57 mlan Exp mlan $ */ #ifndef _SAA7196_H_ #define _SAA7196_H_ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/media/video/stradis.c linux-2.5/drivers/media/video/stradis.c --- linux-2.5.23/drivers/media/video/stradis.c Wed Jun 19 03:11:52 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.23/drivers/media/video/vino.c linux-2.5/drivers/media/video/vino.c --- linux-2.5.23/drivers/media/video/vino.c Wed Jun 19 03:11:51 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.23/drivers/media/video/w9966.c linux-2.5/drivers/media/video/w9966.c --- linux-2.5.23/drivers/media/video/w9966.c Wed Jun 19 03:11:50 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.23/drivers/media/video/zr36067.c linux-2.5/drivers/media/video/zr36067.c --- linux-2.5.23/drivers/media/video/zr36067.c Wed Jun 19 03:11:59 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.23/drivers/message/i2o/README linux-2.5/drivers/message/i2o/README --- linux-2.5.23/drivers/message/i2o/README Wed Jun 19 03:11:53 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.23/drivers/message/i2o/i2o_block.c linux-2.5/drivers/message/i2o/i2o_block.c --- linux-2.5.23/drivers/message/i2o/i2o_block.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/message/i2o/i2o_block.c Mon Jun 17 22:52:28 2002 @@ -285,6 +285,7 @@ if(req->cmd == READ) { + DEBUG("READ\n"); __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); while(bio) { @@ -324,6 +325,7 @@ } else if(req->cmd == WRITE) { + DEBUG("WRITE\n"); __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); while(bio) { @@ -419,6 +421,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) @@ -442,7 +445,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; } @@ -465,6 +468,7 @@ */ if(m[0] & (1<<13)) { + DEBUG("FAIL"); /* * FAILed message from controller * We increment the error count and abort it @@ -504,7 +508,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); @@ -803,7 +807,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; @@ -1401,19 +1405,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; } @@ -1457,34 +1458,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.23/drivers/message/i2o/i2o_config.c linux-2.5/drivers/message/i2o/i2o_config.c --- linux-2.5.23/drivers/message/i2o/i2o_config.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/message/i2o/i2o_config.c Sat May 25 19:52:02 2002 @@ -25,7 +25,10 @@ * 2 of the License, or (at your option) any later version. */ +#include // Nuke me with the ifdef. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include #include @@ -47,7 +50,7 @@ static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; -#define MODINC(x,y) (x = x++ % y) +#define MODINC(x,y) ((x) = ((x) + 1) % (y)) struct i2o_cfg_info { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/message/i2o/i2o_core.c linux-2.5/drivers/message/i2o/i2o_core.c --- linux-2.5.23/drivers/message/i2o/i2o_core.c Wed Jun 19 03:11:56 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.23/drivers/message/i2o/i2o_lan.c linux-2.5/drivers/message/i2o/i2o_lan.c --- linux-2.5.23/drivers/message/i2o/i2o_lan.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/message/i2o/i2o_lan.c Sat May 25 19:52:02 2002 @@ -25,9 +25,12 @@ * TODO: tests for other LAN classes (Token Ring, Fibre Channel) */ +#include + +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif -#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/message/i2o/i2o_scsi.c linux-2.5/drivers/message/i2o/i2o_scsi.c --- linux-2.5.23/drivers/message/i2o/i2o_scsi.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/message/i2o/i2o_scsi.c Sat May 25 19:52:02 2002 @@ -31,7 +31,10 @@ * Fix the resource management problems. */ +#include // nuke me later. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include #include @@ -191,7 +194,7 @@ { /* Create a scsi error for this */ current_command = (Scsi_Cmnd *)m[3]; - lock = ¤t_command->host->host_lock; + lock = current_command->host->host_lock; printk("Aborted %ld\n", current_command->serial_number); spin_lock_irq(lock); @@ -286,22 +289,17 @@ * It worked maybe ? */ current_command->result = DID_OK << 16 | ds; - lock = ¤t_command->host->host_lock; + lock = current_command->host->host_lock; spin_lock(lock); current_command->scsi_done(current_command); spin_unlock(lock); return; } -struct i2o_handler i2o_scsi_handler= -{ - i2o_scsi_reply, - NULL, - NULL, - NULL, - "I2O SCSI OSM", - 0, - I2O_CLASS_SCSI_PERIPHERAL +struct i2o_handler i2o_scsi_handler = { + reply: i2o_scsi_reply, + name: "I2O SCSI OSM", + class: I2O_CLASS_SCSI_PERIPHERAL, }; static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/mtd/Config.in linux-2.5/drivers/mtd/Config.in --- linux-2.5.23/drivers/mtd/Config.in Wed Jun 19 03:11:48 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.23/drivers/mtd/Makefile linux-2.5/drivers/mtd/Makefile --- linux-2.5.23/drivers/mtd/Makefile Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/mtd/Makefile Mon Jun 17 21:59:51 2002 @@ -1,13 +1,11 @@ # # Makefile for the memory technology device drivers. # -# # $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $ -export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o - -obj-y += chips/ maps/ devices/ nand/ +export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o mtdconcat.o +obj-y += chips/ maps/ devices/ nand/ # *** BIG UGLY NOTE *** # # The shiny new inter_module_xxx has introduced yet another ugly link @@ -26,6 +24,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.23/drivers/mtd/afs.c linux-2.5/drivers/mtd/afs.c --- linux-2.5.23/drivers/mtd/afs.c Wed Jun 19 03:11:58 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.23/drivers/mtd/chips/Makefile linux-2.5/drivers/mtd/chips/Makefile --- linux-2.5.23/drivers/mtd/chips/Makefile Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/mtd/chips/Makefile Fri May 31 02:42:58 2002 @@ -1,7 +1,7 @@ # # linux/drivers/chips/Makefile # -# $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $ +# $Id: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $ export-objs := chipreg.o gen_probe.o @@ -18,7 +18,6 @@ obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o -obj-$(CONFIG_MTD_INTELPROBE) += intel_probe.o obj-$(CONFIG_MTD_JEDEC) += jedec.o obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o obj-$(CONFIG_MTD_RAM) += map_ram.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/mtd/chips/amd_flash.c linux-2.5/drivers/mtd/chips/amd_flash.c --- linux-2.5.23/drivers/mtd/chips/amd_flash.c Wed Jun 19 03:11:50 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.23/drivers/mtd/chips/jedec.c linux-2.5/drivers/mtd/chips/jedec.c --- linux-2.5.23/drivers/mtd/chips/jedec.c Wed Jun 19 03:11:56 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.23/drivers/mtd/devices/blkmtd.c linux-2.5/drivers/mtd/devices/blkmtd.c --- linux-2.5.23/drivers/mtd/devices/blkmtd.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/mtd/devices/blkmtd.c Tue Jun 4 15:51:31 2002 @@ -305,7 +305,6 @@ DEBUG(1, "blkmtd: writetask: starting (pid = %d)\n", tsk->pid); daemonize(); strcpy(tsk->comm, "blkmtdd"); - tsk->tty = NULL; spin_lock_irq(&tsk->sigmask_lock); sigfillset(&tsk->blocked); recalc_sigpending(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/mtd/devices/doc1000.c linux-2.5/drivers/mtd/devices/doc1000.c --- linux-2.5.23/drivers/mtd/devices/doc1000.c Wed Jun 19 03:11:48 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.23/drivers/mtd/devices/mtdram.c linux-2.5/drivers/mtd/devices/mtdram.c --- linux-2.5.23/drivers/mtd/devices/mtdram.c Wed Jun 19 03:11:46 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.23/drivers/mtd/ftl.c linux-2.5/drivers/mtd/ftl.c --- linux-2.5.23/drivers/mtd/ftl.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/mtd/ftl.c Mon Jun 17 22:52:28 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 @@ -855,11 +855,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; } @@ -880,9 +885,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); @@ -895,6 +897,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.23/drivers/mtd/maps/Config.in linux-2.5/drivers/mtd/maps/Config.in --- linux-2.5.23/drivers/mtd/maps/Config.in Wed Jun 19 03:11:55 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.23/drivers/mtd/maps/Makefile linux-2.5/drivers/mtd/maps/Makefile --- linux-2.5.23/drivers/mtd/maps/Makefile Wed Jun 19 03:11:44 2002 +++ linux-2.5/drivers/mtd/maps/Makefile Fri May 31 02:43:14 2002 @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $ +# $Id: Makefile,v 1.21 2002/02/22 09:34:44 gleixner Exp $ # Chip mappings obj-$(CONFIG_MTD_CDB89712) += cdb89712.o @@ -9,9 +9,15 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o +obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o +obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_L440GX) += l440gx.o +obj-$(CONFIG_MTD_AMD766ROM) += amd766rom.o +obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o +obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o +obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_NORA) += nora.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o @@ -27,5 +33,9 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o +obj-$(CONFIG_MTD_PCI) += pci.o +obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o +obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o +obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/mtd/maps/amd766rom.c linux-2.5/drivers/mtd/maps/amd766rom.c --- linux-2.5.23/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.23/drivers/mtd/maps/autcpu12-nvram.c linux-2.5/drivers/mtd/maps/autcpu12-nvram.c --- linux-2.5.23/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.23/drivers/mtd/maps/dc21285.c linux-2.5/drivers/mtd/maps/dc21285.c --- linux-2.5.23/drivers/mtd/maps/dc21285.c Wed Jun 19 03:11:53 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.23/drivers/mtd/maps/dilnetpc.c linux-2.5/drivers/mtd/maps/dilnetpc.c --- linux-2.5.23/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.23/drivers/mtd/maps/epxa10db-flash.c linux-2.5/drivers/mtd/maps/epxa10db-flash.c --- linux-2.5.23/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.23/drivers/mtd/maps/ich2rom.c linux-2.5/drivers/mtd/maps/ich2rom.c --- linux-2.5.23/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.23/drivers/mtd/maps/integrator-flash.c linux-2.5/drivers/mtd/maps/integrator-flash.c --- linux-2.5.23/drivers/mtd/maps/integrator-flash.c Wed Jun 19 03:11:57 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.23/drivers/mtd/maps/iq80310.c linux-2.5/drivers/mtd/maps/iq80310.c --- linux-2.5.23/drivers/mtd/maps/iq80310.c Wed Jun 19 03:11:52 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.23/drivers/mtd/maps/l440gx.c linux-2.5/drivers/mtd/maps/l440gx.c --- linux-2.5.23/drivers/mtd/maps/l440gx.c Wed Jun 19 03:11:51 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.23/drivers/mtd/maps/mbx860.c linux-2.5/drivers/mtd/maps/mbx860.c --- linux-2.5.23/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.23/drivers/mtd/maps/pb1xxx-flash.c linux-2.5/drivers/mtd/maps/pb1xxx-flash.c --- linux-2.5.23/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.23/drivers/mtd/maps/pci.c linux-2.5/drivers/mtd/maps/pci.c --- linux-2.5.23/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.23/drivers/mtd/maps/sa1100-flash.c linux-2.5/drivers/mtd/maps/sa1100-flash.c --- linux-2.5.23/drivers/mtd/maps/sa1100-flash.c Wed Jun 19 03:11:50 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.23/drivers/mtd/maps/sc520cdp.c linux-2.5/drivers/mtd/maps/sc520cdp.c --- linux-2.5.23/drivers/mtd/maps/sc520cdp.c Wed Jun 19 03:11:58 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.23/drivers/mtd/maps/solutionengine.c linux-2.5/drivers/mtd/maps/solutionengine.c --- linux-2.5.23/drivers/mtd/maps/solutionengine.c Wed Jun 19 03:11:58 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.23/drivers/mtd/maps/tsunami_flash.c linux-2.5/drivers/mtd/maps/tsunami_flash.c --- linux-2.5.23/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.23/drivers/mtd/mtdblock.c linux-2.5/drivers/mtd/mtdblock.c --- linux-2.5.23/drivers/mtd/mtdblock.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/mtd/mtdblock.c Mon Jun 17 22:52:28 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 */ @@ -48,6 +48,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... * @@ -274,11 +282,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; } @@ -301,6 +312,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)); @@ -316,6 +328,7 @@ if (!mtdblk->cache_data) { put_mtd_device(mtdblk->mtd); kfree(mtdblk); + BLK_DEC_USE_COUNT; return -ENOMEM; } } @@ -379,6 +392,7 @@ DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + BLK_DEC_USE_COUNT; release_return(0); } @@ -520,8 +534,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) @@ -554,7 +571,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.23/drivers/mtd/mtdblock_ro.c linux-2.5/drivers/mtd/mtdblock_ro.c --- linux-2.5.23/drivers/mtd/mtdblock_ro.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/mtd/mtdblock_ro.c Mon Jun 17 22:52:28 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); } @@ -216,9 +224,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; @@ -246,7 +257,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.23/drivers/mtd/mtdconcat.c linux-2.5/drivers/mtd/mtdconcat.c --- linux-2.5.23/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.23/drivers/mtd/mtdcore.c linux-2.5/drivers/mtd/mtdcore.c --- linux-2.5.23/drivers/mtd/mtdcore.c Wed Jun 19 03:11:54 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.23/drivers/mtd/mtdpart.c linux-2.5/drivers/mtd/mtdpart.c --- linux-2.5.23/drivers/mtd/mtdpart.c Wed Jun 19 03:11:49 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.23/drivers/mtd/nand/nand_ecc.c linux-2.5/drivers/mtd/nand/nand_ecc.c --- linux-2.5.23/drivers/mtd/nand/nand_ecc.c Wed Jun 19 03:11:51 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.23/drivers/mtd/nftlcore.c linux-2.5/drivers/mtd/nftlcore.c --- linux-2.5.23/drivers/mtd/nftlcore.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/mtd/nftlcore.c Mon Jun 17 22:52:28 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) @@ -956,8 +964,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; } @@ -970,11 +981,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); @@ -992,7 +1002,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 @@ -1019,7 +1031,7 @@ { #ifdef PRERELEASE - printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.82 $, nftlmount.c %s\n", nftlmountrev); + printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.85 $, nftlmount.c %s\n", nftlmountrev); #endif if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/3c509.c linux-2.5/drivers/net/3c509.c --- linux-2.5.23/drivers/net/3c509.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/net/3c509.c Sat May 11 21:34:27 2002 @@ -47,8 +47,8 @@ - ethtool support v1.18b 1Mar2002 Zwane Mwaikambo - Power Management support - v1.18c 1Mar2002 David Ruggiero - - Full duplex support + v1.18c 1Mar2002 David Ruggiero + - Full duplex support */ #define DRV_NAME "3c509" @@ -142,9 +142,9 @@ #define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ #define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ -#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ -#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ -#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ +#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ +#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ +#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ /* * Must be a power of two (we use a binary and in the @@ -504,10 +504,10 @@ memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; dev->irq = irq; - + if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */ dev->if_port = (dev->mem_start & 0x0f); - } else { /* xcvr codes 0/8 */ + } else { /* xcvr codes 0/8 */ /* use eeprom value, but save user's full-duplex selection */ dev->if_port = (if_port | (dev->mem_start & 0x08) ); } @@ -1110,10 +1110,10 @@ if ((dev->if_port & 0x03) == 3) /* BNC interface */ /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); + outw(StartCoax, ioaddr + EL3_CMD); else if ((dev->if_port & 0x03) == 0) { /* 10baseT interface */ /* Combine secondary sw_info word (the adapter level) and primary - sw_info word (duplex setting plus other useless bits) */ + sw_info word (duplex setting plus other useless bits) */ EL3WINDOW(0); sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) | (read_eeprom(ioaddr, 0x0d) & 0xBff0); @@ -1148,7 +1148,7 @@ /* Enable link beat and jabber check. */ outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); } - + /* Switch to the stats window, and clear all stats by reading. */ outw(StatsDisable, ioaddr + EL3_CMD); EL3WINDOW(6); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/3c59x.c linux-2.5/drivers/net/3c59x.c --- linux-2.5.23/drivers/net/3c59x.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/net/3c59x.c Fri Jun 7 02:36:08 2002 @@ -166,15 +166,7 @@ - Rename wait_for_completion() to issue_and_wait() to avoid completion.h clash. - LK1.1.17 18Dec01 akpm - - PCI ID 9805 is a Python-T, not a dual-port Cyclone. Apparently. - And it has NWAY. - - Mask our advertised modes (vp->advertising) with our capabilities - (MII reg5) when deciding which duplex mode to use. - - Add `global_options' as default for options[]. Ditto global_enable_wol, - global_full_duplex. - - - See http://www.zip.com.au/~akpm/linux/#3c59x-2.3 for more details. + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. - Also see Documentation/networking/vortex.txt */ @@ -189,8 +181,8 @@ #define DRV_NAME "3c59x" -#define DRV_VERSION "LK1.1.17" -#define DRV_RELDATE "18 Dec 2001" +#define DRV_VERSION "LK1.1.16" +#define DRV_RELDATE "19 July 2001" @@ -278,13 +270,10 @@ MODULE_LICENSE("GPL"); MODULE_PARM(debug, "i"); -MODULE_PARM(global_options, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(global_full_duplex, "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(hw_checksums, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(global_enable_wol, "i"); MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); @@ -294,13 +283,10 @@ MODULE_PARM(watchdog, "i"); MODULE_PARM_DESC(debug, "3c59x debug level (0-6)"); MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex"); -MODULE_PARM_DESC(global_options, "3c59x: same as options, but applies to all NICs if options is unset"); MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)"); -MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if options is unset"); MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)"); MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)"); MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)"); -MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if options is unset"); MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt"); MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)"); @@ -487,7 +473,7 @@ {"3c900 Boomerang 10Mbps Combo", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c900 Cyclone 10Mbps Combo", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, @@ -510,8 +496,8 @@ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c980 Cyclone", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c980C Python-T", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, + {"3c982 Dual Port Server Cyclone", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3cSOHO100-TX Hurricane", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, @@ -867,9 +853,6 @@ static int hw_checksums[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int global_options = -1; -static int global_full_duplex = -1; -static int global_enable_wol = -1; /* #define dev_alloc_skb dev_alloc_skb_debug */ @@ -1012,8 +995,6 @@ SET_MODULE_OWNER(dev); vp = dev->priv; - option = global_options; - /* The lower four bits are the media type. */ if (dev->mem_start) { /* @@ -1022,10 +1003,10 @@ */ option = dev->mem_start; } - else if (card_idx < MAX_UNITS) { - if (options[card_idx] >= 0) - option = options[card_idx]; - } + else if (card_idx < MAX_UNITS) + option = options[card_idx]; + else + option = -1; if (option > 0) { if (option & 0x8000) @@ -1118,11 +1099,6 @@ vp->bus_master = (option & 16) ? 1 : 0; } - if (global_full_duplex > 0) - vp->full_duplex = 1; - if (global_enable_wol > 0) - vp->enable_wol = 1; - if (card_idx < MAX_UNITS) { if (full_duplex[card_idx] > 0) vp->full_duplex = 1; @@ -1268,12 +1244,11 @@ } else dev->if_port = vp->default_media; - if ((vp->available_media & 0x4b) || (vci->drv_flags & HAS_NWAY) || - dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { + if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int phy, phy_idx = 0; EL3WINDOW(4); mii_preamble_required++; - mdio_sync(ioaddr, 32); + mii_preamble_required++; mdio_read(dev, 24, 1); for (phy = 0; phy < 32 && phy_idx < 1; phy++) { int mii_status, phyx; @@ -1289,8 +1264,6 @@ else phyx = phy; mii_status = mdio_read(dev, phyx, 1); - printk("phy=%d, phyx=%d, mii_status=0x%04x\n", - phy, phyx, mii_status); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; if (print_info) { @@ -1471,14 +1444,11 @@ /* Read BMSR (reg1) only to clear old status. */ mii_reg1 = mdio_read(dev, vp->phys[0], 1); mii_reg5 = mdio_read(dev, vp->phys[0], 5); - if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) { + if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) ; /* No MII device or no link partner report */ - } else { - mii_reg5 &= vp->advertising; - if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ + else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ vp->full_duplex = 1; - } vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); if (vortex_debug > 1) printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," @@ -1699,10 +1669,8 @@ if (mii_status & 0x0004) { int mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (! vp->force_fd && mii_reg5 != 0xffff) { - int duplex; - - mii_reg5 &= vp->advertising; - duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + int duplex = (mii_reg5&0x0100) || + (mii_reg5 & 0x01C0) == 0x0040; if (vp->full_duplex != duplex) { vp->full_duplex = duplex; printk(KERN_INFO "%s: Setting %s-duplex based on MII " @@ -1785,11 +1753,9 @@ dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); EL3WINDOW(4); - printk(KERN_ERR " diagnostics: net %04x media %04x dma %08x fifo %04x\n", - inw(ioaddr + Wn4_NetDiag), - inw(ioaddr + Wn4_Media), - inl(ioaddr + PktStatus), - inw(ioaddr + Wn4_FIFODiag)); + printk(KERN_ERR " diagnostics: net %04x media %04x dma %8.8x.\n", + inw(ioaddr + Wn4_NetDiag), inw(ioaddr + Wn4_Media), + inl(ioaddr + PktStatus)); /* Slight code bloat to be user friendly. */ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" @@ -2572,6 +2538,7 @@ ((vp->drv_flags & HAS_HWCKSM) == 0) && (hw_checksums[vp->card_idx] == -1)) { printk(KERN_WARNING "%s supports hardware checksums, and we're not using them!\n", dev->name); + printk(KERN_WARNING "Please see http://www.uow.edu.au/~andrewm/zerocopy.html\n"); } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/8139too.c linux-2.5/drivers/net/8139too.c --- linux-2.5.23/drivers/net/8139too.c Wed Jun 19 03:11:44 2002 +++ linux-2.5/drivers/net/8139too.c Tue Jun 4 15:51:31 2002 @@ -1556,8 +1556,7 @@ struct rtl8139_private *tp = dev->priv; unsigned long timeout; - daemonize (); - reparent_to_init(); + daemonize(); spin_lock_irq(¤t->sigmask_lock); sigemptyset(¤t->blocked); recalc_sigpending(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/82596.c linux-2.5/drivers/net/82596.c --- linux-2.5.23/drivers/net/82596.c Wed Jun 19 03:11:49 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.23/drivers/net/8390.h linux-2.5/drivers/net/8390.h --- linux-2.5.23/drivers/net/8390.h Wed Jun 19 03:11:57 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.23/drivers/net/Config.help linux-2.5/drivers/net/Config.help --- linux-2.5.23/drivers/net/Config.help Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/net/Config.help Mon Jun 3 17:10:22 2002 @@ -880,6 +880,10 @@ If you have an Alchemy Semi AU1000 ethernet controller on an SGI MIPS system, say Y. Otherwise, say N. +CONFIG_MIPS_AU1000_ENET + If you have an Alchemy Semi AU1000 ethernet controller + on an SGI MIPS system, say Y. Otherwise, say N. + CONFIG_SGI_IOC3_ETH If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1441,6 +1445,11 @@ Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet cards. Specifications and data at . + +CONFIG_LP486E + Say Y here to support the 82596-based on-board Ethernet controller + for the Panther motherboard, which is one of the two shipped in the + Intel Professional Workstation. CONFIG_LP486E Say Y here to support the 82596-based on-board Ethernet controller diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/Config.in linux-2.5/drivers/net/Config.in --- linux-2.5.23/drivers/net/Config.in Wed Jun 19 03:11:47 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.23/drivers/net/Space.c linux-2.5/drivers/net/Space.c --- linux-2.5.23/drivers/net/Space.c Wed Jun 19 03:11:47 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.23/drivers/net/a2065.c linux-2.5/drivers/net/a2065.c --- linux-2.5.23/drivers/net/a2065.c Wed Jun 19 03:11:56 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.23/drivers/net/acenic.c linux-2.5/drivers/net/acenic.c --- linux-2.5.23/drivers/net/acenic.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/net/acenic.c Fri May 17 01:33:49 2002 @@ -120,6 +120,10 @@ #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX #define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a #endif +#ifndef PCI_DEVICE_ID_FARALLON_PN9100T +#define PCI_DEVICE_ID_FARALLON_PN9100T 0xfa +#endif + #ifndef PCI_VENDOR_ID_SGI #define PCI_VENDOR_ID_SGI 0x10a9 #endif @@ -144,6 +148,9 @@ */ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_FARALLON_PN9100T, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { } @@ -173,12 +180,12 @@ #endif #ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) {do{} while(0);} +#define SET_MODULE_OWNER(dev) do { } while(0) #define ACE_MOD_INC_USE_COUNT MOD_INC_USE_COUNT #define ACE_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT #else -#define ACE_MOD_INC_USE_COUNT {do{} while(0);} -#define ACE_MOD_DEC_USE_COUNT {do{} while(0);} +#define ACE_MOD_INC_USE_COUNT do { } while(0) +#define ACE_MOD_DEC_USE_COUNT do { } while(0) #endif @@ -259,7 +266,7 @@ #define dev_kfree_skb_irq(a) dev_kfree_skb(a) #define netif_wake_queue(dev) clear_bit(0, &dev->tbusy) #define netif_stop_queue(dev) set_bit(0, &dev->tbusy) -#define late_stop_netif_stop_queue(dev) {do{} while(0);} +#define late_stop_netif_stop_queue(dev) do { } while(0) #define early_stop_netif_stop_queue(dev) test_and_set_bit(0,&dev->tbusy) #define early_stop_netif_wake_queue(dev) netif_wake_queue(dev) @@ -273,7 +280,7 @@ #define ace_mark_net_bh() mark_bh(NET_BH) #define netif_queue_stopped(dev) dev->tbusy #define netif_running(dev) dev->start -#define ace_if_down(dev) {do{dev->start = 0;} while(0);} +#define ace_if_down(dev) do { dev->start = 0; } while(0) #define tasklet_struct tq_struct static inline void tasklet_schedule(struct tasklet_struct *tasklet) @@ -291,13 +298,13 @@ tasklet->routine = (void (*)(void *))func; tasklet->data = (void *)data; } -#define tasklet_kill(tasklet) {do{} while(0);} +#define tasklet_kill(tasklet) do { } while(0) #else #define late_stop_netif_stop_queue(dev) netif_stop_queue(dev) #define early_stop_netif_stop_queue(dev) 0 -#define early_stop_netif_wake_queue(dev) {do{} while(0);} -#define ace_mark_net_bh() {do{} while(0);} -#define ace_if_down(dev) {do{} while(0);} +#define early_stop_netif_wake_queue(dev) do { } while(0) +#define ace_mark_net_bh() do { } while(0) +#define ace_if_down(dev) do { } while(0) #endif #if (LINUX_VERSION_CODE >= 0x02031b) @@ -313,7 +320,7 @@ #ifndef ARCH_HAS_PREFETCHW #ifndef prefetchw -#define prefetchw(x) {do{} while(0);} +#define prefetchw(x) do { } while(0) #endif #endif @@ -611,6 +618,8 @@ */ !((pdev->vendor == PCI_VENDOR_ID_DEC) && (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) && + !((pdev->vendor == PCI_VENDOR_ID_ALTEON) && + (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T)) && !((pdev->vendor == PCI_VENDOR_ID_SGI) && (pdev->device == PCI_DEVICE_ID_SGI_ACENIC))) continue; @@ -708,6 +717,13 @@ switch(pdev->vendor) { case PCI_VENDOR_ID_ALTEON: + if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { + strncpy(ap->name, "Farallon PN9100-T " + "Gigabit Ethernet", sizeof (ap->name)); + printk(KERN_INFO "%s: Farallon PN9100-T ", + dev->name); + break; + } strncpy(ap->name, "AceNIC Gigabit Ethernet", sizeof (ap->name)); printk(KERN_INFO "%s: Alteon AceNIC ", dev->name); @@ -1355,7 +1371,7 @@ tmp &= ~DMA_READ_WRITE_MASK; tmp |= DMA_READ_MAX_128; /* - * All the docs sy MUST NOT. Well, I did. + * All the docs say MUST NOT. Well, I did. * Nothing terrible happens, if we load wrong size. * Bit w&i still works better! */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/appletalk/ltpc.c linux-2.5/drivers/net/appletalk/ltpc.c --- linux-2.5.23/drivers/net/appletalk/ltpc.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/net/appletalk/ltpc.c Fri May 17 02:05:47 2002 @@ -1063,26 +1063,39 @@ int autoirq; unsigned long flags; unsigned long f; + int portfound=0; SET_MODULE_OWNER(dev); save_flags(flags); /* probe for the I/O port address */ - if (io != 0x240 && !check_region(0x220,8)) { + if (io != 0x240 && request_region(0x220,8,"ltpc")) { x = inb_p(0x220+6); - if ( (x!=0xff) && (x>=0xf0) ) io = 0x220; + if ( (x!=0xff) && (x>=0xf0) ) { + io = 0x220; + portfound=1; + } + else { + release_region(0x220,8); + } } - if (io != 0x220 && !check_region(0x240,8)) { + if (io != 0x220 && request_region(0x240,8,"ltpc")) { y = inb_p(0x240+6); - if ( (y!=0xff) && (y>=0xf0) ) io = 0x240; + if ( (y!=0xff) && (y>=0xf0) ){ + io = 0x240; + portfound=1; + } + else { + release_region(0x240,8); + } } - if(io) { - /* found it, now grab it */ - request_region(io,8,"ltpc"); - } else { + if(io && !portfound && request_region(io,8,"ltpc")){ + portfound = 1; + } + if(!portfound) { /* give up in despair */ printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/bmac.c linux-2.5/drivers/net/bmac.c --- linux-2.5.23/drivers/net/bmac.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/net/bmac.c Sat May 25 19:52:03 2002 @@ -25,11 +25,11 @@ #include #include #include +#include #ifdef CONFIG_PMAC_PBOOK #include #include -#include -#endif +#endif /* CONFIG_PMAC_PBOOK */ #include "bmac.h" #define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1)))) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/de600.c linux-2.5/drivers/net/de600.c --- linux-2.5.23/drivers/net/de600.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/net/de600.c Mon May 6 16:10:01 2002 @@ -683,14 +683,10 @@ return -ENODEV; } -#if 0 /* Not yet */ - if (check_region(DE600_IO, 3)) { - printk(", port 0x%x busy\n", DE600_IO); + if (!request_region(DE600_IO, 3, "de600")) { + printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); return -EBUSY; } -#endif - request_region(DE600_IO, 3, "de600"); - printk(", Ethernet Address: %02X", dev->dev_addr[0]); for (i = 1; i < ETH_ALEN; i++) printk(":%02X",dev->dev_addr[i]); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/defxx.c linux-2.5/drivers/net/defxx.c --- linux-2.5.23/drivers/net/defxx.c Wed Jun 19 03:11:44 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.23/drivers/net/depca.c linux-2.5/drivers/net/depca.c --- linux-2.5.23/drivers/net/depca.c Wed Jun 19 03:11:55 2002 +++ linux-2.5/drivers/net/depca.c Wed May 8 13:58:47 2002 @@ -339,16 +339,6 @@ #define MAX_NUM_DEPCAS 2 /* -** Memory Alignment. Each descriptor is 4 longwords long. To force a -** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and -** DESC_ALIGN. ALIGN aligns the start address of the private memory area -** and hence the RX descriptor ring's first entry. -*/ -#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */ -#define ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */ -#define ALIGN ALIGN8 /* Keep the LANCE happy... */ - -/* ** The DEPCA Rx and Tx ring descriptors. */ struct depca_rx_desc { @@ -641,7 +631,7 @@ offset += sizeof(struct depca_init); /* Tx & Rx descriptors (aligned to a quadword boundary) */ - offset = (offset + ALIGN) & ~ALIGN; + offset = ALIGN(offset, 8); lp->rx_ring = (struct depca_rx_desc *)(lp->sh_mem + offset); lp->rx_ring_offset = offset; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/fc/iph5526.c linux-2.5/drivers/net/fc/iph5526.c --- linux-2.5.23/drivers/net/fc/iph5526.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/net/fc/iph5526.c Fri Jun 7 02:36:08 2002 @@ -2984,8 +2984,7 @@ */ if ((type == ETH_P_ARP) || (status == 0)) dev_kfree_skb(skb); - else - netif_wake_queue(dev); + netif_wake_queue(dev); LEAVE("iph5526_send_packet"); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/hamradio/dmascc.c linux-2.5/drivers/net/hamradio/dmascc.c --- linux-2.5.23/drivers/net/hamradio/dmascc.c Wed Jun 19 03:11:53 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.23/drivers/net/hamradio/mkiss.c linux-2.5/drivers/net/hamradio/mkiss.c --- linux-2.5.23/drivers/net/hamradio/mkiss.c Wed Jun 19 03:11:53 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.23/drivers/net/hamradio/mkiss.h linux-2.5/drivers/net/hamradio/mkiss.h --- linux-2.5.23/drivers/net/hamradio/mkiss.h Wed Jun 19 03:11:48 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.23/drivers/net/irda/Config.help linux-2.5/drivers/net/irda/Config.help --- linux-2.5.23/drivers/net/irda/Config.help Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/net/irda/Config.help Mon Jun 17 22:52:29 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.23/drivers/net/irda/Makefile linux-2.5/drivers/net/irda/Makefile --- linux-2.5.23/drivers/net/irda/Makefile Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/net/irda/Makefile Mon Jun 17 22:02:38 2002 @@ -25,7 +25,7 @@ obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o obj-$(CONFIG_EP7211_IR) += ep7211_ir.o obj-$(CONFIG_MCP2120_DONGLE) += mcp2120.o -obj-$(CONFIG_ACT200L_DONGLE) += act200l.o -obj-$(CONFIG_MA600_DONGLE) += ma600.o +obj-$(CONFIG_ACT200L_DONGLE) += act200l.o +obj-$(CONFIG_MA600_DONGLE) += ma600.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/irda/ali-ircc.c linux-2.5/drivers/net/irda/ali-ircc.c --- linux-2.5.23/drivers/net/irda/ali-ircc.c Wed Jun 19 03:11:53 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.23/drivers/net/macmace.c linux-2.5/drivers/net/macmace.c --- linux-2.5.23/drivers/net/macmace.c Wed Jun 19 03:11:52 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.23/drivers/net/macsonic.c linux-2.5/drivers/net/macsonic.c --- linux-2.5.23/drivers/net/macsonic.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/net/macsonic.c Sat May 25 19:52:04 2002 @@ -20,6 +20,9 @@ * and duplicating packets. Needs more testing. * * 99/01/03 MSch: upgraded to version 0.92 of the core driver, fixed. + * + * 00/10/31 sammy@sammy.net: Updated driver for 2.4 kernels, fixed problems + * on centris. */ #include @@ -46,6 +49,7 @@ #include #include #include +#include #include @@ -125,36 +129,42 @@ int __init macsonic_init(struct net_device* dev) { - struct sonic_local* lp = (struct sonic_local *)dev->priv; + struct sonic_local* lp; int i; /* Allocate the entire chunk of memory for the descriptors. Note that this cannot cross a 64K boundary. */ for (i = 0; i < 20; i++) { unsigned long desc_base, desc_top; - if ((lp->sonic_desc = - kmalloc(SIZEOF_SONIC_DESC - * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_KERNEL | GFP_DMA)) == NULL) { + if((lp = kmalloc(sizeof(struct sonic_local), GFP_KERNEL | GFP_DMA)) == NULL) { printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name); return -ENOMEM; } - desc_base = (unsigned long) lp->sonic_desc; - desc_top = desc_base + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode); + + desc_base = (unsigned long) lp; + desc_top = desc_base + sizeof(struct sonic_local); if ((desc_top & 0xffff) >= (desc_base & 0xffff)) break; /* Hmm. try again (FIXME: does this actually work?) */ - kfree(lp->sonic_desc); + kfree(lp); printk(KERN_DEBUG "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n", dev->name, desc_base, desc_top); } - if (lp->sonic_desc == NULL) { + if (lp == NULL) { printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n", dev->name); return -ENOMEM; } + dev->priv = lp; + +#if 0 + /* this code is only here as a curiousity... mainly, where the + fuck did SONIC_BUS_SCALE come from, and what was it supposed + to do? the normal allocation works great for 32 bit stuffs.. */ + /* Now set up the pointers to point to the appropriate places */ lp->cda = lp->sonic_desc; lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); @@ -163,6 +173,15 @@ lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); +#endif + + memset(lp, 0, sizeof(struct sonic_local)); + + lp->cda_laddr = (unsigned int)&(lp->cda); + lp->tda_laddr = (unsigned int)lp->tda; + lp->rra_laddr = (unsigned int)lp->rra; + lp->rda_laddr = (unsigned int)lp->rda; + /* FIXME, maybe we should use skbs */ if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) { @@ -172,15 +191,17 @@ return -ENOMEM; } + lp->rba_laddr = (unsigned int)lp->rba; + { int rs, ds; /* almost always 12*4096, but let's not take chances */ rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096; /* almost always under a page, but let's not take chances */ - ds = ((SIZEOF_SONIC_DESC + 4095) / 4096) * 4096; + ds = ((sizeof(struct sonic_local) + 4095) / 4096) * 4096; kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER); - kernel_set_cachemode(lp->sonic_desc, ds, IOMAP_NOCACHE_SER); + kernel_set_cachemode(lp, ds, IOMAP_NOCACHE_SER); } #if 0 @@ -277,6 +298,7 @@ static int once_is_more_than_enough; struct sonic_local* lp; int i; + int dma_bitmode; if (once_is_more_than_enough) return -ENODEV; @@ -316,7 +338,7 @@ printk("yes\n"); - if (dev) { + if (dev) dev = init_etherdev(dev, sizeof(struct sonic_local)); if (!dev) return -ENOMEM; @@ -328,13 +350,17 @@ } } else { dev = init_etherdev(NULL, sizeof(struct sonic_local)); - } if (dev == NULL) return -ENOMEM; - lp = (struct sonic_local*) dev->priv; - memset(lp, 0, sizeof(struct sonic_local)); + if(dev->priv) { + printk("%s: warning! sonic entering with priv already allocated!\n", + dev->name); + printk("%s: discarding, will attempt to reallocate\n", dev->name); + dev->priv = NULL; + } + /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ @@ -356,8 +382,11 @@ /* The PowerBook's SONIC is 16 bit always. */ if (macintosh_config->ident == MAC_MODEL_PB520) { - lp->reg_offset = 0; - lp->dma_bitmode = 0; + reg_offset = 0; + dma_bitmode = 0; + } else if (macintosh_config->ident == MAC_MODEL_C610) { + reg_offset = 0; + dma_bitmode = 1; } else { /* Some of the comm-slot cards are 16 bit. But some of them are not. The 32-bit cards use offset 2 and @@ -368,27 +397,41 @@ /* Technically this is not necessary since we zeroed it above */ - lp->reg_offset = 0; - lp->dma_bitmode = 0; + reg_offset = 0; + dma_bitmode = 0; sr = sonic_read(dev, SONIC_SR); if (sr == 0 || sr == 0xffff) { - lp->reg_offset = 2; + reg_offset = 2; /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */ sr = sonic_read(dev, SONIC_SR); - lp->dma_bitmode = 1; + dma_bitmode = 1; } printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", - dev->name, sr, lp->dma_bitmode?32:16, lp->reg_offset); + dev->name, sr, dma_bitmode?32:16, reg_offset); } + - + /* this carries my sincere apologies -- by the time I got to updating + the driver, support for "reg_offsets" appeares nowhere in the sonic + code, going back for over a year. Fortunately, my Mac does't seem + to use whatever this was. + + If you know how this is supposed to be implemented, either fix it, + or contact me (sammy@sammy.net) to explain what it is. --Sam */ + + if(reg_offset) { + printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name); + return -ENODEV; + } + /* Software reset, then initialize control registers. */ sonic_write(dev, SONIC_CMD, SONIC_CR_RST); sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | - (lp->dma_bitmode ? SONIC_DCR_DW : 0)); + (dma_bitmode ? SONIC_DCR_DW : 0)); + /* This *must* be written back to in order to restore the extended programmable output bits */ sonic_write(dev, SONIC_DCR2, 0); @@ -452,7 +495,7 @@ u16 sonic_dcr; int id; int i; - int reg_offset, dma_bitmode; + int dma_bitmode; /* Find the first SONIC that hasn't been initialized already */ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, @@ -538,8 +581,6 @@ memset(lp, 0, sizeof(struct sonic_local)); /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ - lp->reg_offset = reg_offset; - lp->dma_bitmode = dma_bitmode; dev->base_addr = base_addr; dev->irq = SLOT2IRQ(ndev->board->slot); @@ -552,6 +593,11 @@ printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset); + if(reg_offset) { + printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name); + return -ENODEV; + } + /* Software reset, then initialize control registers. */ sonic_write(dev, SONIC_CMD, SONIC_CR_RST); sonic_write(dev, SONIC_DCR, sonic_dcr @@ -614,6 +660,9 @@ #define vdma_free(baz) #define sonic_chiptomem(bat) (bat) #define PHYSADDR(quux) (quux) + +#define sonic_request_irq request_irq +#define sonic_free_irq free_irq #include "sonic.c" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/natsemi.c linux-2.5/drivers/net/natsemi.c --- linux-2.5.23/drivers/net/natsemi.c Wed Jun 19 03:11:46 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.23/drivers/net/pcmcia/Config.help linux-2.5/drivers/net/pcmcia/Config.help --- linux-2.5.23/drivers/net/pcmcia/Config.help Wed Jun 19 03:11:58 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.23/drivers/net/pcmcia/Config.in linux-2.5/drivers/net/pcmcia/Config.in --- linux-2.5.23/drivers/net/pcmcia/Config.in Wed Jun 19 03:11:56 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.23/drivers/net/pcmcia/axnet_cs.c linux-2.5/drivers/net/pcmcia/axnet_cs.c --- linux-2.5.23/drivers/net/pcmcia/axnet_cs.c Wed Jun 19 03:11:56 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.23/drivers/net/pcmcia/i82593.h linux-2.5/drivers/net/pcmcia/i82593.h --- linux-2.5.23/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.23/drivers/net/pcmcia/nmclan_cs.c linux-2.5/drivers/net/pcmcia/nmclan_cs.c --- linux-2.5.23/drivers/net/pcmcia/nmclan_cs.c Wed Jun 19 03:11:47 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.23/drivers/net/rclanmtl.c linux-2.5/drivers/net/rclanmtl.c --- linux-2.5.23/drivers/net/rclanmtl.c Wed Jun 19 03:11:56 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.23/drivers/net/rclanmtl.h linux-2.5/drivers/net/rclanmtl.h --- linux-2.5.23/drivers/net/rclanmtl.h Wed Jun 19 03:11:55 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.23/drivers/net/rcpci45.c linux-2.5/drivers/net/rcpci45.c --- linux-2.5.23/drivers/net/rcpci45.c Wed Jun 19 03:11:50 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.23/drivers/net/rrunner.c linux-2.5/drivers/net/rrunner.c --- linux-2.5.23/drivers/net/rrunner.c Wed Jun 19 03:11:50 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.23/drivers/net/skfp/h/fplustm.h linux-2.5/drivers/net/skfp/h/fplustm.h --- linux-2.5.23/drivers/net/skfp/h/fplustm.h Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/net/skfp/h/fplustm.h Fri Jun 7 02:36:08 2002 @@ -50,38 +50,82 @@ u_long err_tkerr ; /* token error */ } ; +#define SK_XD_ALIGN (size_t) 32 + /* * Transmit Descriptor struct */ +struct s_dummy_txd { + u_int txd_tbctrl ; /* transmit buffer control */ + u_int txd_txdscr ; /* transmit frame status word */ + u_int txd_tbadr ; /* physical tx buffer address */ + u_int txd_ntdadr ; /* physical pointer to the next TxD */ +#ifdef ENA_64BIT_SUP + u_int txd_tbadr_hi ; /* physical tx buffer addr(high dword)*/ +#endif + caddr_t txd_virt ; /* virtual pointer to the data frag */ + /* virt pointer to the next TxD */ + struct s_smt_fp_txd volatile far *txd_next ; + struct s_txd_os txd_os ; /* OS - specific struct */ + /* No padding here! */ +} ; + +#define SK_DUMMY_TXD sizeof(struct s_dummy_txd) +#define SK_TXD_PAD (((SK_DUMMY_TXD+SK_XD_ALIGN-1) \ + & ~(SK_XD_ALIGN-1))-SK_DUMMY_TXD) struct s_smt_fp_txd { u_int txd_tbctrl ; /* transmit buffer control */ u_int txd_txdscr ; /* transmit frame status word */ u_int txd_tbadr ; /* physical tx buffer address */ u_int txd_ntdadr ; /* physical pointer to the next TxD */ #ifdef ENA_64BIT_SUP - u_int txd_tbadr_hi ; /* physical tx buffer addr (high dword)*/ + u_int txd_tbadr_hi ; /* physical tx buffer addr(high dword)*/ #endif - char far *txd_virt ; /* virtual pointer to the data frag */ + caddr_t txd_virt ; /* virtual pointer to the data frag */ /* virt pointer to the next TxD */ struct s_smt_fp_txd volatile far *txd_next ; struct s_txd_os txd_os ; /* OS - specific struct */ + char padding[SK_TXD_PAD]; /* padding */ } ; + + /* * Receive Descriptor struct */ + +struct s_dummy_rxd { + u_int rxd_rbctrl ; /* receive buffer control */ + u_int rxd_rfsw ; /* receive frame status word */ + u_int rxd_rbadr ; /* physical rx buffer address */ + u_int rxd_nrdadr ; /* physical pointer to the next RxD */ +#ifdef ENA_64BIT_SUP + u_int rxd_rbadr_hi ; /* physical tx buffer addr(high dword)*/ +#endif + caddr_t rxd_virt ; /* virtual pointer to the data frag */ + /* virt pointer to the next RxD */ + struct s_smt_fp_rxd volatile far *rxd_next ; + struct s_rxd_os rxd_os ; /* OS - specific struct */ + /* No padding here! */ +} ; + +#define SK_DUMMY_RXD sizeof(struct s_dummy_rxd) +#define SK_RXD_PAD (((SK_DUMMY_RXD+SK_XD_ALIGN-1) \ + & ~(SK_XD_ALIGN-1))-SK_DUMMY_RXD) + struct s_smt_fp_rxd { u_int rxd_rbctrl ; /* receive buffer control */ u_int rxd_rfsw ; /* receive frame status word */ u_int rxd_rbadr ; /* physical rx buffer address */ u_int rxd_nrdadr ; /* physical pointer to the next RxD */ #ifdef ENA_64BIT_SUP - u_int rxd_rbadr_hi ; /* physical tx buffer addr (high dword)*/ + u_int rxd_rbadr_hi ; /* physical tx buffer addr(high dword)*/ #endif - char far *rxd_virt ; /* virtual pointer to the data frag */ + caddr_t rxd_virt ; /* virtual pointer to the data frag */ /* virt pointer to the next RxD */ struct s_smt_fp_rxd volatile far *rxd_next ; struct s_rxd_os rxd_os ; /* OS - specific struct */ + char padding[SK_RXD_PAD] ; } ; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/skfp/skfddi.c linux-2.5/drivers/net/skfp/skfddi.c --- linux-2.5.23/drivers/net/skfp/skfddi.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/net/skfp/skfddi.c Fri Jun 7 02:36:08 2002 @@ -56,6 +56,7 @@ * 12-Nov-99 CG Source code release * 22-Nov-99 CG Included in kernel source. * 07-May-00 DM 64 bit fixes, new dma interface + * 06-May-02 ML Structure fixes * * Compilation options (-Dxxx): * DRIVERDEBUG print lots of messages to log file @@ -68,7 +69,7 @@ /* Version information string - should be updated prior to */ /* each new release!!! */ -#define VERSION "2.06" +#define VERSION "2.07" static const char *boot_msg = "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" @@ -188,6 +189,7 @@ }; MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mirko Lindner "); // Define module-wide (static) variables diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/sonic.h linux-2.5/drivers/net/sonic.h --- linux-2.5.23/drivers/net/sonic.h Wed Jun 19 03:11:45 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.23/drivers/net/sun3_82586.c linux-2.5/drivers/net/sun3_82586.c --- linux-2.5.23/drivers/net/sun3_82586.c Wed Jun 19 03:11:55 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.23/drivers/net/sungem.c linux-2.5/drivers/net/sungem.c --- linux-2.5.23/drivers/net/sungem.c Wed Jun 19 03:11:58 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.23/drivers/net/tc35815.c linux-2.5/drivers/net/tc35815.c --- linux-2.5.23/drivers/net/tc35815.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/net/tc35815.c Fri May 17 01:42:48 2002 @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/tlan.c linux-2.5/drivers/net/tlan.c --- linux-2.5.23/drivers/net/tlan.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/drivers/net/tlan.c Sat May 25 19:52:04 2002 @@ -166,7 +166,10 @@ * Thanks to Gunnar Eikman *******************************************************************************/ +#include // nuke me later +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/tokenring/madgemc.c linux-2.5/drivers/net/tokenring/madgemc.c --- linux-2.5.23/drivers/net/tokenring/madgemc.c Wed Jun 19 03:11:58 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.23/drivers/net/tokenring/tmspci.c linux-2.5/drivers/net/tokenring/tmspci.c --- linux-2.5.23/drivers/net/tokenring/tmspci.c Wed Jun 19 03:11:58 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.23/drivers/net/tulip/ChangeLog linux-2.5/drivers/net/tulip/ChangeLog --- linux-2.5.23/drivers/net/tulip/ChangeLog Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/net/tulip/ChangeLog Sun May 19 16:39:09 2002 @@ -15,17 +15,22 @@ PCI transaction. Fix bugs in tulip MWI config also. +2002-02-07 Uwe Bonnes + + * tulip_core (tulip_pci_tbl[]): + Add PCI id for comet tulip clone. + 2002-01-28 Stefan Rompf , Jeff Garzik - * 21142.c (t21142_timer): Use return value of - tulip_check_duplex() to indicate to system whether or not - carrier is present. Use carrier presence/absence to determine - when next the 21142 media timer should check for link beat. - - * timer (tulip_timer): Un-comment-out calls to - netif_carrier_{on,off}, as there is now value in - reporting link beta information to userspace. + * 21142.c (t21142_timer): Use return value of + tulip_check_duplex() to indicate to system whether or not + carrier is present. Use carrier presence/absence to determine + when next the 21142 media timer should check for link beat. + + * timer (tulip_timer): Un-comment-out calls to + netif_carrier_{on,off}, as there is now value in + reporting link beta information to userspace. 2002-01-28 Pavel Roskin @@ -39,8 +44,22 @@ 2002-02-07 Uwe Bonnes - * tulip_core (tulip_pci_tbl[]): - Add PCI id for comet tulip clone. + * tulip_core (tulip_pci_tbl[]): + Add PCI id for comet tulip clone. + +2001-12-19 John Zielinski + + * tulip_core.c (tulip_up, tulip_init_one): + More places to revert PHY autoconfiguration bit removal. + +2001-12-18 Jeff Garzik + + * tulip.h: revert PHY autoconfiguration bit removal + +2001-12-16 Andrew Lambeth + + * tulip_core.c (tulip_start_xmit): Use the more-portable + spin_lock_irqsave. 2001-12-11 Jeff Garzik diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/tulip/tulip.h linux-2.5/drivers/net/tulip/tulip.h --- linux-2.5.23/drivers/net/tulip/tulip.h Wed Jun 19 03:11:53 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.23/drivers/net/tulip/tulip_core.c linux-2.5/drivers/net/tulip/tulip_core.c --- linux-2.5.23/drivers/net/tulip/tulip_core.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/net/tulip/tulip_core.c Sun May 19 16:39:09 2002 @@ -2,7 +2,7 @@ /* Maintained by Jeff Garzik - Copyright 2000,2001 The Linux Kernel Team + Copyright 2000-2002 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms @@ -94,6 +94,8 @@ static int csr0 = 0x01A00000 | 0x9000; #elif defined(__arm__) || defined(__sh__) static int csr0 = 0x01A00000 | 0x4800; +#elif defined(__mips__) +static int csr0 = 0x00200000 | 0x4000; #else #warning Processor architecture undefined! static int csr0 = 0x00A00000 | 0x4800; @@ -649,8 +651,9 @@ int entry; u32 flag; dma_addr_t mapping; + unsigned long eflags; - spin_lock_irq(&tp->lock); + spin_lock_irqsave(&tp->lock, eflags); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % TX_RING_SIZE; @@ -685,7 +688,7 @@ /* Trigger an immediate transmit demand. */ outl(0, dev->base_addr + CSR1); - spin_unlock_irq(&tp->lock); + spin_unlock_irqrestore(&tp->lock, eflags); dev->trans_start = jiffies; @@ -1487,6 +1490,16 @@ tp->flags &= ~HAS_MEDIA_TABLE; } #endif +#ifdef CONFIG_MIPS_COBALT + if ((pdev->bus->number == 0) && + ((PCI_SLOT(pdev->devfn) == 7) || + (PCI_SLOT(pdev->devfn) == 12))) { + /* Cobalt MAC address in first EEPROM locations. */ + sa_offset = 0; + /* No media table either */ + tp->flags &= ~HAS_MEDIA_TABLE; + } +#endif for (i = 0; i < 6; i ++) { dev->dev_addr[i] = ee_data[i + sa_offset]; sum += ee_data[i + sa_offset]; @@ -1524,7 +1537,7 @@ #endif #if defined(__i386__) /* Patch up x86 BIOS bug. */ if (last_irq) - irq = last_irq; + dev->irq = last_irq; #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/tulip/winbond-840.c linux-2.5/drivers/net/tulip/winbond-840.c --- linux-2.5.23/drivers/net/tulip/winbond-840.c Wed Jun 19 03:11:49 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.23/drivers/net/via-rhine.c linux-2.5/drivers/net/via-rhine.c --- linux-2.5.23/drivers/net/via-rhine.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/net/via-rhine.c Sun May 19 16:39:10 2002 @@ -359,9 +359,9 @@ { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL }, { "VIA VT6105M Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL }, }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = @@ -369,7 +369,7 @@ {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, - {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, + {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, {0,} /* terminate list */ }; MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); @@ -390,7 +390,7 @@ /* Bits in ConfigD (select backoff algorithm (Ethernet capture effect)) */ enum backoff_bits { - BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08 + BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08 }; #ifdef USE_MEM @@ -980,6 +980,8 @@ writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers. */ + + writew(0x0006, ioaddr + PCIBusConfig); /* Store & forward */ /* Configure initial FIFO thresholds. */ writeb(0x20, ioaddr + TxConfig); @@ -1041,7 +1043,7 @@ if (phy_id == np->phys[0]) { switch (regnum) { - case MII_BMCR: /* Is user forcing speed/duplex? */ + case MII_BMCR: /* Is user forcing speed/duplex? */ if (value & 0x9000) /* Autonegotiation. */ np->mii_if.duplex_lock = 0; else diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/wan/8253x/8253x.h linux-2.5/drivers/net/wan/8253x/8253x.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xchr.c linux-2.5/drivers/net/wan/8253x/8253xchr.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xctl.h linux-2.5/drivers/net/wan/8253x/8253xctl.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xdbg.c linux-2.5/drivers/net/wan/8253x/8253xdbg.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xini.c linux-2.5/drivers/net/wan/8253x/8253xini.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xint.c linux-2.5/drivers/net/wan/8253x/8253xint.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xioc.h linux-2.5/drivers/net/wan/8253x/8253xioc.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xmcs.c linux-2.5/drivers/net/wan/8253x/8253xmcs.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xmcs.h linux-2.5/drivers/net/wan/8253x/8253xmcs.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xnet.c linux-2.5/drivers/net/wan/8253x/8253xnet.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xplx.c linux-2.5/drivers/net/wan/8253x/8253xplx.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xsyn.c linux-2.5/drivers/net/wan/8253x/8253xsyn.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xtty.c linux-2.5/drivers/net/wan/8253x/8253xtty.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/8253xutl.c linux-2.5/drivers/net/wan/8253x/8253xutl.c --- linux-2.5.23/drivers/net/wan/8253x/8253xutl.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xutl.c Fri Jun 7 02:36:08 2002 @@ -0,0 +1,1422 @@ +/* -*- 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; + schedule_timeout(char_time); + if (signal_pending(current)) + { + break; + } + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + { + break; + } + } +} + +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.23/drivers/net/wan/8253x/Makefile linux-2.5/drivers/net/wan/8253x/Makefile --- linux-2.5.23/drivers/net/wan/8253x/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/Makefile Sun May 19 17:27:50 2002 @@ -0,0 +1,28 @@ +# Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version +# 2 of the License, or (at your option) any later version. + +# File: drivers/net/WAN/atiXX50/Makefile +# +# Makefile for the Aurora ESSC based cards +# Specifically the 2520, 4020, 4520, 8520 +# + +all: ASLX.o + +O_TARGET := ASLX.o + +obj-y := 8253xini.o 8253xnet.o 8253xsyn.o crc32.o 8253xdbg.o 8253xplx.o 8253xtty.o 8253xchr.o 8253xint.o amcc5920.o 8253xmcs.o 8253xutl.o +obj-m := ASLX.o + +#EXTRA_CFLAGS += -I. -DFREEININTERRUPT +EXTRA_CFLAGS += -I. + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s *~ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/wan/8253x/PciRegs.h linux-2.5/drivers/net/wan/8253x/PciRegs.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/Reg9050.h linux-2.5/drivers/net/wan/8253x/Reg9050.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/amcc5920.c linux-2.5/drivers/net/wan/8253x/amcc5920.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/crc32.c linux-2.5/drivers/net/wan/8253x/crc32.c --- linux-2.5.23/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.23/drivers/net/wan/8253x/crc32.h linux-2.5/drivers/net/wan/8253x/crc32.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/crc32dcl.h linux-2.5/drivers/net/wan/8253x/crc32dcl.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/endian.h linux-2.5/drivers/net/wan/8253x/endian.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/readme.txt linux-2.5/drivers/net/wan/8253x/readme.txt --- linux-2.5.23/drivers/net/wan/8253x/readme.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/readme.txt Sun May 19 17:38:06 2002 @@ -0,0 +1,185 @@ +10 February 2002 + +1) This release reformats the files according to kernel linux-c +conventions. If you do not have kernel linux-c mode configured +for your version of emacs, add the following to your .emacs file. + +(defun linux-c-mode () + "C mode with adjusted defaults for use with the Linux kernel." + (interactive) + (c-mode) + (c-set-style "K&R") + (setq c-basic-offset 8)) + +Then you will be able to manually invoke linux-c-mode as a Meta-X +command. + +The line + +/* -*- linux-c -*- */ + +that is now found at the top of each C source file automatically puts +the buffer into linux-c-mode when emacs opens the file for editing. + +2) The following network ioctl have been removed + +#define SAB8253XSETMAC (SIOCDEVPRIVATE + 5 + 2) +#define SAB8253XGETMAC (SIOCDEVPRIVATE + 5 + 3) + +along with the PSEUDOMAC structure and references to this structure. + +The following standard ioctls provide the same functionality. + +#define SIOCSIFHWADDR 0x8924 /* set hardware address */ +#define SIOCGIFHWADDR 0x8927 /* Get hardware address */ + +The 8253xmac tool has been removed. To start the ASLX sab8253x +network interface, you should use a command like the following with +the substitutions appropriate to your environment. + +ifconfig 8253x006 hw ether 000000030405 test1 + +You should substitute for 8253x006 the network interface that you are +using. For 000000030405 you should substitute the MAC address that +you desire to use. For test1 you should substitute the host name or +host IP address that you wish to use for this interface. + +3) As many functions and non-local variables as possible have been +declared static in order to prevent name space polution. + +4) Support has been added for programmatic selection of signaling +interface for the Aurora WAN multiserver 3500 series extension boards. + +Ports associated with this cards can be programmed via the + +#define ATIS_IOCSSIGMODE _IOW(ATIS_MAGIC_IOC,6,unsigned int) + +ioctl to have either RS232, RS422, RS449, RS530, V.35 or no (=off) +physical layer signaling. + +The program 8253xmode.c has been added to demonstrate the use +of this set ioctl as well as the associated get ioctl. + +#define ATIS_IOCGSIGMODE _IOW(ATIS_MAGIC_IOC,7,unsigned int) + +The program is invoked as follows. + +8253xmode /dev/ttyS* mode + +where mode is 232, 442, 449, 530, v.35 or off. + +The proc file has been modified to show information associated with +the signaling state. + +martillo@ylith:~ > cat /proc/tty/driver/auraserial +serinfo:2.01N driver:1.22 +TTY MAJOR = 4, CUA MAJOR = 5, STTY MAJOR = 254. +128: port 0: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +129: port 1: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: openA: NOPRG +130: port 2: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: openA: NOPRG +131: port 3: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +132: port 4: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +133: port 5: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: openS: NOPRG +134: port 6: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +135: port 7: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +136: port 0: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +137: port 1: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +138: port 2: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +139: port 3: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +140: port 4: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +141: port 5: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +142: port 6: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +143: port 7: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +144: port 0: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +145: port 1: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +146: port 2: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +147: port 3: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +148: port 4: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS530 +149: port 5: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +150: port 6: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +151: port 7: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +152: port 0: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +153: port 1: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +154: port 2: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +155: port 3: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +156: port 4: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +157: port 5: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +158: port 6: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +159: port 7: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +160: port 0: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +161: port 1: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +162: port 2: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +163: port 3: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +164: port 4: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +165: port 5: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +166: port 6: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +167: port 7: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +168: port 0: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +169: port 1: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +170: port 2: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +171: port 3: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +172: port 4: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +173: port 5: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +174: port 6: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +175: port 7: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +176: port 0: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +177: port 1: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +178: port 2: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +179: port 3: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +180: port 4: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +181: port 5: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +182: port 6: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +183: port 7: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +184: port 0: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +185: port 1: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +186: port 2: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +187: port 3: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +188: port 4: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +189: port 5: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +190: port 6: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +191: port 7: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +192: port 0: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +193: port 1: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +194: port 2: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +195: port 3: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +196: port 4: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +197: port 5: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +198: port 6: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +199: port 7: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: openA: RS232 + +The above file indicates the minor device number, port number relative +to chip, chip type, chip version number, chip number (meaningful for +4X20 and multichannel servers), interface type, bus number, slot +number, port availability (AO = asynchronous only, NR = No +Restrictions, or NA = Not Available), status (closed, open +Synchronous, open Asynchronous, open Character, or open Network), and +signaling type (NOPRG = not selectable programmatically; other +possibilities inclue OFF, RS232, RS442, RS449, RS530 and V.35). + +Note that by default ports come up in RS232 mode. + +The following module parameter has been added. + +MODULE_PARM(sab8253x_default_sp502_mode, "i"); + +The asynchronous TTY functionality can immediately be used without +extra configuration. [Note that immediate use of the WMS3500 products +is possible because the default value of sab8253x_default_sp502_mode +is SP502_RS232_MODE (== 1). If a different default mode is needed, it +can be set as options in the /etc/modules.conf file. OFF = 0. +RS232 = 1, RS422 = 2, RS485 = 3, RS449 = 4, EIA530 = 5 and V.35 = 6, as +defined in 8253xioc.h.] + +5) I added a readme.txt an an overview of the driver sab8253xov.txt +and the functional and design specifications (sab8253xfs.txt and +sab8253xds.txt) to the patch. The functional and design +specifications were blindly exported to text from the html versions. + +The documents are more nicely formated at + +http://www.telfordtools.com/sab8253x/sab8253xfs.html + +and + +http://www.telfordtools.com/sab8253x/sab8253xds.html + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/wan/8253x/ring.h linux-2.5/drivers/net/wan/8253x/ring.h --- linux-2.5.23/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.23/drivers/net/wan/8253x/sab8253xov.txt linux-2.5/drivers/net/wan/8253x/sab8253xov.txt --- linux-2.5.23/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.23/drivers/net/wan/8253x/sp502.h linux-2.5/drivers/net/wan/8253x/sp502.h --- linux-2.5.23/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.23/drivers/net/wan/Config.help linux-2.5/drivers/net/wan/Config.help --- linux-2.5.23/drivers/net/wan/Config.help Wed Jun 19 03:11:46 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.23/drivers/net/wan/Config.in linux-2.5/drivers/net/wan/Config.in --- linux-2.5.23/drivers/net/wan/Config.in Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/net/wan/Config.in Mon Jun 17 22:52:29 2002 @@ -48,6 +48,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.23/drivers/net/wan/Makefile linux-2.5/drivers/net/wan/Makefile --- linux-2.5.23/drivers/net/wan/Makefile Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/net/wan/Makefile Sat May 25 19:07:44 2002 @@ -51,6 +51,13 @@ obj-$(CONFIG_LANMEDIA) += lmc/ +subdir-$(CONFIG_ATI_XX20) += 8253x + +ifeq ($(CONFIG_ATI_XX20),y) + obj-y += 8253x/ASLX.o +endif + + obj-$(CONFIG_DLCI) += dlci.o obj-$(CONFIG_SDLA) += sdla.o ifeq ($(CONFIG_WANPIPE_MULTPPP),y) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/wan/hdlc.c linux-2.5/drivers/net/wan/hdlc.c --- linux-2.5.23/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.23/drivers/net/wan/lapbether.c linux-2.5/drivers/net/wan/lapbether.c --- linux-2.5.23/drivers/net/wan/lapbether.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/net/wan/lapbether.c Sat May 25 19:52:05 2002 @@ -170,6 +170,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -264,6 +265,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; netif_rx(skb); } @@ -286,6 +288,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; netif_rx(skb); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/wan/lmc/lmc_debug.c linux-2.5/drivers/net/wan/lmc/lmc_debug.c --- linux-2.5.23/drivers/net/wan/lmc/lmc_debug.c Wed Jun 19 03:11:51 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.23/drivers/net/wan/lmc/lmc_proto.c linux-2.5/drivers/net/wan/lmc/lmc_proto.c --- linux-2.5.23/drivers/net/wan/lmc/lmc_proto.c Wed Jun 19 03:11:56 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.23/drivers/net/wan/lmc/lmc_var.h linux-2.5/drivers/net/wan/lmc/lmc_var.h --- linux-2.5.23/drivers/net/wan/lmc/lmc_var.h Wed Jun 19 03:11:54 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.23/drivers/net/wan/sbni.c linux-2.5/drivers/net/wan/sbni.c --- linux-2.5.23/drivers/net/wan/sbni.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/net/wan/sbni.c Sun May 26 01:09:33 2002 @@ -203,7 +203,7 @@ sbni_isa_probe( struct net_device *dev ) { if( dev->base_addr > 0x1ff - && !check_region( dev->base_addr, SBNI_IO_EXTENT ) + && request_region( dev->base_addr, SBNI_IO_EXTENT, dev->name ) && sbni_probe1( dev, dev->base_addr, dev->irq ) ) return 0; @@ -258,7 +258,7 @@ for( i = 0; netcard_portlist[ i ]; ++i ) { int ioaddr = netcard_portlist[ i ]; - if( !check_region( ioaddr, SBNI_IO_EXTENT ) + if( request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) && sbni_probe1( dev, ioaddr, 0 )) return 0; } @@ -289,7 +289,7 @@ pci_irq_line = pdev->irq; /* Avoid already found cards from previous calls */ - if( check_region( pci_ioaddr, SBNI_IO_EXTENT ) ) { + if( !pci_request_region( pci_ioaddr, SBNI_IO_EXTENT, dev->name ) ) { pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsys ); if( subsys != 2 || /* Dual adapter is present */ check_region( pci_ioaddr += 4, SBNI_IO_EXTENT ) ) @@ -318,9 +318,6 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) { struct net_local *nl; - - if( !request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) ) - return 0; if( sbni_card_probe( ioaddr ) ) { release_region( ioaddr, SBNI_IO_EXTENT ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/wan/sdla_chdlc.c linux-2.5/drivers/net/wan/sdla_chdlc.c --- linux-2.5.23/drivers/net/wan/sdla_chdlc.c Wed Jun 19 03:11:55 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.23/drivers/net/wan/sdla_fr.c linux-2.5/drivers/net/wan/sdla_fr.c --- linux-2.5.23/drivers/net/wan/sdla_fr.c Wed Jun 19 03:11:59 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; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/net/wan/sdla_ppp.c linux-2.5/drivers/net/wan/sdla_ppp.c --- linux-2.5.23/drivers/net/wan/sdla_ppp.c Wed Jun 19 03:11:49 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.23/drivers/net/wan/sealevel.c linux-2.5/drivers/net/wan/sealevel.c --- linux-2.5.23/drivers/net/wan/sealevel.c Wed Jun 19 03:11:56 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.23/drivers/net/wan/syncppp.c linux-2.5/drivers/net/wan/syncppp.c --- linux-2.5.23/drivers/net/wan/syncppp.c Wed Jun 19 03:11:50 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.23/drivers/net/wan/wanpipe_multppp.c linux-2.5/drivers/net/wan/wanpipe_multppp.c --- linux-2.5.23/drivers/net/wan/wanpipe_multppp.c Wed Jun 19 03:11:55 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.23/drivers/net/wan/x25_asy.c linux-2.5/drivers/net/wan/x25_asy.c --- linux-2.5.23/drivers/net/wan/x25_asy.c Wed Jun 19 03:11:49 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.23/drivers/net/wd.c linux-2.5/drivers/net/wd.c --- linux-2.5.23/drivers/net/wd.c Wed Jun 19 03:11:47 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.23/drivers/net/wireless/airo_cs.c linux-2.5/drivers/net/wireless/airo_cs.c --- linux-2.5.23/drivers/net/wireless/airo_cs.c Wed Jun 19 03:11:51 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.23/drivers/parport/ChangeLog linux-2.5/drivers/parport/ChangeLog --- linux-2.5.23/drivers/parport/ChangeLog Wed Jun 19 03:11:57 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.23/drivers/parport/daisy.c linux-2.5/drivers/parport/daisy.c --- linux-2.5.23/drivers/parport/daisy.c Wed Jun 19 03:11:51 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.23/drivers/parport/parport_cs.c linux-2.5/drivers/parport/parport_cs.c --- linux-2.5.23/drivers/parport/parport_cs.c Wed Jun 19 03:11:59 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.23/drivers/parport/parport_pc.c linux-2.5/drivers/parport/parport_pc.c --- linux-2.5.23/drivers/parport/parport_pc.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/parport/parport_pc.c Wed Jun 19 14:44:35 2002 @@ -2706,6 +2706,7 @@ oxsemi_954, oxsemi_840, aks_0100, + mobility_pp, }; @@ -2789,6 +2790,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 = { @@ -2870,6 +2872,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.23/drivers/parport/parport_serial.c linux-2.5/drivers/parport/parport_serial.c --- linux-2.5.23/drivers/parport/parport_serial.c Wed Jun 19 03:11:58 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.23/drivers/pci/Makefile linux-2.5/drivers/pci/Makefile --- linux-2.5.23/drivers/pci/Makefile Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/pci/Makefile Wed Jun 12 03:01:51 2002 @@ -22,9 +22,9 @@ obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o obj-$(CONFIG_PARISC) += setup-bus.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o -obj-$(CONFIG_PPC32) += setup-irq.o -obj-$(CONFIG_DDB5476) += setup-bus.o +obj-$(CONFIG_PPC32) += setup-bus.o obj-$(CONFIG_SGI_IP27) += setup-irq.o +obj-$(CONFIG_SGI_IP32) += setup-irq.o ifndef CONFIG_X86 obj-y += syscall.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pci/gen-devlist.c linux-2.5/drivers/pci/gen-devlist.c --- linux-2.5.23/drivers/pci/gen-devlist.c Wed Jun 19 03:11:54 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.23/drivers/pci/pool.c linux-2.5/drivers/pci/pool.c --- linux-2.5.23/drivers/pci/pool.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/pci/pool.c Tue Jun 4 15:41:51 2002 @@ -309,9 +309,9 @@ return; } if (page->bitmap [map] & (1UL << block)) { - printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n", + printk (KERN_ERR "pci_pool_free %s/%s, dma %lx already free\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, dma); + pool->name, (unsigned long) dma); return; } memset (vaddr, POOL_POISON_BYTE, pool->size); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pci/quirks.c linux-2.5/drivers/pci/quirks.c --- linux-2.5.23/drivers/pci/quirks.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/pci/quirks.c Tue Jun 4 15:43:53 2002 @@ -90,7 +90,7 @@ * VIA Apollo KT133 needs PCI latency patch * Made according to a windows driver based patch by George E. Breese * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm - * Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for + * Also see http://www.au-ja.org/review-kt133a-1-en.phtml for * the info on which Mr Breese based his work. * * Updated based on further information from the site and also on diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pci/setup-bus.c linux-2.5/drivers/pci/setup-bus.c --- linux-2.5.23/drivers/pci/setup-bus.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/pci/setup-bus.c Sat Jun 1 00:34:35 2002 @@ -106,6 +106,14 @@ DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n", bus->number, bridge->name)); + /* Add bridge resources to the resource tree. */ + if (bus->resource[0]->end > bus->resource[0]->start && + request_resource(bus->resource[0], bus->resource[0]) < 0) + printk(KERN_ERR "PCI: failed to reserve IO for bus %d\n", bus->number); + if (bus->resource[1]->end > bus->resource[1]->start && + request_resource(bus->resource[1], bus->resource[1]) < 0) + printk(KERN_ERR "PCI: failed to reserve MEM for bus %d\n", bus->number); + /* Set up the top and bottom of the PCI I/O segment for this bus. */ if (bus->resource[0]->flags & IORESOURCE_IO) { pci_read_config_dword(bridge, PCI_IO_BASE, &l); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pcmcia/Config.in linux-2.5/drivers/pcmcia/Config.in --- linux-2.5.23/drivers/pcmcia/Config.in Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/pcmcia/Config.in Wed Jun 19 14:45:15 2002 @@ -21,6 +21,8 @@ if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA fi + if [ "$CONFIG_8xx" = "y" ]; then + tristate ' M8xx support' CONFIG_PCMCIA_M8XX + fi fi - endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pcmcia/Makefile linux-2.5/drivers/pcmcia/Makefile --- linux-2.5.23/drivers/pcmcia/Makefile Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/pcmcia/Makefile Sat Jun 1 00:34:35 2002 @@ -14,6 +14,7 @@ obj-$(CONFIG_TCIC) += tcic.o obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o +obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o yenta_socket-objs := pci_socket.o yenta.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pcmcia/cistpl.c linux-2.5/drivers/pcmcia/cistpl.c --- linux-2.5.23/drivers/pcmcia/cistpl.c Wed Jun 19 03:11:51 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.23/drivers/pcmcia/cs.c linux-2.5/drivers/pcmcia/cs.c --- linux-2.5.23/drivers/pcmcia/cs.c Wed Jun 19 03:11:50 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.23/drivers/pcmcia/cs_internal.h linux-2.5/drivers/pcmcia/cs_internal.h --- linux-2.5.23/drivers/pcmcia/cs_internal.h Wed Jun 19 03:11:45 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.23/drivers/pcmcia/hd64465_ss.c linux-2.5/drivers/pcmcia/hd64465_ss.c --- linux-2.5.23/drivers/pcmcia/hd64465_ss.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/pcmcia/hd64465_ss.c Wed Jun 19 20:14:18 2002 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pcmcia/i82092.c linux-2.5/drivers/pcmcia/i82092.c --- linux-2.5.23/drivers/pcmcia/i82092.c Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/pcmcia/i82092.c Wed Jun 19 20:14:18 2002 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pcmcia/i82365.c linux-2.5/drivers/pcmcia/i82365.c --- linux-2.5.23/drivers/pcmcia/i82365.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/pcmcia/i82365.c Wed Jun 19 20:13:56 2002 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pcmcia/m8xx_pcmcia.c linux-2.5/drivers/pcmcia/m8xx_pcmcia.c --- linux-2.5.23/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.23/drivers/pcmcia/pci_socket.h linux-2.5/drivers/pcmcia/pci_socket.h --- linux-2.5.23/drivers/pcmcia/pci_socket.h Wed Jun 19 03:11:49 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.23/drivers/pcmcia/ricoh.h linux-2.5/drivers/pcmcia/ricoh.h --- linux-2.5.23/drivers/pcmcia/ricoh.h Wed Jun 19 03:11:54 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.23/drivers/pcmcia/rsrc_mgr.c linux-2.5/drivers/pcmcia/rsrc_mgr.c --- linux-2.5.23/drivers/pcmcia/rsrc_mgr.c Wed Jun 19 03:11:56 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.23/drivers/pcmcia/tcic.c linux-2.5/drivers/pcmcia/tcic.c --- linux-2.5.23/drivers/pcmcia/tcic.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/pcmcia/tcic.c Wed Jun 19 20:14:20 2002 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -393,7 +394,11 @@ printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: "); sock = 0; - if (check_region(tcic_base, 16) == 0) { + if (!request_region(tcic_base, 16, "tcic-2")) { + printk("could not allocate ports,\n "); + return -ENODEV; + } + else { tcic_setw(TCIC_ADDR, 0); if (tcic_getw(TCIC_ADDR) == 0) { tcic_setw(TCIC_ADDR, 0xc3a5); @@ -409,15 +414,12 @@ if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2; } } - } else - printk("could not allocate ports, "); - + } if (sock == 0) { printk("not found.\n"); + release_region(tcic_base, 16); return -ENODEV; } - - request_region(tcic_base, 16, "tcic-2"); sockets = 0; for (i = 0; i < sock; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pcmcia/ti113x.h linux-2.5/drivers/pcmcia/ti113x.h --- linux-2.5.23/drivers/pcmcia/ti113x.h Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/pcmcia/ti113x.h Mon Jun 17 22:52:29 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; } @@ -252,14 +331,15 @@ static int ti1250_init(pci_socket_t *socket) { yenta_init(socket); + ti113x_init(socket); ti_irqmux(socket) = config_readl(socket, TI122X_IRQMUX); ti_irqmux(socket) = (ti_irqmux(socket) & ~0x0f) | 0x02; /* route INTA */ if (!(ti_sysctl(socket) & TI122X_SCR_INTRTIE)) ti_irqmux(socket) |= 0x20; /* route INTB */ - + config_writel(socket, TI122X_IRQMUX, ti_irqmux(socket)); - + config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pcmcia/yenta.c linux-2.5/drivers/pcmcia/yenta.c --- linux-2.5.23/drivers/pcmcia/yenta.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/pcmcia/yenta.c Wed Jun 19 07:35:19 2002 @@ -235,6 +235,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) { @@ -287,6 +289,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.. */ @@ -689,7 +693,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 @@ -784,6 +788,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.23/drivers/pnp/isapnp.c linux-2.5/drivers/pnp/isapnp.c --- linux-2.5.23/drivers/pnp/isapnp.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/pnp/isapnp.c Tue Jun 18 16:43:25 2002 @@ -28,6 +28,8 @@ * 2001-11-07 Added isapnp_{,un}register_driver calls along the lines * of the pci driver interface * Kai Germaschewski + * 2002-06-06 Made the use of dma channel 0 configurable + * Gerald Teschl */ #include @@ -56,13 +58,10 @@ #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) */ +int isapnp_allow_dma0 = -1; /* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */ int isapnp_skip_pci_scan; /* skip PCI resource scanning */ int isapnp_verbose = 1; /* verbose mode */ int isapnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */ @@ -78,6 +77,8 @@ MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port"); MODULE_PARM(isapnp_reset, "i"); MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards"); +MODULE_PARM(isapnp_allow_dma0, "i"); +MODULE_PARM_DESC(isapnp_allow_dma0, "Allow dma value 0 during auto activation"); MODULE_PARM(isapnp_skip_pci_scan, "i"); MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning"); MODULE_PARM(isapnp_verbose, "i"); @@ -1754,13 +1755,14 @@ static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx) { - int i; + int i, mindma =1; struct pci_dev *dev; /* Some machines allow DMA 0, but others don't. In fact on some boxes DMA 0 is the memory refresh. Play safe */ - - if (dma < 1 || dma == 4 || dma > 7) + if (isapnp_allow_dma0 == 1) + mindma = 0; + if (dma < mindma || dma == 4 || dma > 7) return 1; for (i = 0; i < 8; i++) { if (isapnp_reserve_dma[i] == dma) @@ -2142,19 +2144,13 @@ kfree(card); } -#endif /* MODULE */ - 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); -#ifdef MODULE + release_region(_PNPWRP, 1); + release_region(isapnp_rdp, 1); #ifdef CONFIG_PROC_FS isapnp_proc_done(); #endif @@ -2163,9 +2159,10 @@ list_del(list); isapnp_free_card(pci_bus_b(list)); } -#endif } +#endif /* MODULE */ + static int isapnp_announce_device(struct isapnp_driver *drv, struct pci_dev *dev) { @@ -2317,14 +2314,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 +2335,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 +2350,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.23/drivers/pnp/isapnp_proc.c linux-2.5/drivers/pnp/isapnp_proc.c --- linux-2.5.23/drivers/pnp/isapnp_proc.c Wed Jun 19 03:11:52 2002 +++ linux-2.5/drivers/pnp/isapnp_proc.c Tue Jun 18 16:43:25 2002 @@ -950,6 +950,22 @@ res->start = res->end = dma; res->flags = IORESOURCE_DMA; } + +extern int isapnp_allow_dma0; +static int isapnp_set_allow_dma0(char *line) +{ + int i; + char value[32]; + + isapnp_get_str(value, line, sizeof(value)); + i = simple_strtoul(value, NULL, 0); + if (i < 0 || i > 1) { + printk("isapnp: wrong value %i for allow_dma0\n", i); + return 1; + } + isapnp_allow_dma0 = i; + return 0; +} static int isapnp_set_dma(char *line) { @@ -1036,6 +1052,8 @@ char cmd[32]; line = isapnp_get_str(cmd, line, sizeof(cmd)); + if (!strcmp(cmd, "allow_dma0")) + return isapnp_set_allow_dma0(line); if (!strcmp(cmd, "card")) return isapnp_set_card(line); if (!strcmp(cmd, "csn")) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pnp/pnpbios_core.c linux-2.5/drivers/pnp/pnpbios_core.c --- linux-2.5.23/drivers/pnp/pnpbios_core.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/pnp/pnpbios_core.c Tue Jun 4 15:51:31 2002 @@ -610,7 +610,6 @@ static struct pnp_docking_station_info now; int docked = -1, d = 0; daemonize(); - reparent_to_init(); strcpy(current->comm, "kpnpbiosd"); while(!unloading && !signal_pending(current)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/pnp/quirks.c linux-2.5/drivers/pnp/quirks.c --- linux-2.5.23/drivers/pnp/quirks.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/pnp/quirks.c Tue Jun 18 16:45:50 2002 @@ -102,6 +102,28 @@ return; } +extern int isapnp_allow_dma0; +static void __init quirk_opl3sax_resources(struct pci_dev *dev) +{ + /* This really isn't a device quirk but isapnp core code + * doesn't allow a DMA channel of 0, afflicted card is an + * OPL3Sax where x=4. + */ + struct isapnp_resources *res; + int max; + res = (struct isapnp_resources *)dev->sysdata; + max = res->dma->map; + for (res = res->alt; res; res = res->alt) { + if (res->dma->map > max) + max = res->dma->map; + } + if (max == 1 && isapnp_allow_dma0 == -1) { + printk(KERN_INFO "isapnp: opl3sa4 quirk: Allowing dma 0.\n"); + isapnp_allow_dma0 = 1; + } + return; +} + /* * ISAPnP Quirks * Cards or devices that need some tweaking due to broken hardware @@ -133,6 +155,8 @@ quirk_sb16audio_resources }, { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0045), quirk_sb16audio_resources }, + { ISAPNP_VENDOR('Y','M','H'), ISAPNP_DEVICE(0x0021), + quirk_opl3sax_resources }, { 0 } }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/s390/char/ctrlchar.c linux-2.5/drivers/s390/char/ctrlchar.c --- linux-2.5.23/drivers/s390/char/ctrlchar.c Wed Jun 19 03:11:59 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.23/drivers/s390/misc/chandev.c linux-2.5/drivers/s390/misc/chandev.c --- linux-2.5.23/drivers/s390/misc/chandev.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/s390/misc/chandev.c Wed Jun 12 03:01:55 2002 @@ -904,25 +904,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; @@ -1738,8 +1719,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.23/drivers/sbus/audio/cs4231.c linux-2.5/drivers/sbus/audio/cs4231.c --- linux-2.5.23/drivers/sbus/audio/cs4231.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/sbus/audio/cs4231.c Fri Jun 7 02:36:08 2002 @@ -35,7 +35,7 @@ #include #include #include -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64) #define EB4231_SUPPORT #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/sbus/char/jsflash.c linux-2.5/drivers/sbus/char/jsflash.c --- linux-2.5.23/drivers/sbus/char/jsflash.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/sbus/char/jsflash.c Mon Jun 17 22:21:26 2002 @@ -42,11 +42,8 @@ */ #define MAJOR_NR JSFD_MAJOR -#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 @@ -197,6 +194,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; @@ -204,6 +209,7 @@ struct jsfd_part *jdp; unsigned long offset; size_t len; + int uptodate; for (;;) { if (blk_queue_empty(QUEUE)) @@ -213,7 +219,7 @@ dev = MINOR(req->rq_dev); if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { - end_request(CURRENT, 0); + jfsd_end_request(req, 0); continue; } jdp = &jsf0.dv[dev & JSF_PART_MASK]; @@ -221,31 +227,31 @@ offset = req->sector << 9; len = req->current_nr_sectors << 9; if ((offset + len) > jdp->dsize) { - end_request(CURRENT, 0); + jfsd_end_request(req, 0); continue; } if (req->cmd == WRITE) { printk(KERN_ERR "jsfd: write\n"); - end_request(CURRENT, 0); + jfsd_end_request(req, 0); continue; } if (req->cmd != READ) { printk(KERN_ERR "jsfd: bad req->cmd %d\n", req->cmd); - end_request(CURRENT, 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(CURRENT, 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(CURRENT, 1); + jfsd_end_request(req, 1); } } @@ -665,7 +671,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.23/drivers/sbus/char/pcikbd.c linux-2.5/drivers/sbus/char/pcikbd.c --- linux-2.5.23/drivers/sbus/char/pcikbd.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/sbus/char/pcikbd.c Fri Jun 7 02:36:08 2002 @@ -29,7 +29,7 @@ #include #include -#if defined(CONFIG_USB) && defined(CONFIG_SPARC64) +#if (defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)) && defined(CONFIG_SPARC64) #include #endif #include @@ -640,7 +640,7 @@ restore_flags(flags); } -#if defined(CONFIG_USB) && defined(CONFIG_SPARC64) +#if (defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)) && defined(CONFIG_SPARC64) static void isa_kd_nosound(unsigned long __unused) { /* disable counter 2 */ @@ -758,7 +758,7 @@ } } } -#ifdef CONFIG_USB +#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE) /* We are being called for the sake of USB keyboard * state initialization. So we should check for beeper * device in this case. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/sbus/char/riowatchdog.c linux-2.5/drivers/sbus/char/riowatchdog.c --- linux-2.5.23/drivers/sbus/char/riowatchdog.c Wed Jun 19 03:11:55 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.23/drivers/sbus/char/sab82532.c linux-2.5/drivers/sbus/char/sab82532.c --- linux-2.5.23/drivers/sbus/char/sab82532.c Wed Jun 19 03:11:53 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.23/drivers/sbus/char/su.c linux-2.5/drivers/sbus/char/su.c --- linux-2.5.23/drivers/sbus/char/su.c Wed Jun 19 03:11:49 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.23/drivers/sbus/char/sunkbd.c linux-2.5/drivers/sbus/char/sunkbd.c --- linux-2.5.23/drivers/sbus/char/sunkbd.c Wed Jun 19 03:11:57 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.23/drivers/sbus/char/sunserial.c linux-2.5/drivers/sbus/char/sunserial.c --- linux-2.5.23/drivers/sbus/char/sunserial.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/sbus/char/sunserial.c Fri Jun 7 02:36:08 2002 @@ -139,7 +139,7 @@ nop_getkeycode }; -#ifdef CONFIG_USB +#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE) extern void pci_compute_shiftstate(void); extern int pci_setkeycode(unsigned int, unsigned int); extern int pci_getkeycode(unsigned int); @@ -158,7 +158,7 @@ err = init->init(); init = init->next; } -#ifdef CONFIG_USB +#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE) if (!serial_console && kbd_ops.compute_shiftstate == nop_compute_shiftstate) { printk("kbd_init: Assuming USB keyboard.\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/sbus/char/zs.c linux-2.5/drivers/sbus/char/zs.c --- linux-2.5.23/drivers/sbus/char/zs.c Wed Jun 19 03:11:59 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.23/drivers/scsi/Config.help linux-2.5/drivers/scsi/Config.help --- linux-2.5.23/drivers/scsi/Config.help Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/scsi/Config.help Tue Jun 18 16:16:32 2002 @@ -136,6 +136,17 @@ . The module will be called sg.o. If unsure, say N. +CONFIG_CHR_DEV_SM + This driver provides a SCSI hotplug agent with information about + comings and goings in the SCSI subsystem. Lists of attached and + recently detached devices as well as a host list are available. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt and + Documentation/scsi.txt. The module will be called scsimon.o. If unsure, + say N. + CONFIG_SCSI_MULTI_LUN If you have a SCSI device that supports more than one LUN (Logical Unit Number), e.g. a CD jukebox, and only one LUN is detected, you @@ -179,6 +190,10 @@ there should be no noticeable performance impact as long as you have logging turned off. +CONFIG_SGIWD93_SCSI + If you have a Western Digital WD93 SCSI controller on + an SGI MIPS system, say Y. Otherwise, say N. + CONFIG_SCSI_DECNCR Say Y here to support the NCR53C94 SCSI controller chips on IOASIC based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. @@ -978,6 +993,11 @@ The module will be called qlogicfc.o. If you want to compile it as a module, say M here and read . +CONFIG_SCSI_QLOGIC_FC_FIRMWARE + Say Y to include ISP2100 Fabric Initiator/Target Firmware, with + expanded LUN addressing and FcTape (FCP-2) support, in the + Qlogic QLA 1280 driver. + CONFIG_SCSI_QLOGIC_1280 Say Y if you have a QLogic ISP1x80/1x160 SCSI host adapter. @@ -1384,4 +1404,13 @@ which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read . + +CONFIG_BROKEN_SCSI_ERROR_HANDLING + SCSI error handling in 2.5 is somewhat different to 2.4. In particular, + the old-style error handling is non-existant any more. Some SCSI drivers + however are still not updated, and still reference the old method of + handling errors, which breaks compilation. + Choosing this option will allow the drivers to compile again, but with + *NO* error handling whatsoever. This is dangerous, and should not be used + with a filesystem you particularly care about. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/Config.in linux-2.5/drivers/scsi/Config.in --- linux-2.5.23/drivers/scsi/Config.in Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/scsi/Config.in Wed Jun 19 14:49:59 2002 @@ -1,5 +1,7 @@ comment 'SCSI support type (disk, tape, CD-ROM)' +bool ' Use SCSI drivers with broken error handling [DANGEROUS]' CONFIG_BROKEN_SCSI_ERROR_HANDLING + dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then @@ -18,6 +20,8 @@ fi dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI +dep_tristate ' SCSI monitor support' CONFIG_CHR_DEV_SM $CONFIG_SCSI + comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN @@ -225,6 +229,7 @@ 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 + int ' initial bus reset delay (ms) (0 = no reset)' CONFIG_SCSI_MESH_RESET_DELAY_MS 4000 fi dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/Makefile linux-2.5/drivers/scsi/Makefile --- linux-2.5.23/drivers/scsi/Makefile Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/scsi/Makefile Tue Jun 18 16:16:32 2002 @@ -118,6 +118,7 @@ obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o +obj-$(CONFIG_CHR_DEV_SM) += scsimon.o scsi_mod-objs := scsi.o hosts.o scsi_ioctl.o constants.o scsicam.o \ scsi_proc.o scsi_error.o scsi_queue.o scsi_lib.o \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/README.st linux-2.5/drivers/scsi/README.st --- linux-2.5.23/drivers/scsi/README.st Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/scsi/README.st Wed Jun 19 07:35:19 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 Jun 18 18:13:50 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.23/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux-2.5/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- linux-2.5.23/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Tue Jun 18 15:26:22 2002 @@ -78,8 +78,6 @@ eh_device_reset_handler: ahc_linux_dev_reset, \ eh_bus_reset_handler: ahc_linux_bus_reset, \ eh_host_reset_handler: NULL, \ - abort: NULL, \ - reset: NULL, \ slave_attach: NULL, \ bios_param: AIC7XXX_BIOSPARAM, \ can_queue: 253, /* max simultaneous cmds */\ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/dtc.c linux-2.5/drivers/scsi/dtc.c --- linux-2.5.23/drivers/scsi/dtc.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/scsi/dtc.c Mon Jun 17 22:52:29 2002 @@ -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 @@ -101,336 +100,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.23/drivers/scsi/fdomain.c linux-2.5/drivers/scsi/fdomain.c --- linux-2.5.23/drivers/scsi/fdomain.c Wed Jun 19 03:11:49 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.23/drivers/scsi/g_NCR5380.h linux-2.5/drivers/scsi/g_NCR5380.h --- linux-2.5.23/drivers/scsi/g_NCR5380.h Wed Jun 19 03:11:46 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.23/drivers/scsi/hosts.c linux-2.5/drivers/scsi/hosts.c --- linux-2.5.23/drivers/scsi/hosts.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/scsi/hosts.c Tue Jun 18 15:55:46 2002 @@ -73,8 +73,8 @@ struct Scsi_Host * scsi_hostlist; struct Scsi_Device_Template * scsi_devicelist; -int max_scsi_hosts; -int next_scsi_host; +int max_scsi_hosts; /* host_no for next new host */ +int next_scsi_host; /* count of registered scsi hosts */ void scsi_unregister(struct Scsi_Host * sh){ @@ -99,21 +99,8 @@ if (shn) shn->host_registered = 0; /* else {} : This should not happen, we should panic here... */ - /* If we are removing the last host registered, it is safe to reuse - * its host number (this avoids "holes" at boot time) (DB) - * It is also safe to reuse those of numbers directly below which have - * been released earlier (to avoid some holes in numbering). - */ - if(sh->host_no == max_scsi_hosts - 1) { - while(--max_scsi_hosts >= next_scsi_host) { - shpnt = scsi_hostlist; - while(shpnt && shpnt->host_no != max_scsi_hosts - 1) - shpnt = shpnt->next; - if(shpnt) - break; - } - } next_scsi_host--; + kfree((char *) sh); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/hosts.h linux-2.5/drivers/scsi/hosts.h --- linux-2.5.23/drivers/scsi/hosts.h Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/scsi/hosts.h Sun May 26 19:08:10 2002 @@ -165,40 +165,10 @@ int (*eh_bus_reset_handler)(Scsi_Cmnd *); int (*eh_host_reset_handler)(Scsi_Cmnd *); - /* - * Since the mid level driver handles time outs, etc, we want to - * be able to abort the current command. Abort returns 0 if the - * abortion was successful. The field SCpnt->abort reason - * can be filled in with the appropriate reason why we wanted - * the abort in the first place, and this will be used - * in the mid-level code instead of the host_byte(). - * If non-zero, the code passed to it - * will be used as the return code, otherwise - * DID_ABORT should be returned. - * - * Note that the scsi driver should "clean up" after itself, - * resetting the bus, etc. if necessary. - * - * NOTE - this interface is depreciated, and will go away. Use - * the eh_ routines instead. - */ - int (* abort)(Scsi_Cmnd *); - - /* - * The reset function will reset the SCSI bus. Any executing - * commands should fail with a DID_RESET in the host byte. - * The Scsi_Cmnd is passed so that the reset routine can figure - * out which host adapter should be reset, and also which command - * within the command block was responsible for the reset in - * the first place. Some hosts do not implement a reset function, - * and these hosts must call scsi_request_sense(SCpnt) to keep - * the command alive. - * - * NOTE - this interface is depreciated, and will go away. Use - * the eh_ routines instead. - */ - int (* reset)(Scsi_Cmnd *, unsigned int); - +#ifdef CONFIG_BROKEN_SCSI_ERROR_HANDLING + int (* abort)(Scsi_Cmnd *); + int (* reset)(Scsi_Cmnd *, unsigned int); +#endif /* * This function is used to select synchronous communications, * which will result in a higher data throughput. Not implemented diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/i60uscsi.c linux-2.5/drivers/scsi/i60uscsi.c --- linux-2.5.23/drivers/scsi/i60uscsi.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/scsi/i60uscsi.c Sat May 25 19:52:05 2002 @@ -640,7 +640,6 @@ ULONG idx; UCHAR index; UCHAR i; - ULONG flags; Ch = hcsp->HCS_Index; for (i = 0; i < 8; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/ibmmca.c linux-2.5/drivers/scsi/ibmmca.c --- linux-2.5.23/drivers/scsi/ibmmca.c Wed Jun 19 03:11:47 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.23/drivers/scsi/imm.c linux-2.5/drivers/scsi/imm.c --- linux-2.5.23/drivers/scsi/imm.c Wed Jun 19 03:11:59 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.23/drivers/scsi/ini9100u.c linux-2.5/drivers/scsi/ini9100u.c --- linux-2.5.23/drivers/scsi/ini9100u.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/scsi/ini9100u.c Tue Jun 18 16:18:25 2002 @@ -108,7 +108,7 @@ #define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) -#error Please convert me to Documentation/DMA-mapping.txt +/* #error Please convert me to Documentation/DMA-mapping.txt */ #ifndef LINUX_VERSION_CODE #include @@ -491,7 +491,9 @@ if (SCpnt->use_sg) { pSrbSG = (struct scatterlist *) SCpnt->request_buffer; if (SCpnt->use_sg == 1) { /* If only one entry in the list *//* treat it as regular I/O */ - pSCB->SCB_BufPtr = (U32) VIRT_TO_BUS(pSrbSG->address); + pSCB->SCB_BufPtr = (U32) VIRT_TO_BUS( + (unsigned char *)page_address(pSrbSG->page) + + pSrbSG->offset); TotalLen = pSrbSG->length; pSCB->SCB_SGLen = 0; } else { /* Assign SG physical address */ @@ -500,7 +502,9 @@ for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0]; /* 1.01g */ i < SCpnt->use_sg; i++, pSG++, pSrbSG++) { - pSG->SG_Ptr = (U32) VIRT_TO_BUS(pSrbSG->address); + pSG->SG_Ptr = (U32) VIRT_TO_BUS( + (unsigned char *)page_address(pSrbSG->page) + + pSrbSG->offset); TotalLen += pSG->SG_Len = pSrbSG->length; } pSCB->SCB_SGLen = i; @@ -552,6 +556,7 @@ return -1; } +#if 0 /* * Abort a queued command * (commands that are on the bus can't be aborted easily) @@ -578,6 +583,16 @@ return tul_reset_scsi_bus(pHCB); else return tul_device_reset(pHCB, (ULONG) SCpnt, SCpnt->target, reset_flags); +} +#endif + +static int i91u_eh_bus_reset(Scsi_Cmnd * SCpnt) +{ + HCS *pHCB; + + pHCB = (HCS *) SCpnt->host->base; + tul_reset_scsi_bus(pHCB); + return SUCCESS; } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/ini9100u.h linux-2.5/drivers/scsi/ini9100u.h --- linux-2.5.23/drivers/scsi/ini9100u.h Wed Jun 19 03:11:44 2002 +++ linux-2.5/drivers/scsi/ini9100u.h Tue Jun 18 16:18:25 2002 @@ -82,8 +82,11 @@ extern int i91u_release(struct Scsi_Host *); extern int i91u_command(Scsi_Cmnd *); extern int i91u_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +#if 0 extern int i91u_abort(Scsi_Cmnd *); extern int i91u_reset(Scsi_Cmnd *, unsigned int); +#endif +static int i91u_eh_bus_reset(Scsi_Cmnd * SCpnt); extern int i91u_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */ #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03g" @@ -102,10 +105,8 @@ eh_strategy_handler: NULL, \ eh_abort_handler: NULL, \ eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ + eh_bus_reset_handler: i91u_eh_bus_reset, \ eh_host_reset_handler: NULL, \ - abort: i91u_abort, \ - reset: i91u_reset, \ slave_attach: NULL, \ bios_param: i91u_biosparam, \ can_queue: 1, \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/inia100.c linux-2.5/drivers/scsi/inia100.c --- linux-2.5.23/drivers/scsi/inia100.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/scsi/inia100.c Tue Jun 4 15:48:49 2002 @@ -380,7 +380,11 @@ printk("inia100: initial orchid fail!!\n"); return (0); } - request_region(pHCB->HCS_Base, 256, "inia100"); /* Register */ + if (!request_region(pHCB->HCS_Base, 256, "inia100")) { + printk(KERN_WARNING "inia100: io port 0x%x, is busy.\n", + pHCB->HCS_Base); + return (0); + } hreg = scsi_register(tpnt, sizeof(ORC_HCS)); if (hreg == NULL) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/ips.c linux-2.5/drivers/scsi/ips.c --- linux-2.5.23/drivers/scsi/ips.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/scsi/ips.c Fri Jun 7 02:36:08 2002 @@ -83,7 +83,7 @@ /* 2.3.18 and later */ /* - Sync with other changes from the 2.3 kernels */ /* 4.00.06 - Fix timeout with initial FFDC command */ -/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ +/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ /* 4.10.00 - Add support for ServeRAID 4M/4L */ /* 4.10.13 - Fix for dynamic unload and proc file system */ /* 4.20.03 - Rename version to coincide with new release schedules */ @@ -194,6 +194,7 @@ #ifdef MODULE static char *ips = NULL; MODULE_PARM(ips, "s"); + MODULE_LICENSE("GPL"); #endif /* @@ -596,8 +597,7 @@ } return (1); - -__setup("ips=", ips_setup); +} #else @@ -632,10 +632,10 @@ } } } +} #endif -} /****************************************************************************/ /* */ @@ -887,7 +887,7 @@ DEBUG_VAR(1, "(%s%d) detect, IO region %x, size: %d", ips_name, ips_next_controller, io_addr, io_len); - if (check_region(io_addr, io_len)) { + if (!request_region(io_addr, io_len, "ips")) { /* Couldn't allocate io space */ printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n", ips_name, ips_next_controller, io_addr, io_len); @@ -896,8 +896,6 @@ continue; } - - request_region(io_addr, io_len, "ips"); } /* get planer status */ @@ -1706,6 +1704,10 @@ #endif /* NO_IPS_RESET */ } + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) +__setup("ips=", ips_setup); +#endif /****************************************************************************/ /* */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/megaraid.c linux-2.5/drivers/scsi/megaraid.c --- linux-2.5.23/drivers/scsi/megaraid.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/scsi/megaraid.c Wed Jun 19 20:28:52 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;*/ @@ -1866,7 +1866,14 @@ return NULL; } - copy_from_user (pScb->buff_ptr, user_area, xfer_size); + if (copy_from_user (pScb->buff_ptr, user_area, xfer_size)) { + printk + ("megaraid: Copy failed for M_RD_IOCTL_CMD_NEW.\n"); + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + kfree (pScb->buff_ptr); + return NULL; + } pScb->iDataSize = xfer_size; switch (data[0]) { @@ -4534,7 +4541,6 @@ unsigned int cmd, unsigned long arg) { int adapno; - kdev_t dev; u32 inlen; struct uioctl_t ioc; char *kvaddr = NULL; @@ -4628,10 +4634,10 @@ /* * Copy struct mcontroller to user area */ - copy_to_user (ioc.data, - mcontroller + adapno, - sizeof (struct mcontroller)); - return 0; + return copy_to_user (ioc.data, + mcontroller + adapno, + sizeof (struct mcontroller)) + ? -EFAULT : 0; default: return (-EINVAL); @@ -4730,7 +4736,16 @@ if (inlen) { /* copyin the user data */ - copy_from_user(kvaddr, (char *)uaddr, length ); + if (copy_from_user(kvaddr, (char *)uaddr, length )) { + printk(KERN_WARNING "megaraid:copy failed\n"); + dma_free_consistent(pdevp, length, kvaddr, dma_addr); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ + kfree(scsicmd); +#else + scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); +#endif + return -EFAULT; + } } } @@ -4747,7 +4762,17 @@ down(&mimd_ioctl_sem); if( !scsicmd->result && outlen ) { - copy_to_user(uaddr, kvaddr, length); + if (copy_to_user(uaddr, kvaddr, length)) { + up(&mimd_ioctl_sem); + dma_free_consistent(pdevp, length, kvaddr, dma_addr); + printk(KERN_WARNING "megaraid:copy failed\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ + kfree(scsicmd); +#else + scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); +#endif + return -EFAULT; + } } /* @@ -4876,9 +4901,19 @@ if (inlen) { if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { /* copyin the user data */ - copy_from_user (kvaddr, uaddr, ioc.pthru.dataxferlen); + ret = copy_from_user (kvaddr, uaddr, ioc.pthru.dataxferlen); } else { - copy_from_user (kvaddr, uaddr, inlen); + ret = copy_from_user (kvaddr, uaddr, inlen); + } + if (ret) { + dma_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr ); + printk (KERN_WARNING "megaraid:copy failed\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ + kfree(scsicmd); +#else + scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); +#endif + return -EFAULT; } } } @@ -4896,10 +4931,22 @@ if (!scsicmd->result && outlen) { if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { - copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen); + ret = copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen); } else { - copy_to_user (uaddr, kvaddr, outlen); + ret = copy_to_user (uaddr, kvaddr, outlen); } + if (ret) { + up (&mimd_ioctl_sem); + dma_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr ); + printk (KERN_WARNING "megaraid:copy failed\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ + kfree(scsicmd); +#else + scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); +#endif + return -EFAULT; + } + } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/pas16.c linux-2.5/drivers/scsi/pas16.c --- linux-2.5.23/drivers/scsi/pas16.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/scsi/pas16.c Mon Jun 17 22:52:29 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 @@ -132,467 +128,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.23/drivers/scsi/pci2000.c linux-2.5/drivers/scsi/pci2000.c --- linux-2.5.23/drivers/scsi/pci2000.c Wed Jun 19 03:11:57 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.23/drivers/scsi/pcmcia/aha152x_stub.c linux-2.5/drivers/scsi/pcmcia/aha152x_stub.c --- linux-2.5.23/drivers/scsi/pcmcia/aha152x_stub.c Wed Jun 19 03:11:52 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.23/drivers/scsi/pcmcia/fdomain_stub.c linux-2.5/drivers/scsi/pcmcia/fdomain_stub.c --- linux-2.5.23/drivers/scsi/pcmcia/fdomain_stub.c Wed Jun 19 03:11:56 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.23/drivers/scsi/pcmcia/qlogic_stub.c linux-2.5/drivers/scsi/pcmcia/qlogic_stub.c --- linux-2.5.23/drivers/scsi/pcmcia/qlogic_stub.c Wed Jun 19 03:11:55 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.23/drivers/scsi/ppa.c linux-2.5/drivers/scsi/ppa.c --- linux-2.5.23/drivers/scsi/ppa.c Wed Jun 19 03:11:46 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.23/drivers/scsi/qlogicfc.c linux-2.5/drivers/scsi/qlogicfc.c --- linux-2.5.23/drivers/scsi/qlogicfc.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/scsi/qlogicfc.c Fri Jun 7 02:36:08 2002 @@ -1342,18 +1342,11 @@ num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); num_free = (num_free > 2) ? num_free - 2 : 0; - host->can_queue = hostdata->queued + num_free; + host->can_queue = host->host_busy + num_free; if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) host->can_queue = QLOGICFC_REQ_QUEUE_LEN; host->sg_tablesize = QLOGICFC_MAX_SG(num_free); - /* this is really gross */ - if (host->can_queue <= host->host_busy){ - if (host->can_queue+2 < host->host_busy) - DEBUG(printk("qlogicfc%d.c crosses its fingers.\n", hostdata->host_id)); - host->can_queue = host->host_busy + 1; - } - LEAVE("isp2x00_queuecommand"); return 0; @@ -1623,16 +1616,10 @@ num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); num_free = (num_free > 2) ? num_free - 2 : 0; - host->can_queue = hostdata->queued + num_free; + host->can_queue = host->host_busy + num_free; if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) host->can_queue = QLOGICFC_REQ_QUEUE_LEN; host->sg_tablesize = QLOGICFC_MAX_SG(num_free); - - if (host->can_queue <= host->host_busy){ - if (host->can_queue+2 < host->host_busy) - DEBUG(printk("qlogicfc%d : crosses its fingers.\n", hostdata->host_id)); - host->can_queue = host->host_busy + 1; - } outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); LEAVE_INTR("isp2x00_intr_handler"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/scsi.h linux-2.5/drivers/scsi/scsi.h --- linux-2.5.23/drivers/scsi/scsi.h Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/scsi/scsi.h Mon Jun 17 22:52:29 2002 @@ -676,8 +676,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.23/drivers/scsi/scsi_ioctl.c linux-2.5/drivers/scsi/scsi_ioctl.c --- linux-2.5.23/drivers/scsi/scsi_ioctl.c Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/scsi/scsi_ioctl.c Mon Jun 17 22:52:29 2002 @@ -379,9 +379,12 @@ scsi_ioctl_get_pci(Scsi_Device * dev, void *arg) { - if (!dev->host->pci_dev) return -ENXIO; - return copy_to_user(arg, dev->host->pci_dev->slot_name, - sizeof(dev->host->pci_dev->slot_name)); + if (!dev->host->pci_dev) + return -ENXIO; + if(copy_to_user(arg, dev->host->pci_dev->slot_name, + sizeof(dev->host->pci_dev->slot_name))) + return -EFAULT; + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/scsi_scan.c linux-2.5/drivers/scsi/scsi_scan.c --- linux-2.5.23/drivers/scsi/scsi_scan.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/scsi/scsi_scan.c Mon Jun 17 22:52:30 2002 @@ -124,6 +124,8 @@ {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"RELISYS", "Scorpio", "*", BLIST_NOLUN}, /* responds to all LUN */ + {"RELISYS", "VM3530+", "*", BLIST_NOLUN}, /* responds to all LUN */ + {"ACROSS", "", "*", BLIST_NOLUN}, /* responds to all LUN */ {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all LUN */ /* @@ -661,8 +663,9 @@ /* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */ } else { /* assume no peripheral if any other sort of error */ + scsi_release_commandblocks(SDpnt); scsi_release_request(SRpnt); - return 0; + return SCSI_SCAN_NO_RESPONSE; } } @@ -723,6 +726,8 @@ */ scsi_release_commandblocks(SDpnt); scsi_release_request(SRpnt); + kfree(SDpnt->inquiry); + SDpnt->inquiry = NULL; return SCSI_SCAN_DEVICE_PRESENT; } /* The Toshiba ROM was "gender-changed" here as an inline hack. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/scsimon.c linux-2.5/drivers/scsi/scsimon.c --- linux-2.5.23/drivers/scsi/scsimon.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/scsi/scsimon.c Tue Jun 18 16:16:32 2002 @@ -0,0 +1,990 @@ +/* + SCSI upper level driver that permits user applications to monitor + the state of SCSI devices and hosts. The original purpose of this + driver is to support hotplugging notification. + See http://www.torque.net/scsi/scsimon.html for more information. + + * Copyright (C) 2001,2002 Douglas Gilbert + * + * 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. + * + */ +#include +/* static char * scsimon_version_str = "Version: 0.1.99 (20020409)"; */ + static int scsimon_version_num = 196; /* 2 digits for each component */ + +/* + * For more information contact: + * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au) + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "scsi.h" +#include "hosts.h" +#include +#include + + +static int scsimon_init(void); +static int scsimon_attach(Scsi_Device *); +static void scsimon_finish(void); +static int scsimon_detect(Scsi_Device *); +static void scsimon_detach(Scsi_Device *); + +static struct Scsi_Device_Template scsimon_template = +{ + module:THIS_MODULE, + name:"scsimon", + tag:"scsimon", + scsi_type:0xff, + major:MISC_MAJOR, + detect:scsimon_detect, + init:scsimon_init, + finish:scsimon_finish, + attach:scsimon_attach, + detach:scsimon_detach +}; + + +static int scsimon_open(struct inode * inode, struct file * filp); +static int scsimon_release(struct inode * inode, struct file * filp); +static ssize_t scsimon_read(struct file * filp, char * buf, + size_t count, loff_t *ppos); +static int scsimon_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd_in, unsigned long arg); +static unsigned int scsimon_poll(struct file * filp, poll_table * wait); +static int scsimon_fasync(int fd, struct file * filp, int mode); + +static struct file_operations scsimon_fops = { + owner: THIS_MODULE, + read: scsimon_read, + poll: scsimon_poll, + ioctl: scsimon_ioctl, + open: scsimon_open, + release: scsimon_release, + fasync: scsimon_fasync, +}; + +static struct miscdevice scsimon_miscdev = { + SCSIMON_MINOR, + "scsimon", + &scsimon_fops +}; + + +typedef struct scsimon_fd /* holds the state of a file descriptor */ +{ + struct scsimon_fd * nextfp; /* NULL when last opened fd */ + struct fasync_struct * async_qp; /* for asynchronous notification */ +} Sm_fd; + +typedef struct scsimon_attached +{ + struct scsimon_attached * next_att; /* NULL if last */ + Scsi_Device * device; + unsigned int host; + unsigned int bus; + unsigned int target; + unsigned int lun; + unsigned long time_attached; /* jiffy count when attached */ + unsigned long event_count; +} Sm_attached; + +typedef struct scsimon_detached +{ + struct scsimon_detached * next_det; /* NULL if last */ + unsigned int host; + unsigned int bus; + unsigned int target; + unsigned int lun; + char vendor[8]; + char model[16]; + char rev[4]; + char host_name[16]; + char host_info[80]; + char scsi_type; + char scsi_level; /* as in SCSI field in INQ */ + char removable; + char emulated; + int access_count; + char writeable; + char changed; + char lockable; + char online; + unsigned long time_detached; /* jiffy count when detached */ + unsigned long event_count; /* event count when detached */ + unsigned long event_attached; /* event count when attached */ +} Sm_detached; + +typedef struct scsimon_hotinfo +{ + int action; /* 0 -> attach, 1 -> detach */ + unsigned int host; + unsigned int bus; + unsigned int target; + unsigned int lun; + unsigned long event_attached; + unsigned long event_detached; + char vendor[8]; + char model[16]; + char rev[4]; + char scsi_type; + char removable; + char emulated; + char writeable; + char lockable; + int access_count; +} Sm_hotinfo; + +static rwlock_t scsimon_lock = RW_LOCK_UNLOCKED; + +/* static Sm_fd * sm_fd_rootp; */ +static Sm_attached * sm_att_rootp; +static Sm_detached * sm_det_rootp; +static int sm_locked_down; /* hack to keep module loaded */ +static unsigned long sm_event_count; /* bumped on each change */ +static unsigned long sm_init_time; +static int sm_max_detached_elems = 10; /* forgets oldest */ +static int sm_flag_attached; +static int sm_flag_detached; + +static void sm_trunc_alist(int fromPos); +static void sm_trunc_dlist(int fromPos); +static Sm_fd * sm_add_sfp(void); +static void sm_remove_sfp(Sm_fd *); +static void sm_read_state(struct scsimon_state *); +static void sm_read_att_list(struct scsimon_att_list *); +static void sm_read_det_list(struct scsimon_det_list *); +static void sm_read_host_list(struct scsimon_host_list *); +static void sm_call_policy (Sm_hotinfo *); + + +static int scsimon_open(struct inode * inode, struct file * filp) +{ + Sm_fd * sfp; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_open: flags=0x%x\n", + filp->f_flags)); + if ((sfp = sm_add_sfp())) + filp->private_data = sfp; + else + return -ENOMEM; + return 0; +} + +static int scsimon_release(struct inode * inode, struct file * filp) +{ + Sm_fd * sfp; + + if (! (sfp = (Sm_fd *)filp->private_data)) { + return -ENXIO; + } + SCSI_LOG_TIMEOUT(3, printk("scsimon_release:\n")); + scsimon_fasync(-1, filp, 0); /* remove from async notify list */ + filp->private_data = NULL; + sm_remove_sfp(sfp); + return 0; +} + +static ssize_t scsimon_read(struct file * filp, char * buf, + size_t count, loff_t *ppos) +{ + Sm_fd * sfp; + unsigned long iflags; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_read: count=%d\n", (int)count)); + if (! (sfp = (Sm_fd *)filp->private_data)) + return -ENXIO; + write_lock_irqsave(&scsimon_lock, iflags); + sm_flag_attached = 0; + sm_flag_detached = 0; + write_unlock_irqrestore(&scsimon_lock, iflags); + return count; +} + +static int scsimon_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd_in, unsigned long arg) +{ + int val, result, read_only; + unsigned long iflags; + Sm_fd * sfp; + + if (! (sfp = (Sm_fd *)filp->private_data)) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("scsimon_ioctl: cmd=0x%x\n", (int)cmd_in)); + read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); + + switch(cmd_in) + { + case SCSIMON_LOCK_MOD: + if (0 == sm_locked_down) { + sm_locked_down++; + MOD_INC_USE_COUNT; + } + return 0; + case SCSIMON_UNLOCK_MOD: + if (sm_locked_down > 0) { + sm_locked_down--; + MOD_DEC_USE_COUNT; + } + return 0; + case SCSIMON_GET_VERSION_NUM: + return put_user(scsimon_version_num, (int *)arg); + case SCSIMON_SET_MX_DLIST_LEN: + result = get_user(val, (int *)arg); + if (result) return result; + sm_max_detached_elems = val; + return 0; + case SCSIMON_GET_MX_DLIST_LEN: + return put_user(sm_max_detached_elems, (int *)arg); + case SCSIMON_GET_STATE: + result = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct scsimon_state)); + if (result) return result; + else { + struct scsimon_state ss; + + sm_read_state(&ss); + __copy_to_user((void *)arg, &ss, + sizeof(struct scsimon_state)); + return 0; + } + case SCSIMON_GET_ATT_LIST: + { + struct scsimon_att_list * sm_alp = + (struct scsimon_att_list *)arg; + struct scsimon_att_list * sm_alop; + size_t sz = sizeof(struct scsimon_att_list); + + result = verify_area(VERIFY_WRITE, (void *)arg, sz); + if (result) return result; + __get_user(val, &sm_alp->max_num); + if (val > 1) { + sz += ((val - 1) * + sizeof(struct scsimon_att_dev)); + result = verify_area(VERIFY_WRITE, + (void *)arg, sz); + if (result) return result; + } + sm_alop = (struct scsimon_att_list *) + kmalloc(sz, GFP_ATOMIC); + if (NULL == sm_alop) + return -ENOMEM; + memset(sm_alop, 0, sz); + sm_alop->max_num = val; + __get_user(sm_alop->match_event, &sm_alp->match_event); + __get_user(sm_alop->flags, &sm_alp->flags); + sm_read_att_list(sm_alop); + __copy_to_user((void *)arg, sm_alop, sz); + kfree((char *)sm_alop); + return 0; + } + case SCSIMON_GET_DET_LIST: + { + struct scsimon_det_list * sm_dlp = + (struct scsimon_det_list *)arg; + struct scsimon_det_list * sm_dlop; + size_t sz = sizeof(struct scsimon_det_list); + + result = verify_area(VERIFY_WRITE, (void *)arg, sz); + if (result) return result; + __get_user(val, &sm_dlp->max_num); + if (val > 1) { + sz += ((val - 1) * + sizeof(struct scsimon_det_dev)); + result = verify_area(VERIFY_WRITE, + (void *)arg, sz); + if (result) return result; + } + sm_dlop = (struct scsimon_det_list *) + kmalloc(sz, GFP_ATOMIC); + if (NULL == sm_dlop) + return -ENOMEM; + memset(sm_dlop, 0, sz); + sm_dlop->max_num = val; + __get_user(sm_dlop->match_event, &sm_dlp->match_event); + __get_user(sm_dlop->flags, &sm_dlp->flags); + sm_read_det_list(sm_dlop); + __copy_to_user((void *)arg, sm_dlop, sz); + kfree((char *)sm_dlop); + return 0; + } + case SCSIMON_GET_HOST_LIST: + { + struct scsimon_host_list * sm_hlp = + (struct scsimon_host_list *)arg; + struct scsimon_host_list * sm_hlop; + size_t sz = sizeof(struct scsimon_host_list); + + result = verify_area(VERIFY_WRITE, (void *)arg, sz); + if (result) return result; + __get_user(val, &sm_hlp->max_num); + if (val > 1) { + sz += ((val - 1) * + sizeof(struct scsimon_host)); + result = verify_area(VERIFY_WRITE, + (void *)arg, sz); + if (result) return result; + } + sm_hlop = (struct scsimon_host_list *) + kmalloc(sz, GFP_ATOMIC); + if (NULL == sm_hlop) + return -ENOMEM; + memset(sm_hlop, 0, sz); + sm_hlop->max_num = val; + __get_user(sm_hlop->host, &sm_hlp->host); + __get_user(sm_hlop->flags, &sm_hlp->flags); + sm_read_host_list(sm_hlop); + __copy_to_user((void *)arg, sm_hlop, sz); + kfree((char *)sm_hlop); + return 0; + } + case SCSIMON_SEND_HOST_IOCTL: + { + struct scsimon_host_ioctl hio; + size_t sz = sizeof(struct scsimon_host_ioctl); + struct Scsi_Host * shp; + Scsi_Device dummy_sd; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + result = verify_area(VERIFY_READ, (void *)arg, sz); + if (result) return result; + __copy_from_user(&hio, (void *)arg, sz); + memset(&dummy_sd, 0, sizeof(dummy_sd)); + for (shp = scsi_hostlist; shp; shp = shp->next) { + if (hio.host != shp->host_no) + continue; + dummy_sd.host = shp; + if (shp->hostt->ioctl) + return shp->hostt->ioctl(&dummy_sd, + hio.request, hio.arg); + else + return -EIO; + } + return -ENODEV; + } + case SCSIMON_SET_ONLINE_STATE: + { + struct scsimon_online_state sm_os; + size_t sz = sizeof(struct scsimon_online_state); + Sm_attached * sap; + + result = verify_area(VERIFY_READ, (void *)arg, sz); + if (result) return result; + __copy_from_user(&sm_os, (void *)arg, sz); + if ((sm_os.online_state != 0) && + (sm_os.online_state != 1)) + return 0; + write_lock_irqsave(&scsimon_lock, iflags); + for (sap = sm_att_rootp; sap; sap = sap->next_att) { + if (sm_os.att_event == sap->event_count) + break; + } + if (sap && sap->device) { + if (!capable(CAP_SYS_ADMIN) || + !capable(CAP_SYS_RAWIO)) + result = -EACCES; + else { + sap->device->online = + sm_os.online_state; + result = 0; + } + } + else + result = -ENODEV; + write_unlock_irqrestore(&scsimon_lock, iflags); + return result; + } + default: + return -ENOTTY; + } +} + +/* Use POLLIN for attach, POLLHUP for detach and a read() clears flags */ +static unsigned int scsimon_poll(struct file * filp, poll_table * wait) +{ + unsigned int res = 0; + Sm_fd * sfp; + + if (! (sfp = (Sm_fd *)filp->private_data)) + return POLLERR; + if (sm_flag_attached) + res = POLLIN | POLLRDNORM; + if (sm_flag_detached) + res |= POLLHUP; + SCSI_LOG_TIMEOUT(3, printk("scsimon_poll: res=0x%x\n", (int)res)); + return res; +} + +static int scsimon_fasync(int fd, struct file * filp, int mode) +{ + int retval; + Sm_fd * sfp; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_fasync: mode=%d\n", mode)); + if (! (sfp = (Sm_fd *)filp->private_data)) + return -ENXIO; + retval = fasync_helper(fd, filp, mode, &sfp->async_qp); + return (retval < 0) ? retval : 0; +} + +static int scsimon_detect(Scsi_Device * scsidp) +{ + return 1; +} + +/* Driver initialization */ +static int scsimon_init() +{ + SCSI_LOG_TIMEOUT(3, printk("scsimon_init\n")); + return 0; +} + +static int scsimon_attach(Scsi_Device * scsidp) +{ + unsigned long iflags; + Sm_attached * sap; + Sm_hotinfo shi; + Scsi_Device * sdp; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_attach: scsidp=%p\n", scsidp)); + write_lock_irqsave(&scsimon_lock, iflags); + sap = (Sm_attached *)kmalloc(sizeof(Sm_attached), GFP_ATOMIC); + if (NULL == sap) { + scsidp->attached--; + write_unlock_irqrestore(&scsimon_lock, iflags); + printk(KERN_WARNING "scsimon_attach: no kernel memory\n"); + return 1; + } + memset(sap, 0, sizeof(Sm_attached)); + memset(&shi, 0, sizeof(Sm_hotinfo)); + sm_event_count++; + sap->event_count = sm_event_count; + shi.action = 0; /* attach */ + shi.event_attached = sap->event_count; + sap->time_attached = jiffies; + sap->device = scsidp; + sap->host = scsidp->host->host_no; + shi.host = sap->host; + sap->bus = scsidp->channel; + shi.bus = sap->bus; + sap->target = scsidp->id; + shi.target = sap->target; + sap->lun = scsidp->lun; + shi.lun = sap->lun; + sdp = sap->device; + if (sdp->vendor) + memcpy(shi.vendor, sdp->vendor, sizeof(shi.vendor)); + if (sdp->model) + memcpy(shi.model, sdp->model, sizeof(shi.model)); + if (sdp->rev) + memcpy(shi.rev, sdp->rev, sizeof(shi.rev)); + shi.scsi_type = sdp->type; + shi.removable = sdp->removable; + shi.emulated = sdp->host->hostt->emulated; + shi.access_count = sdp->access_count; + shi.writeable = sdp->writeable; + shi.lockable = sdp->lockable; + + if (sm_att_rootp) { /* postpend to list */ + Sm_attached * xap = sm_att_rootp; + while (xap->next_att) + xap = xap->next_att; + xap->next_att = sap; + } + else + sm_att_rootp = sap; + + sm_flag_attached = 1; + scsimon_template.nr_dev++; /* currently attached devices */ + scsimon_template.dev_noticed++;/* total attachment count */ + write_unlock_irqrestore(&scsimon_lock, iflags); + sm_call_policy(&shi); + return 0; +} + +static void scsimon_finish(void) +{ + SCSI_LOG_TIMEOUT(3, printk("scsimon_finish\n")); +} + +static void scsimon_detach(Scsi_Device * scsidp) +{ + unsigned long iflags; + Sm_attached * sap; + Sm_attached * psap = NULL; + Sm_detached * sep; + Scsi_Device * sdp; + Sm_hotinfo shi; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_detach: scsidp=%p\n", scsidp)); + write_lock_irqsave(&scsimon_lock, iflags); + for (sap = sm_att_rootp; sap; sap = sap->next_att) { + if (scsidp == sap->device) + break; + psap = sap; + } + sep = (Sm_detached *)kmalloc(sizeof(Sm_detached), GFP_ATOMIC); + if ((NULL == sap) || (NULL == sep)) { + write_unlock_irqrestore(&scsimon_lock, iflags); + printk(KERN_WARNING "scsimon_detach: missing attach or " + "no kernel memory\n"); + return; + } + memset(sep, 0, sizeof(Sm_detached)); + memset(&shi, 0, sizeof(Sm_hotinfo)); + shi.action = 1; /* flags detach */ + sm_event_count++; + /* xfer from alist element to new dlist element */ + sep->host = sap->host; + shi.host = sep->host; + sep->bus = sap->bus; + shi.bus = sep->bus; + sep->target = sap->target; + shi.target = sep->target; + sep->lun = sap->lun; + shi.lun = sep->lun; + sdp = sap->device; + if (sdp->vendor) + memcpy(sep->vendor, sdp->vendor, sizeof(sep->vendor)); + memcpy(shi.vendor, sep->vendor, sizeof(shi.vendor)); + if (sdp->model) + memcpy(sep->model, sdp->model, sizeof(sep->model)); + memcpy(shi.model, sep->model, sizeof(shi.model)); + if (sdp->rev) + memcpy(sep->rev, sdp->rev, sizeof(sep->rev)); + memcpy(shi.rev, sep->rev, sizeof(shi.rev)); + if (sdp->host->hostt->name) + strncpy(sep->host_name, sdp->host->hostt->name, + sizeof(sep->host_name)); + if (sdp->host->hostt->info) + strncpy(sep->host_info, sdp->host->hostt->info(sdp->host), + sizeof(sep->host_info)); + sep->scsi_type = sdp->type; + shi.scsi_type = sep->scsi_type; + sep->scsi_level = sdp->scsi_level; + if (sep->scsi_level > 1) + --sep->scsi_level; + sep->removable = sdp->removable; + shi.removable = sep->removable; + sep->emulated = sdp->host->hostt->emulated; + shi.emulated = sep->emulated; + sep->access_count = sdp->access_count; + shi.access_count = sep->access_count; + sep->writeable = sdp->writeable; + shi.writeable = sep->writeable; + sep->changed = sdp->changed; + sep->lockable = sdp->lockable; + shi.lockable = sep->lockable; + sep->online = sdp->online; + + sep->event_count = sm_event_count; + shi.event_detached = sep->event_count; + sep->event_attached = sap->event_count; + shi.event_attached = sep->event_attached; + sep->time_detached = jiffies; + + if (NULL == psap) + sm_att_rootp = sap->next_att; + else + psap->next_att = sap->next_att; + kfree((char *)sap); + + sep->next_det = sm_det_rootp; /* prepend most recent to list */ + sm_det_rootp = sep; + + sm_flag_detached = 1; + scsidp->attached--; + scsimon_template.nr_dev--; /* currently attached devices */ + scsimon_template.dev_max++; /* total detachment count */ + + sm_trunc_dlist(sm_max_detached_elems); + write_unlock_irqrestore(&scsimon_lock, iflags); + sm_call_policy(&shi); + return; +} + +static void sm_trunc_alist(int fromPos) +{ + Sm_attached * sap = sm_att_rootp; + Sm_attached * psap = NULL; + Sm_attached * nsap; + int k; + + for (k = 0; ((k < fromPos) && sap); ++k, sap = sap->next_att) + psap = sap; + if (sap) { + while (sap) { + nsap = sap->next_att; + kfree((char *)sap); + sap = nsap; + } + if (NULL == psap) + sm_att_rootp = NULL; + else + psap->next_att = NULL; + } +} + +static void sm_trunc_dlist(int fromPos) +{ + Sm_detached * sep = sm_det_rootp; + Sm_detached * psep = NULL; + Sm_detached * nsep; + int k; + + for (k = 0; ((k < fromPos) && sep); ++k, sep = sep->next_det) + psep = sep; + if (sep) { + while (sep) { + nsep = sep->next_det; + kfree((char *)sep); + sep = nsep; + } + if (NULL == psep) + sm_det_rootp = NULL; + else + psep->next_det = NULL; + } +} + +static Sm_fd * sm_add_sfp() +{ + Sm_fd * sfp; + + if ((sfp = (Sm_fd *)kmalloc(sizeof(Sm_fd), GFP_ATOMIC))) + memset(sfp, 0, sizeof(Sm_fd)); + return sfp; +} + +static void sm_remove_sfp(Sm_fd * sfp) +{ + kfree((char *)sfp); +} + +static void sm_read_state(struct scsimon_state * ssp) +{ + Sm_detached * sep; + struct Scsi_Host * shp; + int k; + unsigned int high_host = 0; + unsigned long iflags; + + read_lock_irqsave(&scsimon_lock, iflags); + jiffies_to_timespec(sm_init_time, &ssp->init_time); + ssp->devices_attached = scsimon_template.nr_dev; + ssp->total_attachs = scsimon_template.dev_noticed; + ssp->total_detachs = scsimon_template.dev_max; + for (k = 0, sep = sm_det_rootp; sep; k++, sep = sep->next_det) + ; + ssp->detach_list_len = (unsigned int)k; + ssp->event_count = sm_event_count; + ssp->lock_mod_state = sm_locked_down; + for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { + if (shp->host_no > high_host) + high_host = shp->host_no; + } + ssp->count_hosts = k; + ssp->high_host = high_host; + read_unlock_irqrestore(&scsimon_lock, iflags); +} + +static void sm_read_att_elem(struct scsimon_att_dev * sm_ap, + Sm_attached * sap) +{ + Scsi_Device * sdp = sap->device; + + sm_ap->att_event = sap->event_count; + jiffies_to_timespec(sap->time_attached, &sm_ap->att_time); + sm_ap->d.host = sap->host; + sm_ap->d.bus = sap->bus; + sm_ap->d.target = sap->target; + sm_ap->d.lun = sap->lun; + memcpy(sm_ap->d.vendor, sdp->vendor, sizeof(sm_ap->d.vendor)); + memcpy(sm_ap->d.model, sdp->model, sizeof(sm_ap->d.model)); + memcpy(sm_ap->d.rev, sdp->rev, sizeof(sm_ap->d.rev)); + sm_ap->d.scsi_type = sdp->type; + sm_ap->d.scsi_level = sdp->scsi_level; + if (sm_ap->d.scsi_level > 1) + --sm_ap->d.scsi_level; + sm_ap->d.removable = sdp->removable; + sm_ap->d.emulated = sdp->host->hostt->emulated; + sm_ap->d.access_count = sdp->access_count; + sm_ap->d.writeable = sdp->writeable; + sm_ap->d.changed = sdp->changed; + sm_ap->d.lockable = sdp->lockable; + sm_ap->d.online = sdp->online; +} + +static void sm_read_att_list(struct scsimon_att_list * alp) +{ + Sm_attached * sap; + int k; + unsigned long iflags; + + read_lock_irqsave(&scsimon_lock, iflags); + alp->curr_event = sm_event_count; + for (k = 0, sap = sm_att_rootp; (k < alp->max_num) && sap; + sap = sap->next_att) { + if (alp->match_event > 0) { + if (alp->match_event == sap->event_count) { + k = 1; + sm_read_att_elem(&alp->arr[0], sap); + break; + } + continue; + } + sm_read_att_elem(&alp->arr[k], sap); + k++; + } + alp->num_out = k; + read_unlock_irqrestore(&scsimon_lock, iflags); +} + +static void sm_read_det_elem(struct scsimon_det_dev * sm_dp, + Sm_detached * sep) +{ + sm_dp->att_event = sep->event_attached; + sm_dp->det_event = sep->event_count; + jiffies_to_timespec(sep->time_detached, &sm_dp->det_time); + memcpy(sm_dp->host_name, sep->host_name, sizeof(sm_dp->host_name)); + memcpy(sm_dp->host_info, sep->host_info, sizeof(sm_dp->host_info)); + sm_dp->d.host = sep->host; + sm_dp->d.bus = sep->bus; + sm_dp->d.target = sep->target; + sm_dp->d.lun = sep->lun; + memcpy(sm_dp->d.vendor, sep->vendor, sizeof(sm_dp->d.vendor)); + memcpy(sm_dp->d.model, sep->model, sizeof(sm_dp->d.model)); + memcpy(sm_dp->d.rev, sep->rev, sizeof(sm_dp->d.rev)); + sm_dp->d.scsi_type = sep->scsi_type; + sm_dp->d.scsi_level = sep->scsi_level; + sm_dp->d.removable = sep->removable; + sm_dp->d.emulated = sep->emulated; + sm_dp->d.access_count = sep->access_count; + sm_dp->d.writeable = sep->writeable; + sm_dp->d.changed = sep->changed; + sm_dp->d.lockable = sep->lockable; + sm_dp->d.online = sep->online; +} + +static void sm_read_det_list(struct scsimon_det_list * dlp) +{ + Sm_detached * sep; + int k; + unsigned long iflags; + + read_lock_irqsave(&scsimon_lock, iflags); + dlp->curr_event = sm_event_count; + for (k = 0, sep = sm_det_rootp; (k < dlp->max_num) && sep; + sep = sep->next_det) { + if (dlp->match_event > 0) { + if (dlp->match_event == sep->event_attached) { + k = 1; + sm_read_det_elem(&dlp->arr[0], sep); + break; + } + continue; + } + sm_read_det_elem(&dlp->arr[k], sep); + k++; + } + dlp->num_out = k; + read_unlock_irqrestore(&scsimon_lock, iflags); +} + +static void sm_read_host_elem(struct scsimon_host * sm_hp, + struct Scsi_Host * shp) +{ + sm_hp->host = shp->host_no; + sm_hp->host_scsi_id = shp->this_id; + sm_hp->emulated = shp->hostt->emulated; + /* sm_hp->is_module = shp->loaded_as_module; */ + if (shp->hostt->name) + strncpy(sm_hp->host_name, shp->hostt->name, + sizeof(sm_hp->host_name)); + if (shp->hostt->info) + strncpy(sm_hp->host_info, shp->hostt->info(shp), + sizeof(sm_hp->host_info)); +} + +static void sm_read_host_list(struct scsimon_host_list * hlp) +{ + struct Scsi_Host * shp; + int k; + unsigned long iflags; + int match; + + match = (SCSIMON_HOST_FLAG_MATCH & hlp->flags) ? 1 : 0; + read_lock_irqsave(&scsimon_lock, iflags); + hlp->curr_event = sm_event_count; + for (k = 0, shp = scsi_hostlist; shp && (k < hlp->max_num); + shp = shp->next) { + if (match) { + if (shp->host_no == hlp->host) { + sm_read_host_elem(&hlp->arr[0], shp); + k = 1; + break; + } + continue; + } + sm_read_host_elem(&hlp->arr[k], shp); + k++; + } + hlp->num_out = k; + read_unlock_irqrestore(&scsimon_lock, iflags); +} + +#ifdef CONFIG_HOTPLUG + +static void sm_call_policy(Sm_hotinfo * hip) +{ + char *argv [3], **envp, *buf, *scratch; + int k = 0, value; + + if (!hotplug_path [0]) + return; + if (in_interrupt ()) { + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: in_interrupt\n")); + return; + } + if (! current->fs->root) { + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: no root fs\n")); + return; + } + if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) { + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: ENOMEM\n")); + return; + } + if (!(buf = kmalloc (512, GFP_KERNEL))) { + kfree (envp); + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: ENOMEM\n")); + return; + } + + /* only one standardized param to hotplug command: type */ + argv [0] = hotplug_path; + argv [1] = "scsi"; + argv [2] = 0; + + /* minimal command environment */ + envp [k++] = "HOME=/"; + envp [k++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + + /* extensible set of named bus-specific parameters, + * supporting multiple driver selection algorithms. + */ + scratch = buf; + + /* action: add, remove */ + envp [k++] = scratch; + scratch += sprintf (scratch, "ACTION=%s", + hip->action ? "remove" : "add") + 1; + + /* per-device configuration hacks are common */ + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_HOST=%u", hip->host) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_BUS=%u", hip->bus) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_TARGET=%u", hip->target) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_LUN=%u", hip->lun) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_VENDOR=%.8s", hip->vendor) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_MODEL=%.16s", hip->model) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_REV=%.4s", hip->rev) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_TYPE=%d", hip->scsi_type) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_REMOVABLE=%d", hip->removable) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_EMULATED=%d", hip->emulated) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_WRITEABLE=%d", hip->writeable) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_LOCKABLE=%d", hip->lockable) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_ACCESS_COUNT=%d", + hip->access_count) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_EVENT_ATTACHED=%lu", + hip->event_attached) + 1; + if (1 == hip->action) { + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_EVENT_DETACHED=%lu", + hip->event_detached) + 1; + } + + envp [k++] = 0; + /* assert: (scratch - buf) < sizeof buf */ + + /* NOTE: user mode daemons can call the agents too */ + + value = call_usermodehelper (argv [0], argv, envp); + kfree (buf); + kfree (envp); + if (value != 0) { + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: " + "call_usermodehelper returned %d\n", value)); + } +} + +#else + +static void sm_call_policy (Sm_hotinfo * hip) { } + +#endif + +MODULE_AUTHOR("Douglas Gilbert"); +MODULE_DESCRIPTION("SCSI monitor (scsimon) driver"); + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +static int __init init_scsimon(void) +{ + int res; + + sm_init_time = jiffies; + res = scsi_register_device(&scsimon_template); + misc_register(&scsimon_miscdev); + return res; +} + +static void __exit exit_scsimon( void) +{ + misc_deregister(&scsimon_miscdev); + scsi_unregister_device(&scsimon_template); + sm_trunc_alist(0); + sm_trunc_dlist(0); +} + +module_init(init_scsimon); +module_exit(exit_scsimon); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/sd.c linux-2.5/drivers/scsi/sd.c --- linux-2.5.23/drivers/scsi/sd.c Wed Jun 19 03:11:49 2002 +++ linux-2.5/drivers/scsi/sd.c Tue Jun 18 20:00:13 2002 @@ -46,7 +46,6 @@ #include #include -#include #include #define MAJOR_NR SCSI_DISK0_MAJOR diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/sgiwd93.c linux-2.5/drivers/scsi/sgiwd93.c --- linux-2.5.23/drivers/scsi/sgiwd93.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/scsi/sgiwd93.c Fri May 10 01:27:40 2002 @@ -4,10 +4,13 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * 1999 Andrew R. Baker (andrewb@uab.edu) * - Support for 2nd SCSI controller on Indigo2 + * 2001 Florian Lohoff (flo@rfc822.org) + * - Delete HPC scatter gather (Read corruption on + * multiple disks) + * - Cleanup wback cache handling * * (In all truth, Jed Schimmel wrote all this code.) * - * $Id: sgiwd93.c,v 1.19 2000/02/04 07:40:47 ralf Exp $ */ #include #include @@ -36,32 +39,13 @@ struct hpc_chunk { struct hpc_dma_desc desc; - unsigned long padding; + u32 _padding; /* align to quadword boundary */ }; struct Scsi_Host *sgiwd93_host = NULL; struct Scsi_Host *sgiwd93_host1 = NULL; /* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */ -static inline void write_wd33c93_count(const wd33c93_regs regs, - unsigned long value) -{ - *regs.SASR = WD_TRANSFER_COUNT_MSB; - *regs.SCMD = ((value >> 16) & 0xff); - *regs.SCMD = ((value >> 8) & 0xff); - *regs.SCMD = ((value >> 0) & 0xff); -} - -static inline unsigned long read_wd33c93_count(const wd33c93_regs regs) -{ - unsigned long value; - - *regs.SASR = WD_TRANSFER_COUNT_MSB; - value = (*regs.SCMD << 16); - value |= (*regs.SCMD << 8); - value |= (*regs.SCMD << 0); - return value; -} /* XXX woof! */ static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs) @@ -82,7 +66,6 @@ unsigned long physaddr; unsigned long count; - dma_cache_wback_inv((unsigned long)addr,len); physaddr = PHYSADDR(addr); while (len) { /* @@ -101,7 +84,6 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata; - const wd33c93_regs regs = hdata->regs; struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; @@ -112,46 +94,17 @@ hdata->dma_dir = datainp; - if(cmd->SCp.buffers_residual) { - struct scatterlist *slp = cmd->SCp.buffer; - int i, totlen = 0; + /* + * wd33c93 shouldn't pass us bogus dma_setups, but + * it does:-( The other wd33c93 drivers deal with + * it the same way (which isn't that obvious). + * IMHO a better fix would be, not to do these + * dma setups in the first place + */ + if (cmd->SCp.ptr == NULL) + return 1; -#ifdef DEBUG_DMA - printk("SCLIST<"); -#endif - for(i = 0; i <= cmd->SCp.buffers_residual; i++) { -#ifdef DEBUG_DMA - printk("[%p,%d]", - page_address(slp[i].page) + slp[i].offset, - slp[i].length); -#endif - fill_hpc_entries (&hcp, - page_address(slp[i].page) + slp[i].offset, - slp[i].length); - totlen += slp[i].length; - } -#ifdef DEBUG_DMA - printk(">tlen<%d>", totlen); -#endif - hdata->dma_bounce_len = totlen; /* a trick... */ - write_wd33c93_count(regs, totlen); - } else { - /* Non-scattered dma. */ -#ifdef DEBUG_DMA - printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual); -#endif - /* - * wd33c93 shouldn't pass us bogus dma_setups, but - * it does:-( The other wd33c93 drivers deal with - * it the same way (which isn't that obvious). - * IMHO a better fix would be, not to do these - * dma setups in the first place - */ - if (cmd->SCp.ptr == NULL) - return 1; - fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); - write_wd33c93_count(regs, cmd->SCp.this_residual); - } + fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); /* To make sure, if we trip an HPC bug, that we transfer * every single byte, we tag on an extra zero length dma @@ -166,10 +119,14 @@ /* Start up the HPC. */ hregs->ndptr = PHYSADDR(hdata->dma_bounce_buffer); - if(datainp) + if(datainp) { + dma_cache_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE); - else + } else { + dma_cache_wback_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR); + } + return 0; } @@ -177,7 +134,6 @@ int status) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata; - const wd33c93_regs regs = hdata->regs; struct hpc3_scsiregs *hregs; if (!SCpnt) @@ -197,44 +153,6 @@ } hregs->ctrl = 0; - /* See how far we got and update scatterlist state if necessary. */ - if(SCpnt->SCp.buffers_residual) { - struct scatterlist *slp = SCpnt->SCp.buffer; - int totlen, wd93_residual, transferred, i; - - /* Yep, we were doing the scatterlist thang. */ - totlen = hdata->dma_bounce_len; - wd93_residual = read_wd33c93_count(regs); - transferred = totlen - wd93_residual; - -#ifdef DEBUG_DMA - printk("tlen<%d>resid<%d>transf<%d> ", - totlen, wd93_residual, transferred); -#endif - - /* Avoid long winded partial-transfer search for common case. */ - if(transferred != totlen) { - /* This is the nut case. */ -#ifdef DEBUG_DMA - printk("Jed was here..."); -#endif - for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) { - if(slp[i].length >= transferred) - break; - transferred -= slp[i].length; - } - } else { - /* This is the common case. */ -#ifdef DEBUG_DMA - printk("did it all..."); -#endif - i = SCpnt->SCp.buffers_residual; - } - SCpnt->SCp.buffer = &slp[i]; - SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i; - SCpnt->SCp.ptr = (char *) page_address(slp[i].page) + slp[i].offset; - SCpnt->SCp.this_residual = slp[i].length; - } #ifdef DEBUG_DMA printk("\n"); #endif @@ -264,6 +182,9 @@ }; hcp--; hcp->desc.pnext = PHYSADDR(buf); + + /* Force flush to memory */ + dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); } int __init sgiwd93_detect(Scsi_Host_Template *SGIblows) @@ -273,8 +194,8 @@ struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1; struct WD33C93_hostdata *hdata; struct WD33C93_hostdata *hdata1; - uchar *buf; wd33c93_regs regs; + uchar *buf; if(called) return 0; /* Should bitch on the console about this... */ @@ -294,10 +215,10 @@ return 0; } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG0 | 0x03 | KSEG1 */ - regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc0003); - regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc0007); + regs.SASR = (unsigned char*) KSEG1ADDR (0x1fbc0003); + regs.SCMD = (unsigned char*) KSEG1ADDR (0x1fbc0007); wd33c93_init(sgiwd93_host, regs, dma_setup, dma_stop, WD33C93_FS_16_20); hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata; @@ -329,17 +250,16 @@ return 1; /* We registered host0 so return success*/ } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG1 | 0x03 | KSEG1 */ - regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc8003); - regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc8007); + regs.SASR = (unsigned char*) KSEG1ADDR(0x1fbc8003); + regs.SCMD = (unsigned char*) KSEG1ADDR(0x1fbc8007); wd33c93_init(sgiwd93_host1, regs, dma_setup, dma_stop, - WD33C93_FS_16_20); + WD33C93_FS_16_20); hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata; hdata1->no_sync = 0; hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) { printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).\n", SGI_WD93_1_IRQ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/sim710.h linux-2.5/drivers/scsi/sim710.h --- linux-2.5.23/drivers/scsi/sim710.h Wed Jun 19 03:11:55 2002 +++ linux-2.5/drivers/scsi/sim710.h Fri Jun 7 02:36:08 2002 @@ -23,8 +23,8 @@ #include -#define SIM710_SCSI { proc_name: "sim710", \ - name: "Simple 53c710", \ +#define SIM710_SCSI { proc_name: "sim710", \ + name: "53c710", \ detect: sim710_detect, \ release: sim710_release, \ queuecommand: sim710_queuecommand, \ @@ -413,7 +413,7 @@ #define CTEST3_800_FM 0x02 /* Fetch mode pin */ /* bit 0 is reserved on 800 series chips */ -#define CTEST4_REG_400 (0x18^bE) /* Chip test 4 rw */ +#define CTEST4_REG_700 (0x18^bE) /* Chip test 4 rw */ #define CTEST4_REG_800 (0x21^bE) /* Chip test 4 rw */ /* 0x80 is reserved on 700 series chips */ #define CTEST4_800_BDIS 0x80 /* Burst mode disable */ @@ -791,6 +791,20 @@ #define ISTAT_REG ISTAT_REG_700 #define SCRATCH_REG SCRATCHB_REG_10 +#define ADDER_REG ADDER_REG_10 +#define SIEN_REG SIEN_REG_700 +#define SDID_REG SDID_REG_700 +#define CTEST0_REG CTEST0_REG_700 +#define CTEST1_REG CTEST1_REG_700 +#define CTEST2_REG CTEST2_REG_700 +#define CTEST3_REG CTEST3_REG_700 +#define CTEST4_REG CTEST4_REG_700 +#define CTEST5_REG CTEST5_REG_700 +#define CTEST6_REG CTEST6_REG_700 +#define SODL_REG SODL_REG_700 +#define SBDL_REG SBDL_REG_700 +#define SIDL_REG SIDL_REG_700 +#define LCRC_REG LCRC_REG_10 #ifdef MEM_MAPPED #define NCR_read8(address) \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/sim710.scr linux-2.5/drivers/scsi/sim710.scr --- linux-2.5.23/drivers/scsi/sim710.scr Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/scsi/sim710.scr Fri Jun 7 02:36:08 2002 @@ -15,15 +15,12 @@ ABSOLUTE reselected_identify = 0 ABSOLUTE msgin_buf = 0 +ABSOLUTE msg_reject = 0 +ABSOLUTE test1_src = 0 +ABSOLUTE test1_dst = 0 /* Interrupt values passed back to driver */ -ABSOLUTE int_bad_extmsg1a = 0xab930000 -ABSOLUTE int_bad_extmsg1b = 0xab930001 -ABSOLUTE int_bad_extmsg2a = 0xab930002 -ABSOLUTE int_bad_extmsg2b = 0xab930003 -ABSOLUTE int_bad_extmsg3a = 0xab930004 -ABSOLUTE int_bad_extmsg3b = 0xab930005 ABSOLUTE int_bad_msg1 = 0xab930006 ABSOLUTE int_bad_msg2 = 0xab930007 ABSOLUTE int_bad_msg3 = 0xab930008 @@ -47,9 +44,9 @@ ABSOLUTE int_disc2 = 0xab93001a ABSOLUTE int_disc3 = 0xab93001b ABSOLUTE int_not_rej = 0xab93001c +ABSOLUTE int_test1 = 0xab93001d - -/* Bit field settings used to record status in SCRATCH */ +/* Bit field settings used to record status in SCRATCH0 */ ABSOLUTE had_select = 0x01 ABSOLUTE had_msgout = 0x02 @@ -60,6 +57,9 @@ ABSOLUTE had_msgin = 0x40 ABSOLUTE had_extmsg = 0x80 +/* Bit field settings used to record status in SCRATCH1 */ + +ABSOLUTE did_reject = 0x01 /* These scripts are heavily based on the examples in the NCR 53C710 * Programmer's Guide (Preliminary). @@ -68,7 +68,6 @@ ENTRY do_select do_select: CLEAR TARGET - MOVE SCRATCH0 & 0 TO SCRATCH0 ; Enable selection timer MOVE CTEST7 & 0xef TO CTEST7 SELECT ATN FROM dsa_select, reselect @@ -401,17 +400,23 @@ MOVE SCRATCH0 | had_extmsg TO SCRATCH0 CLEAR ACK MOVE 1, msgin_buf + 1, WHEN MSG_IN - JUMP ext_msg1a, IF 0x03 - INT int_bad_extmsg1a -ext_msg1a: + JUMP reject_msg1, IF NOT 0x03 ; Only handle SDTR CLEAR ACK MOVE 1, msgin_buf + 2, WHEN MSG_IN - JUMP ext_msg1b, IF 0x01 ; Must be SDTR - INT int_bad_extmsg1b -ext_msg1b: + JUMP reject_msg1, IF NOT 0x01 ; Only handle SDTR CLEAR ACK MOVE 2, msgin_buf + 3, WHEN MSG_IN INT int_msg_sdtr1 +reject_msg1: + MOVE SCRATCH1 | did_reject TO SCRATCH1 + SET ATN + CLEAR ACK + JUMP reject_msg1a, WHEN NOT MSG_IN + MOVE 1, msgin_buf + 7, WHEN MSG_IN + JUMP reject_msg1 +reject_msg1a: + MOVE 1, msg_reject, WHEN MSG_OUT + JUMP redo_msgin1 disc1: CLEAR ACK ENTRY wait_disc1 @@ -446,17 +451,23 @@ MOVE SCRATCH0 | had_extmsg TO SCRATCH0 CLEAR ACK MOVE 1, msgin_buf + 1, WHEN MSG_IN - JUMP ext_msg2a, IF 0x03 - INT int_bad_extmsg2a -ext_msg2a: + JUMP reject_msg2, IF NOT 0x03 ; Only handle SDTR CLEAR ACK MOVE 1, msgin_buf + 2, WHEN MSG_IN - JUMP ext_msg2b, IF 0x01 ; Must be SDTR - INT int_bad_extmsg2b -ext_msg2b: + JUMP reject_msg2, IF NOT 0x01 ; Only handle SDTR CLEAR ACK MOVE 2, msgin_buf + 3, WHEN MSG_IN INT int_msg_sdtr2 +reject_msg2: + MOVE SCRATCH1 | did_reject TO SCRATCH1 + SET ATN + CLEAR ACK + JUMP reject_msg2a, WHEN NOT MSG_IN + MOVE 1, msgin_buf + 7, WHEN MSG_IN + JUMP reject_msg2 +reject_msg2a: + MOVE 1, msg_reject, WHEN MSG_OUT + JUMP redo_msgin2 disc2: CLEAR ACK ENTRY wait_disc2 @@ -491,17 +502,23 @@ MOVE SCRATCH0 | had_extmsg TO SCRATCH0 CLEAR ACK MOVE 1, msgin_buf + 1, WHEN MSG_IN - JUMP ext_msg3a, IF 0x03 - INT int_bad_extmsg3a -ext_msg3a: + JUMP reject_msg3, IF NOT 0x03 ; Only handle SDTR CLEAR ACK MOVE 1, msgin_buf + 2, WHEN MSG_IN - JUMP ext_msg3b, IF 0x01 ; Must be SDTR - INT int_bad_extmsg3b -ext_msg3b: + JUMP reject_msg3, IF NOT 0x01 ; Only handle SDTR CLEAR ACK MOVE 2, msgin_buf + 3, WHEN MSG_IN INT int_msg_sdtr3 +reject_msg3: + MOVE SCRATCH1 | did_reject TO SCRATCH1 + SET ATN + CLEAR ACK + JUMP reject_msg3a, WHEN NOT MSG_IN + MOVE 1, msgin_buf + 7, WHEN MSG_IN + JUMP reject_msg3 +reject_msg3a: + MOVE 1, msg_reject, WHEN MSG_OUT + JUMP redo_msgin3 disc3: CLEAR ACK ENTRY wait_disc3 @@ -551,4 +568,9 @@ selected: INT int_selected + +ENTRY test1 +test1: + MOVE MEMORY 4, test1_src, test1_dst + INT int_test1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/sim710_u.h linux-2.5/drivers/scsi/sim710_u.h --- linux-2.5.23/drivers/scsi/sim710_u.h Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/scsi/sim710_u.h Fri Jun 7 02:36:09 2002 @@ -1,3 +1,4 @@ +#undef A_did_reject #undef A_dsa_cmnd #undef A_dsa_datain #undef A_dsa_dataout @@ -14,12 +15,6 @@ #undef A_had_msgout #undef A_had_select #undef A_had_status -#undef A_int_bad_extmsg1a -#undef A_int_bad_extmsg1b -#undef A_int_bad_extmsg2a -#undef A_int_bad_extmsg2b -#undef A_int_bad_extmsg3a -#undef A_int_bad_extmsg3b #undef A_int_bad_msg1 #undef A_int_bad_msg2 #undef A_int_bad_msg3 @@ -43,8 +38,12 @@ #undef A_int_sel_not_cmd #undef A_int_selected #undef A_int_status_not_msgin +#undef A_int_test1 +#undef A_msg_reject #undef A_msgin_buf #undef A_reselected_identify +#undef A_test1_dst +#undef A_test1_src #undef Ent_do_select #undef Ent_done_ident #undef Ent_end_data_trans @@ -61,6 +60,7 @@ #undef Ent_resume_msgin3b #undef Ent_resume_pmm #undef Ent_resume_rej_ident +#undef Ent_test1 #undef Ent_wait_disc1 #undef Ent_wait_disc2 #undef Ent_wait_disc3 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/sun3_NCR5380.c linux-2.5/drivers/scsi/sun3_NCR5380.c --- linux-2.5.23/drivers/scsi/sun3_NCR5380.c Wed Jun 19 03:11:47 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.23/drivers/scsi/sun3_scsi.c linux-2.5/drivers/scsi/sun3_scsi.c --- linux-2.5.23/drivers/scsi/sun3_scsi.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/scsi/sun3_scsi.c Mon Jun 17 22:31:28 2002 @@ -79,8 +79,10 @@ #include "sun3_scsi.h" #include "NCR5380.h" +/* #define OLDDMA */ + #define USE_WRAPPER -#define RESET_BOOT +/*#define RESET_BOOT */ #define DRIVER_SETUP #define NDEBUG 0 @@ -93,7 +95,7 @@ #undef DRIVER_SETUP #endif -#undef SUPPORT_TAGS +/* #define SUPPORT_TAGS */ #define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI ); @@ -125,7 +127,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; @@ -259,7 +263,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)); @@ -309,6 +313,11 @@ dregs->fifo_count = 0; called = 1; + +#ifdef RESET_BOOT + sun3_scsi_reset_boot(instance); +#endif + return 1; } @@ -340,7 +349,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, @@ -360,7 +369,7 @@ barrier(); /* switch on SCSI IRQ again */ - sun3_enable_irq( IRQ_SUN3_SCSI ); +// sun3_enable_irq( IRQ_SUN3_SCSI ); printk( " done\n" ); } @@ -426,8 +435,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 @@ -453,7 +466,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, @@ -532,10 +544,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) @@ -548,6 +560,7 @@ } } +#endif count = sun3scsi_dma_count(default_instance); #ifdef OLDDMA @@ -587,6 +600,7 @@ } dvma_unmap(sun3_dma_orig_addr); + sun3_dma_orig_addr = NULL; #endif sun3_udc_write(UDC_RESET, UDC_CSR); dregs->fifo_count = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/scsi/sym53c8xx.c linux-2.5/drivers/scsi/sym53c8xx.c --- linux-2.5.23/drivers/scsi/sym53c8xx.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/scsi/sym53c8xx.c Mon Jun 17 22:52:30 2002 @@ -14115,7 +14115,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.23/drivers/scsi/t128.c linux-2.5/drivers/scsi/t128.c --- linux-2.5.23/drivers/scsi/t128.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/scsi/t128.c Mon Jun 17 22:52:30 2002 @@ -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 @@ -122,276 +113,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.23/drivers/scsi/tmscsim.c linux-2.5/drivers/scsi/tmscsim.c --- linux-2.5.23/drivers/scsi/tmscsim.c Wed Jun 19 03:11:55 2002 +++ linux-2.5/drivers/scsi/tmscsim.c Mon Jun 17 22:52:30 2002 @@ -1445,7 +1445,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))) { @@ -2519,15 +2519,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.23/drivers/scsi/wd33c93.c linux-2.5/drivers/scsi/wd33c93.c --- linux-2.5.23/drivers/scsi/wd33c93.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/drivers/scsi/wd33c93.c Fri May 10 02:05:26 2002 @@ -1409,11 +1409,31 @@ -static void reset_wd33c93(struct Scsi_Host *instance) +void reset_wd33c93(struct Scsi_Host *instance) { struct WD33C93_hostdata *hostdata = (struct WD33C93_hostdata *)instance->hostdata; const wd33c93_regs regs = hostdata->regs; uchar sr; + +#ifdef CONFIG_SGI_IP22 +{ +int busycount = 0; +extern void sgiwd93_reset(unsigned long); + /* wait 'til the chip gets some time for us */ + while ((READ_AUX_STAT() & ASR_BSY) && busycount++ < 100) + udelay (10); + /* + * there are scsi devices out there, which manage to lock up + * the wd33c93 in a busy condition. In this state it won't + * accept the reset command. The only way to solve this is to + * give the chip a hardware reset (if possible). The code below + * does this for the SGI Indy, where this is possible + */ + /* still busy ? */ + if (READ_AUX_STAT() & ASR_BSY) + sgiwd93_reset(instance->base); /* yeah, give it the hard one */ +} +#endif write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF | instance->this_id | hostdata->clock_freq); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/sgi/char/Makefile linux-2.5/drivers/sgi/char/Makefile --- linux-2.5.23/drivers/sgi/char/Makefile Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/sgi/char/Makefile Fri May 31 02:44:03 2002 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -export-objs := newport.o shmiq.o sgicons.o usema.o +export-objs := newport.o rrm.o shmiq.o sgicons.o usema.o obj-y := newport.o shmiq.o sgicons.o usema.o streamable.o obj-$(CONFIG_SGI_SERIAL) += sgiserial.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/sgi/char/ds1286.c linux-2.5/drivers/sgi/char/ds1286.c --- linux-2.5.23/drivers/sgi/char/ds1286.c Wed Jun 19 03:11:52 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.23/drivers/sgi/char/sgiserial.c linux-2.5/drivers/sgi/char/sgiserial.c --- linux-2.5.23/drivers/sgi/char/sgiserial.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/sgi/char/sgiserial.c Fri Jun 7 02:36:09 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; @@ -1232,7 +1233,7 @@ tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.custom_divisor = info->custom_divisor; - return copy_to_user(retinfo,&tmp,sizeof(*retinfo)); + return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT: 0; } static int set_serial_info(struct sgi_serial * info, @@ -1883,7 +1884,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sgi_console_driver; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -1909,9 +1912,9 @@ callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); save_flags(flags); cli(); @@ -2010,7 +2013,7 @@ if (request_irq(zilog_irq, rs_interrupt, (SA_INTERRUPT), "Zilog8530", zs_chain)) - panic("Unable to attach zs intr\n"); + panic("Unable to attach zs intr"); restore_flags(flags); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/tc/lk201.c linux-2.5/drivers/tc/lk201.c --- linux-2.5.23/drivers/tc/lk201.c Wed Jun 19 03:11:59 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.23/drivers/tc/lk201.h linux-2.5/drivers/tc/lk201.h --- linux-2.5.23/drivers/tc/lk201.h Wed Jun 19 03:11:54 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.23/drivers/tc/zs.c linux-2.5/drivers/tc/zs.c --- linux-2.5.23/drivers/tc/zs.c Wed Jun 19 03:11:51 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.23/drivers/telephony/Config.help linux-2.5/drivers/telephony/Config.help --- linux-2.5.23/drivers/telephony/Config.help Wed Jun 19 03:11:58 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.23/drivers/telephony/Config.in linux-2.5/drivers/telephony/Config.in --- linux-2.5.23/drivers/telephony/Config.in Wed Jun 19 03:11:56 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.23/drivers/telephony/ixj.c linux-2.5/drivers/telephony/ixj.c --- linux-2.5.23/drivers/telephony/ixj.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/telephony/ixj.c Wed Jun 19 20:38:41 2002 @@ -274,8 +274,7 @@ #include "ixj.h" -#define TYPE(dev) (MINOR(dev) >> 4) -#define NUM(dev) (MINOR(dev) & 0xf) +#define NUM(dev) (minor(dev) & 0xf) static int ixjdebug; static int hertz = HZ; @@ -386,7 +385,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; @@ -800,24 +799,24 @@ ixj_DownloadG729 = regfunc; for (cnt = 0; cnt < IXJMAX; cnt++) { IXJ *j = get_ixj(cnt); - while(test_and_set_bit(cnt, (void *)&j->busyflags) != 0) { + while(test_and_set_bit(cnt, j->busyflags) != 0) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } ixj_DownloadG729(j, 0L); - clear_bit(cnt, &j->busyflags); + clear_bit(cnt, j->busyflags); } break; case TS85LOADER: ixj_DownloadTS85 = regfunc; for (cnt = 0; cnt < IXJMAX; cnt++) { IXJ *j = get_ixj(cnt); - while(test_and_set_bit(cnt, (void *)&j->busyflags) != 0) { + while(test_and_set_bit(cnt, j->busyflags) != 0) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } ixj_DownloadTS85(j, 0L); - clear_bit(cnt, &j->busyflags); + clear_bit(cnt, j->busyflags); } break; case PRE_READ: @@ -1258,7 +1257,7 @@ IXJ *j = (IXJ *)ptr; board = j->board; - if (j->DSPbase && atomic_read(&j->DSPWrite) == 0 && test_and_set_bit(board, (void *)&j->busyflags) == 0) { + if (j->DSPbase && atomic_read(&j->DSPWrite) == 0 && test_and_set_bit(board, j->busyflags) == 0) { ixj_perfmon(j->timerchecks); j->hookstate = ixj_hookstate(j); if (j->tone_state) { @@ -1269,7 +1268,7 @@ j->ex.bits.hookstate = 1; ixj_kill_fasync(j, SIG_HOOKSTATE, POLL_IN); } - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); ixj_add_timer(j); return; } @@ -1281,14 +1280,14 @@ if (j->tone_state == 1) { ixj_play_tone(j, j->tone_index); if (j->dsp.low == 0x20) { - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); ixj_add_timer(j); return; } } else { ixj_play_tone(j, 0); if (j->dsp.low == 0x20) { - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); ixj_add_timer(j); return; } @@ -1301,7 +1300,7 @@ if (j->flags.busytone) { ixj_busytone(j); if (j->dsp.low == 0x20) { - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); ixj_add_timer(j); return; } @@ -1309,7 +1308,7 @@ if (j->flags.ringback) { ixj_ringback(j); if (j->dsp.low == 0x20) { - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); ixj_add_timer(j); return; } @@ -1433,7 +1432,7 @@ } j->flags.cidring = 0; } - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); ixj_add_timer(j); return; } else { @@ -1462,7 +1461,7 @@ j->flags.cidring = 1; } } - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); ixj_add_timer(j); return; } @@ -1498,7 +1497,7 @@ if (j->ex.bytes) { wake_up_interruptible(&j->poll_q); /* Wake any blocked selects */ } - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); } ixj_add_timer(j); } @@ -2269,7 +2268,7 @@ * Set up locks to ensure that only one process is talking to the DSP at a time. * This is necessary to keep the DSP from locking up. */ - while(test_and_set_bit(board, (void *)&j->busyflags) != 0) { + while(test_and_set_bit(board, j->busyflags) != 0) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } @@ -2461,7 +2460,7 @@ j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1; file_p->private_data = NULL; - clear_bit(board, &j->busyflags); + clear_bit(board, j->busyflags); MOD_DEC_USE_COUNT; return 0; } @@ -3396,12 +3395,12 @@ } ixj_play_tone(j, 23); - clear_bit(j->board, &j->busyflags); + clear_bit(j->board, j->busyflags); while(j->tone_state) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } - while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) { + while(test_and_set_bit(j->board, j->busyflags) != 0) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } @@ -3423,12 +3422,12 @@ } ixj_play_tone(j, 24); - clear_bit(j->board, &j->busyflags); + clear_bit(j->board, j->busyflags); while(j->tone_state) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } - while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) { + while(test_and_set_bit(j->board, j->busyflags) != 0) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } @@ -3438,12 +3437,12 @@ j->cidcw_wait = jiffies + ((50 * hertz) / 100); - clear_bit(j->board, &j->busyflags); + clear_bit(j->board, j->busyflags); while(!j->flags.cidcw_ack && time_before(jiffies, j->cidcw_wait)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } - while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) { + while(test_and_set_bit(j->board, j->busyflags) != 0) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } @@ -6202,7 +6201,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)); @@ -6213,14 +6212,14 @@ * Set up locks to ensure that only one process is talking to the DSP at a time. * This is necessary to keep the DSP from locking up. */ - while(test_and_set_bit(board, (void *)&j->busyflags) != 0) { + while(test_and_set_bit(board, j->busyflags) != 0) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } if (ixjdebug & 0x0040) - printk("phone%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg); - if (minor >= IXJMAX) { - clear_bit(board, &j->busyflags); + printk("phone%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor_no, cmd, arg); + if (minor_no >= IXJMAX) { + clear_bit(board, j->busyflags); return -ENODEV; } /* @@ -6746,8 +6745,8 @@ break; } if (ixjdebug & 0x0040) - printk("phone%d ioctl end, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg); - clear_bit(board, &j->busyflags); + printk("phone%d ioctl end, cmd: 0x%x, arg: 0x%lx\n", minor_no, cmd, arg); + clear_bit(board, j->busyflags); return retval; } @@ -6901,25 +6900,26 @@ /* Internet PhoneJack Lite */ { j->cardtype = QTI_PHONEJACK_LITE; - if (check_region(j->XILINXbase, 4)) { + if (!request_region(j->XILINXbase, 4, "ixj control")) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); return -1; } - request_region(j->XILINXbase, 4, "ixj control"); j->pld_slicw.pcib.e1 = 1; outb_p(j->pld_slicw.byte, j->XILINXbase); } else { j->cardtype = QTI_LINEJACK; - if (check_region(j->XILINXbase, 8)) { + if (!request_region(j->XILINXbase, 8, "ixj control")) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); return -1; } - request_region(j->XILINXbase, 8, "ixj control"); } } else if (j->dsp.low == 0x22) { j->cardtype = QTI_PHONEJACK_PCI; - request_region(j->XILINXbase, 4, "ixj control"); + if (!request_region(j->XILINXbase, 4, "ixj control")) { + printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); + return -1; + } j->pld_slicw.pcib.e1 = 1; outb_p(j->pld_slicw.byte, j->XILINXbase); } else @@ -6936,19 +6936,17 @@ } break; case QTI_LINEJACK: - if (check_region(j->XILINXbase, 8)) { + if (!request_region(j->XILINXbase, 8, "ixj control")) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); return -1; } - request_region(j->XILINXbase, 8, "ixj control"); break; case QTI_PHONEJACK_LITE: case QTI_PHONEJACK_PCI: - if (check_region(j->XILINXbase, 4)) { + if (!request_region(j->XILINXbase, 4, "ixj control")) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); return -1; } - request_region(j->XILINXbase, 4, "ixj control"); j->pld_slicw.pcib.e1 = 1; outb_p(j->pld_slicw.byte, j->XILINXbase); break; @@ -7735,7 +7733,10 @@ } j = ixj_alloc(); - request_region(j->DSPbase, 16, "ixj DSP"); + if (!request_region(j->DSPbase, 16, "ixj DSP")) { + printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->DSPbase); + break; + } if (func != 0x110) j->XILINXbase = dev->resource[1].start; /* get real port */ @@ -7798,7 +7799,10 @@ j = ixj_alloc(); j->DSPbase = dspio[i]; - request_region(j->DSPbase, 16, "ixj DSP"); + if (!request_region(j->DSPbase, 16, "ixj DSP")) { + printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->DSPbase); + break; + } j->XILINXbase = xio[i]; j->cardtype = 0; @@ -7842,7 +7846,11 @@ j->DSPbase = pci_resource_start(pci, 0); j->serial = (PCIEE_GetSerialNumber)pci_resource_start(pci, 2); j->XILINXbase = j->DSPbase + 0x10; - request_region(j->DSPbase, 16, "ixj DSP"); + if (!request_region(j->DSPbase, 16, "ixj DSP")) { + printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->DSPbase); + break; + } + j->cardtype = QTI_PHONEJACK_PCI; j->board = *cnt; probe = ixj_selfprobe(j); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/telephony/ixj.h linux-2.5/drivers/telephony/ixj.h --- linux-2.5.23/drivers/telephony/ixj.h Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/telephony/ixj.h Wed Jun 19 20:37:59 2002 @@ -1199,7 +1199,7 @@ unsigned char cid_play_flag; char play_mode; IXJ_FLAGS flags; - unsigned int busyflags; + bitmap_member(busyflags, IXJMAX); unsigned int rec_frame_size; unsigned int play_frame_size; unsigned int cid_play_frame_size; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/class/audio.c linux-2.5/drivers/usb/class/audio.c --- linux-2.5.23/drivers/usb/class/audio.c Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/usb/class/audio.c Tue Jun 18 15:49:20 2002 @@ -2349,6 +2349,7 @@ if (vma->vm_pgoff != 0) goto out; + vma->vm_flags &= ~VM_IO; ret = dmabuf_mmap(vma, db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); out: unlock_kernel(); @@ -3832,8 +3833,7 @@ return; } down(&open_sem); - list_del(&s->audiodev); - INIT_LIST_HEAD(&s->audiodev); + list_del_init(&s->audiodev); s->usbdev = NULL; /* deregister all audio and mixer devices, so no new processes can open this device */ for(list = s->audiolist.next; list != &s->audiolist; list = list->next) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/core/hub.c linux-2.5/drivers/usb/core/hub.c --- linux-2.5.23/drivers/usb/core/hub.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/usb/core/hub.c Tue Jun 18 15:49:20 2002 @@ -499,10 +499,8 @@ spin_lock_irqsave(&hub_event_lock, flags); /* Delete it and then reset it */ - list_del(&hub->event_list); - INIT_LIST_HEAD(&hub->event_list); - list_del(&hub->hub_list); - INIT_LIST_HEAD(&hub->hub_list); + list_del_init(&hub->event_list); + list_del_init(&hub->hub_list); spin_unlock_irqrestore(&hub_event_lock, flags); @@ -519,10 +517,8 @@ spin_lock_irqsave(&hub_event_lock, flags); /* Delete it and then reset it */ - list_del(&hub->event_list); - INIT_LIST_HEAD(&hub->event_list); - list_del(&hub->hub_list); - INIT_LIST_HEAD(&hub->hub_list); + list_del_init(&hub->event_list); + list_del_init(&hub->hub_list); spin_unlock_irqrestore(&hub_event_lock, flags); @@ -946,8 +942,7 @@ hub = list_entry(tmp, struct usb_hub, event_list); dev = hub->dev; - list_del(tmp); - INIT_LIST_HEAD(tmp); + list_del_init(tmp); down(&hub->khubd_sem); /* never blocks, we were on list */ spin_unlock_irqrestore(&hub_event_lock, flags); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/core/inode.c linux-2.5/drivers/usb/core/inode.c --- linux-2.5.23/drivers/usb/core/inode.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/usb/core/inode.c Tue Jun 18 15:49:20 2002 @@ -672,8 +672,7 @@ } while (!list_empty(&dev->filelist)) { ds = list_entry(dev->filelist.next, struct dev_state, list); - list_del(&ds->list); - INIT_LIST_HEAD(&ds->list); + list_del_init(&ds->list); down_write(&ds->devsem); ds->dev = NULL; up_write(&ds->devsem); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/host/hc_sl811.c linux-2.5/drivers/usb/host/hc_sl811.c --- linux-2.5.23/drivers/usb/host/hc_sl811.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/usb/host/hc_sl811.c Tue Jun 18 15:49:20 2002 @@ -1206,8 +1206,7 @@ usb_deregister_bus (hci->bus); usb_free_bus (hci->bus); - list_del (&hci->hci_hcd_list); - INIT_LIST_HEAD (&hci->hci_hcd_list); + list_del_init (&hci->hci_hcd_list); kfree (hci); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/host/usb-ohci.c linux-2.5/drivers/usb/host/usb-ohci.c --- linux-2.5.23/drivers/usb/host/usb-ohci.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/usb/host/usb-ohci.c Tue Jun 18 15:49:20 2002 @@ -2434,8 +2434,7 @@ usb_free_bus (ohci->bus); } - list_del (&ohci->ohci_hcd_list); - INIT_LIST_HEAD (&ohci->ohci_hcd_list); + list_del_init (&ohci->ohci_hcd_list); ohci_mem_cleanup (ohci); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/net/usbnet.c linux-2.5/drivers/usb/net/usbnet.c --- linux-2.5.23/drivers/usb/net/usbnet.c Wed Jun 19 03:11:45 2002 +++ linux-2.5/drivers/usb/net/usbnet.c Wed Jun 19 20:13:56 2002 @@ -116,6 +116,7 @@ #include #include #include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/storage/datafab.c linux-2.5/drivers/usb/storage/datafab.c --- linux-2.5.23/drivers/usb/storage/datafab.c Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/usb/storage/datafab.c Sat May 25 19:52:06 2002 @@ -671,7 +671,7 @@ srb->result = SUCCESS; } else { info->sense_key = UNIT_ATTENTION; - srb->result = CHECK_CONDITION << 1; + srb->result = CHECK_CONDITION; } return rc; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/storage/jumpshot.c linux-2.5/drivers/usb/storage/jumpshot.c --- linux-2.5.23/drivers/usb/storage/jumpshot.c Wed Jun 19 03:11:46 2002 +++ linux-2.5/drivers/usb/storage/jumpshot.c Sat May 25 19:52:06 2002 @@ -616,7 +616,7 @@ srb->result = SUCCESS; } else { info->sense_key = UNIT_ATTENTION; - srb->result = CHECK_CONDITION << 1; + srb->result = CHECK_CONDITION; } return rc; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/storage/unusual_devs.h linux-2.5/drivers/usb/storage/unusual_devs.h --- linux-2.5.23/drivers/usb/storage/unusual_devs.h Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/usb/storage/unusual_devs.h Sun May 19 16:11:12 2002 @@ -117,6 +117,21 @@ US_SC_SCSI, US_PR_BULK, NULL, US_FL_FIX_INQUIRY ), +/* Reported by Leif Sawyer */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0240, 0x0240, + "H45 ScanLogic", + "SL11R-IDE 9951SQFP-1.2 K004", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY | US_FL_SL_IDE_BUG ), + +/* Reported by Rene Engelhard and + Dylan Egan */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0260, 0x0260, + "ScanLogic", + "SL11R-IDE unknown HW rev", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_SL_IDE_BUG ), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/storage/usb.c linux-2.5/drivers/usb/storage/usb.c --- linux-2.5.23/drivers/usb/storage/usb.c Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/usb/storage/usb.c Wed Jun 19 07:35:19 2002 @@ -310,7 +310,6 @@ * so get rid of all our resources.. */ daemonize(); - reparent_to_init(); /* avoid getting signals */ spin_lock_irq(¤t->sigmask_lock); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/usb/storage/usb.h linux-2.5/drivers/usb/storage/usb.h --- linux-2.5.23/drivers/usb/storage/usb.h Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/usb/storage/usb.h Wed Jun 19 07:35:19 2002 @@ -102,10 +102,11 @@ #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 */ /* kernel thread actions */ -#define US_ACT_COMMAND 1 +#define US_ACT_COMMAND 1 #define US_ACT_EXIT 5 /* processing state machine states */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/Config.help linux-2.5/drivers/video/Config.help --- linux-2.5.23/drivers/video/Config.help Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/video/Config.help Sat Jun 1 02:15:26 2002 @@ -68,6 +68,12 @@ Say Y to enable support for the Amiga Phase 5 CVisionPPC BVisionPPC framebuffer cards. Phase 5 is no longer with us, alas. +CONFIG_FB_PM3 + This is the frame buffer device driver for the 3DLabs Permedia3 + chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & + similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 + and maybe other boards. + CONFIG_FB_AMIGA This is the frame buffer device driver for the builtin graphics chipset found in Amigas. @@ -586,6 +592,12 @@ CONFIG_FB_IMSTT The IMS Twin Turbo is a PCI-based frame buffer card bundled with many Macintosh and compatible computers. + +CONFIG_FB_TX3912 + The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core; + see . + + Say Y here to enable kernel support for the on-board framebuffer. CONFIG_FB_VIRTUAL This is a `virtual' frame buffer device. It operates on a chunk of diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/acornfb.c linux-2.5/drivers/video/acornfb.c --- linux-2.5.23/drivers/video/acornfb.c Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/video/acornfb.c Sat Jun 1 02:15:26 2002 @@ -1155,9 +1155,6 @@ off += start; vma->vm_pgoff = off >> PAGE_SHIFT; - /* This is an IO map - tell maydump to skip this VMA */ - vma->vm_flags |= VM_IO; - #ifdef CONFIG_CPU_32 pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE; #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/aty128.h linux-2.5/drivers/video/aty128.h --- linux-2.5.23/drivers/video/aty128.h Wed Jun 19 03:11:53 2002 +++ linux-2.5/drivers/video/aty128.h Sat Jun 1 02:15:26 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.23/drivers/video/aty128fb.c linux-2.5/drivers/video/aty128fb.c --- linux-2.5.23/drivers/video/aty128fb.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/video/aty128fb.c Sat Jun 1 02:15:26 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) @@ -157,7 +163,9 @@ {"Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL, rage_128}, {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF, rage_128_pro}, {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR, rage_128_pro}, - {"Rage128 Pro TR (AGP)", PCI_DEVICE_ID_ATI_RAGE128_U3, rage_128_pro}, + {"Rage128 Pro TF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_U1, rage_128_pro}, + {"Rage128 Pro TR (AGP)", PCI_DEVICE_ID_ATI_RAGE128_U3, rage_128_pro}, + {"Rage128 Pro TF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_U1, rage_128_pro}, {"Rage Mobility M3 (PCI)", PCI_DEVICE_ID_ATI_RAGE128_LE, rage_M3}, {"Rage Mobility M3 (AGP)", PCI_DEVICE_ID_ATI_RAGE128_LF, rage_M3}, {NULL, 0, rage_128} @@ -218,15 +226,12 @@ static const char *aty128fb_name = "ATY Rage128"; static char fontname[40] __initdata = { 0 }; +static u32 pseudo_palette[17]; static int noaccel __initdata = 0; -#ifdef MODULE static char *font __initdata = NULL; static char *mode __initdata = NULL; -#ifdef CONFIG_MTRR static int nomtrr __initdata = 0; -#endif -#endif /* MODULE */ static char *mode_option __initdata = NULL; @@ -235,6 +240,11 @@ static int default_cmode __initdata = CMODE_8; #endif +#ifdef CONFIG_PMAC_PBOOK +static int default_crt_on __initdata = 0; +static int default_lcd_on __initdata = 1; +#endif + #ifdef CONFIG_MTRR static int mtrr = 1; #endif @@ -259,7 +269,7 @@ u32 offset, offset_cntl; u32 xoffset, yoffset; u32 vxres, vyres; - u32 bpp; + u32 depth, bpp; }; struct aty128_pll { @@ -288,24 +298,12 @@ unsigned long regbase_phys; /* physical mmio */ void *regbase; /* remapped mmio */ unsigned long frame_buffer_phys; /* physical fb memory */ - void *frame_buffer; /* remaped framebuffer */ u32 vram_size; /* onboard video ram */ int chip_gen; const struct aty128_meminfo *mem; /* onboard mem info */ struct aty128fb_par default_par, current_par; struct display disp; struct { u8 red, green, blue, pad; } palette[256]; - 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; #ifdef CONFIG_PCI struct pci_dev *pdev; #endif @@ -314,10 +312,23 @@ #endif int blitter_may_be_busy; int fifo_slots; /* free slots in FIFO (64 max) */ +#ifdef CONFIG_PMAC_PBOOK + unsigned char *save_framebuffer; + int pm_reg; + int crt_on, lcd_on; + u32 save_lcd_gen_cntl; +#endif }; static struct fb_info_aty128 *board_list = NULL; +#ifdef CONFIG_PMAC_PBOOK + int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when); + static struct pmu_sleep_notifier aty128_sleep_notifier = { + aty128_sleep_notify, SLEEP_LEVEL_VIDEO, + }; +#endif + #define round_div(n, d) ((n+(d/2))/d) /* @@ -335,12 +346,15 @@ static int aty128fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); + u_int transp, struct fb_info *info); static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *fb); static int aty128fb_blank(int blank, struct fb_info *fb); +static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info); static int aty128fb_rasterimg(struct fb_info *info, int start); + /* * Interface to the low level console driver */ @@ -382,7 +396,7 @@ static void do_wait_for_fifo(u16 entries, struct fb_info_aty128 *info); static void wait_for_fifo(u16 entries, struct fb_info_aty128 *info); static void wait_for_idle(struct fb_info_aty128 *info); -static u32 bpp_to_depth(u32 bpp); +static u32 depth_to_dst(u32 depth); #ifdef FBCON_HAS_CFB8 static struct display_switch fbcon_aty128_8; @@ -424,9 +438,10 @@ fb_set_var: aty128fb_set_var, fb_get_cmap: aty128fb_get_cmap, fb_set_cmap: gen_set_cmap, - fb_setcolreg: aty128fb_setcolreg, fb_pan_display: aty128fb_pan_display, + fb_setcolreg: aty128fb_setcolreg, fb_blank: aty128fb_blank, + fb_ioctl: aty128fb_ioctl, fb_rasterimg: aty128fb_rasterimg, }; @@ -501,7 +516,7 @@ _aty_ld_pll(unsigned int pll_index, const struct fb_info_aty128 *info) { - aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F); + aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F); return aty_ld_le32(CLOCK_CNTL_DATA); } @@ -510,7 +525,7 @@ _aty_st_pll(unsigned int pll_index, u32 val, const struct fb_info_aty128 *info) { - aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN); + aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN); aty_st_le32(CLOCK_CNTL_DATA, val); } @@ -703,7 +718,7 @@ GMC_SRC_CLIP_DEFAULT | GMC_DST_CLIP_DEFAULT | GMC_BRUSH_SOLIDCOLOR | - (bpp_to_depth(par->crtc.bpp) << 8) | + (depth_to_dst(par->crtc.depth) << 8) | GMC_SRC_DSTCOLOR | GMC_BYTE_ORDER_MSB_TO_LSB | GMC_DP_CONVERSION_TEMP_6500 | @@ -736,18 +751,20 @@ } -/* convert bpp values to their register representation */ +/* convert depth values to their register representation */ static u32 -bpp_to_depth(u32 bpp) -{ - if (bpp <= 8) - return DST_8BPP; - else if (bpp <= 16) - return DST_15BPP; - else if (bpp <= 24) - return DST_24BPP; - else if (bpp <= 32) - return DST_32BPP; +depth_to_dst(u32 depth) + { + if (depth <= 8) + return DST_8BPP; + else if (depth <= 15) + return DST_15BPP; + else if (depth == 16) + return DST_16BPP; + else if (depth <= 24) + return DST_24BPP; + else if (depth <= 32) + return DST_32BPP; return -EINVAL; } @@ -770,12 +787,8 @@ aty_st_le32(CRTC_PITCH, crtc->pitch); aty_st_le32(CRTC_OFFSET, crtc->offset); aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl); - /* Disable ATOMIC updating. Is this the right place? - * -- BenH: Breaks on my G4 - */ -#if 0 - aty_st_le32(PPLL_CNTL, aty_ld_le32(PPLL_CNTL) & ~(0x00030000)); -#endif + /* Disable ATOMIC updating. Is this the right place? */ + aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~(0x00030000)); } @@ -784,7 +797,7 @@ struct aty128_crtc *crtc, const struct fb_info_aty128 *info) { - u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; + u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst; u32 left, right, upper, lower, hslen, vslen, sync, vmode; u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; @@ -809,6 +822,11 @@ sync = var->sync; vmode = var->vmode; + if (bpp != 16) + depth = bpp; + else + depth = (var->green.length == 6) ? 16 : 15; + /* check for mode eligibility * accept only non interlaced modes */ if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) @@ -824,17 +842,16 @@ if (vyres < yres + yoffset) vyres = yres + yoffset; - /* convert bpp into ATI register depth */ - depth = bpp_to_depth(bpp); + /* convert depth into ATI register depth */ + dst = depth_to_dst(depth); - /* make sure we didn't get an invalid depth */ - if (depth == -EINVAL) { - printk(KERN_ERR "aty128fb: Invalid depth\n"); + if (dst == -EINVAL) { + printk(KERN_ERR "aty128fb: Invalid depth or RGBA\n"); return -EINVAL; } - /* convert depth to bpp */ - bytpp = mode_bytpp[depth]; + /* convert register depth to bytes per pixel */ + bytpp = mode_bytpp[dst]; /* make sure there is enough video ram for the mode */ if ((u32)(vxres * vyres * bytpp) > info->vram_size) { @@ -875,7 +892,7 @@ c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; - crtc->gen_cntl = 0x3000000L | c_sync | (depth << 8); + crtc->gen_cntl = 0x3000000L | c_sync | (dst << 8); crtc->h_total = h_total | (h_disp << 16); crtc->v_total = v_total | (v_disp << 16); @@ -898,6 +915,7 @@ crtc->vyres = vyres; crtc->xoffset = xoffset; crtc->yoffset = yoffset; + crtc->depth = depth; crtc->bpp = bpp; return 0; @@ -905,7 +923,7 @@ static int -aty128_bpp_to_var(int pix_width, struct fb_var_screeninfo *var) +aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var) { /* fill in pixel info */ @@ -922,7 +940,6 @@ var->transp.length = 0; break; case CRTC_PIX_WIDTH_15BPP: - case CRTC_PIX_WIDTH_16BPP: var->bits_per_pixel = 16; var->red.offset = 10; var->red.length = 5; @@ -933,6 +950,17 @@ var->transp.offset = 0; var->transp.length = 0; break; + case CRTC_PIX_WIDTH_16BPP: + var->bits_per_pixel = 16; + 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; + break; case CRTC_PIX_WIDTH_24BPP: var->bits_per_pixel = 24; var->red.offset = 16; @@ -1001,7 +1029,7 @@ (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); - aty128_bpp_to_var(pix_width, var); + aty128_pix_width_to_var(pix_width, var); var->xres = xres; var->yres = yres; @@ -1021,6 +1049,44 @@ return 0; } +#ifdef CONFIG_PMAC_PBOOK +static void +aty128_set_crt_enable(struct fb_info_aty128 *info, int on) +{ + if (on) { + aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON); + aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) | DAC_PALETTE2_SNOOP_EN)); + } else + aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON); +} + +static void +aty128_set_lcd_enable(struct fb_info_aty128 *info, int on) +{ + u32 reg; + + if (on) { + reg = aty_ld_le32(LVDS_GEN_CNTL); + reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION; + reg &= ~LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef CONFIG_PMAC_BACKLIGHT + aty128_set_backlight_enable(get_backlight_enable(), get_backlight_level(), info); +#endif + } else { +#ifdef CONFIG_PMAC_BACKLIGHT + aty128_set_backlight_enable(0, 0, info); +#endif + reg = aty_ld_le32(LVDS_GEN_CNTL); + reg |= LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); + mdelay(100); + reg &= ~(LVDS_ON /*| LVDS_EN*/); + aty_st_le32(LVDS_GEN_CNTL, reg); + } +} +#endif + static void aty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info) { @@ -1058,6 +1124,23 @@ /* clear the reset, just in case */ aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET); + +#if 0 + if (info->chip_gen == rage_M3) { + /* XXX energy saving, disable VCLK during blanking */ + aty_pll_wait_readupdate(info); + aty_st_pll(VCLK_ECP_CNTL, aty_ld_pll(VCLK_ECP_CNTL) | 0xc0); + aty_pll_writeupdate(info); + + /* Set PM clocks */ + aty_pll_wait_readupdate(info); + aty_st_pll(XCLK_CNTL, aty_ld_pll(XCLK_CNTL) | 0x00330000); + aty_pll_writeupdate(info); + aty_pll_wait_readupdate(info); + aty_st_pll(MCLK_CNTL, aty_ld_pll(MCLK_CNTL) | 0x00000700); + aty_pll_writeupdate(info); + } +#endif } @@ -1126,7 +1209,7 @@ static int aty128_ddafifo(struct aty128_ddafifo *dsp, const struct aty128_pll *pll, - u32 bpp, + u32 depth, const struct fb_info_aty128 *info) { const struct aty128_meminfo *m = info->mem; @@ -1134,11 +1217,10 @@ u32 fifo_width = info->constants.fifo_width; u32 fifo_depth = info->constants.fifo_depth; s32 x, b, p, ron, roff; - u32 n, d; + u32 n, d, bpp; - /* 15bpp is really 16bpp */ - if (bpp == 15) - bpp = 16; + /* round up to multiple of 8 */ + bpp = (depth+7) & ~7; n = xclk * fifo_width; d = pll->vclk * bpp; @@ -1219,15 +1301,21 @@ config = aty_ld_le32(CONFIG_CNTL) & ~3; #if defined(__BIG_ENDIAN) - if (par->crtc.bpp >= 24) - config |= 2; /* make aperture do 32 byte swapping */ - else if (par->crtc.bpp > 8) - config |= 1; /* make aperture do 16 byte swapping */ + if (par->crtc.bpp == 32) + config |= 2; /* make aperture do 32 bit swapping */ + else if (par->crtc.bpp == 16) + config |= 1; /* make aperture do 16 bit swapping */ #endif aty_st_le32(CONFIG_CNTL, config); aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */ +#ifdef CONFIG_PMAC_PBOOK + if (info->chip_gen == rage_M3) { + aty128_set_crt_enable(info, info->crt_on); + aty128_set_lcd_enable(info, info->lcd_on); + } +#endif if (par->accel_flags & FB_ACCELF_TEXT) aty128_init_engine(par, info); @@ -1253,11 +1341,11 @@ } #endif /* CONFIG_FB_COMPAT_XPMAC */ #if defined(CONFIG_BOOTX_TEXT) - btext_update_display(info->frame_buffer_phys, - (((par->crtc.h_total>>16) & 0xff)+1)*8, - ((par->crtc.v_total>>16) & 0x7ff)+1, - par->crtc.bpp, - par->crtc.vxres*par->crtc.bpp/8); + btext_update_display(info->frame_buffer_phys, + (((par->crtc.h_total>>16) & 0xff)+1)*8, + ((par->crtc.v_total>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); #endif /* CONFIG_BOOTX_TEXT */ } @@ -1277,7 +1365,7 @@ if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info))) return err; - if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info))) + if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.depth, info))) return err; if (var->accel_flags & FB_ACCELF_TEXT) @@ -1345,7 +1433,7 @@ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; struct aty128fb_par par; struct display *display; - int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; + int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldgreen, oldaccel; int accel, err; display = (con >= 0) ? &fb_display[con] : fb->disp; @@ -1390,16 +1478,17 @@ oldvxres = display->var.xres_virtual; oldvyres = display->var.yres_virtual; oldbpp = display->var.bits_per_pixel; + oldgreen = display->var.green.length; oldaccel = display->var.accel_flags; display->var = *var; if (oldxres != var->xres || oldyres != var->yres || oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || - oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { + oldgreen != var->green.length || oldbpp != var->bits_per_pixel || + oldaccel != var->accel_flags) { struct fb_fix_screeninfo fix; aty128_encode_fix(&fix, &par, info); - fb->screen_base = info->frame_buffer; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -1424,7 +1513,7 @@ if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con) aty128_set_par(&par, info); - if (oldbpp != var->bits_per_pixel) { + if (oldbpp != var->bits_per_pixel || oldgreen != var->green.length) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; do_install_cmap(con, &info->fb_info); @@ -1445,22 +1534,21 @@ break; #endif #ifdef FBCON_HAS_CFB16 - case 15: case 16: disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16; - disp->dispsw_data = info->fbcon_cmap.cfb16; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif #ifdef FBCON_HAS_CFB24 case 24: disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24; - disp->dispsw_data = info->fbcon_cmap.cfb24; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif #ifdef FBCON_HAS_CFB32 case 32: disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32; - disp->dispsw_data = info->fbcon_cmap.cfb32; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif default: @@ -1487,7 +1575,7 @@ fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->line_length = (par->crtc.vxres * par->crtc.bpp) >> 3; - fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR + fix->visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; fix->ywrapstep = 0; fix->xpanstep = 8; @@ -1521,8 +1609,6 @@ /* * Pan or Wrap the Display - * - * Not supported (yet!) */ static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con, @@ -1546,7 +1632,10 @@ par->crtc.xoffset = xoffset; par->crtc.yoffset = yoffset; - offset = ((yoffset * par->crtc.vxres + xoffset) * par->crtc.bpp) >> 6; + offset = ((yoffset * par->crtc.vxres + xoffset)*(par->crtc.bpp >> 3)) & ~7; + + if (par->crtc.bpp == 24) + offset += 8 * (offset % 3); /* Must be multiple of 8 and 3 */ aty_st_le32(CRTC_OFFSET, offset); @@ -1562,24 +1651,45 @@ aty128fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { -#if 1 - fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2); -#else - struct fb_info_aty128 fb = (struct fb_info_aty128 *)info; + struct display *disp = (con < 0) ? info->disp : (fb_display + con); if (con == info->currcon) /* current console? */ - return fb_get_cmap(cmap, kspc, aty128_getcolreg, info); - else if (fb_display[con].cmap.len) /* non default colormap? */ - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else { - int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 32; - fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); - } -#endif + return fb_get_cmap(cmap, kspc, aty128_getcolreg, info); + else if (disp->cmap.len) /* non default colormap? */ + fb_copy_cmap(&disp->cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap((disp->var.bits_per_pixel==8) ? 256 : 32), + cmap, kspc ? 0 : 2); return 0; } + /* + * Helper function to store a single palette register + */ +static __inline__ void +aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue, + struct fb_info_aty128 *info) +{ + /* Note: For now, on M3, we set palette on both heads, which may + * be useless. Can someone with a M3 check this ? + * + * This code would still be useful if using the second CRTC to + * do mirroring + */ + + if (info->chip_gen == rage_M3) { +#if 0 + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); + aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue); +#endif + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + } + aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue); +} + static int aty128fb_rasterimg(struct fb_info *info, int start) { @@ -1600,7 +1710,9 @@ if (!options || !*options) return 0; - while ((this_opt = strsep(&options, ",")) != NULL) { + while ((this_opt = strsep(&options, ",")) != 0) { + if (!*this_opt) + continue; if (!strncmp(this_opt, "font:", 5)) { char *p; int i; @@ -1613,6 +1725,12 @@ fontname[i] = 0; } else if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; +#ifdef CONFIG_PMAC_PBOOK + } else if (!strncmp(this_opt, "lcd:", 4)) { + default_lcd_on = simple_strtoul(this_opt+4, NULL, 0); + } else if (!strncmp(this_opt, "crt:", 4)) { + default_crt_on = simple_strtoul(this_opt+4, NULL, 0); +#endif } #ifdef CONFIG_MTRR else if(!strncmp(this_opt, "nomtrr", 6)) { @@ -1659,7 +1777,7 @@ { struct fb_var_screeninfo var; u32 dac; - int j, k, size; + int j, k; u8 chip_rev; const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; char *video_card = "Rage128"; @@ -1687,12 +1805,17 @@ info->fb_info.node = NODEV; info->fb_info.fbops = &aty128fb_ops; info->fb_info.disp = &info->disp; + info->fb_info.pseudo_palette = pseudo_palette; strcpy(info->fb_info.fontname, fontname); info->fb_info.changevar = NULL; info->fb_info.switch_con = &aty128fbcon_switch; info->fb_info.updatevar = NULL; info->fb_info.flags = FBINFO_FLAG_DEFAULT; - +#ifdef CONFIG_PMAC_PBOOK + info->lcd_on = default_lcd_on; + info->crt_on = default_crt_on; +#endif + var = default_var; #ifdef CONFIG_PPC if (_machine == _MACH_Pmac) { @@ -1716,16 +1839,16 @@ /* iBook SE */ if (machine_is_compatible("PowerBook2,2")) default_vmode = VMODE_800_600_60; - + /* PowerBook Firewire (Pismo), iBook Dual USB */ if (machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook4,1")) + machine_is_compatible("PowerBook4,1")) default_vmode = VMODE_1024_768_60; /* PowerBook Titanium */ if (machine_is_compatible("PowerBook3,2")) default_vmode = VMODE_1152_768_60; - + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; @@ -1762,6 +1885,8 @@ dac = aty_ld_le32(DAC_CNTL); dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL); dac |= DAC_MASK; + if (info->chip_gen == rage_M3) + dac |= DAC_PALETTE2_SNOOP_EN; aty_st_le32(DAC_CNTL, dac); /* turn off bus mastering, just in case */ @@ -1772,9 +1897,6 @@ board_list = aty128_board_list_add(board_list, info); - size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 32; - fb_alloc_cmap(info->fb_info.cmap, size, 0); - if (register_framebuffer(&info->fb_info) < 0) return 0; @@ -1783,6 +1905,14 @@ if (info->chip_gen == rage_M3) register_backlight_controller(&aty128_backlight_controller, info, "ati"); #endif /* CONFIG_PMAC_BACKLIGHT */ +#ifdef CONFIG_PMAC_PBOOK + if (!info->pdev) + printk(KERN_WARNING "aty128fb: Not a PCI card, can't enable power management\n"); + else { + info->pm_reg = pci_find_capability(info->pdev, PCI_CAP_ID_PM); + pmu_register_sleep_notifier(&aty128_sleep_notifier); + } +#endif printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", GET_FB_IDX(info->fb_info.node), aty128fb_name, name); @@ -1848,7 +1978,7 @@ if ((err = pci_enable_device(pdev))) { printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n", err); - goto err_out; + return -ENODEV; } fb_addr = pci_resource_start(pdev, 0); @@ -1890,9 +2020,9 @@ /* Virtualize the framebuffer */ info->frame_buffer_phys = fb_addr; - info->frame_buffer = ioremap(fb_addr, info->vram_size); + info->fb_info.screen_base = ioremap(fb_addr, info->vram_size); - if (!info->frame_buffer) { + if (!info->fb_info.screen_base) { iounmap((void *)info->regbase); goto err_free_info; } @@ -1936,7 +2066,7 @@ return 0; err_out: - iounmap(info->frame_buffer); + iounmap(info->fb_info.screen_base); iounmap(info->regbase); err_free_info: kfree(info); @@ -2167,6 +2297,12 @@ aty_st_8(CRTC_EXT_CNTL+1, state); +#ifdef CONFIG_PMAC_PBOOK + if (info->chip_gen == rage_M3) { + aty128_set_crt_enable(info, info->crt_on && !blank); + aty128_set_lcd_enable(info, info->lcd_on && !blank); + } +#endif #ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && !blank) set_backlight_enable(1); @@ -2174,6 +2310,7 @@ return 0; } + /* * Read a single color register and split it into * colors/transparent. Return != 0 for invalid regno. @@ -2205,7 +2342,7 @@ u_int transp, struct fb_info *fb) { struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; - u32 col; + u32 palreg; if (regno > 255) return 1; @@ -2225,66 +2362,45 @@ if ((info->current_par.crtc.bpp > 8) && (regno == 0)) { int i; - if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); - - for (i=16; i<256; i++) { - aty_st_8(PALETTE_INDEX, i); - col = (i << 16) | (i << 8) | i; - aty_st_le32(PALETTE_DATA, col); - } - - if (info->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); - - for (i=16; i<256; i++) { - aty_st_8(PALETTE_INDEX, i); - col = (i << 16) | (i << 8) | i; - aty_st_le32(PALETTE_DATA, col); - } - } + for (i=0; i<256; i++) + aty128_st_pal(i, i, i, i, info); } /* initialize palette */ - if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + palreg = regno; if (info->current_par.crtc.bpp == 16) - aty_st_8(PALETTE_INDEX, (regno << 3)); - else - aty_st_8(PALETTE_INDEX, regno); - col = (red << 16) | (green << 8) | blue; - aty_st_le32(PALETTE_DATA, col); - if (info->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); - if (info->current_par.crtc.bpp == 16) - aty_st_8(PALETTE_INDEX, (regno << 3)); - else - aty_st_8(PALETTE_INDEX, regno); - aty_st_le32(PALETTE_DATA, col); + palreg = regno * 8; + + if (info->current_par.crtc.depth == 16) { + aty128_st_pal(palreg/2, info->palette[regno/2].red, green, + info->palette[regno/2].blue, info); + green = info->palette[regno*2].green; } + if (info->current_par.crtc.bpp == 8 || regno < 32) + aty128_st_pal(palreg, red, green, blue, info); + if (regno < 16) - switch (info->current_par.crtc.bpp) { + switch (info->current_par.crtc.depth) { #ifdef FBCON_HAS_CFB16 - case 9 ... 16: - info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | - regno; + case 15: + ((u16 *)(info->fb_info.pseudo_palette))[regno] = (regno << 10) | (regno << 5) | regno; + break; + case 16: + ((u16 *)(info->fb_info.pseudo_palette))[regno] = (regno << 11) | (regno << 5) | regno; break; #endif #ifdef FBCON_HAS_CFB24 - case 17 ... 24: - info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | - regno; + case 24: + ((u32 *)(info->fb_info.pseudo_palette))[regno] = (regno << 16) | (regno << 8) | regno; break; #endif #ifdef FBCON_HAS_CFB32 - case 25 ... 32: { - u32 i; - - i = (regno << 8) | regno; - info->fbcon_cmap.cfb32[regno] = (i << 16) | i; + case 32: { + u32 i = (regno << 8) | regno; + ((u32 *)(info->fb_info.pseudo_palette))[regno] = (i << 16) | i; break; } #endif @@ -2292,27 +2408,108 @@ return 0; } +#define ATY_MIRROR_LCD_ON 0x00000001 +#define ATY_MIRROR_CRT_ON 0x00000002 + +/* out param: u32* backlight value: 0 to 15 */ +#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, sizeof(__u32*)) +/* in param: u32* backlight value: 0 to 15 */ +#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, sizeof(__u32*)) + +static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info) +{ +#ifdef CONFIG_PMAC_PBOOK + struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info; + u32 value; + int rc; +#endif + + switch (cmd) { +#ifdef CONFIG_PMAC_PBOOK + case FBIO_ATY128_SET_MIRROR: + if (fb->chip_gen != rage_M3) + return -EINVAL; + rc = get_user(value, (__u32*)arg); + if (rc) + return rc; + fb->lcd_on = (value & 0x01) != 0; + fb->crt_on = (value & 0x02) != 0; + if (!fb->crt_on && !fb->lcd_on) + fb->lcd_on = 1; + aty128_set_crt_enable(fb, fb->crt_on); + aty128_set_lcd_enable(fb, fb->lcd_on); + break; + case FBIO_ATY128_GET_MIRROR: + if (fb->chip_gen != rage_M3) + return -EINVAL; + value = (fb->crt_on << 1) | fb->lcd_on; + return put_user(value, (__u32*)arg); +#endif + default: + return -EINVAL; + } + return 0; +} + #ifdef CONFIG_PMAC_BACKLIGHT static int backlight_conv[] = { 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 }; +/* We turn off the LCD completely instead of just dimming the backlight. + * This provides greater power saving and the display is useless without + * backlight anyway + */ +#define BACKLIGHT_LVDS_OFF +/* That one prevents proper CRT output with LCD off */ +#undef BACKLIGHT_DAC_OFF + static int aty128_set_backlight_enable(int on, int level, void* data) { struct fb_info_aty128 *info = (struct fb_info_aty128 *)data; unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); - + + if (!info->lcd_on) + on = 0; reg |= LVDS_BL_MOD_EN | LVDS_BLON; if (on && level > BACKLIGHT_OFF) { + reg |= LVDS_DIGION; + if (!reg & LVDS_ON) { + reg &= ~LVDS_BLON; + aty_st_le32(LVDS_GEN_CNTL, reg); + (void)aty_ld_le32(LVDS_GEN_CNTL); + mdelay(10); + reg |= LVDS_BLON; + aty_st_le32(LVDS_GEN_CNTL, reg); + } reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT); +#ifdef BACKLIGHT_LVDS_OFF + reg |= LVDS_ON | LVDS_EN; + reg &= ~LVDS_DISPLAY_DIS; +#endif + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef BACKLIGHT_DAC_OFF + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN)); +#endif } else { reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT); +#ifdef BACKLIGHT_LVDS_OFF + reg |= LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); + (void)aty_ld_le32(LVDS_GEN_CNTL); + udelay(10); + reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION); +#endif + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef BACKLIGHT_DAC_OFF + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN); +#endif } - aty_st_le32(LVDS_GEN_CNTL, reg); return 0; } @@ -2333,18 +2530,18 @@ u_int width, u_int height, struct fb_info_aty128 *info) { - u32 save_dp_datatype, save_dp_cntl, bppval; + u32 save_dp_datatype, save_dp_cntl, dstval; if (!width || !height) return; - bppval = bpp_to_depth(info->current_par.crtc.bpp); - if (bppval == DST_24BPP) { + dstval = depth_to_dst(info->current_par.crtc.depth); + if (dstval == DST_24BPP) { srcx *= 3; dstx *= 3; width *= 3; - } else if (bppval == -EINVAL) { - printk("aty128fb: invalid depth\n"); + } else if (dstval == -EINVAL) { + printk("aty128fb: invalid depth or RGBA\n"); return; } @@ -2356,7 +2553,7 @@ aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); - aty_st_le32(DP_DATATYPE, save_dp_datatype | bppval | SRC_DSTCOLOR); + aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR); aty_st_le32(DST_Y_X, (dsty << 16) | dstx); aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); @@ -2582,6 +2779,139 @@ }; #endif +#ifdef CONFIG_PMAC_PBOOK +static void +aty128_set_suspend(struct fb_info_aty128 *info, int suspend) +{ + u32 pmgt; + u16 pwr_command; + + if (!info->pm_reg) + return; + + /* Set the chip into the appropriate suspend mode (we use D2, + * D3 would require a complete re-initialisation of the chip, + * including PCI config registers, clocks, AGP configuration, ...) + */ + if (suspend) { + /* Make sure CRTC2 is reset. Remove that the day we decide to + * actually use CRTC2 and replace it with real code for disabling + * the CRTC2 output during sleep + */ + aty_st_le32(CRTC2_GEN_CNTL, aty_ld_le32(CRTC2_GEN_CNTL) & + ~(CRTC2_EN)); + + /* Set the power management mode to be PCI based */ + pmgt = aty_ld_pll(POWER_MANAGEMENT); +#if 0 + pmgt &= ~PWR_MGT_MODE_MASK; + pmgt |= PWR_MGT_MODE_PCI | PWR_MGT_ON | PWR_MGT_TRISTATE_MEM_EN | PWR_MGT_AUTO_PWR_UP_EN; +#else /* Use this magic value for now */ + pmgt = 0x0c005407; +#endif + aty_st_pll(POWER_MANAGEMENT, pmgt); + (void)aty_ld_pll(POWER_MANAGEMENT); + aty_st_le32(BUS_CNTL1, 0x00000010); + aty_st_le32(MEM_POWER_MISC, 0x0c830000); + mdelay(100); + pci_read_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, &pwr_command); + /* Switch PCI power management to D2 */ + pci_write_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, + (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | 2); + pci_read_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, &pwr_command); + } else { + /* Switch back PCI power management to D0 */ + mdelay(100); + pci_write_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, 0); + mdelay(100); + pci_read_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, &pwr_command); + mdelay(100); + } +} + +extern struct display_switch fbcon_dummy; + +/* + * Save the contents of the frame buffer when we go to sleep, + * and restore it when we wake up again. + */ +int +aty128_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct fb_info_aty128 *info; + int result; + + result = PBOOK_SLEEP_OK; + + for (info = board_list; info != NULL; info = info->next) { + struct fb_fix_screeninfo fix; + int nb; + + aty128fb_get_fix(&fix, fg_console, (struct fb_info *)info); + nb = fb_display[fg_console].var.yres * fix.line_length; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + info->save_framebuffer = vmalloc(nb); + if (info->save_framebuffer == NULL) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + if (info->save_framebuffer) { + vfree(info->save_framebuffer); + info->save_framebuffer = 0; + } + break; + case PBOOK_SLEEP_NOW: + if (info->currcon >= 0) + fb_display[info->currcon].dispsw = &fbcon_dummy; + + wait_for_idle(info); + aty128_reset_engine(info); + wait_for_idle(info); + + /* Backup fb content */ + if (info->save_framebuffer) + memcpy_fromio(info->save_framebuffer, + (void *)info->fb_info.screen_base, nb); + + /* Blank display and LCD */ + aty128fbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); + + /* Sleep the chip */ + aty128_set_suspend(info, 1); + + break; + case PBOOK_WAKE: + /* Wake the chip */ + aty128_set_suspend(info, 0); + + aty128_reset_engine(info); + wait_for_idle(info); + + /* Restore fb content */ + if (info->save_framebuffer) { + memcpy_toio((void *)info->fb_info.screen_base, + info->save_framebuffer, nb); + vfree(info->save_framebuffer); + info->save_framebuffer = 0; + } + + if (info->currcon >= 0) { + aty128_set_dispsw( + &fb_display[info->currcon], + info, + info->current_par.crtc.bpp, + info->current_par.accel_flags & FB_ACCELF_TEXT); + } + aty128fbcon_blank(0, (struct fb_info *)info); + break; + } + } + return result; +} +#endif /* CONFIG_PMAC_PBOOK */ + #ifdef MODULE MODULE_AUTHOR("(c)1999-2000 Brad Douglas "); MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards"); @@ -2639,7 +2969,7 @@ info->vram_size); #endif /* CONFIG_MTRR */ iounmap(info->regbase); - iounmap(info->frame_buffer); + iounmap(info->fb_info.screen_base); release_mem_region(pci_resource_start(info->pdev, 0), pci_resource_len(info->pdev, 0)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/dummycon.c linux-2.5/drivers/video/dummycon.c --- linux-2.5.23/drivers/video/dummycon.c Wed Jun 19 03:11:51 2002 +++ linux-2.5/drivers/video/dummycon.c Sat Jun 1 02:15:26 2002 @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/fbcon.c linux-2.5/drivers/video/fbcon.c --- linux-2.5.23/drivers/video/fbcon.c Wed Jun 19 03:11:48 2002 +++ linux-2.5/drivers/video/fbcon.c Wed Jun 19 07:35:20 2002 @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -137,6 +138,12 @@ static void fbcon_free_font(struct display *); static int fbcon_set_origin(struct vc_data *); +#ifdef CONFIG_PM +static int pm_fbcon_request(struct pm_dev *dev, pm_request_t rqst, void *data); +static struct pm_dev *pm_fbcon; +static int fbcon_sleeping; +#endif + /* * Emmanuel: fbcon will now use a hardware cursor if the * low-level driver provides a non-NULL dispsw->cursor pointer, @@ -233,6 +240,7 @@ static struct timer_list cursor_timer = { function: cursor_timer_handler }; +static int use_timer_cursor; static void cursor_timer_handler(unsigned long dev_addr) { @@ -359,8 +367,6 @@ fb_display[unit]._fontheightlog = fontheightlog; fb_display[unit].userfont = userfont; fb_display[unit].fb_info = newfb; - if (conp) - conp->vc_display_fg = &newfb->display_fg; if (!newfb->display_fg) newfb->display_fg = conp; if (!newfb->changevar) @@ -457,11 +463,16 @@ #endif if (irqres) { + use_timer_cursor = 1; cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE; cursor_timer.expires = jiffies+HZ/50; add_timer(&cursor_timer); } +#ifdef CONFIG_PM + pm_fbcon = pm_register(PM_SYS_DEV, PM_SYS_VGA, pm_fbcon_request); +#endif + return display_desc; } @@ -491,7 +502,6 @@ fb_display[unit].cmap.transp = 0; fbcon_setup(unit, init, !init); /* Must be done after fbcon_setup to prevent excess updates */ - conp->vc_display_fg = &info->display_fg; if (!info->display_fg) info->display_fg = conp; } @@ -554,6 +564,7 @@ { struct display *p = &fb_display[con]; struct vc_data *conp = p->conp; + struct vc_data *vc = conp; int nr_rows, nr_cols; int old_rows, old_cols; unsigned short *save = NULL, *r, *q; @@ -609,7 +620,7 @@ REFCOUNT(p->fontdata)++; charcnt = FNTCHARCNT(p->fontdata); } - con_copy_unimap(con, i); + con_copy_unimap(fb_display[con].conp, fb_display[i].conp); } } @@ -725,11 +736,11 @@ if (!init) { if (conp->vc_cols != nr_cols || conp->vc_rows != nr_rows) vc_resize_con(nr_rows, nr_cols, con); - else if (CON_IS_VISIBLE(conp) && - vt_cons[conp->vc_num]->vc_mode == KD_TEXT) { + else if (IS_VISIBLE && + conp->vc_mode == KD_TEXT) { if (p->dispsw->clear_margins) p->dispsw->clear_margins(conp, p, 0); - update_screen(con); + update_screen(conp); } if (save) { q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows); @@ -800,7 +811,7 @@ u_int y_break; int redraw_cursor = 0; - if (!p->can_soft_blank && console_blanked) + if (!p->can_soft_blank && conp->display_fg->vt_blanked) return; if (!height || !width) @@ -833,10 +844,10 @@ struct display *p = &fb_display[unit]; int redraw_cursor = 0; - if (!p->can_soft_blank && console_blanked) + if (!p->can_soft_blank && conp->display_fg->vt_blanked) return; - if (vt_cons[unit]->vc_mode != KD_TEXT) + if (conp->vc_mode != KD_TEXT) return; if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) { @@ -858,10 +869,10 @@ struct display *p = &fb_display[unit]; int redraw_cursor = 0; - if (!p->can_soft_blank && console_blanked) + if (!p->can_soft_blank && conp->display_fg->vt_blanked) return; - if (vt_cons[unit]->vc_mode != KD_TEXT) + if (conp->vc_mode != KD_TEXT) return; if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) && @@ -1289,10 +1300,10 @@ struct display *p = &fb_display[unit]; int scroll_partial = !(p->scrollmode & __SCROLL_YNOPARTIAL); - if (!p->can_soft_blank && console_blanked) + if (!p->can_soft_blank && conp->display_fg->vt_blanked) return 0; - if (!count || vt_cons[unit]->vc_mode != KD_TEXT) + if (!count || conp->vc_mode != KD_TEXT) return 0; fbcon_cursor(conp, CM_ERASE); @@ -1436,7 +1447,7 @@ int unit = conp->vc_num; struct display *p = &fb_display[unit]; - if (!p->can_soft_blank && console_blanked) + if (!p->can_soft_blank && conp->display_fg->vt_blanked) return; if (!width || !height) @@ -1512,7 +1523,7 @@ } } if (logo_shown >= 0) { - struct vc_data *conp2 = vc_cons[logo_shown].d; + struct vc_data *conp2 = vt_cons->vc_cons[logo_shown]; if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows) conp2->vc_top = 0; @@ -1537,12 +1548,12 @@ if (info && info->switch_con) (*info->switch_con)(unit, info); - if (p->dispsw->clear_margins && vt_cons[unit]->vc_mode == KD_TEXT) + if (p->dispsw->clear_margins && vt_cons->vc_cons[unit]->vc_mode == KD_TEXT) p->dispsw->clear_margins(conp, p, 0); if (logo_shown == -2) { logo_shown = fg_console; fbcon_show_logo(); /* This is protected above by initmem_freed */ - update_region(fg_console, + update_region(vt_cons->vc_cons[fg_console], conp->vc_origin + conp->vc_size_row * conp->vc_top, conp->vc_size_row * (conp->vc_bottom - conp->vc_top) / 2); return 0; @@ -1558,14 +1569,18 @@ if (blank < 0) /* Entering graphics mode */ return 0; +#ifdef CONFIG_PM + if (fbcon_sleeping) + return 0; +#endif /* CONFIG_PM */ fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW); if (!p->can_soft_blank) { if (blank) { if (p->visual == FB_VISUAL_MONO01) { - if (p->fb_info->screen_base) - fb_memset255(p->fb_info->screen_base, + if (info->screen_base) + fb_memset255(info->screen_base, p->var.xres_virtual*p->var.yres_virtual* p->var.bits_per_pixel>>3); } else { @@ -1590,6 +1605,7 @@ return 1; } } + if (info->fbops->fb_blank) (*info->fbops->fb_blank)(blank, info); return 0; @@ -1664,6 +1680,7 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont) { struct display *p = &fb_display[unit]; + struct vc_data *vc = p->conp; int resize; int w = op->width; int h = op->height; @@ -1676,7 +1693,7 @@ return -ENXIO; } - if (CON_IS_VISIBLE(p->conp) && softback_lines) + if (IS_VISIBLE && softback_lines) fbcon_set_origin(p->conp); resize = (w != fontwidth(p)) || (h != fontheight(p)); @@ -1757,7 +1774,7 @@ p->vrows--; updatescrollmode(p); vc_resize_con( p->var.yres/h, p->var.xres/w, unit ); - if (CON_IS_VISIBLE(conp) && softback_buf) { + if (IS_VISIBLE && softback_buf) { int l = fbcon_softback_size / conp->vc_size_row; if (l > 5) softback_end = softback_buf + l * conp->vc_size_row; @@ -1767,10 +1784,10 @@ softback_top = 0; } } - } else if (CON_IS_VISIBLE(p->conp) && vt_cons[unit]->vc_mode == KD_TEXT) { + } else if (IS_VISIBLE && vc->display_fg->vc_cons[unit]->vc_mode == KD_TEXT) { if (p->dispsw->clear_margins) p->dispsw->clear_margins(p->conp, p, 0); - update_screen(unit); + update_screen(p->conp); } if (old_data && (--REFCOUNT(old_data) == 0)) @@ -1936,7 +1953,7 @@ int i, j, k; u8 val; - if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked)) + if (!conp->vc_can_do_color || (!p->can_soft_blank && conp->display_fg->vt_blanked)) return -EINVAL; for (i = j = 0; i < 16; i++) { k = table[i]; @@ -2036,10 +2053,10 @@ if (softback_top) { if (conp->vc_num != unit) return 0; - if (vt_cons[unit]->vc_mode != KD_TEXT || !lines) + if (conp->vc_mode != KD_TEXT || !lines) return 0; if (logo_shown >= 0) { - struct vc_data *conp2 = vc_cons[logo_shown].d; + struct vc_data *conp2 = vt_cons->vc_cons[logo_shown]; if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows) conp2->vc_top = 0; @@ -2057,7 +2074,7 @@ scr_memcpyw((u16 *)q, (u16 *)p, conp->vc_size_row); } softback_in = p; - update_region(unit, conp->vc_origin, logo_lines * conp->vc_cols); + update_region(vt_cons->vc_cons[unit], conp->vc_origin, logo_lines * conp->vc_cols); } logo_shown = -1; } @@ -2080,7 +2097,7 @@ return 0; if (!p->can_soft_blank && - (console_blanked || vt_cons[unit]->vc_mode != KD_TEXT || !lines)) + (conp->display_fg->vt_blanked || conp->vc_mode != KD_TEXT || !lines)) return 0; fbcon_cursor(conp, CM_ERASE); @@ -2109,7 +2126,7 @@ static int fbcon_set_origin(struct vc_data *conp) { - if (softback_lines && !console_blanked) + if (softback_lines && !conp->display_fg->vt_blanked) fbcon_scrolldelta(conp, softback_lines); return 0; } @@ -2401,7 +2418,7 @@ else dst = fb + y1*line + x/8; for( x1 = 0; x1 < LOGO_LINE; ++x1 ) - fb_writeb(fb_readb(src++) ^ inverse, dst++); + fb_writeb(*src++ ^ inverse, dst++); } done = 1; } @@ -2447,6 +2464,39 @@ return done ? (LOGO_H + fontheight(p) - 1) / fontheight(p) : 0 ; } + +#ifdef CONFIG_PM +/* console.c doesn't do enough here */ +static int +pm_fbcon_request(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + unsigned long flags; + + switch (rqst) + { + case PM_RESUME: + acquire_console_sem(); + fbcon_sleeping = 0; + if (use_timer_cursor) { + cursor_timer.expires = jiffies+HZ/50; + add_timer(&cursor_timer); + } + release_console_sem(); + break; + case PM_SUSPEND: + acquire_console_sem(); + save_flags(flags); + cli(); + if (use_timer_cursor) + del_timer(&cursor_timer); + fbcon_sleeping = 1; + restore_flags(flags); + release_console_sem(); + break; + } + return 0; +} +#endif /* CONFIG_PM */ /* * The console `switch' structure for the frame buffer based console diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/fbmem.c linux-2.5/drivers/video/fbmem.c --- linux-2.5.23/drivers/video/fbmem.c Wed Jun 19 03:11:44 2002 +++ linux-2.5/drivers/video/fbmem.c Wed Jun 19 10:34:51 2002 @@ -132,7 +132,7 @@ extern int pmagbbfb_init(void); extern void maxinefb_init(void); extern int tx3912fb_init(void); -extern int tx3912fb_setup(char*); +extern void tx3912fb_setup(char*); extern int radeonfb_init(void); extern int radeonfb_setup(char*); extern int e1355fb_init(void); @@ -644,10 +644,7 @@ #elif defined(__i386__) || defined(__x86_64__) if (boot_cpu_data.x86 > 3) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; -#elif defined(__mips__) - pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; - pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; -#elif defined(__arm__) +#elif defined(__arm__) || defined(__mips__) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); #elif defined(__sh__) pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/matrox/matroxfb_base.c linux-2.5/drivers/video/matrox/matroxfb_base.c --- linux-2.5.23/drivers/video/matrox/matroxfb_base.c Wed Jun 19 03:11:57 2002 +++ linux-2.5/drivers/video/matrox/matroxfb_base.c Sat Jun 1 02:15:26 2002 @@ -68,7 +68,7 @@ * "Samuel Hocevar" * Fixes * - * "Anton Altaparmakov" + * "Anton Altaparmakov" * G400 MAX/non-MAX distinction * * "Ken Aaker" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/mdacon.c linux-2.5/drivers/video/mdacon.c --- linux-2.5.23/drivers/video/mdacon.c Wed Jun 19 03:11:55 2002 +++ linux-2.5/drivers/video/mdacon.c Sat Jun 1 02:15:26 2002 @@ -24,6 +24,7 @@ * * Changelog: * Paul G. (03/2001) Fix mdacon= boot prompt to use __setup(). + * 20011230 Jan.Schubert@GMX.li - consider non-Hercules MDA compatible */ #include @@ -33,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -78,8 +78,6 @@ static int mda_first_vc = 13; static int mda_last_vc = 16; -static struct vc_data *mda_display_fg = NULL; - MODULE_PARM(mda_first_vc, "1-255i"); MODULE_PARM(mda_last_vc, "1-255i"); @@ -338,7 +336,7 @@ mda_type_name = "MDA"; if (! mda_detect()) { - printk("mdacon: MDA card not detected.\n"); + printk(KERN_WARNING "mdacon: MDA card not detected.\n"); return NULL; } @@ -349,7 +347,7 @@ /* cursor looks ugly during boot-up, so turn it off */ mda_set_cursor(mda_vram_len - 1); - printk("mdacon: %s with %ldK of memory detected.\n", + printk(KERN_INFO "mdacon: %s with %ldK of memory detected.\n", mda_type_name, mda_vram_len/1024); return "MDA-2"; @@ -358,7 +356,6 @@ static void mdacon_init(struct vc_data *c, int init) { c->vc_complement_mask = 0x0800; /* reverse video */ - c->vc_display_fg = &mda_display_fg; if (init) { c->vc_cols = mda_num_columns; @@ -366,22 +363,12 @@ } else { vc_resize_con(mda_num_lines, mda_num_columns, c->vc_num); } - - /* make the first MDA console visible */ - - if (mda_display_fg == NULL) - mda_display_fg = c; - MOD_INC_USE_COUNT; } static void mdacon_deinit(struct vc_data *c) { - /* con_set_default_unimap(c->vc_num); */ - - if (mda_display_fg == c) - mda_display_fg = NULL; - + /* con_set_default_unimap(c); */ MOD_DEC_USE_COUNT; } @@ -605,28 +592,23 @@ con_invert_region: mdacon_invert_region, }; -void __init mda_console_init(void) +int __init mda_console_init(void) { if (mda_first_vc > mda_last_vc) - return; + return -EINVAL; take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0); -} - -#ifdef MODULE - -MODULE_LICENSE("GPL"); - -int init_module(void) -{ - mda_console_init(); - return 0; } -void cleanup_module(void) +void __exit mda_console_exit(void) { give_up_console(&mda_con); } +#ifdef MODULE +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MDA console driver. Default console allocation: vc/13 - vc/16"); +module_init(mda_console_init); +module_exit(mda_console_exit); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/modedb.c linux-2.5/drivers/video/modedb.c --- linux-2.5.23/drivers/video/modedb.c Wed Jun 19 03:11:54 2002 +++ linux-2.5/drivers/video/modedb.c Sat Jun 1 02:15:26 2002 @@ -41,7 +41,7 @@ #define DEFAULT_MODEDB_INDEX 0 -static const struct fb_videomode modedb[] __initdata = { +static struct fb_videomode modedb[] __initdata = { { /* 640x400 @ 70 Hz, 31.5 kHz hsync */ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, @@ -125,6 +125,10 @@ }, { /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */ NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ + NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0, FB_VMODE_NONINTERLACED }, { /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/newport_con.c linux-2.5/drivers/video/newport_con.c --- linux-2.5.23/drivers/video/newport_con.c Wed Jun 19 03:11:58 2002 +++ linux-2.5/drivers/video/newport_con.c Sat Jun 1 02:15:26 2002 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/platinumfb.h linux-2.5/drivers/video/platinumfb.h --- linux-2.5.23/drivers/video/platinumfb.h Wed Jun 19 03:11:50 2002 +++ linux-2.5/drivers/video/platinumfb.h Sat Jun 1 02:15:26 2002 @@ -158,7 +158,7 @@ /* 832x624, 75Hz (13) */ static struct platinum_regvals platinum_reg_init_13 = { 0x70, - { 864, 1680, 3360 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */ + { 864, 1696, 3360 }, { 0xff0, 4, 0, 0, 0, 0, 0x299, 0, 0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37, 0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52, @@ -310,6 +310,13 @@ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }} }; + +/* MacOS does 1680 instead of 1696 to fit 832x624@75-16bpp in 1MB */ +#define fixup_pitch(ll, info, cmode) \ + do { \ + if ((cmode) == CMODE_16 && (ll) == 1696 && info->total_vram == 0x100000) \ + (ll) = 1680; \ + } while(0) static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = { &platinum_reg_init_1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/promcon.c linux-2.5/drivers/video/promcon.c --- linux-2.5.23/drivers/video/promcon.c Wed Jun 19 03:11:56 2002 +++ linux-2.5/drivers/video/promcon.c Sat Jun 1 02:15:26 2002 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -135,7 +134,7 @@ } static void __init -promcon_init_unimap(struct vc_data *conp) +promcon_init_unimap(struct vc_data *vc) { mm_segment_t old_fs = get_fs(); struct unipair *p, *p1; @@ -156,9 +155,9 @@ k++; } set_fs(KERNEL_DS); - con_clear_unimap(conp->vc_num, NULL); - con_set_unimap(conp->vc_num, k, p); - con_protect_unimap(conp->vc_num, 1); + con_clear_unimap(vc, NULL); + con_set_unimap(vc, k, p); + con_protect_unimap(vc, 1); set_fs(old_fs); kfree(p); } @@ -176,11 +175,11 @@ p = *conp->vc_uni_pagedir_loc; if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir || !--conp->vc_uni_pagedir_loc[1]) - con_free_unimap(conp->vc_num); + con_free_unimap(vc); conp->vc_uni_pagedir_loc = promcon_uni_pagedir; promcon_uni_pagedir[1]++; if (!promcon_uni_pagedir[0] && p) { - promcon_init_unimap(conp); + promcon_init_unimap(vc); } if (!init) { if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1) @@ -189,13 +188,13 @@ } static void -promcon_deinit(struct vc_data *conp) +promcon_deinit(struct vc_data *vc) { /* When closing the last console, reset video origin */ if (!--promcon_uni_pagedir[1]) - con_free_unimap(conp->vc_num); - conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir; - con_set_default_unimap(conp->vc_num); + con_free_unimap(vc); + vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; + con_set_default_unimap(vc); } static int @@ -243,7 +242,7 @@ unsigned char save; int i, last = 0; - if (console_blanked) + if (conp->display_fg->vt_blanked) return; if (count <= 0) @@ -329,7 +328,7 @@ { unsigned short s; - if (console_blanked) + if (conp->display_fg->vt_blanked) return; scr_writew(c, &s); @@ -342,7 +341,7 @@ unsigned char buf[256], *b = buf; int i, j; - if (console_blanked) + if (conp->display_fg->vt_blanked) return; b += promcon_start(conp, b); @@ -411,7 +410,7 @@ { char buf[256], *b = buf; - if (console_blanked) + if (conp->display_fg->vt_blanked) return; b += promcon_start(conp, b); @@ -482,7 +481,7 @@ unsigned short *s; int i; - if (console_blanked) + if (conp->display_fg->vt_blanked) return 0; p += promcon_start(conp, p); @@ -602,5 +601,5 @@ else #endif if (conswitchp == &prom_con) - promcon_init_unimap(vc_cons[fg_console].d); + promcon_init_unimap(vt_cons->vc_cons[fg_console]); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/pvr2fb.c linux-2.5/drivers/video/pvr2fb.c --- linux-2.5.23/drivers/video/pvr2fb.c Wed Jun 19 03:11:47 2002 +++ linux-2.5/drivers/video/pvr2fb.c Sat Jun 1 02:15:26 2002 @@ -163,17 +163,6 @@ static int pvr2fb_inverse = 0; static struct { u_short red, green, blue, alpha; } palette[256]; -static 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; static char pvr2fb_name[16] = "NEC PowerVR2"; @@ -211,8 +200,6 @@ struct fb_info *info); static int pvr2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); -static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); static int pvr2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info); static int pvr2fb_blank(int blank, struct fb_info *info); @@ -257,7 +244,7 @@ fb_get_var: pvr2fb_get_var, fb_set_var: pvr2fb_set_var, fb_get_cmap: pvr2fb_get_cmap, - fb_set_cmap: pvr2fb_set_cmap, + fb_set_cmap: gen_set_cmap, fb_setcolreg: pvr2fb_setcolreg, fb_pan_display: pvr2fb_pan_display, fb_blank: pvr2fb_blank, @@ -394,19 +381,19 @@ #ifdef FBCON_HAS_CFB16 case 16: display->dispsw = &fbcon_cfb16; - display->dispsw_data = fbcon_cmap.cfb16; + display->dispsw_data = info->pseudo_palette; break; #endif #ifdef FBCON_HAS_CFB24 case 24: display->dispsw = &fbcon_cfb24; - display->dispsw_data = fbcon_cmap.cfb24; + display->dispsw_data = info->pseudo_palette; break; #endif #ifdef FBCON_HAS_CFB32 case 32: display->dispsw = &fbcon_cfb32; - display->dispsw_data = fbcon_cmap.cfb32; + display->dispsw_data = info->pseudo_palette; break; #endif default: @@ -474,27 +461,6 @@ return 0; } -/* Set the colormap */ - -static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - int err; - - if (!fb_display[con].cmap.len) { /* no colormap allocated? */ - if ((err = fb_alloc_cmap(&fb_display[con].cmap, - 1<currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, info); - else - fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); - - return 0; -} - static int pvr2fbcon_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ @@ -575,7 +541,7 @@ switch (currbpp) { #ifdef FBCON_HAS_CFB16 case 16: /* RGB 565 */ - fbcon_cmap.cfb16[regno] = (red & 0xf800) | + ((u16 *)(info->pseudo_palette))[regno] = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); break; @@ -583,13 +549,13 @@ #ifdef FBCON_HAS_CFB24 case 24: /* RGB 888 */ red >>= 8; green >>= 8; blue >>= 8; - fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | blue; + ((u32 *)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue; break; #endif #ifdef FBCON_HAS_CFB32 case 32: /* ARGB 8888 */ red >>= 8; green >>= 8; blue >>= 8; - fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | blue; + ((u32 *)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue; break; #endif default: @@ -1022,7 +988,8 @@ fb_info.changevar = NULL; fb_info.node = NODEV; fb_info.fbops = &pvr2fb_ops; - fb_info.screen_base = (char *) videomemory; + fb_info.screen_base = videomemory; + fb_info.pseudo_palette = pseudo_palette; fb_info.disp = &disp; fb_info.currcon = -1; fb_info.switch_con = &pvr2fbcon_switch; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/radeon.h linux-2.5/drivers/video/radeon.h --- linux-2.5.23/drivers/video/radeon.h Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/video/radeon.h Sat Jun 1 02:15:26 2002 @@ -96,7 +96,9 @@ #define MEM_VGA_WP_SEL 0x0038 #define MEM_VGA_RP_SEL 0x003C #define HDP_DEBUG 0x0138 -#define SW_SEMAPHORE 0x013C +#define SW_SEMAPHORE 0x013C +#define CRTC2_GEN_CNTL 0x03f8 +#define CRTC2_DISPLAY_BASE_ADDR 0x033c #define SURFACE_CNTL 0x0B00 #define SURFACE0_LOWER_BOUND 0x0B04 #define SURFACE1_LOWER_BOUND 0x0B14 @@ -337,6 +339,7 @@ #define DST_Y_X 0x1438 #define DST_WIDTH_HEIGHT 0x1598 #define DST_HEIGHT_WIDTH 0x143c +#define DST_OFFSET 0x1404 #define SRC_CLUT_ADDRESS 0x1780 #define SRC_CLUT_DATA 0x1784 #define SRC_CLUT_DATA_RD 0x1788 @@ -380,6 +383,7 @@ #define LVDS_GEN_CNTL 0x02d0 #define LVDS_PLL_CNTL 0x02d4 #define TMDS_CRC 0x02a0 +#define TMDS_TRANSMITTER_CNTL 0x02a4 #define RADEON_BASE_CODE 0x0f0b #define RADEON_BIOS_0_SCRATCH 0x0010 @@ -406,11 +410,11 @@ #define SPLL_CNTL 0x000c #define SCLK_CNTL 0x000d #define MPLL_CNTL 0x000e +#define MDLL_CKO 0x000f #define MCLK_CNTL 0x0012 #define AGP_PLL_CNTL 0x000b #define PLL_TEST_CNTL 0x0013 - /* MCLK_CNTL bit constants */ #define FORCEON_MCLKA (1 << 16) #define FORCEON_MCLKB (1 << 17) @@ -474,10 +478,17 @@ #define CRTC_INTERLACE_EN (1 << 1) #define CRTC_EXT_DISP_EN (1 << 24) #define CRTC_EN (1 << 25) +#define CRTC_DISP_REQ_EN_B (1 << 26) /* CRTC_STATUS bit constants */ #define CRTC_VBLANK 0x00000001 +/* CRTC2_GEN_CNTL bit constants */ +#define CRT2_ON (1 << 7) +#define CRTC2_DISPLAY_DIS (1 << 23) +#define CRTC2_EN (1 << 25) +#define CRTC2_DISP_REQ_EN_B (1 << 26) + /* CUR_OFFSET, CUR_HORZ_VERT_POSN, CUR_HORZ_VERT_OFF bit constants */ #define CUR_LOCK 0x80000000 @@ -523,14 +534,26 @@ #define LVDS_PANEL_TYPE (1 << 2) #define LVDS_PANEL_FORMAT (1 << 3) #define LVDS_EN (1 << 7) +#define LVDS_BL_MOD_LEVEL_MASK 0x0000ff00 +#define LVDS_BL_MOD_LEVEL_SHIFT 8 +#define LVDS_BL_MOD_EN (1 << 16) #define LVDS_DIGON (1 << 18) #define LVDS_BLON (1 << 19) #define LVDS_SEL_CRTC2 (1 << 23) +#define LVDS_STATE_MASK \ + (LVDS_ON | LVDS_DISPLAY_DIS | LVDS_BL_MOD_LEVEL_MASK | \ + LVDS_EN | LVDS_DIGON | LVDS_BLON) /* LVDS_PLL_CNTL bit constatns */ #define HSYNC_DELAY_SHIFT 0x1c #define HSYNC_DELAY_MASK (0xf << 0x1c) +/* TMDS_TRANSMITTER_CNTL bit constants */ +#define TMDS_PLL_EN (1 << 0) +#define TMDS_PLLRST (1 << 1) +#define TMDS_RAN_PAT_RST (1 << 7) +#define ICHCSEL (1 << 28) + /* FP_HORZ_STRETCH bit constants */ #define HORZ_STRETCH_RATIO_MASK 0xffff #define HORZ_STRETCH_RATIO_MAX 4096 @@ -561,6 +584,7 @@ #define DAC_4BPP_PIX_ORDER 0x00000200 #define DAC_CRC_EN 0x00080000 #define DAC_MASK_ALL (0xff << 24) +#define DAC_EXPAND_MODE (1 << 14) #define DAC_VGA_ADR_EN (1 << 13) #define DAC_RANGE_CNTL (3 << 0) #define DAC_BLANKING (1 << 2) @@ -742,6 +766,15 @@ #define DP_SRC_HOST 0x00000300 #define DP_SRC_HOST_BYTEALIGN 0x00000400 +/* MPLL_CNTL bit constants */ +#define MPLL_RESET 0x00000001 + +/* MDLL_CKO bit constants */ +#define MDLL_CKO__MCKOA_RESET 0x00000002 + +/* VCLK_ECP_CNTL constants */ +#define PIXCLK_ALWAYS_ONb 0x00000040 +#define PIXCLK_DAC_ALWAYS_ONb 0x00000080 /* masks */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.23/drivers/video/radeonfb.c linux-2.5/drivers/video/radeonfb.c --- linux-2.5.23/drivers/video/radeonfb.c Wed Jun 19 03:11:59 2002 +++ linux-2.5/drivers/video/radeonfb.c Sat Jun 1 02:15:26 2002 @@ -15,13 +15,17 @@ * blanking, pan_display, and cmap fixes, 0.1.0 * 2001-10-10 Radeon 7500 and 8500 support, and experimental * flat panel support, 0.1.1 + * 2001-11-17 Radeon M6 (ppc) support, Daniel Berlin, 0.1.2 + * 2001-11-18 DFP fixes, Kevin Hendricks, 0.1.3 + * 2001-11-29 more cmap, backlight fixes, Benjamin Herrenschmidt + * 2002-01-18 DFP panel detection via BIOS, Michael Clark, 0.1.4 * * Special thanks to ATI DevRel team for their hardware donations. * */ -#define RADEON_VERSION "0.1.1" +#define RADEON_VERSION "0.1.4" #include @@ -39,12 +43,33 @@ #include #include #include +#include #include #if defined(__powerpc__) #include +#include +#include