diff -u --recursive --new-file v2.1.128/linux/CREDITS linux/CREDITS --- v2.1.128/linux/CREDITS Thu Nov 12 16:21:17 1998 +++ linux/CREDITS Mon Nov 16 10:32:58 1998 @@ -429,7 +429,7 @@ N: Cort Dougan E: cort@cs.nmt.edu W: http://www.cs.nmt.edu/~cort/ -D: PowerPC PReP port +D: PowerPC S: Computer Science Department S: New Mexico Tech S: Socorro, New Mexico 87801 diff -u --recursive --new-file v2.1.128/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.128/linux/Documentation/Configure.help Thu Nov 12 16:21:17 1998 +++ linux/Documentation/Configure.help Sun Nov 15 10:12:01 1998 @@ -1759,6 +1759,58 @@ which includes a server that supports the frame buffer device directly (XF68_FBDev). +Matrox unified accelerated driver +CONFIG_FB_MATROX + Say Y here if you have Matrox Millenium, Matrox Millenium II, Matrox + Mystique, Matrox Mystique 220 or Matrox Productiva G100 in your box. + At this time, G100 support is untested and G200 support does not + exist at all. If you want, you can select M, in this case module + matroxfb.o will be created. + You can pass parameters into driver if it is compiled into kernel by + specifying "video=matrox:XXX", where meaning of XXX you can found at + the end of main source file (drivers/video/matroxfb.c) at boottime. + Same parameters can be passed into insmod if driver is used as + module. + +Matrox Millenium support +CONFIG_FB_MATROX_MILLENIUM + Say Y here if you have Matrox Millenium or Matrox Millenium II in the + box. If you select "Advanced lowlevel driver options", you should + check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp packed pixel, 24 + bpp packed pixel and 32 bpp packed pixel. You can also use font + widths different from 8. + +Matrox Mystique support +CONFIG_FB_MATROX_MYSTIQUE + Say Y here if you have Matrox Mystique or Matrox Mystique 220 in the + box. If you select "Advanced lowlevel driver options", you should + check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel + and 32 bpp packed pixel. You can also use font widths different + from 8. + +Matrox G100 support +CONFIG_FB_MATROX_G100 + Say Y here if you have Matrox Productiva G100 in the box. But THIS + DRIVER IS NOT TESTED BECAUSE OF I HAVE NO G100 board and G100 + technical sheets are top secret at this time. But driver should not + cause any damage to your computer. + If you select "Advanced lowlevel driver options", you should check + 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and + 32 bpp packed pixel. You can also use font widths different from 8. + +Matrox unified driver multihead support +CONFIG_FB_MATROX_MULTIHEAD + Say Y here if you have more than one (supported) Matrox device in + computer and you want to use all of them. If you have only one + device, you should say N because of driver compiled with Y is larger + and a bit slower, especially on ia32 (ix86). + If you compiled driver as module, you are VERY interested in speed + and you can use 40KB of memory per each Matrox device, you can + compile driver without multihead support and instead of it insmod + more module instances. In this case, you MUST specify parameter dev=N + to insmod, where N is sequential number of Matrox device (0 = first, + 1 = second and so on). + MDA text console (dual-headed) CONFIG_MDA_CONSOLE Say Y here if you have an old MDA or monochrome Hercules graphics @@ -3740,6 +3792,13 @@ The module will be called fdomain.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Future Domain MCS-600/700 SCSI support +CONFIG_SCSI_FD_MCS + This is support for Future Domain MCS 600/700 MCA SCSI adapters. Some + PS/2s are also equipped with IBM Fast SCSI Adapter/A which is an OEM + of the MCS 700. This driver also supports Reply SB16/SCSI card (the + SCSI part). It supports multiple adapters in the same system. + Generic NCR5380/53c400 SCSI support CONFIG_SCSI_GENERIC_NCR5380 This is the generic NCR family of SCSI controllers, not to be @@ -3878,9 +3937,8 @@ this feature, enter 0 or 1 here (it doesn't matter which). The default value is 8 and should be supported by most hard disks. - This option has no effect for adapters with NVRAM, since the driver - will get this information from the user set-up. It also can be - overridden using a boot setup option, as follows (example): + This value can be overridden from the boot command line using the + 'tags' option as follows (example): 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to 4, set queue depth to 16 for target 2 and target 3 on controller 0 and set queue depth to 10 for target 0 / lun 2 on controller 1. @@ -3895,12 +3953,10 @@ CONFIG_SCSI_NCR53C8XX_MAX_TAGS This option allows you to specify the maximum number of commands that can be queued to any device, when tagged command queuing is - possible. The default value is 32. Minimum is 2, maximum is 64. For - value less than 32, this option only saves a little memory - (8*7*(32-MAXTAGS) bytes), so using less than 32 isn't worth it. For - value greater than 32, latency on reselection will be increased by 1 - or 2 micro-seconds. - + possible. The default value is 32. Minimum is 2, maximum is 64. + Modern hard disks are able to support 64 tags and even more, but + donnot seem to be faster when more than 32 tags are being used. + So, the normal answer here is to go with the default value 32 unless you are using very large hard disks with large cache (>= 1 MB) that are able to take advantage of more than 32 tagged commands. @@ -5013,9 +5069,9 @@ Comtrol Hostess SV-11 support CONFIG_HOSTESS_SV11 - This is a network card for high speed synchronous serial links. It - is commonly used to connect to Cisco equipment over HSSI links. At - this point, the driver can only be compiled as a module. + This is a network card for low speed synchronous serial links, at + up to 256Kbits. It supports both PPP and Cisco HDLC + At this point, the driver can only be compiled as a module. WAN Drivers CONFIG_WAN_DRIVERS @@ -5576,7 +5632,7 @@ is for you, read the Ethernet-HOWTO, available via FTP (user: anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. -AT1700 support +AT1700/1720 support CONFIG_AT1700 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available via FTP (user: anonymous) in @@ -9627,7 +9683,7 @@ Ariadne support CONFIG_ARIADNE - If you have a VillageTronics Ariadne Ethernet adapter, say Y. + If you have a Village Tronic Ariadne Ethernet adapter, say Y. Otherwise, say N. This driver is also available as a module ( = code which can be @@ -9637,7 +9693,7 @@ Ariadne II support CONFIG_ARIADNE2 - If you have a VillageTronics Ariadne II Ethernet adapter, say Y. + If you have a Village Tronic Ariadne II Ethernet adapter, say Y. Otherwise, say N. This driver is also available as a module ( = code which can be @@ -10213,7 +10269,7 @@ # LocalWords: INSNS Ataris AutoConfig ZORRO OCS AMIFB Agnus Denise ECS CDTV GB # LocalWords: AGA Cybervision CYBER GSP TMS DMI Zorro ACSI ROMs SLM BioNet GVP # LocalWords: PAMsNet TekMagic Cyberstorm MkI CYBERSTORMII MkII BLZ onboard cx -# LocalWords: VillageTronics ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB +# LocalWords: Village Tronic ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB # LocalWords: Rhotron BioData's Multiface AMIGAMOUSE COPCON Amiga's bitplanes # LocalWords: ATARIMOUSE MFPSER SCC's MegaSTE ESCC Atari's GVPIOEXT DMASOUND # LocalWords: fdutils cisco univercd rpcg htm iface lapb LAPBETHER tpqic qic diff -u --recursive --new-file v2.1.128/linux/Documentation/networking/ltpc.txt linux/Documentation/networking/ltpc.txt --- v2.1.128/linux/Documentation/networking/ltpc.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/networking/ltpc.txt Fri Nov 13 10:29:43 1998 @@ -6,18 +6,37 @@ driver applies only to the one with the 65c02 processor chip on it. To include it in the kernel, select the CONFIG_LTPC switch in the -configuration dialog; at this time (kernel 2.1.23) compiling it as -a module will not work. +configuration dialog. You can also compile it as a module. + +While the driver will attempt to autoprobe the I/O port address, IRQ +line, and DMA channel of the card, this does not always work. For +this reason, you should be prepared to supply these parameters +yourself. (see "Card Configuration" below for how to determine or +change the settings on your card) + +When the driver is compiled into the kernel, you can add a line such +as the following to your /etc/lilo.conf: + + append="ltpc=0x240,9,1" + +where the parameters (in order) are the port address, IRQ, and DMA +channel. The second and third values can be omitted, in which case +the driver will try to determine them itself. + +If you load the driver as a module, you can pass the parameters "io=", +"irq=", and "dma=" on the command line with insmod or modprobe, or add +them as options in /etc/conf.modules: + + alias lt0 ltpc # autoload the module when the interface is configured + options ltpc io=0x240 irq=9 dma=1 Before starting up the netatalk demons (perhaps in rc.local), you need to add a line such as: -/sbin/ifconfig ltalk0 127.0.0.42 - + /sbin/ifconfig lt0 127.0.0.42 -The driver will autoprobe, and you should see a message like: -"LocalTalk card found at 240, IR9, DMA1." -at bootup. +The address is unimportant - however, the card needs to be configured +with ifconfig so that Netatalk can find it. The appropriate netatalk configuration depends on whether you are attached to a network that includes AppleTalk routers or not. If, @@ -25,22 +44,22 @@ printers, you need to set up netatalk to "seed". The way I do this is to have the lines -dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033" -ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033" + dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033" + lt0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033" in my atalkd.conf. What is going on here is that I need to fool netatalk into thinking that there are two AppleTalk interfaces -present -- otherwise it refuses to seed. This is a hack, and a -more permanent solution would be to alter the netatalk code. -Note that the dummy driver needs to accept multicasts also -- earlier -versions of dummy.c may need to be patched. - +present; otherwise, it refuses to seed. This is a hack, and a more +permanent solution would be to alter the netatalk code. Also, make +sure you have the correct name for the dummy interface - If it's +compiled as a module, you will need to refer to it as "dummy0" or some +such. If you are attached to an extended AppleTalk network, with routers on it, then you don't need to fool around with this -- the appropriate line in atalkd.conf is -ltalk0 -phase 1 + lt0 -phase 1 -------------------------------------- @@ -74,19 +93,32 @@ -------------------------------------- IP: - Many people are interested in this driver in order to use IP -when LocalTalk, but no Ethernet, is available. While the code to do -this is not strictly speaking part of this driver, an experimental -version is available which seems to work under kernel 2.0.xx. It is -not yet functional in the 2.1.xx kernels. + +Yes, it is possible to do IP over LocalTalk. However, you can't just +treat the LocalTalk device like an ordinary Ethernet device, even if +that's what it looks like to Netatalk. + +Instead, you follow the same procedure as for doing IP in EtherTalk. +See Documentation/networking/ipddp.txt for more information about the +kernel driver and userspace tools needed. -------------------------------------- BUGS: -2.0.xx: - -2.1.xx: The module support doesn't work yet. +IRQ autoprobing often doesn't work on a cold boot. To get around +this, either compile the driver as a module, or pass the parameters +for the card to the kernel as described above. + +Also, as usual, autoprobing is not recommended when you use the driver +as a module. (though it usually works at boot time, at least) + +Polled mode is *really* slow sometimes, but this seems to depend on +the configuration of the network. + +It may theoretically be possible to use two LTPC cards in the same +machine, but this is unsupported, so if you really want to do this, +you'll probably have to hack the initialization code a bit. ______________________________________ @@ -96,3 +128,4 @@ -- Bradford Johnson +-- Updated 11/09/1998 by David Huggins-Daines diff -u --recursive --new-file v2.1.128/linux/Documentation/sysctl/README linux/Documentation/sysctl/README --- v2.1.128/linux/Documentation/sysctl/README Wed Jun 24 22:54:02 1998 +++ linux/Documentation/sysctl/README Fri Nov 13 10:07:26 1998 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/*/* version 0.1 +Documentation for /proc/sys/ kernel version 2.1.128 (c) 1998, Rik van Riel 'Why', I hear you ask, 'would anyone even _want_ documentation @@ -12,6 +12,9 @@ Furthermore, the programmers who built sysctl have built it to be actually used, not just for the fun of programming it :-) +If you prefer HTML, feel free to visit the Linux-MM homepage +... + ============================================================== Legal blurb: @@ -58,9 +61,9 @@ debug/ dev/ device specific information (eg dev/cdrom/info) fs/ specific filesystems + filehandle, inode, dentry and quota tuning binfmt_misc kernel/ global kernel info / tuning - open file / inode tuning miscellaneous stuff net/ networking stuff, for documentation look in: diff -u --recursive --new-file v2.1.128/linux/Documentation/sysctl/fs.txt linux/Documentation/sysctl/fs.txt --- v2.1.128/linux/Documentation/sysctl/fs.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sysctl/fs.txt Fri Nov 13 10:07:26 1998 @@ -0,0 +1,116 @@ +Documentation for /proc/sys/fs/* kernel version 2.1.128 + (c) 1998, Rik van Riel + +For general info and legal blurb, please look in README. + +============================================================== + +This file contains documentation for the sysctl files in +/proc/sys/fs/ and is valid for Linux kernel version 2.1. + +The files in this directory can be used to tune and monitor +miscellaneous and general things in the operation of the Linux +kernel. Since some of the files _can_ be used to screw up your +system, it is advisable to read both documentation and source +before actually making adjustments. + +Currently, these files are in /proc/sys/fs: +- dentry-state +- dquot-max +- dquot-nr +- file-max +- file-nr +- inode-max +- inode-nr +- inode-state + +Documentation for the files in /proc/sys/fs/binfmt_misc is +in Documentation/binfmt_misc.txt. + +============================================================== + +dentry-state: + +From linux/fs/dentry.c: +-------------------------------------------------------------- +struct { + int nr_dentry; + int nr_unused; + int age_limit; /* age in seconds */ + int want_pages; /* pages requested by system */ + int dummy[2]; +} dentry_stat = {0, 0, 45, 0,}; +-------------------------------------------------------------- + +Dentries are dynamically allocated and deallocated, and +nr_dentry seems to be 0 all the time. Hence it's safe to +assume that only nr_unused, age_limit and want_pages are +used. Nr_unused seems to be exactly what its name says. +Age_limit is the age in seconds after which dcache entries +can be reclaimed when memory is short and want_pages is +nonzero when shrink_dcache_pages() has been called and the +dcache isn't pruned yet. + +============================================================== + +dquot-max & dquot-nr: + +The file dquot-max shows the maximum number of cached disk +quota entries. + +The file dquot-nr shows the number of allocated disk quota +entries and the number of free disk quota entries. + +If the number of free cached disk quotas is very low and +you have some awesome number of simultaneous system users, +you might want to raise the limit. + +============================================================== + +file-max & file-nr: + +The kernel allocates file handles dynamically, but as yet it +doesn't free them again. + +The value in file-max denotes the maximum number of file- +handles that the Linux kernel will allocate. When you get lots +of error messages about running out of file handles, you might +want to increase this limit. + +The three values in file-nr denote the number of allocated +file handles, the number of used file handles and the maximum +number of file handles. When the allocated file handles come +close to the maximum, but the number of actually used ones is +far behind, you've encountered a peak in your usage of file +handles and you don't need to increase the maximum. + +============================================================== + +inode-max, inode-nr & inode-state: + +As with file handles, the kernel allocates the inode structures +dynamically, but can't free them yet. + +The value in inode-max denotes the maximum number of inode +handlers. This value should be 3-4 times larger than the value +in file-max, since stdin, stdout and network sockets also +need an inode struct to handle them. When you regularly run +out of inodes, you need to increase this value. + +The file inode-nr contains the first two items from +inode-state, so we'll skip to that file... + +Inode-state contains three actual numbers and four dummies. +The actual numbers are, in order of appearance, nr_inodes, +nr_free_inodes and preshrink. + +Nr_inodes stands for the number of inodes the system has +allocated, this can be slightly more than inode-max because +Linux allocates them one pageful at a time. + +Nr_free_inodes represents the number of free inodes (?) and +preshrink is nonzero when the nr_inodes > inode-max and the +system needs to prune the inode list instead of allocating +more. + + diff -u --recursive --new-file v2.1.128/linux/Documentation/sysctl/kernel.txt linux/Documentation/sysctl/kernel.txt --- v2.1.128/linux/Documentation/sysctl/kernel.txt Thu Nov 12 16:21:17 1998 +++ linux/Documentation/sysctl/kernel.txt Fri Nov 13 10:07:26 1998 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/kernel/* version 0.1 +Documentation for /proc/sys/kernel/* kernel version 2.1.128 (c) 1998, Rik van Riel For general info and legal blurb, please look in README. @@ -14,26 +14,27 @@ system, it is advisable to read both documentation and source before actually making adjustments. -Currently, these files are in /proc/sys/kernel: +Currently, these files might (depending on your configuration) +show up in /proc/sys/kernel: - acct - ctrl-alt-del - dentry-state - domainname -- file-max -- file-nr - hostname -- inode-max -- inode-nr -- inode-state +- htab-reclaim [ PPC only ] +- java-appletviewer [ binfmt_java, obsolete ] +- java-interpreter [ binfmt_java, obsolete ] - modprobe ==> Documentation/kmod.txt - osrelease - ostype - panic +- powersave-nap [ PPC only ] - printk - real-root-dev ==> Documentation/initrd.txt -- reboot-cmd ==> SPARC specific -- securelevel +- reboot-cmd [ SPARC only ] +- sg-big-buff [ generic SCSI device (sg) ] - version +- zero-paged [ PPC only ] ============================================================== @@ -69,30 +70,6 @@ ============================================================== -dentry-state: - -From linux/fs/dentry.c: --------------------------------------------------------------- -struct { - int nr_dentry; - int nr_unused; - int age_limit; /* age in seconds */ - int want_pages; /* pages requested by system */ - int dummy[2]; -} dentry_stat = {0, 0, 45, 0,}; --------------------------------------------------------------- - -Dentries are dynamically allocated and deallocated, and -nr_dentry seems to be 0 all the time. Hence it's safe to -assume that only nr_unused, age_limit and want_pages are -used. Nr_unused seems to be exactly what its name says. -Age_limit is the age in seconds after which dcache entries -can be reclaimed when memory is short and want_pages is -nonzero when shrink_dcache_pages() has been called and the -dcache isn't pruned yet. - -============================================================== - domainname & hostname: These files can be controlled to set the domainname and @@ -104,52 +81,12 @@ ============================================================== -file-max & file-nr: - -The kernel allocates file handles dynamically, but as yet it -doesn't free them again. - -The value in file-max denotes the maximum number of file- -handles that the Linux kernel will allocate. When you get lots -of error messages about running out of file handles, you might -want to increase this limit. - -The three values in file-nr denote the number of allocated -file handles, the number of used file handles and the maximum -number of file handles. When the allocated file handles come -close to the maximum, but the number of actually used ones is -far behind, you've encountered a peak in your usage of file -handles and you don't need to increase the maximum. - -============================================================== - -inode-max, inode-nr & inode-state: - -As with file handles, the kernel allocates the inode structures -dynamically, but can't free them yet. - -The value in inode-max denotes the maximum number of inode -handlers. This value should be 3-4 times larger than the value -in file-max, since stdin, stdout and network sockets also -need an inode struct to handle them. When you regularly run -out of inodes, you need to increase this value. - -The file inode-nr contains the first two items from -inode-state, so we'll skip to that file... - -Inode-state contains three actual numbers and four dummies. -The actual numbers are, in order of appearance, nr_inodes, -nr_free_inodes and preshrink. - -Nr_inodes stands for the number of inodes the system has -allocated, this can be slightly more than inode-max because -Linux allocates them one pageful at a time. - -Nr_free_inodes represents the number of free inodes (?) and -preshrink is nonzero when the nr_inodes > inode-max and the -system needs to prune the inode list instead of allocating -more. +htab-reclaim: (PPC only) +Setting this to a non-zero value, the PowerPC htab +(see Documentation/powerpc/ppc_htab.txt) is pruned +each time the system hits the idle loop. + ============================================================== osrelease, ostype & version: @@ -177,6 +114,13 @@ ============================================================== +powersave-nap: (PPC only) + +If set, Linux-PPC will use the 'nap' mode of powersaving, +otherwise the 'doze' mode will be used. + +============================================================== + printk: The four values in printk denote: console_loglevel, @@ -202,27 +146,30 @@ ============================================================== -securelevel: +reboot-cmd: (Sparc only) -When the value in this file is nonzero, root is prohibited -from: -- changing the immutable and append-only flags on files -- changing sysctl things (limited ???) +??? This seems to be a way to give an argument to the Sparc +ROM/Flash boot loader. Maybe to tell it what to do after +rebooting. ??? ============================================================== -real-root-dev: (CONFIG_INITRD only) +sg-big-buff: -This file is used to configure the real root device when using -an initial ramdisk to configure the system before switching to -the 'real' root device. See linux/Documentation/initrd.txt for -more info. +This file shows the size of the generic SCSI (sg) buffer. +You can't tune it just yet, but you could change it on +compile time by editing include/scsi/sg.h and changing +the value of SG_BIG_BUFF. -============================================================== +There shouldn't be any reason to change this value. If +you can come up with one, you probably know what you +are doing anyway :) -reboot-cmd: (Sparc only) +============================================================== -??? This seems to be a way to give an argument to the Sparc -ROM/Flash boot loader. Maybe to tell it what to do after -rebooting. ??? +zero-paged: (PPC only) +When enabled (non-zero), Linux-PPC will pre-zero pages in +the idle loop, possibly speeding up get_free_pages. Since +this only affects what the idle loop is doing, you should +enable this and see if anything changes. diff -u --recursive --new-file v2.1.128/linux/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt --- v2.1.128/linux/Documentation/sysctl/vm.txt Wed Jun 24 22:54:02 1998 +++ linux/Documentation/sysctl/vm.txt Fri Nov 13 10:07:26 1998 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/vm/* version 0.1 +Documentation for /proc/sys/vm/* kernel version 2.1.128 (c) 1998, Rik van Riel For general info and legal blurb, please look in README. @@ -20,8 +20,8 @@ - kswapd - overcommit_memory - pagecache +- pagetable_cache - swapctl -- swapout_interval ============================================================== @@ -56,7 +56,7 @@ } bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}}; -------------------------------------------------------------- -The first parameter governs the maximum number of of dirty +The first parameter governs the maximum number of dirty buffers in the buffer cache. Dirty means that the contents of the buffer still have to be written to disk (as opposed to a clean buffer, which can just be forgotten about). @@ -101,8 +101,9 @@ min_percent -- this is the minimum percentage of memory that should be spent on buffer memory borrow_percent -- when Linux is short on memory, and the - buffer cache uses more memory, free pages - are stolen from it + buffer cache uses more memory than this, + the MM subsystem will prune the buffercache + more heavily than other memory max_percent -- this is the maximum amount of memory that can be used for buffer memory @@ -112,25 +113,17 @@ This file contains the values in the struct freepages. That struct contains three members: min, low and high. -Although the goal of the Linux memory management subsystem -is to avoid fragmentation and make large chunks of free -memory (so that we can hand out DMA buffers and such), there -still are some page-based limits in the system, mainly to -make sure we don't waste too much memory trying to get large -free area's. - The meaning of the numbers is: freepages.min When the number of free pages in the system reaches this number, only the kernel can allocate more memory. -freepages.low If memory is too fragmented, the swapout - daemon is started, except when the number - of free pages is larger than freepages.low. -freepages.high The swapping daemon exits when memory is - sufficiently defragmented, when the number - of free pages reaches freepages.high or when - it has tried the maximum number of times. +freepages.low If the number of free pages gets below this + point, the kernel starts swapping agressively. +freepages.high The kernel tries to keep up to this amount of + memory free; if memory comes below this point, + the kernel gently starts swapping in the hopes + that it never has to do real agressive swapping. ============================================================== @@ -210,7 +203,8 @@ This file does exactly the same as buffermem, only this file controls the struct page_cache, and thus controls -the amount of memory allowed for memory mapping of files. +the amount of memory allowed for memory mapping and generic +caching of files. You don't want the minimum level to be too low, otherwise your system might thrash when memory is tight or fragmentation @@ -218,6 +212,23 @@ ============================================================== +pagetable_cache: + +The kernel keeps a number of page tables in a per-processor +cache (this helps a lot on SMP systems). The cache size for +each processor will be between the low and the high value. + +On a low-memory, single CPU system you can safely set these +values to 0 so you don't waste the memory. On SMP systems it +is used so that the system can do fast pagetable allocations +without having to aquire the kernel memory lock. + +For large systems, the settings are probably OK. For normal +systems they won't hurt a bit. For small systems (<16MB ram) +it might be advantageous to set both values to 0. + +============================================================== + swapctl: This file contains no less than 8 variables. @@ -274,14 +285,4 @@ might want to either increase sc_bufferout_weight, or decrease the value of sc_pageout_weight. -============================================================== - -swapout_interval: - -The single value in this file controls the amount of time -between successive wakeups of kswapd when nr_free_pages is -between free_pages_low and free_pages_high. The default value -of HZ/4 is usually right, but when kswapd can't keep up with -the number of allocations in your system, you might want to -decrease this number. diff -u --recursive --new-file v2.1.128/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.128/linux/MAINTAINERS Thu Nov 12 16:21:17 1998 +++ linux/MAINTAINERS Mon Nov 16 10:32:58 1998 @@ -387,7 +387,7 @@ LINUX FOR POWERPC (PREP) P: Cort Dougan M: cort@cs.nmt.edu -W: http://www.cs.nmt.edu/~linuxppc/ +W: http://linuxppc.cs.nmt.edu/ S: Maintained LINUX FOR POWER MACINTOSH diff -u --recursive --new-file v2.1.128/linux/Makefile linux/Makefile --- v2.1.128/linux/Makefile Thu Nov 12 16:21:17 1998 +++ linux/Makefile Thu Nov 12 16:21:37 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 128 +SUBLEVEL = 129 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.1.128/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.128/linux/arch/i386/defconfig Sun Nov 8 14:02:42 1998 +++ linux/arch/i386/defconfig Mon Nov 16 22:50:28 1998 @@ -275,6 +275,7 @@ CONFIG_LOCKD=y # CONFIG_CODA_FS is not set # CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_SYSV_FS is not set diff -u --recursive --new-file v2.1.128/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.1.128/linux/arch/i386/kernel/i386_ksyms.c Tue Jul 28 14:21:07 1998 +++ linux/arch/i386/kernel/i386_ksyms.c Fri Nov 13 10:29:44 1998 @@ -98,6 +98,9 @@ EXPORT_SYMBOL(mca_set_adapter_procfn); EXPORT_SYMBOL(mca_isenabled); EXPORT_SYMBOL(mca_isadapter); +EXPORT_SYMBOL(mca_mark_as_used); +EXPORT_SYMBOL(mca_mark_as_unused); +EXPORT_SYMBOL(mca_find_unused_adapter); #endif #ifdef CONFIG_VT diff -u --recursive --new-file v2.1.128/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v2.1.128/linux/arch/i386/kernel/time.c Thu Nov 12 16:21:18 1998 +++ linux/arch/i386/kernel/time.c Sun Nov 15 11:14:36 1998 @@ -526,9 +526,9 @@ /* Now let's take care of CTC channel 2 */ "movb $0xb0, %%al\n\t" /* binary, mode 0, LSB/MSB, ch 2*/ "outb %%al, $0x43\n\t" /* Write to CTC command port */ - "movb $0x0c, %%al\n\t" + "movl %1, %%eax\n\t" "outb %%al, $0x42\n\t" /* LSB of count */ - "movb $0xe9, %%al\n\t" + "shrl $8, %%eax\n\t" "outb %%al, $0x42\n\t" /* MSB of count */ /* Read the TSC; counting has just started */ @@ -562,12 +562,12 @@ * do a real 64-by-64 divide before that time's up. */ "movl %%eax, %%ecx\n\t" "xorl %%eax, %%eax\n\t" - "movl %1, %%edx\n\t" + "movl %2, %%edx\n\t" "divl %%ecx\n\t" /* eax= 2^32 / (1 * TSC counts per microsecond) */ /* Return eax for the use of fast_gettimeoffset */ "movl %%eax, %0\n\t" : "=r" (retval) - : "r" (5 * 1000020/HZ) + : "r" (5 * LATCH), "r" (5 * 1000020/HZ) : /* we clobber: */ "ax", "bx", "cx", "dx", "cc", "memory"); return retval; } diff -u --recursive --new-file v2.1.128/linux/arch/ppc/Makefile linux/arch/ppc/Makefile --- v2.1.128/linux/arch/ppc/Makefile Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/Makefile Sun Nov 15 10:51:41 1998 @@ -16,6 +16,8 @@ ifeq ($(shell uname -m),ppc) CHECKS = checks +else +CROSS_COMPILE = ppc-linux-elf- endif ASFLAGS = diff -u --recursive --new-file v2.1.128/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c --- v2.1.128/linux/arch/ppc/amiga/amiints.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/amiga/amiints.c Sun Nov 15 10:51:41 1998 @@ -108,6 +108,11 @@ custom.intreq = 0x7fff; #ifdef CONFIG_APUS + /* Clear any inter-CPU interupt requests. Circumvents bug in + Blizzard IPL emulation HW (or so it appears). */ + APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); + + /* Init IPL emulation. */ APUS_WRITE(APUS_REG_INT, REGINT_INTMASTER | REGINT_ENABLEIPL); APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK); @@ -304,12 +309,14 @@ } if (irq >= IRQ_AMIGA_CIAB) { + cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB))); cia_able_irq(&ciab_base, CIA_ICR_SETCLR | (1 << (irq - IRQ_AMIGA_CIAB))); return; } if (irq >= IRQ_AMIGA_CIAA) { + cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA))); cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | (1 << (irq - IRQ_AMIGA_CIAA))); return; diff -u --recursive --new-file v2.1.128/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c --- v2.1.128/linux/arch/ppc/amiga/config.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/amiga/config.c Sun Nov 15 10:51:41 1998 @@ -434,10 +434,6 @@ */ if (AMIGAHW_PRESENT(MAGIC_REKICK)) *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; - -#ifdef CONFIG_ZORRO - zorro_init(); -#endif } static unsigned short jiffy_ticks; @@ -739,33 +735,32 @@ savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM); savekmsg->magic1 = SAVEKMSG_MAGIC1; savekmsg->magic2 = SAVEKMSG_MAGIC2; - savekmsg->magicptr = VTOP(savekmsg); + savekmsg->magicptr = virt_to_phys(savekmsg); savekmsg->size = 0; } static void amiga_serial_putc(char c) { - custom.serdat = (unsigned char)c | 0x100; - -#ifdef CONFIG_APUS - /* I'm sure this should not be necessary since the address is - marked non-cachable and coherent. Still, without it the - serial output is not usable. -jskov */ - eieio (); -#endif - - while (!(custom.serdatr & 0x2000)) - ; + custom.serdat = (unsigned char)c | 0x100; + iobarrier (); + while (!(custom.serdatr & 0x2000)) + ; } void amiga_serial_console_write(struct console *co, const char *s, unsigned int count) { - while (count--) { - if (*s == '\n') - amiga_serial_putc('\r'); - amiga_serial_putc(*s++); - } +#if 0 /* def CONFIG_KGDB */ + /* FIXME:APUS GDB doesn't seem to like O-packages before it is + properly connected with the target. */ + __gdb_output_string (s, count); +#else + while (count--) { + if (*s == '\n') + amiga_serial_putc('\r'); + amiga_serial_putc(*s++); + } +#endif } #ifdef CONFIG_SERIAL_CONSOLE diff -u --recursive --new-file v2.1.128/linux/arch/ppc/amiga/time.c linux/arch/ppc/amiga/time.c --- v2.1.128/linux/arch/ppc/amiga/time.c Thu Aug 6 14:06:29 1998 +++ linux/arch/ppc/amiga/time.c Sun Nov 15 10:51:41 1998 @@ -1,3 +1,4 @@ +#include /* CONFIG_HEARTBEAT */ #include #include #include @@ -68,3 +69,24 @@ } +void apus_heartbeat (void) +{ +#ifdef CONFIG_HEARTBEAT + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<= 47) && (bus_speed < 53)) { + bus_speed = 50; + freq = 12500000; + } else if ((bus_speed >= 57) && (bus_speed < 63)) { + bus_speed = 60; + freq = 15000000; + } else if ((bus_speed >= 63) && (bus_speed < 69)) { + bus_speed = 66; + freq = 16500000; + } else { + printk ("APUS: Unable to determine bus speed (%d). " + "Defaulting to 50MHz", bus_speed); + bus_speed = 50; + freq = 12500000; + } + + /* Ease diagnostics... */ { - int speed; - switch (freq) - { - case 0: - freq = 15000000; - speed = 60; - break; - - case 1: - freq = 16500000; - speed =66; - break; - } - - /* Use status of left mouse button to select - RAM speed. */ - if (!(ciaa.pra & 0x40)) - { - APUS_WRITE (APUS_REG_WAITSTATE, - REGWAITSTATE_SETRESET - |REGWAITSTATE_PPCR - |REGWAITSTATE_PPCW); - printk (" [RAM R/W waitstate removed. " - "(expecting 60ns RAM).] "); + extern int __map_without_bats; + + printk ("APUS: BATs=%d, BUS=%dMHz, RAM=%dns\n", + (__map_without_bats) ? 0 : 1, + bus_speed, + (__60nsram) ? 60 : 70); + + /* print a bit more if asked politely... */ + if (!(ciaa.pra & 0x40)){ + extern unsigned int bat_addrs[4][3]; + int b; + for (b = 0; b < 4; ++b) { + printk ("APUS: BAT%d ", b); + printk ("%08x-%08x -> %08x\n", + bat_addrs[b][0], + bat_addrs[b][1], + bat_addrs[b][2]); + } } - - printk ("PowerUp Bus Speed: %dMHz\n", speed); } freq *= 60; /* try to make freq/1e6 an integer */ diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.1.128/linux/arch/ppc/kernel/chrp_setup.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/chrp_setup.c Sun Nov 15 10:51:43 1998 @@ -39,6 +39,7 @@ #include #include #include +#include extern void hydra_init(void); extern void w83c553f_init(void); @@ -191,7 +192,15 @@ aux_device_present = 0xaa; - ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ +#ifdef CONFIG_BLK_DEV_INITRD + /* this is fine for chrp */ + initrd_below_start_ok = 1; + + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ printk("Boot arguments: %s\n", cmd_line); @@ -205,7 +214,6 @@ /* PCI bridge config space access area - * appears to be not in devtree on longtrail. */ ioremap(GG2_PCI_CONFIG_BASE, 0x80000); - /* * Temporary fixes for PCI devices. * -- Geert @@ -217,10 +225,13 @@ * Fix the Super I/O configuration */ sio_init(); - #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + /* my starmax 6000 needs this but the longtrail shouldn't do it -- Cort */ + if ( !strncmp("MOT", get_property(find_path_device("/"), + "model", NULL),3) ) + *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c --- v2.1.128/linux/arch/ppc/kernel/feature.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/feature.c Sun Nov 15 10:51:43 1998 @@ -0,0 +1,249 @@ +/* + * arch/ppc/kernel/feature.c + * + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * 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 + +#define MAX_FEATURE_REGS 2 +#undef DEBUG_FEATURE + +static u32 feature_bits_pbook[] = { + 0, /* FEATURE_null */ + OH_SCC_RESET, /* FEATURE_Serial_reset */ + OH_SCC_ENABLE, /* FEATURE_Serial_enable */ + OH_SCCA_IO, /* FEATURE_Serial_IO_A */ + OH_SCCB_IO, /* FEATURE_Serial_IO_B */ + OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */ + OH_MESH_ENABLE, /* FEATURE_MESH_enable */ + OH_IDE_ENABLE, /* FEATURE_IDE_enable */ + OH_VIA_ENABLE, /* FEATURE_VIA_enable */ + OH_IDECD_POWER, /* FEATURE_CD_power */ + OH_BAY_RESET, /* FEATURE_Mediabay_reset */ + OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */ + OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */ + OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */ + OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ + 0, /* FEATURE_BMac_reset */ + 0, /* FEATURE_BMac_IO_enable */ + 0, /* FEATURE_Modem_PowerOn -> guess...*/ + 0 /* FEATURE_Modem_Reset -> guess...*/ +}; + +/* assume these are the same as the ohare until proven otherwise */ +static u32 feature_bits_heathrow[] = { + 0, /* FEATURE_null */ + OH_SCC_RESET, /* FEATURE_Serial_reset */ + OH_SCC_ENABLE, /* FEATURE_Serial_enable */ + OH_SCCA_IO, /* FEATURE_Serial_IO_A */ + OH_SCCB_IO, /* FEATURE_Serial_IO_B */ + OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */ + OH_MESH_ENABLE, /* FEATURE_MESH_enable */ + OH_IDE_ENABLE, /* FEATURE_IDE_enable */ + OH_VIA_ENABLE, /* FEATURE_VIA_enable */ + OH_IDECD_POWER, /* FEATURE_CD_power */ + OH_BAY_RESET, /* FEATURE_Mediabay_reset */ + OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */ + OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */ + OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */ + OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ + 0x80000000, /* FEATURE_BMac_reset */ + 0x60000000, /* FEATURE_BMac_IO_enable */ + 0x02000000, /* FEATURE_Modem_PowerOn -> guess...*/ + 0x07000000 /* FEATURE_Modem_Reset -> guess...*/ +}; + +/* definition of a feature controller object */ +struct feature_controller +{ + u32* bits; + volatile u32* reg; + struct device_node* device; +}; + +/* static functions */ +static void +feature_add_controller(struct device_node *controller_device, u32* bits); + +static int +feature_lookup_controller(struct device_node *device); + +/* static varialbles */ +static struct feature_controller controllers[MAX_FEATURE_REGS]; +static int controller_count = 0; + + +void +feature_init(void) +{ + struct device_node *np; + + np = find_devices("mac-io"); + while (np != NULL) + { + feature_add_controller(np, feature_bits_heathrow); + np = np->next; + } + if (controller_count == 0) + { + np = find_devices("ohare"); + if (np) + { + if (find_devices("via-pmu") != NULL) + feature_add_controller(np, feature_bits_pbook); + else + /* else not sure; maybe this is a Starmax? */ + feature_add_controller(np, NULL); + } + } + + if (controller_count) + printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); +} + +static void +feature_add_controller(struct device_node *controller_device, u32* bits) +{ + struct feature_controller* controller; + + if (controller_count >= MAX_FEATURE_REGS) + { + printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n", + controller_device->full_name, MAX_FEATURE_REGS); + return; + } + controller = &controllers[controller_count]; + + controller->bits = bits; + controller->device = controller_device; + if (controller_device->n_addrs == 0) { + printk(KERN_ERR "No addresses for %s\n", + controller_device->full_name); + return; + } + + controller->reg = (volatile u32 *)ioremap( + controller_device->addrs[0].address + OHARE_FEATURE_REG, 4); + + if (bits == NULL) { + printk(KERN_INFO "Twiddling the magic ohare bits\n"); + out_le32(controller->reg, STARMAX_FEATURES); + return; + } + + controller_count++; +} + +static int +feature_lookup_controller(struct device_node *device) +{ + int i; + + if (device == NULL) + return -EINVAL; + + while(device) + { + for (i=0; iparent; + } + +#ifdef DEBUG_FEATURE + printk("feature: <%s> not found on any controller\n", + device->name); +#endif + + return -ENODEV; +} + +int +feature_set(struct device_node* device, enum system_feature f) +{ + int controller; + unsigned long flags; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + +#ifdef DEBUG_FEATURE + printk("feature: <%s> setting feature %d in controller @0x%x\n", + device->name, (int)f, (unsigned int)controllers[controller].reg); +#endif + + save_flags(flags); + cli(); + st_le32( controllers[controller].reg, + ld_le32(controllers[controller].reg) | + controllers[controller].bits[f]); + restore_flags(flags); + udelay(10); + + return 0; +} + +int +feature_clear(struct device_node* device, enum system_feature f) +{ + int controller; + unsigned long flags; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + +#ifdef DEBUG_FEATURE + printk("feature: <%s> clearing feature %d in controller @0x%x\n", + device->name, (int)f, (unsigned int)controllers[controller].reg); +#endif + + save_flags(flags); + cli(); + st_le32( controllers[controller].reg, + ld_le32(controllers[controller].reg) & + ~(controllers[controller].bits[f])); + restore_flags(flags); + udelay(10); + + return 0; +} + +int +feature_test(struct device_node* device, enum system_feature f) +{ + int controller; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + + return (ld_le32(controllers[controller].reg) & + controllers[controller].bits[f]) != 0; +} + diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.1.128/linux/arch/ppc/kernel/head.S Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/head.S Sun Nov 15 10:51:43 1998 @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.107 1998/09/25 19:48:52 paulus Exp $ + * $Id: head.S,v 1.111 1998/11/10 01:10:32 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -210,7 +210,8 @@ mr r27,r7 #ifndef CONFIG_8xx bl prom_init - + .globl __secondary_start +__secondary_start: /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely @@ -1395,15 +1396,13 @@ next_slot: .long 0 -/* - * FPU stuff for the 6xx/7xx follows - * -- Cort - */ load_up_fpu: /* * Disable FP for the task which had the FPU previously, * and save its floating-point registers in its thread_struct. * Enables the FPU for use in the kernel on return. + * On SMP we know the fpu is free, since we give it up every + * switch. -- Cort */ #ifndef CONFIG_APUS lis r6,-KERNELBASE@h @@ -1411,28 +1410,23 @@ lis r6,CYBERBASEp@h lwz r6,0(r6) #endif + addis r3,r6,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) mfmsr r5 ori r5,r5,MSR_FP SYNC mtmsr r5 /* enable use of fpu now */ -#ifndef __SMP__ - SYNC - cmpi 0,r4,0 - beq 1f -#else /* * All the saving of last_task_used_math is handled * by a switch_to() call to smp_giveup_fpu() in SMP so * last_task_used_math is not used. - * - * We should never be here on SMP anyway, since the fpu should - * always be on. * -- Cort */ - b 1f -#endif +#ifndef __SMP__ + SYNC + cmpi 0,r4,0 + beq 1f add r4,r4,r6 addi r4,r4,TSS /* want TSS of last_task_used_math */ SAVE_32FPRS(0, r4) @@ -1444,19 +1438,17 @@ li r20,MSR_FP|MSR_FE0|MSR_FE1 andc r4,r4,r20 /* disable FP for previous task */ stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) - +#endif /* __SMP__ */ 1: ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 /* enable use of FP after return */ mfspr r5,SPRG3 /* current task's TSS (phys) */ lfd fr0,TSS_FPSCR-4(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) -/* - * on SMP we don't really use last_task_used_math but set it - * here anyway to avoid the ifdef's -- Cort - */ subi r4,r5,TSS sub r4,r4,r6 +#ifndef __SMP__ stw r4,last_task_used_math@l(r3) +#endif /* __SMP__ */ /* restore registers and return */ lwz r3,_CCR(r21) lwz r4,_LINK(r21) @@ -1516,8 +1508,10 @@ cmpi 0,r4,0 beqlr- /* if no previous owner, done */ addi r4,r4,TSS /* want TSS of last_task_used_math */ +#ifndef __SMP__ li r5,0 stw r5,last_task_used_math@l(r3) +#endif /* __SMP__ */ SAVE_32FPRS(0, r4) mffs fr0 stfd fr0,TSS_FPSCR-4(r4) @@ -1628,14 +1622,27 @@ 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ 4: #endif /* CONFIG_8xx */ +#ifdef __SMP__ + /* if we're the second cpu stack and r2 are different + * and we want to not clear the bss -- Cort */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + lwz r5,0(r5) + cmpi 0,r5,0 + beq 99f + + /* get current */ + lis r2,current_set@h + ori r2,r2,current_set@l + addi r2,r2,4 + lwz r2,0(r2) + + b 10f +99: +#endif /* __SMP__ */ /* ptr to current */ lis r2,init_task_union@h ori r2,r2,init_task_union@l - /* stack */ - addi r1,r2,TASK_UNION_SIZE - li r0,0 - stwu r0,-STACK_FRAME_OVERHEAD(r1) - /* Clear out the BSS */ lis r11,_end@ha addi r11,r11,_end@l @@ -1651,6 +1658,15 @@ 3: stwu r0,4(r8) bdnz 3b 2: +#ifdef __SMP__ +10: +#endif /* __SMP__ */ + + /* stack */ + addi r1,r2,TASK_UNION_SIZE + li r0,0 + stwu r0,-STACK_FRAME_OVERHEAD(r1) + /* * Decide what sort of machine this is and initialize the MMU. */ @@ -1999,6 +2015,8 @@ beq+ 1f addi r3,r1,STACK_FRAME_OVERHEAD bl do_IRQ + .globl lost_irq_ret +lost_irq_ret: b 3b 1: lis r4,bh_mask@ha lwz r4,bh_mask@l(r4) @@ -2007,6 +2025,8 @@ and. r4,r4,r5 beq+ 2f bl do_bottom_half + .globl do_bottom_half_ret +do_bottom_half_ret: SYNC mtmsr r30 /* disable interrupts again */ SYNC @@ -2024,6 +2044,8 @@ li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD bl do_signal + .globl do_signal_ret +do_signal_ret: b 0b 8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ stw r4,TSS+KSP(r2) /* save kernel stack pointer */ diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.1.128/linux/arch/ppc/kernel/idle.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/idle.c Sun Nov 15 10:51:43 1998 @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.50 1998/08/18 16:19:25 cort Exp $ + * $Id: idle.c,v 1.56 1998/10/13 19:14:36 paulus Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -11,8 +11,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#define __KERNEL_SYSCALLS__ - #include #include #include @@ -32,9 +30,6 @@ #include #include #include -#ifdef CONFIG_PMAC -#include -#endif void zero_paged(void); void power_save(void); @@ -60,15 +55,7 @@ if ( !current->need_resched && zero_paged_on ) zero_paged(); if ( !current->need_resched && htab_reclaim_on ) htab_reclaim(); - - /* - * Only processor 1 may sleep now since processor 2 would - * never wake up. Need to add timer code for processor 2 - * then it can sleep. -- Cort - */ -#ifndef __SMP__ if ( !current->need_resched ) power_save(); -#endif /* __SMP__ */ run_task_queue(&tq_scheduler); schedule(); } @@ -93,14 +80,8 @@ */ asmlinkage int sys_idle(void) { - extern int media_bay_task(void *); if(current->pid != 0) return -EPERM; - -#ifdef CONFIG_PMAC - if (media_bay_present) - kernel_thread(media_bay_task, NULL, 0); -#endif idled(NULL); return 0; /* should never execute this but it makes gcc happy -- Cort */ diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.1.128/linux/arch/ppc/kernel/irq.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/irq.c Sun Nov 15 10:51:43 1998 @@ -9,7 +9,7 @@ * Adapted for Power Macintosh by Paul Mackerras * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). - * + * * This file contains the code used by various IRQ handling routines: * asking for different IRQ's should be done through these routines * instead of just grabbing them. Thus setups with different IRQ numbers @@ -63,8 +63,9 @@ extern void amiga_disable_irq(unsigned int irq); extern void amiga_enable_irq(unsigned int irq); static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } -static volatile unsigned char *gg2_int_ack_special; +static volatile unsigned char *chrp_int_ack_special; extern volatile unsigned long ipi_count; +static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base); #ifdef CONFIG_APUS /* Rename a few functions. Requires the CONFIG_APUS protection. */ @@ -88,6 +89,7 @@ #define VEC_SPUR (24) #undef SHOW_IRQ +#undef SHOW_GATWICK_IRQS #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) #define cached_21 (((char *)(cached_irq_mask))[3]) #define cached_A1 (((char *)(cached_irq_mask))[2]) @@ -96,6 +98,7 @@ unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; int max_irqs; +int max_real_irqs; static struct irqaction *irq_action[NR_IRQS]; static int spurious_interrupts = 0; static unsigned int cached_irq_mask[NR_MASK_WORDS]; @@ -111,11 +114,32 @@ }; /* XXX these addresses should be obtained from the device tree */ -volatile struct pmac_irq_hw *pmac_irq_hw[2] = { +volatile struct pmac_irq_hw *pmac_irq_hw[4] = { (struct pmac_irq_hw *) 0xf3000020, (struct pmac_irq_hw *) 0xf3000010, + (struct pmac_irq_hw *) 0xf4000020, + (struct pmac_irq_hw *) 0xf4000010, }; +/* This is the interrupt used on the main controller for the secondary + controller. Happens on PowerBooks G3 Series (a second mac-io) + -- BenH + */ +static int second_irq = -999; + +/* Returns the number of 0's to the left of the most significant 1 bit */ +static inline int cntlzw(int bits) +{ + int lz; + + asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits)); + return lz; +} + +static inline void sync(void) +{ + asm volatile ("sync"); +} /* nasty hack for shared irq's since we need to do kmalloc calls but * can't very very early in the boot when we need to do a request irq. @@ -173,12 +197,12 @@ /* spin_unlock(&irq_controller_lock);*/ } -void pmac_mask_and_ack_irq(int irq_nr) +void __pmac pmac_mask_and_ack_irq(int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; - if (irq_nr >= max_irqs) + if ((unsigned)irq_nr >= max_irqs) return; /*spin_lock(&irq_controller_lock);*/ @@ -188,13 +212,15 @@ out_le32(&pmac_irq_hw[i]->ack, bit); out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]); out_le32(&pmac_irq_hw[i]->ack, bit); + /* make sure ack gets to controller before we enable interrupts */ + sync(); /*spin_unlock(&irq_controller_lock);*/ /*if ( irq_controller_lock.lock ) panic("irq controller lock still held in mask and ack\n");*/ } -void chrp_mask_and_ack_irq(int irq_nr) +void __openfirmware chrp_mask_and_ack_irq(int irq_nr) { /* spinlocks are done by i8259_mask_and_ack() - Cort */ if (is_8259_irq(irq_nr)) @@ -211,12 +237,12 @@ } } -static void pmac_set_irq_mask(int irq_nr) +static void __pmac pmac_set_irq_mask(int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; - if (irq_nr >= max_irqs) + if ((unsigned)irq_nr >= max_irqs) return; /* enable unmasked interrupts */ @@ -251,19 +277,20 @@ i8259_set_irq_mask(irq_nr); } -static void pmac_mask_irq(unsigned int irq_nr) +static void __pmac pmac_mask_irq(unsigned int irq_nr) { clear_bit(irq_nr, cached_irq_mask); pmac_set_irq_mask(irq_nr); + sync(); } -static void pmac_unmask_irq(unsigned int irq_nr) +static void __pmac pmac_unmask_irq(unsigned int irq_nr) { set_bit(irq_nr, cached_irq_mask); pmac_set_irq_mask(irq_nr); } -static void chrp_mask_irq(unsigned int irq_nr) +static void __openfirmware chrp_mask_irq(unsigned int irq_nr) { if (is_8259_irq(irq_nr)) i8259_mask_irq(irq_nr); @@ -271,7 +298,7 @@ openpic_disable_irq(irq_to_openpic(irq_nr)); } -static void chrp_unmask_irq(unsigned int irq_nr) +static void __openfirmware chrp_unmask_irq(unsigned int irq_nr) { if (is_8259_irq(irq_nr)) i8259_unmask_irq(irq_nr); @@ -325,7 +352,7 @@ for (i = 0 ; i < NR_IRQS ; i++) { action = irq_action[i]; - if (!action || !action->handler) + if ((!action || !action->handler) && (i != second_irq)) continue; len += sprintf(buf+len, "%3d: ", i); #ifdef __SMP__ @@ -341,7 +368,10 @@ len += sprintf(buf+len, " 82c59 "); break; case _MACH_Pmac: - len += sprintf(buf+len, " PMAC-PIC "); + if (i < 64) + len += sprintf(buf+len, " PMAC-PIC "); + else + len += sprintf(buf+len, " GATWICK "); break; case _MACH_chrp: if ( is_8259_irq(i) ) @@ -354,23 +384,26 @@ break; } - len += sprintf(buf+len, " %s",action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s", action->name); - } - len += sprintf(buf+len, "\n"); + if (i != second_irq) { + len += sprintf(buf+len, " %s",action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ", %s", action->name); + } + len += sprintf(buf+len, "\n"); + } else + len += sprintf(buf+len, " Gatwick secondary IRQ controller\n"); } #ifdef __SMP__ /* should this be per processor send/receive? */ - len += sprintf(buf+len, "IPI: %10lu\n", ipi_count); + len += sprintf(buf+len, "IPI: %10lu", ipi_count); for ( i = 0 ; i <= smp_num_cpus-1; i++ ) len += sprintf(buf+len," "); - len += sprintf(buf+len, " interprocessor messages received\n"); + len += sprintf(buf+len, " interprocessor messages received\n"); #endif len += sprintf(buf+len, "BAD: %10u",spurious_interrupts); for ( i = 0 ; i <= smp_num_cpus-1; i++ ) len += sprintf(buf+len," "); - len += sprintf(buf+len, " spurious or short\n"); + len += sprintf(buf+len, " spurious or short\n"); return len; } @@ -604,7 +637,6 @@ #endif /* __SMP__ */ - asmlinkage void do_IRQ(struct pt_regs *regs) { int irq; @@ -627,9 +659,6 @@ if (!atomic_read(&n_lost_interrupts)) { extern void smp_message_recv(void); - goto out; - - ipi_count++; smp_message_recv(); goto out; } @@ -642,20 +671,48 @@ switch ( _machine ) { case _MACH_Pmac: - for (irq = max_irqs - 1; irq > 0; irq -= 32) { - int i = irq >> 5, lz; + for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { + int i = irq >> 5; bits = ld_le32(&pmac_irq_hw[i]->flag) | lost_interrupts[i]; if (bits == 0) continue; - /* lz = number of 0 bits to left of most sig. 1 */ - asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits)); - irq -= lz; + irq -= cntlzw(bits); break; } + + /* Here, we handle interrupts coming from Gatwick, + * normal interrupt code will take care of acking and + * masking the irq on Gatwick itself but we ack&mask + * the Gatwick main interrupt on Heathrow now. It's + * unmasked later, after interrupt handling. -- BenH + */ + if (irq == second_irq) { + mask_and_ack_irq(second_irq); + for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) { + int i = irq >> 5; + bits = ld_le32(&pmac_irq_hw[i]->flag) + | lost_interrupts[i]; + if (bits == 0) + continue; + irq -= cntlzw(bits); + break; + } + /* If not found, on exit, irq is 63 (128-1-32-32). + * We set it to -1 and revalidate second controller + */ + if (irq < max_real_irqs) { + irq = -1; + unmask_irq(second_irq); + } +#ifdef SHOW_GATWICK_IRQS + printk("Gatwick irq %d (i:%d, bits:0x%08lx\n", irq, i, bits); +#endif + } + break; case _MACH_chrp: - irq = openpic_irq(0); + irq = openpic_irq(0); if (irq == IRQ_8259_CASCADE) { /* @@ -663,7 +720,7 @@ * * This should go in the above mask/ack code soon. -- Cort */ - irq = *gg2_int_ack_special; + irq = *chrp_int_ack_special; /* * Acknowledge as soon as possible to allow i8259 * interrupt nesting @@ -740,11 +797,13 @@ } #endif } - + if (irq < 0) { - printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n", regs->nip); + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + spurious_interrupts++; goto out; - } + } #else /* CONFIG_8xx */ /* For MPC8xx, read the SIVEC register and shift the bits down @@ -753,9 +812,7 @@ bits = ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sivec; irq = bits >> 26; #endif /* CONFIG_8xx */ - mask_and_ack_irq(irq); - status = 0; action = irq_action[irq]; kstat.irqs[cpu][irq]++; @@ -765,14 +822,10 @@ do { status |= action->flags; action->handler(irq, action->dev_id, regs); - /*if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq);*/ action = action->next; } while ( action ); __cli(); - /* spin_lock(&irq_controller_lock);*/ unmask_irq(irq); - /* spin_unlock(&irq_controller_lock);*/ } else { #ifndef CONFIG_8xx if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */ @@ -781,8 +834,13 @@ disable_irq( irq ); } + /* This was a gatwick sub-interrupt, we re-enable them on Heathrow + now */ + if (_machine == _MACH_Pmac && irq >= max_real_irqs) + unmask_irq(second_irq); + /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */ -#ifndef CONFIG_8xx +#ifndef CONFIG_8xx if ( is_prep && (irq > 7) ) goto retry_cascade; /* do_bottom_half is called if necessary from int_return in head.S */ @@ -808,12 +866,16 @@ #ifdef SHOW_IRQ printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n", - irq,handler,devname,dev_id); + irq,(int)handler,devname,(int)dev_id); #endif /* SHOW_IRQ */ if (irq >= NR_IRQS) return -EINVAL; + /* Cannot allocate second controller IRQ */ + if (irq == second_irq) + return -EBUSY; + if (!handler) { /* Free */ @@ -838,7 +900,7 @@ cli(); action->handler = handler; - action->flags = irqflags; + action->flags = irqflags; action->mask = 0; action->name = devname; action->dev_id = dev_id; @@ -909,6 +971,9 @@ { extern void xmon_irq(int, void *, struct pt_regs *); int i; + struct device_node *irqctrler; + unsigned long addr; + struct device_node *np; #ifndef CONFIG_8xx switch (_machine) @@ -918,12 +983,59 @@ mask_irq = pmac_mask_irq; unmask_irq = pmac_unmask_irq; - /* G3 powermacs have 64 interrupts, others have 32 */ - max_irqs = (find_devices("mac-io") ? 64 : 32); - printk("System has %d possible interrupts\n", max_irqs); + /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, + others have 32 */ + max_irqs = max_real_irqs = 32; + irqctrler = find_devices("mac-io"); + if (irqctrler) + { + max_real_irqs = 64; + if (irqctrler->next) + max_irqs = 128; + else + max_irqs = 64; + } + + /* get addresses of first controller */ + if (irqctrler) { + if (irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 0; i < 2; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (2 - i) * 0x10); + } + + /* get addresses of second controller */ + irqctrler = (irqctrler->next) ? irqctrler->next : NULL; + if (irqctrler && irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 2; i < 4; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (4 - i) * 0x10); + } + } + /* disable all interrupts in all controllers */ for (i = 0; i * 32 < max_irqs; ++i) out_le32(&pmac_irq_hw[i]->enable, 0); + + + /* get interrupt line of secondary interrupt controller */ + if (irqctrler) { + second_irq = irqctrler->intrs[0].line; + printk(KERN_INFO "irq: secondary controller on irq %d\n", + (int)second_irq); + if (device_is_compatible(irqctrler, "gatwick")) + pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); + enable_irq(second_irq); + } + printk("System has %d possible interrupts\n", max_irqs); + if (max_irqs != max_real_irqs) + printk(KERN_DEBUG "%d interrupts on main controller\n", + max_real_irqs); + #ifdef CONFIG_XMON request_irq(20, xmon_irq, 0, "NMI", 0); #endif /* CONFIG_XMON */ @@ -932,8 +1044,15 @@ mask_and_ack_irq = chrp_mask_and_ack_irq; mask_irq = chrp_mask_irq; unmask_irq = chrp_unmask_irq; - gg2_int_ack_special = (volatile unsigned char *) - ioremap(GG2_INT_ACK_SPECIAL, 1); + + if ( !(np = find_devices("pci") ) ) + printk("Cannot find pci to get ack address\n"); + else + { + chrp_int_ack_special = (volatile unsigned char *) + (*(unsigned long *)get_property(np, + "8259-interrupt-acknowledge", NULL)); + } openpic_init(1); i8259_init(); cached_irq_mask[0] = cached_irq_mask[1] = ~0UL; @@ -993,3 +1112,61 @@ } #endif /* CONFIG_8xx */ } + +/* This routine will fix some missing interrupt values in the device tree + * on the gatwick mac-io controller used by some PowerBooks + */ +__pmac +static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) +{ + struct device_node *node; + static struct interrupt_info int_pool[4]; + + memset(int_pool, 0, sizeof(int_pool)); + node = gw->child; + while(node) + { + /* Fix SCC */ + if (strcasecmp(node->name, "escc") == 0) + if (node->child && node->child->n_intrs == 0) + { + node->child->n_intrs = 1; + node->child->intrs = &int_pool[0]; + int_pool[0].line = 15+irq_base; + printk(KERN_INFO "irq: fixed SCC on second controller (%d)\n", + int_pool[0].line); + } + /* Fix media-bay & left SWIM */ + if (strcasecmp(node->name, "media-bay") == 0) + { + struct device_node* ya_node; + + if (node->n_intrs == 0) + { + node->n_intrs = 1; + node->intrs = &int_pool[1]; + int_pool[1].line = 29+irq_base; + printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", + int_pool[1].line); + } + ya_node = node->child; + while(ya_node) + { + if ((strcasecmp(ya_node->name, "floppy") == 0) && + ya_node->n_intrs == 0) + { + ya_node->n_intrs = 2; + ya_node->intrs = &int_pool[2]; + int_pool[2].line = 19+irq_base; + int_pool[3].line = 1+irq_base; + printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", + int_pool[2].line, int_pool[3].line); + } + ya_node = ya_node->sibling; + } + } + node = node->sibling; + } + +} + diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.1.128/linux/arch/ppc/kernel/misc.S Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/misc.S Sun Nov 15 10:51:43 1998 @@ -363,9 +363,25 @@ mfspr r3,THRM1 blr +_GLOBAL(_get_THRM2) + mfspr r3,THRM2 + blr + +_GLOBAL(_get_THRM3) + mfspr r3,THRM3 + blr + _GLOBAL(_set_THRM1) mtspr THRM1,r3 blr + +_GLOBAL(_set_THRM2) + mtspr THRM2,r3 + blr + +_GLOBAL(_set_THRM3) + mtspr THRM3,r3 + blr _GLOBAL(_get_L2CR) mfspr r3,L2CR @@ -453,7 +469,6 @@ #define __NR__exit __NR_exit SYSCALL(idle) -SYSCALL(setup) SYSCALL(sync) SYSCALL(setsid) SYSCALL(write) @@ -490,12 +505,12 @@ .long sys_mknod .long sys_chmod /* 15 */ .long sys_lchown - .long sys_ni_syscall + .long sys_ni_syscall /* old break syscall holder */ .long sys_stat .long sys_lseek .long sys_getpid /* 20 */ .long sys_mount - .long sys_umount + .long sys_oldumount .long sys_setuid .long sys_getuid .long sys_stime /* 25 */ @@ -504,11 +519,11 @@ .long sys_fstat .long sys_pause .long sys_utime /* 30 */ - .long /*sys_stty*/ sys_ni_syscall - .long /*sys_gtty*/ sys_ni_syscall + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ .long sys_access .long sys_nice - .long /*sys_ftime*/ sys_ni_syscall /* 35 */ + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ .long sys_sync .long sys_kill .long sys_rename @@ -517,7 +532,7 @@ .long sys_dup .long sys_pipe .long sys_times - .long /*sys_prof*/ sys_ni_syscall + .long sys_ni_syscall /* old prof syscall holder */ .long sys_brk /* 45 */ .long sys_setgid .long sys_getgid @@ -525,13 +540,13 @@ .long sys_geteuid .long sys_getegid /* 50 */ .long sys_acct - .long /*sys_phys*/ sys_ni_syscall - .long /*sys_lock*/ sys_ni_syscall + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ .long sys_ioctl .long sys_fcntl /* 55 */ - .long /*sys_mpx*/ sys_ni_syscall + .long sys_ni_syscall /* old mpx syscall holder */ .long sys_setpgid - .long /*sys_ulimit*/ sys_ni_syscall + .long sys_ni_syscall /* old ulimit syscall holder */ .long sys_olduname .long sys_umask /* 60 */ .long sys_chroot @@ -562,7 +577,7 @@ .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir /* was sys_readdir */ + .long old_readdir .long sys_mmap /* 90 */ .long sys_munmap .long sys_truncate @@ -571,7 +586,7 @@ .long sys_fchown /* 95 */ .long sys_getpriority .long sys_setpriority - .long /*sys_profil*/ sys_ni_syscall + .long sys_ni_syscall /* old profil syscall holder */ .long sys_statfs .long sys_fstatfs /* 100 */ .long sys_ioperm @@ -610,7 +625,7 @@ .long sys_bdflush .long sys_sysfs /* 135 */ .long sys_personality - .long 0 /* for afs_syscall */ + .long sys_ni_syscall /* for afs_syscall */ .long sys_setfsuid .long sys_setfsgid .long sys_llseek /* 140 */ @@ -638,28 +653,28 @@ .long sys_nanosleep .long sys_mremap .long sys_setresuid - .long sys_getresuid /* 165 */ + .long sys_getresuid /* 165 */ .long sys_query_module .long sys_poll .long sys_nfsservctl - .long sys_setresgid - .long sys_getresgid /* 170 */ + .long sys_setresgid + .long sys_getresgid /* 170 */ .long sys_prctl .long sys_rt_sigreturn .long sys_rt_sigaction .long sys_rt_sigprocmask - .long sys_rt_sigpending /* 175 */ + .long sys_rt_sigpending /* 175 */ .long sys_rt_sigtimedwait .long sys_rt_sigqueueinfo .long sys_rt_sigsuspend .long sys_pread - .long sys_pwrite /* 180 */ + .long sys_pwrite /* 180 */ .long sys_chown .long sys_getcwd .long sys_capget .long sys_capset - .long sys_sigaltstack /* 185 */ + .long sys_sigaltstack /* 185 */ .long sys_sendfile - .long sys_ni_syscall - .long sys_ni_syscall + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ .space (NR_syscalls-183)*4 diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.1.128/linux/arch/ppc/kernel/pci.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/pci.c Sun Nov 15 10:51:43 1998 @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.38 1998/08/31 06:28:02 cort Exp $ + * $Id: pci.c,v 1.39 1998/10/13 20:59:04 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -164,7 +164,7 @@ get_property(find_path_device("/"), "model", NULL),3) ) { isa_io_base = 0xfe000000; - set_config_access_method(raven); + set_config_access_method(grackle); } else { diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.1.128/linux/arch/ppc/kernel/pmac_pci.c Thu Aug 6 14:06:29 1998 +++ linux/arch/ppc/kernel/pmac_pci.c Sun Nov 15 10:51:43 1998 @@ -40,7 +40,6 @@ #define BANDIT_COHERENT 0x40 __pmac - void *pci_io_base(unsigned int bus) { struct bridge_data *bp; @@ -50,6 +49,7 @@ return bp->io_base; } +__pmac int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, unsigned char *devfn_ptr) { @@ -68,6 +68,7 @@ return 0; } +__pmac int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { @@ -90,6 +91,7 @@ return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { @@ -114,6 +116,7 @@ return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { @@ -138,6 +141,7 @@ return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { @@ -159,6 +163,7 @@ return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { @@ -182,6 +187,7 @@ return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { @@ -406,7 +412,7 @@ ioremap(0xfec00000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); - bp->io_base = (void *) ioremap(0xfe000000, 0x10000); + bp->io_base = (void *) ioremap(0xfe000000, 0x20000); } if (isa_io_base == 0) isa_io_base = (unsigned long) bp->io_base; diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.1.128/linux/arch/ppc/kernel/pmac_setup.c Fri Oct 23 22:01:20 1998 +++ linux/arch/ppc/kernel/pmac_setup.c Sun Nov 15 10:51:43 1998 @@ -49,9 +49,9 @@ #include #include #include -#include #include #include +#include #include "time.h" unsigned char drive_info; @@ -64,7 +64,6 @@ static void ohare_init(void); __pmac - int pmac_get_cpuinfo(char *buffer) { @@ -151,6 +150,7 @@ #define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), SD_MINOR_NUMBER(i)) #define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) +__init kdev_t sd_find_target(void *host, int tgt) { Scsi_Disk *dp; @@ -168,13 +168,13 @@ * Dummy mksound function that does nothing. * The real one is in the dmasound driver. */ +__pmac static void pmac_mksound(unsigned int hz, unsigned int ticks) { } static volatile u32 *sysctrl_regs; -static volatile u32 *feature_addr; __initfunc(void pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) @@ -206,10 +206,11 @@ and some registers used by smp boards */ sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); __ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY)); + ohare_init(); *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); - ohare_init(); + feature_init(); #ifdef CONFIG_KGDB zs_kgdb_hook(0); @@ -234,39 +235,19 @@ __initfunc(static void ohare_init(void)) { - struct device_node *np; - - np = find_devices("ohare"); - if (np == 0) - return; - if (np->next != 0) - printk(KERN_WARNING "only using the first ohare\n"); - if (np->n_addrs == 0) { - printk(KERN_ERR "No addresses for %s\n", np->full_name); - return; - } - feature_addr = (volatile u32 *) - ioremap(np->addrs[0].address + OHARE_FEATURE_REG, 4); - - if (find_devices("via-pmu") == 0) { - printk(KERN_INFO "Twiddling the magic ohare bits\n"); - out_le32(feature_addr, STARMAX_FEATURES); - } else { - out_le32(feature_addr, in_le32(feature_addr) | PBOOK_FEATURES); - printk(KERN_DEBUG "feature reg = %x\n", in_le32(feature_addr)); - } - /* * Turn on the L2 cache. * We assume that we have a PSX memory controller iff * we have an ohare I/O controller. */ - if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { - if (sysctrl_regs[4] & 0x10) - sysctrl_regs[4] |= 0x04000020; - else - sysctrl_regs[4] |= 0x04000000; - printk(KERN_INFO "Level 2 cache enabled\n"); + if (find_devices("ohare") != NULL) { + if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { + if (sysctrl_regs[4] & 0x10) + sysctrl_regs[4] |= 0x04000020; + else + sysctrl_regs[4] |= 0x04000000; + printk(KERN_INFO "Level 2 cache enabled\n"); + } } } @@ -277,8 +258,10 @@ int boot_part; kdev_t boot_dev; -__initfunc(void powermac_init(void)) +void __init powermac_init(void) { + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return; adb_init(); pmac_nvram_init(); if (_machine == _MACH_Pmac) { @@ -363,7 +346,9 @@ #endif } -__initfunc(void note_bootable_part(kdev_t dev, int part)) +/* can't be initfunc - can be called whenever a disk is first accessed */ +__pmac +void note_bootable_part(kdev_t dev, int part) { static int found_boot = 0; char *p; diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c --- v2.1.128/linux/arch/ppc/kernel/pmac_support.c Fri May 8 23:14:45 1998 +++ linux/arch/ppc/kernel/pmac_support.c Sun Nov 15 10:51:43 1998 @@ -25,8 +25,7 @@ #define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ -__pmac - +__init void pmac_nvram_init(void) { struct device_node *dp; diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.1.128/linux/arch/ppc/kernel/ppc_ksyms.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/ppc_ksyms.c Sun Nov 15 10:51:43 1998 @@ -24,6 +24,7 @@ #include #include #include +#include #define __KERNEL_SYSCALLS__ #include @@ -100,7 +101,6 @@ EXPORT_SYMBOL(strspn); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); -EXPORT_SYMBOL(strnicmp); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); @@ -159,6 +159,10 @@ EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); +#ifndef CONFIG_MACH_SPECIFIC +EXPORT_SYMBOL(_machine); +#endif + EXPORT_SYMBOL(adb_request); EXPORT_SYMBOL(adb_autopoll); EXPORT_SYMBOL(adb_register); @@ -174,10 +178,15 @@ EXPORT_SYMBOL(abort); EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); +EXPORT_SYMBOL(find_compatible_devices); EXPORT_SYMBOL(find_path_device); +EXPORT_SYMBOL(find_phandle); EXPORT_SYMBOL(get_property); EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); +EXPORT_SYMBOL(feature_set); +EXPORT_SYMBOL(feature_clear); +EXPORT_SYMBOL(feature_test); EXPORT_SYMBOL(note_scsi_host); EXPORT_SYMBOL(kd_mksound); #ifdef CONFIG_PMAC diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- v2.1.128/linux/arch/ppc/kernel/prep_pci.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/prep_pci.c Sun Nov 15 10:51:43 1998 @@ -1,5 +1,5 @@ /* - * $Id: prep_pci.c,v 1.22 1998/08/05 20:11:15 cort Exp $ + * $Id: prep_pci.c,v 1.23 1998/10/21 10:52:24 cort Exp $ * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -462,6 +462,11 @@ Motherboard_map = Utah_pci_IRQ_map; Motherboard_routes = Utah_pci_IRQ_routes; break; + case 0xE0: /* MTX -- close enough?? to Genesis, so reuse it */ + Motherboard_map_name = "Motorola MTX"; + Motherboard_map = Genesis_pci_IRQ_map; + Motherboard_routes = Genesis_pci_IRQ_routes; + break; case 0x40: /* PowerStack */ default: /* Can't hurt, can it? */ Motherboard_map_name = "Blackhawk (Powerstack)"; diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.1.128/linux/arch/ppc/kernel/prep_setup.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/prep_setup.c Sun Nov 15 10:51:44 1998 @@ -196,7 +196,7 @@ sprintf(cmd_line,"%s console=tty0 console=ttyS0,9600n8", cmd_line); printk("Boot arguments: %s\n", cmd_line); -#ifdef CONFIG_CS4232 +#ifdef CONFIG_SOUND_CS4232 /* * setup proper values for the cs4232 driver so we don't have * to recompile for the motorola or ibm workstations sound systems. @@ -233,8 +233,7 @@ } } } -#endif /* CONFIG_CS4232 */ - +#endif /* CONFIG_SOUND_CS4232 */ /*print_residual_device_info();*/ request_region(0x20,0x20,"pic1"); diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.1.128/linux/arch/ppc/kernel/process.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/process.c Sun Nov 15 10:51:44 1998 @@ -163,14 +163,19 @@ #endif #ifdef SHOW_TASK_SWITCHES - printk("%s/%d -> %s/%d NIP %08lx cpu %d sfr %d lock %x\n", + printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n", prev->comm,prev->pid, new->comm,new->pid,new->tss.regs->nip,new->processor, - new->tss.smp_fork_ret,scheduler_lock.lock); + scheduler_lock.lock,new->fs->root,prev->fs->root); #endif #ifdef __SMP__ /* avoid complexity of lazy save/restore of fpu - * by just saving it every time we switch out -- Cort + * by just saving it every time we switch out if + * this task used the fpu during the last quantum. + * + * If it tries to use the fpu again, it'll trap and + * reload its fp regs. + * -- Cort */ if ( prev->tss.regs->msr & MSR_FP ) smp_giveup_fpu(prev); @@ -383,6 +388,7 @@ { int res; + lock_kernel(); res = do_fork(SIGCHLD, regs->gpr[1], regs); /* only parent returns here */ @@ -404,18 +410,23 @@ { int error; char * filename; - lock_kernel(); filename = getname((char *) a0); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; +#ifdef __SMP__ + if ( regs->msr & MSR_FP ) + smp_giveup_fpu(current); +#else if ( last_task_used_math == current ) - last_task_used_math = NULL; + giveup_fpu(); +#endif error = do_execve(filename, (char **) a1, (char **) a2, regs); putname(filename); out: unlock_kernel(); + return error; } diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.1.128/linux/arch/ppc/kernel/prom.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/prom.c Sun Nov 15 10:51:44 1998 @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.39 1998/09/18 09:14:52 paulus Exp $ + * $Id: prom.c,v 1.46 1998/11/11 03:55:09 paulus Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,13 @@ unsigned size; }; +struct pci_intr_map { + struct pci_address addr; + unsigned dunno; + phandle int_ctrler; + unsigned intr; +}; + typedef unsigned long interpret_func(struct device_node *, unsigned long); static interpret_func interpret_pci_props; static interpret_func interpret_dbdma_props; @@ -90,6 +98,31 @@ static struct device_node *allnodes = 0; +static void clearscreen(void); + +#ifdef CONFIG_BOOTX_TEXT + +static void drawchar(char c); +static void drawstring(const char *c); +static void scrollscreen(void); + +static void draw_byte(unsigned char c, long locX, long locY); +static void draw_byte_32(unsigned char *bits, unsigned long *base); +static void draw_byte_16(unsigned char *bits, unsigned long *base); +static void draw_byte_8(unsigned char *bits, unsigned long *base); + +static long g_loc_X; +static long g_loc_Y; +static long g_max_loc_X; +static long g_max_loc_Y; + +#define cmapsz (16*256) + +static unsigned char vga_font[cmapsz]; + +#endif + + static void *call_prom(const char *service, int nargs, int nret, ...); static void prom_exit(void); static unsigned long copy_device_tree(unsigned long, unsigned long); @@ -100,6 +133,7 @@ static void relocate_nodes(void); static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); +static void *early_get_property(unsigned long, unsigned long, char *); extern void enter_rtas(void *); extern unsigned long reloc_offset(void); @@ -133,7 +167,7 @@ #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) -__openfirmware +__init static void prom_exit() { @@ -148,7 +182,7 @@ ; } -__openfirmware +__init void prom_enter(void) { @@ -161,7 +195,7 @@ RELOC(prom)(&args); } -__openfirmware +__init static void * call_prom(const char *service, int nargs, int nret, ...) { @@ -183,13 +217,23 @@ return prom_args.args[nargs]; } -__openfirmware +__init void prom_print(const char *msg) { const char *p, *q; unsigned long offset = reloc_offset(); + if (RELOC(prom_stdout) == 0) + { +#ifdef CONFIG_BOOTX_TEXT + if (RELOC(boot_infos) != 0) + drawstring(msg); +#endif + return; + } + + for (p = msg; *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n'; ++q) ; @@ -208,7 +252,7 @@ * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. */ -__openfirmware +__init void prom_init(int r3, int r4, prom_entry pp) { @@ -217,10 +261,6 @@ unsigned long offset = reloc_offset(); int l; char *p, *d; -#ifdef __SMP__ - if ( RELOC(first_cpu_booted) ) - return; -#endif /* __SMP__ */ /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) @@ -230,24 +270,45 @@ * set up some pointers and return. */ if (r3 == 0x426f6f58 && pp == NULL) { boot_infos_t *bi = (boot_infos_t *) r4; - unsigned int *screen; - int nw, ln; unsigned long space; + unsigned long ptr, x; + char *model; + + RELOC(boot_infos) = PTRUNRELOC(bi); - /* first clear the screen */ - for (ln = 0; ln < bi->dispDeviceRect[3]; ++ln) { - screen = (unsigned int *) (bi->dispDeviceBase - + ln * bi->dispDeviceRowBytes); - nw = bi->dispDeviceRect[2] * bi->dispDeviceDepth / 32; - for (; nw > 0; --nw) - *screen++ = 0; + clearscreen(); + +#ifdef CONFIG_BOOTX_TEXT + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y) = 0; + RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; + RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; + prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE " booting...\n")); +#endif + + /* + * XXX If this is an iMac, turn off the USB controller. + */ + model = (char *) early_get_property + (r4 + bi->deviceTreeOffset, 4, RELOC("model")); + if (model && strcmp(model, RELOC("iMac,1")) == 0) { + out_le32((unsigned *)0x80880008, 1); /* XXX */ } - RELOC(boot_infos) = PTRUNRELOC(bi); space = bi->deviceTreeOffset + bi->deviceTreeSize; if (bi->ramDisk) space = bi->ramDisk + bi->ramDiskSize; RELOC(klimit) = PTRUNRELOC((char *) bi + space); + + /* + * Touch each page to make sure the PTEs for them + * are in the hash table - the aim is to try to avoid + * getting DSI exceptions while copying the kernel image. + */ + for (ptr = (KERNELBASE + offset) & PAGE_MASK; + ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) + x = *(volatile unsigned long *)ptr; + return; } @@ -342,7 +403,7 @@ * So we check whether we will need to open the display, * and if so, open it now. */ -__openfirmware +__init static unsigned long check_display(unsigned long mem) { @@ -392,7 +453,7 @@ return ALIGN(mem); } -__openfirmware +__init static int prom_next_node(phandle *nodep) { @@ -415,7 +476,7 @@ /* * Make a copy of the device tree from the PROM. */ -__openfirmware +__init static unsigned long copy_device_tree(unsigned long mem_start, unsigned long mem_end) { @@ -436,7 +497,7 @@ return new_start; } -__openfirmware +__init static unsigned long inspect_node(phandle node, struct device_node *dad, unsigned long mem_start, unsigned long mem_end, @@ -521,7 +582,7 @@ * It traverses the device tree and fills in the name, type, * {n_}addrs and {n_}intrs fields of each node. */ -__openfirmware +__init void finish_device_tree(void) { @@ -535,7 +596,27 @@ klimit = (char *) mem; } -__openfirmware +/* + * early_get_property is used to access the device tree image prepared + * by BootX very early on, before the pointers in it have been relocated. + */ +__init void * +early_get_property(unsigned long base, unsigned long node, char *prop) +{ + struct device_node *np = (struct device_node *)(base + node); + struct property *pp; + + for (pp = np->properties; pp != 0; pp = pp->next) { + pp = (struct property *) (base + (unsigned long)pp); + if (strcmp((char *)((unsigned long)pp->name + base), + prop) == 0) { + return (void *)((unsigned long)pp->value + base); + } + } + return 0; +} + +__init static unsigned long finish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc) @@ -556,16 +637,17 @@ ifunc = NULL; else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) ifunc = interpret_pci_props; - else if (!strcmp(np->type, "dbdma") - || (ifunc == interpret_dbdma_props - && (!strcmp(np->type, "escc") - || !strcmp(np->type, "media-bay")))) + else if (!strcmp(np->type, "dbdma")) ifunc = interpret_dbdma_props; - else if (!strcmp(np->type, "mac-io")) + else if (!strcmp(np->type, "mac-io") + || ifunc == interpret_macio_props) ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; - else + else if (!((ifunc == interpret_dbdma_props + || ifunc == interpret_macio_props) + && (!strcmp(np->type, "escc") + || !strcmp(np->type, "media-bay")))) ifunc = NULL; /* if we were booted from BootX, convert the full name */ @@ -594,7 +676,7 @@ * are offsets from the start of the tree. * This procedure updates the pointers. */ -__openfirmware +__init static void relocate_nodes(void) { unsigned long base; @@ -620,13 +702,14 @@ } } -__openfirmware +__init static unsigned long interpret_pci_props(struct device_node *np, unsigned long mem_start) { struct address_range *adr; struct pci_reg_property *pci_addrs; - int i, l, *ip; + int i, l, *ip, ml; + struct pci_intr_map *imp; pci_addrs = (struct pci_reg_property *) get_property(np, "assigned-addresses", &l); @@ -645,6 +728,30 @@ mem_start += i * sizeof(struct address_range); } + /* + * If the pci host bridge has an interrupt-map property, + * look for our node in it. + */ + if (np->parent != 0 && pci_addrs != 0 + && (imp = (struct pci_intr_map *) + get_property(np->parent, "interrupt-map", &ml)) != 0 + && (ip = (int *) get_property(np, "interrupts", &l)) != 0) { + unsigned int busdevfn = pci_addrs[0].addr.a_hi & 0xffff00; + np->n_intrs = 0; + np->intrs = (struct interrupt_info *) mem_start; + for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) { + if (imp[i].addr.a_hi == busdevfn) { + np->intrs[np->n_intrs].line = imp[i].intr; + np->intrs[np->n_intrs].sense = 0; + ++np->n_intrs; + } + } + if (np->n_intrs == 0) + np->intrs = 0; + mem_start += np->n_intrs * sizeof(struct interrupt_info); + return mem_start; + } + ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); @@ -661,7 +768,7 @@ return mem_start; } -__openfirmware +__init static unsigned long interpret_dbdma_props(struct device_node *np, unsigned long mem_start) { @@ -710,7 +817,7 @@ return mem_start; } -__openfirmware +__init static unsigned long interpret_macio_props(struct device_node *np, unsigned long mem_start) { @@ -748,18 +855,28 @@ ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = l / (2 * sizeof(int)); - mem_start += np->n_intrs * sizeof(struct interrupt_info); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = openpic_to_irq(*ip++); - np->intrs[i].sense = *ip++; + if (_machine == _MACH_Pmac) { + /* for the iMac */ + np->n_intrs = l / sizeof(int); + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = *ip++; + np->intrs[i].sense = 0; + } + } else { + /* CHRP machines */ + np->n_intrs = l / (2 * sizeof(int)); + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = openpic_to_irq(*ip++); + np->intrs[i].sense = *ip++; + } } + mem_start += np->n_intrs * sizeof(struct interrupt_info); } return mem_start; } -__openfirmware +__init static unsigned long interpret_isa_props(struct device_node *np, unsigned long mem_start) { @@ -797,7 +914,7 @@ return mem_start; } -__openfirmware +__init static unsigned long interpret_root_props(struct device_node *np, unsigned long mem_start) { @@ -876,6 +993,30 @@ return head; } +/* Checks if the given "compat" string matches one of the strings in + * the device's "compatible" property + */ +__openfirmware +int +device_is_compatible(struct device_node *device, const char *compat) +{ + const char* cp; + int cplen, l; + + cp = (char *) get_property(device, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strcasecmp(cp, compat) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + /* * Construct and return a list of the device_nodes with a given type * and compatible property. @@ -885,15 +1026,13 @@ find_compatible_devices(const char *type, const char *compat) { struct device_node *head, **prevp, *np; - const char *cp; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { if (type != NULL && !(np->type != 0 && strcasecmp(np->type, type) == 0)) continue; - cp = (char *) get_property(np, "compatible", NULL); - if (cp != NULL && strcasecmp(cp, compat) == 0) { + if (device_is_compatible(np, compat)) { *prevp = np; prevp = &np->next; } @@ -951,6 +1090,7 @@ return 0; } +#if 0 __openfirmware void print_properties(struct device_node *np) @@ -1001,7 +1141,9 @@ } } } +#endif +/* this can be called after setup -- Cort */ __openfirmware int call_rtas(const char *service, int nargs, int nret, @@ -1038,7 +1180,7 @@ return u.words[nargs+3]; } -__openfirmware +__init void abort() { @@ -1048,3 +1190,563 @@ #endif prom_exit(); } + +#define CALC_BASE(y) (bi->dispDeviceBase + bi->dispDeviceRect[0] * \ + (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * (y)) + +__init +static void +clearscreen(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned long *base = (unsigned long *)CALC_BASE(0); + unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * + (bi->dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) + { + unsigned long *ptr = base; + for(j=width; j; --j) + *(ptr++) = 0; + base += (bi->dispDeviceRowBytes >> 2); + } +} + +#ifdef CONFIG_BOOTX_TEXT + +__init +static void +scrollscreen(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned long *src = (unsigned long *)CALC_BASE(16); + unsigned long *dst = (unsigned long *)CALC_BASE(0); + unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * + (bi->dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) + { + unsigned long *src_ptr = src; + unsigned long *dst_ptr = dst; + for(j=width; j; --j) + *(dst_ptr++) = *(src_ptr++); + src += (bi->dispDeviceRowBytes >> 2); + dst += (bi->dispDeviceRowBytes >> 2); + } + for (i=0; i<16; i++) + { + unsigned long *dst_ptr = dst; + for(j=width; j; --j) + *(dst_ptr++) = 0; + dst += (bi->dispDeviceRowBytes >> 2); + } +} + +__init +static void +drawchar(char c) +{ + unsigned long offset = reloc_offset(); + + switch(c) + { + case '\r': RELOC(g_loc_X) = 0; break; + case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break; + default: + draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); + if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) + { + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y)++; + } + } + while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) + { + scrollscreen(); + RELOC(g_loc_Y)--; + } +} + +__init +static void +drawstring(const char *c) +{ + while(*c) + drawchar(*(c++)); +} + +__init +static void +draw_byte(unsigned char c, long locX, long locY) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned char *base = bi->dispDeviceBase + + (bi->dispDeviceRowBytes * ((locY * 16) + bi->dispDeviceRect[1])) + + (bi->dispDeviceDepth >> 3) * ((locX * 8) + bi->dispDeviceRect[0]); + unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; + + switch(bi->dispDeviceDepth) + { + case 32: + draw_byte_32(font, (unsigned long *)base); + break; + case 16: + draw_byte_16(font, (unsigned long *)base); + break; + case 8: + draw_byte_8(font, (unsigned long *)base); + break; + default: + break; + } +} + +__init +static unsigned long expand_bits_8[16] = { + 0x00000000, + 0x000000ff, + 0x0000ff00, + 0x0000ffff, + 0x00ff0000, + 0x00ff00ff, + 0x00ffff00, + 0x00ffffff, + 0xff000000, + 0xff0000ff, + 0xff00ff00, + 0xff00ffff, + 0xffff0000, + 0xffff00ff, + 0xffffff00, + 0xffffffff +}; + +__init +static unsigned long expand_bits_16[4] = { + 0x00000000, + 0x0000ffff, + 0xffff0000, + 0xffffffff +}; + + +__init +static void +draw_byte_32(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0xFFFFFFFFUL; + int bg = 0x00000000UL; + + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (-(bits >> 7) & fg) ^ bg; + base[1] = (-((bits >> 6) & 1) & fg) ^ bg; + base[2] = (-((bits >> 5) & 1) & fg) ^ bg; + base[3] = (-((bits >> 4) & 1) & fg) ^ bg; + base[4] = (-((bits >> 3) & 1) & fg) ^ bg; + base[5] = (-((bits >> 2) & 1) & fg) ^ bg; + base[6] = (-((bits >> 1) & 1) & fg) ^ bg; + base[7] = (-(bits & 1) & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static void +draw_byte_16(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0xFFFFFFFFUL; + int bg = 0x00000000UL; + unsigned long *eb = RELOC(expand_bits_16); + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (eb[bits >> 6] & fg) ^ bg; + base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; + base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; + base[3] = (eb[bits & 3] & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static void +draw_byte_8(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0x0F0F0F0FUL; + int bg = 0x00000000UL; + unsigned long *eb = RELOC(expand_bits_8); + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (eb[bits >> 4] & fg) ^ bg; + base[1] = (eb[bits & 0xf] & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static unsigned char vga_font[cmapsz] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, +0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, +0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, +0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, +0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, +0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, +0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, +0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, +0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, +0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, +0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, +0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, +0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, +0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, +0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, +0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, +0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, +0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, +0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, +0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, +0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, +0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, +0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, +0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, +0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, +0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, +0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, +0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, +0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, +0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, +0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, +0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, +0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, +0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, +0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, +0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, +0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, +0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, +0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, +0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, +0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, +0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, +0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, +0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, +0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, +0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, +0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, +0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, +0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, +0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, +0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, +0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, +0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, +0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, +0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, +0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, +0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, +0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, +0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, +0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, +0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, +0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, +0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, +0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, +0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, +0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, +0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, +0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, +0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, +0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, +0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +}; + +#endif /* CONFIG_BOOTX_TEXT */ diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c --- v2.1.128/linux/arch/ppc/kernel/residual.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/residual.c Sun Nov 15 10:51:44 1998 @@ -1,5 +1,5 @@ /* - * $Id: residual.c,v 1.12 1998/08/27 23:15:56 paulus Exp $ + * $Id: residual.c,v 1.14 1998/10/11 17:38:10 cort Exp $ * * Code to deal with the PReP residual data. * @@ -49,7 +49,7 @@ #include -const char * PnP_BASE_TYPES[]= { +const char * PnP_BASE_TYPES[] __initdata = { "Reserved", "MassStorageDevice", "NetworkInterfaceController", @@ -65,7 +65,7 @@ /* Device Sub Type Codes */ -const unsigned char * PnP_SUB_TYPES[] = { +const unsigned char * PnP_SUB_TYPES[] __initdata = { "\001\000SCSIController", "\001\001IDEController", "\001\002FloppyController", @@ -122,7 +122,7 @@ /* Device Interface Type Codes */ -const unsigned char * PnP_INTERFACES[]= { +const unsigned char * PnP_INTERFACES[] __initdata = { "\000\000\000General", "\001\000\000GeneralSCSI", "\001\001\000GeneralIDE", @@ -240,7 +240,7 @@ NULL }; -static const unsigned char *PnP_SUB_TYPE_STR(unsigned char BaseType, +static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, unsigned char SubType) { const unsigned char ** s=PnP_SUB_TYPES; while (*s && !((*s)[0]==BaseType @@ -249,7 +249,7 @@ else return("Unknown !"); }; -static const unsigned char *PnP_INTERFACE_STR(unsigned char BaseType, +static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, unsigned char SubType, unsigned char Interface) { const unsigned char ** s=PnP_INTERFACES; @@ -260,7 +260,7 @@ else return NULL; }; -static void printsmallvendor(PnP_TAG_PACKET *pkt, int size) { +static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) { int i, c; char decomp[4]; #define p pkt->S14_Pack.S14_Data.S14_PPCPack @@ -285,7 +285,7 @@ #undef p } -static void printsmallpacket(PnP_TAG_PACKET * pkt, int size) { +static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) { static const unsigned char * intlevel[] = {"high", "low"}; static const unsigned char * intsense[] = {"edge", "level"}; @@ -352,7 +352,7 @@ } } -static void printlargevendor(PnP_TAG_PACKET * pkt, int size) { +static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) { static const unsigned char * addrtype[] = {"I/O", "Memory", "System"}; static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"}; static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"}; @@ -462,7 +462,7 @@ } } -static void printlargepacket(PnP_TAG_PACKET * pkt, int size) { +static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) { switch (tag_large_item_name(pkt->S1_Pack.Tag)) { case LargeVendorItem: printlargevendor(pkt, size); @@ -473,7 +473,7 @@ break; } } -static void printpackets(PnP_TAG_PACKET * pkt, const char * cat) { +static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) { if (pkt->S1_Pack.Tag== END_TAG) { printk(" No packets describing %s resources.\n", cat); return; @@ -494,7 +494,7 @@ } while (pkt->S1_Pack.Tag != END_TAG); } -void print_residual_device_info(void) +void __init print_residual_device_info(void) { int i; PPC_DEVICE *dev; @@ -562,8 +562,8 @@ } - -static void printVPD(void) { +#if 0 +static void __init printVPD(void) { #define vpd res->VitalProductData int ps=vpd.PageSize, i, j; static const char* Usage[]={ @@ -628,7 +628,6 @@ /* * Spit out some info about residual data */ -#if 0 void print_residual_device_info(void) { int i; @@ -764,7 +763,7 @@ little endian in the heap, so we use two parameters to avoid writing two very similar functions */ -static int same_DevID(unsigned short vendor, +static int __init same_DevID(unsigned short vendor, unsigned short Number, char * str) { @@ -780,7 +779,7 @@ return 0; } -PPC_DEVICE *residual_find_device(unsigned long BusMask, +PPC_DEVICE __init *residual_find_device(unsigned long BusMask, unsigned char * DevID, int BaseType, int SubType, @@ -803,7 +802,7 @@ return 0; } -PPC_DEVICE *residual_find_device_id(unsigned long BusMask, +PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask, unsigned short DevID, int BaseType, int SubType, @@ -844,7 +843,7 @@ return 0; /* not found */ } -PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p, +PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p, unsigned packet_type, int n) { @@ -858,7 +857,7 @@ return 0; /* not found */ } -PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p, +PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p, unsigned packet_type, int n) { diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.1.128/linux/arch/ppc/kernel/setup.c Fri Oct 9 13:27:06 1998 +++ linux/arch/ppc/kernel/setup.c Sun Nov 15 10:51:44 1998 @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.103 1998/09/18 09:14:56 paulus Exp $ + * $Id: setup.c,v 1.117 1998/11/09 19:55:53 geert Exp $ * Common prep/pmac/chrp boot and setup code. */ @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef CONFIG_MBX #include #endif @@ -131,9 +132,7 @@ cuda_poll(); break; case ADB_VIAPMU: - pmu_request(&req, NULL, 1, PMU_RESET); - for (;;) - pmu_poll(); + pmu_restart(); break; default: } @@ -206,10 +205,7 @@ cuda_poll(); break; case ADB_VIAPMU: - pmu_request(&req, NULL, 5, PMU_SHUTDOWN, - 'M', 'A', 'T', 'T'); - for (;;) - pmu_poll(); + pmu_shutdown(); break; default: } @@ -250,9 +246,11 @@ { #if !defined(CONFIG_MBX) && !defined(CONFIG_APUS) switch (_machine) { +#if defined(CONFIG_BLK_DEV_IDE_PMAC) case _MACH_Pmac: - pmac_ide_init_hwif_ports(p,base,irq); + pmac_ide_init_hwif_ports(p,base,irq); break; +#endif case _MACH_chrp: chrp_ide_init_hwif_ports(p,base,irq); break; @@ -267,68 +265,31 @@ unsigned long cpu_temp(void) { -#if 0 - unsigned long i, temp, thrm1, dir; - int sanity; + unsigned char thres = 0; - /* - * setup thrm3 - need to give TAU at least 20us - * to do the compare so assume a 300MHz clock. - * We need 300*20 ticks then. - * -- Cort - */ - asm("mtspr 1020, %1\n\t" - "mtspr 1021, %1\n\t" - "mtspr 1022, %0\n\t":: - "r" ( ((300*20)<<18) | THRM3_E), "r" (0) ); - -#if 0 - for ( i = 127 ; i >= 0 ; i-- ) - { - asm("mtspr 1020, %0\n\t":: - "r" (THRM1_TID|THRM1_V|(i<<2)) ); - /* check value */ - while ( !( thrm1 & THRM1_TIV) ) - asm("mfspr %0, 1020 \n\t": "=r" (thrm1) ); - if ( thrm1 & THRM1_TIN ) - { - printk("tin set: %x tiv %x\n", thrm1,thrm1&THRM1_TIV); - goto out; - } - - } -#endif #if 0 - i = 32; /* increment */ - dir = 1; /* direction we're checking 0=up 1=down */ - temp = 64; /* threshold checking against */ - while ( i ) - { - _set_THRM1((1<<29) | THRM1_V | (temp<<2) ); - printk("checking %d in dir %d thrm set to %x/%x\n", temp,dir, - ( (1<<29) | THRM1_V | (temp<<2)),_get_THRM1()); - /* check value */ - sanity = 0x0fffffff; - while ( (!( thrm1 & THRM1_TIV)) && (sanity--) ) - thrm1 = _get_THRM1(); - /*asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );*/ - if ( ! sanity || sanity==0xffffffff ) printk("no sanity\n"); - /* temp is not in that direction */ - if ( !(thrm1 & THRM1_TIN) ) - { - printk("not in that dir thrm1 %x\n",thrm1); - if ( dir == 0 ) dir = 1; - else dir = 0; - } - if ( dir ) temp -= i; - else temp += i; - i /= 2; - } - asm("mtspr 1020, %0\n\t" - "mtspr 1022, %0\n\t" ::"r" (0) ); + /* disable thrm2 */ + _set_THRM2( 0 ); + /* threshold 0 C, tid: exceeding threshold, tie: don't generate interrupt */ + _set_THRM1( THRM1_V ); + + /* we need 20us to do the compare - assume 300MHz processor clock */ + _set_THRM3(0); + _set_THRM3(THRM3_E | (300*30)<<18 ); + + udelay(100); + /* wait for the compare to complete */ + /*while ( !(_get_THRM1() & THRM1_TIV) ) ;*/ + if ( !(_get_THRM1() & THRM1_TIV) ) + printk("no tiv\n"); + if ( _get_THRM1() & THRM1_TIN ) + printk("crossed\n"); + /* turn everything off */ + _set_THRM3(0); + _set_THRM1(0); #endif -#endif - return 0; + + return thres; } int get_cpuinfo(char *buffer) @@ -342,12 +303,11 @@ unsigned long i; #ifdef __SMP__ - extern unsigned long cpu_present_map; - extern struct cpuinfo_PPC cpu_data[NR_CPUS]; +#define CPU_PRESENT(x) (cpu_callin_map[(x)]) #define GET_PVR ((long int)(cpu_data[i].pvr)) #define CD(x) (cpu_data[i].x) #else -#define cpu_present_map 1L +#define CPU_PRESENT(x) ((x)==0) #define smp_num_cpus 1 #define GET_PVR ((long int)_get_PVR()) #define CD(x) (x) @@ -355,7 +315,7 @@ for ( i = 0; i < smp_num_cpus ; i++ ) { - if ( ! ( cpu_present_map & (1< *memory_end_p) - { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,*memory_end_p); - initrd_start = 0; - } - } -#endif - #ifdef CONFIG_MBX mbx_setup_arch(memory_start_p,memory_end_p); #else /* CONFIG_MBX */ diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.1.128/linux/arch/ppc/kernel/signal.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/signal.c Sun Nov 15 10:51:44 1998 @@ -1,7 +1,7 @@ /* * linux/arch/ppc/kernel/signal.c * - * $Id: signal.c,v 1.20 1998/09/28 16:47:09 cort Exp $ + * $Id: signal.c,v 1.21 1998/10/22 19:37:49 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -245,7 +245,7 @@ goto badframe; sr = (struct sigregs *) sigctx.regs; regs->gpr[3] = ret = sigctx.signal; - regs->gpr[4] = (unsigned long) sr; + regs->gpr[4] = (unsigned long) sc; regs->link = (unsigned long) &sr->tramp; regs->nip = sigctx.handler; @@ -293,7 +293,7 @@ || get_user(regs->gpr[3], &sc->signal)) goto badframe; regs->gpr[1] = newsp; - regs->gpr[4] = (unsigned long) frame; + regs->gpr[4] = (unsigned long) sc; regs->link = (unsigned long) frame->tramp; return; diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.1.128/linux/arch/ppc/kernel/smp.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/smp.c Sun Nov 15 10:51:45 1998 @@ -1,5 +1,5 @@ /* - * $Id: smp.c,v 1.33 1998/09/25 04:32:30 cort Exp $ + * $Id: smp.c,v 1.36 1998/10/08 01:17:48 cort Exp $ * * Smp support for ppc. * @@ -35,24 +35,20 @@ int smp_threads_ready = 0; volatile int smp_commenced = 0; int smp_num_cpus = 1; -unsigned long cpu_present_map = 0; -volatile int cpu_number_map[NR_CPUS]; -volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; -volatile int __cpu_logical_map[NR_CPUS]; -static unsigned char boot_cpu_id = 0; struct cpuinfo_PPC cpu_data[NR_CPUS]; struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */ volatile unsigned long ipi_count; spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; - unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; - int first_cpu_booted = 0; -int start_secondary(void *); +/* all cpu mappings are 1-1 -- Cort */ +int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,}; +volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; +int start_secondary(void *); extern int cpu_idle(void *unused); void smp_local_timer_interrupt(struct pt_regs * regs) @@ -60,7 +56,6 @@ int cpu = smp_processor_id(); extern void update_one_process(struct task_struct *,unsigned long, unsigned long,unsigned long,int); - if (!--prof_counter[cpu]) { int user=0,system=0; struct task_struct * p = current; @@ -106,7 +101,7 @@ * Right now it only works for stop cpu's but will be setup * later for more general message passing. * - * As it is now, if we're sending two message as the same time + * As it is now, if we're sending two message at the same time * we have race conditions. I avoided doing locks here since * all that works right now is the stop cpu message. * @@ -117,17 +112,25 @@ { int msg = smp_message[smp_processor_id()]; - printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg); + /* clear interrupt */ + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); /* make sure msg is for us */ if ( msg == -1 ) return; + ipi_count++; + /*printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);*/ + switch( msg ) { case MSG_STOP_CPU: __cli(); while (1) ; break; + case MSG_RESCHEDULE: + current->need_resched = 1; + break; case 0xf0f0: /* syncing time bases - just return */ break; default: @@ -141,19 +144,17 @@ void smp_send_reschedule(int cpu) { - /* for now, nothing */ + smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0); } - spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED; void smp_message_pass(int target, int msg, unsigned long data, int wait) { - printk("SMP %d: sending smp message\n", current->processor); - - spin_lock(&mesg_pass_lock); if ( _machine != _MACH_Pmac ) return; - + /*printk("SMP %d: sending smp message\n", current->processor);*/ +if (smp_processor_id() ) printk("pass from cpu 1\n"); + spin_lock(&mesg_pass_lock); #define OTHER (~smp_processor_id() & 1) switch( target ) @@ -169,9 +170,10 @@ break; } /* interrupt secondary processor */ - /**(volatile unsigned long *)(0xf80000c0) = 0xffffffff; - eieio();*/ - *(volatile unsigned long *)(0xf80000c0) = 0; + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); + *(volatile unsigned long *)(0xf80000c0) = 0L; + eieio(); /* interrupt primary */ /**(volatile unsigned long *)(0xf3019000);*/ spin_unlock(&mesg_pass_lock); @@ -180,6 +182,7 @@ __initfunc(void smp_boot_cpus(void)) { extern struct task_struct *current_set[NR_CPUS]; + extern void __secondary_start(void); int i; struct task_struct *p; @@ -189,21 +192,14 @@ dcbf(&first_cpu_booted); for (i = 0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; prof_counter[i] = 1; prof_multiplier[i] = 1; } - - cpu_present_map = 0; - for(i=0; i < NR_CPUS; i++) - __cpu_logical_map[i] = -1; - - smp_store_cpu_info(boot_cpu_id); - active_kernel_processor = boot_cpu_id; - current->processor = boot_cpu_id; - cpu_present_map |= 1; - cpu_number_map[boot_cpu_id] = 0; - __cpu_logical_map[0] = boot_cpu_id; + + cpu_callin_map[0] = 1; + smp_store_cpu_info(0); + active_kernel_processor = 0; + current->processor = 0; if ( _machine != _MACH_Pmac ) { @@ -211,10 +207,6 @@ return; } - /* assume a 2nd processor for now */ - cpu_present_map |= (1 << 1); - smp_num_cpus = 2; - /* create a process for second processor */ kernel_thread(start_secondary, NULL, CLONE_PID); p = task[1]; @@ -222,15 +214,16 @@ panic("No idle task for secondary processor\n"); p->processor = 1; current_set[1] = p; + /* need to flush here since secondary bat's aren't setup */ dcbf((void *)¤t_set[1]); - /* setup entry point of secondary processor */ - /* *(volatile unsigned long *)(0xf2800000) - = (unsigned long)secondary_entry-KERNELBASE;*/ - *(volatile unsigned long *)(0xf2800000) = 0x100; + *(volatile unsigned long *)(0xf2800000) = + (unsigned long)__secondary_start-KERNELBASE; eieio(); /* interrupt secondary to begin executing code */ + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); *(volatile unsigned long *)(0xf80000c0) = 0L; eieio(); /* @@ -241,24 +234,21 @@ */ for ( i = 1000; i && !cpu_callin_map[1] ; i-- ) udelay(100); - + if(cpu_callin_map[1]) { - cpu_number_map[1] = 1; - __cpu_logical_map[i] = 1; - printk("Processor 1 found.\n"); - + printk("Processor %d found.\n", smp_num_cpus); + smp_num_cpus++; #if 0 /* this sync's the decr's, but we don't want this now -- Cort */ set_dec(decrementer_count); #endif - /* interrupt secondary to start decr's on both cpus */ - smp_message_pass(1,0xf0f0, 0, 0); - /* interrupt secondary to begin executing code */ - /**(volatile unsigned long *)(0xf80000c0) = 0L; - eieio();*/ } else { - smp_num_cpus--; - printk("Processor %d is stuck.\n", 1); + printk("Processor %d is stuck. \n", smp_num_cpus); } + /* reset the entry point so if we get another intr we won't + * try to startup again */ + *(volatile unsigned long *)(0xf2800000) = 0x100; + /* send interrupt to other processors to start decr's on all cpus */ + smp_message_pass(1,0xf0f0, 0, 0); } __initfunc(void smp_commence(void)) @@ -278,7 +268,7 @@ } /* Activate a secondary processor. */ -__initfunc(int start_secondary(void *unused)) +asmlinkage int __init start_secondary(void *unused) { printk("SMP %d: start_secondary()\n",current->processor); smp_callin(); @@ -288,16 +278,14 @@ __initfunc(void smp_callin(void)) { printk("SMP %d: smp_callin()\n",current->processor); - smp_store_cpu_info(1); + smp_store_cpu_info(current->processor); set_dec(decrementer_count); current->mm->mmap->vm_page_prot = PAGE_SHARED; current->mm->mmap->vm_start = PAGE_OFFSET; current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; - - /* assume we're just the secondary processor for now */ - cpu_callin_map[1] = 1; + cpu_callin_map[current->processor] = current->processor; while(!smp_commenced) barrier(); __sti(); @@ -317,6 +305,7 @@ { struct cpuinfo_PPC *c = &cpu_data[id]; + /* assume bogomips are same for everything */ c->loops_per_sec = loops_per_sec; c->pvr = _get_PVR(); } diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.1.128/linux/arch/ppc/kernel/time.c Thu Aug 6 14:06:29 1998 +++ linux/arch/ppc/kernel/time.c Sun Nov 15 10:51:45 1998 @@ -1,5 +1,5 @@ /* - * $Id: time.c,v 1.35 1998/07/24 11:05:47 geert Exp $ + * $Id: time.c,v 1.36 1998/10/10 12:16:08 geert Exp $ * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -106,7 +106,12 @@ #ifdef __SMP__ smp_local_timer_interrupt(regs); #endif - +#ifdef CONFIG_APUS + { + extern void apus_heartbeat (void); + apus_heartbeat (); + } +#endif hardirq_exit(cpu); /* restore the HID0 in case dcache was off - see idle.c * this hack should leave for a better solution -- Cort */ diff -u --recursive --new-file v2.1.128/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c --- v2.1.128/linux/arch/ppc/lib/locks.c Thu Aug 6 14:06:29 1998 +++ linux/arch/ppc/lib/locks.c Sun Nov 15 10:51:45 1998 @@ -1,5 +1,5 @@ /* - * $Id: locks.c,v 1.18 1998/07/28 03:50:27 cort Exp $ + * $Id: locks.c,v 1.20 1998/10/08 01:17:32 cort Exp $ * * Locks for smp ppc * @@ -18,13 +18,13 @@ #define DEBUG_LOCKS 1 #undef INIT_STUCK -#define INIT_STUCK 10000 +#define INIT_STUCK 0xffffffff void _spin_lock(spinlock_t *lock) { int cpu = smp_processor_id(); #ifdef DEBUG_LOCKS - int stuck = INIT_STUCK; + unsigned int stuck = INIT_STUCK; #endif /* DEBUG_LOCKS */ /* try expensive atomic load/store to get lock */ while((unsigned long )xchg_u32((void *)&lock->lock,0xffffffff)) { @@ -67,13 +67,13 @@ void _spin_unlock(spinlock_t *lp) { #ifdef DEBUG_LOCKS - if ( !lp->lock ) - panic("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp, - smp_processor_id(),current->comm,current->pid); + if ( !lp->lock ) + printk("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp, + smp_processor_id(),current->comm,current->pid); if ( lp->owner_cpu != smp_processor_id() ) - panic("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n", - lp, smp_processor_id(), (int)lp->owner_cpu, - lp->owner_pc,lp->lock); + printk("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n", + lp, smp_processor_id(), (int)lp->owner_cpu, + lp->owner_pc,lp->lock); #endif /* DEBUG_LOCKS */ lp->owner_pc = lp->owner_cpu = 0; eieio(); diff -u --recursive --new-file v2.1.128/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.1.128/linux/arch/ppc/mm/fault.c Wed Sep 9 14:51:06 1998 +++ linux/arch/ppc/mm/fault.c Sun Nov 15 10:51:45 1998 @@ -38,7 +38,7 @@ extern void (*debugger)(struct pt_regs *); extern void (*debugger_fault_handler)(struct pt_regs *); extern int (*debugger_dabr_match)(struct pt_regs *); -int debugger_kernel_faults = 0; +int debugger_kernel_faults = 1; #endif unsigned long htab_reloads = 0; /* updated by head.S:hash_page() */ diff -u --recursive --new-file v2.1.128/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.1.128/linux/arch/ppc/mm/init.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/mm/init.c Sun Nov 15 10:51:45 1998 @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.123 1998/09/19 19:03:55 geert Exp $ + * $Id: init.c,v 1.130 1998/11/10 10:09:20 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -114,7 +114,8 @@ * (i.e. page tables) instead of the bats. * -- Cort */ -#undef MAP_RAM_WITH_SEGREGS 1 +int __map_without_bats = 0; + /* optimization for 603 to load the tlb directly from the linux table -- Cort */ #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */ @@ -243,20 +244,24 @@ printk("%3d ", p->processor); if ( (p->processor != NO_PROC_ID) && (p == current_set[p->processor]) ) - + { + iscur = 1; + printk("current"); + } #else if ( p == current ) -#endif /* __SMP__ */ { iscur = 1; printk("current"); } + if ( p == last_task_used_math ) { if ( iscur ) printk(","); printk("last math"); } +#endif /* __SMP__ */ printk("\n"); } } @@ -677,18 +682,21 @@ __initfunc(static void coalesce_mem_pieces(struct mem_pieces *mp)) { - unsigned long a, e; + unsigned long a, s, ns; int i, j, d; d = 0; for (i = 0; i < mp->n_regions; i = j) { a = mp->regions[i].address; - e = a + mp->regions[i].size; + s = mp->regions[i].size; for (j = i + 1; j < mp->n_regions - && mp->regions[j].address <= e; ++j) - e = mp->regions[j].address + mp->regions[j].size; + && mp->regions[j].address - a <= s; ++j) { + ns = mp->regions[j].address + mp->regions[j].size - a; + if (ns > s) + s = ns; + } mp->regions[d].address = a; - mp->regions[d].size = e - a; + mp->regions[d].size = s; ++d; } mp->n_regions = d; @@ -800,28 +808,41 @@ int i; unsigned long v, p, s, f; #ifndef CONFIG_8xx - unsigned long tot, mem_base, bl, done; -#ifndef MAP_RAM_WITH_SEGREGS - /* Set up BAT2 and if necessary BAT3 to cover RAM. */ - mem_base = __pa(KERNELBASE); - tot = (unsigned long)end_of_DRAM - KERNELBASE; - for (bl = 128<<10; bl < 256<<20; bl <<= 1) { - if (bl * 2 > tot) - break; - } + if (!__map_without_bats) { + unsigned long tot, mem_base, bl, done; + unsigned long max_size = (256<<20); + unsigned long align; + + /* Set up BAT2 and if necessary BAT3 to cover RAM. */ + mem_base = __pa(KERNELBASE); + + /* Make sure we don't map a block larger than the + smallest alignment of the physical address. */ + /* alignment of mem_base */ + align = ~(mem_base-1) & mem_base; + /* set BAT block size to MIN(max_size, align) */ + if (align && align < max_size) + max_size = align; - setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE); - done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1; - if (done < tot) { - /* use BAT3 to cover a bit more */ - tot -= done; - for (bl = 128<<10; bl < 256<<20; bl <<= 1) + tot = (unsigned long)end_of_DRAM - KERNELBASE; + for (bl = 128<<10; bl < max_size; bl <<= 1) { if (bl * 2 > tot) break; - setbat(3, KERNELBASE+done, mem_base+done, bl, RAM_PAGE); + } + + setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE); + done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1; + if (done < tot) { + /* use BAT3 to cover a bit more */ + tot -= done; + for (bl = 128<<10; bl < max_size; bl <<= 1) + if (bl * 2 > tot) + break; + setbat(3, KERNELBASE+done, mem_base+done, bl, + RAM_PAGE); + } } -#endif v = KERNELBASE; for (i = 0; i < phys_mem.n_regions; ++i) { @@ -897,7 +918,10 @@ switch (_machine) { case _MACH_Pmac: + FREESEC(__prep_begin,__prep_end,num_prep_pages); + break; case _MACH_chrp: + FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; case _MACH_prep: @@ -965,8 +989,14 @@ setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE); break; case _MACH_Pmac: - setbat(0, 0xf3000000, 0xf3000000, 0x100000, IO_PAGE); - ioremap_base = 0xf0000000; + { + unsigned long base = 0xf3000000; + struct device_node *macio = find_devices("mac-io"); + if (macio && macio->n_addrs) + base = macio->addrs[0].address; + setbat(0, base, base, 0x100000, IO_PAGE); + ioremap_base = 0xf0000000; + } break; case _MACH_apus: /* Map PPC exception vectors. */ diff -u --recursive --new-file v2.1.128/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig --- v2.1.128/linux/arch/ppc/pmac_defconfig Sun Nov 8 14:02:44 1998 +++ linux/arch/ppc/pmac_defconfig Sun Nov 15 10:51:45 1998 @@ -35,16 +35,20 @@ CONFIG_BINFMT_MISC=m # CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -CONFIG_MACMOUSE=y +CONFIG_ADBMOUSE=y +CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_PROC_DEVICETREE=y # CONFIG_KGDB is not set -CONFIG_XMON=y +# CONFIG_XMON is not set +# CONFIG_TOTALMP is not set +CONFIG_BOOTX_TEXT=y # # Plug and Play support @@ -70,6 +74,10 @@ # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_IDEPCI is not set # CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_PMAC_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set # @@ -159,7 +167,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -CONFIG_SCSI_AIC7XXX=m +CONFIG_SCSI_AIC7XXX=y # CONFIG_OVERRIDE_CMDS is not set CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=15 @@ -216,23 +224,26 @@ # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set -CONFIG_DE4X5=m +CONFIG_DE4X5=y CONFIG_DEC_ELCP=m # CONFIG_DGRS is not set # CONFIG_EEXPRESS_PRO100 is not set # CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set # CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set +# CONFIG_HIPPI is not set # CONFIG_DLCI is not set # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set -CONFIG_PPP=m +CONFIG_PPP=y # # CCP compressors for PPP are only built as modules. @@ -241,6 +252,7 @@ # CONFIG_NET_RADIO is not set # CONFIG_TR is not set # CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set # # Amateur Radio support @@ -264,11 +276,12 @@ CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y CONFIG_FB_ATY=y CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y # CONFIG_FB_S3TRIO is not set -# CONFIG_FB_VGA is not set +# CONFIG_FB_MATROX is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -293,8 +306,9 @@ CONFIG_SERIAL=m # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_MOUSE is not set -# CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set @@ -322,6 +336,7 @@ CONFIG_PROC_FS=y CONFIG_NFS_FS=y CONFIG_NFSD=y +# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_CODA_FS is not set @@ -330,12 +345,16 @@ # CONFIG_NTFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=m +CONFIG_HFS_FS=y # CONFIG_ROMFS_FS is not set CONFIG_AUTOFS_FS=y # CONFIG_UFS_FS is not set -# CONFIG_ADFS_FS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set CONFIG_DEVPTS_FS=y +# CONFIG_ADFS_FS is not set +# CONFIG_QNX4FS_FS is not set CONFIG_MAC_PARTITION=y CONFIG_NLS=y @@ -374,3 +393,9 @@ # CONFIG_SOUND=y CONFIG_DMASOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set diff -u --recursive --new-file v2.1.128/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig --- v2.1.128/linux/arch/ppc/prep_defconfig Sun Nov 8 14:02:44 1998 +++ linux/arch/ppc/prep_defconfig Sun Nov 15 10:51:45 1998 @@ -41,7 +41,7 @@ # CONFIG_MAC_KEYBOARD is not set # CONFIG_MAC_FLOPPY is not set # CONFIG_MAC_SERIAL is not set -# CONFIG_MACMOUSE is not set +# CONFIG_ADBMOUSE is not set # CONFIG_PROC_DEVICETREE is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set diff -u --recursive --new-file v2.1.128/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.1.128/linux/arch/sparc/defconfig Sun Nov 8 14:02:44 1998 +++ linux/arch/sparc/defconfig Wed Nov 18 09:06:05 1998 @@ -69,6 +69,7 @@ # CONFIG_SPARCAUDIO_AMD7930 is not set # CONFIG_SPARCAUDIO_CS4231 is not set # CONFIG_SPARCAUDIO_DBRI is not set +# CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m CONFIG_NET=y CONFIG_SYSVIPC=y diff -u --recursive --new-file v2.1.128/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v2.1.128/linux/arch/sparc/kernel/entry.S Thu Aug 6 14:06:30 1998 +++ linux/arch/sparc/kernel/entry.S Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.152 1998/07/29 16:32:24 jj Exp $ +/* $Id: entry.S,v 1.153 1998/11/11 15:12:33 jj Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -313,7 +313,8 @@ patch_handler_irq: call C_LABEL(handler_irq) add %sp, REGWIN_SZ, %o1 ! pt_regs ptr - wr %l0, PSR_ET, %psr + or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq + wr %g2, PSR_ET, %psr ! keep ET up WRITE_PAUSE RESTORE_ALL diff -u --recursive --new-file v2.1.128/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.1.128/linux/arch/sparc/kernel/sparc_ksyms.c Sun Nov 8 14:02:45 1998 +++ linux/arch/sparc/kernel/sparc_ksyms.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.72 1998/10/22 15:15:08 ecd Exp $ +/* $Id: sparc_ksyms.c,v 1.73 1998/11/06 13:49:54 jj Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -41,6 +41,7 @@ #endif #include #include +#include struct poll { int fd; @@ -157,6 +158,8 @@ EXPORT_SYMBOL(sparc_alloc_io); EXPORT_SYMBOL(sparc_free_io); EXPORT_SYMBOL(io_remap_page_range); +EXPORT_SYMBOL(iounit_map_dma_init); +EXPORT_SYMBOL(iounit_map_dma_page); /* Btfixup stuff cannot have versions, it would be complicated too much */ #ifndef __SMP__ diff -u --recursive --new-file v2.1.128/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.1.128/linux/arch/sparc/kernel/sun4d_smp.c Fri Oct 9 13:27:06 1998 +++ linux/arch/sparc/kernel/sun4d_smp.c Mon Nov 16 10:37:28 1998 @@ -168,10 +168,6 @@ printk("Entering SMP Mode...\n"); - smp_penguin_ctable.which_io = 0; - smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; - smp_penguin_ctable.reg_size = 0; - for (i = 0; i < NR_CPUS; i++) cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data; @@ -220,7 +216,16 @@ for (no = 0; no < linux_num_cpus; no++) if (linux_cpus[no].mid == i) break; - + + /* + * Initialize the contexts table + * Since the call to prom_startcpu() trashes the structure, + * we need to re-initialize it for each cpu + */ + smp_penguin_ctable.which_io = 0; + smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; + smp_penguin_ctable.reg_size = 0; + /* whirrr, whirrr, whirrrrrrrrr... */ SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, linux_cpus[no].prom_node)); local_flush_cache_all(); @@ -230,10 +235,10 @@ SMP_PRINTK(("prom_startcpu returned :)\n")); /* wheee... it's going... */ - for(timeout = 0; timeout < 5000000; timeout++) { + for(timeout = 0; timeout < 10000; timeout++) { if(cpu_callin_map[i]) break; - udelay(100); + udelay(200); } if(cpu_callin_map[i]) { diff -u --recursive --new-file v2.1.128/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c --- v2.1.128/linux/arch/sparc/kernel/sun4m_smp.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/sun4m_smp.c Mon Nov 16 10:37:28 1998 @@ -143,10 +143,6 @@ printk("Entering SMP Mode...\n"); - smp_penguin_ctable.which_io = 0; - smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; - smp_penguin_ctable.reg_size = 0; - for (i = 0; i < NR_CPUS; i++) cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data; @@ -189,6 +185,15 @@ /* See trampoline.S for details... */ entry += ((i-1) * 3); + /* + * Initialize the contexts table + * Since the call to prom_startcpu() trashes the structure, + * we need to re-initialize it for each cpu + */ + smp_penguin_ctable.which_io = 0; + smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; + smp_penguin_ctable.reg_size = 0; + /* whirrr, whirrr, whirrrrrrrrr... */ printk("Starting CPU %d at %p\n", i, entry); mid_xlate[i] = (linux_cpus[i].mid & ~8); @@ -197,10 +202,10 @@ &smp_penguin_ctable, 0, (char *)entry); /* wheee... it's going... */ - for(timeout = 0; timeout < 5000000; timeout++) { + for(timeout = 0; timeout < 10000; timeout++) { if(cpu_callin_map[i]) break; - udelay(100); + udelay(200); } if(cpu_callin_map[i]) { /* Another "Red Snapper". */ diff -u --recursive --new-file v2.1.128/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.1.128/linux/arch/sparc/mm/fault.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/mm/fault.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.95 1998/09/18 19:50:32 davem Exp $ +/* $Id: fault.c,v 1.96 1998/11/08 11:13:56 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -231,7 +231,8 @@ if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(current, vma, address, write); + if (!handle_mm_fault(current, vma, address, write)) + goto do_sigbus; up(&mm->mmap_sem); return; /* @@ -241,7 +242,7 @@ bad_area: up(&mm->mmap_sem); /* Is this in ex_table? */ - +do_kernel_fault: g2 = regs->u_regs[UREG_G2]; if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) { if (fixup > 10) { /* Values below are reserved for other things */ @@ -279,6 +280,15 @@ return; } unhandled_fault (address, tsk, regs); + return; + +do_sigbus: + up(&mm->mmap_sem); + tsk->tss.sig_address = address; + tsk->tss.sig_desc = SUBSIG_MISCERROR; + force_sig(SIGBUS, tsk); + if (! from_user) + goto do_kernel_fault; } asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write, @@ -372,7 +382,8 @@ else if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; - handle_mm_fault(current, vma, address, write); + if (!handle_mm_fault(current, vma, address, write)) + goto do_sigbus; up(&mm->mmap_sem); return; bad_area: @@ -385,6 +396,12 @@ tsk->tss.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, tsk, 1); return; + +do_sigbus: + up(&mm->mmap_sem); + tsk->tss.sig_address = address; + tsk->tss.sig_desc = SUBSIG_MISCERROR; + force_sig(SIGBUS, tsk); } void window_overflow_fault(void) diff -u --recursive --new-file v2.1.128/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c --- v2.1.128/linux/arch/sparc/mm/generic.c Thu Dec 19 01:03:32 1996 +++ linux/arch/sparc/mm/generic.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.5 1996/12/18 06:43:23 tridge Exp $ +/* $Id: generic.c,v 1.6 1998/10/27 23:28:00 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -41,10 +41,11 @@ unsigned long addr = pte_page(page); if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr))) return; - free_page(addr); - if (current->mm->rss <= 0) - return; - current->mm->rss--; + /* + * free_page() used to be able to clear swap cache + * entries. We may now have to do it manually. + */ + free_page_and_swap_cache(addr); return; } swap_free(pte_val(page)); diff -u --recursive --new-file v2.1.128/linux/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c --- v2.1.128/linux/arch/sparc/mm/io-unit.c Fri May 8 23:14:46 1998 +++ linux/arch/sparc/mm/io-unit.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.11 1998/04/13 07:26:37 davem Exp $ +/* $Id: io-unit.c,v 1.13 1998/11/08 11:13:57 davem Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -230,4 +230,52 @@ #ifdef CONFIG_SBUS BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM); #endif +} + +__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size) +{ + int i, j, k, npages; + unsigned long rotor, scan, limit; + unsigned long flags; + __u32 ret; + struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; + + npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT; + i = 0x0213; + spin_lock_irqsave(&iounit->lock, flags); +next: j = (i & 15); + rotor = iounit->rotor[j - 1]; + limit = iounit->limit[j]; + scan = rotor; +nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan); + if (scan + npages > limit) { + if (limit != rotor) { + limit = rotor; + scan = iounit->limit[j - 1]; + goto nexti; + } + i >>= 4; + if (!(i & 15)) + panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size); + goto next; + } + for (k = 1, scan++; k < npages; k++) + if (test_bit(scan++, iounit->bmap)) + goto nexti; + iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1]; + scan -= npages; + ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT); + for (k = 0; k < npages; k++, scan++) + set_bit(scan, iounit->bmap); + spin_unlock_irqrestore(&iounit->lock, flags); + return ret; +} + +__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus) +{ + int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT; + struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; + + iounit->page_table[scan] = MKIOPTE(mmu_v2p(((unsigned long)addr) & PAGE_MASK)); + return vaddr + (((unsigned long)addr) & ~PAGE_MASK); } diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.1.128/linux/arch/sparc64/config.in Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc64/config.in Wed Nov 18 09:06:05 1998 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.57 1998/09/17 11:05:14 jj Exp $ +# $Id: config.in,v 1.58 1998/11/16 04:47:30 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -224,7 +224,10 @@ tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 - tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX +# Turned off until updated 3c59x.c driver +# gets approved by Linus... --DAVEM +# +# tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX fi # bool 'FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.1.128/linux/arch/sparc64/defconfig Sun Nov 8 14:02:46 1998 +++ linux/arch/sparc64/defconfig Wed Nov 18 09:06:05 1998 @@ -74,6 +74,7 @@ # CONFIG_SPARCAUDIO_AMD7930 is not set # CONFIG_SPARCAUDIO_CS4231 is not set # CONFIG_SPARCAUDIO_DBRI is not set +# CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m CONFIG_PCI_OLD_PROC=y CONFIG_NET=y @@ -198,7 +199,7 @@ # CONFIG_AIC7XXX_PROC_STATS is not set CONFIG_AIC7XXX_RESET_DELAY=5 CONFIG_SCSI_NCR53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=10 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set @@ -238,7 +239,6 @@ CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m CONFIG_DE4X5=m -CONFIG_VORTEX=m # # Filesystems diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.1.128/linux/arch/sparc64/kernel/ioctl32.c Sun Nov 8 14:02:46 1998 +++ linux/arch/sparc64/kernel/ioctl32.c Wed Nov 18 09:06:05 1998 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.53 1998/10/26 08:01:01 jj Exp $ +/* $Id: ioctl32.c,v 1.55 1998/11/17 07:43:17 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -34,6 +34,7 @@ #include #include #include +#include #include /* Ugly hack. */ @@ -52,6 +53,8 @@ #include #include +#include + /* Use this to get at 32-bit user passed pointers. See sys_sparc32.c for description about these. */ #define A(__x) ((unsigned long)(__x)) @@ -63,6 +66,12 @@ __ret; \ }) +/* Aiee. Someone does not find a difference between int and long */ +#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) +#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) +#define EXT2_IOC32_GETVERSION _IOR('v', 1, int) +#define EXT2_IOC32_SETVERSION _IOW('v', 2, int) + extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -94,6 +103,18 @@ return -EFAULT; return err; } + +static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* These are just misnamed, they actually get/put from/to user an int */ + switch (cmd) { + case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; + case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; + case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; + case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; + } + return sys_ioctl(fd, cmd, arg); +} struct timeval32 { int tv_sec; @@ -1551,6 +1572,13 @@ error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)arg); goto out; + case EXT2_IOC32_GETFLAGS: + case EXT2_IOC32_SETFLAGS: + case EXT2_IOC32_GETVERSION: + case EXT2_IOC32_SETVERSION: + error = do_ext2_ioctl(fd, cmd, arg); + goto out; + /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ @@ -1859,13 +1887,159 @@ case AUDIO_GETDEV_SUNOS: case AUDIO_FLUSH: + /* Big Q for sound/OSS */ + case SNDCTL_SEQ_RESET: + case SNDCTL_SEQ_SYNC: + case SNDCTL_SYNTH_INFO: + case SNDCTL_SEQ_CTRLRATE: + case SNDCTL_SEQ_GETOUTCOUNT: + case SNDCTL_SEQ_GETINCOUNT: + case SNDCTL_SEQ_PERCMODE: + case SNDCTL_FM_LOAD_INSTR: + case SNDCTL_SEQ_TESTMIDI: + case SNDCTL_SEQ_RESETSAMPLES: + case SNDCTL_SEQ_NRSYNTHS: + case SNDCTL_SEQ_NRMIDIS: + case SNDCTL_MIDI_INFO: + case SNDCTL_SEQ_THRESHOLD: + case SNDCTL_SYNTH_MEMAVL: + case SNDCTL_FM_4OP_ENABLE: + case SNDCTL_SEQ_PANIC: + case SNDCTL_SEQ_OUTOFBAND: + case SNDCTL_SEQ_GETTIME: + case SNDCTL_SYNTH_ID: + case SNDCTL_SYNTH_CONTROL: + case SNDCTL_SYNTH_REMOVESAMPLE: + + /* Big T for sound/OSS */ + case SNDCTL_TMR_TIMEBASE: + case SNDCTL_TMR_START: + case SNDCTL_TMR_STOP: + case SNDCTL_TMR_CONTINUE: + case SNDCTL_TMR_TEMPO: + case SNDCTL_TMR_SOURCE: + case SNDCTL_TMR_METRONOME: + case SNDCTL_TMR_SELECT: + + /* Little m for sound/OSS */ + case SNDCTL_MIDI_PRETIME: + case SNDCTL_MIDI_MPUMODE: + case SNDCTL_MIDI_MPUCMD: + + /* Big P for sound/OSS */ + case SNDCTL_DSP_RESET: + case SNDCTL_DSP_SYNC: + case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_GETBLKSIZE: + case SNDCTL_DSP_CHANNELS: + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + case SNDCTL_DSP_GETFMTS: + case SNDCTL_DSP_SETFMT: + case SNDCTL_DSP_GETOSPACE: + case SNDCTL_DSP_GETISPACE: + case SNDCTL_DSP_NONBLOCK: + case SNDCTL_DSP_GETCAPS: + case SNDCTL_DSP_GETTRIGGER: + case SNDCTL_DSP_SETTRIGGER: + case SNDCTL_DSP_GETIPTR: + case SNDCTL_DSP_GETOPTR: + /* case SNDCTL_DSP_MAPINBUF: XXX needs translation */ + /* case SNDCTL_DSP_MAPOUTBUF: XXX needs translation */ + case SNDCTL_DSP_SETSYNCRO: + case SNDCTL_DSP_SETDUPLEX: + case SNDCTL_DSP_GETODELAY: + case SNDCTL_DSP_PROFILE: + + case SOUND_PCM_READ_RATE: + case SOUND_PCM_READ_CHANNELS: + case SOUND_PCM_READ_BITS: + case SOUND_PCM_READ_FILTER: + + /* Big C for sound/OSS */ + case SNDCTL_COPR_RESET: + case SNDCTL_COPR_LOAD: + case SNDCTL_COPR_RDATA: + case SNDCTL_COPR_RCODE: + case SNDCTL_COPR_WDATA: + case SNDCTL_COPR_WCODE: + case SNDCTL_COPR_RUN: + case SNDCTL_COPR_HALT: + case SNDCTL_COPR_SENDMSG: + case SNDCTL_COPR_RCVMSG: + + /* Big M for sound/OSS */ + case SOUND_MIXER_READ_VOLUME: + case SOUND_MIXER_READ_BASS: + case SOUND_MIXER_READ_TREBLE: + case SOUND_MIXER_READ_SYNTH: + case SOUND_MIXER_READ_PCM: + case SOUND_MIXER_READ_SPEAKER: + case SOUND_MIXER_READ_LINE: + case SOUND_MIXER_READ_MIC: + case SOUND_MIXER_READ_CD: + case SOUND_MIXER_READ_IMIX: + case SOUND_MIXER_READ_ALTPCM: + case SOUND_MIXER_READ_RECLEV: + case SOUND_MIXER_READ_IGAIN: + case SOUND_MIXER_READ_OGAIN: + case SOUND_MIXER_READ_LINE1: + case SOUND_MIXER_READ_LINE2: + case SOUND_MIXER_READ_LINE3: + case SOUND_MIXER_READ_MUTE: + /* case SOUND_MIXER_READ_ENHANCE: same value as READ_MUTE */ + /* case SOUND_MIXER_READ_LOUD: same value as READ_MUTE */ + case SOUND_MIXER_READ_RECSRC: + case SOUND_MIXER_READ_DEVMASK: + case SOUND_MIXER_READ_RECMASK: + case SOUND_MIXER_READ_STEREODEVS: + case SOUND_MIXER_READ_CAPS: + + case SOUND_MIXER_WRITE_VOLUME: + case SOUND_MIXER_WRITE_BASS: + case SOUND_MIXER_WRITE_TREBLE: + case SOUND_MIXER_WRITE_SYNTH: + case SOUND_MIXER_WRITE_PCM: + case SOUND_MIXER_WRITE_SPEAKER: + case SOUND_MIXER_WRITE_LINE: + case SOUND_MIXER_WRITE_MIC: + case SOUND_MIXER_WRITE_CD: + case SOUND_MIXER_WRITE_IMIX: + case SOUND_MIXER_WRITE_ALTPCM: + case SOUND_MIXER_WRITE_RECLEV: + case SOUND_MIXER_WRITE_IGAIN: + case SOUND_MIXER_WRITE_OGAIN: + case SOUND_MIXER_WRITE_LINE1: + case SOUND_MIXER_WRITE_LINE2: + case SOUND_MIXER_WRITE_LINE3: + case SOUND_MIXER_WRITE_MUTE: + /* case SOUND_MIXER_WRITE_ENHANCE: same value as WRITE_MUTE */ + /* case SOUND_MIXER_WRITE_LOUD: same value as WRITE_MUTE */ + case SOUND_MIXER_WRITE_RECSRC: + + case SOUND_MIXER_INFO: + case SOUND_OLD_MIXER_INFO: + case SOUND_MIXER_ACCESS: + case SOUND_MIXER_PRIVATE1: + case SOUND_MIXER_PRIVATE2: + case SOUND_MIXER_PRIVATE3: + case SOUND_MIXER_PRIVATE4: + case SOUND_MIXER_PRIVATE5: + case SOUND_MIXER_GETLEVELS: + case SOUND_MIXER_SETLEVELS: + + case OSS_GETVERSION: + /* AUTOFS */ case AUTOFS_IOC_READY: case AUTOFS_IOC_FAIL: case AUTOFS_IOC_CATATONIC: case AUTOFS_IOC_PROTOVER: case AUTOFS_IOC_EXPIRE: - + error = sys_ioctl (fd, cmd, arg); goto out; diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c --- v2.1.128/linux/arch/sparc64/kernel/psycho.c Sun Nov 8 14:02:46 1998 +++ linux/arch/sparc64/kernel/psycho.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: psycho.c,v 1.65 1998/10/20 14:41:28 ecd Exp $ +/* $Id: psycho.c,v 1.66 1998/11/02 22:27:45 davem Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) @@ -1406,9 +1406,9 @@ dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device); for(preg = 0; preg < 6; preg++) { if(pdev->base_address[preg] != 0) - prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]); + dprintf("%d[%016lx] ", preg, pdev->base_address[preg]); } - prom_printf("\n"); + dprintf("\n"); #endif } @@ -1930,8 +1930,8 @@ out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn) { return ((pbm->parent == 0) || - ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 4) || - ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 6) || + ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) || + ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) || (pci_probe_enable == 0)); } diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.1.128/linux/arch/sparc64/kernel/rtrap.S Sun Nov 8 14:02:47 1998 +++ linux/arch/sparc64/kernel/rtrap.S Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.44 1998/10/21 22:27:22 davem Exp $ +/* $Id: rtrap.S,v 1.45 1998/11/09 15:33:29 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -172,7 +172,13 @@ wrpr %l7, PSTATE_IE, %pstate call update_perfctrs nop - ba,a,pt %xcc, check_user_wins + wrpr %l7, 0x0, %pstate + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + brz,pt %o2, 1f + sethi %hi(TSTATE_PEF), %l6 + wrpr %l7, PSTATE_IE, %pstate + call fault_in_user_windows + add %sp, STACK_BIAS + REGWIN_SZ, %o0 1: andcc %l1, %l6, %g0 diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.1.128/linux/arch/sparc64/kernel/sparc64_ksyms.c Sun Nov 8 14:02:47 1998 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.48 1998/10/20 03:09:08 jj Exp $ +/* $Id: sparc64_ksyms.c,v 1.49 1998/10/28 08:11:28 jj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -257,6 +257,9 @@ EXPORT_SYMBOL(prom_cpu_nodes); EXPORT_SYMBOL(sys_ioctl); EXPORT_SYMBOL(sys32_ioctl); +EXPORT_SYMBOL(get_unmapped_area); +EXPORT_SYMBOL(move_addr_to_kernel); +EXPORT_SYMBOL(move_addr_to_user); #endif /* Special internal versions of library functions. */ diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/sys32.S linux/arch/sparc64/kernel/sys32.S --- v2.1.128/linux/arch/sparc64/kernel/sys32.S Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/sys32.S Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: sys32.S,v 1.7 1998/09/11 10:39:46 jj Exp $ +/* $Id: sys32.S,v 1.8 1998/10/28 08:10:37 jj Exp $ * sys32.S: I-cache tricks for 32-bit compatability layer simple * conversions. * @@ -13,16 +13,10 @@ .align 32 .globl sys32_mmap sys32_mmap: - srl %o0, 0, %o0 ! IEU0 Group - sethi %hi(0xffffffff), %g2 ! IEU1 - srl %o1, 0, %o1 ! IEU0 Group - or %g2, %lo(0xffffffff), %g2 ! IEU1 - srl %o2, 0, %o2 ! IEU0 Group - sethi %hi(sys_mmap), %g1 ! IEU1 - and %o3, %g2, %o3 ! IEU0 Group - and %o4, %g2, %o4 ! IEU1 - jmpl %g1 + %lo(sys_mmap), %g0 ! CTI Group brk forced - and %o5, %g2, %o5 ! IEU0 + srl %o4, 0, %o4 + sethi %hi(sys_mmap), %g1 + jmpl %g1 + %lo(sys_mmap), %g0 + srl %o5, 0, %o5 .align 32 .globl sys32_lseek @@ -36,14 +30,12 @@ sethi %hi(0xffff), %g2 sethi %hi(sys_chmod), %g1 orcc %g2, %lo(0xffff), %g2 - srl %o0, 0, %o0 jmpl %g1 + %lo(sys_chmod), %g0 and %o1, %g2, %o1 sys32_chown: sethi %hi(0xffff), %g2 sethi %hi(sys_chown), %g1 orcc %g2, %lo(0xffff), %g2 - srl %o0, 0, %o0 and %o1, %g2, %o1 jmpl %g1 + %lo(sys_chown), %g0 and %o2, %g2, %o2 @@ -51,7 +43,6 @@ sethi %hi(0xffff), %g2 sethi %hi(sys_lchown), %g1 orcc %g2, %lo(0xffff), %g2 - srl %o0, 0, %o0 and %o1, %g2, %o1 jmpl %g1 + %lo(sys_lchown), %g0 and %o2, %g2, %o2 @@ -59,27 +50,21 @@ sethi %hi(0xffff), %g2 sethi %hi(sys_mknod), %g1 orcc %g2, %lo(0xffff), %g2 - srl %o0, 0, %o0 jmpl %g1 + %lo(sys_mknod), %g0 and %o2, %g2, %o2 .align 32 .globl sys32_sendto, sys32_recvfrom, sys32_getsockopt sys32_sendto: - srl %o1, 0, %o1 sethi %hi(sys_sendto), %g1 - srl %o2, 0, %o2 jmpl %g1 + %lo(sys_sendto), %g0 srl %o4, 0, %o4 sys32_recvfrom: - srl %o1, 0, %o1 - sethi %hi(sys_recvfrom), %g1 - srl %o2, 0, %o2 srl %o4, 0, %o4 + sethi %hi(sys_recvfrom), %g1 jmpl %g1 + %lo(sys_recvfrom), %g0 srl %o5, 0, %o5 sys32_getsockopt: - srl %o3, 0, %o3 sethi %hi(sys_getsockopt), %g1 jmpl %g1 + %lo(sys_getsockopt), %g0 srl %o4, 0, %o4 diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.1.128/linux/arch/sparc64/kernel/sys_sparc32.c Sun Nov 8 14:02:47 1998 +++ linux/arch/sparc64/kernel/sys_sparc32.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.98 1998/10/26 20:01:11 davem Exp $ +/* $Id: sys_sparc32.c,v 1.100 1998/11/08 11:14:00 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -1110,10 +1110,11 @@ { fd_set_buffer *fds; struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x); - unsigned long timeout, nn; + unsigned long nn; + long timeout; int ret; - timeout = ~0UL; + timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { time_t sec, usec; @@ -1124,8 +1125,6 @@ timeout = (usec + 1000000/HZ - 1) / (1000000/HZ); timeout += sec * HZ; - if (timeout) - timeout += jiffies + 1; } ret = -ENOMEM; @@ -1147,12 +1146,11 @@ zero_fd_set(n, fds->res_out); zero_fd_set(n, fds->res_ex); - ret = do_select(n, fds, timeout); + ret = do_select(n, fds, &timeout); if (tvp && !(current->personality & STICKY_TIMEOUTS)) { - unsigned long timeout = current->timeout - jiffies - 1; time_t sec = 0, usec = 0; - if ((long) timeout > 0) { + if (timeout) { sec = timeout / HZ; usec = timeout % HZ; usec *= (1000000/HZ); @@ -1160,7 +1158,6 @@ put_user(sec, &tvp->tv_sec); put_user(usec, &tvp->tv_usec); } - current->timeout = 0; if (ret < 0) goto out; @@ -3533,15 +3530,15 @@ typedef __kernel_ssize_t32 ssize_t32; asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf, - __kernel_size_t32 count, u32 pos) + __kernel_size_t32 count, u32 poshi, u32 poslo) { - return sys_pread(fd, ubuf, count, pos); + return sys_pread(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo)); } asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf, - __kernel_size_t32 count, u32 pos) + __kernel_size_t32 count, u32 poshi, u32 poslo) { - return sys_pwrite(fd, ubuf, count, pos); + return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo)); } diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.1.128/linux/arch/sparc64/mm/fault.c Sun Nov 8 14:02:49 1998 +++ linux/arch/sparc64/mm/fault.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.25 1998/10/19 21:52:26 davem Exp $ +/* $Id: fault.c,v 1.26 1998/11/08 11:14:03 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -155,7 +155,8 @@ goto bad_area; } current->mm->segments = (void *) (address & PAGE_SIZE); - handle_mm_fault(current, vma, address, write); + if (!handle_mm_fault(current, vma, address, write)) + goto do_sigbus; up(&mm->mmap_sem); return; /* @@ -165,6 +166,7 @@ bad_area: up(&mm->mmap_sem); +do_kernel_fault: { unsigned long g2 = regs->u_regs[UREG_G2]; @@ -204,4 +206,13 @@ } unhandled_fault (address, current, regs); } + return; + +do_sigbus: + up(&mm->mmap_sem); + current->tss.sig_address = address; + current->tss.sig_desc = SUBSIG_MISCERROR; + force_sig(SIGBUS, current); + if (regs->tstate & TSTATE_PRIV) + goto do_kernel_fault; } diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c --- v2.1.128/linux/arch/sparc64/mm/generic.c Mon Jul 7 08:18:55 1997 +++ linux/arch/sparc64/mm/generic.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.2 1997/07/01 09:11:42 jj Exp $ +/* $Id: generic.c,v 1.3 1998/10/27 23:28:07 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -41,10 +41,11 @@ unsigned long addr = pte_page(page); if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr))) return; - free_page(addr); - if (current->mm->rss <= 0) - return; - current->mm->rss--; + /* + * free_page() used to be able to clear swap cache + * entries. We may now have to do it manually. + */ + free_page_and_swap_cache(addr); return; } swap_free(pte_val(page)); diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S --- v2.1.128/linux/arch/sparc64/mm/ultra.S Sun Nov 8 14:02:50 1998 +++ linux/arch/sparc64/mm/ultra.S Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.29 1998/10/22 03:05:51 davem Exp $ +/* $Id: ultra.S,v 1.31 1998/11/07 06:39:21 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -62,35 +62,37 @@ and %o4, 0x3ff, %o5 cmp %o5, %o0 bne,pt %icc, 2f - andn %o4, 0x3ff, %o4 -/*IC6*/ cmp %o4, %o1 +/*IC6*/ andn %o4, 0x3ff, %o4 + cmp %o4, %o1 blu,pt %xcc, 2f cmp %o4, %o3 blu,pn %xcc, 4f 2: ldxa [%g2] ASI_DTLB_TAG_READ, %o4 and %o4, 0x3ff, %o5 cmp %o5, %o0 - andn %o4, 0x3ff, %o4 -/*IC7*/ bne,pt %icc, 3f +/*IC7*/ andn %o4, 0x3ff, %o4 + bne,pt %icc, 3f cmp %o4, %o1 blu,pt %xcc, 3f cmp %o4, %o3 blu,pn %xcc, 5f nop 3: brnz,pt %g2, 1b - sub %g2, (1 << 3), %g2 -/*IC8*/ retl +/*IC8*/ sub %g2, (1 << 3), %g2 + retl wrpr %g1, 0x0, %pstate 4: stxa %g0, [%g3] ASI_IMMU stxa %g0, [%g2] ASI_ITLB_DATA_ACCESS ba,pt %xcc, 2b flush %g6 5: stxa %g0, [%g3] ASI_DMMU - stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS +/*IC9*/ stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS ba,pt %xcc, 3b flush %g6 + + .align 32 __flush_tlb_mm_slow: -/*IC9*/ rdpr %pstate, %g1 +/*IC10*/rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o1] ASI_DMMU stxa %g0, [%g3] ASI_DMMU_DEMAP @@ -98,21 +100,25 @@ flush %g6 stxa %g2, [%o1] ASI_DMMU flush %g6 -/*IC10*/retl +/*IC11*/retl wrpr %g1, 0, %pstate + + .align 32 __flush_tlb_page_slow: - rdpr %pstate, %g1 +/*IC12*/rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o2] ASI_DMMU stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP flush %g6 -/*IC11*/stxa %g2, [%o2] ASI_DMMU + stxa %g2, [%o2] ASI_DMMU flush %g6 - retl +/*IC13*/retl wrpr %g1, 0, %pstate + + .align 32 __flush_tlb_range_pbp_slow: - rdpr %pstate, %g1 +/*IC13*/rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o2] ASI_DMMU 2: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP @@ -120,7 +126,7 @@ brnz,pt %o5, 2b sub %o5, %o4, %o5 flush %g6 -/*IC13*/stxa %g2, [%o2] ASI_DMMU +/*IC14*/stxa %g2, [%o2] ASI_DMMU flush %g6 retl wrpr %g1, 0x0, %pstate @@ -128,24 +134,26 @@ .align 32 .globl flush_icache_page flush_icache_page: /* %o0 = phys_page */ - sethi %hi(1 << 13), %o2 ! I-cache valid/set bit + sethi %hi(1 << 13), %o2 ! IC_set bit + mov 1, %g1 srlx %o0, 5, %o0 ! phys-addr comparitor - clr %o1 ! I-cache address + clr %o1 ! IC_addr + sllx %g1, 36, %g1 + sub %g1, 1, %g2 + andn %g2, 0xff, %g2 ! IC_tag mask + nop + 1: ldda [%o1] ASI_IC_TAG, %o4 - andcc %o5, %o2, %g0 - be,pn %xcc, 2f - andn %o5, %o2, %o5 + and %o5, %g2, %o5 cmp %o5, %o0 - be,pn %xcc, iflush1 -2: ldda [%o1 + %o2] ASI_IC_TAG, %o4 -4: andcc %o5, %o2, %g0 - be,pn %xcc, 3f - andn %o5, %o2, %o5 + nop +2: ldda [%o1 + %o2] ASI_IC_TAG, %o4 + and %o5, %g2, %o5 cmp %o5, %o0 + be,pn %xcc, iflush2 nop - 3: add %o1, 0x20, %o1 cmp %o1, %o2 bne,pt %xcc, 1b @@ -153,11 +161,11 @@ retl nop iflush1:stxa %g0, [%o1] ASI_IC_TAG - membar #Sync - ba,a,pt %xcc, 4b + ba,pt %xcc, 2b + flush %g6 iflush2:stxa %g0, [%o1 + %o2] ASI_IC_TAG - membar #Sync - ba,a,pt %xcc, 3b + ba,pt %xcc, 3b + flush %g6 #ifdef __SMP__ /* These are all called by the slaves of a cross call, at diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/Makefile linux/arch/sparc64/solaris/Makefile --- v2.1.128/linux/arch/sparc64/solaris/Makefile Sun Nov 8 14:02:50 1998 +++ linux/arch/sparc64/solaris/Makefile Mon Nov 16 10:37:28 1998 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := solaris.o -O_OBJS := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o timod.o +O_OBJS := entry64.o fs.o misc.o signal.o systbl.o socket.o ioctl.o ipc.o socksys.o timod.o ifeq ($(CONFIG_SOLARIS_EMUL),m) M_OBJS := $(O_TARGET) CPPFLAGS = $(MODFLAGS) diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c --- v2.1.128/linux/arch/sparc64/solaris/fs.c Thu Aug 6 14:06:31 1998 +++ linux/arch/sparc64/solaris/fs.c Mon Nov 16 10:37:28 1998 @@ -1,7 +1,7 @@ -/* $Id: fs.c,v 1.10 1998/05/09 06:15:45 davem Exp $ +/* $Id: fs.c,v 1.11 1998/10/28 08:12:04 jj Exp $ * fs.c: fs related syscall emulation for Solaris * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -55,6 +55,26 @@ s32 st_pad4[8]; /* expansion area */ }; +struct sol_stat64 { + u32 st_dev; + s32 st_pad1[3]; /* network id */ + u64 st_ino; + u32 st_mode; + u32 st_nlink; + u32 st_uid; + u32 st_gid; + u32 st_rdev; + s32 st_pad2[2]; + s64 st_size; + timestruct_t st_atime; + timestruct_t st_mtime; + timestruct_t st_ctime; + s64 st_blksize; + s32 st_blocks; + char st_fstype[16]; + s32 st_pad4[4]; /* expansion area */ +}; + #define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8)) static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf) @@ -80,6 +100,29 @@ return 0; } +static inline int putstat64(struct sol_stat64 *ubuf, struct stat *kbuf) +{ + if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev) || + __put_user (kbuf->st_ino, &ubuf->st_ino) || + __put_user (kbuf->st_mode, &ubuf->st_mode) || + __put_user (kbuf->st_nlink, &ubuf->st_nlink) || + __put_user (kbuf->st_uid, &ubuf->st_uid) || + __put_user (kbuf->st_gid, &ubuf->st_gid) || + __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev) || + __put_user (kbuf->st_size, &ubuf->st_size) || + __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec) || + __put_user (0, &ubuf->st_atime.tv_nsec) || + __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec) || + __put_user (0, &ubuf->st_mtime.tv_nsec) || + __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec) || + __put_user (0, &ubuf->st_ctime.tv_nsec) || + __put_user (kbuf->st_blksize, &ubuf->st_blksize) || + __put_user (kbuf->st_blocks, &ubuf->st_blocks) || + __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype)) + return -EFAULT; + return 0; +} + asmlinkage int solaris_stat(u32 filename, u32 statbuf) { int ret; @@ -108,6 +151,28 @@ return solaris_stat(filename, statbuf); } +asmlinkage int solaris_stat64(u32 filename, u32 statbuf) +{ + int ret; + struct stat s; + char *filenam; + mm_segment_t old_fs = get_fs(); + int (*sys_newstat)(char *,struct stat *) = + (int (*)(char *,struct stat *))SYS(stat); + + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { + set_fs (KERNEL_DS); + ret = sys_newstat(filenam, &s); + set_fs (old_fs); + putname32 (filenam); + if (putstat64 ((struct sol_stat64 *)A(statbuf), &s)) + return -EFAULT; + } + return ret; +} + asmlinkage int solaris_lstat(u32 filename, u32 statbuf) { int ret; @@ -135,6 +200,28 @@ return solaris_lstat(filename, statbuf); } +asmlinkage int solaris_lstat64(u32 filename, u32 statbuf) +{ + int ret; + struct stat s; + char *filenam; + mm_segment_t old_fs = get_fs(); + int (*sys_newlstat)(char *,struct stat *) = + (int (*)(char *,struct stat *))SYS(lstat); + + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { + set_fs (KERNEL_DS); + ret = sys_newlstat(filenam, &s); + set_fs (old_fs); + putname32 (filenam); + if (putstat64 ((struct sol_stat64 *)A(statbuf), &s)) + return -EFAULT; + } + return ret; +} + asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf) { int ret; @@ -156,6 +243,22 @@ return solaris_fstat(fd, statbuf); } +asmlinkage int solaris_fstat64(unsigned int fd, u32 statbuf) +{ + int ret; + struct stat s; + mm_segment_t old_fs = get_fs(); + int (*sys_newfstat)(unsigned,struct stat *) = + (int (*)(unsigned,struct stat *))SYS(fstat); + + set_fs (KERNEL_DS); + ret = sys_newfstat(fd, &s); + set_fs (old_fs); + if (putstat64 ((struct sol_stat64 *)A(statbuf), &s)) + return -EFAULT; + return ret; +} + asmlinkage int solaris_mknod(u32 path, u32 mode, s32 dev) { int (*sys_mknod)(const char *,int,dev_t) = @@ -172,6 +275,14 @@ return solaris_mknod(path, mode, dev); } +asmlinkage int solaris_getdents64(unsigned int fd, void *dirent, unsigned int count) +{ + int (*sys_getdents)(unsigned int, void *, unsigned int) = + (int (*)(unsigned int, void *, unsigned int))SYS(getdents); + + return sys_getdents(fd, dirent, count); +} + /* This statfs thingie probably will go in the near future, but... */ struct sol_statfs { @@ -276,6 +387,23 @@ u32 f_filler[16]; }; +struct sol_statvfs64 { + u32 f_bsize; + u32 f_frsize; + u64 f_blocks; + u64 f_bfree; + u64 f_bavail; + u64 f_files; + u64 f_ffree; + u64 f_favail; + u32 f_fsid; + char f_basetype[16]; + u32 f_flag; + u32 f_namemax; + char f_fstr[32]; + u32 f_filler[16]; +}; + static int report_statvfs(struct inode *inode, u32 buf) { struct statfs s; @@ -313,6 +441,43 @@ return error; } +static int report_statvfs64(struct inode *inode, u32 buf) +{ + struct statfs s; + mm_segment_t old_fs = get_fs(); + int error; + struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf); + + set_fs (KERNEL_DS); + error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs)); + set_fs (old_fs); + if (!error) { + const char *p = inode->i_sb->s_type->name; + int i = 0; + int j = strlen (p); + + if (j > 15) j = 15; + if (IS_RDONLY(inode)) i = 1; + if (IS_NOSUID(inode)) i |= 2; + if (put_user (s.f_bsize, &ss->f_bsize) || + __put_user (0, &ss->f_frsize) || + __put_user (s.f_blocks, &ss->f_blocks) || + __put_user (s.f_bfree, &ss->f_bfree) || + __put_user (s.f_bavail, &ss->f_bavail) || + __put_user (s.f_files, &ss->f_files) || + __put_user (s.f_ffree, &ss->f_ffree) || + __put_user (s.f_ffree, &ss->f_favail) || + __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) || + __copy_to_user (ss->f_basetype,p,j) || + __put_user (0, (char *)&ss->f_basetype[j]) || + __put_user (s.f_namelen, &ss->f_namemax) || + __put_user (i, &ss->f_flag) || + __clear_user (&ss->f_fstr, 32)) + return -EFAULT; + } + return error; +} + asmlinkage int solaris_statvfs(u32 path, u32 buf) { struct dentry * dentry; @@ -362,12 +527,62 @@ return error; } +asmlinkage int solaris_statvfs64(u32 path, u32 buf) +{ + struct dentry * dentry; + int error; + + lock_kernel(); + dentry = namei((const char *)A(path)); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + struct inode * inode = dentry->d_inode; + + error = -ENOSYS; + if (inode->i_sb->s_op->statfs) + error = report_statvfs64(inode, buf); + dput(dentry); + } + unlock_kernel(); + return error; +} + +asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf) +{ + struct inode * inode; + struct dentry * dentry; + struct file * file; + int error; + + lock_kernel(); + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + if (!(dentry = file->f_dentry)) + error = -ENOENT; + else if (!(inode = dentry->d_inode)) + error = -ENOENT; + else if (!inode->i_sb) + error = -ENODEV; + else if (!inode->i_sb->s_op->statfs) + error = -ENOSYS; + else + error = report_statvfs64(inode, buf); + fput(file); +out: + unlock_kernel(); + return error; +} + asmlinkage int solaris_open(u32 filename, int flags, u32 mode) { int (*sys_open)(const char *,int,int) = (int (*)(const char *,int,int))SYS(open); int fl = flags & 0xf; - + +/* if (flags & 0x2000) - allow LFS */ if (flags & 0x8050) fl |= O_SYNC; if (flags & 0x80) fl |= O_NONBLOCK; if (flags & 0x100) fl |= O_CREAT; @@ -558,78 +773,20 @@ return -ENOSYS; } -asmlinkage int solaris_pread(int fd, u32 buf, u32 nbyte, s32 offset) +asmlinkage int solaris_pread(unsigned int fd, char *buf, u32 count, u32 pos) { - off_t temp; - int retval; - struct file * file; - long (*sys_read)(unsigned int, char *, unsigned long) = - (long (*)(unsigned int, char *, unsigned long))SYS(read); - long (*sys_lseek)(unsigned int, off_t, unsigned int) = - (long (*)(unsigned int, off_t, unsigned int))SYS(lseek); - - lock_kernel(); - retval = -EBADF; - file = fget(fd); - if (!file) - goto bad; - - temp = file->f_pos; - if (temp != offset) { - retval = sys_lseek(fd, offset, 0); - if (retval < 0) - goto out_putf; - } - retval = sys_read(fd, (char *)A(buf), nbyte); - if (file->f_pos != temp) { - if (!retval) - retval = sys_lseek(fd, temp, 0); - else - sys_lseek(fd, temp, 0); - } - -out_putf: - fput(file); -bad: - unlock_kernel(); - return retval; + ssize_t (*sys_pread)(unsigned int, char *, size_t, loff_t) = + (ssize_t (*)(unsigned int, char *, size_t, loff_t))SYS(pread); + + return sys_pread(fd, buf, count, (loff_t)pos); } -asmlinkage int solaris_pwrite(int fd, u32 buf, u32 nbyte, s32 offset) +asmlinkage int solaris_pwrite(unsigned int fd, char *buf, u32 count, u32 pos) { - off_t temp; - int retval; - struct file * file; - long (*sys_write)(unsigned int, char *, unsigned long) = - (long (*)(unsigned int, char *, unsigned long))SYS(read); - long (*sys_lseek)(unsigned int, off_t, unsigned int) = - (long (*)(unsigned int, off_t, unsigned int))SYS(lseek); - - lock_kernel(); - retval = -EBADF; - file = fget(fd); - if (!file) - goto bad; - - temp = file->f_pos; - if (temp != offset) { - retval = sys_lseek(fd, offset, 0); - if (retval < 0) - goto out_putf; - } - retval = sys_write(fd, (char *)A(buf), nbyte); - if (file->f_pos != temp) { - if (!retval) - retval = sys_lseek(fd, temp, 0); - else - sys_lseek(fd, temp, 0); - } - -out_putf: - fput(file); -bad: - unlock_kernel(); - return retval; + ssize_t (*sys_pwrite)(unsigned int, char *, size_t, loff_t) = + (ssize_t (*)(unsigned int, char *, size_t, loff_t))SYS(pwrite); + + return sys_pwrite(fd, buf, count, (loff_t)pos); } /* POSIX.1 names */ diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c --- v2.1.128/linux/arch/sparc64/solaris/misc.c Thu Aug 6 14:06:31 1998 +++ linux/arch/sparc64/solaris/misc.c Mon Nov 16 10:37:28 1998 @@ -1,7 +1,7 @@ -/* $Id: misc.c,v 1.12 1998/06/16 04:37:08 davem Exp $ +/* $Id: misc.c,v 1.13 1998/10/28 08:11:58 jj Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include #include @@ -43,16 +46,86 @@ /* 120 */ 22, 22, 88, 86, 85, 22, 22, }; +#define SOLARIS_NR_OPEN 256 + +static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 off) +{ + struct file *file = NULL; + unsigned long retval, ret_type; + + lock_kernel(); + current->personality |= PER_SVR4; + if (flags & MAP_NORESERVE) { + static int cnt = 0; + + if (cnt < 5) { + printk("%s: unimplemented Solaris MAP_NORESERVE mmap() flag\n", + current->comm); + cnt++; + } + flags &= ~MAP_NORESERVE; + } + retval = -EBADF; + if(!(flags & MAP_ANONYMOUS)) { + if(fd >= SOLARIS_NR_OPEN) + goto out; + file = fget(fd); + if (!file) + goto out; + if (file->f_dentry && file->f_dentry->d_inode) { + struct inode * inode = file->f_dentry->d_inode; + if(MAJOR(inode->i_rdev) == MEM_MAJOR && + MINOR(inode->i_rdev) == 5) { + flags |= MAP_ANONYMOUS; + fput(file); + file = NULL; + } + } + } + + retval = -ENOMEM; + if(!(flags & MAP_FIXED) && !addr) { + unsigned long attempt = get_unmapped_area(addr, len); + if(!attempt || (attempt >= 0xf0000000UL)) + goto out_putf; + addr = (u32) attempt; + } + if(!(flags & MAP_FIXED)) + addr = 0; + ret_type = flags & _MAP_NEW; + flags &= ~_MAP_NEW; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + retval = do_mmap(file, + (unsigned long) addr, (unsigned long) len, + (unsigned long) prot, (unsigned long) flags, off); + if(!ret_type) + retval = ((retval < 0xf0000000) ? 0 : retval); +out_putf: + if (file) + fput(file); +out: + unlock_kernel(); + return (u32) retval; +} + asmlinkage u32 solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off) { - u32 (*sunos_mmap)(u32,u32,u32,u32,u32,u32) = - (u32 (*)(u32,u32,u32,u32,u32,u32))SUNOS(71); - u32 ret; + return do_solaris_mmap(addr, len, prot, flags, fd, (u64) off); +} + +asmlinkage u32 solaris_mmap64(struct pt_regs *regs, u32 len, u32 prot, u32 flags, u32 fd, u32 offhi) +{ + u32 offlo; - ret = sunos_mmap(addr,len,prot,flags,fd,off); - /* sunos_mmap sets personality to PER_BSD */ - current->personality = PER_SVR4; - return ret; + if (regs->u_regs[UREG_G1]) { + if (get_user (offlo, (u32 *)(long)((u32)regs->u_regs[UREG_I6] + 0x5c))) + return -EFAULT; + } else { + if (get_user (offlo, (u32 *)(long)((u32)regs->u_regs[UREG_I6] + 0x60))) + return -EFAULT; + } + return do_solaris_mmap((u32)regs->u_regs[UREG_I0], len, prot, flags, fd, (((u64)offhi)<<32)|offlo); } asmlinkage int solaris_brk(u32 brk) @@ -326,6 +399,18 @@ } } +asmlinkage int solaris_setreuid(s32 ruid, s32 euid) +{ + int (*sys_setreuid)(uid_t, uid_t) = (int (*)(uid_t, uid_t))SYS(setreuid); + return sys_setreuid(ruid, euid); +} + +asmlinkage int solaris_setregid(s32 rgid, s32 egid) +{ + int (*sys_setregid)(gid_t, gid_t) = (int (*)(gid_t, gid_t))SYS(setregid); + return sys_setregid(rgid, egid); +} + asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid) { int ret; @@ -376,6 +461,257 @@ (int (*)(struct timeval *, struct timezone *))SYS(gettimeofday); return sys_gettimeofday((struct timeval *)(u64)tim, NULL); +} + +#define RLIM_SOL_INFINITY32 0x7fffffff +#define RLIM_SOL_SAVED_MAX32 0x7ffffffe +#define RLIM_SOL_SAVED_CUR32 0x7ffffffd +#define RLIM_SOL_INFINITY ((u64)-3) +#define RLIM_SOL_SAVED_MAX ((u64)-2) +#define RLIM_SOL_SAVED_CUR ((u64)-1) +#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) +#define RLIMIT_SOL_NOFILE 5 +#define RLIMIT_SOL_VMEM 6 + +struct rlimit32 { + s32 rlim_cur; + s32 rlim_max; +}; + +asmlinkage int solaris_getrlimit(unsigned int resource, struct rlimit32 *rlim) +{ + struct rlimit r; + int ret; + mm_segment_t old_fs = get_fs (); + int (*sys_getrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(getrlimit); + + if (resource > RLIMIT_SOL_VMEM) + return -EINVAL; + switch (resource) { + case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break; + case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break; + default: break; + } + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &r); + set_fs (old_fs); + if (!ret) { + if (r.rlim_cur == RLIM_INFINITY) + r.rlim_cur = RLIM_SOL_INFINITY32; + else if ((u64)r.rlim_cur > RLIM_SOL_INFINITY32) + r.rlim_cur = RLIM_SOL_SAVED_CUR32; + if (r.rlim_max == RLIM_INFINITY) + r.rlim_max = RLIM_SOL_INFINITY32; + else if ((u64)r.rlim_max > RLIM_SOL_INFINITY32) + r.rlim_max = RLIM_SOL_SAVED_MAX32; + ret = put_user (r.rlim_cur, &rlim->rlim_cur); + ret |= __put_user (r.rlim_max, &rlim->rlim_max); + } + return ret; +} + +asmlinkage int solaris_setrlimit(unsigned int resource, struct rlimit32 *rlim) +{ + struct rlimit r, rold; + int ret; + mm_segment_t old_fs = get_fs (); + int (*sys_getrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(getrlimit); + int (*sys_setrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(setrlimit); + + if (resource > RLIMIT_SOL_VMEM) + return -EINVAL; + switch (resource) { + case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break; + case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break; + default: break; + } + if (get_user (r.rlim_cur, &rlim->rlim_cur) || + __get_user (r.rlim_max, &rlim->rlim_max)) + return -EFAULT; + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &rold); + if (!ret) { + if (r.rlim_cur == RLIM_SOL_INFINITY32) + r.rlim_cur = RLIM_INFINITY; + else if (r.rlim_cur == RLIM_SOL_SAVED_CUR32) + r.rlim_cur = rold.rlim_cur; + else if (r.rlim_cur == RLIM_SOL_SAVED_MAX32) + r.rlim_cur = rold.rlim_max; + if (r.rlim_max == RLIM_SOL_INFINITY32) + r.rlim_max = RLIM_INFINITY; + else if (r.rlim_max == RLIM_SOL_SAVED_CUR32) + r.rlim_max = rold.rlim_cur; + else if (r.rlim_max == RLIM_SOL_SAVED_MAX32) + r.rlim_max = rold.rlim_max; + ret = sys_setrlimit(resource, &r); + } + set_fs (old_fs); + return ret; +} + +asmlinkage int solaris_getrlimit64(unsigned int resource, struct rlimit *rlim) +{ + struct rlimit r; + int ret; + mm_segment_t old_fs = get_fs (); + int (*sys_getrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(getrlimit); + + if (resource > RLIMIT_SOL_VMEM) + return -EINVAL; + switch (resource) { + case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break; + case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break; + default: break; + } + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &r); + set_fs (old_fs); + if (!ret) { + if (r.rlim_cur == RLIM_INFINITY) + r.rlim_cur = RLIM_SOL_INFINITY; + if (r.rlim_max == RLIM_INFINITY) + r.rlim_max = RLIM_SOL_INFINITY; + ret = put_user (r.rlim_cur, &rlim->rlim_cur); + ret |= __put_user (r.rlim_max, &rlim->rlim_max); + } + return ret; +} + +asmlinkage int solaris_setrlimit64(unsigned int resource, struct rlimit *rlim) +{ + struct rlimit r, rold; + int ret; + mm_segment_t old_fs = get_fs (); + int (*sys_getrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(getrlimit); + int (*sys_setrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(setrlimit); + + if (resource > RLIMIT_SOL_VMEM) + return -EINVAL; + switch (resource) { + case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break; + case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break; + default: break; + } + if (get_user (r.rlim_cur, &rlim->rlim_cur) || + __get_user (r.rlim_max, &rlim->rlim_max)) + return -EFAULT; + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &rold); + if (!ret) { + if (r.rlim_cur == RLIM_SOL_INFINITY) + r.rlim_cur = RLIM_INFINITY; + else if (r.rlim_cur == RLIM_SOL_SAVED_CUR) + r.rlim_cur = rold.rlim_cur; + else if (r.rlim_cur == RLIM_SOL_SAVED_MAX) + r.rlim_cur = rold.rlim_max; + if (r.rlim_max == RLIM_SOL_INFINITY) + r.rlim_max = RLIM_INFINITY; + else if (r.rlim_max == RLIM_SOL_SAVED_CUR) + r.rlim_max = rold.rlim_cur; + else if (r.rlim_max == RLIM_SOL_SAVED_MAX) + r.rlim_max = rold.rlim_max; + ret = sys_setrlimit(resource, &r); + } + set_fs (old_fs); + return ret; +} + +struct timeval32 { + int tv_sec, tv_usec; +}; + +struct sol_ntptimeval { + struct timeval32 time; + s32 maxerror; + s32 esterror; +}; + +struct sol_timex { + u32 modes; + s32 offset; + s32 freq; + s32 maxerror; + s32 esterror; + s32 status; + s32 constant; + s32 precision; + s32 tolerance; + s32 ppsfreq; + s32 jitter; + s32 shift; + s32 stabil; + s32 jitcnt; + s32 calcnt; + s32 errcnt; + s32 stbcnt; +}; + +asmlinkage int solaris_ntp_gettime(struct sol_ntptimeval *ntp) +{ + int (*sys_adjtimex)(struct timex *) = + (int (*)(struct timex *))SYS(adjtimex); + struct timex t; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + t.modes = 0; + ret = sys_adjtimex(&t); + set_fs(old_fs); + if (ret < 0) + return ret; + ret = put_user (t.time.tv_sec, &ntp->time.tv_sec); + ret |= __put_user (t.time.tv_usec, &ntp->time.tv_usec); + ret |= __put_user (t.maxerror, &ntp->maxerror); + ret |= __put_user (t.esterror, &ntp->esterror); + return ret; +} + +asmlinkage int solaris_ntp_adjtime(struct sol_timex *txp) +{ + int (*sys_adjtimex)(struct timex *) = + (int (*)(struct timex *))SYS(adjtimex); + struct timex t; + int ret, err; + mm_segment_t old_fs = get_fs(); + + ret = get_user (t.modes, &txp->modes); + ret |= __get_user (t.offset, &txp->offset); + ret |= __get_user (t.freq, &txp->freq); + ret |= __get_user (t.maxerror, &txp->maxerror); + ret |= __get_user (t.esterror, &txp->esterror); + ret |= __get_user (t.status, &txp->status); + ret |= __get_user (t.constant, &txp->constant); + set_fs(KERNEL_DS); + ret = sys_adjtimex(&t); + set_fs(old_fs); + if (ret < 0) + return ret; + err = put_user (t.offset, &txp->offset); + err |= __put_user (t.freq, &txp->freq); + err |= __put_user (t.maxerror, &txp->maxerror); + err |= __put_user (t.esterror, &txp->esterror); + err |= __put_user (t.status, &txp->status); + err |= __put_user (t.constant, &txp->constant); + err |= __put_user (t.precision, &txp->precision); + err |= __put_user (t.tolerance, &txp->tolerance); + err |= __put_user (t.ppsfreq, &txp->ppsfreq); + err |= __put_user (t.jitter, &txp->jitter); + err |= __put_user (t.shift, &txp->shift); + err |= __put_user (t.stabil, &txp->stabil); + err |= __put_user (t.jitcnt, &txp->jitcnt); + err |= __put_user (t.calcnt, &txp->calcnt); + err |= __put_user (t.errcnt, &txp->errcnt); + err |= __put_user (t.stbcnt, &txp->stbcnt); + if (err) + return -EFAULT; + return ret; } asmlinkage int do_sol_unimplemented(struct pt_regs *regs) diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/socket.c linux/arch/sparc64/solaris/socket.c --- v2.1.128/linux/arch/sparc64/solaris/socket.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/solaris/socket.c Mon Nov 16 10:37:28 1998 @@ -0,0 +1,463 @@ +/* $Id: socket.c,v 1.1 1998/10/28 08:12:11 jj Exp $ + * socket.c: Socket syscall emulation for Solaris 2.6+ + * + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "conv.h" + +#define SOCK_SOL_STREAM 2 +#define SOCK_SOL_DGRAM 1 +#define SOCK_SOL_RAW 4 +#define SOCK_SOL_RDM 5 +#define SOCK_SOL_SEQPACKET 6 + +static int socket_check(int family, int type) +{ + if (family != PF_UNIX && family != PF_INET) + return -ESOCKTNOSUPPORT; + switch (type) { + case SOCK_SOL_STREAM: type = SOCK_STREAM; break; + case SOCK_SOL_DGRAM: type = SOCK_DGRAM; break; + case SOCK_SOL_RAW: type = SOCK_RAW; break; + case SOCK_SOL_RDM: type = SOCK_RDM; break; + case SOCK_SOL_SEQPACKET: type = SOCK_SEQPACKET; break; + default: return -EINVAL; + } + return type; +} + +asmlinkage int solaris_socket(int family, int type, int protocol) +{ + int (*sys_socket)(int, int, int) = + (int (*)(int, int, int))SYS(socket); + + type = socket_check (family, type); + if (type < 0) return type; + return sys_socket(family, type, protocol); +} + +asmlinkage int solaris_socketpair(int family, int type, int protocol, int *usockvec) +{ + int (*sys_socketpair)(int, int, int, int *) = + (int (*)(int, int, int, int *))SYS(socketpair); + + type = socket_check (family, type); + if (type < 0) return type; + return sys_socketpair(family, type, protocol, usockvec); +} + +asmlinkage int solaris_bind(int fd, struct sockaddr *addr, int addrlen) +{ + int (*sys_bind)(int, struct sockaddr *, int) = + (int (*)(int, struct sockaddr *, int))SUNOS(104); + + return sys_bind(fd, addr, addrlen); +} + +asmlinkage int solaris_setsockopt(int fd, int level, int optname, u32 optval, int optlen) +{ + int (*sunos_setsockopt)(int, int, int, u32, int) = + (int (*)(int, int, int, u32, int))SUNOS(105); + + return sunos_setsockopt(fd, level, optname, optval, optlen); +} + +asmlinkage int solaris_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen) +{ + int (*sunos_getsockopt)(int, int, int, u32, u32) = + (int (*)(int, int, int, u32, u32))SUNOS(118); + + return sunos_getsockopt(fd, level, optname, optval, optlen); +} + +asmlinkage int solaris_connect(int fd, struct sockaddr *addr, int addrlen) +{ + int (*sys_connect)(int, struct sockaddr *, int) = + (int (*)(int, struct sockaddr *, int))SYS(connect); + + return sys_connect(fd, addr, addrlen); +} + +asmlinkage int solaris_accept(int fd, struct sockaddr *addr, int *addrlen) +{ + int (*sys_accept)(int, struct sockaddr *, int *) = + (int (*)(int, struct sockaddr *, int *))SYS(accept); + + return sys_accept(fd, addr, addrlen); +} + +asmlinkage int solaris_listen(int fd, int backlog) +{ + int (*sys_listen)(int, int) = + (int (*)(int, int))SUNOS(106); + + return sys_listen(fd, backlog); +} + +asmlinkage int solaris_shutdown(int fd, int how) +{ + int (*sys_shutdown)(int, int) = + (int (*)(int, int))SYS(shutdown); + + return sys_shutdown(fd, how); +} + +#define MSG_SOL_OOB 0x1 +#define MSG_SOL_PEEK 0x2 +#define MSG_SOL_DONTROUTE 0x4 +#define MSG_SOL_EOR 0x8 +#define MSG_SOL_CTRUNC 0x10 +#define MSG_SOL_TRUNC 0x20 +#define MSG_SOL_WAITALL 0x40 +#define MSG_SOL_DONTWAIT 0x80 + +static int solaris_to_linux_msgflags(int flags) +{ + int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE); + + if (flags & MSG_SOL_EOR) fl |= MSG_EOR; + if (flags & MSG_SOL_CTRUNC) fl |= MSG_CTRUNC; + if (flags & MSG_SOL_TRUNC) fl |= MSG_TRUNC; + if (flags & MSG_SOL_WAITALL) fl |= MSG_WAITALL; + if (flags & MSG_SOL_DONTWAIT) fl |= MSG_DONTWAIT; + return fl; +} + +static int linux_to_solaris_msgflags(int flags) +{ + int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE); + + if (flags & MSG_EOR) fl |= MSG_SOL_EOR; + if (flags & MSG_CTRUNC) fl |= MSG_SOL_CTRUNC; + if (flags & MSG_TRUNC) fl |= MSG_SOL_TRUNC; + if (flags & MSG_WAITALL) fl |= MSG_SOL_WAITALL; + if (flags & MSG_DONTWAIT) fl |= MSG_SOL_DONTWAIT; + return fl; +} + +asmlinkage int solaris_recvfrom(int s, char *buf, int len, int flags, u32 from, u32 fromlen) +{ + int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *) = + (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom); + + return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), (struct sockaddr *)A(from), (int *)A(fromlen)); +} + +asmlinkage int solaris_recv(int s, char *buf, int len, int flags) +{ + int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *) = + (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom); + + return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL); +} + +asmlinkage int solaris_sendto(int s, char *buf, int len, int flags, u32 to, u32 tolen) +{ + int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int *) = + (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(sendto); + + return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), (struct sockaddr *)A(to), (int *)A(tolen)); +} + +asmlinkage int solaris_send(int s, char *buf, int len, int flags) +{ + int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int *) = + (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(sendto); + + return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL); +} + +asmlinkage int solaris_getpeername(int fd, struct sockaddr *addr, int *addrlen) +{ + int (*sys_getpeername)(int, struct sockaddr *, int *) = + (int (*)(int, struct sockaddr *, int *))SYS(getpeername); + + return sys_getpeername(fd, addr, addrlen); +} + +asmlinkage int solaris_getsockname(int fd, struct sockaddr *addr, int *addrlen) +{ + int (*sys_getsockname)(int, struct sockaddr *, int *) = + (int (*)(int, struct sockaddr *, int *))SYS(getsockname); + + return sys_getsockname(fd, addr, addrlen); +} + +/* XXX This really belongs in some header file... -DaveM */ +#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - + 16 for IP, 16 for IPX, + 24 for IPv6, + about 80 for AX.25 */ + +/* XXX These as well... */ +extern __inline__ struct socket *socki_lookup(struct inode *inode) +{ + return &inode->u.socket_i; +} + +extern __inline__ struct socket *sockfd_lookup(int fd, int *err) +{ + struct file *file; + struct inode *inode; + + if (!(file = fget(fd))) { + *err = -EBADF; + return NULL; + } + + inode = file->f_dentry->d_inode; + if (!inode || !inode->i_sock || !socki_lookup(inode)) { + *err = -ENOTSOCK; + fput(file); + return NULL; + } + + return socki_lookup(inode); +} + +extern __inline__ void sockfd_put(struct socket *sock) +{ + fput(sock->file); +} + +struct sol_nmsghdr { + u32 msg_name; + int msg_namelen; + u32 msg_iov; + u32 msg_iovlen; + u32 msg_control; + u32 msg_controllen; + u32 msg_flags; +}; + +struct sol_cmsghdr { + u32 cmsg_len; + int cmsg_level; + int cmsg_type; + unsigned char cmsg_data[0]; +}; + +struct iovec32 { + u32 iov_base; + u32 iov_len; +}; + +static inline int iov_from_user32_to_kern(struct iovec *kiov, + struct iovec32 *uiov32, + int niov) +{ + int tot_len = 0; + + while(niov > 0) { + u32 len, buf; + + if(get_user(len, &uiov32->iov_len) || + get_user(buf, &uiov32->iov_base)) { + tot_len = -EFAULT; + break; + } + tot_len += len; + kiov->iov_base = (void *)A(buf); + kiov->iov_len = (__kernel_size_t) len; + uiov32++; + kiov++; + niov--; + } + return tot_len; +} + +static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg, + struct sol_nmsghdr *umsg) +{ + u32 tmp1, tmp2, tmp3; + int err; + + err = get_user(tmp1, &umsg->msg_name); + err |= __get_user(tmp2, &umsg->msg_iov); + err |= __get_user(tmp3, &umsg->msg_control); + if (err) + return -EFAULT; + + kmsg->msg_name = (void *)A(tmp1); + kmsg->msg_iov = (struct iovec *)A(tmp2); + kmsg->msg_control = (void *)A(tmp3); + + err = get_user(kmsg->msg_namelen, &umsg->msg_namelen); + err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); + err |= get_user(kmsg->msg_flags, &umsg->msg_flags); + + kmsg->msg_flags = solaris_to_linux_msgflags(kmsg->msg_flags); + + return err; +} + +/* I've named the args so it is easy to tell whose space the pointers are in. */ +static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov, + char *kern_address, int mode) +{ + int tot_len; + + if(kern_msg->msg_namelen) { + if(mode==VERIFY_READ) { + int err = move_addr_to_kernel(kern_msg->msg_name, + kern_msg->msg_namelen, + kern_address); + if(err < 0) + return err; + } + kern_msg->msg_name = kern_address; + } else + kern_msg->msg_name = NULL; + + if(kern_msg->msg_iovlen > UIO_FASTIOV) { + kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec), + GFP_KERNEL); + if(!kern_iov) + return -ENOMEM; + } + + tot_len = iov_from_user32_to_kern(kern_iov, + (struct iovec32 *)kern_msg->msg_iov, + kern_msg->msg_iovlen); + if(tot_len >= 0) + kern_msg->msg_iov = kern_iov; + else if(kern_msg->msg_iovlen > UIO_FASTIOV) + kfree(kern_iov); + + return tot_len; +} + +asmlinkage int solaris_sendmsg(int fd, struct sol_nmsghdr *user_msg, unsigned user_flags) +{ + struct socket *sock; + char address[MAX_SOCK_ADDR]; + struct iovec iov[UIO_FASTIOV]; + unsigned char ctl[sizeof(struct cmsghdr) + 20]; + unsigned char *ctl_buf = ctl; + struct msghdr kern_msg; + int err, total_len; + + if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) + return -EFAULT; + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; + err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ); + if (err < 0) + goto out; + total_len = err; + + if(kern_msg.msg_controllen) { + struct sol_cmsghdr *ucmsg = (struct sol_cmsghdr *)kern_msg.msg_control; + unsigned long *kcmsg; + __kernel_size_t32 cmlen; + + if(kern_msg.msg_controllen > sizeof(ctl) && + kern_msg.msg_controllen <= 256) { + err = -ENOBUFS; + ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL); + if(!ctl_buf) + goto out_freeiov; + } + __get_user(cmlen, &ucmsg->cmsg_len); + kcmsg = (unsigned long *) ctl_buf; + *kcmsg++ = (unsigned long)cmlen; + err = -EFAULT; + if(copy_from_user(kcmsg, &ucmsg->cmsg_level, + kern_msg.msg_controllen - sizeof(__kernel_size_t32))) + goto out_freectl; + kern_msg.msg_control = ctl_buf; + } + kern_msg.msg_flags = solaris_to_linux_msgflags(user_flags); + + lock_kernel(); + sock = sockfd_lookup(fd, &err); + if (sock != NULL) { + if (sock->file->f_flags & O_NONBLOCK) + kern_msg.msg_flags |= MSG_DONTWAIT; + err = sock_sendmsg(sock, &kern_msg, total_len); + sockfd_put(sock); + } + unlock_kernel(); + +out_freectl: + /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ + if(ctl_buf != ctl) + kfree(ctl_buf); +out_freeiov: + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); +out: + return err; +} + +asmlinkage int solaris_recvmsg(int fd, struct sol_nmsghdr *user_msg, unsigned int user_flags) +{ + struct iovec iovstack[UIO_FASTIOV]; + struct msghdr kern_msg; + char addr[MAX_SOCK_ADDR]; + struct socket *sock; + struct iovec *iov = iovstack; + struct sockaddr *uaddr; + int *uaddr_len; + unsigned long cmsg_ptr; + int err, total_len, len = 0; + + if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) + return -EFAULT; + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; + + uaddr = kern_msg.msg_name; + uaddr_len = &user_msg->msg_namelen; + err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); + if (err < 0) + goto out; + total_len = err; + + cmsg_ptr = (unsigned long) kern_msg.msg_control; + kern_msg.msg_flags = 0; + + lock_kernel(); + sock = sockfd_lookup(fd, &err); + if (sock != NULL) { + if (sock->file->f_flags & O_NONBLOCK) + user_flags |= MSG_DONTWAIT; + err = sock_recvmsg(sock, &kern_msg, total_len, user_flags); + if(err >= 0) + len = err; + sockfd_put(sock); + } + unlock_kernel(); + + if(uaddr != NULL && err >= 0) + err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); + if(err >= 0) { + err = __put_user(linux_to_solaris_msgflags(kern_msg.msg_flags), &user_msg->msg_flags); + if(!err) { + /* XXX Convert cmsg back into userspace 32-bit format... */ + err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr, + &user_msg->msg_controllen); + } + } + + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); +out: + if(err < 0) + return err; + return len; +} diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/systbl.S linux/arch/sparc64/solaris/systbl.S --- v2.1.128/linux/arch/sparc64/solaris/systbl.S Thu Apr 23 20:21:32 1998 +++ linux/arch/sparc64/solaris/systbl.S Mon Nov 16 10:37:28 1998 @@ -1,7 +1,7 @@ -/* $Id: systbl.S,v 1.6 1998/03/26 08:46:08 jj Exp $ +/* $Id: systbl.S,v 1.7 1998/10/28 08:11:49 jj Exp $ * systbl.S: System call entry point table for Solaris compatibility. * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) */ @@ -156,8 +156,8 @@ .word solaris_fxstat /* fxstat ddx 125 */ .word solaris_xmknod /* xmknod dsox 126 */ .word solaris_unimplemented /* syslocal d 127 */ - .word solaris_unimplemented /* setrlimit 128 */ - .word solaris_unimplemented /* getrlimit 129 */ + .word solaris_setrlimit /* setrlimit dp 128 */ + .word solaris_getrlimit /* getrlimit dp 129 */ .word CHAIN(chown) /* lchown sdd 130 */ .word solaris_unimplemented /* memcntl 131 */ .word solaris_getpmsg /* getpmsg dxxxx 132 */ @@ -230,8 +230,8 @@ .word CHAIN(nanosleep) /* nanosleep dd 199 */ .word solaris_facl /* facl dddp 200 */ .word solaris_unimplemented /* 201 */ - .word solaris_unimplemented /* 202 */ - .word solaris_unimplemented /* 203 */ + .word solaris_setreuid /* setreuid dd 202 */ + .word solaris_setregid /* setregid dd 203 */ .word solaris_unimplemented /* 204 */ .word solaris_unimplemented /* 205 */ .word solaris_unimplemented /* 206 */ @@ -241,43 +241,43 @@ .word solaris_unimplemented /* 210 */ .word solaris_unimplemented /* 211 */ .word solaris_unimplemented /* 212 */ - .word solaris_unimplemented /* 213 */ - .word solaris_unimplemented /* 214 */ - .word solaris_unimplemented /* 215 */ - .word solaris_unimplemented /* 216 */ - .word solaris_unimplemented /* 217 */ - .word solaris_unimplemented /* 218 */ - .word solaris_unimplemented /* 219 */ - .word solaris_unimplemented /* 220 */ - .word solaris_unimplemented /* 221 */ - .word solaris_unimplemented /* 222 */ - .word solaris_unimplemented /* 223 */ - .word solaris_unimplemented /* 224 */ - .word solaris_unimplemented /* 225 */ + .word solaris_getdents64 /* getdents64 dpd 213 */ + .word REGS(solaris_mmap64) /* mmap64 xxxxdX 214 */ + .word solaris_stat64 /* stat64 sP 215 */ + .word solaris_lstat64 /* lstat64 sP 216 */ + .word solaris_fstat64 /* fstat64 dP 217 */ + .word solaris_statvfs64 /* statvfs64 sP 218 */ + .word solaris_fstatvfs64 /* fstatvfs64 dP 219 */ + .word solaris_setrlimit64 /* setrlimit64 dP 220 */ + .word solaris_getrlimit64 /* getrlimit64 dP 221 */ + .word CHAIN(pread) /* pread64 dpdD 222 */ + .word CHAIN(pwrite) /* pwrite64 dpdD 223 */ + .word CHAIN(creat) /* creat64 so 224 */ + .word solaris_open /* open64 soo 225 */ .word solaris_unimplemented /* 226 */ .word solaris_unimplemented /* 227 */ .word solaris_unimplemented /* 228 */ .word solaris_unimplemented /* 229 */ - .word solaris_unimplemented /* 230 */ - .word solaris_unimplemented /* 231 */ - .word solaris_unimplemented /* 232 */ - .word solaris_unimplemented /* 233 */ - .word solaris_unimplemented /* 234 */ - .word solaris_unimplemented /* 235 */ - .word solaris_unimplemented /* 236 */ - .word solaris_unimplemented /* 237 */ - .word solaris_unimplemented /* 238 */ - .word solaris_unimplemented /* 239 */ - .word solaris_unimplemented /* 240 */ - .word solaris_unimplemented /* 241 */ - .word solaris_unimplemented /* 242 */ - .word solaris_unimplemented /* 243 */ - .word solaris_unimplemented /* 244 */ - .word solaris_unimplemented /* 245 */ - .word solaris_unimplemented /* 246 */ + .word solaris_socket /* socket ddd 230 */ + .word solaris_socketpair /* socketpair dddp 231 */ + .word solaris_bind /* bind dpd 232 */ + .word solaris_listen /* listen dd 233 */ + .word solaris_accept /* accept dpp 234 */ + .word solaris_connect /* connect dpd 235 */ + .word solaris_shutdown /* shutdown dd 236 */ + .word solaris_recv /* recv dpdd 237 */ + .word solaris_recvfrom /* recvfrom dpddpp 238 */ + .word solaris_recvmsg /* recvmsg dpd 239 */ + .word solaris_send /* send dpdd 240 */ + .word solaris_sendmsg /* sendmsg dpd 241 */ + .word solaris_sendto /* sendto dpddpd 242 */ + .word solaris_getpeername /* getpeername dpp 243 */ + .word solaris_getsockname /* getsockname dpp 244 */ + .word solaris_getsockopt /* getsockopt dddpp 245 */ + .word solaris_setsockopt /* setsockopt dddpp 246 */ .word solaris_unimplemented /* 247 */ - .word solaris_unimplemented /* 248 */ - .word solaris_unimplemented /* 249 */ + .word solaris_ntp_gettime /* ntp_gettime p 248 */ + .word solaris_ntp_adjtime /* ntp_adjtime p 249 */ .word solaris_unimplemented /* 250 */ .word solaris_unimplemented /* 251 */ .word solaris_unimplemented /* 252 */ diff -u --recursive --new-file v2.1.128/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.1.128/linux/drivers/block/Config.in Fri Oct 23 22:01:20 1998 +++ linux/drivers/block/Config.in Mon Nov 16 10:32:58 1998 @@ -48,7 +48,7 @@ fi fi if [ "$CONFIG_PPC" = "y" ]; then - bool ' WInbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 + bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 fi fi if [ "$CONFIG_PMAC" = "y" ]; then @@ -77,7 +77,7 @@ fi fi if [ "$CONFIG_MCA" = "y" ]; then - bool 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2 + tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2 fi if [ "$CONFIG_ZORRO" = "y" ]; then tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM @@ -94,7 +94,9 @@ comment 'Additional Block Devices' tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP -tristate 'Network block device support' CONFIG_BLK_DEV_NBD +if [ "$CONFIG_NET" = "y" ]; then + tristate 'Network block device support' CONFIG_BLK_DEV_NBD +fi bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then tristate ' Linear (append) mode' CONFIG_MD_LINEAR diff -u --recursive --new-file v2.1.128/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.1.128/linux/drivers/block/amiflop.c Wed Aug 26 11:37:34 1998 +++ linux/drivers/block/amiflop.c Sun Nov 15 11:23:08 1998 @@ -114,7 +114,7 @@ #define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) drive */ #define FD_DD_5 0xaaaaaaaa /* double-density 5.25" (440K) drive */ -static long int fd_def_df0 = 0; /* default for df0 if it doesn't identify */ +static long int fd_def_df0 = FD_DD_3; /* default for df0 if it doesn't identify */ MODULE_PARM(fd_def_df0,"l"); @@ -1858,20 +1858,6 @@ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; - - - #if 0 /* Doesn't seem to be correct */ - if (fd_def_df0==0) { - if ((amiga.model == AMI_3000) || (amiga.model == AMI_3000T) || - (amiga.model == AMI_3000PLUS) || (amiga.model == AMI_4000)) - fd_def_df0=FD_HD_3; - else - fd_def_df0=FD_DD_3; - } - #else - /* Now we hope that every HD drive will identify itself correctly */ - fd_def_df0 = FD_DD_3; - #endif for (i = 0; i < 128; i++) mfmdecode[i]=255; diff -u --recursive --new-file v2.1.128/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.1.128/linux/drivers/block/genhd.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/block/genhd.c Mon Nov 16 10:32:58 1998 @@ -61,6 +61,10 @@ extern int scsi_dev_init(void); extern int net_dev_init(void); +#ifdef CONFIG_PPC +extern void note_bootable_part(kdev_t dev, int part); +#endif + /* * disk_name() is used by genhd.c and md.c. * It formats the devicename of the indicated disk @@ -862,7 +866,7 @@ int blk, blocks_in_map; int dev_bsize, dev_pos, pos; unsigned secsize; -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC int first_bootable = 1; #endif struct mac_partition *part; @@ -916,18 +920,18 @@ fsec + be32_to_cpu(part->start_block) * (secsize/512), be32_to_cpu(part->block_count) * (secsize/512)); -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC /* * If this is the first bootable partition, tell the * setup code, in case it wants to make this the root. */ - if (first_bootable + if ( (_machine == _MACH_Pmac) && first_bootable && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE) && strcasecmp(part->processor, "powerpc") == 0) { note_bootable_part(dev, blk); first_bootable = 0; } -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ ++current_minor; } diff -u --recursive --new-file v2.1.128/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.1.128/linux/drivers/block/ide-pmac.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/block/ide-pmac.c Sun Nov 15 10:51:46 1998 @@ -25,10 +25,13 @@ #include #include #include +#include #include "ide.h" ide_ioreg_t pmac_ide_regbase[MAX_HWIFS]; int pmac_ide_irq[MAX_HWIFS]; +int pmac_ide_count; +struct device_node *pmac_ide_node[MAX_HWIFS]; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC #define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */ @@ -45,15 +48,18 @@ void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) { - int i; + int i, r; *p = 0; if (base == 0) return; - if (base == mb_cd_base && !check_media_bay(MB_CD)) { - mb_cd_index = -1; + /* we check only for -EINVAL meaning that we have found a matching + bay but with the wrong device type */ + + r = check_media_bay_by_base(base, MB_CD); + if (r == -EINVAL) return; - } + for (i = 0; i < 8; ++i) *p++ = base + i * 0x10; *p = base + 0x160; @@ -93,8 +99,8 @@ /* Move removable devices such as the media-bay CDROM on the PB3400 to the end of the list. */ for (; p != NULL; p = p->next) { - if (p->parent && p->parent->name - && strcasecmp(p->parent->name, "media-bay") == 0) { + if (p->parent && p->parent->type + && strcasecmp(p->parent->type, "media-bay") == 0) { *rp = p; rp = &p->next; } else { @@ -111,7 +117,13 @@ np->full_name); continue; } + base = (unsigned long) ioremap(np->addrs[0].address, 0x200); + + /* XXX This is bogus. Should be fixed in the registry by checking + the kind of host interrupt controller, a bit like gatwick + fixes in irq.c + */ if (np->n_intrs == 0) { printk("ide: no intrs for device %s, using 13\n", np->full_name); @@ -121,13 +133,13 @@ } pmac_ide_regbase[i] = base; pmac_ide_irq[i] = irq; + pmac_ide_node[i] = np; if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { - mb_cd_index = i; - mb_cd_base = base; - mb_cd_irq = irq; - } + media_bay_set_ide_infos(np->parent,base,irq,i); + } else + feature_set(np, FEATURE_IDE_enable); hwif = &ide_hwifs[i]; pmac_ide_init_hwif_ports(hwif->io_ports, base, &hwif->irq); @@ -143,6 +155,7 @@ ++i; } + pmac_ide_count = i; } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC diff -u --recursive --new-file v2.1.128/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.1.128/linux/drivers/block/ide-probe.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/block/ide-probe.c Fri Nov 13 09:55:31 1998 @@ -78,8 +78,18 @@ ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap); id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */ - drive->present = 1; printk("%s: %s, ", drive->name, id->model); + drive->present = 1; + + /* + * Prevent long system lockup probing later for non-existant + * slave drive if the hwif is actually a Kodak CompactFlash card. + */ + if (!strcmp(id->model, "KODAK ATA_FLASH")) { + ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit]; + mate->present = 0; + mate->noprobe = 1; + } /* * Check for an ATAPI device diff -u --recursive --new-file v2.1.128/linux/drivers/block/ns87415.c linux/drivers/block/ns87415.c --- v2.1.128/linux/drivers/block/ns87415.c Mon Oct 5 13:13:38 1998 +++ linux/drivers/block/ns87415.c Mon Nov 16 10:37:28 1998 @@ -31,7 +31,7 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { ide_hwif_t *hwif = HWIF(drive); - unsigned int bit, new, *old = (unsigned int *) hwif->select_data; + unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data; struct pci_dev *dev = hwif->pci_dev; unsigned long flags; @@ -39,24 +39,20 @@ __cli(); /* local CPU only */ new = *old; - /* adjust IRQ enable bit */ + /* Adjust IRQ enable bit */ bit = 1 << (8 + hwif->channel); new = drive->present ? (new & ~bit) : (new | bit); - /* select PIO or DMA */ - bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1)); - new = use_dma ? (new | bit) : (new & ~bit); + /* Select PIO or DMA, DMA may only be selected for one drive/channel. */ + bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1)); + other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1)); + new = use_dma ? ((new & ~other) | bit) : (new & ~bit); if (new != *old) { - if (use_dma) { - bit = (1 << (5 + drive->select.b.unit)); - outb((inb(hwif->dma_base+2) & 0x60) | bit, - hwif->dma_base+2); - } - *old = new; (void) pci_write_config_dword(dev, 0x40, new); } + __restore_flags(flags); /* local CPU only */ } @@ -94,6 +90,10 @@ struct pci_dev *dev = hwif->pci_dev; unsigned int ctrl, using_inta; byte progif; +#ifdef __sparc_v9__ + int timeout; + byte stat; +#endif /* * We cannot probe for IRQ: both ports share common IRQ on INTA. @@ -126,22 +126,6 @@ pci_write_config_byte(dev, 0x55, 0xee); #ifdef __sparc_v9__ -{ - int timeout; - byte stat; - /* - * Put reasonable values in the timing registers - * for DMA2 mode performance. - */ - pci_write_config_byte(dev, 0x44, 0xfe); - pci_write_config_byte(dev, 0x45, 0xfe); - pci_write_config_byte(dev, 0x48, 0xfe); - pci_write_config_byte(dev, 0x49, 0xfe); - pci_write_config_byte(dev, 0x4c, 0xfe); - pci_write_config_byte(dev, 0x4d, 0xfe); - pci_write_config_byte(dev, 0x50, 0xfe); - pci_write_config_byte(dev, 0x51, 0xfe); - /* * XXX: Reset the device, if we don't it will not respond * to SELECT_DRIVE() properly during first probe_hwif(). @@ -156,9 +140,11 @@ if (stat == 0xff) break; } while ((stat & BUSY_STAT) && --timeout); -} #endif } + + outb(0x60, hwif->dma_base + 2); + if (!using_inta) hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ else if (!hwif->irq && hwif->mate && hwif->mate->irq) diff -u --recursive --new-file v2.1.128/linux/drivers/block/sl82c105.c linux/drivers/block/sl82c105.c --- v2.1.128/linux/drivers/block/sl82c105.c Thu Aug 6 14:06:31 1998 +++ linux/drivers/block/sl82c105.c Sun Nov 15 10:51:46 1998 @@ -14,11 +14,6 @@ #include "ide.h" #include "ide_modes.h" -unsigned int chrp_ide_irq = 0; -int chrp_ide_ports_known = 0; -ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; -ide_ioreg_t chrp_idedma_regbase; - void ide_init_sl82c105(ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; @@ -36,38 +31,4 @@ pci_read_config_dword(dev, 0x40, &t32); printk("IDE control/status register: %08x\n",t32); pci_write_config_dword(dev, 0x40, 0x10ff08a1); -} - -/* nobody ever calls these.. ?? -mlord - * - * Yes somebody certainly does, check asm-ppc/ide.h for the place. -DaveM - */ -void chrp_ide_probe(void) { - - struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL); - - chrp_ide_ports_known = 1; - - if(pdev) { - chrp_ide_regbase[0]=pdev->base_address[0] & - PCI_BASE_ADDRESS_IO_MASK; - chrp_ide_regbase[1]=pdev->base_address[2] & - PCI_BASE_ADDRESS_IO_MASK; - chrp_idedma_regbase=pdev->base_address[4] & - PCI_BASE_ADDRESS_IO_MASK; - chrp_ide_irq=pdev->irq; - } -} - - -void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) -{ - ide_ioreg_t port = base; - int i = 8; - - while (i--) - *p++ = port++; - *p++ = port; - if (irq != NULL) - *irq = chrp_ide_irq; } diff -u --recursive --new-file v2.1.128/linux/drivers/block/swim3.c linux/drivers/block/swim3.c --- v2.1.128/linux/drivers/block/swim3.c Sun Nov 8 14:02:51 1998 +++ linux/drivers/block/swim3.c Sun Nov 15 10:51:46 1998 @@ -22,12 +22,15 @@ #include #include #include +#include #define MAJOR_NR FLOPPY_MAJOR #include -static int floppy_blocksizes[2] = {512}; -static int floppy_sizes[2] = {2880}; +static int floppy_blocksizes[2] = {512,512}; +static int floppy_sizes[2] = {2880,2880}; + +#define MAX_FLOPPIES 2 enum swim_state { idle, @@ -139,11 +142,12 @@ int ejected; struct wait_queue *wait; int wanted; - int in_media_bay; + struct device_node* media_bay; /* NULL when not in bay */ char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)]; }; -static struct floppy_state floppy_states[1]; +static struct floppy_state floppy_states[MAX_FLOPPIES]; +static int floppy_count = 0; static unsigned short write_preamble[] = { 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, /* gap field */ @@ -175,7 +179,7 @@ static void seek_timeout(unsigned long data); static void xfer_timeout(unsigned long data); static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs); +/*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/ static int grab_drive(struct floppy_state *fs, enum swim_state state, int interruptible); static void release_drive(struct floppy_state *fs); @@ -190,6 +194,7 @@ size_t count, loff_t *ppos); static int floppy_check_change(kdev_t dev); static int floppy_revalidate(kdev_t dev); +static int swim3_add_device(struct device_node *swims); int swim3_init(void); #define IOCTL_MODE_BIT 8 @@ -212,11 +217,11 @@ volatile struct swim3 *sw = fs->swim3; swim3_select(fs, action); - udelay(1); + udelay(10); sw->select |= LSTRB; eieio(); - udelay(2); + udelay(20); sw->select &= ~LSTRB; eieio(); - udelay(1); + udelay(10); out_8(&sw->select, RELAX); } @@ -226,7 +231,7 @@ int stat; swim3_select(fs, bit); - udelay(1); + udelay(10); stat = in_8(&sw->status); out_8(&sw->select, RELAX); return (stat & DATA) == 0; @@ -234,13 +239,19 @@ static void do_fd_request(void) { - start_request(&floppy_states[0]); + int i; + for(i=0;istate == idle && fs->wanted) { @@ -261,11 +272,6 @@ CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors); #endif - drive = MINOR(CURRENT->rq_dev); - if (drive != 0) { - end_request(0); - continue; - } if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) { end_request(0); continue; @@ -438,7 +444,7 @@ case settling: /* wait for SEEK_COMPLETE to become true */ swim3_select(fs, SEEK_COMPLETE); - udelay(1); + udelay(10); out_8(&sw->intr_enable, ERROR | DATA_CHANGED); in_8(&sw->intr); /* clear DATA_CHANGED */ if (in_8(&sw->status) & DATA) { @@ -560,7 +566,7 @@ err = in_8(&sw->error); intr = in_8(&sw->intr); #if 0 - printk(KERN_DEBUG "swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err); + printk("swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err); #endif if ((intr & ERROR) && fs->state != do_transfer) printk(KERN_ERR "swim3_interrupt, state=%d, cmd=%x, intr=%x, err=%x\n", @@ -685,9 +691,11 @@ } } +/* static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) { } +*/ static int grab_drive(struct floppy_state *fs, enum swim_state state, int interruptible) @@ -755,12 +763,20 @@ { struct floppy_state *fs; int err; + int devnum = MINOR(inode->i_rdev); + if (devnum >= floppy_count) + return -ENODEV; + if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) || ((cmd & 0x80) && !suser())) return -EPERM; - fs = &floppy_states[0]; + fs = &floppy_states[devnum]; + + if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) + return -ENXIO; + switch (cmd) { case FDEJECT: if (fs->ref_count != 1) @@ -780,19 +796,21 @@ struct floppy_state *fs; volatile struct swim3 *sw; int n, err; + int devnum = MINOR(inode->i_rdev); - if (MINOR(inode->i_rdev) != 0) + if (devnum >= floppy_count) return -ENODEV; - fs = &floppy_states[0]; + + fs = &floppy_states[devnum]; sw = fs->swim3; err = 0; if (fs->ref_count == 0) { - if (fs->in_media_bay && !check_media_bay(MB_FD)) + if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; out_8(&sw->mode, 0x95); out_8(&sw->control_bic, 0xff); out_8(&sw->reg5, 0x28); - udelay(1); + udelay(10); out_8(&sw->intr_enable, 0); out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE); swim3_action(fs, MOTOR_ON); @@ -856,9 +874,11 @@ { struct floppy_state *fs; volatile struct swim3 *sw; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; - if (MINOR(inode->i_rdev) != 0) - return -ENXIO; /* * If filp is NULL, we're being called from blkdev_release * or after a failed mount attempt. In the former case the @@ -868,7 +888,7 @@ if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT))) block_fsync (filp, filp->f_dentry); - fs = &floppy_states[0]; + fs = &floppy_states[devnum]; sw = fs->swim3; if (fs->ref_count > 0 && --fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); @@ -880,10 +900,12 @@ static int floppy_check_change(kdev_t dev) { struct floppy_state *fs; + int devnum = MINOR(dev); - if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0) + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) return 0; - fs = &floppy_states[0]; + + fs = &floppy_states[devnum]; return fs->ejected; } @@ -892,10 +914,16 @@ struct floppy_state *fs; volatile struct swim3 *sw; int ret, n; + int devnum = MINOR(dev); - if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0) + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) return 0; - fs = &floppy_states[0]; + + fs = &floppy_states[devnum]; + + if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) + return -ENXIO; + sw = fs->swim3; grab_drive(fs, revalidating, 0); out_8(&sw->intr_enable, 0); @@ -929,10 +957,12 @@ { struct inode *inode = filp->f_dentry->d_inode; struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); - if (MINOR(inode->i_rdev) != 0) + if (devnum >= floppy_count) return -ENODEV; - fs = &floppy_states[0]; + + fs = &floppy_states[devnum]; if (fs->ejected) return -ENXIO; return block_read(filp, buf, count, ppos); @@ -943,10 +973,12 @@ { struct inode * inode = filp->f_dentry->d_inode; struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); - if (MINOR(inode->i_rdev) != 0) + if (devnum >= floppy_count) return -ENODEV; - fs = &floppy_states[0]; + + fs = &floppy_states[devnum]; if (fs->ejected) return -ENXIO; return block_write(filp, buf, count, ppos); @@ -975,50 +1007,72 @@ int swim3_init(void) { - struct device_node *swims; - struct floppy_state *fs = &floppy_states[0]; - int is_3400 = 0; - - if (find_devices("media-bay") != NULL) { - /* assume this is a PB3400 */ - swims = find_devices("floppy"); - is_3400 = 1; - } else { - swims = find_devices("swim3"); + struct device_node *swim; + + swim = find_devices("floppy"); + while (swim && (floppy_count < MAX_FLOPPIES)) + { + swim3_add_device(swim); + swim = swim->next; + } + + swim = find_devices("swim3"); + while (swim && (floppy_count < MAX_FLOPPIES)) + { + swim3_add_device(swim); + swim = swim->next; + } + + if (floppy_count > 0) + { + if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { + printk(KERN_ERR "Unable to get major %d for floppy\n", + MAJOR_NR); + return -EBUSY; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_size[MAJOR_NR] = floppy_sizes; } - if (swims == NULL) - return 0; + return 0; +} - if (swims->next != NULL) - printk(KERN_ERR "Warning: only using first SWIM3 floppy controller\n"); - if (swims->n_addrs != 2 || swims->n_intrs != 2) { - printk(KERN_ERR "swim3: expecting 2 addrs and 2 intrs! (%d, %d)\n", - swims->n_addrs, swims->n_intrs); +static int swim3_add_device(struct device_node *swim) +{ + struct device_node *mediabay; + struct floppy_state *fs = &floppy_states[floppy_count]; + + if (swim->n_addrs < 2) + { + printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n", + swim->n_addrs, swim->n_intrs); return -EINVAL; } - if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { - printk(KERN_ERR "Unable to get major %d for floppy\n", - MAJOR_NR); - return -EBUSY; + if (swim->n_intrs < 2) + { + printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n", + swim->n_addrs, swim->n_intrs); + return -EINVAL; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_size[MAJOR_NR] = floppy_sizes; + mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL; + if (mediabay == NULL) + feature_set(swim, FEATURE_SWIM3_enable); + memset(fs, 0, sizeof(*fs)); fs->state = idle; - fs->swim3 = (volatile struct swim3 *) swims->addrs[0].address; - fs->dma = (struct dbdma_regs *) swims->addrs[1].address; - fs->swim3_intr = swims->intrs[0].line; - fs->dma_intr = swims->intrs[1].line; + fs->swim3 = (volatile struct swim3 *) ioremap(swim->addrs[0].address, 0x200); + fs->dma = (struct dbdma_regs *) ioremap(swim->addrs[1].address, 0x200); + fs->swim3_intr = swim->intrs[0].line; + fs->dma_intr = swim->intrs[1].line; fs->cur_cyl = -1; fs->cur_sector = -1; fs->secpercyl = 36; fs->secpertrack = 18; fs->total_secs = 2880; - fs->in_media_bay = is_3400; + fs->media_bay = mediabay; fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space); memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd)); @@ -1026,19 +1080,26 @@ if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr); + feature_clear(swim, FEATURE_SWIM3_enable); return -EBUSY; } +/* if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA", fs->dma_intr); + feature_clear(swim, FEATURE_SWIM3_enable); return -EBUSY; } +*/ init_timer(&fs->timeout); do_floppy = NULL; - printk(KERN_INFO "fd0: SWIM3 floppy controller\n"); + printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count, + mediabay ? "in media bay" : ""); + floppy_count++; + return 0; } diff -u --recursive --new-file v2.1.128/linux/drivers/block/via82c586.c linux/drivers/block/via82c586.c --- v2.1.128/linux/drivers/block/via82c586.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/block/via82c586.c Fri Nov 13 10:29:44 1998 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/via82C586.c Version 0.01 Aug 16, 1998 + * linux/drivers/block/via82c586.c Version 0.01 Aug 16, 1998 * * Copyright (C) 1998 Michel Aubry * Copyright (C) 1998 Andre Hedrick diff -u --recursive --new-file v2.1.128/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.1.128/linux/drivers/cdrom/cdrom.c Sun Nov 8 14:02:52 1998 +++ linux/drivers/cdrom/cdrom.c Fri Nov 13 10:29:44 1998 @@ -174,7 +174,9 @@ struct cdrom_device_ops * cdo); static void sanitize_format(union cdrom_addr *addr, u_char * curr, u_char requested); +#ifdef CONFIG_SYSCTL static void cdrom_sysctl_register(void); +#endif /* CONFIG_SYSCTL */ static struct cdrom_device_info *topCdromPtr = NULL; struct file_operations cdrom_fops = diff -u --recursive --new-file v2.1.128/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.128/linux/drivers/char/Makefile Sun Nov 8 14:02:53 1998 +++ linux/drivers/char/Makefile Mon Nov 16 10:32:58 1998 @@ -224,11 +224,11 @@ endif endif -ifeq ($(CONFIG_MACMOUSE),y) -L_OBJS += macmouse.o +ifeq ($(CONFIG_ADBMOUSE),y) +L_OBJS += adbmouse.o else - ifeq ($(CONFIG_MACMOUSE),m) - M_OBJS += macmouse.o + ifeq ($(CONFIG_ADBMOUSE),m) + M_OBJS += adbmouse.o endif endif diff -u --recursive --new-file v2.1.128/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c --- v2.1.128/linux/drivers/char/adbmouse.c Wed Aug 26 11:37:36 1998 +++ linux/drivers/char/adbmouse.c Sun Nov 15 10:51:46 1998 @@ -3,6 +3,7 @@ * * 27 Oct 1997 Michael Schmitz * logitech fixes by anthony tong + * further hacking by Paul Mackerras * * Apple mouse protocol according to: * @@ -33,14 +34,21 @@ #include #include -#include +#include +#ifdef __powerpc__ #include +#endif +#ifdef __mc68000__ +#include +#endif static struct mouse_status mouse; -static int adb_mouse_x_threshold = 2, adb_mouse_y_threshold = 2; -static int adb_mouse_buttons = 0; +static unsigned char adb_mouse_buttons[16]; -extern void (*adb_mouse_interrupt_hook) (char *, int); +extern void (*adb_mouse_interrupt_hook)(unsigned char *, int); +extern int adb_emulate_buttons; +extern int adb_button2_keycode; +extern int adb_button3_keycode; extern int console_loglevel; @@ -48,11 +56,11 @@ * XXX: need to figure out what ADB mouse packets mean ... * This is the stuff stolen from the Atari driver ... */ -static void adb_mouse_interrupt(char *buf, int nb) +static void adb_mouse_interrupt(unsigned char *buf, int nb) { - static int buttons = 7; + int buttons, id; - /* +/* Handler 1 -- 100cpi original Apple mouse protocol. Handler 2 -- 200cpi original Apple mouse protocol. @@ -60,76 +68,62 @@ contain the following values: BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = ???? ???? (?) - data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device. - data[3] = bxxx xxxx First button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - - NOTE: data[0] is confirmed by the parent function and need not be - checked here. - */ + 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] = 0000 0000 ADB packet identifer. - data[1] = 0100 0000 Extended protocol register. - Bits 6-7 are the device id, which should be 1. - Bits 4-5 are resolution which is in "units/inch". - The Logitech MouseMan returns these bits clear but it has - 200/300cpi resolution. - Bits 0-3 are unique vendor id. - data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device. - Bits 2-3 should be 8 + 4. - Bits 4-7 should be 3 for a mouse device. - data[3] = bxxx xxxx Left button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - data[5] = byyy bxxx Third button and fourth button. - Y is additiona. high bits of y-axis motion. + 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 additional high bits of y-axis motion. X is additional high bits of x-axis motion. - NOTE: data[0] and data[2] are confirmed by the parent function and - need not be checked here. - */ - - /* - * '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 - */ + This procedure also gets called from the keyboard code if we + are emulating mouse buttons with keys. In this case data[0] == 0 + (data[0] cannot be 0 for a real ADB packet). + + 'buttons' here means 'button down' states! + Button 1 (left) : bit 2, busmouse button 3 + Button 2 (middle): bit 1, busmouse button 2 + Button 3 (right) : bit 0, busmouse button 1 +*/ /* x/y and buttons swapped */ - if (nb > 0) { /* real packet : use buttons? */ - if (console_loglevel >= 8) - printk("adb_mouse: real data; "); - /* button 1 (left, bit 2) : always significant ! */ - 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 ! (buf[3] = 0 else) */ - if ( nb == 6 ) - buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */ - } else { /* fake packet : use 2+3 */ - if (console_loglevel >= 8) - printk("adb_mouse: fake data; "); - /* we only see state changes here, but the fake driver takes care - * to preserve state... button 1 state must stay unchanged! */ - buttons = (buttons&4) | ((buf[2] & 0x80 ? 1 : 0) | - (buf[3] & 0x80 ? 2 : 0)); - } + if (console_loglevel >= 8) + printk("KERN_DEBUG adb_mouse: %s data; ", buf[0]? "real": "fake"); + + 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 */ + + add_mouse_randomness(((~buttons&7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f)); + + 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]; - add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f)); - mouse.buttons = buttons & 7; + mouse.buttons = buttons; mouse.dx += ((buf[2]&0x7f) < 64 ? (buf[2]&0x7f) : (buf[2]&0x7f)-128 ); mouse.dy -= ((buf[1]&0x7f) < 64 ? (buf[1]&0x7f) : (buf[1]&0x7f)-128 ); @@ -141,7 +135,6 @@ wake_up_interruptible(&mouse.wait); if (mouse.fasyncptr) kill_fasync(mouse.fasyncptr, SIGIO); - } static int fasync_mouse(int fd, struct file *filp, int on) @@ -167,13 +160,16 @@ static int open_mouse(struct inode *inode, struct file *file) { + int id; + if (mouse.active++) return 0; mouse.ready = 0; mouse.dx = mouse.dy = 0; - adb_mouse_buttons = 0; + for (id = 0; id < 16; ++id) + adb_mouse_buttons[id] = 7; /* all buttons up */ MOD_INC_USE_COUNT; adb_mouse_interrupt_hook = adb_mouse_interrupt; return 0; @@ -198,24 +194,24 @@ dy = mouse.dy; buttons = mouse.buttons; if (dx > 127) - dx = 127; + dx = 127; else if (dx < -128) - dx = -128; + dx = -128; if (dy > 127) - dy = 127; + dy = 127; else if (dy < -128) - dy = -128; + dy = -128; mouse.dx -= dx; mouse.dy -= dy; if (mouse.dx == 0 && mouse.dy == 0) - mouse.ready = 0; + mouse.ready = 0; if (put_user(buttons | 0x80, buffer++) || put_user((char) dx, buffer++) || put_user((char) dy, buffer++)) - return -EFAULT; - if (count > 3) - if (clear_user(buffer, count - 3)) return -EFAULT; + if (count > 3) + if (clear_user(buffer, count - 3)) + return -EFAULT; return count; } @@ -254,40 +250,35 @@ mouse.ready = 0; mouse.wait = NULL; +#ifdef __powerpc__ if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) return -ENODEV; - printk(KERN_INFO "Macintosh ADB mouse installed.\n"); +#endif +#ifdef __mc68000__ + if (!MACH_IS_MAC) + return -ENODEV; +#endif + printk(KERN_INFO "Macintosh ADB mouse driver installed.\n"); misc_register(&adb_mouse); return 0; } -#define MIN_THRESHOLD 1 -#define MAX_THRESHOLD 20 /* more seems not reasonable... */ - +/* + * 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 + */ __initfunc(void adb_mouse_setup(char *str, int *ints)) { - if (ints[0] < 1) { - printk( "adb_mouse_setup: no arguments!\n" ); - return; - } - else if (ints[0] > 2) { - printk( "adb_mouse_setup: too many arguments\n" ); - } - - if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD) - printk( "adb_mouse_setup: bad threshold value (ignored)\n" ); - else { - adb_mouse_x_threshold = ints[1]; - adb_mouse_y_threshold = ints[1]; - if (ints[0] > 1) { - if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD) - printk("adb_mouse_setup: bad threshold value (ignored)\n" ); - else - adb_mouse_y_threshold = ints[2]; + if (ints[0] >= 1) { + adb_emulate_buttons = ints[1] > 0; + if (ints[1] > 1) + adb_button2_keycode = ints[1]; + if (ints[0] >= 2) + adb_button3_keycode = ints[2]; } - } - } #ifdef MODULE diff -u --recursive --new-file v2.1.128/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.1.128/linux/drivers/char/cyclades.c Sun Nov 8 14:02:54 1998 +++ linux/drivers/char/cyclades.c Sun Nov 15 21:41:11 1998 @@ -1,7 +1,7 @@ #define BLOCKMOVE #define Z_WAKE static char rcsid[] = -"$Revision: 2.2.1.7 $$Date: 1998/09/03 12:07:28 $"; +"$Revision: 2.2.1.8 $$Date: 1998/11/13 12:46:20 $"; /* * linux/drivers/char/cyclades.c @@ -31,6 +31,10 @@ * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.2.1.8 1998/11/13 12:46:20 ivan + * cy_close function now resets (correctly) the tty->closing flag; + * JIFFIES_DIFF macro fixed. + * * Revision 2.2.1.7 1998/09/03 12:07:28 ivan * Fixed bug in cy_close function, which was not informing HW of * which port should have the reception disabled before doing so; @@ -612,7 +616,7 @@ #define STD_COM_FLAGS (0) -#define JIFFIES_DIFF(n, j) ((n) - (j)) +#define JIFFIES_DIFF(n, j) ((j) - (n)) static DECLARE_TASK_QUEUE(tq_cyclades); @@ -2730,6 +2734,7 @@ 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) { diff -u --recursive --new-file v2.1.128/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c --- v2.1.128/linux/drivers/char/lp_m68k.c Wed Aug 26 11:37:37 1998 +++ linux/drivers/char/lp_m68k.c Sun Nov 15 11:23:23 1998 @@ -477,7 +477,7 @@ EXPORT_SYMBOL(register_parallel); EXPORT_SYMBOL(unregister_parallel); -__initfunc(int lp_init(void)) +__initfunc(int lp_m68k_init(void)) { extern char m68k_debug_device[]; @@ -517,12 +517,12 @@ #ifdef MODULE int init_module(void) { -return lp_init(); + return lp_m68k_init(); } void cleanup_module(void) { -unregister_chrdev(LP_MAJOR, "lp"); + unregister_chrdev(LP_MAJOR, "lp"); } #endif diff -u --recursive --new-file v2.1.128/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.1.128/linux/drivers/char/mem.c Sun Nov 8 14:02:55 1998 +++ linux/drivers/char/mem.c Mon Nov 16 10:32:58 1998 @@ -53,6 +53,9 @@ #ifdef CONFIG_MDA_CONSOLE extern void mda_console_init(void); #endif +#if defined(CONFIG_PPC) || defined(CONFIG_MAC) +extern void adbdev_init(void); +#endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) @@ -509,9 +512,11 @@ case 3: filp->f_op = &null_fops; break; +#ifndef CONFIG_PPC case 4: filp->f_op = &port_fops; break; +#endif case 5: filp->f_op = &zero_fops; break; @@ -595,6 +600,9 @@ #endif #ifdef CONFIG_VIDEO_BT848 i2c_init(); +#endif +#if defined(CONFIG_PPC) || defined(CONFIG_MAC) + adbdev_init(); #endif #ifdef CONFIG_VIDEO_DEV videodev_init(); diff -u --recursive --new-file v2.1.128/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.128/linux/drivers/char/misc.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/char/misc.c Mon Nov 16 10:32:58 1998 @@ -64,14 +64,12 @@ #define DYNAMIC_MINORS 64 /* like dynamic majors */ static unsigned char misc_minors[DYNAMIC_MINORS / 8]; -extern int adbdev_init(void); extern int bus_mouse_init(void); extern int qpmouse_init(void); extern int ms_bus_mouse_init(void); extern int atixl_busmouse_init(void); extern int amiga_mouse_init(void); extern int atari_mouse_init(void); -extern int mac_mouse_init(void); extern int sun_mouse_init(void); extern int adb_mouse_init(void); extern void watchdog_init(void); @@ -196,9 +194,6 @@ if (proc_misc) proc_misc->read_proc = misc_read_proc; #endif /* PROC_FS */ -#ifdef CONFIG_MAC - adbdev_init(); -#endif #ifdef CONFIG_BUSMOUSE bus_mouse_init(); #endif @@ -217,13 +212,10 @@ #ifdef CONFIG_ATARIMOUSE atari_mouse_init(); #endif -#ifdef CONFIG_MACMOUSE - mac_mouse_init(); -#endif #ifdef CONFIG_SUN_MOUSE sun_mouse_init(); #endif -#ifdef CONFIG_MACMOUSE +#ifdef CONFIG_ADBMOUSE adb_mouse_init(); #endif #ifdef CONFIG_PC110_PAD diff -u --recursive --new-file v2.1.128/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.1.128/linux/drivers/char/random.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/random.c Fri Nov 13 10:29:44 1998 @@ -1407,19 +1407,15 @@ switch (cmd) { case RNDGETENTCNT: - retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); - if (retval) - return(retval); ent_count = random_state.entropy_count; - put_user(ent_count, (int *) arg); + if (put_user(ent_count, (int *) arg)) + return -EFAULT; return 0; case RNDADDTOENTCNT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int)); - if (retval) - return(retval); - get_user(ent_count, (int *) arg); + if (get_user(ent_count, (int *) arg)) + return -EFAULT; /* * Add i to entropy_count, limiting the result to be * between 0 and POOLBITS. @@ -1446,16 +1442,14 @@ if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; - retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int)); - if (retval) - return(retval); ent_count = random_state.entropy_count; - put_user(ent_count, p++); - retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int)); - if (retval) - return(retval); - get_user(size, p); - put_user(POOLWORDS, p++); + if (put_user(ent_count, p++)) + return -EFAULT; + + if (get_user(size, p)) + return -EFAULT; + if (put_user(POOLWORDS, p++)) + return -EFAULT; if (size < 0) return -EINVAL; if (size > POOLWORDS) @@ -1467,16 +1461,12 @@ if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; - retval = verify_area(VERIFY_READ, (void *) p, 2*sizeof(int)); - if (retval) - return(retval); - get_user(ent_count, p++); + if (get_user(ent_count, p++)) + return -EFAULT; if (ent_count < 0) return -EINVAL; - get_user(size, p++); - retval = verify_area(VERIFY_READ, (void *) p, size); - if (retval) - return retval; + if (get_user(size, p++)) + return -EFAULT; retval = random_write(file, (const char *) p, size, &file->f_pos); if (retval < 0) diff -u --recursive --new-file v2.1.128/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.1.128/linux/drivers/char/vt.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/char/vt.c Sun Nov 15 11:24:14 1998 @@ -57,6 +57,11 @@ struct vt_struct *vt_cons[MAX_NR_CONSOLES]; +/* Keyboard type: Default is KB_101, but can be set by machine + * specific code. + */ +unsigned char keyboard_type = KB_101; + #ifndef __alpha__ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); #endif @@ -462,7 +467,7 @@ /* * this is naive. */ - ucval = KB_101; + ucval = keyboard_type; goto setchar; #ifndef __alpha__ diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile --- v2.1.128/linux/drivers/macintosh/Makefile Thu Aug 6 14:06:32 1998 +++ linux/drivers/macintosh/Makefile Sun Nov 15 10:51:46 1998 @@ -16,14 +16,15 @@ M_OBJS := ifndef CONFIG_MBX -L_OBJS := via-cuda.o adb.o nvram.o macio-adb.o via-pmu.o mediabay.o +L_OBJS := via-cuda.o nvram.o macio-adb.o via-pmu.o mediabay.o +LX_OBJS := adb.o endif ifeq ($(CONFIG_MAC_SERIAL),y) - LX_OBJS += macserial.o + L_OBJS += macserial.o else ifeq ($(CONFIG_MAC_SERIAL),m) - MX_OBJS += macserial.o + M_OBJS += macserial.o endif endif diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c --- v2.1.128/linux/drivers/macintosh/adb.c Wed Aug 26 11:37:38 1998 +++ linux/drivers/macintosh/adb.c Sun Nov 15 10:51:46 1998 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -19,10 +20,13 @@ #include #include +EXPORT_SYMBOL(adb_hardware); + enum adb_hw adb_hardware = ADB_NONE; int (*adb_send_request)(struct adb_request *req, int sync); -int (*adb_autopoll)(int on); -static void adb_scan_bus(void); +int (*adb_autopoll)(int devs); +int (*adb_reset_bus)(void); +static int adb_scan_bus(void); static struct adb_handler { void (*handler)(unsigned char *, int, struct pt_regs *, int); @@ -50,13 +54,13 @@ } #endif -static void adb_scan_bus(void) +static int adb_scan_bus(void) { int i, highFree=0, noMovement; + int devmask = 0; struct adb_request req; - /* reset ADB bus */ - /*adb_request(&req, NULL, ADBREQ_SYNC, 1, 0);*/ + adb_reset_bus(); /* reset ADB bus */ /* assumes adb_handler[] is all zeroes at this point */ for (i = 1; i < 16; i++) { @@ -134,24 +138,27 @@ adb_handler[i].handler_id = req.reply[2]; printk(" [%d]: %d %x", i, adb_handler[i].original_address, adb_handler[i].handler_id); + devmask |= 1 << i; } printk("\n"); + return devmask; } void adb_init(void) { adb_send_request = (void *) adb_nodev; adb_autopoll = (void *) adb_nodev; + adb_reset_bus = adb_nodev; if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + return; via_cuda_init(); via_pmu_init(); macio_adb_init(); if (adb_hardware == ADB_NONE) printk(KERN_WARNING "Warning: no ADB interface detected\n"); else { - adb_scan_bus(); - adb_autopoll(1); + int devs = adb_scan_bus(); + adb_autopoll(devs); } } @@ -187,8 +194,7 @@ ids->nids = 0; for (i = 1; i < 16; i++) { - if ((adb_handler[i].original_address == default_id) || - (adb_handler[i].handler_id == handler_id)) { + if (adb_handler[i].original_address == default_id) { if (adb_handler[i].handler != 0) { printk(KERN_ERR "Two handlers for ADB device %d\n", diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c --- v2.1.128/linux/drivers/macintosh/mac_keyb.c Thu Aug 6 14:06:32 1998 +++ linux/drivers/macintosh/mac_keyb.c Sun Nov 15 10:51:46 1998 @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -170,16 +172,22 @@ static void keyboard_input(unsigned char *, int, struct pt_regs *, int); static void input_keycode(int, int); static void leds_done(struct adb_request *); +static void mac_put_queue(int); +#ifdef CONFIG_ADBMOUSE /* XXX: Hook for mouse driver */ -void (*adb_mouse_interrupt_hook) (char *, int); -static int adb_emulate_buttons = 0; +void (*adb_mouse_interrupt_hook)(unsigned char *, int); +int adb_emulate_buttons = 0; +int adb_button2_keycode = 0x7d; /* right control key */ +int adb_button3_keycode = 0x7c; /* right option key */ +#endif + extern int console_loglevel; extern struct kbd_struct kbd_table[]; +extern struct wait_queue * keypress_wait; extern void handle_scancode(unsigned char); -extern void put_queue(int); static struct adb_ids keyboard_ids; static struct adb_ids mouse_ids; @@ -264,6 +272,7 @@ if (!repeat) del_timer(&repeat_timer); +#ifdef CONFIG_ADBMOUSE /* * XXX: Add mouse button 2+3 fake codes here if mouse open. * Keep track of 'button' states here as we only send @@ -273,52 +282,27 @@ * Might also want to know how many buttons need to be emulated. * -> hide this as function in arch/m68k/mac ? */ - if ( (adb_emulate_buttons) && - (adb_mouse_interrupt_hook || console_loglevel == 10) ) { - unsigned char button, button2, button3, fake_event; - static unsigned char button2state=0, button3state=0; /* up */ + if (adb_emulate_buttons + && (keycode == adb_button2_keycode + || keycode == adb_button3_keycode) + && (adb_mouse_interrupt_hook || console_loglevel == 10)) { + int button; /* faked ADB packet */ - static char data[4] = { 0, 0x80, 0x80, 0x80 }; + static unsigned char data[4] = { 0, 0x80, 0x80, 0x80 }; - button = 0; - fake_event = 0; - switch (keycode) { /* which 'button' ? */ - case 0x7c: /* R-option */ - button3 = (!up_flag); /* new state */ - if (button3 != button3state) /* change ? */ - button = 3; - button3state = button3; /* save state */ - fake_event = 3; - break; - case 0x7d: /* R-control */ - button2 = (!up_flag); /* new state */ - if (button2 != button2state) /* change ? */ - button = 2; - button2state = button2; /* save state */ - fake_event = 2; - break; - } - if (fake_event && console_loglevel >= 8) - printk("fake event: button2 %d button3 %d button %d\n", - button2state, button3state, button); - if (button) { /* there's been a button state change */ - /* fake a mouse packet : send all bytes, change one! */ - data[button] = (up_flag ? 0x80 : 0); + button = keycode == adb_button2_keycode? 2: 3; + if (data[button] != up_flag) { + /* send a fake mouse packet */ + data[button] = up_flag; + if (console_loglevel >= 8) + printk("fake mouse event: %x %x %x\n", + data[1], data[2], data[3]); if (adb_mouse_interrupt_hook) - adb_mouse_interrupt_hook(data, -1); - else - printk("mouse_fake: data %x %x %x buttons %x \n", - data[1], data[2], data[3], - ~( (data[1] & 0x80 ? 0 : 4) - | (data[2] & 0x80 ? 0 : 1) - | (data[3] & 0x80 ? 0 : 2) )&7 ); + adb_mouse_interrupt_hook(data, 4); } - /* - * XXX: testing mouse emulation ... don't process fake keys! - */ - if (fake_event) - return; + return; } +#endif /* CONFIG_ADBMOUSE */ if (kbd->kbdmode != VC_RAW) { if (!up_flag && !dont_repeat[keycode]) { @@ -361,6 +345,20 @@ restore_flags(flags); } +static void mac_put_queue(int ch) +{ + extern struct tty_driver console_driver; + struct tty_struct *tty; + + tty = console_driver.table? console_driver.table[fg_console]: NULL; + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + con_schedule_flip(tty); + } +} + +#ifdef CONFIG_ADBMOUSE static void mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { @@ -399,33 +397,6 @@ */ /* - 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] = 0000 0000 ADB packet identifer. - data[1] = 0100 0000 Extended protocol register. - Bits 6-7 are the device id, which should be 1. - Bits 4-5 are resolution which is in "units/inch". - The Logitech MouseMan returns these bits clear but it has - 200/300cpi resolution. - Bits 0-3 are unique vendor id. - data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device. - Bits 2-3 should be 8 + 4. - Bits 4-7 should be 3 for a mouse device. - data[3] = bxxx xxxx Left button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - data[5] = byyy bxxx Third button and fourth button. Y is additional - high bits of y-axis motion. XY is additional - high bits of x-axis motion. - - NOTE: data[0] and data[2] are confirmed by the parent function and - need not be checked here. - */ - - /* Handler 1 -- 100cpi original Apple mouse protocol. Handler 2 -- 200cpi original Apple mouse protocol. @@ -433,28 +404,27 @@ contain the following values: BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = ???? ???? (?) - data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device. - data[3] = bxxx xxxx First button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. + 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. - NOTE: data[0] is confirmed by the parent function and need not be - checked here. + 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 additional + high bits of y-axis motion. XY is additional + high bits of x-axis motion. */ struct kbd_struct *kbd; if (adb_mouse_interrupt_hook) adb_mouse_interrupt_hook(data, nb); - else - if (console_loglevel == 10) - printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", - data[1], data[2], data[3], - ~((data[1] & 0x80 ? 0 : 4) - | (data[2] & 0x80 ? 0 : 1) - | (data[3] & 0x80 ? 0 : 2))&7, - ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ), - ((data[1]&0x7f) < 64 ? -(data[1]&0x7f) : 128-(data[1]&0x7f) ) ); kbd = kbd_table + fg_console; @@ -464,9 +434,9 @@ unsigned char uchButtonSecond; /* Send first button, second button and movement. */ - put_queue( 0x7e ); - put_queue( data[1] ); - put_queue( data[2] ); + mac_put_queue(0x7e); + mac_put_queue(data[1]); + mac_put_queue(data[2]); /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ @@ -475,12 +445,12 @@ /* Send second button. */ if (uchButtonSecond != uch_ButtonStateSecond) { - put_queue( 0x3f | uchButtonSecond ); + mac_put_queue(0x3f | uchButtonSecond); uch_ButtonStateSecond = uchButtonSecond; } /* Macintosh 3-button mouse (handler 4). */ - if ((nb == 4) && autopoll /*?*/) { + if (nb == 4) { static unsigned char uch_ButtonStateThird = 0x80; unsigned char uchButtonThird; @@ -489,12 +459,13 @@ /* Send third button. */ if (uchButtonThird != uch_ButtonStateThird) { - put_queue( 0x40 | uchButtonThird ); + mac_put_queue(0x40 | uchButtonThird); uch_ButtonStateThird = uchButtonThird; } } } } +#endif /* CONFIG_ADBMOUSE */ /* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ static unsigned char mac_ledmap[8] = { @@ -571,11 +542,14 @@ memcpy(key_maps[8], macalt_map, sizeof(plain_map)); memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map)); +#ifdef CONFIG_ADBMOUSE /* initialize mouse interrupt hook */ adb_mouse_interrupt_hook = NULL; - adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input); adb_register(ADB_MOUSE, 1, &mouse_ids, mouse_input); +#endif /* CONFIG_ADBMOUSE */ + + adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input); for(i = 0; i < keyboard_ids.nids; i++) { /* turn off all leds */ @@ -633,10 +607,4 @@ ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38); } } -} - -void adb_setup_mouse( char *s, int *ints ) -{ - if (ints[0] >= 1) - adb_emulate_buttons = ints[1]; } diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c --- v2.1.128/linux/drivers/macintosh/macio-adb.c Fri May 8 23:14:47 1998 +++ linux/drivers/macintosh/macio-adb.c Sun Nov 15 10:51:46 1998 @@ -61,8 +61,9 @@ static void macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs); static int macio_adb_send_request(struct adb_request *req, int sync); -static int macio_adb_autopoll(int on); +static int macio_adb_autopoll(int devs); static void macio_adb_poll(void); +static int macio_reset_bus(void); static void completed(void); __openfirmware @@ -108,14 +109,30 @@ adb_hardware = ADB_MACIO; adb_send_request = macio_adb_send_request; adb_autopoll = macio_adb_autopoll; + adb_reset_bus = macio_reset_bus; } -static int macio_adb_autopoll(int on) +static int macio_adb_autopoll(int devs) { - out_8(&adb->autopoll.r, on? APE: 0); + out_8(&adb->active_hi.r, devs >> 8); + out_8(&adb->active_lo.r, devs); + out_8(&adb->autopoll.r, devs? APE: 0); return 0; } +static int macio_reset_bus(void) +{ + int timeout = 1000000; + + out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST); + while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) { + if (--timeout == 0) { + out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) & ~ADB_RST); + return -1; + } + } + return 0; +} /* Send an ADB command */ static int macio_adb_send_request(struct adb_request *req, int sync) diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.1.128/linux/drivers/macintosh/macserial.c Sun Nov 8 14:02:58 1998 +++ linux/drivers/macintosh/macserial.c Tue Nov 17 14:57:24 1998 @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef CONFIG_KGDB #include #endif @@ -165,25 +166,35 @@ unsigned char reg) { unsigned char retval; + unsigned long flags; + /* + * We have to make this atomic. + */ + spin_lock_irqsave(&channel->lock, flags); if (reg != 0) { *channel->control = reg; RECOVERY_DELAY; } retval = *channel->control; RECOVERY_DELAY; + spin_unlock_irqrestore(&channel->lock, flags); return retval; } static inline void write_zsreg(struct mac_zschannel *channel, unsigned char reg, unsigned char value) { + unsigned long flags; + + spin_lock_irqsave(&channel->lock, flags); if (reg != 0) { *channel->control = reg; RECOVERY_DELAY; } *channel->control = value; RECOVERY_DELAY; + spin_unlock_irqrestore(&channel->lock, flags); return; } @@ -434,6 +445,10 @@ for (;;) { zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; +#ifdef SERIAL_DEBUG_INTR +// printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg); +#endif + if ((zs_intreg & CHAN_IRQMASK) == 0) break; @@ -1261,6 +1276,15 @@ tty->closing = 0; info->event = 0; info->tty = 0; + + if (info->is_cobalt_modem) { + /* Power down modem */ + feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Modem_PowerOn); + mdelay(15); + } + if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -1271,6 +1295,7 @@ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); + restore_flags(flags); } @@ -1508,9 +1533,25 @@ /* * Start up serial port */ + + if (info->is_cobalt_modem) { + /* Power up modem */ + feature_set(info->dev_node, FEATURE_Modem_PowerOn); + mdelay(250); + feature_clear(info->dev_node, FEATURE_Modem_Reset); + mdelay(10); + } retval = startup(info); - if (retval) + if (retval) { + if (info->is_cobalt_modem) { + /* Power down modem */ + feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Modem_PowerOn); + mdelay(15); + } return retval; + } retval = block_til_ready(tty, filp, info); if (retval) { @@ -1518,6 +1559,13 @@ printk("rs_open returning after block_til_ready with %d\n", retval); #endif + if (info->is_cobalt_modem) { + /* Power down modem */ + feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Modem_PowerOn); + mdelay(15); + } return retval; } @@ -1568,8 +1616,14 @@ dev->full_name); continue; } + feature_clear(dev, FEATURE_Serial_reset); + mdelay(5); + feature_set(dev, FEATURE_Serial_enable); + feature_set(dev, FEATURE_Serial_IO_A); + feature_set(dev, FEATURE_Serial_IO_B); + mdelay(5); for (ch = dev->child; ch != 0; ch = ch->sibling) { - if (ch->n_addrs < 1 || ch ->n_intrs < 1) { + if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) { printk("Can't use %s: %d addrs %d intrs\n", ch->full_name, ch->n_addrs, ch->n_intrs); continue; @@ -1578,8 +1632,20 @@ ioremap(ch->addrs[0].address, 0x1000); zs_channels[n].data = zs_channels[n].control + ch->addrs[0].size / 2; + spin_lock_init(&zs_channels[n].lock); zs_soft[n].zs_channel = &zs_channels[n]; + zs_soft[n].dev_node = ch; zs_soft[n].irq = ch->intrs[0].line; + zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt"); + if (zs_soft[n].is_cobalt_modem) + { + /* Just in case the modem is up, shut it down */ + feature_set(ch, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(ch, FEATURE_Modem_PowerOn); + mdelay(15); + } + /* XXX this assumes the prom puts chan A before B */ if (n & 1) zs_soft[n].zs_chan_a = &zs_channels[n-1]; @@ -1696,6 +1762,9 @@ for (info = zs_chain, i = 0; info; info = info->zs_next, i++) { + unsigned char* connector; + int lenp; + #ifdef CONFIG_KGDB if (info->kgdb_channel) { continue; @@ -1719,8 +1788,14 @@ info->open_wait = 0; info->close_wait = 0; printk("tty%02d at 0x%08x (irq = %d)", info->line, - info->port, info->irq); - printk(" is a Z8530 ESCC\n"); + info->port, info->irq); + printk(" is a Z8530 ESCC"); + connector = get_property(info->dev_node, "AAPL,connector", &lenp); + if (connector) + printk(", port = %s", connector); + if (info->is_cobalt_modem) + printk(" (cobalt modem)"); + printk("\n"); } restore_flags(flags); diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h --- v2.1.128/linux/drivers/macintosh/macserial.h Sat Aug 16 09:53:08 1997 +++ linux/drivers/macintosh/macserial.h Sun Nov 15 10:51:47 1998 @@ -84,6 +84,7 @@ struct mac_zschannel { volatile unsigned char *control; volatile unsigned char *data; + spinlock_t lock; }; struct mac_serial { @@ -91,11 +92,13 @@ struct mac_zschannel *zs_channel; /* Channel registers */ struct mac_zschannel *zs_chan_a; /* A side registers */ unsigned char read_reg_zero; + struct device_node* dev_node; char soft_carrier; /* Use soft carrier on this channel */ char break_abort; /* Is serial console in, so process brk/abrt */ char kgdb_channel; /* Kgdb is running on this channel */ char is_cons; /* Is this our console. */ + char is_cobalt_modem; /* is a gatwick-based cobalt modem */ unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c --- v2.1.128/linux/drivers/macintosh/mediabay.c Sun Nov 8 14:02:59 1998 +++ linux/drivers/macintosh/mediabay.c Sun Nov 15 10:51:47 1998 @@ -8,6 +8,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#define __KERNEL_SYSCALLS__ + #include #include #include @@ -16,44 +18,54 @@ #include #include #include +#include +#include #include #include #include -#include +#include #include #include + +#undef MB_USE_INTERRUPTS + struct media_bay_hw { unsigned char b0; unsigned char contents; unsigned char b2; unsigned char b3; - unsigned feature; }; -static volatile struct media_bay_hw *mb_addr; +struct media_bay_info { + volatile struct media_bay_hw* addr; + int content_id; + int previous_id; + int ready; + int last_value; + int value_count; + int reset_timer; + struct device_node* dev_node; +#ifdef CONFIG_BLK_DEV_IDE + unsigned long cd_base; + int cd_index; + int cd_irq; + int cd_timer; +#endif +}; -#define MB_CONTENTS() ((in_8(&mb_addr->contents) >> 4) & 7) -#define SET_FEATURES(set, clr) \ - out_le32(&mb_addr->feature, \ - (in_le32(&mb_addr->feature) & ~(clr)) | (set)); +#define MAX_BAYS 2 -static int media_bay_id = -1; -static int mb_ready; -static int mb_last_value; -static int mb_value_count; +static volatile struct media_bay_info media_bays[MAX_BAYS]; +int media_bay_count = 0; -int media_bay_present; +#define MB_CONTENTS(i) ((in_8(&media_bays[i].addr->contents) >> 4) & 7) #ifdef CONFIG_BLK_DEV_IDE -unsigned long mb_cd_base; -int mb_cd_index = -1; -int mb_cd_irq; - /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ -#define MB_IDE_READY() ((in_8((volatile unsigned char *) \ - (mb_cd_base + 0x70)) & 0x80) == 0) +#define MB_IDE_READY(i) ((in_8((volatile unsigned char *) \ + (media_bays[i].cd_base + 0x70)) & 0x80) == 0) #endif /* @@ -66,16 +78,17 @@ * Hold the media-bay reset signal true for this many ticks * after a device is inserted before releasing it. */ -#define MB_RESET_COUNT 10 +#define MB_RESET_COUNT 20 /* * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted * (or until the device is ready) before registering the IDE interface. */ -#define MB_IDE_WAIT 500 +#define MB_IDE_WAIT 1000 -static void poll_media_bay(void); -static void set_media_bay(int id); +static void poll_media_bay(int which); +static void set_media_bay(int which, int id); +static int media_bay_task(void *); /* * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL @@ -92,29 +105,62 @@ media_bay_init(void) { struct device_node *np; - - np = find_devices("media-bay"); - if (np == NULL || np->n_addrs == 0) - return; - mb_addr = (volatile struct media_bay_hw *) - ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); - -#if 0 - if (np->n_intrs == 0) { - printk(KERN_WARNING "No interrupt for media bay?\n"); - } else { - if (request_irq(np->intrs[0].line, media_bay_intr, 0, - "Media bay", NULL)) - printk(KERN_WARNING "Couldn't get IRQ %d for " - "media bay\n", np->intrs[0].line); + int n,i; + + for (i=0; in_addrs == 0) + continue; + media_bays[n].addr = (volatile struct media_bay_hw *) + ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); + +#ifdef MB_USE_INTERRUPTS + if (np->n_intrs == 0) + { + printk(KERN_ERR "media bay %d has no irq\n",n); + continue; + } + + if (request_irq(np_intrs[0].line, media_bay_intr, 0, "Media bay", NULL)) + { + printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", irq, n); + continue; + } +#endif + media_bay_count++; + + set_media_bay(n, MB_CONTENTS(n)); + if (media_bays[n].content_id != MB_NO) { + feature_clear(media_bays[n].dev_node, FEATURE_Mediabay_reset); + udelay(500); + } + media_bays[n].ready = 1; + media_bays[n].previous_id = media_bays[n].content_id; + media_bays[n].reset_timer = 0; + media_bays[n].dev_node = np; +#ifdef CONFIG_BLK_DEV_IDE + media_bays[n].cd_timer = 0; #endif + n++; + np=np->next; + } + + if (media_bay_count) + { + printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count); - media_bay_present = 1; - set_media_bay(MB_CONTENTS()); - if (media_bay_id != MB_NO) { - SET_FEATURES(0, OH_BAY_RESET); - mb_ready = 1; + kernel_thread(media_bay_task, NULL, 0); } } @@ -130,9 +176,61 @@ #endif int -check_media_bay(int what) +check_media_bay(struct device_node *which_bay, int what) { - return what == media_bay_id && mb_ready; +#ifdef CONFIG_BLK_DEV_IDE + int i; + + for (i=0; icomm, "media-bay"); - for (;;) { - poll_media_bay(); - if (media_bay_id != prev) { - reset_timer = (media_bay_id != MB_NO)? + for (;;) + { + bay = &media_bays[i]; + poll_media_bay(i); + if (bay->content_id != bay->previous_id) { + bay->reset_timer = (bay->content_id != MB_NO) ? MB_RESET_COUNT: 0; - mb_ready = 0; + bay->ready = 0; #ifdef CONFIG_BLK_DEV_IDE - cd_timer = 0; - if (media_bay_id != MB_CD && mb_cd_index >= 0) { - printk(KERN_DEBUG "Unregistering mb ide\n"); - ide_unregister(mb_cd_index); - mb_cd_index = -1; + bay->cd_timer = 0; + if (bay->content_id != MB_CD && bay->cd_index >= 0) { + printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); + ide_unregister(bay->cd_index); + bay->cd_index = -1; } #endif - } else if (reset_timer) { - if (--reset_timer == 0) { - SET_FEATURES(0, OH_BAY_RESET); - mb_ready = 1; + } else if (bay->reset_timer) { + if (--bay->reset_timer == 0) { + feature_clear(bay->dev_node, FEATURE_Mediabay_reset); + bay->ready = 1; #ifdef CONFIG_BLK_DEV_IDE - if (media_bay_id == MB_CD && mb_cd_base != 0) - cd_timer = MB_IDE_WAIT; + bay->cd_timer = 0; + if (bay->content_id == MB_CD && bay->cd_base != 0) + bay->cd_timer = MB_IDE_WAIT; #endif } #ifdef CONFIG_BLK_DEV_IDE - } else if (cd_timer && (--cd_timer == 0 || MB_IDE_READY()) - && mb_cd_index < 0) { - mb_cd_index = ide_register(mb_cd_base, 0, mb_cd_irq); - printk(KERN_DEBUG "media-bay is ide %d\n", mb_cd_index); + } else if (bay->cd_timer && (--bay->cd_timer == 0 || MB_IDE_READY(i)) + && bay->cd_index < 0) { + bay->cd_timer = 0; + printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq); + printk("\n"); + bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq); + if (bay->cd_index == -1) + printk("\nCD-ROM badly inserted. Remove it and try again !\n"); + else + printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index); #endif } - prev = media_bay_id; + bay->previous_id = bay->content_id; current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); if (signal_pending(current)) return 0; + i = (i+1)%media_bay_count; } } void -poll_media_bay(void) +poll_media_bay(int which) { - int id = MB_CONTENTS(); + int id = MB_CONTENTS(which); - if (id == mb_last_value) { - if (id != media_bay_id - && ++mb_value_count >= MB_STABLE_COUNT) - set_media_bay(id); + if (id == media_bays[which].last_value) { + if (id != media_bays[which].content_id + && ++media_bays[which].value_count >= MB_STABLE_COUNT) + set_media_bay(which, id); } else { - mb_last_value = id; - mb_value_count = 0; + media_bays[which].last_value = id; + media_bays[which].value_count = 0; } } static void -set_media_bay(int id) +set_media_bay(int which, int id) { - u32 clr, set; + volatile struct media_bay_info* bay; - media_bay_id = id; - mb_last_value = id; - clr = OH_FLOPPY_ENABLE | OH_IDECD_POWER; - set = 0; + bay = &media_bays[which]; + + bay->content_id = id; + bay->last_value = id; + switch (id) { case MB_CD: - set = OH_BAY_ENABLE | OH_IDECD_POWER | OH_BAY_IDE_ENABLE; - printk(KERN_INFO "media bay contains a CD-ROM drive\n"); + feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_set(bay->dev_node, FEATURE_Mediabay_enable); + feature_set(bay->dev_node, FEATURE_CD_power); + feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable); + printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which); break; case MB_FD: - set = OH_BAY_ENABLE | OH_BAY_FLOPPY_ENABLE | OH_FLOPPY_ENABLE; - printk(KERN_INFO "media bay contains a floppy disk drive\n"); + feature_clear(bay->dev_node, FEATURE_CD_power); + feature_set(bay->dev_node, FEATURE_Mediabay_enable); + feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_set(bay->dev_node, FEATURE_SWIM3_enable); + printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which); break; case MB_NO: - printk(KERN_INFO "media bay is empty\n"); + feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_clear(bay->dev_node, FEATURE_CD_power); + printk(KERN_INFO "media bay %d is empty\n", which); break; default: - set = OH_BAY_ENABLE; - printk(KERN_INFO "media bay contains an unknown device (%d)\n", - id); + feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_clear(bay->dev_node, FEATURE_CD_power); + feature_set(bay->dev_node, FEATURE_Mediabay_enable); + printk(KERN_INFO "media bay %d contains an unknown device (%d)\n", + which, id); break; } - - SET_FEATURES(set, clr); - printk(KERN_DEBUG "feature reg now %x\n", in_le32(&mb_addr->feature)); + + udelay(500); } diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c --- v2.1.128/linux/drivers/macintosh/via-cuda.c Sun Jun 7 11:16:31 1998 +++ linux/drivers/macintosh/via-cuda.c Sun Nov 15 10:51:47 1998 @@ -80,7 +80,8 @@ static void via_interrupt(int irq, void *arg, struct pt_regs *regs); static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs); static int cuda_adb_send_request(struct adb_request *req, int sync); -static int cuda_adb_autopoll(int on); +static int cuda_adb_autopoll(int devs); +static int cuda_reset_bus(void); __openfirmware @@ -141,6 +142,7 @@ /* Set function pointers */ adb_send_request = cuda_adb_send_request; adb_autopoll = cuda_adb_autopoll; + adb_reset_bus = cuda_reset_bus; } #define WAIT_FOR(cond, what) \ @@ -216,11 +218,23 @@ /* Enable/disable autopolling */ static int -cuda_adb_autopoll(int on) +cuda_adb_autopoll(int devs) { struct adb_request req; - cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, on); + cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0)); + while (!req.complete) + cuda_poll(); + return 0; +} + +/* Reset adb bus - how do we do this?? */ +static int +cuda_reset_bus(void) +{ + struct adb_request req; + + cuda_request(&req, NULL, 2, ADB_PACKET, 0); /* maybe? */ while (!req.complete) cuda_poll(); return 0; diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c --- v2.1.128/linux/drivers/macintosh/via-pmu.c Wed Aug 26 11:37:38 1998 +++ linux/drivers/macintosh/via-pmu.c Sun Nov 15 10:51:47 1998 @@ -30,6 +30,7 @@ #include #include #include +#include /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -99,7 +100,8 @@ static void pmu_start(void); static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); static int pmu_adb_send_request(struct adb_request *req, int sync); -static int pmu_adb_autopoll(int on); +static int pmu_adb_autopoll(int devs); +static int pmu_reset_bus(void); static void send_byte(int x); static void recv_byte(void); static void pmu_sr_intr(struct pt_regs *regs); @@ -162,6 +164,8 @@ return; if (vias->next != 0) printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); + + feature_set(vias, FEATURE_VIA_enable); #if 0 { int i; @@ -215,6 +219,7 @@ /* Set function pointers */ adb_send_request = pmu_adb_send_request; adb_autopoll = pmu_adb_autopoll; + adb_reset_bus = pmu_reset_bus; } static int @@ -281,11 +286,12 @@ /* Enable/disable autopolling */ static int -pmu_adb_autopoll(int on) +pmu_adb_autopoll(int devs) { struct adb_request req; - if (on) { + if (devs) { + adb_dev_map = devs; pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86, adb_dev_map >> 8, adb_dev_map); pmu_adb_flags = 2; @@ -298,6 +304,49 @@ return 0; } +/* Reset the ADB bus */ +static int +pmu_reset_bus(void) +{ + struct adb_request req; + long timeout; + int save_autopoll = adb_dev_map; + + /* anyone got a better idea?? */ + pmu_adb_autopoll(0); + + req.nbytes = 5; + req.done = NULL; + req.data[0] = PMU_ADB_CMD; + req.data[1] = 0; + req.data[2] = 3; + req.data[3] = 0; + req.data[4] = 0; + req.reply_len = 0; + req.reply_expected = 1; + if (pmu_queue_request(&req) != 0) + { + printk(KERN_ERR "pmu_reset_bus: pmu_queue_request failed\n"); + return 0; + } + while (!req.complete) + pmu_poll(); + timeout = 100000; + while (!req.complete) { + if (--timeout < 0) { + printk(KERN_ERR "pmu_reset_bus (reset): no response from PMU\n"); + return 0; + } + udelay(10); + pmu_poll(); + } + + if (save_autopoll != 0) + pmu_adb_autopoll(save_autopoll); + + return 1; +} + /* Construct and send a pmu request */ int pmu_request(struct adb_request *req, void (*done)(struct adb_request *), @@ -366,7 +415,10 @@ req->nbytes = 5; for (i = 1; i <= 4; ++i) req->data[i] = req->data[i+1]; - req->reply_len = 0; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_SET_TIME; return pmu_queue_request(req); } break; @@ -691,6 +743,44 @@ { } +void +pmu_restart(void) +{ + struct adb_request req; + + _disable_interrupts(); + + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, CB1_INT); + while(!req.complete) + pmu_poll(); + + pmu_request(&req, NULL, 1, PMU_RESET); + while(!req.complete || (pmu_state != idle)) + pmu_poll(); + for (;;) + ; +} + +void +pmu_shutdown(void) +{ + struct adb_request req; + + _disable_interrupts(); + + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, CB1_INT); + while(!req.complete) + pmu_poll(); + + pmu_request(&req, NULL, 5, PMU_SHUTDOWN, + 'M', 'A', 'T', 'T'); + while(!req.complete || (pmu_state != idle)) + pmu_poll(); + for (;;) + ; +} + + #ifdef CONFIG_PMAC_PBOOK /* @@ -855,11 +945,13 @@ notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); /* reenable ADB autopoll */ - pmu_adb_autopoll(1); + pmu_adb_autopoll(adb_dev_map); /* Turn on the screen backlight, if it was on before */ if (save_backlight) pmu_enable_backlight(1); + + /* Wait for the hard disk to spin up */ return 0; } diff -u --recursive --new-file v2.1.128/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c --- v2.1.128/linux/drivers/misc/parport_arc.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/misc/parport_arc.c Sun Nov 15 09:52:25 1998 @@ -14,6 +14,7 @@ * a subset of the standard printer control lines connected. */ +#include #include #include #include @@ -141,7 +142,9 @@ printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n", p->irq); +#ifdef CONFIG_PROC_FS parport_proc_register(p); +#endif p->flags |= PARPORT_FLAG_COMA; if (parport_probe_hook) diff -u --recursive --new-file v2.1.128/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c --- v2.1.128/linux/drivers/misc/parport_ax.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/misc/parport_ax.c Wed Nov 18 09:06:05 1998 @@ -1,4 +1,4 @@ -/* $Id: parport_ax.c,v 1.12 1998/07/26 03:03:31 davem Exp $ +/* $Id: parport_ax.c,v 1.14 1998/11/16 04:48:02 davem Exp $ * Parallel-port routines for Sun Ultra/AX architecture * * Author: Eddie C. Dost @@ -11,6 +11,7 @@ * Grant Guenther */ +#include #include #include #include @@ -585,7 +586,9 @@ printmode(ECPPS2); } printk("]\n"); +#ifdef CONFIG_PROC_FS parport_proc_register(p); +#endif p->flags |= PARPORT_FLAG_COMA; p->ops->write_control(p, 0x0c); @@ -628,7 +631,9 @@ if (p->modes & PARPORT_MODE_PCSPP) { if (!(p->flags & PARPORT_FLAG_COMA)) parport_quiesce(p); +#ifdef CONFIG_PROC_FS parport_proc_unregister(p); +#endif parport_unregister_port(p); } p = tmp; diff -u --recursive --new-file v2.1.128/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c --- v2.1.128/linux/drivers/misc/parport_init.c Tue Apr 14 14:29:20 1998 +++ linux/drivers/misc/parport_init.c Fri Nov 13 10:29:44 1998 @@ -98,13 +98,17 @@ #ifdef MODULE int init_module(void) { +#ifdef CONFIG_PROC_FS (void)parport_proc_init(); /* We can go on without it. */ +#endif return 0; } void cleanup_module(void) { +#ifdef CONFIG_PROC_FS parport_proc_cleanup(); +#endif } #else __initfunc(int parport_init(void)) @@ -115,7 +119,9 @@ #ifdef CONFIG_PNP_PARPORT parport_probe_hook = &parport_probe_one; #endif +#ifdef CONFIG_PROC_FS parport_proc_init(); +#endif #ifdef CONFIG_PARPORT_PC parport_pc_init(io, irq, dma); #endif @@ -139,8 +145,10 @@ EXPORT_SYMBOL(parport_enumerate); EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok); EXPORT_SYMBOL(parport_wait_peripheral); +#ifdef CONFIG_PROC_FS EXPORT_SYMBOL(parport_proc_register); EXPORT_SYMBOL(parport_proc_unregister); +#endif EXPORT_SYMBOL(parport_probe_hook); EXPORT_SYMBOL(parport_parse_irqs); diff -u --recursive --new-file v2.1.128/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.1.128/linux/drivers/misc/parport_pc.c Sun Nov 8 14:02:59 1998 +++ linux/drivers/misc/parport_pc.c Sun Nov 15 09:52:26 1998 @@ -34,6 +34,7 @@ * accomodate this. */ +#include #include #include #include @@ -755,9 +756,11 @@ } #undef printmode printk("]\n"); +#ifdef CONFIG_PROC_FS if (probedirq != PARPORT_IRQ_NONE) printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq); parport_proc_register(p); +#endif p->flags |= PARPORT_FLAG_COMA; /* Done probing. Now put the port into a sensible start-up state. */ @@ -821,7 +824,9 @@ if (p->modes & PARPORT_MODE_PCSPP) { if (!(p->flags & PARPORT_FLAG_COMA)) parport_quiesce(p); +#ifdef CONFIG_PROC_FS parport_proc_unregister(p); +#endif parport_unregister_port(p); } p = tmp; diff -u --recursive --new-file v2.1.128/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.128/linux/drivers/net/3c59x.c Thu Nov 12 16:21:19 1998 +++ linux/drivers/net/3c59x.c Fri Nov 13 10:29:44 1998 @@ -77,7 +77,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.128/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.1.128/linux/drivers/net/Space.c Thu Nov 12 16:21:19 1998 +++ linux/drivers/net/Space.c Fri Nov 13 10:29:43 1998 @@ -559,7 +559,7 @@ #if defined(CONFIG_LTPC) extern int ltpc_probe(struct device *); static struct device dev_ltpc = { - "ltalk0\0 ", + "lt0\0 ", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, ltpc_probe }; diff -u --recursive --new-file v2.1.128/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v2.1.128/linux/drivers/net/at1700.c Thu Nov 12 16:21:19 1998 +++ linux/drivers/net/at1700.c Sun Nov 15 09:52:26 1998 @@ -33,6 +33,7 @@ static const char *version = "at1700.c:v1.15 4/7/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +#include #include #include diff -u --recursive --new-file v2.1.128/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.1.128/linux/drivers/net/bmac.c Sun Nov 8 14:02:59 1998 +++ linux/drivers/net/bmac.c Sun Nov 15 10:51:47 1998 @@ -54,6 +54,7 @@ int rx_dma_intr; volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */ volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */ + struct device_node *node; struct sk_buff *rx_bufs[N_RX_RING]; int rx_fill; int rx_empty; @@ -235,11 +236,11 @@ dbdma_reset(rd); dbdma_reset(td); - feature_set(FEATURE_BMac_IO_enable); + feature_set(bp->node, FEATURE_BMac_IO_enable); udelay(10000); - feature_set(FEATURE_BMac_reset); + feature_set(bp->node, FEATURE_BMac_reset); udelay(10000); - feature_clear(FEATURE_BMac_reset); + feature_clear(bp->node, FEATURE_BMac_reset); udelay(10000); } @@ -374,8 +375,6 @@ //bmwrite(dev, TXCFG, TxMACEnable); /* TxNeverGiveUp maybe later */ bmread(dev, STATUS); /* read it just to clear it */ - bmwrite(dev, INTDISABLE, EnableNormal); - /* zero out the chip Hash Filter registers */ for (i=0; i<4; i++) bp->hash_table_mask[i] = 0; bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */ @@ -387,10 +386,11 @@ bmwrite(dev, MADD0, *pWord16++); bmwrite(dev, MADD1, *pWord16++); bmwrite(dev, MADD2, *pWord16); - bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets); - + + bmwrite(dev, INTDISABLE, EnableNormal); + return; } @@ -620,6 +620,8 @@ bp->tx_bufs[bp->tx_fill] = skb; bp->tx_fill = i; + bp->stats.tx_bytes += skb->len; + dbdma_continue(td); return 0; @@ -669,6 +671,7 @@ skb_reserve(bp->rx_bufs[i], 2); bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]); ++bp->stats.rx_packets; + bp->stats.rx_bytes += nb; } else { ++bp->stats.rx_dropped; } @@ -1241,7 +1244,7 @@ dev->base_addr = bmacs->addrs[0].address; dev->irq = bmacs->intrs[0].line; - + bmwrite(dev, INTDISABLE, DisableAll); addr = get_property(bmacs, "mac-address", NULL); @@ -1288,6 +1291,7 @@ bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1); skb_queue_head_init(bp->queue); + bp->node = bmacs; memset(&bp->stats, 0, sizeof(bp->stats)); memset((char *) bp->tx_cmds, 0, (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); diff -u --recursive --new-file v2.1.128/linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c --- v2.1.128/linux/drivers/net/hamradio/mkiss.c Sun Jul 26 11:57:16 1998 +++ linux/drivers/net/hamradio/mkiss.c Fri Nov 13 10:29:44 1998 @@ -894,7 +894,6 @@ static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) { struct ax_disp *ax = (struct ax_disp *)tty->disc_data; - int err; unsigned int tmp; /* First make sure we're connected. */ diff -u --recursive --new-file v2.1.128/linux/drivers/net/hostess_sv11.c linux/drivers/net/hostess_sv11.c --- v2.1.128/linux/drivers/net/hostess_sv11.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/hostess_sv11.c Fri Nov 13 10:29:44 1998 @@ -160,8 +160,8 @@ static int hostess_ioctl(struct device *d, struct ifreq *ifr, int cmd) { - struct sv11_device *sv11=d->priv; - /* z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */ + /* struct sv11_device *sv11=d->priv; + z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */ return sppp_do_ioctl(d, ifr,cmd); } diff -u --recursive --new-file v2.1.128/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.1.128/linux/drivers/net/ltpc.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/ltpc.c Fri Nov 13 10:29:43 1998 @@ -67,6 +67,25 @@ * Hacked about a bit to clean things up - Alan Cox * Probably broken it from the origina 1.8 * + + * 1998/11/09: David Huggins-Daines + * Cleaned up the initialization code to use the standard autoirq methods, + and to probe for things in the standard order of i/o, irq, dma. This + removes the "reset the reset" hack, because I couldn't figure out an + easy way to get the card to trigger an interrupt after it. + * Added support for passing configuration parameters on the kernel command + line and through insmod + * Changed the device name from "ltalk0" to "lt0", both to conform with the + other localtalk driver, and to clear up the inconsistency between the + module and the non-module versions of the driver :-) + * Added a bunch of comments (I was going to make some enums for the state + codes and the register offsets, but I'm still not sure exactly what their + semantics are) + * Don't poll anymore in interrupt-driven mode + * It seems to work as a module now (as of 2.1.127), but I don't think + I'm responsible for that... + + * * Revision 1.7 1996/12/12 03:42:33 bradford * DMA alloc cribbed from 3c505.c. * @@ -180,6 +199,9 @@ #define DEBUG_UPPER 2 #define DEBUG_LOWER 4 +static int io=0; +static int irq=0; +static int dma=0; #ifdef MODULE #include @@ -245,25 +267,34 @@ return __get_dma_pages(GFP_KERNEL, order); } +/* DMA data buffer, DMA command buffer */ static unsigned char *ltdmabuf; static unsigned char *ltdmacbuf; +/* private struct, holds our appletalk address */ + struct ltpc_private { struct net_device_stats stats; struct at_addr my_addr; }; +/* transmit queue element struct */ + struct xmitQel { struct xmitQel *next; + /* command buffer */ unsigned char *cbuf; short cbuflen; + /* data buffer */ unsigned char *dbuf; short dbuflen; unsigned char QWrite; /* read or write data */ unsigned char mailbox; }; +/* the transmit queue itself */ + static struct xmitQel *xmQhd=NULL,*xmQtl=NULL; static void enQ(struct xmitQel *qel) @@ -310,8 +341,10 @@ return qel; } +/* and... the queue elements we'll be using */ static struct xmitQel qels[16]; +/* and their corresponding mailboxes */ static unsigned char mailbox[16]; static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; @@ -331,6 +364,8 @@ return 1; /* timed out */ } +/* get the first free mailbox */ + static int getmbox(void) { unsigned long flags; @@ -347,6 +382,7 @@ return 0; } +/* read a command from the card */ static void handlefc(struct device *dev) { /* called *only* from idle, non-reentrant */ @@ -370,6 +406,7 @@ if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n"); } +/* read data from the card */ static void handlefd(struct device *dev) { int dma = dev->dma; @@ -463,7 +500,8 @@ if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n"); } -static unsigned char rescbuf[2] = {0,0}; +/* ready made command for getting the result from the card */ +static unsigned char rescbuf[2] = {LT_GETRESULT,0}; static unsigned char resdbuf[2]; static int QInIdle=0; @@ -482,7 +520,7 @@ struct xmitQel *q=0; int oops; int i; - int statusPort = dev->base_addr+6; + int base = dev->base_addr; save_flags(flags); cli(); @@ -495,8 +533,8 @@ restore_flags(flags); - - (void) inb_p(statusPort); /* this tri-states the IRQ line */ + /* this tri-states the IRQ line */ + (void) inb_p(base+6); oops = 100; @@ -506,19 +544,22 @@ goto done; } - state = inb_p(statusPort); - if (state != inb_p(statusPort)) goto loop; + state = inb_p(base+6); + if (state != inb_p(base+6)) goto loop; switch(state) { - case 0xfc: + case 0xfc: + /* incoming command */ if (debug&DEBUG_LOWER) printk("idle: fc\n"); handlefc(dev); break; - case 0xfd: + case 0xfd: + /* incoming data */ if(debug&DEBUG_LOWER) printk("idle: fd\n"); handlefd(dev); break; - case 0xf9: + case 0xf9: + /* result ready */ if (debug&DEBUG_LOWER) printk("idle: f9\n"); if(!mboxinuse[0]) { mboxinuse[0] = 1; @@ -536,6 +577,7 @@ printk("timed out idle f9\n"); break; case 0xf8: + /* ?? */ if (xmQhd) { inb_p(dev->base_addr+1); inb_p(dev->base_addr+0); @@ -545,7 +587,8 @@ goto done; } break; - case 0xfa: + case 0xfa: + /* waiting for command */ if(debug&DEBUG_LOWER) printk("idle: fa\n"); if (xmQhd) { q=deQ(); @@ -561,7 +604,7 @@ printk("\n"); } handlecommand(dev); - if(0xfa==inb_p(statusPort)) { + if(0xfa==inb_p(base+6)) { /* we timed out, so return */ goto done; } @@ -582,13 +625,17 @@ } } break; - case 0xfb: + case 0Xfb: + /* data transfer ready */ if(debug&DEBUG_LOWER) printk("idle: fb\n"); if(q->QWrite) { memcpy(ltdmabuf,q->dbuf,q->dbuflen); handlewrite(dev); } else { handleread(dev); + /* non-zero mailbox numbers are for + commmands, 0 is for GETRESULT + requests */ if(q->mailbox) { memcpy(q->dbuf,ltdmabuf,q->dbuflen); } else { @@ -605,13 +652,14 @@ QInIdle=0; /* now set the interrupts back as appropriate */ - /* the first 7 takes it out of tri-state (but still high) */ + /* the first read takes it out of tri-state (but still high) */ /* the second resets it */ - /* note that after this point, any read of 6 will trigger an interrupt */ + /* note that after this point, any read of base+6 will + trigger an interrupt */ if (dev->irq) { - inb_p(dev->base_addr+7); - inb_p(dev->base_addr+7); + inb_p(base+7); + inb_p(base+7); } return; } @@ -703,6 +751,8 @@ return do_write(dev, &c, sizeof(c.setflags),&c,0); } +/* LLAP to DDP translation */ + static int sendup_buffer (struct device *dev) { /* on entry, command is in ltdmacbuf, data in ltdmabuf */ @@ -912,23 +962,14 @@ if (!dev) return; /* we've been downed */ - if (dev->irq) - { - /* we're set up for interrupts */ - if (0xf8 != inb_p(dev->base_addr+7)) { - /* trigger an interrupt */ - (void) inb_p(dev->base_addr+6); - } - ltpc_timer.expires = jiffies+100; - } else { - /* we're strictly polling mode */ - idle(dev); - ltpc_timer.expires = jiffies+5; - } - + idle(dev); + ltpc_timer.expires = jiffies+5; + add_timer(<pc_timer); } +/* DDP to LLAP translation */ + static int ltpc_xmit(struct sk_buff *skb, struct device *dev) { /* in kernel 1.3.xx, on entry skb->data points to ddp header, @@ -975,150 +1016,18 @@ return stats; } -static unsigned short irqhitmask; - -__initfunc(static void lt_probe_handler(int irq, void *dev_id, struct pt_regs *reg_ptr)) -{ - irqhitmask |= 1<jiffies) ; /* wait for strays */ - - straymask = irqhitmask; /* pick up any strays */ - - /* if someone already owns this address, don't probe */ - if (!check_region(0x220,8)) { - inb_p(0x227); - inb_p(0x227); - x=inb_p(0x226); - timeout = jiffies+2; - while(timeout>jiffies) ; - if(straymask != irqhitmask) base = 0x220; - } - if (!check_region(0x240,8)) { - inb_p(0x247); - inb_p(0x247); - y=inb_p(0x246); - timeout = jiffies+2; - while(timeout>jiffies) ; - if(straymask != irqhitmask) base = 0x240; - } - - /* at this point, either we have an irq and the base addr, or - * there isn't any irq and we don't know the base address, but - * in either event the card is no longer latched in reset and - * the irq request line is tri-stated. - */ - - cli(); - - if (!probe3) free_irq(3,dev); - if (!probe4) free_irq(4,dev); - if (!probe9) free_irq(9,dev); - - sti(); - - irqhitmask &= ~straymask; - - irq = ffz(~irqhitmask); - if (irqhitmask != 1<=0xf0) ) base = 0x220; - } - - if (!check_region(0x240,8)) { - y = inb_p(0x240+6); - if ( (y!=0xff) && (y>=0xf0) ) base = 0x240; - } - } - - if(base) { - request_region(base,8,"ltpc"); - } else { - printk("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",x,y); - restore_flags(flags); - return -1; - } - - ltdmabuf = (unsigned char *) dma_mem_alloc(1000); - - if (ltdmabuf) ltdmacbuf = <dmabuf[800]; - - if (!ltdmabuf) { - printk("ltpc: mem alloc failed\n"); - restore_flags(flags); - return(-1); - } - - if(debug&DEBUG_VERBOSE) { - printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf); - } - - /* reset the card */ - - inb_p(base+1); - inb_p(base+3); - timeout = jiffies+2; - while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */ - inb_p(base+0); - inb_p(base+2); - inb_p(base+7); /* clear reset */ - inb_p(base+4); - inb_p(base+5); - inb_p(base+5); /* enable dma */ - inb_p(base+6); /* tri-state interrupt line */ - - timeout = jiffies+100; - - while(timeout>jiffies) { - /* wait for the card to complete initialization */ - } - - /* now, figure out which dma channel we're using */ - - /* set up both dma 1 and 3 for read call */ - - if (!request_dma(1,"ltpc")) { - - f=claim_dma_lock(); - disable_dma(1); - clear_dma_ff(1); + int dma = 0; + int timeout; + unsigned long f; + + if (!request_dma(1,"ltpc")) { + f=claim_dma_lock(); + disable_dma(1); + clear_dma_ff(1); set_dma_mode(1,DMA_MODE_WRITE); set_dma_addr(1,virt_to_bus(ltdmabuf)); set_dma_count(1,sizeof(struct lt_mem)); @@ -1142,26 +1051,26 @@ /* FIXME -- do timings better! */ - ltdmabuf[0] = 2; /* read request */ + ltdmabuf[0] = LT_READMEM; ltdmabuf[1] = 1; /* mailbox */ ltdmabuf[2] = 0; ltdmabuf[3] = 0; /* address */ ltdmabuf[4] = 0; ltdmabuf[5] = 1; /* read 0x0100 bytes */ ltdmabuf[6] = 0; /* dunno if this is necessary */ - inb_p(base+1); - inb_p(base+0); + inb_p(io+1); + inb_p(io+0); timeout = jiffies+100; while(timeout>jiffies) { - if ( 0xfa == inb_p(base+6) ) break; + if ( 0xfa == inb_p(io+6) ) break; } - inb_p(base+3); - inb_p(base+2); + inb_p(io+3); + inb_p(io+2); while(timeout>jiffies) { - if ( 0xfb == inb_p(base+6) ) break; + if ( 0xfb == inb_p(io+6) ) break; } - /* release the other dma channel */ + /* release the other dma channel (if we opened both of them) */ if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){ dma&=1; @@ -1172,31 +1081,134 @@ dma&=0x2; free_dma(1); } - - if (!dma) { /* no dma channel */ - printk("No DMA channel found on ltpc card.\n"); - restore_flags(flags); - return -1; - } - + /* fix up dma number */ dma|=1; - /* set up read */ + return dma; +} + +__initfunc(int ltpc_probe(struct device *dev)) +{ + int err; + int x=0,y=0; + int timeout; + int autoirq; + unsigned long flags; + unsigned long f; + + save_flags(flags); + + /* probe for the I/O port address */ + if (io != 0x240 && !check_region(0x220,8)) { + x = inb_p(0x220+6); + if ( (x!=0xff) && (x>=0xf0) ) io = 0x220; + } + + if (io != 0x220 && !check_region(0x240,8)) { + y = inb_p(0x240+6); + if ( (y!=0xff) && (y>=0xf0) ) io = 0x240; + } + + if(io) { + /* found it, now grab it */ + request_region(io,8,"ltpc"); + } else { + /* give up in despair */ + printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n", + x,y); + restore_flags(flags); + return -1; + } + + /* probe for the IRQ line */ + if (irq < 2) { + autoirq_setup(2); + + /* reset the interrupt line */ + inb_p(io+7); + inb_p(io+7); + /* trigger an interrupt (I hope) */ + inb_p(io+6); + + autoirq = autoirq_report(1); + + if (autoirq == 0) { + printk("ltpc: probe at %#x failed to detect IRQ line.\n", + io); + } + else { + irq = autoirq; + } + } + + /* allocate a DMA buffer */ + ltdmabuf = (unsigned char *) dma_mem_alloc(1000); + + if (ltdmabuf) ltdmacbuf = <dmabuf[800]; + + if (!ltdmabuf) { + printk("ltpc: mem alloc failed\n"); + restore_flags(flags); + return(-1); + } + + if(debug&DEBUG_VERBOSE) { + printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf); + } + + /* reset the card */ + + inb_p(io+1); + inb_p(io+3); + timeout = jiffies+2; + while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */ + inb_p(io+0); + inb_p(io+2); + inb_p(io+7); /* clear reset */ + inb_p(io+4); + inb_p(io+5); + inb_p(io+5); /* enable dma */ + inb_p(io+6); /* tri-state interrupt line */ + + timeout = jiffies+100; + + while(timeout>jiffies) { + /* wait for the card to complete initialization */ + } + + /* now, figure out which dma channel we're using, unless it's + already been specified */ + /* well, 0 is a legal DMA channel, but the LTPC card doesn't + use it... */ + if (dma == 0) { + dma = ltpc_probe_dma(io); + if (!dma) { /* no dma channel */ + printk("No DMA channel found on ltpc card.\n"); + restore_flags(flags); + return -1; + } + } + + /* print out friendly message */ if(irq) - printk("LocalTalk card found at %03x, IR%d, DMA%d.\n",base,irq,dma); + printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma); else - printk("LocalTalk card found at %03x, DMA%d. Using polled mode.\n",base,dma); - - dev->base_addr = base; + printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma); + + /* seems more logical to do this *after* probing the card... */ + err = ltpc_init(dev); + if (err) return err; + + dev->base_addr = io; dev->irq = irq; dev->dma = dma; - if(debug&DEBUG_VERBOSE) { - printk("finishing up transfer\n"); - } - + /* the card will want to send a result at this point */ + /* (I think... leaving out this part makes the kernel crash, + so I put it back in...) */ + f=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); @@ -1206,41 +1218,65 @@ enable_dma(dma); release_dma_lock(f); - (void) inb_p(base+3); - (void) inb_p(base+2); + (void) inb_p(io+3); + (void) inb_p(io+2); timeout = jiffies+100; while(timeout>jiffies) { - if( 0xf9 == inb_p(base+6)) break; + if( 0xf9 == inb_p(io+6)) break; } if(debug&DEBUG_VERBOSE) { printk("setting up timer and irq\n"); } - init_timer(<pc_timer); - ltpc_timer.function=ltpc_poll; - ltpc_timer.data = (unsigned long) dev; - if (irq) { + /* grab it and don't let go :-) */ (void) request_irq( irq, <pc_interrupt, 0, "ltpc", dev); - (void) inb_p(base+7); /* enable interrupts from board */ - (void) inb_p(base+7); /* and reset irq line */ - ltpc_timer.expires = 100; - /* poll it once per second just in case */ + (void) inb_p(io+7); /* enable interrupts from board */ + (void) inb_p(io+7); /* and reset irq line */ } else { - ltpc_timer.expires = 5; - /* polled mode -- 20 times per second */ - } - - ltpc_timer.expires += jiffies; /* 1.2 to 1.3 change... */ + /* polled mode -- 20 times per second */ + /* this is really, really slow... should it poll more often? */ + init_timer(<pc_timer); + ltpc_timer.function=ltpc_poll; + ltpc_timer.data = (unsigned long) dev; - add_timer(<pc_timer); - - restore_flags(flags); + ltpc_timer.expires = jiffies + 5; + add_timer(<pc_timer); + restore_flags(flags); + } return 0; } +/* handles "ltpc=io,irq,dma" kernel command lines */ +__initfunc(void ltpc_setup(char *str, int *ints)) +{ + if (ints[0] == 0) { + if (str && !strncmp(str, "auto", 4)) { + /* do nothing :-) */ + } + else { + /* usage message */ + printk (KERN_ERR + "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n"); + } + return; + } else { + io = ints[1]; + if (ints[0] > 1) { + irq = ints[2]; + return; + } + if (ints[0] > 2) { + dma = ints[3]; + return; + } + /* ignore any other paramters */ + } + return; +} + #ifdef MODULE static char dev_name[8]; @@ -1251,17 +1287,28 @@ 0x0, 0, 0, 0, 0, NULL, ltpc_probe }; +MODULE_PARM(debug, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); + int init_module(void) { + int err, result; + + if(io == 0) + printk(KERN_NOTICE + "ltpc: Autoprobing is not recommended for modules\n"); + /* Find a name for this unit */ - int err=dev_alloc_name(&dev_ltpc,"lt%d"); + err=dev_alloc_name(&dev_ltpc,"lt%d"); if(err<0) return err; - if (register_netdev(&dev_ltpc) != 0) { - if(debug&DEBUG_VERBOSE) printk("EIO from register_netdev\n"); - return -EIO; + if ((result = register_netdev(&dev_ltpc)) != 0) { + printk(KERN_DEBUG "could not register Localtalk-PC device\n"); + return result; } else { if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n"); return 0; @@ -1322,3 +1369,4 @@ if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n"); } #endif /* MODULE */ + diff -u --recursive --new-file v2.1.128/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.1.128/linux/drivers/net/net_init.c Tue Jun 23 10:01:23 1998 +++ linux/drivers/net/net_init.c Mon Nov 16 10:39:27 1998 @@ -41,6 +41,7 @@ #include #include #include +#include /* The network devices currently exist only in the socket namespace, so these entries are unused. The only ones that make sense are @@ -219,6 +220,21 @@ hippi_setup(tmp_dev); return tmp_dev; } + +static int hippi_neigh_setup_dev(struct device *dev, struct neigh_parms *p) +{ + /* Never send broadcast/multicast ARP messages */ + p->mcast_probes = 0; + + /* In IPv6 unicast probes are valid even on NBMA, + * because they are encapsulated in normal IPv6 protocol. + * Should be a generic flag. + */ + if (p->tbl->family != AF_INET6) + p->ucast_probes = 0; + return 0; +} + #endif void ether_setup(struct device *dev) @@ -304,6 +320,7 @@ dev->hard_header_parse = NULL; dev->hard_header_cache = NULL; dev->header_cache_update = NULL; + dev->neigh_setup = hippi_neigh_setup_dev; /* * We don't support HIPPI `ARP' for the time being, and probably @@ -317,12 +334,13 @@ dev->tx_queue_len = 25 /* 5 */; memset(dev->broadcast, 0xFF, HIPPI_ALEN); - /* New-style flags. */ - dev->flags = IFF_NODYNARP; /* - * HIPPI doesn't support - * broadcast+multicast and we only - * use static ARP tables. - */ + + /* + * HIPPI doesn't support broadcast+multicast and we only use + * static ARP tables. ARP is disabled by hippi_neigh_setup_dev. + */ + dev->flags = 0; + dev_init_buffers(dev); } #endif diff -u --recursive --new-file v2.1.128/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c --- v2.1.128/linux/drivers/net/rtl8139.c Thu Nov 12 16:21:19 1998 +++ linux/drivers/net/rtl8139.c Sun Nov 15 09:52:26 1998 @@ -56,7 +56,6 @@ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (4*HZ) -#include #ifdef MODULE #ifdef MODVERSIONS #include diff -u --recursive --new-file v2.1.128/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c --- v2.1.128/linux/drivers/net/sgiseeq.c Fri May 8 23:14:48 1998 +++ linux/drivers/net/sgiseeq.c Mon Nov 16 10:39:27 1998 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: sgiseeq.c,v 1.5 1998/05/01 01:35:40 ralf Exp $ + * $Id: sgiseeq.c,v 1.6 1998/10/14 17:29:44 ralf Exp $ */ #include @@ -88,7 +88,7 @@ /* Ptrs to the descriptors in KSEG1 uncached space. */ struct sgiseeq_rx_desc *rx_desc; struct sgiseeq_tx_desc *tx_desc; - unsigned long _padding[14]; /* Pad out to largest cache line size. */ + unsigned long _padding[30]; /* Pad out to largest cache line size. */ struct sgiseeq_rx_desc rxvector[SEEQ_RX_BUFFERS]; struct sgiseeq_tx_desc txvector[SEEQ_TX_BUFFERS]; diff -u --recursive --new-file v2.1.128/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.1.128/linux/drivers/net/shaper.c Tue Aug 18 22:02:04 1998 +++ linux/drivers/net/shaper.c Fri Nov 13 10:29:44 1998 @@ -157,7 +157,7 @@ skb->shapelatency=0; skb->shapeclock=shaper->recovery; - if(skb->shapeclockshapeclock, jiffies)) skb->shapeclock=jiffies; skb->priority=0; /* short term bug fix */ skb->shapestamp=jiffies; @@ -320,7 +320,7 @@ if(sh_debug) printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies); - if(skb->shapeclock <= jiffies + SHAPER_BURST) + if(skb->shapeclock - jiffies <= SHAPER_BURST) { /* * Pull the frame and get interrupts back on. @@ -385,10 +385,14 @@ /* * Can't open until attached. + * Also can't open until speed is set, or we'll get + * a division by zero. */ if(shaper->dev==NULL) return -ENODEV; + if(shaper->bitspersec==0) + return -EINVAL; MOD_INC_USE_COUNT; return 0; } @@ -543,6 +547,7 @@ shdev->type=dev->type; shdev->addr_len=dev->addr_len; shdev->mtu=dev->mtu; + sh->bitspersec=0; return 0; } @@ -564,7 +569,7 @@ case SHAPER_GET_DEV: if(sh->dev==NULL) return -ENODEV; - memcpy(ss->ss_name, sh->dev->name, sizeof(ss->ss_name)); + strcpy(ss->ss_name, sh->dev->name); return 0; case SHAPER_SET_SPEED: shaper_setspeed(sh,ss->ss_speed); diff -u --recursive --new-file v2.1.128/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.1.128/linux/drivers/net/sunhme.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/net/sunhme.c Mon Nov 16 10:37:28 1998 @@ -38,6 +38,9 @@ #include #include #include +#ifndef __sparc_v9__ +#include +#endif #include #include @@ -1061,14 +1064,23 @@ (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), (u32)virt_to_bus((volatile void *)skb->data)); - } else { + } else +#endif +#ifndef __sparc_v9__ + if (sparc_cpu_model == sun4d) { + __u32 va = (__u32)hp->sun4d_buffers + i * PAGE_SIZE; + + hb->happy_meal_rxd[i].rx_addr = + iounit_map_dma_page(va, skb->data, hp->happy_sbus_dev->my_bus); + hb->happy_meal_rxd[i].rx_flags = + (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); + } else #endif + { hb->happy_meal_rxd[i].rx_addr = (u32)((unsigned long) skb->data); hb->happy_meal_rxd[i].rx_flags = (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); -#ifdef CONFIG_PCI } -#endif skb_reserve(skb, RX_OFFSET); } @@ -1078,6 +1090,7 @@ HMD(("done\n")); } +#ifndef __sparc_v9__ static void sun4c_happy_meal_init_rings(struct happy_meal *hp) { struct hmeal_init_block *hb = hp->happy_block; @@ -1099,6 +1112,7 @@ hb->happy_meal_txd[i].tx_flags = 0; HMD(("done\n")); } +#endif static void happy_meal_begin_auto_negotiation(struct happy_meal *hp, struct hmeal_tcvregs *tregs) @@ -1234,9 +1248,11 @@ /* Alloc and reset the tx/rx descriptor chains. */ HMD(("happy_meal_init: to happy_meal_init_rings\n")); +#ifndef __sparc_v9__ if(sparc_cpu_model == sun4c) sun4c_happy_meal_init_rings(hp); else +#endif happy_meal_init_rings(hp, from_irq); /* Shut up the MIF. */ @@ -1681,7 +1697,6 @@ : "=r" (flags) : "r" (&this->tx_flags), "i" (ASI_PL)); #else - flush_cache_all(); flags = flip_dword(this->tx_flags); #endif if(flags & TXFLAG_OWN) @@ -1700,6 +1715,7 @@ } #endif +#ifndef __sparc_v9__ static inline void sun4c_happy_meal_tx(struct happy_meal *hp) { struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; @@ -1721,6 +1737,7 @@ hp->tx_old = elem; TXD((">")); } +#endif #ifdef RXDEBUG #define RXD(x) printk x @@ -1855,7 +1872,6 @@ : "=r" (flags) : "r" (&this->rx_flags), "i" (ASI_PL)); #else - flush_cache_all(); flags = flip_dword(this->rx_flags); /* FIXME */ #endif while(!(flags & RXFLAG_OWN)) { @@ -1949,7 +1965,6 @@ : "=r" (flags) : "r" (&this->rx_flags), "i" (ASI_PL)); #else - flush_cache_all(); flags = flip_dword(this->rx_flags); /* FIXME */ #endif } @@ -1960,6 +1975,7 @@ } #endif +#ifndef __sparc_v9__ static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev, struct hmeal_gregs *gregs) { @@ -2023,6 +2039,115 @@ RXD((">")); } +static inline void sun4d_happy_meal_rx(struct happy_meal *hp, struct device *dev, + struct hmeal_gregs *gregs) +{ + struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0]; + struct happy_meal_rxd *this; + int elem = hp->rx_new, drops = 0; + __u32 va; + + RXD(("RX<")); + this = &rxbase[elem]; + while(!(this->rx_flags & RXFLAG_OWN)) { + struct sk_buff *skb; + unsigned int flags = this->rx_flags; + int len = flags >> 16; + u16 csum = flags & RXFLAG_CSUM; + + RXD(("[%d ", elem)); + + /* Check for errors. */ + if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { + RXD(("ERR(%08x)]", flags)); + hp->net_stats.rx_errors++; + if(len < ETH_ZLEN) + hp->net_stats.rx_length_errors++; + if(len & (RXFLAG_OVERFLOW >> 16)) { + hp->net_stats.rx_over_errors++; + hp->net_stats.rx_fifo_errors++; + } + + /* Return it to the Happy meal. */ + drop_it: + hp->net_stats.rx_dropped++; + va = (__u32)hp->sun4d_buffers + elem * PAGE_SIZE; + this->rx_addr = iounit_map_dma_page(va, hp->rx_skbs[elem]->data, + hp->happy_sbus_dev->my_bus); + this->rx_flags = + (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); + goto next; + } + skb = hp->rx_skbs[elem]; + if(len > RX_COPY_THRESHOLD) { + struct sk_buff *new_skb; + + /* Now refill the entry, if we can. */ + new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + if(!new_skb) { + drops++; + goto drop_it; + } + + hp->rx_skbs[elem] = new_skb; + new_skb->dev = dev; + skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); + va = (__u32)hp->sun4d_buffers + elem * PAGE_SIZE; + rxbase[elem].rx_addr = iounit_map_dma_page(va, new_skb->data, + hp->happy_sbus_dev->my_bus); + + skb_reserve(new_skb, RX_OFFSET); + rxbase[elem].rx_flags = + (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); + + /* Trim the original skb for the netif. */ + skb_trim(skb, len); + } else { + struct sk_buff *copy_skb = dev_alloc_skb(len+2); + + if(!copy_skb) { + drops++; + goto drop_it; + } + + copy_skb->dev = dev; + skb_reserve(copy_skb, 2); + skb_put(copy_skb, len); + memcpy(copy_skb->data, skb->data, len); + + /* Reuse original ring buffer. */ + va = (__u32)hp->sun4d_buffers + elem * PAGE_SIZE; + rxbase[elem].rx_addr = iounit_map_dma_page(va, skb->data, + hp->happy_sbus_dev->my_bus); + rxbase[elem].rx_flags = + (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); + + skb = copy_skb; + } + + /* This card is _fucking_ hot... */ + if(!(csum ^ 0xffff)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + + RXD(("len=%d csum=%4x]", len, csum)); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + hp->net_stats.rx_packets++; + hp->net_stats.rx_bytes+=len; + next: + elem = NEXT_RX(elem); + this = &rxbase[elem]; + } + hp->rx_new = elem; + if(drops) + printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name); + RXD((">")); +} +#endif + static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct device *dev = (struct device *) dev_id; @@ -2157,6 +2282,50 @@ dev->interrupt = 0; HMD(("done\n")); } + +static void sun4d_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct hmeal_gregs *gregs = hp->gregs; + struct hmeal_tcvregs *tregs = hp->tcvregs; + unsigned int happy_status = hme_read32(hp, &gregs->stat); + + HMD(("happy_meal_interrupt: status=%08x ", happy_status)); + + dev->interrupt = 1; + + if(happy_status & GREG_STAT_ERRORS) { + HMD(("ERRORS ")); + if(happy_meal_is_not_so_happy(hp, gregs, /* un- */ happy_status)) { + dev->interrupt = 0; + return; + } + } + + if(happy_status & GREG_STAT_MIFIRQ) { + HMD(("MIFIRQ ")); + happy_meal_mif_interrupt(hp, gregs, tregs); + } + + if(happy_status & GREG_STAT_TXALL) { + HMD(("TXALL ")); + happy_meal_tx(hp); + } + + if(happy_status & GREG_STAT_RXTOHOST) { + HMD(("RXTOHOST ")); + sun4d_happy_meal_rx(hp, dev, gregs); + } + + if(dev->tbusy && (TX_BUFFS_AVAIL(hp) >= 0)) { + hp->dev->tbusy = 0; + mark_bh(NET_BH); + } + + dev->interrupt = 0; + HMD(("done\n")); +} #endif static int happy_meal_open(struct device *dev) @@ -2173,6 +2342,14 @@ printk("happy meal: Can't order irq %d to go.\n", dev->irq); return -EAGAIN; } + } else if (sparc_cpu_model == sun4d) { + if(request_irq(dev->irq, &sun4d_happy_meal_interrupt, + SA_SHIRQ, "HAPPY MEAL", (void *) dev)) { + HMD(("EAGAIN\n")); + printk("happy_meal(SBUS): Can't order irq %s to go.\n", + __irq_itoa(dev->irq)); + return -EAGAIN; + } } else #endif #ifdef CONFIG_PCI @@ -2327,6 +2504,7 @@ } #endif +#ifndef __sparc_v9__ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev) { struct happy_meal *hp = (struct happy_meal *) dev->priv; @@ -2383,6 +2561,59 @@ return 0; } +static int sun4d_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct happy_meal *hp = (struct happy_meal *) dev->priv; + int len, entry; + __u32 va; + + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { + int tickssofar = jiffies - dev->trans_start; + + if (tickssofar >= 40) { + printk ("%s: transmit timed out, resetting\n", dev->name); + hp->net_stats.tx_errors++; + tx_dump_log(); + printk ("%s: Happy Status %08x TX[%08x:%08x]\n", dev->name, + hme_read32(hp, &hp->gregs->stat), + hme_read32(hp, &hp->etxregs->cfg), + hme_read32(hp, &hp->bigmacregs->tx_cfg)); + happy_meal_init(hp, 0); + dev->tbusy = 0; + dev->trans_start = jiffies; + } else + tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_TBUSY, 0); + return 1; + } + + if(!TX_BUFFS_AVAIL(hp)) { + tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0); + return 1; + } + len = skb->len; + entry = hp->tx_new; + + SXD(("SX", len, entry)); + hp->tx_skbs[entry] = skb; + va = (__u32)hp->sun4d_buffers + (RX_RING_SIZE + entry) * PAGE_SIZE; + hp->happy_block->happy_meal_txd[entry].tx_addr = + iounit_map_dma_page(va, skb->data, hp->happy_sbus_dev->my_bus); + hp->happy_block->happy_meal_txd[entry].tx_flags = + (TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE)); + hp->tx_new = NEXT_TX(entry); + + /* Get it going. */ + dev->trans_start = jiffies; + hme_write32(hp, &hp->etxregs->tx_pnding, ETX_TP_DMAWAKEUP); + + if(TX_BUFFS_AVAIL(hp)) + dev->tbusy = 0; + + tx_add_log(hp, TXLOG_ACTION_TXMIT, 0); + return 0; +} +#endif + static struct net_device_stats *happy_meal_get_stats(struct device *dev) { struct happy_meal *hp = (struct happy_meal *) dev->priv; @@ -2561,11 +2792,17 @@ sparc_dvma_malloc(PAGE_SIZE, "Happy Meal Init Block", &hp->hblock_dvma); +#ifndef __sparc_v9__ if(sparc_cpu_model == sun4c) hp->sun4c_buffers = (struct hmeal_buffers *) sparc_dvma_malloc(sizeof(struct hmeal_buffers), "Happy Meal Bufs", &hp->s4c_buf_dvma); + else if (sparc_cpu_model == sun4d) + hp->sun4d_buffers = (struct hmeal_buffers *) + iounit_map_dma_init(hp->happy_sbus_dev->my_bus, + (RX_RING_SIZE + TX_RING_SIZE) * PAGE_SIZE); else +#endif hp->sun4c_buffers = 0; /* Force check of the link first time we are brought up. */ @@ -2583,9 +2820,13 @@ hp->dev = dev; dev->open = &happy_meal_open; dev->stop = &happy_meal_close; +#ifndef __sparc_v9__ if(sparc_cpu_model == sun4c) dev->hard_start_xmit = &sun4c_happy_meal_start_xmit; + else if (sparc_cpu_model == sun4d) + dev->hard_start_xmit = &sun4d_happy_meal_start_xmit; else +#endif dev->hard_start_xmit = &happy_meal_start_xmit; dev->get_stats = &happy_meal_get_stats; dev->set_multicast_list = &happy_meal_set_multicast; @@ -2684,6 +2925,11 @@ } hp->hblock_dvma = (u32) virt_to_bus(hp->happy_block); +#ifndef __sparc_v9__ + /* This case we currently need to use 'sparc_alloc_io' */ + hp->happy_block = sparc_alloc_io (hp->hblock_dvma, NULL, + PAGE_SIZE, "sunhme", 0, 0); +#endif hp->sun4c_buffers = 0; hp->linkcheck = 0; @@ -2796,6 +3042,11 @@ sparc_free_io(hp->erxregs, sizeof(struct hmeal_erxregs)); sparc_free_io(hp->bigmacregs, sizeof(struct hmeal_bigmacregs)); sparc_free_io(hp->tcvregs, sizeof(struct hmeal_tcvregs)); +#ifndef __sparc_v9__ + if (sparc_cpu_model == sun4d) + iounit_map_dma_finish(hp->happy_sbus_dev->my_bus, + (__u32)hp->sun4d_buffers, (RX_RING_SIZE + TX_RING_SIZE) * PAGE_SIZE); +#endif unregister_netdev(hp->dev); kfree(hp->dev); root_happy_dev = sunshine; diff -u --recursive --new-file v2.1.128/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h --- v2.1.128/linux/drivers/net/sunhme.h Mon Oct 5 13:13:40 1998 +++ linux/drivers/net/sunhme.h Mon Nov 16 10:37:28 1998 @@ -525,6 +525,7 @@ /* We may use this for Ultra as well, will have to see, maybe not. */ struct hmeal_buffers *sun4c_buffers; /* CPU visible address. */ +#define sun4d_buffers sun4c_buffers /* No need to make this a separate. */ __u32 s4c_buf_dvma; /* DVMA visible address. */ unsigned int happy_flags; /* Driver state flags */ @@ -664,7 +665,6 @@ { rp->rx_addr = flip_dword(addr); rp->rx_flags = flip_dword(flags); - flush_cache_all(); } extern inline void pcihme_write_txd(struct happy_meal_txd *tp, @@ -673,7 +673,6 @@ { tp->tx_addr = flip_dword(addr); tp->tx_flags = flip_dword(flags); - flush_cache_all(); } #endif /* def __sparc_v9__ */ diff -u --recursive --new-file v2.1.128/linux/drivers/net/syncppp.c linux/drivers/net/syncppp.c --- v2.1.128/linux/drivers/net/syncppp.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/syncppp.c Fri Nov 13 10:29:44 1998 @@ -859,6 +859,9 @@ if(dev->flags&IFF_UP) return -EBUSY; + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + switch(cmd) { case SPPPIOCCISCO: @@ -872,11 +875,7 @@ case SPPPIOCDEBUG: sp->pp_flags&=~PP_DEBUG; if(ifr->ifr_flags) - { - if(!capable(CAP_NET_ADMIN)) - return -EPERM; sp->pp_flags|=PP_DEBUG; - } break; default: return -EINVAL; diff -u --recursive --new-file v2.1.128/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.1.128/linux/drivers/net/yellowfin.c Thu Nov 12 16:21:20 1998 +++ linux/drivers/net/yellowfin.c Sun Nov 15 09:52:26 1998 @@ -63,7 +63,6 @@ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT ((2000*HZ)/1000) -#include #ifdef MODULE #ifdef MODVERSIONS #include diff -u --recursive --new-file v2.1.128/linux/drivers/pci/pcisyms.c linux/drivers/pci/pcisyms.c --- v2.1.128/linux/drivers/pci/pcisyms.c Thu Nov 12 16:21:20 1998 +++ linux/drivers/pci/pcisyms.c Sun Nov 15 09:52:26 1998 @@ -6,6 +6,7 @@ * Copyright 1998 Martin Mares */ +#include #include #include diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/Config.in linux/drivers/sbus/audio/Config.in --- v2.1.128/linux/drivers/sbus/audio/Config.in Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/audio/Config.in Wed Nov 18 09:06:05 1998 @@ -10,4 +10,5 @@ dep_tristate ' AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO dep_tristate ' CS4231 Lowlevel Driver' CONFIG_SPARCAUDIO_CS4231 $CONFIG_SPARCAUDIO dep_tristate ' DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO + dep_tristate ' Dummy Lowlevel Driver' CONFIG_SPARCAUDIO_DUMMY $CONFIG_SPARCAUDIO fi diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/Makefile linux/drivers/sbus/audio/Makefile --- v2.1.128/linux/drivers/sbus/audio/Makefile Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/audio/Makefile Wed Nov 18 09:06:05 1998 @@ -16,47 +16,57 @@ M_OBJS := ifeq ($(CONFIG_SPARCAUDIO),y) -SBUS_AUDIO=y +M=y else ifeq ($(CONFIG_SPARCAUDIO),m) - SBUS_AUDIO_MODULE=y + MM=y endif endif ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y) -SBUS_AUDIO=y +M=y OX_OBJS += amd7930.o else ifeq ($(CONFIG_SPARCAUDIO_AMD7930),m) - SBUS_AUDIO_MODULE=y + MM=y MX_OBJS += amd7930.o endif endif ifeq ($(CONFIG_SPARCAUDIO_CS4231),y) -SBUS_AUDIO=y +M=y O_OBJS += cs4231.o else ifeq ($(CONFIG_SPARCAUDIO_CS4231),m) - SBUS_AUDIO_MODULE=y + MM=y M_OBJS += cs4231.o endif endif ifeq ($(CONFIG_SPARCAUDIO_DBRI),y) -SBUS_AUDIO=y -O_OBJS += dbri.o +M=y +OX_OBJS += dbri.o else ifeq ($(CONFIG_SPARCAUDIO_DBRI),m) - SBUS_AUDIO_MODULE=y - M_OBJS += dbri.o + MM=y + MX_OBJS += dbri.o endif endif -ifdef SBUS_AUDIO +ifeq ($(CONFIG_SPARCAUDIO_DUMMY),y) +M=y +O_OBJS += dmy.o +else + ifeq ($(CONFIG_SPARCAUDIO_DUMMY),m) + MM=y + M_OBJS += dmy.o + endif +endif + +ifdef M OX_OBJS += audio.o else - ifdef SBUS_AUDIO_MODULE + ifdef MM MX_OBJS += audio.o endif endif diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c --- v2.1.128/linux/drivers/sbus/audio/amd7930.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/audio/amd7930.c Wed Nov 18 09:06:05 1998 @@ -13,6 +13,74 @@ * * Thanks to the AMD engineer who was able to get us the AMD79C30 * databook which has all the programming information and gain tables. + * + * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the + * SparcStation 1+. The chip provides microphone and speaker interfaces + * which provide mono-channel audio at 8K samples per second via either + * 8-bit A-law or 8-bit mu-law encoding. Also, the chip features an + * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface, + * which performs basic D channel LAPD processing and provides raw + * B channel data. The digital audio channel, the two ISDN B channels, + * and two 64 Kbps channels to the microprocessor are all interconnected + * via a multiplexer. + * + * This driver interfaces to the Linux HiSax ISDN driver, which performs + * all high-level Q.921 and Q.931 ISDN functions. The file is not + * itself a hardware driver; rather it uses functions exported by + * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio), + * allowing the chip to be simultaneously used for both audio and ISDN data. + * The hardware driver does _no_ buffering, but provides several callbacks + * which are called during interrupt service and should therefore run quickly. + * + * D channel transmission is performed by passing the hardware driver the + * address and size of an skb's data area, then waiting for a callback + * to signal successful transmission of the packet. A task is then + * queued to notify the HiSax driver that another packet may be transmitted. + * + * D channel reception is quite simple, mainly because of: + * 1) the slow speed of the D channel - 16 kbps, and + * 2) the presence of an 8- or 32-byte (depending on chip version) FIFO + * to buffer the D channel data on the chip + * Worst case scenario of back-to-back packets with the 8 byte buffer + * at 16 kbps yields an service time of 4 ms - long enough to preclude + * the need for fancy buffering. We queue a background task that copies + * data out of the receive buffer into an skb, and the hardware driver + * simply does nothing until we're done with the receive buffer and + * reset it for a new packet. + * + * B channel processing is more complex, because of: + * 1) the faster speed - 64 kbps, + * 2) the lack of any on-chip buffering (it interrupts for every byte), and + * 3) the lack of any chip support for HDLC encapsulation + * + * The HiSax driver can put each B channel into one of three modes - + * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay), + * and L1_MODE_HDLC (HDLC encapsulation by low-level driver). + * L1_MODE_HDLC is the most common, used for almost all "pure" digital + * data sessions. L1_MODE_TRANS is used for ISDN audio. + * + * HDLC B channel transmission is performed via a large buffer into + * which the skb is copied while performing HDLC bit-stuffing. A CRC + * is computed and attached to the end of the buffer, which is then + * passed to the low-level routines for raw transmission. Once + * transmission is complete, the hardware driver is set to enter HDLC + * idle by successive transmission of mark (all 1) bytes, waiting for + * the ISDN driver to prepare another packet for transmission and + * deliver it. + * + * HDLC B channel reception is performed via an X-byte ring buffer + * divided into N sections of X/N bytes each. Defaults: X=256 bytes, N=4. + * As the hardware driver notifies us that each section is full, we + * hand it the next section and schedule a background task to peruse + * the received section, bit-by-bit, with an HDLC decoder. As + * packets are detected, they are copied into a large buffer while + * decoding HDLC bit-stuffing. The ending CRC is verified, and if + * it is correct, we alloc a new skb of the correct length (which we + * now know), copy the packet into it, and hand it to the upper layers. + * Optimization: for large packets, we hand the buffer (which also + * happens to be an skb) directly to the upper layer after an skb_trim, + * and alloc a new large buffer for future packets, thus avoiding a copy. + * Then we return to HDLC processing; state is saved between calls. */ #include @@ -22,6 +90,8 @@ #include #include #include +#include +#include #include #include #include @@ -32,6 +102,12 @@ #include #include "amd7930.h" +#if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff +#include "../../isdn/hisax/hisax.h" +#include "../../isdn/hisax/isdnl1.h" +#include "../../isdn/hisax/foreign.h" +#endif + #define MAX_DRIVERS 1 static struct sparcaudio_driver drivers[MAX_DRIVERS]; @@ -274,12 +350,6 @@ map->gr = gx_coeff[level]; } - /* force output to speaker for now */ - map->mmr2 |= AM_MAP_MMR2_LS; - - /* input from external microphone */ - map->mmr2 |= AM_MAP_MMR2_AINB; - amd7930_write_map(drv); } @@ -296,9 +366,6 @@ * driver, since D.output_callback_arg is assumed to be a certain struct ptr */ -#include "../../isdn/hisax/hisax.h" -#include "../../isdn/hisax/isdnl1.h" - #ifdef L2FRAME_DEBUG inline void debug_info(struct amd7930_info *info, char c) { @@ -453,7 +520,7 @@ channel->input_count = 0; if (channel->input_callback) (*channel->input_callback) - (channel->input_callback_arg); + (channel->input_callback_arg, 1); } } } @@ -498,16 +565,7 @@ static int amd7930_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) { - struct amd7930_info *info = (struct amd7930_info *)drv->private; - - /* Set the default audio parameters. */ - info->rgain = 128; - info->pgain = 200; - info->mgain = 0; - amd7930_update_map(drv); - MOD_INC_USE_COUNT; - return 0; } @@ -640,6 +698,21 @@ return AUDIO_DEV_AMD; } +static int amd7930_get_formats(struct sparcaudio_driver *drv) +{ + return (AFMT_MU_LAW | AFMT_A_LAW); +} + +static int amd7930_get_output_ports(struct sparcaudio_driver *drv) +{ + return (AUDIO_SPEAKER | AUDIO_HEADPHONE); +} + +static int amd7930_get_input_ports(struct sparcaudio_driver *drv) +{ + return (AUDIO_MICROPHONE); +} + static int amd7930_set_output_volume(struct sparcaudio_driver *drv, int vol) { struct amd7930_info *info = (struct amd7930_info *)drv->private; @@ -681,6 +754,13 @@ return 0; } +static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + return info->mgain; +} + /* Cheats. The amd has the minimum capabilities we support */ static int amd7930_get_output_balance(struct sparcaudio_driver *drv) { @@ -697,25 +777,68 @@ return AUDIO_MIN_PLAY_CHANNELS; } +static int amd7930_set_output_channels(struct sparcaudio_driver *drv, + int value) +{ + return (value == AUDIO_MIN_PLAY_CHANNELS) ? 0 : -EINVAL; +} + static int amd7930_get_input_channels(struct sparcaudio_driver *drv) { return AUDIO_MIN_REC_CHANNELS; } +static int +amd7930_set_input_channels(struct sparcaudio_driver *drv, int value) +{ + return (value == AUDIO_MIN_REC_CHANNELS) ? 0 : -EINVAL; +} + static int amd7930_get_output_precision(struct sparcaudio_driver *drv) { return AUDIO_MIN_PLAY_PRECISION; } +static int +amd7930_set_output_precision(struct sparcaudio_driver *drv, int value) +{ + return (value == AUDIO_MIN_PLAY_PRECISION) ? 0 : -EINVAL; +} + static int amd7930_get_input_precision(struct sparcaudio_driver *drv) { return AUDIO_MIN_REC_PRECISION; } -/* This should eventually be made to DTRT, whatever that ends up */ +static int +amd7930_set_input_precision(struct sparcaudio_driver *drv, int value) +{ + return (value == AUDIO_MIN_REC_PRECISION) ? 0 : -EINVAL; +} + static int amd7930_get_output_port(struct sparcaudio_driver *drv) { - return AUDIO_SPEAKER; /* some of these have only HEADPHONE */ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + if (info->map.mmr2 & AM_MAP_MMR2_LS) + return AUDIO_SPEAKER; + return AUDIO_HEADPHONE; +} + +static int amd7930_set_output_port(struct sparcaudio_driver *drv, int value) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + switch (value) { + case AUDIO_HEADPHONE: + info->map.mmr2 &= ~AM_MAP_MMR2_LS; + break; + case AUDIO_SPEAKER: + info->map.mmr2 |= AM_MAP_MMR2_LS; + break; + default: + return -EINVAL; + } + amd7930_update_map(drv); + return 0; } /* Only a microphone here, so no troubles */ @@ -724,15 +847,31 @@ return AUDIO_MICROPHONE; } -/* This chip also supports AUDIO_ENCODING_ALAW, add support later */ -static int amd7930_get_output_encoding(struct sparcaudio_driver *drv) -{ - return AUDIO_ENCODING_ULAW; -} - -static int amd7930_get_input_encoding(struct sparcaudio_driver *drv) +static int amd7930_get_encoding(struct sparcaudio_driver *drv) { - return AUDIO_ENCODING_ULAW; + struct amd7930_info *info = (struct amd7930_info *)drv->private; + if (info->map.mmr1 & AM_MAP_MMR1_ALAW) + return AUDIO_ENCODING_ALAW; + return AUDIO_ENCODING_ULAW; +} + +static int +amd7930_set_encoding(struct sparcaudio_driver *drv, int value) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + switch (value) { + case AUDIO_ENCODING_ULAW: + info->map.mmr1 &= ~AM_MAP_MMR1_ALAW; + break; + case AUDIO_ENCODING_ALAW: + info->map.mmr1 |= AM_MAP_MMR1_ALAW; + break; + default: + return -EINVAL; + } + amd7930_update_map(drv); + return 0; } /* This is what you get. Take it or leave it */ @@ -741,31 +880,55 @@ return AMD7930_RATE; } -static int amd7930_get_input_rate(struct sparcaudio_driver *drv) +static int +amd7930_set_output_rate(struct sparcaudio_driver *drv, int value) { - return AMD7930_RATE; + return (value == AMD7930_RATE) ? 0 : -EINVAL; } -static int amd7930_get_output_muted(struct sparcaudio_driver *drv) +static int amd7930_get_input_rate(struct sparcaudio_driver *drv) { - return 0; + return AMD7930_RATE; } -static int amd7930_get_output_ports(struct sparcaudio_driver *drv) +static int +amd7930_set_input_rate(struct sparcaudio_driver *drv, int value) { - return AUDIO_SPEAKER | AUDIO_HEADPHONE; + return (value == AMD7930_RATE) ? 0 : -EINVAL; } -static int amd7930_get_input_ports(struct sparcaudio_driver *drv) +static int amd7930_get_output_muted(struct sparcaudio_driver *drv) { - return AUDIO_MICROPHONE; + return 0; } -static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv) +static void amd7930_loopback(struct sparcaudio_driver *drv, unsigned int value) { - struct amd7930_info *info = (struct amd7930_info *)drv->private; + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + if (value) + info->map.mmr1 |= AM_MAP_MMR1_LOOPBACK; + else + info->map.mmr1 &= ~AM_MAP_MMR1_LOOPBACK; + amd7930_update_map(drv); + return; +} + +static int amd7930_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg, + struct sparcaudio_driver *drv) +{ + int retval = 0; + + switch (cmd) { + case AUDIO_DIAG_LOOPBACK: + amd7930_loopback(drv, (unsigned int)arg); + break; + default: + retval = -EINVAL; + } - return info->mgain; + return retval; } @@ -909,8 +1072,8 @@ * */ - -int amd7930_get_irqnum(int dev) +#if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff +static int amd7930_get_irqnum(int dev) { struct amd7930_info *info; @@ -923,7 +1086,7 @@ return info->irq; } -int amd7930_get_liu_state(int dev) +static int amd7930_get_liu_state(int dev) { struct amd7930_info *info; @@ -936,7 +1099,7 @@ return info->liu_state; } -void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg) +static void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg) { struct amd7930_info *info; register unsigned long flags; @@ -971,7 +1134,7 @@ restore_flags(flags); } -void amd7930_liu_activate(int dev, int priority) +static void amd7930_liu_activate(int dev, int priority) { struct amd7930_info *info; register unsigned long flags; @@ -1003,7 +1166,7 @@ restore_flags(flags); } -void amd7930_liu_deactivate(int dev) +static void amd7930_liu_deactivate(int dev) { struct amd7930_info *info; register unsigned long flags; @@ -1024,8 +1187,8 @@ restore_flags(flags); } -void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count, - void (*callback)(void *, int), void *callback_arg) +static void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count, + void (*callback)(void *, int), void *callback_arg) { struct amd7930_info *info; register unsigned long flags; @@ -1069,9 +1232,9 @@ restore_flags(flags); } -void amd7930_drecv(int dev, __u8 *buffer, unsigned int size, - void (*callback)(void *, int, unsigned int), - void *callback_arg) +static void amd7930_drecv(int dev, __u8 *buffer, unsigned int size, + void (*callback)(void *, int, unsigned int), + void *callback_arg) { struct amd7930_info *info; register unsigned long flags; @@ -1115,7 +1278,8 @@ restore_flags(flags); } -int amd7930_bopen(int dev, int chan, u_char xmit_idle_char) +static int amd7930_bopen(int dev, unsigned int chan, + int mode, u_char xmit_idle_char) { struct amd7930_info *info; register unsigned long flags; @@ -1124,6 +1288,10 @@ return -1; } + if (mode == L1_MODE_HDLC) { + return -1; + } + info = (struct amd7930_info *) drivers[dev].private; save_and_cli(flags); @@ -1167,7 +1335,7 @@ return 0; } -void amd7930_bclose(int dev, int chan) +static void amd7930_bclose(int dev, unsigned int chan) { struct amd7930_info *info; register unsigned long flags; @@ -1202,8 +1370,9 @@ restore_flags(flags); } -void amd7930_bxmit(int dev, int chan, __u8 * buffer, unsigned long count, - void (*callback)(void *), void *callback_arg) +static void amd7930_bxmit(int dev, unsigned int chan, + __u8 * buffer, unsigned long count, + void (*callback)(void *, int), void *callback_arg) { struct amd7930_info *info; struct amd7930_channel *Bchan; @@ -1228,8 +1397,10 @@ } } -void amd7930_brecv(int dev, int chan, __u8 * buffer, unsigned long size, - void (*callback)(void *), void *callback_arg) +static void amd7930_brecv(int dev, unsigned int chan, + __u8 * buffer, unsigned long size, + void (*callback)(void *, int, unsigned int), + void *callback_arg) { struct amd7930_info *info; struct amd7930_channel *Bchan; @@ -1254,17 +1425,21 @@ } } -EXPORT_SYMBOL(amd7930_get_irqnum); -EXPORT_SYMBOL(amd7930_get_liu_state); -EXPORT_SYMBOL(amd7930_liu_init); -EXPORT_SYMBOL(amd7930_liu_activate); -EXPORT_SYMBOL(amd7930_liu_deactivate); -EXPORT_SYMBOL(amd7930_dxmit); -EXPORT_SYMBOL(amd7930_drecv); -EXPORT_SYMBOL(amd7930_bopen); -EXPORT_SYMBOL(amd7930_bclose); -EXPORT_SYMBOL(amd7930_bxmit); -EXPORT_SYMBOL(amd7930_brecv); +struct foreign_interface amd7930_foreign_interface = { + amd7930_get_irqnum, + amd7930_get_liu_state, + amd7930_liu_init, + amd7930_liu_activate, + amd7930_liu_deactivate, + amd7930_dxmit, + amd7930_drecv, + amd7930_bopen, + amd7930_bclose, + amd7930_bxmit, + amd7930_brecv +}; +EXPORT_SYMBOL(amd7930_foreign_interface); +#endif /* @@ -1274,7 +1449,7 @@ static struct sparcaudio_operations amd7930_ops = { amd7930_open, amd7930_release, - NULL, /* amd7930_ioctl */ + amd7930_ioctl, amd7930_start_output, amd7930_stop_output, amd7930_start_input, @@ -1290,31 +1465,44 @@ amd7930_get_output_balance, NULL, /* amd7930_set_input_balance */ amd7930_get_input_balance, - NULL, /* amd7930_set_output_channels */ + amd7930_set_output_channels, amd7930_get_output_channels, - NULL, /* amd7930_set_input_channels */ + amd7930_set_input_channels, amd7930_get_input_channels, - NULL, /* amd7930_set_output_precision */ + amd7930_set_output_precision, amd7930_get_output_precision, - NULL, /* amd7930_set_input_precision */ + amd7930_set_input_precision, amd7930_get_input_precision, - NULL, /* amd7930_set_output_port */ + amd7930_set_output_port, amd7930_get_output_port, NULL, /* amd7930_set_input_port */ amd7930_get_input_port, - NULL, /* amd7930_set_output_encoding */ - amd7930_get_output_encoding, - NULL, /* amd7930_set_input_encoding */ - amd7930_get_input_encoding, - NULL, /* amd7930_set_output_rate */ + amd7930_set_encoding, + amd7930_get_encoding, + amd7930_set_encoding, + amd7930_get_encoding, + amd7930_set_output_rate, amd7930_get_output_rate, - NULL, /* amd7930_set_input_rate */ + amd7930_set_input_rate, amd7930_get_input_rate, amd7930_sunaudio_getdev_sunos, amd7930_get_output_ports, amd7930_get_input_ports, - NULL, /* amd7930_set_output_muted */ + NULL, /* amd7930_set_output_muted */ amd7930_get_output_muted, + NULL, /* amd7930_set_output_pause */ + NULL, /* amd7930_get_output_pause */ + NULL, /* amd7930_set_input_pause */ + NULL, /* amd7930_get_input_pause */ + NULL, /* amd7930_set_output_samples */ + NULL, /* amd7930_get_output_samples */ + NULL, /* amd7930_set_input_samples */ + NULL, /* amd7930_get_input_samples */ + NULL, /* amd7930_set_output_error */ + NULL, /* amd7930_get_output_error */ + NULL, /* amd7930_set_input_error */ + NULL, /* amd7930_get_input_error */ + amd7930_get_formats, }; /* Attach to an amd7930 chip given its PROM node. */ @@ -1373,9 +1561,17 @@ memset(&info->map, 0, sizeof(info->map)); info->map.mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER | AM_MAP_MMR1_GR | AM_MAP_MMR1_STG; + /* Start out with speaker, microphone */ + info->map.mmr2 |= (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB); + + /* Set the default audio parameters. */ + info->rgain = 128; + info->pgain = 200; + info->mgain = 0; + amd7930_update_map(drv); /* Register the amd7930 with the midlevel audio driver. */ - err = register_sparcaudio_driver(drv); + err = register_sparcaudio_driver(drv, 1); if (err < 0) { printk(KERN_ERR "amd7930: unable to register\n"); disable_irq(info->irq); @@ -1399,7 +1595,7 @@ { struct amd7930_info *info = (struct amd7930_info *)drv->private; - unregister_sparcaudio_driver(drv); + unregister_sparcaudio_driver(drv, 1); amd7930_idle(info); disable_irq(info->irq); free_irq(info->irq, drv); diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/amd7930.h linux/drivers/sbus/audio/amd7930.h --- v2.1.128/linux/drivers/sbus/audio/amd7930.h Mon Jan 12 15:15:45 1998 +++ linux/drivers/sbus/audio/amd7930.h Wed Nov 18 09:06:05 1998 @@ -14,26 +14,7 @@ #define _AMD7930_H_ #include - -/* Exported ISDN functions */ - -int amd7930_get_irqnum(int dev); -int amd7930_get_liu_state(int dev); -void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg); -void amd7930_liu_activate(int dev, int priority); -void amd7930_liu_deactivate(int dev); -void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count, - void (*callback)(void *, int), void *callback_arg); -void amd7930_drecv(int dev, __u8 *buffer, unsigned int size, - void (*callback)(void *, int, unsigned int), - void *callback_arg); -int amd7930_bopen(int dev, int chan, u_char xmit_idle_char); -void amd7930_bclose(int dev, int chan); -void amd7930_bxmit(int dev, int chan, __u8 * buffer, unsigned long count, - void (*callback)(void *), void *callback_arg); -void amd7930_brecv(int dev, int chan, __u8 * buffer, unsigned long size, - void (*callback)(void *), void *callback_arg); - +#include /* Register interface presented to the CPU by the amd7930. */ struct amd7930 diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.1.128/linux/drivers/sbus/audio/audio.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/audio/audio.c Wed Nov 18 09:06:05 1998 @@ -1,13 +1,17 @@ /* * drivers/sbus/audio/audio.c * - * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu) - * Copyright (C) 1997 Derrick J. Brashear (shadow@dementia.org) + * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * Copyright (C) 1997,1998 Derrick J. Brashear (shadow@dementia.org) * Copyright (C) 1997 Brent Baccala (baccala@freesoft.org) * * Mixer code adapted from code contributed by and * Copyright (C) 1998 Michael Mraka (michael@fi.muni.cz) + * The mixer code cheats; Sparc hardware doesn't generally allow independent + * line control, and this fakes it badly. * + * SNDCTL_DSP_SETFMT based on code contributed by + * Ion Badulescu (ionut@moisil.cs.columbia.edu) * * This is the audio midlayer that sits between the VFS character * devices and the low-level audio hardware device drivers. @@ -26,191 +30,345 @@ #include #include #include -#include +#include +#include #include #include +#undef __AUDIO_DEBUG +#define __AUDIO_ERROR +#undef __AUDIO_TRACE +#ifdef __AUDIO_DEBUG +#define dprintk(x) printk x +#else +#define dprintk(x) +#endif +#ifdef __AUDIO_ERROR +#define eprintk(x) printk x +#else +#define eprintk(x) +#endif +#ifdef __AUDIO_TRACE +#define tprintk(x) printk x +#else +#define tprintk(x) +#endif -/* - * Low-level driver interface. - */ +static short lis_get_elist_ent( strevent_t *list, pid_t pid ); +static int lis_add_to_elist( strevent_t **list, pid_t pid, short events ); +static int lis_del_from_elist( strevent_t **list, pid_t pid, short events ); +static void lis_free_elist( strevent_t **list); +static void kill_procs( struct strevent *elist, int sig, short e); + +static struct sparcaudio_driver *drivers[SPARCAUDIO_MAX_DEVICES] = {NULL}; + +/* This crap to be pulled off into a local include file */ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 + +#define COPY_IN(arg, get) verify_area(VERIFY_READ, (void *)arg, sizeof(long)); memcpy_fromfs(&get, (long *)arg, sizeof(get)); +#define COPY_OUT(arg, ret) verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); memcpy_tofs((long *)arg, &ret, sizeof(ret)); +#define copy_to_user memcpy_tofs +#define copy_from_user memcpy_fromfs +#define signal_pending(x) (((x)->signal) & ~((x)->blocked)) + +#else -/* We only support one low-level audio driver currently. */ -static struct sparcaudio_driver *driver = NULL; +#include +#include +#define COPY_IN(arg, get) get_user(get, (int *)arg) +#define COPY_OUT(arg, ret) put_user(ret, (int *)arg) +#define sparcaudio_release_ret sparcaudio_release +#define sparcaudioctl_release_ret sparcaudioctl_release +#define sparcaudio_select sparcaudio_poll -int register_sparcaudio_driver(struct sparcaudio_driver *drv) +#endif + +int register_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex) { - int i; + int i, dev; - /* If a driver is already present, don't allow the register. */ - if (driver) - return -EIO; + /* If we've used up SPARCAUDIO_MAX_DEVICES, fail */ + for (dev = 0; dev < SPARCAUDIO_MAX_DEVICES; dev++) { + if (drivers[dev] == NULL) { + break; + } + } + if (drivers[dev]) { + return -EIO; + } /* Ensure that the driver has a proper operations structure. */ - if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output) + if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output || + !drv->ops->start_input || !drv->ops->stop_input) return -EINVAL; - /* Setup the circular queues of output and input buffers - * - * Each buffer is a single page, but output buffers might - * be partially filled (by a write with count < 4096), - * so each output buffer also has a paired output size. - * - * Input buffers, on the other hand, always fill completely, - * so we don't need input counts - each contains 4096 - * bytes of audio data. - * - * TODO: Make number of input/output buffers tunable parameters - */ - - drv->num_output_buffers = 32; - drv->playing_count = 0; - drv->output_front = 0; - drv->output_rear = 0; - drv->output_count = 0; - drv->output_active = 0; - drv->output_buffers = kmalloc(drv->num_output_buffers * sizeof(__u8 *), GFP_KERNEL); - drv->output_sizes = kmalloc(drv->num_output_buffers * sizeof(size_t), GFP_KERNEL); - if (!drv->output_buffers || !drv->output_sizes) goto kmalloc_failed1; - - /* Allocate the pages for each output buffer. */ - for (i = 0; i < drv->num_output_buffers; i++) { - drv->output_buffers[i] = (void *) __get_free_page(GFP_KERNEL); - if (!drv->output_buffers[i]) goto kmalloc_failed2; - } + /* Setup the circular queues of output and input buffers + * + * Each buffer is a single page, but output buffers might + * be partially filled (by a write with count < output_buffer_size), + * so each output buffer also has a paired output size. + * + * Input buffers, on the other hand, always fill completely, + * so we don't need input counts - each contains input_buffer_size + * bytes of audio data. + * + * TODO: Make number of input/output buffers tunable parameters + */ + + drv->num_output_buffers = 8; + drv->output_buffer_size = (4096 * 2); + drv->playing_count = 0; + drv->output_offset = 0; + drv->output_eof = 0; + drv->output_front = 0; + drv->output_rear = 0; + drv->output_count = 0; + drv->output_active = 0; + drv->output_buffers = kmalloc(drv->num_output_buffers * + sizeof(__u8 *), GFP_KERNEL); + drv->output_sizes = kmalloc(drv->num_output_buffers * + sizeof(size_t), GFP_KERNEL); + drv->output_notify = kmalloc(drv->num_output_buffers * + sizeof(char), GFP_KERNEL); + if (!drv->output_buffers || !drv->output_sizes || !drv->output_notify) + goto kmalloc_failed1; + + drv->output_buffer = kmalloc((drv->output_buffer_size * + drv->num_output_buffers), + GFP_KERNEL); + if (!drv->output_buffer) goto kmalloc_failed2; + + /* Allocate the pages for each output buffer. */ + for (i = 0; i < drv->num_output_buffers; i++) { + drv->output_buffers[i] = (void *)(drv->output_buffer + + (i * drv->output_buffer_size)); + drv->output_sizes[i] = 0; + drv->output_notify[i] = 0; + } - /* Setup the circular queue of input buffers. */ - drv->num_input_buffers = 32; - drv->recording_count = 0; - drv->input_front = 0; - drv->input_rear = 0; - drv->input_count = 0; - drv->input_active = 0; - drv->input_buffers = kmalloc(drv->num_input_buffers * sizeof(__u8 *), GFP_KERNEL); - if (!drv->input_buffers) goto kmalloc_failed3; - - /* Allocate the pages for each input buffer. */ - for (i = 0; i < drv->num_input_buffers; i++) { - drv->input_buffers[i] = (void *) __get_free_page(GFP_KERNEL); - if (!drv->input_buffers[i]) goto kmalloc_failed4; + /* Setup the circular queue of input buffers. */ + drv->num_input_buffers = 8; + drv->input_buffer_size = (4096 * 2); + drv->recording_count = 0; + drv->input_front = 0; + drv->input_rear = 0; + drv->input_count = 0; + drv->input_offset = 0; + drv->input_size = 0; + drv->input_active = 0; + drv->input_buffers = kmalloc(drv->num_input_buffers * sizeof(__u8 *), + GFP_KERNEL); + drv->input_sizes = kmalloc(drv->num_input_buffers * + sizeof(size_t), GFP_KERNEL); + if (!drv->input_buffers || !drv->input_sizes) goto kmalloc_failed3; + + /* Allocate the pages for each input buffer. */ + if (duplex == 1) { + drv->input_buffer = kmalloc((drv->input_buffer_size * + drv->num_input_buffers), + GFP_KERNEL); + if (!drv->input_buffer) goto kmalloc_failed4; + + for (i = 0; i < drv->num_input_buffers; i++) { + drv->input_buffers[i] = (void *)(drv->input_buffer + + (i * drv->input_buffer_size)); + } + } else { + if (duplex == 2) { + drv->input_buffer = drv->output_buffer; + drv->input_buffer_size = drv->output_buffer_size; + drv->num_input_buffers = drv->num_output_buffers; + for (i = 0; i < drv->num_input_buffers; i++) + drv->input_buffers[i] = drv->output_buffers[i]; + } else { + for (i = 0; i < drv->num_input_buffers; i++) + drv->input_buffers[i] = NULL; + } } + /* Take note of our duplexity */ + drv->duplex = duplex; + /* Ensure that the driver is marked as not being open. */ drv->flags = 0; MOD_INC_USE_COUNT; - driver = drv; - return 0; + /* Take driver slot, note which we took */ + drv->index = dev; + drivers[dev] = drv; + return 0; kmalloc_failed4: - for (i--; i >= 0; i--) - free_page((unsigned long) drv->input_buffers[i]); + kfree(drv->input_buffer); kmalloc_failed3: - if (drv->input_buffers) - kfree(drv->input_buffers); - i = drv->num_output_buffers; + if (drv->input_sizes) + kfree(drv->input_sizes); + if (drv->input_buffers) + kfree(drv->input_buffers); + i = drv->num_output_buffers; kmalloc_failed2: - for (i--; i >= 0; i--) - free_page((unsigned long) drv->output_buffers[i]); + kfree(drv->output_buffer); kmalloc_failed1: - if (drv->output_buffers) - kfree(drv->output_buffers); - if (drv->output_sizes) - kfree(drv->output_sizes); + if (drv->output_buffers) + kfree(drv->output_buffers); + if (drv->output_sizes) + kfree(drv->output_sizes); + if (drv->output_notify) + kfree(drv->output_notify); - return -ENOMEM; + return -ENOMEM; } -int unregister_sparcaudio_driver(struct sparcaudio_driver *drv) +int unregister_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex) { - int i; - - /* Make sure that the current driver is unregistering. */ - if (driver != drv) + /* Figure out which driver is unregistering */ + if (drivers[drv->index] != drv) return -EIO; /* Deallocate the queue of output buffers. */ - for (i = 0; i < driver->num_output_buffers; i++) - free_page((unsigned long) driver->output_buffers[i]); - kfree(driver->output_buffers); - kfree(driver->output_sizes); - - /* Deallocate the queue of input buffers. */ - for (i = 0; i < driver->num_input_buffers; i++) - free_page((unsigned long) driver->input_buffers[i]); - kfree(driver->input_buffers); + kfree(drv->output_buffer); + kfree(drv->output_buffers); + kfree(drv->output_sizes); + kfree(drv->output_notify); + + /* Deallocate the queue of input buffers. */ + if (duplex == 1) { + kfree(drv->input_buffer); + kfree(drv->input_sizes); + } + kfree(drv->input_buffers); + + if (&(drv->sd_siglist) != NULL) + lis_free_elist( &(drv->sd_siglist) ); MOD_DEC_USE_COUNT; - driver = NULL; + /* Null the appropriate driver */ + drivers[drv->index] = NULL; + return 0; } -void sparcaudio_output_done(struct sparcaudio_driver * drv, int reclaim) +void sparcaudio_output_done(struct sparcaudio_driver * drv, int status) { - /* Reclaim a buffer unless it's still in the DMA pipe */ - if (reclaim) { - if (drv->output_count > 0) - drv->output_count--; - else - if (drv->playing_count > 0) - drv->playing_count--; - } else - drv->playing_count++; - - /* Point the queue after the "done" buffer. */ - drv->output_size -= drv->output_sizes[drv->output_front]; - drv->output_front = (drv->output_front + 1) % drv->num_output_buffers; - - /* If the output queue is empty, shutdown the driver. */ - if (drv->output_count == 0) { - if (drv->playing_count == 0) { - /* Stop the lowlevel driver from outputing. */ - drv->ops->stop_output(drv); - drv->output_active = 0; - - /* Wake up any waiting writers or syncers and return. */ - wake_up_interruptible(&drv->output_write_wait); - wake_up_interruptible(&drv->output_drain_wait); - return; - } - } - - /* If we got back a buffer, see if anyone wants to write to it */ - if (reclaim || ((drv->output_count + drv->playing_count) - < drv->num_output_buffers)) - wake_up_interruptible(&drv->output_write_wait); + /* + * If !status, just restart current output. + * If status & 1, a buffer is finished; make it available again. + * If status & 2, a buffer was claimed for DMA and is still in use. + * + * The playing_count for non-DMA hardware should never be non-zero. + */ + if (status & 1) { + if (drv->playing_count) + drv->playing_count--; + else { + drv->output_count--; + drv->output_size -= drv->output_sizes[drv->output_front]; + if (drv->output_notify[drv->output_front] == 1) { + drv->output_eof++; + drv->output_notify[drv->output_front] = 0; + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); + } + drv->output_front = (drv->output_front + 1) % + drv->num_output_buffers; + } + } - drv->ops->start_output(drv, drv->output_buffers[drv->output_front], - drv->output_sizes[drv->output_front]); + if (status & 2) { + drv->output_count--; + drv->playing_count++; + drv->output_size -= drv->output_sizes[drv->output_front]; + if (drv->output_notify[drv->output_front] == 1) { + drv->output_eof++; + drv->output_notify[drv->output_front] = 0; + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); + } + drv->output_front = (drv->output_front + 1) % + drv->num_output_buffers; + } + + /* If we've played everything go inactive. */ + if ((drv->output_count < 1) && (drv->playing_count < 1)) + drv->output_active = 0; + + /* If we got back a buffer, see if anyone wants to write to it */ + if ((status & 1) || ((drv->output_count + drv->playing_count) + < drv->num_output_buffers)) + wake_up_interruptible(&drv->output_write_wait); + + /* If the output queue is empty, shut down the driver. */ + if ((drv->output_count < 1) && (drv->playing_count < 1)) { + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); + + /* Stop the lowlevel driver from outputing. */ + /* drv->ops->stop_output(drv); Should not be necessary -- DJB 5/25/98 */ + drv->output_active = 0; + + /* Wake up any waiting writers or syncers and return. */ + wake_up_interruptible(&drv->output_write_wait); + wake_up_interruptible(&drv->output_drain_wait); + return; + } + /* Start next block of output if we have it */ + if (drv->output_count > 0) { + drv->ops->start_output(drv, drv->output_buffers[drv->output_front], + drv->output_sizes[drv->output_front]); + drv->output_active = 1; + } else + drv->output_active = 0; } -void sparcaudio_input_done(struct sparcaudio_driver * drv) +void sparcaudio_input_done(struct sparcaudio_driver * drv, int status) { - /* Point the queue after the "done" buffer. */ - drv->input_front = (drv->input_front + 1) % drv->num_input_buffers; - drv->input_count++; - - /* If the input queue is full, shutdown the driver. */ - if (drv->input_count == drv->num_input_buffers) { - /* Stop the lowlevel driver from inputing. */ - drv->ops->stop_input(drv); - drv->input_active = 0; - } else { - /* Otherwise, give the driver the next buffer. */ - drv->ops->start_input(drv, drv->input_buffers[drv->input_front], - 4096); - } + /* Deal with the weird case here */ + if (drv->duplex == 2) { + if (drv->input_count < drv->num_input_buffers) + drv->input_count++; + drv->ops->start_input(drv, drv->input_buffers[drv->input_front], + drv->input_buffer_size); + wake_up_interruptible(&drv->input_read_wait); + return; + } + + /* + * If status % 2, they filled a buffer for us. + * If status & 2, they took a buffer from us. + */ + + if ((status % 2) == 1) { + drv->input_count++; + drv->recording_count--; + drv->input_size+=drv->input_buffer_size; + } + + if (status > 1) { + drv->recording_count++; + drv->input_front = (drv->input_front + 1) % drv->num_input_buffers; + } + + dprintk(("f%d r%d c%d u%d\n", drv->input_front, drv->input_rear, drv->input_count, drv->recording_count)); + /* If the input queue is full, shutdown the driver. */ + if ((drv->input_count + drv->recording_count) == drv->num_input_buffers) { + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); + + /* Stop the lowlevel driver from inputing. */ + drv->ops->stop_input(drv); + drv->input_active = 0; + } else { + /* Otherwise, give the driver the next buffer. */ + drv->ops->start_input(drv, drv->input_buffers[drv->input_front], + drv->input_buffer_size); + } - /* Wake up any tasks that are waiting. */ - wake_up_interruptible(&drv->input_read_wait); + /* Wake up any tasks that are waiting. */ + wake_up_interruptible(&drv->input_read_wait); } @@ -219,803 +377,1680 @@ * VFS layer interface */ -static loff_t sparcaudio_llseek(struct file * file, loff_t offset, int origin) +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 +static int sparcaudio_select(struct inode * inode, struct file * file, + int sel_type, select_table * wait) { - return -ESPIPE; + struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> + SPARCAUDIO_DEVICE_SHIFT)]; + + switch (sel_type) { + case SEL_IN: + if (((!file->f_flags & O_NONBLOCK) && drv->input_count) || + (drv->input_size > drv->buffer_size)) { + dprintk(("read ready: c%d o%d\n", drv->input_count, drv->input_offset)); + return 1; + } + select_wait(&drv->input_read_wait, wait); + break; + case SEL_OUT: + dprintk(("sel out: c%d o%d p%d\n", drv->output_count, drv->output_offset, drv->playing_count)); + if ((drv->output_count + drv->playing_count) < (drv->num_output_buffers)) { + return 1; + } + select_wait(&drv->output_write_wait, wait); + break; + case SEL_EX: + break; + } + + return 0; +} +#else +static unsigned int sparcaudio_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = 0; + struct inode *inode = file->f_dentry->d_inode; + struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> + SPARCAUDIO_DEVICE_SHIFT)]; + + poll_wait(file, &drv->input_read_wait, wait); + poll_wait(file, &drv->output_write_wait, wait); + if (((!file->f_flags & O_NONBLOCK) && drv->input_count) || + (drv->input_size > drv->buffer_size)) { + mask |= POLLIN | POLLRDNORM; + } + if ((drv->output_count + drv->playing_count) < (drv->num_output_buffers)) { + mask |= POLLOUT | POLLWRNORM; + } + return mask; } +#endif -static ssize_t sparcaudio_read(struct file * file, - char *buf, size_t count, loff_t *ppos) +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 +static int sparcaudio_lseek(struct inode * inode, struct file * file, + off_t offset, int origin) +#else +static loff_t sparcaudio_lseek(struct file * file, loff_t offset, int origin) +#endif { - int bytes_to_copy; + return -ESPIPE; +} - if (! file->f_mode & FMODE_READ) - return -EINVAL; +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 +static int sparcaudio_read(struct inode * inode, struct file * file, + char *buf, int count) +#else +static ssize_t sparcaudio_read(struct file * file, char *buf, + size_t count, loff_t *ppos) +#endif +{ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff + struct inode *inode = file->f_dentry->d_inode; +#endif + struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> + SPARCAUDIO_DEVICE_SHIFT)]; + int bytes_to_copy, bytes_read = 0, err; - if (driver->input_count == 0) { - interruptible_sleep_on(&driver->input_read_wait); - if (signal_pending(current)) - return -EINTR; - } + if (! file->f_mode & FMODE_READ) + return -EINVAL; - bytes_to_copy = 4096 - driver->input_offset; - if (bytes_to_copy > count) - bytes_to_copy = count; - - copy_to_user_ret(buf, driver->input_buffers[driver->input_rear]+driver->input_offset, - bytes_to_copy, -EFAULT); - driver->input_offset += bytes_to_copy; - - if (driver->input_offset >= 4096) { - driver->input_rear = (driver->input_rear + 1) % driver->num_input_buffers; - driver->input_count--; - driver->input_offset = 0; - } + if ((file->f_flags & O_NONBLOCK) && (drv->input_size < count)) + return -EAGAIN; + + while (count > 0) { + if (drv->input_count == 0) { + /* This *should* never happen. */ + if (file->f_flags & O_NONBLOCK) { + printk("Warning: audio input leak!\n"); + return -EAGAIN; + } + interruptible_sleep_on(&drv->input_read_wait); + if (signal_pending(current)) + return -EINTR; + } + + bytes_to_copy = drv->input_buffer_size - drv->input_offset; + + if (bytes_to_copy > count) + bytes_to_copy = count; - return bytes_to_copy; -} + err = verify_area(VERIFY_WRITE, buf, bytes_to_copy); + if (err) + return err; + + copy_to_user(buf, drv->input_buffers[drv->input_rear]+drv->input_offset, + bytes_to_copy); + + drv->input_offset += bytes_to_copy; + drv->input_size -= bytes_to_copy; + buf += bytes_to_copy; + count -= bytes_to_copy; + bytes_read += bytes_to_copy; + + if (drv->input_offset >= drv->input_buffer_size) { + drv->input_rear = (drv->input_rear + 1) % + drv->num_input_buffers; + drv->input_count--; + drv->input_offset = 0; + } + /* If we're in "loop audio" mode, try waking up the other side + * in case they're waiting for us to eat a block. + */ + if (drv->duplex == 2) { + wake_up_interruptible(&drv->output_write_wait); + } + } -static void sparcaudio_reorganize_buffers(struct sparcaudio_driver * driver) -{ - /* It may never matter but if it does this routine will pack */ - /* buffers to free space for more data */ + return bytes_read; } -static void sparcaudio_sync_output(struct sparcaudio_driver * driver) +static void sparcaudio_sync_output(struct sparcaudio_driver * drv) { - unsigned long flags; + unsigned long flags; - /* If the low-level driver is not active, activate it. */ - save_and_cli(flags); - if ((!driver->output_active) && (driver->output_count > 0)) { - driver->ops->start_output(driver, - driver->output_buffers[driver->output_front], - driver->output_sizes[driver->output_front]); - driver->output_active = 1; - } - restore_flags(flags); + /* If the low-level driver is not active, activate it. */ + save_and_cli(flags); + if ((!drv->output_active) && (drv->output_count > 0)) { + drv->ops->start_output(drv, + drv->output_buffers[drv->output_front], + drv->output_sizes[drv->output_front]); + drv->output_active = 1; + } + restore_flags(flags); } +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 +static int sparcaudio_write(struct inode * inode, struct file * file, + const char *buf, int count) +#else static ssize_t sparcaudio_write(struct file * file, const char *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) +#endif { - int bytes_written = 0, bytes_to_copy; +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff + struct inode *inode = file->f_dentry->d_inode; +#endif + struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> + SPARCAUDIO_DEVICE_SHIFT)]; + int bytes_written = 0, bytes_to_copy, err; + + if (! file->f_mode & FMODE_WRITE) + return -EINVAL; + + /* + * A signal they want notification when this is processed. Too bad + * sys_write doesn't tell us unless you patch it, in 2.0 kernels. + */ + if (count == 0) { +#ifndef notdef + drv->output_eof++; + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); +#else + /* Nice code, but the world isn't ready yet... */ + drv->output_notify[drv->output_rear] = 1; +#endif + } - if (! file->f_mode & FMODE_WRITE) - return -EINVAL; + /* Loop until all output is written to device. */ + while (count > 0) { + /* Check to make sure that an output buffer is available. */ + if (drv->num_output_buffers == (drv->output_count + drv->playing_count)) { + /* We need buffers, so... */ + sparcaudio_sync_output(drv); + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + interruptible_sleep_on(&drv->output_write_wait); + if (signal_pending(current)) + return bytes_written > 0 ? bytes_written : -EINTR; + } - /* Loop until all output is written to device. */ - while (count > 0) { - /* Check to make sure that an output buffer is available. */ - /* If not, make valiant attempt */ - if (driver->num_output_buffers == - (driver->output_count + driver->playing_count)) - sparcaudio_reorganize_buffers(driver); - - if (driver->num_output_buffers == - (driver->output_count + driver->playing_count)) { - /* We need buffers, so... */ - sparcaudio_sync_output(driver); - interruptible_sleep_on(&driver->output_write_wait); - if (signal_pending(current)) - return bytes_written > 0 ? bytes_written : -EINTR; - } + /* No buffers were freed. Go back to sleep */ + if (drv->num_output_buffers == (drv->output_count + drv->playing_count)) + continue; + + /* Deal with the weird case of a reader in the write area by trying to + * let them keep ahead of us... Go to sleep until they start servicing. + */ + if ((drv->duplex == 2) && (drv->flags & SDF_OPEN_READ) && + (drv->output_rear == drv->input_rear) && (drv->input_count > 0)) { + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + interruptible_sleep_on(&drv->output_write_wait); + if (signal_pending(current)) + return bytes_written > 0 ? bytes_written : -EINTR; + } - /* No buffers were freed. Go back to sleep */ - if (driver->num_output_buffers == - (driver->output_count + driver->playing_count)) - continue; - - /* Determine how much we can copy in this iteration. */ - bytes_to_copy = count; - if (bytes_to_copy > 4096) - bytes_to_copy = 4096; - - copy_from_user_ret(driver->output_buffers[driver->output_rear], - buf, bytes_to_copy, -EFAULT); - - /* Update the queue pointers. */ - buf += bytes_to_copy; - count -= bytes_to_copy; - bytes_written += bytes_to_copy; - driver->output_sizes[driver->output_rear] = bytes_to_copy; - driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers; - driver->output_count++; - driver->output_size += bytes_to_copy; - } - sparcaudio_sync_output(driver); + /* Determine how much we can copy in this iteration. */ + bytes_to_copy = count; + if (bytes_to_copy > drv->output_buffer_size - drv->output_offset) + bytes_to_copy = drv->output_buffer_size - drv->output_offset; + + err = verify_area(VERIFY_READ, buf, bytes_to_copy); + if (err) + return err; - /* Return the number of bytes written to the caller. */ - return bytes_written; + copy_from_user(drv->output_buffers[drv->output_rear]+drv->output_offset, buf, bytes_to_copy); + + /* Update the queue pointers. */ + buf += bytes_to_copy; + count -= bytes_to_copy; + bytes_written += bytes_to_copy; + + /* A block can get orphaned in a flush and not cleaned up. */ + if (drv->output_offset) + drv->output_sizes[drv->output_rear] += bytes_to_copy; + else + drv->output_sizes[drv->output_rear] = bytes_to_copy; + + drv->output_notify[drv->output_rear] = 0; + + if (drv->output_sizes[drv->output_rear] == drv->output_buffer_size) { + drv->output_rear = (drv->output_rear + 1) + % drv->num_output_buffers; + drv->output_count++; + drv->output_offset = 0; + } else + drv->output_offset += bytes_to_copy; + + drv->output_size+=bytes_to_copy; + } + + sparcaudio_sync_output(drv); + + /* Return the number of bytes written to the caller. */ + return bytes_written; } -#define COPY_IN(arg, get) get_user(get, (int *)arg) -#define COPY_OUT(arg, ret) put_user(ret, (int *)arg) - /* Add these in as new devices are supported. Belongs in audioio.h, actually */ -#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_VOLUME) -#define MONO_DEVICES (SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SPEAKER | SOUND_MASK_MIC) +#define MONO_DEVICES (SOUND_MASK_SPEAKER | SOUND_MASK_MIC) -static inline int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) { - int i = 0, j = 0; - if (_IOC_DIR(cmd) & _IOC_WRITE) { - /* For any missing routines, pretend we changed things anyhow for now */ - switch (cmd & 0xff) { - case SOUND_MIXER_VOLUME: - if (driver->ops->get_output_channels) - j = driver->ops->get_output_channels(driver); - COPY_IN(arg, i); - if (j == 1) { - i = s_to_m(i); - if (driver->ops->set_output_volume) - driver->ops->set_output_volume(driver, i * 255/100); - if (driver->ops->get_output_volume) - i = driver->ops->get_output_volume(driver); - i = m_to_s(i); - } else { - /* there should be stuff here which calculates balance and - volume on a stereo device. will do it eventually */ - i = s_to_g(i); - if (driver->ops->set_output_volume) - driver->ops->set_output_volume(driver, i * 255/100); - if (driver->ops->get_output_volume) - i = driver->ops->get_output_volume(driver); - j = s_to_b(i); - if (driver->ops->set_output_balance) - driver->ops->set_output_balance(driver, j); - if (driver->ops->get_output_balance) - j = driver->ops->get_output_balance(driver); - i = b_to_s(i,j); - } - return COPY_OUT(arg, i); - default: - /* Play like we support other things */ - return COPY_OUT(arg, i); - } - } else { - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - if (driver->ops->get_input_port) - i = driver->ops->get_input_port(driver); - /* only one should ever be selected */ - if (i & AUDIO_ANALOG_LOOPBACK) j = SOUND_MASK_IMIX; /* ? */ - if (i & AUDIO_CD) j = SOUND_MASK_CD; - if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE; - if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC; - - return COPY_OUT(arg, j); - - case SOUND_MIXER_RECMASK: - if (driver->ops->get_input_ports) - i = driver->ops->get_input_ports(driver); - /* what do we support? */ - if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; - if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; - if (i & AUDIO_CD) j |= SOUND_MASK_CD; - if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */ - - return COPY_OUT(arg, j); - - case SOUND_MIXER_CAPS: /* mixer capabilities */ - i = SOUND_CAP_EXCL_INPUT; - return COPY_OUT(arg, i); - - case SOUND_MIXER_DEVMASK: /* all supported devices */ - case SOUND_MIXER_STEREODEVS: /* what supports stereo */ - if (driver->ops->get_input_ports) - i = driver->ops->get_input_ports(driver); - /* what do we support? */ - if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; - if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; - if (i & AUDIO_CD) j |= SOUND_MASK_CD; - if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */ - - if (driver->ops->get_output_ports) - i = driver->ops->get_output_ports(driver); - if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER; - if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE; /* ? */ - if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE; - - j |= SOUND_MASK_VOLUME; - - if ((cmd & 0xff) == SOUND_MIXER_STEREODEVS) - j &= ~(MONO_DEVICES); - return COPY_OUT(arg, j); - - case SOUND_MIXER_VOLUME: - if (driver->ops->get_output_channels) - j = driver->ops->get_output_channels(driver); - if (j == 1) { - if (driver->ops->get_output_volume) - i = driver->ops->get_output_volume(driver); - i = m_to_s(i); - } else { - /* there should be stuff here which calculates balance and - volume on a stereo device. will do it eventually */ - if (driver->ops->get_output_volume) - i = driver->ops->get_output_volume(driver); - if (driver->ops->get_output_balance) - j = driver->ops->get_output_balance(driver); - i = b_to_s(i,j); - } - return COPY_OUT(arg, i); - - default: - /* Play like we support other things */ - return COPY_OUT(arg, i); - } - } + struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> + SPARCAUDIO_DEVICE_SHIFT)]; + unsigned long i = 0, j = 0, k = 0; + + k = (unsigned long) &arg; + + switch (cmd) { + case SOUND_MIXER_WRITE_RECLEV: + case SOUND_MIXER_WRITE_MIC: + case SOUND_MIXER_WRITE_CD: + case SOUND_MIXER_WRITE_LINE: + tprintk(("setting input volume (0x%x)", k)); + if (drv->ops->get_input_channels) + j = drv->ops->get_input_channels(drv); + if (j == 1) { + i = s_to_m(k); + tprintk((" for mono to %d\n", i)); + if (drv->ops->set_input_volume) + drv->ops->set_input_volume(drv, i); + if (drv->ops->get_input_volume) + i = drv->ops->get_input_volume(drv); + i = m_to_s(i); + } else { + i = s_to_g(k); + j = s_to_b(k); + tprintk((" for stereo to to %d (bal %d)\n", i, j)); + if (drv->ops->set_input_volume) + drv->ops->set_input_volume(drv, i); + if (drv->ops->get_input_volume) + i = drv->ops->get_input_volume(drv); + if (drv->ops->set_input_balance) + drv->ops->set_input_balance(drv, j); + if (drv->ops->get_input_balance) + j = drv->ops->get_input_balance(drv); + i = b_to_s(i,j); + } + return COPY_OUT(arg, i); + case SOUND_MIXER_WRITE_PCM: + case SOUND_MIXER_WRITE_VOLUME: + case SOUND_MIXER_WRITE_SPEAKER: + tprintk(("setting output volume (0x%x)", k)); + if (drv->ops->get_output_channels) + j = drv->ops->get_output_channels(drv); + if (j == 1) { + i = s_to_m(k); + tprintk((" for mono to %d\n", i)); + if (drv->ops->set_output_volume) + drv->ops->set_output_volume(drv, i); + if (drv->ops->get_output_volume) + i = drv->ops->get_output_volume(drv); + i = m_to_s(i); + } else { + i = s_to_g(k); + j = s_to_b(k); + tprintk((" for stereo to to %d (bal %d)\n", i, j)); + if (drv->ops->set_output_volume) + drv->ops->set_output_volume(drv, i); + if (drv->ops->get_output_volume) + i = drv->ops->get_output_volume(drv); + if (drv->ops->set_output_balance) + drv->ops->set_output_balance(drv, j); + if (drv->ops->get_output_balance) + j = drv->ops->get_output_balance(drv); + i = b_to_s(i,j); + } + return COPY_OUT(arg, i); + case SOUND_MIXER_READ_RECSRC: + if (drv->ops->get_input_port) + i = drv->ops->get_input_port(drv); + /* only one should ever be selected */ + if (i & AUDIO_ANALOG_LOOPBACK) j = SOUND_MASK_IMIX; /* ? */ + if (i & AUDIO_CD) j = SOUND_MASK_CD; + if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE; + if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC; + + return COPY_OUT(arg, j); + case SOUND_MIXER_WRITE_RECSRC: + if (!drv->ops->set_input_port) + return -EINVAL; + if (arg & SOUND_MASK_IMIX) j |= AUDIO_ANALOG_LOOPBACK; + if (arg & SOUND_MASK_CD) j |= AUDIO_CD; + if (arg & SOUND_MASK_LINE) j |= AUDIO_LINE_IN; + if (arg & SOUND_MASK_MIC) j |= AUDIO_MICROPHONE; + tprintk(("setting inport to %d\n", j)); + i = drv->ops->set_input_port(drv, j); + + return COPY_OUT(arg, i); + case SOUND_MIXER_READ_RECMASK: + if (drv->ops->get_input_ports) + i = drv->ops->get_input_ports(drv); + /* what do we support? */ + if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; + if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; + if (i & AUDIO_CD) j |= SOUND_MASK_CD; + if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */ + + return COPY_OUT(arg, j); + case SOUND_MIXER_READ_CAPS: /* mixer capabilities */ + i = SOUND_CAP_EXCL_INPUT; + return COPY_OUT(arg, i); + + case SOUND_MIXER_READ_DEVMASK: /* all supported devices */ + case SOUND_MIXER_READ_STEREODEVS: /* what supports stereo */ + if (drv->ops->get_input_ports) + i = drv->ops->get_input_ports(drv); + /* what do we support? */ + if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; + if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; + if (i & AUDIO_CD) j |= SOUND_MASK_CD; + if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */ + + if (drv->ops->get_output_ports) + i = drv->ops->get_output_ports(drv); + if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER; + if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE; /* ? */ + if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE; + + j |= SOUND_MASK_VOLUME; + + if (cmd == SOUND_MIXER_READ_STEREODEVS) + j &= ~(MONO_DEVICES); + return COPY_OUT(arg, j); + case SOUND_MIXER_READ_PCM: + case SOUND_MIXER_READ_SPEAKER: + case SOUND_MIXER_READ_VOLUME: + if (drv->ops->get_output_channels) + j = drv->ops->get_output_channels(drv); + if (j == 1) { + if (drv->ops->get_output_volume) + i = drv->ops->get_output_volume(drv); + i = m_to_s(i); + } else { + if (drv->ops->get_output_volume) + i = drv->ops->get_output_volume(drv); + if (drv->ops->get_output_balance) + j = drv->ops->get_output_balance(drv); + i = b_to_s(i,j); + } + return COPY_OUT((int *)arg, i); + case SOUND_MIXER_READ_RECLEV: + case SOUND_MIXER_READ_MIC: + case SOUND_MIXER_READ_CD: + case SOUND_MIXER_READ_LINE: + if (drv->ops->get_input_channels) + j = drv->ops->get_input_channels(drv); + if (j == 1) { + if (drv->ops->get_input_volume) + i = drv->ops->get_input_volume(drv); + i = m_to_s(i); + } else { + if (drv->ops->get_input_volume) + i = drv->ops->get_input_volume(drv); + if (drv->ops->get_input_balance) + j = drv->ops->get_input_balance(drv); + i = b_to_s(i,j); + } + return COPY_OUT((int *)arg, i); + default: + return -EINVAL; + } } -static int sparcaudio_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +/* AUDIO_SETINFO uses these to set values if possible. */ +static __inline__ int +__sparcaudio_if_set_do(struct sparcaudio_driver *drv, + int (*set_function)(struct sparcaudio_driver *, int), + int (*get_function)(struct sparcaudio_driver *), + unsigned int value) { - int retval = 0; - struct audio_info ainfo; - - if (((cmd >> 8) & 0xff) == 'M') { - return sparcaudio_mixer_ioctl(inode, file, cmd, arg); - } - - switch (cmd) { - case SNDCTL_DSP_SYNC: - case AUDIO_DRAIN: - if (driver->output_count > 0) { - interruptible_sleep_on(&driver->output_drain_wait); - retval = signal_pending(current) ? -EINTR : 0; - } - break; - - case AUDIO_FLUSH: - if (driver->output_active && (file->f_mode & FMODE_WRITE)) { - wake_up_interruptible(&driver->output_write_wait); - driver->ops->stop_output(driver); - driver->output_active = 0; - driver->output_front = 0; - driver->output_rear = 0; - driver->output_count = 0; - driver->output_size = 0; - driver->playing_count = 0; - } - if (driver->input_active && (file->f_mode & FMODE_READ)) { - wake_up_interruptible(&driver->input_read_wait); - driver->ops->stop_input(driver); - driver->input_active = 0; - driver->input_front = 0; - driver->input_rear = 0; - driver->input_count = 0; - driver->recording_count = 0; - } - if ((file->f_mode & FMODE_READ) && - !(driver->flags & SDF_OPEN_READ)) { - driver->ops->start_input(driver, - driver->input_buffers[driver->input_front], - 4096); - driver->input_active = 1; - } - if ((file->f_mode & FMODE_WRITE) && - !(driver->flags & SDF_OPEN_WRITE)) { - sparcaudio_sync_output(driver); - } - break; - - - case AUDIO_GETDEV: - if (driver->ops->sunaudio_getdev) { - audio_device_t tmp; - - driver->ops->sunaudio_getdev(driver, &tmp); - - copy_to_user_ret((audio_device_t *)arg, &tmp, sizeof(tmp), -EFAULT); - } else - retval = -EINVAL; - - break; - - case AUDIO_GETDEV_SUNOS: - if (driver->ops->sunaudio_getdev_sunos) { - int tmp=driver->ops->sunaudio_getdev_sunos(driver); - - if (put_user(tmp, (int *)arg)) - retval = -EFAULT; - } else - retval = -EINVAL; - - break; - - case AUDIO_GETINFO: - - AUDIO_INITINFO(&ainfo); - - if (driver->ops->get_input_rate) - ainfo.record.sample_rate = - driver->ops->get_input_rate(driver); - if (driver->ops->get_input_channels) - ainfo.record.channels = - driver->ops->get_input_channels(driver); - if (driver->ops->get_input_precision) - ainfo.record.precision = - driver->ops->get_input_precision(driver); - if (driver->ops->get_input_encoding) - ainfo.record.encoding = - driver->ops->get_input_encoding(driver); - if (driver->ops->get_input_volume) - ainfo.record.gain = - driver->ops->get_input_volume(driver); - if (driver->ops->get_input_port) - ainfo.record.port = - driver->ops->get_input_port(driver); - if (driver->ops->get_input_ports) - ainfo.record.avail_ports = - driver->ops->get_input_ports(driver); - ainfo.record.buffer_size = 4096; - ainfo.record.samples = 0; - ainfo.record.eof = 0; - ainfo.record.pause = 0; - ainfo.record.error = 0; - ainfo.record.waiting = 0; - if (driver->ops->get_input_balance) - ainfo.record.balance = - driver->ops->get_input_balance(driver); - ainfo.record.minordev = 4; - ainfo.record.open = 1; - ainfo.record.active = 0; - - if (driver->ops->get_output_rate) - ainfo.play.sample_rate = - driver->ops->get_output_rate(driver); - if (driver->ops->get_output_channels) - ainfo.play.channels = - driver->ops->get_output_channels(driver); - if (driver->ops->get_output_precision) - ainfo.play.precision = - driver->ops->get_output_precision(driver); - if (driver->ops->get_output_encoding) - ainfo.play.encoding = - driver->ops->get_output_encoding(driver); - if (driver->ops->get_output_volume) - ainfo.play.gain = - driver->ops->get_output_volume(driver); - if (driver->ops->get_output_port) - ainfo.play.port = - driver->ops->get_output_port(driver); - if (driver->ops->get_output_ports) - ainfo.play.avail_ports = - driver->ops->get_output_ports(driver); - /* This is not defined in the play context in Solaris */ - ainfo.play.buffer_size = 0; - ainfo.play.samples = 0; - ainfo.play.eof = 0; - ainfo.play.pause = 0; - ainfo.play.error = 0; - ainfo.play.waiting = waitqueue_active(&driver->open_wait); - if (driver->ops->get_output_balance) - ainfo.play.balance = - (unsigned char)driver->ops->get_output_balance(driver); - ainfo.play.minordev = 4; - ainfo.play.open = 1; - ainfo.play.active = driver->output_active; - - if (driver->ops->get_monitor_volume) - ainfo.monitor_gain = - driver->ops->get_monitor_volume(driver); - - if (driver->ops->get_output_muted) - ainfo.output_muted = - (unsigned char)driver->ops->get_output_muted(driver); - - copy_to_user_ret((struct audio_info *)arg, &ainfo, - sizeof(ainfo), -EFAULT); + if (set_function && Modify(value)) + return (int)set_function(drv, value); + else if (get_function) + return (int)get_function(drv); + else + return 0; +} - break; +static __inline__ int +__sparcaudio_if_setc_do(struct sparcaudio_driver *drv, + int (*set_function)(struct sparcaudio_driver *, int), + int (*get_function)(struct sparcaudio_driver *), + unsigned char value) +{ + if (set_function && Modifyc(value)) + return (char)set_function(drv, (int)value); + else if (get_function) + return (char)get_function(drv); + else + return 0; +} - case AUDIO_SETINFO: - { - audio_info_t curinfo, newinfo; +/* I_FLUSH, I_{G,S}ETSIG, I_NREAD provided for SunOS compatibility + * + * I must admit I'm quite ashamed of the state of the ioctl handling, + * but I do have several optimizations which I'm planning. -- DJB + */ - copy_from_user_ret(&ainfo, (audio_info_t *) arg, sizeof(audio_info_t), -EFAULT); +static int sparcaudio_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0, i, j, k; + int minor = MINOR(inode->i_rdev); + struct audio_info ainfo; + audio_buf_info binfo; + count_info cinfo; + struct sparcaudio_driver *drv = + drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)]; + + switch (minor & 0xf) { + case SPARCAUDIO_MIXER_MINOR: + return sparcaudio_mixer_ioctl(inode, file, cmd, arg); + case SPARCAUDIO_DSP16_MINOR: + case SPARCAUDIO_DSP_MINOR: + case SPARCAUDIO_AUDIO_MINOR: + case SPARCAUDIO_AUDIOCTL_MINOR: + switch (cmd) { + case I_GETSIG: + case I_GETSIG_SOLARIS: + j = (int)lis_get_elist_ent(drv->sd_siglist,current->pid); + COPY_OUT(arg, j); + retval = drv->input_count; + break; - /* Without these there's no point in trying */ - if (!driver->ops->get_input_precision || - !driver->ops->get_input_channels || - !driver->ops->get_input_rate || - !driver->ops->get_input_encoding || - !driver->ops->get_output_precision || - !driver->ops->get_output_channels || - !driver->ops->get_output_rate || - !driver->ops->get_output_encoding) - { - retval = -EINVAL; - break; + case I_SETSIG: + case I_SETSIG_SOLARIS: + if ((minor & 0xf) == SPARCAUDIO_AUDIOCTL_MINOR) { + if (!arg){ + if (lis_del_from_elist(&(drv->sd_siglist),current->pid,S_ALL)) + retval = -EINVAL; + else + if (!drv->sd_siglist) + drv->sd_sigflags=0; } - - /* Do bounds checking for things which always apply. - * Follow with enforcement of basic tenets of certain - * encodings. Everything over and above generic is - * enforced by the driver, which can assume that - * Martian cases are taken care of here. */ - if (Modify(ainfo.play.gain) && - ((ainfo.play.gain > AUDIO_MAX_GAIN) || - (ainfo.play.gain < AUDIO_MIN_GAIN))) { - /* Need to differentiate this from e.g. the above error */ + else + if (lis_add_to_elist(&(drv->sd_siglist),current->pid, + (short)arg)) + retval = -EAGAIN; + else + ((drv->sd_sigflags) |= (arg)); + } + break; + case I_NREAD: + case I_NREAD_SOLARIS: + /* According to the Solaris man page, this copies out + * the size of the first streams buffer and returns + * the number of streams messages on the read queue as + * as its retval. (streamio(7I)) This should work. */ + + j = (drv->input_count > 0) ? drv->input_buffer_size : 0; + COPY_OUT(arg, j); + retval = drv->input_count; + break; + /* + * A poor substitute until we do true resizable buffers. + */ + case SNDCTL_DSP_GETISPACE: + binfo.fragstotal = drv->num_input_buffers; + binfo.fragments = drv->num_input_buffers - + (drv->input_count + drv->recording_count); + binfo.fragsize = drv->input_buffer_size; + binfo.bytes = binfo.fragments*binfo.fragsize; + + retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo)); + if (retval) break; + copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo)); + break; + case SNDCTL_DSP_GETOSPACE: + binfo.fragstotal = drv->num_output_buffers; + binfo.fragments = drv->num_output_buffers - + (drv->output_count + drv->playing_count + + (drv->output_offset ? 1 : 0)); + binfo.fragsize = drv->output_buffer_size; + binfo.bytes = binfo.fragments*binfo.fragsize + + (drv->output_buffer_size - drv->output_offset); + + retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo)); + if (retval) break; + copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo)); + break; + case SNDCTL_DSP_GETIPTR: + case SNDCTL_DSP_GETOPTR: + /* + * int bytes (number of bytes read/written since last) + * int blocks (number of frags read/wrote since last call) + * int ptr (current position of dma in buffer) + */ + retval = 0; + cinfo.bytes = 0; + cinfo.ptr = 0; + cinfo.blocks = 0; + cinfo.bytes += cinfo.ptr; + + retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(cinfo)); + if (retval) break; + copy_to_user(&((char *)arg)[0], (char *)&cinfo, sizeof(cinfo)); + break; + case SNDCTL_DSP_SETFRAGMENT: + /* XXX Small hack to get ESD/Enlightenment to work. --DaveM */ + retval = 0; + break; + + case SNDCTL_DSP_SUBDIVIDE: + /* + * I don't understand what I need to do yet. + */ + retval = -EINVAL; + break; + case SNDCTL_DSP_SETTRIGGER: + /* This may not be 100% correct */ + if ((arg & PCM_ENABLE_INPUT) && drv->ops->get_input_pause && + drv->ops->set_input_pause) { + if (drv->ops->get_input_pause(drv)) + drv->ops->set_input_pause(drv, 0); + } else { + if (!drv->ops->get_input_pause(drv)) + drv->ops->set_input_pause(drv, 1); + } + if ((arg & PCM_ENABLE_OUTPUT) && drv->ops->get_output_pause && + drv->ops->set_output_pause) { + if (drv->ops->get_output_pause(drv)) + drv->ops->set_output_pause(drv, 0); + } else { + if (!drv->ops->get_output_pause(drv)) + drv->ops->set_output_pause(drv, 1); + } + break; + case SNDCTL_DSP_GETTRIGGER: + j = 0; + if (drv->ops->get_input_pause) + if (drv->ops->get_input_pause(drv)) + j = PCM_ENABLE_INPUT; + if (drv->ops->get_output_pause) + if (drv->ops->get_output_pause(drv)) + j |= PCM_ENABLE_OUTPUT; + COPY_OUT(arg, j); + break; + case SNDCTL_DSP_GETBLKSIZE: + j = drv->input_buffer_size; + COPY_OUT(arg, j); + break; + case SNDCTL_DSP_SPEED: + if ((!drv->ops->set_output_rate) && + (!drv->ops->set_input_rate)) { retval = -EINVAL; break; } - if (Modify(ainfo.record.gain) && - ((ainfo.record.gain > AUDIO_MAX_GAIN) || - (ainfo.record.gain < AUDIO_MIN_GAIN))) { + COPY_IN(arg, i); + tprintk(("setting speed to %d\n", i)); + drv->ops->set_input_rate(drv, i); + drv->ops->set_output_rate(drv, i); + j = drv->ops->get_output_rate(drv); + COPY_OUT(arg, j); + break; + case SNDCTL_DSP_GETCAPS: + /* + * All Sparc audio hardware is full duplex. + * 4231 supports DMA pointer reading, 7930 is byte at a time. + * Pause functionality emulates trigger + */ + j = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER | DSP_CAP_REALTIME; + COPY_OUT(arg, j); + break; + case SNDCTL_DSP_GETFMTS: + if (drv->ops->get_formats) { + j = drv->ops->get_formats(drv); + COPY_OUT(arg, j); + } else retval = -EINVAL; + break; + case SNDCTL_DSP_SETFMT: + /* need to decode into encoding, precision */ + COPY_IN(arg, i); + + /* handle special case here */ + if (i == AFMT_QUERY) { + j = drv->ops->get_output_encoding(drv); + k = drv->ops->get_output_precision(drv); + if (j == AUDIO_ENCODING_DVI) + i = AFMT_IMA_ADPCM; + else if (k == 8) { + switch (j) { + case AUDIO_ENCODING_ULAW: + i = AFMT_MU_LAW; + break; + case AUDIO_ENCODING_ALAW: + i = AFMT_A_LAW; + break; + case AUDIO_ENCODING_LINEAR8: + i = AFMT_U8; + break; + } + } else if (k == 16) { + case AUDIO_ENCODING_LINEAR: + i = AFMT_S16_BE; + break; + case AUDIO_ENCODING_LINEARLE: + i = AFMT_S16_LE; + break; + } + COPY_OUT(arg, i); break; } - if (Modify(ainfo.monitor_gain) && - ((ainfo.monitor_gain > AUDIO_MAX_GAIN) || - (ainfo.monitor_gain < AUDIO_MIN_GAIN))) { + + /* Without these there's no point in trying */ + if (!drv->ops->set_input_precision || + !drv->ops->set_input_encoding || + !drv->ops->set_output_precision || + !drv->ops->set_output_encoding) { + eprintk(("missing set routines: failed\n")); retval = -EINVAL; break; - } - /* Don't need to check less than zero on these */ - if (Modifyc(ainfo.play.balance) && - (ainfo.play.balance > AUDIO_RIGHT_BALANCE)) { + } + + if (drv->ops->get_formats) + if (!(drv->ops->get_formats(drv) & i)) { + dprintk(("format not supported\n")); + return -EINVAL; + } + + switch (i) { + case AFMT_S16_LE: + ainfo.record.precision = ainfo.play.precision = 16; + ainfo.record.encoding = ainfo.play.encoding = + AUDIO_ENCODING_LINEARLE; + break; + case AFMT_S16_BE: + ainfo.record.precision = ainfo.play.precision = 16; + ainfo.record.encoding = ainfo.play.encoding = + AUDIO_ENCODING_LINEAR; + break; + case AFMT_MU_LAW: + ainfo.record.precision = ainfo.play.precision = 8; + ainfo.record.encoding = ainfo.play.encoding = + AUDIO_ENCODING_ULAW; + break; + case AFMT_A_LAW: + ainfo.record.precision = ainfo.play.precision = 8; + ainfo.record.encoding = ainfo.play.encoding = + AUDIO_ENCODING_ALAW; + break; + case AFMT_U8: + ainfo.record.precision = ainfo.play.precision = 8; + ainfo.record.encoding = ainfo.play.encoding = + AUDIO_ENCODING_LINEAR8; + break; + } + tprintk(("setting fmt to enc %d pr %d\n", ainfo.play.encoding, + ainfo.play.precision)); + if ((drv->ops->set_input_precision(drv, + ainfo.record.precision) + < 0) || + (drv->ops->set_output_precision(drv, + ainfo.play.precision) + < 0) || + (drv->ops->set_input_encoding(drv, + ainfo.record.encoding) + < 0) || + (drv->ops->set_output_encoding(drv, + ainfo.play.encoding) + < 0)) { + dprintk(("setting format: failed\n")); + return -EINVAL; + } + COPY_OUT(arg, i); + break; + case SNDCTL_DSP_CHANNELS: + if ((!drv->ops->set_output_channels) && + (!drv->ops->set_input_channels)) { retval = -EINVAL; break; } - if (Modifyc(ainfo.record.balance) && - (ainfo.record.balance > AUDIO_RIGHT_BALANCE)) { + COPY_IN(arg, i); + drv->ops->set_input_channels(drv, i); + drv->ops->set_output_channels(drv, i); + i = drv->ops->get_output_channels(drv); + COPY_OUT(arg, i); + break; + case SNDCTL_DSP_STEREO: + if ((!drv->ops->set_output_channels) && + (!drv->ops->set_input_channels)) { retval = -EINVAL; break; } - - /* If any of these changed, record them all, then make - * changes atomically. If something fails, back it all out. */ - if (Modify(ainfo.record.precision) || - Modify(ainfo.record.sample_rate) || - Modify(ainfo.record.channels) || - Modify(ainfo.record.encoding) || - Modify(ainfo.play.precision) || - Modify(ainfo.play.sample_rate) || - Modify(ainfo.play.channels) || - Modify(ainfo.play.encoding)) - { - /* If they're trying to change something we - * have no routine for, they lose */ - if ((!driver->ops->set_input_encoding && - Modify(ainfo.record.encoding)) || - (!driver->ops->set_input_rate && - Modify(ainfo.record.sample_rate)) || - (!driver->ops->set_input_precision && - Modify(ainfo.record.precision)) || - (!driver->ops->set_input_channels && - Modify(ainfo.record.channels))) { - retval = -EINVAL; - break; - } - - curinfo.record.encoding = driver->ops->get_input_encoding(driver); - curinfo.record.sample_rate = driver->ops->get_input_rate(driver); - curinfo.record.precision = driver->ops->get_input_precision(driver); - curinfo.record.channels = driver->ops->get_input_channels(driver); - newinfo.record.encoding = Modify(ainfo.record.encoding) ? - ainfo.record.encoding : curinfo.record.encoding; - newinfo.record.sample_rate = Modify(ainfo.record.sample_rate)? - ainfo.record.sample_rate : curinfo.record.sample_rate; - newinfo.record.precision = Modify(ainfo.record.precision) ? - ainfo.record.precision : curinfo.record.precision; - newinfo.record.channels = Modify(ainfo.record.channels) ? - ainfo.record.channels : curinfo.record.channels; + COPY_IN(arg, i); + drv->ops->set_input_channels(drv, (i + 1)); + drv->ops->set_output_channels(drv, (i + 1)); + i = ((drv->ops->get_output_channels(drv)) - 1); + COPY_OUT(arg, i); + break; + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SYNC: + case AUDIO_DRAIN: + /* Deal with weirdness so we can fill buffers */ + if (drv->output_offset) { + drv->output_offset = 0; + drv->output_rear = (drv->output_rear + 1) + % drv->num_output_buffers; + drv->output_count++; + } + if (drv->output_count > 0) { + sparcaudio_sync_output(drv); + /* Only pause for DRAIN/SYNC, not POST */ + if (cmd != SNDCTL_DSP_POST) { + interruptible_sleep_on(&drv->output_drain_wait); + retval = (signal_pending(current)) ? -EINTR : 0; + } + } + break; + case I_FLUSH: + case I_FLUSH_SOLARIS: + if (((unsigned int)arg == FLUSHW) || + ((unsigned int)arg == FLUSHRW)) { + if (file->f_mode & FMODE_WRITE) { + sparcaudio_sync_output(drv); + if (drv->output_active) { + wake_up_interruptible(&drv->output_write_wait); + drv->ops->stop_output(drv); + } + drv->output_offset = 0; + drv->output_active = 0; + drv->output_front = 0; + drv->output_rear = 0; + drv->output_count = 0; + drv->output_size = 0; + drv->playing_count = 0; + drv->output_eof = 0; + } + } + if (((unsigned int)arg == FLUSHR) || + ((unsigned int)arg == FLUSHRW)) { + if (drv->input_active && (file->f_mode & FMODE_READ)) { + wake_up_interruptible(&drv->input_read_wait); + drv->ops->stop_input(drv); + drv->input_active = 0; + drv->input_front = 0; + drv->input_rear = 0; + drv->input_count = 0; + drv->input_size = 0; + drv->input_offset = 0; + drv->recording_count = 0; + } + if ((file->f_mode & FMODE_READ) && + (drv->flags & SDF_OPEN_READ)) { + if (drv->duplex == 2) + drv->input_count = drv->output_count; + drv->ops->start_input(drv, + drv->input_buffers[drv->input_front], + drv->input_buffer_size); + drv->input_active = 1; + } + } + if (((unsigned int)arg == FLUSHW) || + ((unsigned int)arg == FLUSHRW)) { + if ((file->f_mode & FMODE_WRITE) && + !(drv->flags & SDF_OPEN_WRITE)) { + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); + sparcaudio_sync_output(drv); + } + } + break; + case SNDCTL_DSP_RESET: + case AUDIO_FLUSH: + if (drv->output_active && (file->f_mode & FMODE_WRITE)) { + wake_up_interruptible(&drv->output_write_wait); + drv->ops->stop_output(drv); + drv->output_active = 0; + drv->output_front = 0; + drv->output_rear = 0; + drv->output_count = 0; + drv->output_size = 0; + drv->playing_count = 0; + drv->output_offset = 0; + drv->output_eof = 0; + } + if (drv->input_active && (file->f_mode & FMODE_READ)) { + wake_up_interruptible(&drv->input_read_wait); + drv->ops->stop_input(drv); + drv->input_active = 0; + drv->input_front = 0; + drv->input_rear = 0; + drv->input_count = 0; + drv->input_size = 0; + drv->input_offset = 0; + drv->recording_count = 0; + } + if ((file->f_mode & FMODE_READ) && + !(drv->flags & SDF_OPEN_READ)) { + drv->ops->start_input(drv, + drv->input_buffers[drv->input_front], + drv->input_buffer_size); + drv->input_active = 1; + } + if ((file->f_mode & FMODE_WRITE) && + !(drv->flags & SDF_OPEN_WRITE)) { + sparcaudio_sync_output(drv); + } + break; + case AUDIO_GETDEV: + if (drv->ops->sunaudio_getdev) { + audio_device_t tmp; + + retval = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(audio_device_t)); + if (!retval) + drv->ops->sunaudio_getdev(drv, &tmp); + copy_to_user((audio_device_t *)arg, &tmp, sizeof(tmp)); + } else + retval = -EINVAL; + break; + case AUDIO_GETDEV_SUNOS: + if (drv->ops->sunaudio_getdev_sunos) { + int tmp = drv->ops->sunaudio_getdev_sunos(drv); + + retval = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)); + if (!retval) + copy_to_user((int *)arg, &tmp, sizeof(tmp)); + } else + retval = -EINVAL; + break; + case AUDIO_GETINFO: + AUDIO_INITINFO(&ainfo); - switch (newinfo.record.encoding) { - case AUDIO_ENCODING_ALAW: - case AUDIO_ENCODING_ULAW: - if (newinfo.record.precision != 8) { - retval = -EINVAL; - break; - } - if (newinfo.record.channels != 1) { - retval = -EINVAL; - break; - } - break; - case AUDIO_ENCODING_LINEAR: - case AUDIO_ENCODING_LINEARLE: - if (newinfo.record.precision != 16) { - retval = -EINVAL; - break; - } - if (newinfo.record.channels != 1 && - newinfo.record.channels != 2) - { - retval = -EINVAL; - break; - } - break; - case AUDIO_ENCODING_LINEAR8: - if (newinfo.record.precision != 8) { - retval = -EINVAL; - break; - } - if (newinfo.record.channels != 1 && - newinfo.record.channels != 2) - { - retval = -EINVAL; - break; - } - } + if (drv->ops->get_input_rate) + ainfo.record.sample_rate = + drv->ops->get_input_rate(drv); + else + ainfo.record.sample_rate = (8000); + if (drv->ops->get_input_channels) + ainfo.record.channels = + drv->ops->get_input_channels(drv); + else + ainfo.record.channels = (1); + if (drv->ops->get_input_precision) + ainfo.record.precision = + drv->ops->get_input_precision(drv); + else + ainfo.record.precision = (8); + if (drv->ops->get_input_encoding) + ainfo.record.encoding = + drv->ops->get_input_encoding(drv); + else + ainfo.record.encoding = (AUDIO_ENCODING_ULAW); + if (drv->ops->get_input_volume) + ainfo.record.gain = + drv->ops->get_input_volume(drv); + else + ainfo.record.gain = (0); + if (drv->ops->get_input_port) + ainfo.record.port = + drv->ops->get_input_port(drv); + else + ainfo.record.port = (0); + if (drv->ops->get_input_ports) + ainfo.record.avail_ports = + drv->ops->get_input_ports(drv); + else + ainfo.record.avail_ports = (0); + /* To make e.g. vat happy, we let them think they control this */ + ainfo.record.buffer_size = drv->buffer_size; + if (drv->ops->get_input_samples) + ainfo.record.samples = drv->ops->get_input_samples(drv); + else + ainfo.record.samples = 0; + /* This is undefined in the record context in Solaris */ + ainfo.record.eof = 0; + if (drv->ops->get_input_pause) + ainfo.record.pause = + drv->ops->get_input_pause(drv); + else + ainfo.record.pause = 0; + if (drv->ops->get_input_error) + ainfo.record.error = + (unsigned char)drv->ops->get_input_error(drv); + else + ainfo.record.error = 0; + ainfo.record.waiting = 0; + if (drv->ops->get_input_balance) + ainfo.record.balance = + (unsigned char)drv->ops->get_input_balance(drv); + else + ainfo.record.balance = (unsigned char)(AUDIO_MID_BALANCE); + ainfo.record.minordev = 4 + (minor << SPARCAUDIO_DEVICE_SHIFT); + ainfo.record.open = (drv->flags & SDF_OPEN_READ); + ainfo.record.active = 0; + + if (drv->ops->get_output_rate) + ainfo.play.sample_rate = + drv->ops->get_output_rate(drv); + else + ainfo.play.sample_rate = (8000); + if (drv->ops->get_output_channels) + ainfo.play.channels = + drv->ops->get_output_channels(drv); + else + ainfo.play.channels = (1); + if (drv->ops->get_output_precision) + ainfo.play.precision = + drv->ops->get_output_precision(drv); + else + ainfo.play.precision = (8); + if (drv->ops->get_output_encoding) + ainfo.play.encoding = + drv->ops->get_output_encoding(drv); + else + ainfo.play.encoding = (AUDIO_ENCODING_ULAW); + if (drv->ops->get_output_volume) + ainfo.play.gain = + drv->ops->get_output_volume(drv); + else + ainfo.play.gain = (0); + if (drv->ops->get_output_port) + ainfo.play.port = + drv->ops->get_output_port(drv); + else + ainfo.play.port = (0); + if (drv->ops->get_output_ports) + ainfo.play.avail_ports = + drv->ops->get_output_ports(drv); + else + ainfo.play.avail_ports = (0); + /* This is not defined in the play context in Solaris */ + ainfo.play.buffer_size = 0; + if (drv->ops->get_output_samples) + ainfo.play.samples = drv->ops->get_output_samples(drv); + else + ainfo.play.samples = 0; + ainfo.play.eof = drv->output_eof; + if (drv->ops->get_output_pause) + ainfo.play.pause = + drv->ops->get_output_pause(drv); + else + ainfo.play.pause = 0; + if (drv->ops->get_output_error) + ainfo.play.error = + (unsigned char)drv->ops->get_output_error(drv); + else + ainfo.play.error = 0; + ainfo.play.waiting = waitqueue_active(&drv->open_wait); + if (drv->ops->get_output_balance) + ainfo.play.balance = + (unsigned char)drv->ops->get_output_balance(drv); + else + ainfo.play.balance = (unsigned char)(AUDIO_MID_BALANCE); + ainfo.play.minordev = 4 + (minor << SPARCAUDIO_DEVICE_SHIFT); + ainfo.play.open = (drv->flags & SDF_OPEN_WRITE); + ainfo.play.active = drv->output_active; + + if (drv->ops->get_monitor_volume) + ainfo.monitor_gain = + drv->ops->get_monitor_volume(drv); + else + ainfo.monitor_gain = (0); + + if (drv->ops->get_output_muted) + ainfo.output_muted = + (unsigned char)drv->ops->get_output_muted(drv); + else + ainfo.output_muted = (unsigned char)(0); + + retval = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct audio_info)); + if (retval < 0) + break; - if (retval < 0) - break; + copy_to_user((struct audio_info *)arg, &ainfo, sizeof(ainfo)); + + break; + case AUDIO_SETINFO: + { + audio_info_t curinfo, newinfo; + + if (verify_area(VERIFY_READ, (audio_info_t *)arg, + sizeof(audio_info_t))) { + dprintk(("verify_area failed\n")); + return -EINVAL; + } + copy_from_user(&ainfo, (audio_info_t *)arg, sizeof(audio_info_t)); - /* If they're trying to change something we - * have no routine for, they lose */ - if ((!driver->ops->set_output_encoding && - Modify(ainfo.play.encoding)) || - (!driver->ops->set_output_rate && - Modify(ainfo.play.sample_rate)) || - (!driver->ops->set_output_precision && - Modify(ainfo.play.precision)) || - (!driver->ops->set_output_channels && - Modify(ainfo.play.channels))) { + /* Without these there's no point in trying */ + if (!drv->ops->get_input_precision || + !drv->ops->get_input_channels || + !drv->ops->get_input_rate || + !drv->ops->get_input_encoding || + !drv->ops->get_output_precision || + !drv->ops->get_output_channels || + !drv->ops->get_output_rate || + !drv->ops->get_output_encoding) + { + eprintk(("missing get routines: failed\n")); retval = -EINVAL; break; - } - - curinfo.play.encoding = driver->ops->get_output_encoding(driver); - curinfo.play.sample_rate = driver->ops->get_output_rate(driver); - curinfo.play.precision = driver->ops->get_output_precision(driver); - curinfo.play.channels = driver->ops->get_output_channels(driver); - newinfo.play.encoding = Modify(ainfo.play.encoding) ? - ainfo.play.encoding : curinfo.play.encoding; - newinfo.play.sample_rate = Modify(ainfo.play.sample_rate) ? - ainfo.play.sample_rate : curinfo.play.sample_rate; - newinfo.play.precision = Modify(ainfo.play.precision) ? - ainfo.play.precision : curinfo.play.precision; - newinfo.play.channels = Modify(ainfo.play.channels) ? - ainfo.play.channels : curinfo.play.channels; - - switch (newinfo.play.encoding) { - case AUDIO_ENCODING_ALAW: - case AUDIO_ENCODING_ULAW: - if (newinfo.play.precision != 8) { - retval = -EINVAL; - break; - } - if (newinfo.play.channels != 1) { - retval = -EINVAL; - break; - } - break; - case AUDIO_ENCODING_LINEAR: - case AUDIO_ENCODING_LINEARLE: - if (newinfo.play.precision != 16) { - retval = -EINVAL; - break; - } - if (newinfo.play.channels != 1 && - newinfo.play.channels != 2) - { - retval = -EINVAL; - break; - } - break; - case AUDIO_ENCODING_LINEAR8: - if (newinfo.play.precision != 8) { - retval = -EINVAL; - break; - } - if (newinfo.play.channels != 1 && - newinfo.play.channels != 2) - { - retval = -EINVAL; - break; - } - } - - if (retval < 0) - break; + } - /* If we got this far, we're at least sane with - * respect to generics. Try the changes. */ - if ((driver->ops->set_input_precision(driver, ainfo.record.precision) < 0) || - (driver->ops->set_output_precision(driver, ainfo.play.precision) < 0) || - (driver->ops->set_input_channels(driver, ainfo.record.channels) < 0) || - (driver->ops->set_output_channels(driver, ainfo.play.channels) < 0) || - (driver->ops->set_input_rate(driver, ainfo.record.sample_rate) < 0) || - (driver->ops->set_output_rate(driver, ainfo.play.sample_rate) < 0) || - (driver->ops->set_input_encoding(driver, ainfo.record.encoding) < 0) || - (driver->ops->set_output_encoding(driver, ainfo.play.encoding) < 0)) - { - /* Pray we can set it all back. If not, uh... */ - driver->ops->set_input_precision(driver, curinfo.record.precision); - driver->ops->set_output_precision(driver, curinfo.play.precision); - driver->ops->set_input_channels(driver, curinfo.record.channels); - driver->ops->set_output_channels(driver, curinfo.play.channels); - driver->ops->set_input_rate(driver, curinfo.record.sample_rate); - driver->ops->set_output_rate(driver, curinfo.play.sample_rate); - driver->ops->set_input_encoding(driver, curinfo.record.encoding); - driver->ops->set_output_encoding(driver, curinfo.play.encoding); + /* Do bounds checking for things which always apply. + * Follow with enforcement of basic tenets of certain + * encodings. Everything over and above generic is + * enforced by the driver, which can assume that + * Martian cases are taken care of here. */ + if (Modify(ainfo.play.gain) && + ((ainfo.play.gain > AUDIO_MAX_GAIN) || + (ainfo.play.gain < AUDIO_MIN_GAIN))) { + /* Need to differentiate this from e.g. the above error */ + eprintk(("play gain bounds: failed %d\n", ainfo.play.gain)); + retval = -EINVAL; + break; + } + if (Modify(ainfo.record.gain) && + ((ainfo.record.gain > AUDIO_MAX_GAIN) || + (ainfo.record.gain < AUDIO_MIN_GAIN))) { + eprintk(("rec gain bounds: failed %d\n", ainfo.record.gain)); + retval = -EINVAL; + break; + } + if (Modify(ainfo.monitor_gain) && + ((ainfo.monitor_gain > AUDIO_MAX_GAIN) || + (ainfo.monitor_gain < AUDIO_MIN_GAIN))) { + eprintk(("monitor gain bounds: failed\n")); + retval = -EINVAL; + break; + } + /* Don't need to check less than zero on these */ + if (Modifyc(ainfo.play.balance) && + (ainfo.play.balance > AUDIO_RIGHT_BALANCE)) { + eprintk(("play balance bounds: %d failed\n", + (int)ainfo.play.balance)); + retval = -EINVAL; + break; + } + if (Modifyc(ainfo.record.balance) && + (ainfo.record.balance > AUDIO_RIGHT_BALANCE)) { + eprintk(("rec balance bounds: failed\n")); + retval = -EINVAL; + break; + } + + /* If any of these changed, record them all, then make + * changes atomically. If something fails, back it all out. */ + if (Modify(ainfo.record.precision) || + Modify(ainfo.record.sample_rate) || + Modify(ainfo.record.channels) || + Modify(ainfo.record.encoding) || + Modify(ainfo.play.precision) || + Modify(ainfo.play.sample_rate) || + Modify(ainfo.play.channels) || + Modify(ainfo.play.encoding)) + { + /* If they're trying to change something we + * have no routine for, they lose */ + if ((!drv->ops->set_input_encoding && + Modify(ainfo.record.encoding)) || + (!drv->ops->set_input_rate && + Modify(ainfo.record.sample_rate)) || + (!drv->ops->set_input_precision && + Modify(ainfo.record.precision)) || + (!drv->ops->set_input_channels && + Modify(ainfo.record.channels))) { + eprintk(("rec set no routines: failed\n")); + retval = -EINVAL; + break; + } + + curinfo.record.encoding = + drv->ops->get_input_encoding(drv); + curinfo.record.sample_rate = + drv->ops->get_input_rate(drv); + curinfo.record.precision = + drv->ops->get_input_precision(drv); + curinfo.record.channels = + drv->ops->get_input_channels(drv); + newinfo.record.encoding = Modify(ainfo.record.encoding) ? + ainfo.record.encoding : curinfo.record.encoding; + newinfo.record.sample_rate = + Modify(ainfo.record.sample_rate)? + ainfo.record.sample_rate : curinfo.record.sample_rate; + newinfo.record.precision = Modify(ainfo.record.precision) ? + ainfo.record.precision : curinfo.record.precision; + newinfo.record.channels = Modify(ainfo.record.channels) ? + ainfo.record.channels : curinfo.record.channels; + + switch (newinfo.record.encoding) { + case AUDIO_ENCODING_ALAW: + case AUDIO_ENCODING_ULAW: + if (newinfo.record.precision != 8) { + eprintk(("rec law precision bounds: failed\n")); + retval = -EINVAL; + break; + } + if (newinfo.record.channels != 1) { + eprintk(("rec law channel bounds: failed\n")); + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR: + case AUDIO_ENCODING_LINEARLE: + if (newinfo.record.precision != 16) { + eprintk(("rec lin precision bounds: failed\n")); + retval = -EINVAL; + break; + } + if (newinfo.record.channels != 1 && + newinfo.record.channels != 2) + { + eprintk(("rec lin channel bounds: failed\n")); + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR8: + if (newinfo.record.precision != 8) { + eprintk(("rec lin8 precision bounds: failed\n")); + retval = -EINVAL; + break; + } + if (newinfo.record.channels != 1 && + newinfo.record.channels != 2) + { + eprintk(("rec lin8 channel bounds: failed\n")); + retval = -EINVAL; + break; + } + } + + if (retval < 0) + break; + + /* If they're trying to change something we + * have no routine for, they lose */ + if ((!drv->ops->set_output_encoding && + Modify(ainfo.play.encoding)) || + (!drv->ops->set_output_rate && + Modify(ainfo.play.sample_rate)) || + (!drv->ops->set_output_precision && + Modify(ainfo.play.precision)) || + (!drv->ops->set_output_channels && + Modify(ainfo.play.channels))) { + eprintk(("play set no routine: failed\n")); + retval = -EINVAL; + break; + } + + curinfo.play.encoding = + drv->ops->get_output_encoding(drv); + curinfo.play.sample_rate = + drv->ops->get_output_rate(drv); + curinfo.play.precision = + drv->ops->get_output_precision(drv); + curinfo.play.channels = + drv->ops->get_output_channels(drv); + newinfo.play.encoding = Modify(ainfo.play.encoding) ? + ainfo.play.encoding : curinfo.play.encoding; + newinfo.play.sample_rate = Modify(ainfo.play.sample_rate) ? + ainfo.play.sample_rate : curinfo.play.sample_rate; + newinfo.play.precision = Modify(ainfo.play.precision) ? + ainfo.play.precision : curinfo.play.precision; + newinfo.play.channels = Modify(ainfo.play.channels) ? + ainfo.play.channels : curinfo.play.channels; + + switch (newinfo.play.encoding) { + case AUDIO_ENCODING_ALAW: + case AUDIO_ENCODING_ULAW: + if (newinfo.play.precision != 8) { + eprintk(("play law precision bounds: failed\n")); + retval = -EINVAL; + break; + } + if (newinfo.play.channels != 1) { + eprintk(("play law channel bounds: failed\n")); + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR: + case AUDIO_ENCODING_LINEARLE: + if (newinfo.play.precision != 16) { + eprintk(("play lin precision bounds: failed\n")); + retval = -EINVAL; + break; + } + if (newinfo.play.channels != 1 && + newinfo.play.channels != 2) + { + eprintk(("play lin channel bounds: failed\n")); + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR8: + if (newinfo.play.precision != 8) { + eprintk(("play lin8 precision bounds: failed\n")); + retval = -EINVAL; + break; + } + if (newinfo.play.channels != 1 && + newinfo.play.channels != 2) + { + eprintk(("play lin8 channel bounds: failed\n")); + retval = -EINVAL; + break; + } } + + if (retval < 0) + break; + + /* If we got this far, we're at least sane with + * respect to generics. Try the changes. */ + if ((drv->ops->set_input_channels && + (drv->ops->set_input_channels(drv, + newinfo.record.channels) + < 0)) || + (drv->ops->set_output_channels && + (drv->ops->set_output_channels(drv, + newinfo.play.channels) + < 0)) || + (drv->ops->set_input_rate && + (drv->ops->set_input_rate(drv, + newinfo.record.sample_rate) + < 0)) || + (drv->ops->set_output_rate && + (drv->ops->set_output_rate(drv, + newinfo.play.sample_rate) + < 0)) || + (drv->ops->set_input_precision && + (drv->ops->set_input_precision(drv, + newinfo.record.precision) + < 0)) || + (drv->ops->set_output_precision && + (drv->ops->set_output_precision(drv, + newinfo.play.precision) + < 0)) || + (drv->ops->set_input_encoding && + (drv->ops->set_input_encoding(drv, + newinfo.record.encoding) + < 0)) || + (drv->ops->set_output_encoding && + (drv->ops->set_output_encoding(drv, + newinfo.play.encoding) + < 0))) + { + dprintk(("setting format: failed\n")); + /* Pray we can set it all back. If not, uh... */ + if (drv->ops->set_input_channels) + drv->ops->set_input_channels(drv, + curinfo.record.channels); + if (drv->ops->set_output_channels) + drv->ops->set_output_channels(drv, + curinfo.play.channels); + if (drv->ops->set_input_rate) + drv->ops->set_input_rate(drv, + curinfo.record.sample_rate); + if (drv->ops->set_output_rate) + drv->ops->set_output_rate(drv, + curinfo.play.sample_rate); + if (drv->ops->set_input_precision) + drv->ops->set_input_precision(drv, + curinfo.record.precision); + if (drv->ops->set_output_precision) + drv->ops->set_output_precision(drv, + curinfo.play.precision); + if (drv->ops->set_input_encoding) + drv->ops->set_input_encoding(drv, + curinfo.record.encoding); + if (drv->ops->set_output_encoding) + drv->ops->set_output_encoding(drv, + curinfo.play.encoding); + retval = -EINVAL; + break; + } + } + + if (retval < 0) + break; + + newinfo.record.balance = + __sparcaudio_if_setc_do(drv, + drv->ops->set_input_balance, + drv->ops->get_input_balance, + ainfo.record.balance); + newinfo.play.balance = + __sparcaudio_if_setc_do(drv, + drv->ops->set_output_balance, + drv->ops->get_output_balance, + ainfo.play.balance); + newinfo.record.error = + __sparcaudio_if_setc_do(drv, + drv->ops->set_input_error, + drv->ops->get_input_error, + ainfo.record.error); + newinfo.play.error = + __sparcaudio_if_setc_do(drv, + drv->ops->set_output_error, + drv->ops->get_output_error, + ainfo.play.error); + newinfo.output_muted = + __sparcaudio_if_setc_do(drv, + drv->ops->set_output_muted, + drv->ops->get_output_muted, + ainfo.output_muted); + newinfo.record.gain = + __sparcaudio_if_set_do(drv, + drv->ops->set_input_volume, + drv->ops->get_input_volume, + ainfo.record.gain); + newinfo.play.gain = + __sparcaudio_if_set_do(drv, + drv->ops->set_output_volume, + drv->ops->get_output_volume, + ainfo.play.gain); + newinfo.record.port = + __sparcaudio_if_set_do(drv, + drv->ops->set_input_port, + drv->ops->get_input_port, + ainfo.record.port); + newinfo.play.port = + __sparcaudio_if_set_do(drv, + drv->ops->set_output_port, + drv->ops->get_output_port, + ainfo.play.port); + newinfo.record.samples = + __sparcaudio_if_set_do(drv, + drv->ops->set_input_samples, + drv->ops->get_input_samples, + ainfo.record.samples); + newinfo.play.samples = + __sparcaudio_if_set_do(drv, + drv->ops->set_output_samples, + drv->ops->get_output_samples, + ainfo.play.samples); + newinfo.monitor_gain = + __sparcaudio_if_set_do(drv, + drv->ops->set_monitor_volume, + drv->ops->get_monitor_volume, + ainfo.monitor_gain); + + if (Modify(ainfo.record.buffer_size)) { + /* Should sanity check this */ + newinfo.record.buffer_size = ainfo.record.buffer_size; + drv->buffer_size = ainfo.record.buffer_size; + } else + newinfo.record.buffer_size = drv->buffer_size; + + + if (Modify(ainfo.play.eof)) { + ainfo.play.eof = newinfo.play.eof; + newinfo.play.eof = drv->output_eof; + drv->output_eof = ainfo.play.eof; + } else + newinfo.play.eof = drv->output_eof; + + if (drv->flags & SDF_OPEN_READ) { + newinfo.record.pause = + __sparcaudio_if_setc_do(drv, + drv->ops->set_input_pause, + drv->ops->get_input_pause, + ainfo.record.pause); + } else if (drv->ops->get_input_pause) { + newinfo.record.pause = drv->ops->get_input_pause(drv); + } else newinfo.record.pause = 0; + + if (drv->flags & SDF_OPEN_WRITE) { + newinfo.play.pause = + __sparcaudio_if_setc_do(drv, + drv->ops->set_output_pause, + drv->ops->get_output_pause, + ainfo.play.pause); + } else if (drv->ops->get_output_pause) { + newinfo.play.pause = drv->ops->get_output_pause(drv); + } else newinfo.play.pause = 0; + + retval = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct audio_info)); + + /* Even if we fail, if we made changes let's try notification */ + if (!retval) + copy_to_user((struct audio_info *)arg, &newinfo, + sizeof(newinfo)); + +#ifdef REAL_AUDIO_SIGNALS + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); +#endif + break; } - /* Maybe this should be a routine instead of a macro */ -#define IF_SET_DO(x,y) if ((x) && Modify(y)) x(driver, y) -#define IF_SETC_DO(x,y) if ((x) && Modifyc(y)) x(driver, y) - IF_SETC_DO(driver->ops->set_input_balance, (int)ainfo.record.balance); - IF_SETC_DO(driver->ops->set_output_balance, (int)ainfo.play.balance); - IF_SET_DO(driver->ops->set_input_volume, ainfo.record.gain); - IF_SET_DO(driver->ops->set_output_volume, ainfo.play.gain); - IF_SET_DO(driver->ops->set_input_port, ainfo.record.port); - IF_SET_DO(driver->ops->set_output_port, ainfo.play.port); - IF_SET_DO(driver->ops->set_monitor_volume, ainfo.monitor_gain); - IF_SETC_DO(driver->ops->set_output_muted, (int)ainfo.output_muted); -#undef IF_SET_DO -#undef IF_SETC_DO - - break; + + default: + if (drv->ops->ioctl) + retval = drv->ops->ioctl(inode,file,cmd,arg,drv); + else + retval = -EINVAL; } - + break; + case SPARCAUDIO_STATUS_MINOR: + eprintk(("status minor not yet implemented\n")); + retval = -EINVAL; default: - if (driver->ops->ioctl) - retval = driver->ops->ioctl(inode,file,cmd,arg,driver); - else { - retval = -EINVAL; - } + eprintk(("unknown minor device number\n")); + retval = -EINVAL; } - + return retval; } -static int sparcaudioctl_release(struct inode * inode, struct file * file) +static int sparcaudioctl_release_ret(struct inode * inode, struct file * file) { - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; + return 0; +} - return 0; +/* For 2.0 kernels */ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 +static void sparcaudioctl_release(struct inode * inode, struct file * file) +{ + sparcaudioctl_release_ret(inode, file); } +#endif static struct file_operations sparcaudioctl_fops = { - NULL, - NULL, - NULL, - NULL, /* sparcaudio_readdir */ - NULL, /* sparcaudio_select */ - sparcaudio_ioctl, - NULL, /* sparcaudio_mmap */ - NULL, - NULL, /* flush */ - sparcaudioctl_release + NULL, + NULL, + NULL, + NULL, /* sparcaudio_readdir */ + sparcaudio_select, + sparcaudio_ioctl, + NULL, /* sparcaudio_mmap */ + NULL, +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff + NULL, /* sparcaudio_flush */ +#endif + sparcaudioctl_release, }; static int sparcaudio_open(struct inode * inode, struct file * file) { - int minor = MINOR(inode->i_rdev); - int err; + int minor = MINOR(inode->i_rdev); + struct sparcaudio_driver *drv = + drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)]; + int err; + + /* A low-level audio driver must exist. */ + if (!drv) + return -ENODEV; + + switch (minor & 0xf) { + case SPARCAUDIO_AUDIOCTL_MINOR: + file->f_op = &sparcaudioctl_fops; + break; + case SPARCAUDIO_DSP16_MINOR: + case SPARCAUDIO_DSP_MINOR: + case SPARCAUDIO_AUDIO_MINOR: + /* If the driver is busy, then wait to get through. */ + retry_open: + if (file->f_mode & FMODE_READ && drv->flags & SDF_OPEN_READ) { + if (file->f_flags & O_NONBLOCK) + return -EBUSY; + + /* If something is now waiting, signal control device */ + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); - /* A low-level audio driver must exist. */ - if (!driver) - return -ENODEV; - - switch (minor) { - case SPARCAUDIO_AUDIOCTL_MINOR: - file->f_op = &sparcaudioctl_fops; - break; - - case SPARCAUDIO_DSP16_MINOR: - case SPARCAUDIO_DSP_MINOR: - case SPARCAUDIO_AUDIO_MINOR: - /* If the driver is busy, then wait to get through. */ - retry_open: - if (file->f_mode & FMODE_READ && driver->flags & SDF_OPEN_READ) { - if (file->f_flags & O_NONBLOCK) - return -EBUSY; - - interruptible_sleep_on(&driver->open_wait); + interruptible_sleep_on(&drv->open_wait); if (signal_pending(current)) - return -EINTR; - goto retry_open; - } - if (file->f_mode & FMODE_WRITE && driver->flags & SDF_OPEN_WRITE) { - if (file->f_flags & O_NONBLOCK) - return -EBUSY; - - interruptible_sleep_on(&driver->open_wait); + return -EINTR; + goto retry_open; + } + if (file->f_mode & FMODE_WRITE && drv->flags & SDF_OPEN_WRITE) { + if (file->f_flags & O_NONBLOCK) + return -EBUSY; + + /* If something is now waiting, signal control device */ + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); + + interruptible_sleep_on(&drv->open_wait); if (signal_pending(current)) - return -EINTR; - goto retry_open; - } + return -EINTR; + goto retry_open; + } - /* Allow the low-level driver to initialize itself. */ - if (driver->ops->open) { - err = driver->ops->open(inode,file,driver); - if (err < 0) - return err; - } - - /* Mark the driver as locked for read and/or write. */ - if (file->f_mode & FMODE_READ) { - driver->input_offset = 0; - driver->input_front = 0; - driver->input_rear = 0; - driver->input_count = 0; - driver->recording_count = 0; - driver->ops->start_input(driver, driver->input_buffers[driver->input_front], - 4096); - driver->input_active = 1; - driver->flags |= SDF_OPEN_READ; + /* Allow the low-level driver to initialize itself. */ + if (drv->ops->open) { + err = drv->ops->open(inode,file,drv); + if (err < 0) + return err; + } + + /* Mark the driver as locked for read and/or write. */ + if (file->f_mode & FMODE_READ) { + drv->input_offset = 0; + drv->input_front = 0; + drv->input_rear = 0; + drv->input_count = 0; + drv->input_size = 0; + drv->recording_count = 0; + /* Clear pause */ + if (drv->ops->set_input_pause) + drv->ops->set_input_pause(drv, 0); + drv->ops->start_input(drv, drv->input_buffers[drv->input_front], + drv->input_buffer_size); + drv->input_active = 1; + drv->flags |= SDF_OPEN_READ; + } + if (file->f_mode & FMODE_WRITE) { + drv->output_offset = 0; + drv->output_eof = 0; + drv->playing_count = 0; + drv->output_size = 0; + drv->output_front = 0; + drv->output_rear = 0; + drv->output_count = 0; + drv->output_active = 0; + /* Clear pause */ + if (drv->ops->set_output_pause) + drv->ops->set_output_pause(drv, 0); + drv->flags |= SDF_OPEN_WRITE; + } + + break; + case SPARCAUDIO_MIXER_MINOR: + file->f_op = &sparcaudioctl_fops; + break; + + default: + return -ENXIO; } - if (file->f_mode & FMODE_WRITE) { - driver->playing_count = 0; - driver->output_size = 0; - driver->output_front = 0; - driver->output_rear = 0; - driver->output_count = 0; - driver->output_active = 0; - driver->flags |= SDF_OPEN_WRITE; - } - break; - case SPARCAUDIO_MIXER_MINOR: - file->f_op = &sparcaudioctl_fops; - break; - default: - return -ENXIO; - } + MOD_INC_USE_COUNT; - MOD_INC_USE_COUNT; - - /* Success! */ - return 0; + /* Success! */ + return 0; } -static int sparcaudio_release(struct inode * inode, struct file * file) +static int sparcaudio_release_ret(struct inode * inode, struct file * file) { - /* Anything in the queue? */ - sparcaudio_sync_output(driver); + struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> + SPARCAUDIO_DEVICE_SHIFT)]; - /* Stop input */ - driver->ops->stop_input(driver); - driver->input_active = 0; + if (file->f_mode & FMODE_READ) { + /* Stop input */ + drv->ops->stop_input(drv); + drv->input_active = 0; + } + + if (file->f_mode & FMODE_WRITE) { + /* Anything in the queue? */ + if (drv->output_offset) { + drv->output_offset = 0; + drv->output_rear = (drv->output_rear + 1) + % drv->num_output_buffers; + drv->output_count++; + } + sparcaudio_sync_output(drv); - /* Wait for any output still in the queue to be played. */ - if (driver->output_count > 0) - interruptible_sleep_on(&driver->output_drain_wait); + /* Wait for any output still in the queue to be played. */ + if ((drv->output_count > 0) || (drv->playing_count > 0)) + interruptible_sleep_on(&drv->output_drain_wait); - /* Force any output to be stopped. */ - driver->ops->stop_output(driver); - driver->output_active = 0; + /* Force any output to be stopped. */ + drv->ops->stop_output(drv); + drv->output_active = 0; + drv->playing_count = 0; + drv->output_eof = 0; - /* Let the low-level driver do any release processing. */ - if (driver->ops->release) - driver->ops->release(inode,file,driver); + } - if (file->f_mode & FMODE_READ) - driver->flags &= ~(SDF_OPEN_READ); + /* Let the low-level driver do any release processing. */ + if (drv->ops->release) + drv->ops->release(inode,file,drv); - if (file->f_mode & FMODE_WRITE) - driver->flags &= ~(SDF_OPEN_WRITE); + if (file->f_mode & FMODE_READ) + drv->flags &= ~(SDF_OPEN_READ); - MOD_DEC_USE_COUNT; + if (file->f_mode & FMODE_WRITE) + drv->flags &= ~(SDF_OPEN_WRITE); - wake_up_interruptible(&driver->open_wait); + /* Status changed. Signal control device */ + kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); - return 0; + MOD_DEC_USE_COUNT; + + wake_up_interruptible(&drv->open_wait); + + return 0; +} + +/* For 2.0 kernels */ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 +static void sparcaudio_release(struct inode * inode, struct file * file) +{ + sparcaudio_release_ret(inode, file); } +#endif static struct file_operations sparcaudio_fops = { - sparcaudio_llseek, + sparcaudio_lseek, sparcaudio_read, sparcaudio_write, NULL, /* sparcaudio_readdir */ - NULL, /* sparcaudio_select */ + sparcaudio_select, sparcaudio_ioctl, NULL, /* sparcaudio_mmap */ sparcaudio_open, +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff + NULL, /* sparcaudio_flush */ +#endif sparcaudio_release }; +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 +static struct symbol_table sparcaudio_syms = { +#include + X(register_sparcaudio_driver), + X(unregister_sparcaudio_driver), + X(sparcaudio_output_done), + X(sparcaudio_input_done), +#include +}; +#else EXPORT_SYMBOL(register_sparcaudio_driver); EXPORT_SYMBOL(unregister_sparcaudio_driver); EXPORT_SYMBOL(sparcaudio_output_done); EXPORT_SYMBOL(sparcaudio_input_done); +#endif #ifdef MODULE int init_module(void) @@ -1023,20 +2058,27 @@ __initfunc(int sparcaudio_init(void)) #endif { +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 + /* Export symbols for use by the low-level drivers. */ + register_symtab(&sparcaudio_syms); +#endif + /* Register our character device driver with the VFS. */ if (register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops)) return -EIO; + #ifdef CONFIG_SPARCAUDIO_AMD7930 amd7930_init(); #endif - +#ifdef CONFIG_SPARCAUDIO_DBRI + dbri_init(); +#endif #ifdef CONFIG_SPARCAUDIO_CS4231 cs4231_init(); #endif - -#ifdef CONFIG_SPARCAUDIO_DBRI - dbri_init(); +#ifdef CONFIG_SPARCAUDIO_DUMMY + dummy_init(); #endif return 0; @@ -1048,6 +2090,147 @@ unregister_chrdev(SOUND_MAJOR, "sparcaudio"); } #endif + +/* + * Code from Linux Streams, Copyright 1995 by + * Graham Wheeler, Francisco J. Ballesteros, Denis Froschauer + * and available under GPL + */ + +static int +lis_add_to_elist( strevent_t **list, pid_t pid, short events ) +{ + strevent_t *ev = NULL; + + if (*list != NULL) + { + for (ev=(*list)->se_next; + ev != *list && ev->se_pid < pid; + ev=ev->se_next + ); + } + + if (ev == NULL || ev == *list) /* no slot for pid in list */ + { + if ((ev = (strevent_t*)kmalloc(sizeof(strevent_t),GFP_KERNEL))==NULL) + return(-ENOMEM); + + if (!*list) /* create dummy head node */ + { + strevent_t *hd; + if ((hd = (strevent_t*)kmalloc(sizeof(strevent_t),GFP_KERNEL) + )==NULL) + { + kfree(ev); + return(-ENOMEM); + } + (*list=hd)->se_pid=0; + hd->se_next=hd->se_prev=hd; /* empty list */ + } + + /* link node last in the list */ + ev->se_prev=(*list)->se_prev; + (*list)->se_prev->se_next=ev; + ((*list)->se_prev=ev)->se_next=*list; + + ev->se_pid=pid; + ev->se_evs=0; + } + else if (ev->se_pid!=pid){ /* link node in the middle of the list */ + strevent_t *new; + if ((new = (strevent_t*)kmalloc(sizeof(strevent_t),GFP_KERNEL))==NULL){ + return(-ENOMEM); + } + new->se_prev=ev->se_prev; + new->se_next=ev; + ev->se_prev->se_next=new; + ev->se_prev=new; + ev = new ; /* use new element */ + ev->se_pid=pid; + ev->se_evs=0; + } + ev->se_evs|=events; + return(0); +} + +static int +lis_del_from_elist( strevent_t **list, pid_t pid, short events ) +{ + strevent_t *ev = NULL; + + if (*list != NULL) + { + for (ev=(*list)->se_next; + ev != *list && ev->se_pid < pid; + ev=ev->se_next + ); + } + + if (ev == NULL || ev == *list || ev->se_pid != pid ) + return(1); + + if ( (ev->se_evs &= ~events) == 0 ){ /* unlink */ + if (ev->se_next) /* should always be true */ + ev->se_next->se_prev=ev->se_prev; + if (ev->se_prev) /* should always be true */ + ev->se_prev->se_next=ev->se_next; + kfree(ev); + } + return(0); +} + +static void +lis_free_elist( strevent_t **list ) +{ + strevent_t *ev; + strevent_t *nxt ; + + for (ev = *list; ev != NULL; ) + { + nxt = ev->se_next ; + kfree(ev) ; + ev = nxt ; + if (ev == *list) break ; /* all done */ + } + + *list = NULL ; +} + +static short +lis_get_elist_ent( strevent_t *list, pid_t pid ) +{ + strevent_t *ev = NULL; + + if (list == NULL) return(0) ; + + for(ev = list->se_next ; ev != list && ev->se_pid < pid; ev=ev->se_next ) + ; + if (ev != list && ev->se_pid == pid) + return(ev->se_evs); + else + return(0); +} + +static void +kill_procs( struct strevent *elist, int sig, short e) +{ + strevent_t *ev; + int res; + + (void) sig ; + if (elist) { + for(ev = elist->se_next ; ev != elist; ev=ev->se_next ) + if ((ev->se_evs & e) != 0){ + if ((res=kill_proc(ev->se_pid,SIGPOLL,1))<0) { + if (res == -3) { + lis_del_from_elist(&elist, ev->se_pid, S_ALL); + continue; + } + dprintk(("kill_proc: errno %d\n",res)); + } + } + } +} /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.1.128/linux/drivers/sbus/audio/cs4231.c Thu Aug 6 14:06:32 1998 +++ linux/drivers/sbus/audio/cs4231.c Wed Nov 18 09:06:05 1998 @@ -1,10 +1,10 @@ /* * drivers/sbus/audio/cs4231.c * - * Copyright (C) 1996, 1997 Derrick J Brashear (shadow@andrew.cmu.edu) + * Copyright 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu) * * Based on the AMD7930 driver: - * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) * * This is the lowlevel driver for the CS4231 audio chip found on some * sun4m and sun4u machines. @@ -14,6 +14,7 @@ * The APC DMA controller support unfortunately is not documented. Thanks, Sun */ +#include #include #include #include @@ -22,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -35,7 +38,7 @@ #undef __CS4231_DEBUG #undef __CS4231_TRACE -#undef __CS4231_ERROR +#define __CS4231_ERROR #ifdef __CS4231_ERROR #define eprintk(x) printk x #else @@ -70,7 +73,7 @@ static void cs4231_getsamplecount(struct sparcaudio_driver *drv, unsigned int length, unsigned int value); -#define CHIP_READY udelay(100); cs4231_ready(drv); mdelay(1); +#define CHIP_READY udelay(100); cs4231_ready(drv); udelay(1000); /* Enable cs4231 interrupts atomically. */ static __inline__ void cs4231_enable_interrupts(struct sparcaudio_driver *drv) @@ -269,7 +272,7 @@ return 0; } } - eprintk(("output enc failed\n")); + dprintk(("output enc failed\n")); return -EINVAL; } @@ -285,7 +288,7 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int tmp_bits, set_bits; - dprintk(("input encoding %d\n", value)); + tprintk(("input encoding %d\n", value)); if (value != 0) { set_bits = cs4231_encoding_to_bits(drv, value); if (set_bits >= 0) { @@ -299,7 +302,7 @@ return 0; } } - eprintk(("input enc failed\n")); + dprintk(("input enc failed\n")); return -EINVAL; } @@ -329,7 +332,7 @@ return 0; } } - eprintk(("output rate failed\n")); + dprintk(("output rate failed\n")); return -EINVAL; } @@ -345,7 +348,7 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int tmp_bits, set_bits; - dprintk(("input rate %d\n", value)); + tprintk(("input rate %d\n", value)); if (value != 0) { set_bits = cs4231_rate_to_bits(drv, value); if (set_bits >= 0) { @@ -359,7 +362,7 @@ return 0; } } - eprintk(("input rate failed\n")); + dprintk(("input rate failed\n")); return -EINVAL; } @@ -376,7 +379,7 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int tmp_bits; - dprintk(("input channels %d\n", value)); + tprintk(("input channels %d\n", value)); cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c; tmp_bits = cs4231_chip->regs->idr; switch (value) { @@ -387,7 +390,7 @@ cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits); break; default: - eprintk(("input chan failed\n")); + dprintk(("input chan failed\n")); return -(EINVAL); } @@ -421,7 +424,7 @@ cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits); break; default: - eprintk(("output chan failed\n")); + dprintk(("output chan failed\n")); return -(EINVAL); } @@ -437,29 +440,33 @@ return cs4231_chip->perchip_info.play.channels; } -static int cs4231_set_input_precision(struct sparcaudio_driver *drv, int value) +static int cs4231_get_input_precision(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - cs4231_chip->perchip_info.record.precision = value; - return 0; + return cs4231_chip->perchip_info.record.precision; } -static int cs4231_get_input_precision(struct sparcaudio_driver *drv) +static int cs4231_get_output_precision(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - return cs4231_chip->perchip_info.record.precision; + return cs4231_chip->perchip_info.play.precision; } -static int cs4231_set_output_precision(struct sparcaudio_driver *drv, int value) +static int cs4231_set_input_precision(struct sparcaudio_driver *drv, int val) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - cs4231_chip->perchip_info.play.precision = value; - return 0; + + cs4231_chip->perchip_info.record.precision = val; + + return cs4231_chip->perchip_info.record.precision; } -static int cs4231_get_output_precision(struct sparcaudio_driver *drv) +static int cs4231_set_output_precision(struct sparcaudio_driver *drv, int val) { - struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + cs4231_chip->perchip_info.play.precision = val; + return cs4231_chip->perchip_info.play.precision; } @@ -509,6 +516,12 @@ return cs4231_chip->perchip_info.output_muted; } +static int cs4231_get_formats(struct sparcaudio_driver *drv) +{ + return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_IMA_ADPCM | + AFMT_S16_LE | AFMT_S16_BE); +} + static int cs4231_get_output_ports(struct sparcaudio_driver *drv) { return (AUDIO_LINE_OUT | AUDIO_SPEAKER | AUDIO_HEADPHONE); @@ -577,11 +590,11 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int retval = 0; - dprintk(("input port: %d\n", value)); + tprintk(("input port: %d\n", value)); /* You can have one and only one. This is probably wrong, but * appears to be how SunOS is doing it. Should be able to mix. - * More work to be done. + * More work to be done. CD input mixable, analog loopback may be. */ /* Ultra systems do not support AUDIO_INTERNAL_CD_IN */ @@ -663,6 +676,58 @@ return (int)cs4231_chip->perchip_info.monitor_gain; } +static int cs4231_get_output_error(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + return (int)cs4231_chip->perchip_info.play.error; +} + +static int cs4231_get_input_error(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + return (int)cs4231_chip->perchip_info.record.error; +} + +static int cs4231_get_output_samples(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int count = + cs4231_length_to_samplecount(&cs4231_chip->perchip_info.play, + cs4231_chip->regs->dmapc); + + return (cs4231_chip->perchip_info.play.samples - + ((count > cs4231_chip->perchip_info.play.samples) + ? 0 : count)); +} + +static int cs4231_get_input_samples(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int count = + cs4231_length_to_samplecount(&cs4231_chip->perchip_info.record, + cs4231_chip->regs->dmacc); + + return (cs4231_chip->perchip_info.record.samples - + ((count > cs4231_chip->perchip_info.record.samples) ? + 0 : count)); +} + +static int cs4231_get_output_pause(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + return (int)cs4231_chip->perchip_info.play.pause; +} + +static int cs4231_get_input_pause(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + return (int)cs4231_chip->perchip_info.record.pause; +} + /* But for play/record we have these cheesy jacket routines because of * how this crap gets set */ static int cs4231_set_input_volume(struct sparcaudio_driver *drv, int value) @@ -704,7 +769,7 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; cs4231_chip->perchip_info.record.balance = value; - cs4231_record_gain(drv, cs4231_chip->perchip_info.record.gain, + cs4231_record_gain(drv, cs4231_chip->perchip_info.record.gain, cs4231_chip->perchip_info.record.balance); return 0; @@ -745,13 +810,11 @@ r = l = value; if (balance < AUDIO_MID_BALANCE) { - r = (int)(value - ((AUDIO_MID_BALANCE - balance) - << AUDIO_BALANCE_SHIFT)); - if (r < 0) r = 0; + r = (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT)); + if (r < 0) r = 0; } else if (balance > AUDIO_MID_BALANCE) { - l = (int)(value - ((balance - AUDIO_MID_BALANCE) - << AUDIO_BALANCE_SHIFT)); - if (l < 0) l = 0; + l = (int)(value - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT)); + if (l < 0) l = 0; } l_adj = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1); @@ -785,20 +848,18 @@ tprintk(("in play_gain: %d %c\n", value, balance)); r = l = value; if (balance < AUDIO_MID_BALANCE) { - r = (int)(value - ((AUDIO_MID_BALANCE - balance) - << AUDIO_BALANCE_SHIFT)); - if (r < 0) r = 0; + r = (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT)); + if (r < 0) r = 0; } else if (balance > AUDIO_MID_BALANCE) { - l = (int)(value - ((balance - AUDIO_MID_BALANCE) - << AUDIO_BALANCE_SHIFT)); - if (l < 0) l = 0; + l = (int)(value - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT)); + if (l < 0) l = 0; } (l == 0) ? (l_adj = CS4231_MAX_DEV_ATEN) : (l_adj = CS4231_MAX_ATEN - (l * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1))); - (r == 0) ? (r_adj = CS4231_MAX_DEV_ATEN) : (r_adj = CS4231_MAX_ATEN - - (r * (CS4231_MAX_ATEN + 1) / + (r == 0) ? (r_adj = CS4231_MAX_DEV_ATEN) : (r_adj = CS4231_MAX_ATEN - + (r * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1))); cs4231_chip->regs->iar = 0x6; @@ -811,10 +872,10 @@ if ((value == 0) || (value == AUDIO_MAX_GAIN)) { tmp = value; } else { - if (value == l) + if (value == l) tmp = ((CS4231_MAX_ATEN - l_adj) * (AUDIO_MAX_GAIN + 1) / (CS4231_MAX_ATEN + 1)); - else if (r == value) + else if (value == r) tmp = ((CS4231_MAX_ATEN - r_adj) * (AUDIO_MAX_GAIN + 1) / (CS4231_MAX_ATEN + 1)); } @@ -900,7 +961,16 @@ cs4231_output_muted(drv, 0); cs4231_chip->recording_count = 0; + cs4231_chip->input_next_dma_handle = 0; + cs4231_chip->input_dma_handle = 0; + cs4231_chip->input_next_dma_size = 0; + cs4231_chip->input_dma_size = 0; + cs4231_chip->playing_count = 0; + cs4231_chip->output_next_dma_handle = 0; + cs4231_chip->output_dma_handle = 0; + cs4231_chip->output_next_dma_size = 0; + cs4231_chip->output_dma_size = 0; } static int @@ -945,6 +1015,7 @@ } count = thisdir->samples; length = cs4231_length_to_samplecount(thisdir, length); + /* normalize for where we are. */ thisdir->samples = ((count - nextcount) + (length - curcount)); } @@ -957,7 +1028,8 @@ if (!(drv->flags & SDF_OPEN_WRITE) && (cs4231_chip->perchip_info.play.active == 0)) { cs4231_chip->perchip_info.play.open = 1; - cs4231_set_output_port(drv, AUDIO_SPEAKER); + cs4231_chip->perchip_info.play.samples = + cs4231_chip->perchip_info.play.error = 0; } } @@ -965,7 +1037,8 @@ if (!(drv->flags & SDF_OPEN_READ) && (cs4231_chip->perchip_info.record.active == 0)) { cs4231_chip->perchip_info.record.open = 1; - cs4231_set_input_port(drv, AUDIO_MICROPHONE); + cs4231_chip->perchip_info.record.samples = + cs4231_chip->perchip_info.record.error = 0; } } @@ -984,11 +1057,40 @@ /* zero out any info about what data we have as well */ - if (file->f_mode & FMODE_READ) - cs4231_chip->perchip_info.record.open = 0; + if (file->f_mode & FMODE_READ) { + /* stop capture here or midlevel? */ + cs4231_chip->perchip_info.record.open = 0; + if (cs4231_chip->input_dma_handle) { + mmu_release_scsi_one((u32)((unsigned long)cs4231_chip->input_dma_handle), + cs4231_chip->input_dma_size, drv->dev->my_bus); + cs4231_chip->input_dma_handle = 0; + cs4231_chip->input_dma_size = 0; + } + if (cs4231_chip->input_next_dma_handle) { + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_next_dma_handle), + cs4231_chip->input_next_dma_size, drv->dev->my_bus); + cs4231_chip->input_next_dma_handle = 0; + cs4231_chip->input_next_dma_size = 0; + } + } - if (file->f_mode & FMODE_WRITE) + if (file->f_mode & FMODE_WRITE) { + cs4231_chip->perchip_info.play.active = cs4231_chip->perchip_info.play.open = 0; + if (cs4231_chip->output_dma_handle) { + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle), + cs4231_chip->output_dma_size, drv->dev->my_bus); + cs4231_chip->output_dma_handle = 0; + cs4231_chip->output_dma_size = 0; + } + if (cs4231_chip->output_next_dma_handle) { + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_next_dma_handle), + cs4231_chip->output_next_dma_size, + drv->dev->my_bus); + cs4231_chip->output_next_dma_handle = 0; + cs4231_chip->output_next_dma_size = 0; + } + } if (!cs4231_chip->perchip_info.play.open && !cs4231_chip->perchip_info.record.open && @@ -1003,53 +1105,60 @@ static void cs4231_playintr(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int status = 0; - if (cs4231_chip->playlen == 0) + if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0) cs4231_chip->playlen = cs4231_chip->output_size; if (cs4231_chip->output_dma_handle) { - mmu_release_scsi_one((char *)cs4231_chip->output_dma_handle, - 4096, drv->dev->my_bus); - cs4231_chip->output_dma_handle = 0; + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle), + cs4231_chip->output_dma_size, drv->dev->my_bus); + cs4231_chip->output_dma_handle = 0; + cs4231_chip->output_dma_size = 0; + cs4231_chip->playing_count--; + status++; } if (cs4231_chip->output_next_dma_handle) { - cs4231_chip->output_dma_handle = cs4231_chip->output_next_dma_handle; - cs4231_chip->output_next_dma_handle = 0; + cs4231_chip->output_dma_handle = cs4231_chip->output_next_dma_handle; + cs4231_chip->output_dma_size = cs4231_chip->output_next_dma_size; + cs4231_chip->output_next_dma_size = 0; + cs4231_chip->output_next_dma_handle = 0; + } + + if ((cs4231_chip->output_ptr && cs4231_chip->output_size > 0) && + !(cs4231_chip->perchip_info.play.pause)) { + cs4231_chip->output_next_dma_handle = (u32 *) (unsigned long) + mmu_get_scsi_one((char *) cs4231_chip->output_ptr, + cs4231_chip->output_size, drv->dev->my_bus); + cs4231_chip->regs->dmapnva = (u32) (unsigned long) + cs4231_chip->output_next_dma_handle; + cs4231_chip->output_next_dma_size = cs4231_chip->regs->dmapnc = + cs4231_chip->output_size; + cs4231_chip->output_size = 0; + cs4231_chip->output_ptr = NULL; + cs4231_chip->playing_count++; + status += 2; + } else { + cs4231_chip->regs->dmapnva = 0; + cs4231_chip->regs->dmapnc = 0; } - if (cs4231_chip->output_ptr && cs4231_chip->output_size > 0) { - cs4231_chip->output_next_dma_handle = - mmu_get_scsi_one((char *) cs4231_chip->output_ptr, 4096, - drv->dev->my_bus); - cs4231_chip->regs->dmapnva = cs4231_chip->output_next_dma_handle; - cs4231_chip->regs->dmapnc = cs4231_chip->output_size; - cs4231_chip->output_size = 0; - cs4231_chip->output_ptr = NULL; - cs4231_chip->playing_count++; - } + sparcaudio_output_done(drv, status); - /* Get two buffers into the pipe, then chain... */ - if (cs4231_chip->playing_count < 3) - sparcaudio_output_done(drv, 0); - else { - cs4231_chip->playing_count--; - sparcaudio_output_done(drv, 1); - } - - return; + return; } -static void cs4231_recmute(int fmt) +static void cs4231_recclear(int fmt, char *dmabuf, int length) { switch (fmt) { case AUDIO_ENCODING_LINEAR: - /* Insert 0x00 from "here" to end of data stream */ + memset(dmabuf, 0x00, length); break; case AUDIO_ENCODING_ALAW: - /* Insert 0xd5 from "here" to end of data stream */ + memset(dmabuf, 0xd5, length); break; case AUDIO_ENCODING_ULAW: - /* Insert 0xff from "here" to end of data stream */ + memset(dmabuf, 0xff, length); break; } } @@ -1057,19 +1166,51 @@ static int cs4231_recintr(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int status = 0; if (cs4231_chip->perchip_info.record.active == 0) { + dprintk(("going inactive\n")); cs4231_pollinput(drv); - cs4231_recmute(cs4231_chip->perchip_info.record.encoding); cs4231_disable_rec(drv); - } - if (cs4231_chip->input_ptr) { - cs4231_chip->regs->dmacnva = (__u32) cs4231_chip->input_ptr; - cs4231_chip->regs->dmacnc = cs4231_chip->input_size; - cs4231_chip->input_ptr = NULL; + } + + if (cs4231_chip->input_dma_handle) { + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_dma_handle), + cs4231_chip->input_dma_size, drv->dev->my_bus); + cs4231_chip->input_dma_handle = 0; + cs4231_chip->input_dma_size = 0; + cs4231_chip->recording_count--; + status++; + } + if (cs4231_chip->input_next_dma_handle) { + cs4231_chip->input_dma_handle = cs4231_chip->input_next_dma_handle; + cs4231_chip->input_dma_size = cs4231_chip->input_next_dma_size; + cs4231_chip->input_next_dma_size = 0; + cs4231_chip->input_next_dma_handle = 0; + } + + if ((cs4231_chip->input_ptr && cs4231_chip->input_size > 0) && + !(cs4231_chip->perchip_info.record.pause)) { + cs4231_recclear(cs4231_chip->perchip_info.record.encoding, + (char *)cs4231_chip->input_ptr, cs4231_chip->input_size); + cs4231_chip->input_next_dma_handle = (u32*) (unsigned long) + mmu_get_scsi_one((char *) cs4231_chip->input_ptr, + cs4231_chip->input_size, drv->dev->my_bus); + cs4231_chip->regs->dmacnva = (u32) (unsigned long) + cs4231_chip->input_next_dma_handle; + cs4231_chip->input_next_dma_size = cs4231_chip->regs->dmacnc = + cs4231_chip->input_size; cs4231_chip->input_size = 0; - sparcaudio_input_done(drv); + cs4231_chip->input_ptr = NULL; + cs4231_chip->recording_count++; + status += 2; + } else { + cs4231_chip->regs->dmacnva = 0; + cs4231_chip->regs->dmacnc = 0; } + + sparcaudio_input_done(drv, status); + return 1; } @@ -1078,6 +1219,7 @@ { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + tprintk(("in 4231 start output\n")); cs4231_chip->output_ptr = buffer; cs4231_chip->output_size = count; @@ -1088,16 +1230,21 @@ cs4231_ready(drv); cs4231_chip->perchip_info.play.active = 1; - cs4231_chip->playing_count = 0; - cs4231_disable_play(drv); - cs4231_chip->regs->dmacsr &= ~CS_XINT_PLAY; - cs4231_chip->regs->dmacsr &= ~CS_PPAUSE; - cs4231_playintr(drv); - cs4231_enable_play(drv); - cs4231_chip->regs->dmacsr |= CS_PLAY_SETUP; - cs4231_ready(drv); + if ((cs4231_chip->regs->dmacsr & CS_PPAUSE) || + !(cs4231_chip->regs->dmacsr & PDMA_READY)) { + cs4231_chip->regs->dmacsr &= ~CS_XINT_PLAY; + cs4231_chip->regs->dmacsr &= ~CS_PPAUSE; + + cs4231_playintr(drv); + + cs4231_chip->regs->dmacsr |= CS_PLAY_SETUP; + cs4231_enable_play(drv); + + cs4231_ready(drv); + } else + cs4231_playintr(drv); } static void cs4231_stop_output(struct sparcaudio_driver *drv) @@ -1108,17 +1255,17 @@ cs4231_chip->output_ptr = NULL; cs4231_chip->output_size = 0; if (cs4231_chip->output_dma_handle) { - mmu_release_scsi_one((char *)cs4231_chip->output_dma_handle, - 4096, drv->dev->my_bus); - cs4231_chip->output_dma_handle = 0; + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle), + cs4231_chip->output_dma_size, drv->dev->my_bus); + cs4231_chip->output_dma_handle = 0; + cs4231_chip->output_dma_size = 0; } if (cs4231_chip->output_next_dma_handle) { - mmu_release_scsi_one((char *)cs4231_chip->output_next_dma_handle, - 4096, drv->dev->my_bus); - cs4231_chip->output_next_dma_handle = 0; + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_next_dma_handle), + cs4231_chip->output_next_dma_size, drv->dev->my_bus); + cs4231_chip->output_next_dma_handle = 0; + cs4231_chip->output_next_dma_size = 0; } - cs4231_chip->perchip_info.play.active = 0; - cs4231_chip->regs->dmacsr |= (CS_PPAUSE); } static void cs4231_pollinput(struct sparcaudio_driver *drv) @@ -1137,6 +1284,9 @@ { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + cs4231_chip->input_ptr = buffer; + cs4231_chip->input_size = count; + if (cs4231_chip->perchip_info.record.active || (cs4231_chip->perchip_info.record.pause)) return; @@ -1145,12 +1295,20 @@ cs4231_chip->perchip_info.record.active = 1; cs4231_chip->recording_count = 0; - /* init dma foo here */ - cs4231_chip->regs->dmacsr &= ~CS_XINT_CAPT; - cs4231_chip->regs->dmacsr &= ~CS_CPAUSE; - cs4231_recintr(drv); - cs4231_chip->regs->dmacsr |= CS_CAPT_SETUP; - cs4231_enable_rec(drv); + + if ((cs4231_chip->regs->dmacsr & CS_CPAUSE) || + !(cs4231_chip->regs->dmacsr & CDMA_READY)) { + cs4231_chip->regs->dmacsr &= ~CS_XINT_CAPT; + cs4231_chip->regs->dmacsr &= ~CS_CPAUSE; + + cs4231_recintr(drv); + + cs4231_chip->regs->dmacsr |= CS_CAPT_SETUP; + cs4231_enable_rec(drv); + + cs4231_ready(drv); + } else + cs4231_recintr(drv); } static void cs4231_stop_input(struct sparcaudio_driver *drv) @@ -1160,11 +1318,89 @@ cs4231_chip->perchip_info.record.active = 0; cs4231_chip->regs->dmacsr |= (CS_CPAUSE); + cs4231_chip->input_ptr = NULL; + cs4231_chip->input_size = 0; + if (cs4231_chip->input_dma_handle) { + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_dma_handle), + cs4231_chip->input_dma_size, drv->dev->my_bus); + cs4231_chip->input_dma_handle = 0; + cs4231_chip->input_dma_size = 0; + } + if (cs4231_chip->input_next_dma_handle) { + mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_next_dma_handle), + cs4231_chip->input_next_dma_size, drv->dev->my_bus); + cs4231_chip->input_next_dma_handle = 0; + cs4231_chip->input_next_dma_size = 0; + } cs4231_pollinput(drv); +} + +static int cs4231_set_output_pause(struct sparcaudio_driver *drv, int value) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + cs4231_chip->perchip_info.play.pause = value; + + if (!value) + sparcaudio_output_done(drv, 0); + + return value; +} + +static int cs4231_set_output_error(struct sparcaudio_driver *drv, int value) +{ + int i; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + i = cs4231_chip->perchip_info.play.error; + cs4231_chip->perchip_info.play.error = value; + + return i; +} + +static int cs4231_set_input_error(struct sparcaudio_driver *drv, int value) +{ + int i; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + i = cs4231_chip->perchip_info.record.error; + cs4231_chip->perchip_info.record.error = value; + + return i; +} + +static int cs4231_set_output_samples(struct sparcaudio_driver *drv, int value) +{ + int i; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + i = cs4231_chip->perchip_info.play.samples; + cs4231_chip->perchip_info.play.samples = value; + + return i; +} + +static int cs4231_set_input_samples(struct sparcaudio_driver *drv, int value) +{ + int i; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + i = cs4231_chip->perchip_info.record.samples; + cs4231_chip->perchip_info.record.samples = value; + + return i; +} - /* need adjust the end pointer, process the input, and clean up the dma */ +static int cs4231_set_input_pause(struct sparcaudio_driver *drv, int value) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - cs4231_disable_rec(drv); + cs4231_chip->perchip_info.record.pause = value; + + if (value) + cs4231_stop_input(drv); + + return value; } static void cs4231_audio_getdev(struct sparcaudio_driver *drv, @@ -1185,7 +1421,7 @@ static int cs4231_audio_getdev_sunos(struct sparcaudio_driver *drv) { - return AUDIO_DEV_CS4231; + return AUDIO_DEV_CS4231; } static void cs4231_loopback(struct sparcaudio_driver *drv, unsigned int value) @@ -1237,9 +1473,9 @@ if (dummy & CS_XINT_PNVA) { cs4231_chip->perchip_info.play.samples += cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), - cs4231_chip->playlen); + cs4231_chip->playlen); cs4231_playintr(drv); - } + } /* Any other conditions we need worry about? */ } @@ -1253,16 +1489,25 @@ /* Any other conditions we need worry about? */ } - if ((dummy & CS_XINT_CEMP) - && (cs4231_chip->perchip_info.record.active == 0)) - { - /* Fix me */ - cs4231_chip->perchip_info.record.active = 0; + + if (dummy & CS_XINT_CEMP) { + if (cs4231_chip->perchip_info.record.active == 0) { + /* Fix me */ + cs4231_chip->perchip_info.record.active = 0; + cs4231_chip->perchip_info.record.error = 1; + cs4231_recintr(drv); } - if ((dummy & CS_XINT_EMPT) && (cs4231_chip->perchip_info.play.active == 0)) { - cs4231_chip->regs->dmacsr |= (CS_PPAUSE); - cs4231_disable_play(drv); - + } + + if (dummy & CS_XINT_EMPT) { + if (!cs4231_chip->output_next_dma_handle) { + cs4231_chip->regs->dmacsr |= (CS_PPAUSE); + cs4231_disable_play(drv); + cs4231_chip->perchip_info.play.error = 1; + } + cs4231_chip->perchip_info.play.active = 0; + cs4231_playintr(drv); + cs4231_getsamplecount(drv, cs4231_chip->playlen, 0); } @@ -1317,15 +1562,31 @@ cs4231_get_input_ports, cs4231_output_muted, cs4231_get_output_muted, + cs4231_set_output_pause, + cs4231_get_output_pause, + cs4231_set_input_pause, + cs4231_get_input_pause, + cs4231_set_output_samples, + cs4231_get_output_samples, + cs4231_set_input_samples, + cs4231_get_input_samples, + cs4231_set_output_error, + cs4231_get_output_error, + cs4231_set_input_error, + cs4231_get_input_error, + cs4231_get_formats, }; /* Attach to an cs4231 chip given its PROM node. */ static int cs4231_attach(struct sparcaudio_driver *drv, struct linux_sbus_device *sdev) { +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 + struct linux_prom_irqs irq; +#endif + struct linux_sbus *sbus = sdev->my_bus; struct cs4231_chip *cs4231_chip; int err; - struct linux_sbus *sbus = sdev->my_bus; /* Allocate our private information structure. */ drv->private = kmalloc(sizeof(struct cs4231_chip), GFP_KERNEL); @@ -1342,8 +1603,15 @@ drv->dev = sdev; /* Map the registers into memory. */ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 + prom_apply_sbus_ranges(sbus, &sdev->reg_addrs[0], + sdev->num_registers, sdev); +#else prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev); +#endif + cs4231_chip->regs_size = sdev->reg_addrs[0].reg_size; + cs4231_chip->regs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, sdev->reg_addrs[0].reg_size, "cs4231", sdev->reg_addrs[0].which_io, @@ -1356,9 +1624,23 @@ } /* Attach the interrupt handler to the audio interrupt. */ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 + prom_getproperty(sdev->prom_node, "intr", (char *)&irq, sizeof(irq)); + + if (irq.pri < 0) { + sparc_free_io(cs4231_chip->regs, cs4231_chip->regs_size); + kfree(drv->private); + return -EIO; + } + + cs4231_chip->irq = irq.pri; + +#else cs4231_chip->irq = sdev->irqs[0]; +#endif request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv); + enable_irq(cs4231_chip->irq); cs4231_enable_interrupts(drv); @@ -1367,7 +1649,7 @@ cs4231_chip_reset(drv); /* Register ourselves with the midlevel audio driver. */ - err = register_sparcaudio_driver(drv); + err = register_sparcaudio_driver(drv, 1); if (err < 0) { printk(KERN_ERR "cs4231: unable to register\n"); @@ -1395,8 +1677,8 @@ AUDIO_ANALOG_LOOPBACK); /* Announce the hardware to the user. */ - printk(KERN_INFO "cs4231%c at 0x%lx irq %d\n", - (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', + printk(KERN_INFO "audio%d: cs4231%c at 0x%lx irq %d\n", + drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', (unsigned long)cs4231_chip->regs, cs4231_chip->irq); /* Success! */ @@ -1438,7 +1720,7 @@ struct cs4231_chip *info = (struct cs4231_chip *)drv->private; cs4231_disable_interrupts(drv); - unregister_sparcaudio_driver(drv); + unregister_sparcaudio_driver(drv, 1); disable_irq(info->irq); free_irq(info->irq, drv); sparc_free_io(info->regs, info->regs_size); diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/cs4231.h linux/drivers/sbus/audio/cs4231.h --- v2.1.128/linux/drivers/sbus/audio/cs4231.h Thu Aug 6 14:06:32 1998 +++ linux/drivers/sbus/audio/cs4231.h Wed Nov 18 09:06:05 1998 @@ -48,11 +48,14 @@ /* Current buffer that the driver is playing. */ volatile __u8 * output_ptr; volatile unsigned long output_size; - volatile __u32 * output_dma_handle, output_next_dma_handle; + volatile __u32 * output_dma_handle, * output_next_dma_handle; + volatile unsigned long output_dma_size, output_next_dma_size; /* Current record buffer. */ volatile __u8 * input_ptr; volatile unsigned long input_size; + volatile __u32 * input_dma_handle, * input_next_dma_handle; + volatile unsigned long input_dma_size, input_next_dma_size; /* Number of buffers in the pipe. */ volatile unsigned long playing_count; diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c --- v2.1.128/linux/drivers/sbus/audio/dbri.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/audio/dbri.c Wed Nov 18 09:06:05 1998 @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -62,9 +63,13 @@ #include #include "dbri.h" +#if defined(DBRI_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff +#include "../../isdn/hisax/hisax.h" +#include "../../isdn/hisax/isdnl1.h" +#include "../../isdn/hisax/foreign.h" +#endif - -#define DBRI_DEBUG +/* #define DBRI_DEBUG */ #ifdef DBRI_DEBUG @@ -104,34 +109,58 @@ static struct sparcaudio_driver drivers[MAX_DRIVERS]; static char drv_name[] = "DBRI/audio"; static int num_drivers; -static int dbri_cmdlocked = 0; static void * output_callback_arg; /* - * Make sure, that we can send a command to the dbri + * Commands are sent to the DBRI by building a list of them in memory, + * then writing the address of the first list item to DBRI register 8. + * The list is terminated with a WAIT command, which can generate a + * CPU interrupt if required. + * + * Since the DBRI can run asynchronously to the CPU, several means of + * synchronization present themselves. The original scheme (Rudolf's) + * was to set a flag when we "cmdlock"ed the DBRI, clear the flag when + * an interrupt signaled completion, and wait on a wait_queue if a routine + * attempted to cmdlock while the flag was set. The problems arose when + * we tried to cmdlock from inside an interrupt handler, which might + * cause scheduling in an interrupt (if we waited), etc, etc + * + * A more sophisticated scheme might involve a circular command buffer + * or an array of command buffers. A routine could fill one with + * commands and link it onto a list. When a interrupt signaled + * completion of the current command buffer, look on the list for + * the next one. + * + * I've decided to implement something much simpler - after each command, + * the CPU waits for the DBRI to finish the command by polling the P bit + * in DBRI register 0. I've tried to implement this in such a way + * that might make implementing a more sophisticated scheme easier. + * + * Every time a routine wants to write commands to the DBRI, it + * must first call dbri_cmdlock() and get an initial index into dbri->cmd + * (currently always 0) in return. After the commands have been + * write (index incremented after each one), dbri_cmdsend() is called + * with the final index value. */ + static int dbri_cmdlock(struct dbri *dbri) { - unsigned long flags; - int was_sleeping = 0; + return 0; +} - save_flags(flags); - cli(); +static void dbri_cmdsend(struct dbri *dbri, int n) +{ + int maxloops = 1000000; - if(dbri_cmdlocked) { - interruptible_sleep_on(&dbri->wait); - was_sleeping = 1; - } - if(dbri_cmdlocked) - return -EINTR; - dbri_cmdlocked = 1; + dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1); + dbri->regs->reg8 = (int)dbri->cmd; - restore_flags(flags); + while (maxloops > 0 && (dbri->regs->reg0 & D_P)); - if(was_sleeping) - dprintk(D_INT, ("DBRI: Just woke up\n")); - return 0; + if (maxloops == 0) { + printk("DBRI: Maxloops exceeded in dbri_cmdsend\n"); + } } static void dbri_reset(struct sparcaudio_driver *drv) @@ -153,7 +182,7 @@ struct dbri *info = (struct dbri *)drv->private; dbri_reset(drv); - unregister_sparcaudio_driver(drv); + unregister_sparcaudio_driver(drv, 1); free_irq(info->irq, drv); sparc_free_io(info->regs, info->regs_size); kfree(drv->private); @@ -191,13 +220,12 @@ /* * Set up the interrupt queue */ - (void)dbri_cmdlock(dbri); + n = dbri_cmdlock(dbri); - n = 0; dbri->cmd[n++] = DBRI_CMD(D_IIQ, 0, 0); dbri->cmd[n++] = (int)(dbri->intr); - dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1); - dbri->regs->reg8 = (int)dbri->cmd; + + dbri_cmdsend(dbri, n); } @@ -250,9 +278,9 @@ static void mmcodec_init_data(struct dbri *dbri) { - int val, n = 0; + int val, n; - dbri_cmdlock(dbri); + n = dbri_cmdlock(dbri); /* * Data mode: @@ -340,9 +368,7 @@ /* CHI: Slave mode; enable interrupts */ dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) | D_CHI_IR | D_CHI_EN); - dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1); - - dbri->regs->reg8 = (int)dbri->cmd; + dbri_cmdsend(dbri, n); } @@ -351,7 +377,7 @@ */ static void mmcodec_setctrl(struct dbri *dbri) { - int n = 0, val; + int n, val; /* * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait @@ -380,7 +406,7 @@ * by eight clock cycles. Anybody know why? */ - dbri_cmdlock(dbri); + n = dbri_cmdlock(dbri); /* * Control mode: @@ -462,32 +488,24 @@ dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN); dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0); - dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1); - dbri->regs->reg8 = (int)dbri->cmd; - - - /* Wait for the data from the CS4215 */ - interruptible_sleep_on(&dbri->int_wait); + /* Wait for the command to complete */ + dbri_cmdsend(dbri, n); /* Switch CS4215 to data mode - data sheet says * "Set CLB=1 and send two more frames of valid control info" */ - dbri_cmdlock(dbri); + n = dbri_cmdlock(dbri); - n = 0; dbri->mm.ctrl[0] |= CS4215_CLB; dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17)); dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4); - dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1); - dbri->regs->reg8 = (int)dbri->cmd; - - dbri_cmdlock(dbri); + dbri_cmdsend(dbri, n); /* Two frames of control info @ 8kHz frame rate = 250 us delay */ udelay(250); - n = 0; + n = dbri_cmdlock(dbri); /* Now switch back to data mode */ /* Reset CHI Anchor: Stop Send/Receive */ @@ -504,15 +522,8 @@ dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0x16); - dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1); - dbri->regs->reg8 = (int)dbri->cmd; - /* Wait for command to complete */ - dbri_cmdlock(dbri); - n = 0; - dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1); - dbri->regs->reg8 = (int)dbri->cmd; - + dbri_cmdsend(dbri, n); /* Switch CS4215 to data mode - set PIO3 to 1 */ dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 | @@ -563,6 +574,94 @@ return 0; } +void dbri_isdn_init(struct dbri *dbri) +{ + int n, val; + + /* Pipe 0: Receive D channel + * Pipe 8: Receive B1 channel + * Pipe 9: Receive B2 channel + * Pipe 1: Transmit D channel + * Pipe 10: Transmit B1 channel + * Pipe 11: Transmit B2 channel + */ + + n = dbri_cmdlock(dbri); + + /* Pipe 0: SDP */ + val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_0); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + /* Pipe 8: SDP */ + val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + /* Pipe 9: SDP */ + val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_9); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + /* Pipe 1: SDP */ + val = D_SDP_HDLC_D|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_1); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + /* Pipe 10: SDP */ + val = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + /* Pipe 11: SDP */ + val = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_11); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + + dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0); + + /* Pipe 0: DTS */ + val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_0) | D_PIPE(D_P_0); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_LEN(2) | D_TS_CYCLE(17)| D_TS_NEXT(D_P_0); + dbri->cmd[n++] = 0; + + /* Pipe 8: DTS */ + val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_0) | D_PIPE(D_P_8); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_0); + dbri->cmd[n++] = 0; + + /* Pipe 9: DTS */ + val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_8) | D_PIPE(D_P_9); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_0); + dbri->cmd[n++] = 0; + + /* Pipe 1: DTS */ + val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_1) | D_PIPE(D_P_1); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = 0; + dbri->cmd[n++] = D_TS_LEN(2) | D_TS_CYCLE(17)| D_TS_NEXT(D_P_1); + + /* Pipe 10: DTS */ + val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_1) | D_PIPE(D_P_10); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = 0; + dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_1); + + /* Pipe 11: DTS */ + val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_10) | D_PIPE(D_P_11); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = 0; + dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_1); + + + /* Wait for command to complete */ + dbri_cmdsend(dbri, n); +} + void dbri_intr(int irq, void *dev_id, struct pt_regs *regs) { struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; @@ -610,8 +709,16 @@ val = D_INTR_GETVAL(x); + if (D_INTR_GETCODE(x) == D_INTR_SBRI) { + int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7}; + dbri->liu_state = liu_states[val & 0x7]; + if (dbri->liu_callback) + dbri->liu_callback(dbri->liu_callback_arg); + } + switch(D_INTR_GETCHAN(x)) { case D_INTR_CMD: +#if 0 if(D_INTR_GETCMD(x) == D_WAIT) if(val == WAIT_INTR1) { dbri_cmdlocked = 0; @@ -619,25 +726,86 @@ } if(val == WAIT_INTR2) wake_up(&dbri->int_wait); +#endif break; + + case D_P_0: + /* Pipe 0 - D channel receive */ + if (D_INTR_GETCODE(x) == D_INTR_BRDY && + dbri->D.input_callback) { + dbri->D.input_callback(dbri->D.input_callback_arg, + DBRI_RD_STATUS(dbri->D.rd.flags), + DBRI_RD_CNT(dbri->D.rd.flags)-2); + } + break; + + case D_P_1: + /* Pipe 1 - D channel transmit */ + if (D_INTR_GETCODE(x) == D_INTR_XCMP && + dbri->D.output_callback) { + dbri->D.output_callback(dbri->D.output_callback_arg, + DBRI_TD_STATUS(dbri->D.rd.flags)&0xe); + } + break; + case D_P_4: + /* Pipe 4 - audio transmit */ if (D_INTR_GETCODE(x) == D_INTR_XCMP) { sparcaudio_output_done(output_callback_arg, 1); } break; + case D_P_8: + /* Pipe 8 - B1 channel receive */ + if (D_INTR_GETCODE(x) == D_INTR_BRDY && + dbri->B[0].input_callback) { + dbri->B[0].input_callback(dbri->B[0].input_callback_arg, + DBRI_RD_STATUS(dbri->B[0].rd.flags), + DBRI_RD_CNT(dbri->B[0].rd.flags)-2); + } + break; + + case D_P_9: + /* Pipe 9 - B2 channel receive */ + if (D_INTR_GETCODE(x) == D_INTR_BRDY && + dbri->B[1].input_callback) { + dbri->B[1].input_callback(dbri->B[1].input_callback_arg, + DBRI_RD_STATUS(dbri->B[1].rd.flags), + DBRI_RD_CNT(dbri->B[1].rd.flags)-2); + } + break; + + case D_P_10: + /* Pipe 10 - B1 channel transmit */ + if (D_INTR_GETCODE(x) == D_INTR_XCMP && + dbri->B[0].output_callback) { + dbri->B[0].output_callback(dbri->B[0].output_callback_arg, + DBRI_TD_STATUS(dbri->B[0].rd.flags)&0xfe); + } + break; + + case D_P_11: + /* Pipe 11 - B2 channel transmit */ + if (D_INTR_GETCODE(x) == D_INTR_XCMP && + dbri->B[1].output_callback) { + dbri->B[1].output_callback(dbri->B[1].output_callback_arg, + DBRI_TD_STATUS(dbri->B[1].rd.flags)&0xfe); + } + break; + case D_P_18: + /* Pipe 18 - receive CS4215 status */ if(val != 0) { x = reverse_bytes(val,2)&CS4215_12_MASK; -printk("Comparing int: %x with hi(%x)\n", x, *(int *)dbri->mm.ctrl); - if(x == (*(int *)dbri->mm.ctrl >> 16)) -{ -printk("Comp ok\n"); - wake_up(&dbri->int_wait); -} + printk("Comparing int: %x with hi(%x)\n", x, *(int *)dbri->mm.ctrl); + if(x == (*(int *)dbri->mm.ctrl >> 16)) { + printk("Comp ok\n"); + wake_up(&dbri->int_wait); + } } break; case D_P_19: + /* Pipe 19 - receive CS4215 version */ if(val != 0) { dbri->mm.version = reverse_bytes(val, 1) & 0xf; @@ -671,13 +839,6 @@ { struct dbri *dbri = (struct dbri *)drv->private; -#if 0 - /* Set the default audio parameters. */ - info->rgain = 128; - info->pgain = 200; - info->mgain = 0; -#endif - MOD_INC_USE_COUNT; return 0; @@ -693,17 +854,14 @@ __u8 * buffer, unsigned long count) { struct dbri *dbri = (struct dbri *)drv->private; - int val, n = 0; + int val, n; - /* XXX - This routine can be called via interrupt. If DBRI - * was cmdlocked, that would cause a sleep, which would be - * scheduling in an interrupt, and that's not allowed - * - * Fortunately, there's nothing else talking to our DBRI (yet), - * so this isn't a problem (yet) - */ + if (count > (1 << 14) - 1) { + printk("dbri_start_output called with count=%d; truncated", count); + count = (1 << 14) - 1; + } - dbri_cmdlock(dbri); + n = dbri_cmdlock(dbri); dbri->mm.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_D | DBRI_TD_CNT(count); dbri->mm.td.ba = (__u32) buffer; @@ -715,11 +873,9 @@ dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); dbri->cmd[n++] = (__u32)&dbri->mm.td; - dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1); - - dbri->regs->reg8 = (int)dbri->cmd; - output_callback_arg = drv; + + dbri_cmdsend(dbri, n); } static void dbri_stop_output(struct sparcaudio_driver *drv) @@ -727,6 +883,8 @@ struct dbri *dbri = (struct dbri *)drv->private; } + + static struct sparcaudio_operations dbri_ops = { dbri_open, dbri_release, @@ -773,6 +931,340 @@ dummy, /* dbri_get_output_muted, */ }; +/* +**************************************************************************** +************************** ISDN (Hisax) Interface ************************** +**************************************************************************** +*/ + +int dbri_get_irqnum(int dev) +{ + struct dbri *dbri; + + if (dev > num_drivers) { + return(0); + } + + dbri = (struct dbri *) drivers[dev].private; + + /* On the sparc, the cpu's irq number is only part of the "irq" */ + return (dbri->irq & NR_IRQS); +} + +int dbri_get_liu_state(int dev) +{ + struct dbri *dbri; + + if (dev > num_drivers) { + return(0); + } + + dbri = (struct dbri *) drivers[dev].private; + + return dbri->liu_state; +} + +void dbri_liu_init(int dev, void (*callback)(void *), void *callback_arg) +{ + struct dbri *dbri; + + if (dev > num_drivers) { + return; + } + + dbri = (struct dbri *) drivers[dev].private; + + /* Set callback for LIU state change */ + dbri->liu_callback = callback; + dbri->liu_callback_arg = callback_arg; + + dbri_isdn_init(dbri); +} + +void dbri_liu_activate(int dev, int priority) +{ + struct dbri *dbri; + int n, val; + + if (dev > num_drivers) { + return; + } + + dbri = (struct dbri *) drivers[dev].private; + + n = dbri_cmdlock(dbri); + + /* Turn on the ISDN TE interface and request activation */ + val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT; + dbri->cmd[n++] = DBRI_CMD(D_TE, 0, val); + + dbri_cmdsend(dbri, n); + + /* Activate the interface */ + dbri->regs->reg0 |= D_T; +} + +void dbri_liu_deactivate(int dev) +{ + struct dbri *dbri; + + if (dev > num_drivers) { + return; + } + + dbri = (struct dbri *) drivers[dev].private; + + /* Turn off the ISDN TE interface */ + dbri->regs->reg0 &= ~D_T; +} + +void dbri_dxmit(int dev, __u8 *buffer, unsigned int count, + void (*callback)(void *, int), void *callback_arg) +{ + struct dbri *dbri; + int n, val; + + if (dev > num_drivers) { + return; + } + + dbri = (struct dbri *) drivers[dev].private; + + if (count > (1 << 14) - 1) { + printk("dbri_dxmit called with count=%d; truncated", count); + count = (1 << 14) - 1; + } + + n = dbri_cmdlock(dbri); + + /* XXX - Shouldn't I check to make sure D.td isn't is use? */ + + dbri->D.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_CNT(count) | DBRI_TD_I; + dbri->D.td.ba = (__u32) buffer; + dbri->D.td.nda = 0; + dbri->D.td.status = 0; + + /* Pipe 1 is D channel transmit */ + val = D_SDP_HDLC_D|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_1); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = (__u32)&dbri->D.td; + + dbri->D.output_callback = callback; + dbri->D.output_callback_arg = callback_arg; + + dbri_cmdsend(dbri, n); +} + +void dbri_drecv(int dev, __u8 *buffer, unsigned int size, + void (*callback)(void *, int, unsigned int), + void *callback_arg) +{ + struct dbri *dbri; + int n, val; + + if (dev > num_drivers) { + return; + } + + dbri = (struct dbri *) drivers[dev].private; + + if (size > (1 << 14) - 1) { + printk("dbri_drecv called with size=%d; truncated", size); + size = (1 << 14) - 1; + } + + /* Make sure size is a multiple of four */ + size &= ~3; + + n = dbri_cmdlock(dbri); + + /* XXX - Shouldn't I check to make sure D.rd isn't is use? */ + + dbri->D.rd.flags = 0; + dbri->D.rd.ba = (__u32) buffer; + dbri->D.rd.nda = 0; + dbri->D.rd.status = DBRI_RD_B | DBRI_RD_BCNT(size); + + /* Pipe 0 is D channel receive */ + val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_0); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = (__u32)&dbri->D.rd; + + dbri_cmdsend(dbri, n); + + dbri->D.input_callback = callback; + dbri->D.input_callback_arg = callback_arg; +} + +int dbri_bopen(int dev, unsigned int chan, + int hdlcmode, u_char xmit_idle_char) +{ + struct dbri *dbri; + int n, val; + + if (dev > num_drivers || chan > 1) { + return -1; + } + + dbri = (struct dbri *) drivers[dev].private; + + if (hdlcmode) { + + return -1; + + /* Pipe 8/9: receive B1/B2 channel */ + dbri->B[chan].recvSDP = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8+chan); + + /* Pipe 10/11: transmit B1/B2 channel */ + dbri->B[chan].xmitSDP = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10+chan); + + } else { /* !hdlcmode means transparent */ + + /* Pipe 8/9: receive B1/B2 channel */ + dbri->B[chan].recvSDP = D_SDP_MEM|D_SDP_FROM_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8+chan); + + /* Pipe 10/11: transmit B1/B2 channel */ + dbri->B[chan].xmitSDP = D_SDP_MEM|D_SDP_TO_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10+chan); + + } + + n = dbri_cmdlock(dbri); + + /* Pipe 8/9: receive B1/B2 channel */ + val = dbri->B[chan].recvSDP | D_SDP_C; + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + /* Pipe 10/11: transmit B1/B2 channel */ + val = dbri->B[chan].xmitSDP | D_SDP_C; + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + dbri->B[chan].output_callback = NULL; + dbri->B[chan].input_callback = NULL; + + dbri_cmdsend(dbri, n); + + return 0; +} + +void dbri_bclose(int dev, unsigned int chan) +{ + struct dbri *dbri; + + if (dev > num_drivers || chan > 1) { + return; + } + + dbri = (struct dbri *) drivers[dev].private; + + dbri->B[chan].output_callback = NULL; + dbri->B[chan].input_callback = NULL; +} + +void dbri_bxmit(int dev, unsigned int chan, + __u8 *buffer, unsigned long count, + void (*callback)(void *, int), + void *callback_arg) +{ + struct dbri *dbri; + int n, val; + + if (dev > num_drivers || chan > 1) { + return; + } + + dbri = (struct dbri *) drivers[dev].private; + + if (count > (1 << 14) - 1) { + printk("dbri_bxmit called with count=%ld; truncated", count); + count = (1 << 14) - 1; + } + + n = dbri_cmdlock(dbri); + + /* XXX - Shouldn't I check to make sure td isn't is use? */ + + dbri->B[chan].td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_CNT(count); + dbri->B[chan].td.ba = (__u32) buffer; + dbri->B[chan].td.nda = 0; + dbri->B[chan].td.status = 0; + + /* Pipe 10/11 is B1/B2 channel transmit */ + val = dbri->B[chan].xmitSDP; + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = (__u32)&dbri->B[chan].td; + + dbri->B[chan].output_callback = callback; + dbri->B[chan].output_callback_arg = callback_arg; + + dbri_cmdsend(dbri, n); +} + +void dbri_brecv(int dev, unsigned int chan, + __u8 *buffer, unsigned long size, + void (*callback)(void *, int, unsigned int), + void *callback_arg) +{ + struct dbri *dbri; + int n, val; + + if (dev > num_drivers || chan > 1) { + return; + } + + dbri = (struct dbri *) drivers[dev].private; + + if (size > (1 << 14) - 1) { + printk("dbri_brecv called with size=%ld; truncated", size); + size = (1 << 14) - 1; + } + + /* Make sure size is a multiple of four */ + size &= ~3; + + n = dbri_cmdlock(dbri); + + /* XXX - Shouldn't I check to make sure RD isn't is use? */ + + dbri->B[chan].rd.flags = 0; + dbri->B[chan].rd.ba = (__u32) buffer; + dbri->B[chan].rd.nda = 0; + dbri->B[chan].rd.status = DBRI_RD_B | DBRI_RD_BCNT(size); + + /* Pipe 8/9 is B1/B2 channel receive */ + val = dbri->B[chan].recvSDP; + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = (__u32)&dbri->B[chan].rd; + + dbri_cmdsend(dbri, n); + + dbri->B[chan].input_callback = callback; + dbri->B[chan].input_callback_arg = callback_arg; +} + +#if defined(DBRI_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff +struct foreign_interface dbri_foreign_interface = { + dbri_get_irqnum, + dbri_get_liu_state, + dbri_liu_init, + dbri_liu_activate, + dbri_liu_deactivate, + dbri_dxmit, + dbri_drecv, + dbri_bopen, + dbri_bclose, + dbri_bxmit, + dbri_brecv +}; +EXPORT_SYMBOL(dbri_foreign_interface); +#endif + +/* +**************************************************************************** +**************************** Initialization ******************************** +**************************************************************************** +*/ static int dbri_attach(struct sparcaudio_driver *drv, struct linux_sbus_device *sdev) @@ -822,7 +1314,7 @@ } /* Register ourselves with the midlevel audio driver. */ - err = register_sparcaudio_driver(drv); + err = register_sparcaudio_driver(drv,1); if (err) { printk(KERN_ERR "DBRI: unable to register audio\n"); free_irq(dbri->irq, drv); @@ -900,13 +1392,13 @@ * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 + * Local Variables: + * c-indent-level: 8 * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/dbri.h linux/drivers/sbus/audio/dbri.h --- v2.1.128/linux/drivers/sbus/audio/dbri.h Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/audio/dbri.h Wed Nov 18 09:06:05 1998 @@ -33,6 +33,17 @@ __u32 status; }; +struct dbri_channel { + struct dbri_mem td; + struct dbri_mem rd; + unsigned int recvSDP; + unsigned int xmitSDP; + void (*output_callback)(void *, int); + void *output_callback_arg; + void (*input_callback)(void *, int, unsigned int); + void *input_callback_arg; +}; + #include "cs4215.h" /* This structure holds the information for both chips (DBRI & CS4215) */ @@ -49,6 +60,15 @@ struct wait_queue *wait, *int_wait; /* Where to sleep if busy */ struct audio_info perchip_info; + + /* Track ISDN LIU and notify changes */ + int liu_state; + void (*liu_callback)(void *); + void *liu_callback_arg; + + /* Callback routines and descriptors for ISDN channels */ + struct dbri_channel D; + struct dbri_channel B[2]; }; @@ -109,7 +129,7 @@ /* Special bits for some commands */ -#define D_PIPE(v) (v<<0) /* Pipe Nr: 0-15 long, 16-21 short */ +#define D_PIPE(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */ /* Setup Data Pipe */ /* IRM */ @@ -139,8 +159,8 @@ #define D_DTS_VO (1<<16) /* Valid Output Time-Slot Descriptor */ #define D_DTS_INS (1<<15) /* Insert Time Slot */ #define D_DTS_DEL (0<<15) /* Delete Time Slot */ -#define D_DTS_PRVIN(v) (v<<10) /* Previous In Pipe */ -#define D_DTS_PRVOUT(v) (v<<5) /* Previous Out Pipe */ +#define D_DTS_PRVIN(v) ((v)<<10) /* Previous In Pipe */ +#define D_DTS_PRVOUT(v) ((v)<<5) /* Previous Out Pipe */ /* Time Slot defines */ #define D_TS_LEN(v) (v<<24) /* Number of bits in this time slot */ @@ -150,8 +170,8 @@ #define D_TS_MONITOR (2<<10) /* Monitor pipe */ #define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */ #define D_TS_ANCHOR (7<<10) /* Starting short pipes */ -#define D_TS_MON(v) (v<<5) /* Monitor Pipe */ -#define D_TS_NEXT(v) (v<<0) /* Pipe Nr: 0-15 long, 16-21 short */ +#define D_TS_MON(v) ((v)<<5) /* Monitor Pipe */ +#define D_TS_NEXT(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */ /* Concentration Highway Interface Modes */ #define D_CHI_CHICM(v) (v<<16) /* Clock mode */ @@ -276,17 +296,19 @@ #define DBRI_TD_UNR (1<<3) /* Underrun: transmitter is out of data */ #define DBRI_TD_ABT (1<<2) /* Abort: frame aborted */ #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ +#define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ /* Receive descriptor defines */ #define DBRI_RD_F (1<<31) /* End of Frame */ #define DBRI_RD_C (1<<30) /* Completed buffer */ #define DBRI_RD_B (1<<15) /* Final interrupt */ #define DBRI_RD_M (1<<14) /* Marker interrupt */ -#define DBRI_RD_CNT(v) (v<<16) /* Number of valid bytes in the buffer */ #define DBRI_RD_BCNT(v) v /* Buffer size */ #define DBRI_RD_CRC (1<<7) /* 0: CRC is correct */ #define DBRI_RD_BBC (1<<6) /* 1: Bad Byte recieved */ #define DBRI_RD_ABT (1<<5) /* Abort: frame aborted */ #define DBRI_RD_OVRN (1<<3) /* Overrun: data lost */ +#define DBRI_RD_STATUS(v) ((v)&0xff) /* Receive status */ +#define DBRI_RD_CNT(v) ((v>>16)&0x1fff) /* Number of valid bytes in the buffer */ #endif /* _DBRI_H_ */ diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile --- v2.1.128/linux/drivers/sbus/char/Makefile Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/char/Makefile Mon Nov 16 10:37:28 1998 @@ -50,7 +50,7 @@ else # !eq($(ARCH),sparc64) ifeq ($(CONFIG_PCI),y) -O_OBJS += su32.o pcikbd.o +O_OBJS += su.o pcikbd.o endif endif # !eq($(ARCH),sparc64) diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c --- v2.1.128/linux/drivers/sbus/char/envctrl.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/char/envctrl.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: envctrl.c,v 1.8 1998/08/26 10:29:40 davem Exp $ +/* $Id: envctrl.c,v 1.9 1998/11/06 07:38:20 ecd Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -115,10 +115,7 @@ unsigned char dummy; unsigned char stat; int error = -ENODEV; - int count = -1; - - if (len == 0) - return 0; + int count = 0; i2c->data = (dev << 1) | I2C_READ; @@ -134,21 +131,26 @@ if (stat & STATUS_LRB) goto stop; + error = 0; - if (count == (len - 2)) - goto final; + if (len == 0) { + count--; + break; + } - if (++count > 0) { + if (count == (len - 1)) + break; + + if (count++ > 0) { error = PUT_DATA(&i2c->data, buffer++, user); if (error) - goto final; + break; } else dummy = i2c->data; } while (1); -final: i2c->csr = CONTROL_ES0; - if (!error && (++count > 0)) + if (!error && (count++ > 0)) error = PUT_DATA(&i2c->data, buffer++, user); else dummy = i2c->data; @@ -159,14 +161,14 @@ stop: i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK; - if (!error && (++count > 0)) + if (!error && (count++ > 0)) error = PUT_DATA(&i2c->data, buffer++, user); else dummy = i2c->data; if (error) return error; - return count; + return count - 1; } static int @@ -189,19 +191,19 @@ udelay(1); if (stat & STATUS_LRB) - goto stop; + break; + error = count; if (count == len) - goto stop; + break; error = GET_DATA(&i2c->data, buffer++, user); if (error) - goto stop; + break; count++; } while (1); -stop: i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK; return error; } @@ -212,7 +214,7 @@ int count = 0; for (dev = 1; dev < 128; dev++) { - if (i2c_write(dev, 0, 0, 0) == 0) { + if (i2c_read(dev, 0, 0, 0) == 0) { #ifdef DEBUG_BUS_SCAN int i; for (i = 0; i < NR_DEVMAP; i++) @@ -224,7 +226,11 @@ count++; } } - return count ? 0 : -ENODEV; + if (!count) { + printk("%s: no devices found\n", __FUNCTION__); + return -ENODEV; + } + return 0; } static loff_t @@ -317,6 +323,7 @@ #ifdef CONFIG_PCI struct linux_ebus *ebus; struct linux_ebus_device *edev = 0; + int err; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { @@ -327,8 +334,10 @@ } } ebus_done: - if (!edev) + if (!edev) { + printk("%s: ebus device not found\n", __FUNCTION__); return -ENODEV; + } if (check_region(edev->base_address[0], sizeof(*i2c))) { printk("%s: Can't get region %lx, %d\n", @@ -353,7 +362,10 @@ release_region((unsigned long)i2c, sizeof(*i2c)); } - return i2c_scan_bus(); + err = i2c_scan_bus(); + if (err) + release_region((unsigned long)i2c, sizeof(*i2c)); + return err; #else return -ENODEV; #endif diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.1.128/linux/drivers/sbus/char/pcikbd.c Sun Nov 8 14:03:01 1998 +++ linux/drivers/sbus/char/pcikbd.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.23 1998/10/07 11:35:24 jj Exp $ +/* $Id: pcikbd.c,v 1.24 1998/11/08 11:15:24 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -691,7 +691,7 @@ == AUX_STAT_OBF) pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); current->state = TASK_INTERRUPTIBLE; - schedule_timeout((5*HZ + 99)/100); + schedule_timeout((5*HZ + 99) / 100); retries++; } return (retries < MAX_RETRIES); diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c --- v2.1.128/linux/drivers/sbus/char/sab82532.c Sun Nov 8 14:03:01 1998 +++ linux/drivers/sbus/char/sab82532.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.26 1998/10/25 06:46:41 ecd Exp $ +/* $Id: sab82532.c,v 1.27 1998/11/08 11:15:25 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2136,7 +2136,7 @@ __initfunc(static inline void show_serial_version(void)) { - char *revision = "$Revision: 1.26 $"; + char *revision = "$Revision: 1.27 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.1.128/linux/drivers/sbus/char/su.c Sun Nov 8 14:03:01 1998 +++ linux/drivers/sbus/char/su.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.12 1998/10/25 04:24:52 ecd Exp $ +/* $Id: su.c,v 1.16 1998/11/14 23:02:54 ecd Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -37,7 +37,7 @@ printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ kdevname(tty->device), (info->flags), serial_refcount, \ info->count,tty->count,s); \ -} while (0); +} while (0) #else #define DBG_CNT(s) #endif @@ -146,7 +146,7 @@ }; static char *serial_name = "PCIO serial driver"; -static char *serial_version = "1.1"; +static char serial_version[16]; static DECLARE_TASK_QUEUE(tq_serial); @@ -251,10 +251,10 @@ /* * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are * connected with a gate then go to SlavIO. When IRQ4 goes tristated - * gate gives logical one. Since we use level triggered interrupts + * gate outputs a logical one. Since we use level triggered interrupts * we have lockup and watchdog reset. We cannot mask IRQ because - * keyboard shares IRQ with us (Bob Smelik: I would not hire you). - * P3: Assure that OUT2 never goes down. + * keyboard shares IRQ with us (Word has it as Bob Smelik's design). + * This problem is similar to what Alpha people suffer, see serial.c. */ if (offset == UART_MCR) value |= UART_MCR_OUT2; *(volatile unsigned char *)(info->port + offset) = value; @@ -386,14 +386,13 @@ icount = &info->icount; do { ch = serial_inp(info, UART_RX); - 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); + printk("D%02x:%02x.", ch, *status); #endif *tty->flip.flag_buf_ptr = 0; if (*status & (UART_LSR_BI | UART_LSR_PE | @@ -417,8 +416,12 @@ * should be ignored. */ if (*status & info->ignore_status_mask) { - if (++ignored > 100) + if (++ignored > 100) { +#ifdef SERIAL_DEBUG_INTR + printk("ign100.."); +#endif break; + } goto ignore_char; } *status &= info->read_status_mask; @@ -454,6 +457,9 @@ ignore_char: *status = serial_inp(info, UART_LSR); } while (*status & UART_LSR_DR); +#ifdef SERIAL_DEBUG_INTR + printk("E%02x.R%d", *status, tty->flip.count); +#endif tty_flip_buffer_push(tty); } @@ -490,7 +496,7 @@ su_sched_event(info, RS_EVENT_WRITE_WAKEUP); #ifdef SERIAL_DEBUG_INTR - printk("THRE..."); + printk("T%d...", info->xmit_cnt); #endif if (intr_done) *intr_done = 0; @@ -580,7 +586,7 @@ unsigned char status; #ifdef SERIAL_DEBUG_INTR - printk("su_interrupt(%s)...", __irq_itoa(irq)); + printk("su_kbd_ms_interrupt(%s)...", __irq_itoa(irq)); #endif if (!info) return; @@ -611,12 +617,16 @@ int pass_counter = 0; #ifdef SERIAL_DEBUG_INTR - printk("su_interrupt(%s)...", __irq_itoa(irq)); + printk("su_serial_interrupt(%s)...", __irq_itoa(irq)); #endif info = (struct su_struct *)dev_id; - if (!info || !info->tty) + if (!info || !info->tty) { +#ifdef SERIAL_DEBUG_INTR + printk("strain\n"); +#endif return; - + } + do { status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR @@ -629,8 +639,8 @@ transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 - printk("rs loop break\n"); +#ifdef SERIAL_DEBUG_INTR + printk("rs loop break"); #endif break; /* Prevent infinite loops */ } @@ -658,18 +668,16 @@ * interrupt driver proper are done; the interrupt driver schedules * them using su_sched_event(), and they get done here. */ -static void -do_serial_bh(void) +static void do_serial_bh(void) { run_task_queue(&tq_serial); } -static void -do_softint(void *private_) +static void do_softint(void *private_) { struct su_struct *info = (struct su_struct *) private_; struct tty_struct *tty; - + tty = info->tty; if (!tty) return; @@ -724,7 +732,8 @@ cli(); #ifdef SERIAL_DEBUG_OPEN - printk("starting up ttys%d (irq %d)...", info->line, state->irq); + printk("starting up ttys%d (irq %s)...", info->line, + __irq_itoa(info->irq)); #endif if (uart_config[info->type].flags & UART_STARTECH) { @@ -1269,12 +1278,13 @@ su_flush_buffer(struct tty_struct *tty) { struct su_struct *info = (struct su_struct *)tty->driver_data; + unsigned long flags; if (serial_paranoia_check(info, tty->device, "su_flush_buffer")) return; - cli(); + save_flags(flags); cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); + restore_flags(flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) @@ -1313,41 +1323,43 @@ su_throttle(struct tty_struct * tty) { struct su_struct *info = (struct su_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, "su_throttle")) return; - + if (I_IXOFF(tty)) su_send_xchar(tty, STOP_CHAR(tty)); if (tty->termios->c_cflag & CRTSCTS) info->MCR &= ~UART_MCR_RTS; - cli(); + save_flags(flags); cli(); serial_out(info, UART_MCR, info->MCR); - sti(); + restore_flags(flags); } static void su_unthrottle(struct tty_struct * tty) { struct su_struct *info = (struct su_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, "su_unthrottle")) return; - + if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; @@ -1356,9 +1368,9 @@ } if (tty->termios->c_cflag & CRTSCTS) info->MCR |= UART_MCR_RTS; - cli(); + save_flags(flags); cli(); serial_out(info, UART_MCR, info->MCR); - sti(); + restore_flags(flags); } /* @@ -1382,10 +1394,11 @@ { unsigned char status; unsigned int result; + unsigned long flags; - cli(); + save_flags(flags); cli(); status = serial_in(info, UART_LSR); - sti(); + restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); return put_user(result,value); } @@ -1396,11 +1409,12 @@ { unsigned char control, status; unsigned int result; + unsigned long flags; control = info->MCR; - cli(); + save_flags(flags); cli(); status = serial_in(info, UART_MSR); - sti(); + restore_flags(flags); result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) #ifdef TIOCM_OUT1 @@ -1419,6 +1433,7 @@ { int error; unsigned int arg; + unsigned long flags; error = get_user(arg, value); if (error) @@ -1465,9 +1480,9 @@ default: return -EINVAL; } - cli(); + save_flags(flags); cli(); serial_out(info, UART_MCR, info->MCR); - sti(); + restore_flags(flags); return 0; } @@ -1589,13 +1604,14 @@ default: return -ENOIOCTLCMD; } - /* return 0; */ /* Trigger warnings is fall through by a chance. */ + /* return 0; */ /* Trigger warnings if fall through by a chance. */ } static void su_set_termios(struct tty_struct *tty, struct termios *old_termios) { struct su_struct *info = (struct su_struct *)tty->driver_data; + unsigned long flags; if ( (tty->termios->c_cflag == old_termios->c_cflag) && ( RELEVANT_IFLAG(tty->termios->c_iflag) @@ -1608,11 +1624,11 @@ if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - cli(); + save_flags(flags); cli(); serial_out(info, UART_MCR, info->MCR); - sti(); + restore_flags(flags); } - + /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { @@ -1621,9 +1637,9 @@ !test_bit(TTY_THROTTLED, &tty->flags)) { info->MCR |= UART_MCR_RTS; } - cli(); + save_flags(flags); cli(); serial_out(info, UART_MCR, info->MCR); - sti(); + restore_flags(flags); } /* Handle turning off CRTSCTS */ @@ -1771,6 +1787,9 @@ if (info->type == PORT_UNKNOWN) 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 @@ -1838,8 +1857,9 @@ struct su_struct *info) { struct wait_queue wait = { current, NULL }; - int retval; - int do_clocal = 0; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; /* * If the device is in the middle of being closed, then block @@ -1909,19 +1929,21 @@ printk("block_til_ready before block: ttys%d, count = %d\n", info->line, info->count); #endif - cli(); - if (!tty_hung_up_p(filp)) + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; info->count--; - sti(); + } + restore_flags(flags); info->blocked_open++; while (1) { - cli(); + save_flags(flags); cli(); if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) serial_out(info, UART_MCR, serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); - sti(); + restore_flags(flags); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { @@ -1952,7 +1974,7 @@ } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) + if (extra_count) info->count++; info->blocked_open--; #ifdef SERIAL_DEBUG_OPEN @@ -1982,16 +2004,19 @@ if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; info = su_table + line; - if (serial_paranoia_check(info, tty->device, "su_open")) - return -ENODEV; info->count++; + tty->driver_data = info; + info->tty = tty; + + if (serial_paranoia_check(info, tty->device, "su_open")) { + info->count--; + return -ENODEV; + } #ifdef SERIAL_DEBUG_OPEN printk("su_open %s%d, count = %d\n", tty->driver.name, info->line, info->count); #endif - tty->driver_data = info; - info->tty = tty; info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (!tmp_buf) { @@ -2066,8 +2091,9 @@ static __inline__ int line_info(char *buf, struct su_struct *info) { - char stat_buf[30], control, status; - int ret; + char stat_buf[30], control, status; + int ret; + unsigned long flags; ret = sprintf(buf, "%d: uart:%s port:%X irq:%s", info->line, uart_config[info->type].name, @@ -2081,10 +2107,10 @@ /* * Figure out the current RS-232 lines */ - cli(); + save_flags(flags); cli(); status = serial_in(info, UART_MSR); control = info ? info->MCR : serial_in(info, UART_MCR); - sti(); + restore_flags(flags); stat_buf[0] = 0; stat_buf[1] = 0; @@ -2165,9 +2191,15 @@ * number, and identifies which options were configured into this * driver. */ -static __inline__ -void show_su_version(void) +__initfunc(static __inline__ void show_su_version(void)) { + char *revision = "$Revision: 1.16 $"; + char *version, *p; + + version = strchr(revision, ' '); + strcpy(serial_version, ++version); + p = strchr(serial_version, ' '); + *p = '\0'; printk(KERN_INFO "%s version %s\n", serial_name, serial_version); } @@ -2249,23 +2281,21 @@ * 0x80 is a non-existent port; which should be safe since * include/asm/io.h also makes this assumption. */ - scratch = serial_in(info, UART_IER); - su_outb(info, UART_IER, 0); - scratch2 = serial_in(info, UART_IER); - su_outb(info, UART_IER, scratch); + scratch = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, 0); + scratch2 = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, scratch); if (scratch2) { restore_flags(flags); return; /* We failed; there's nothing here */ } -#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */ - scratch = serial_in(info, UART_MCR); - su_outb(info, UART_MCR, UART_MCR_LOOP | scratch); - scratch2 = serial_in(info, UART_MSR); - su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_in(info, UART_MSR) & 0xF0; - su_outb(info, UART_MCR, scratch); - su_outb(info, UART_MSR, scratch2); +#if 0 /* P3: This does not work on MrCoffee. OUT2 is 0x80 - should work... */ + scratch = serial_inp(info, UART_MCR); + serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch); + serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_inp(info, UART_MSR) & 0xF0; + serial_outp(info, UART_MCR, scratch); if (status1 != 0x90) { restore_flags(flags); return; @@ -2273,10 +2303,10 @@ #endif scratch2 = serial_in(info, UART_LCR); - su_outb(info, UART_LCR, 0xBF); /* set up for StarTech test */ - su_outb(info, UART_EFR, 0); /* EFR is the same as FCR */ - su_outb(info, UART_LCR, 0); - su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */ + serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */ + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); scratch = serial_in(info, UART_IIR) >> 6; switch (scratch) { case 0: @@ -2294,38 +2324,38 @@ } if (info->type == PORT_16550A) { /* Check for Startech UART's */ - su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB); - if (su_inb(info, UART_EFR) == 0) { + serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB); + if (serial_in(info, UART_EFR) == 0) { info->type = PORT_16650; } else { - su_outb(info, UART_LCR, 0xBF); - if (su_inb(info, UART_EFR) == 0) + serial_outp(info, UART_LCR, 0xBF); + if (serial_in(info, UART_EFR) == 0) info->type = PORT_16650V2; } } if (info->type == PORT_16550A) { /* Check for TI 16750 */ - su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB); - su_outb(info, UART_FCR, + serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = su_inb(info, UART_IIR) >> 5; + scratch = serial_in(info, UART_IIR) >> 5; if (scratch == 7) { - su_outb(info, UART_LCR, 0); - su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = su_inb(info, UART_IIR) >> 5; + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(info, UART_IIR) >> 5; if (scratch == 6) info->type = PORT_16750; } - su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); } - su_outb(info, UART_LCR, scratch2); + serial_outp(info, UART_LCR, scratch2); if (info->type == PORT_16450) { - scratch = su_inb(info, UART_SCR); - su_outb(info, UART_SCR, 0xa5); - status1 = su_inb(info, UART_SCR); - su_outb(info, UART_SCR, 0x5a); - status2 = su_inb(info, UART_SCR); - su_outb(info, UART_SCR, scratch); + scratch = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0xa5); + status1 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0x5a); + status2 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, scratch); if ((status1 != 0xa5) || (status2 != 0x5a)) info->type = PORT_8250; @@ -2349,9 +2379,10 @@ /* * Reset the UART. */ - su_outb(info, UART_MCR, 0x00); - su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); - su_inb(info, UART_RX); + serial_outp(info, UART_MCR, 0x00); + serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT)); + (void)serial_in(info, UART_RX); + serial_outp(info, UART_IER, 0x00); restore_flags(flags); } diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.1.128/linux/drivers/sbus/char/zs.c Sun Nov 8 14:03:01 1998 +++ linux/drivers/sbus/char/zs.c Mon Nov 16 10:37:28 1998 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.31 1998/10/07 11:35:29 jj Exp $ +/* $Id: zs.c,v 1.32 1998/11/08 11:15:29 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1806,7 +1806,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.31 $"; + char *revision = "$Revision: 1.32 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.1.128/linux/drivers/scsi/ChangeLog.ncr53c8xx Sun Nov 8 14:03:02 1998 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Sun Nov 15 09:57:00 1998 @@ -1,3 +1,9 @@ +Wed Nov 11 10:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.1b + - The driver was unhappy when configured with default_tags > MAX_TAGS + Hopefully doubly-fixed. + - Update the Configure.help driver section that speaks of TAGS. + Wed Oct 21 21:00 1998 Gerard Roudier (groudier@club-internet.fr) * revision 3.1a - Changes from Eddie Dost for Sparc and Alpha: diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.128/linux/drivers/scsi/Config.in Thu Nov 12 16:21:20 1998 +++ linux/drivers/scsi/Config.in Sun Nov 15 09:57:00 1998 @@ -80,7 +80,7 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then - int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 4 + int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c --- v2.1.128/linux/drivers/scsi/NCR5380.c Wed Sep 9 14:51:08 1998 +++ linux/drivers/scsi/NCR5380.c Fri Nov 13 10:29:44 1998 @@ -686,7 +686,7 @@ save_flags(flags); cli(); for (; expires_first && - ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires <= jiffies; ) + time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); ) { instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer; ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL; @@ -776,7 +776,7 @@ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); - while (probe_irq == IRQ_NONE && jiffies < timeout) + while (probe_irq == IRQ_NONE && time_before(jiffies,timeout)) barrier(); NCR5380_write(SELECT_ENABLE_REG, 0); @@ -1123,7 +1123,7 @@ printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no); timeout = jiffies + 5 * HZ; - while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY)); break; case 2: printk("scsi%d: bus busy, attempting abort\n", @@ -1417,7 +1417,7 @@ && !hostdata->dmalen #endif #ifdef USLEEP - && (!hostdata->time_expires || hostdata->time_expires <= jiffies) + && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies)) #endif ) { restore_flags(flags); @@ -1532,10 +1532,10 @@ spin_unlock_irq(&io_request_lock); while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK - && jiffies < timeout); + && time_before(jiffies, timeout)); spin_lock_irq(&io_request_lock); - if (jiffies >= timeout) + if (time_after_eq(jiffies, timeout) ) printk("scsi%d: timeout at NCR5380.c:%d\n", host->host_no, __LINE__); } @@ -1681,11 +1681,11 @@ spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && jiffies < timeout); + && time_before(jiffies,timeout)); spin_lock_irq(&io_request_lock); - if (jiffies >= timeout) { + if (time_after_eq(jiffies,timeout)) { printk("scsi: arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1844,7 +1844,7 @@ waiting period */ #else spin_unlock_irq(&io_request_lock); - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))); spin_lock_irq(&io_request_lock); #endif @@ -1915,10 +1915,10 @@ unsigned long timeout = jiffies + NCR_TIMEOUT; spin_unlock_irq(&io_request_lock); - while (!(NCR5380_read(STATUS_REG) & SR_REQ) && jiffies < timeout); + while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout)); spin_lock_irq(&io_request_lock); - if (jiffies >= timeout) { + if (time_after_eq(jiffies, timeout)) { printk("scsi%d: timeout at NCR5380.c:%d\n", __LINE__); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; @@ -3082,7 +3082,7 @@ { /* RvC: go to sleep if polling time expired */ - if (!cmd->device->disconnect && jiffies >= poll_time) + if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) { hostdata->time_expires = jiffies + USLEEP_SLEEP; #if (NDEBUG & NDEBUG_USLEEP) diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v2.1.128/linux/drivers/scsi/esp.c Thu Aug 6 14:06:33 1998 +++ linux/drivers/scsi/esp.c Mon Nov 16 10:37:28 1998 @@ -1432,7 +1432,6 @@ (SDptr->type != TYPE_ROM || strncmp(SDptr->vendor, "TOSHIBA", 7))) { build_wide_nego_msg(esp, 16); - esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE; SDptr->wide = 1; esp->wnip = 1; goto after_nego_msg_built; diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/fd_mcs.c linux/drivers/scsi/fd_mcs.c --- v2.1.128/linux/drivers/scsi/fd_mcs.c Thu Nov 12 16:21:21 1998 +++ linux/drivers/scsi/fd_mcs.c Sun Nov 15 09:52:27 1998 @@ -88,7 +88,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c --- v2.1.128/linux/drivers/scsi/mesh.c Thu Aug 6 14:06:33 1998 +++ linux/drivers/scsi/mesh.c Sun Nov 15 10:51:48 1998 @@ -28,6 +28,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -222,6 +223,13 @@ struct Scsi_Host *mesh_host; void *dma_cmd_space; + if (_machine == _MACH_Pmac) { + use_active_neg = (find_devices("mac-io") ? 0 : SEQ_ACTIVE_NEG); + } else { + /* CHRP mac-io */ + use_active_neg = SEQ_ACTIVE_NEG; + } + nmeshes = 0; prev_statep = &all_meshes; /* @@ -245,7 +253,7 @@ } mesh_host->unique_id = nmeshes; note_scsi_host(mesh, mesh_host); - + ms = (struct mesh_state *) mesh_host->hostdata; if (ms == 0) panic("no mesh state"); @@ -281,10 +289,6 @@ *prev_statep = ms; prev_statep = &ms->next; - if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) { - printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr); - } - if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL))) { ms->clk_freq = *cfp; @@ -298,18 +302,20 @@ if (mesh_sync_period < minper) mesh_sync_period = minper; + feature_set(mesh, FEATURE_MESH_enable); + mdelay(200); + mesh_init(ms); + if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) { + printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr); + } + ++nmeshes; } - if (_machine == _MACH_Pmac) { - use_active_neg = (find_devices("mac-io") ? 0 : SEQ_ACTIVE_NEG); - if (nmeshes > 0) + + if ((_machine == _MACH_Pmac) && (nmeshes > 0)) register_reboot_notifier(&mesh_notifier); - } else { - /* CHRP mac-io */ - use_active_neg = SEQ_ACTIVE_NEG; - } return nmeshes; } @@ -467,12 +473,27 @@ volatile struct mesh_regs *mr = ms->mesh; volatile struct dbdma_regs *md = ms->dma; - out_8(&mr->interrupt, 0xff); /* clear all interrupt bits */ + udelay(100); + + out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */ + out_8(&mr->exception, 0xff); /* clear all exception bits */ + out_8(&mr->error, 0xff); /* clear all error bits */ + out_8(&mr->sequence, SEQ_RESETMESH); + udelay(10); out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); out_8(&mr->source_id, ms->host->this_id); out_8(&mr->sel_timeout, 25); /* 250ms */ - out_8(&mr->sync_params, ASYNC_PARAMS); /* asynchronous initially */ - out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + out_8(&mr->sync_params, ASYNC_PARAMS); + + out_8(&mr->bus_status1, BS1_RST); /* assert RST */ + udelay(30); /* leave it on for >= 25us */ + out_8(&mr->bus_status1, 0); /* negate RST */ + + out_8(&mr->sequence, SEQ_FLUSHFIFO); + udelay(1); + out_8(&mr->sync_params, ASYNC_PARAMS); + out_8(&mr->sequence, SEQ_ENBRESEL); + out_8(&mr->interrupt, 0xff); /* clear all interrupt bits */ } /* diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.1.128/linux/drivers/scsi/ncr53c8xx.c Sun Nov 8 14:03:02 1998 +++ linux/drivers/scsi/ncr53c8xx.c Sun Nov 15 09:57:00 1998 @@ -73,7 +73,7 @@ */ /* -** October 21 1998, version 3.1a +** November 11 1998, version 3.1b ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -4319,7 +4319,7 @@ #endif tp->usrsync = driver_setup.default_sync; tp->usrwide = driver_setup.max_wide; - tp->usrtags = driver_setup.default_tags; + tp->usrtags = SCSI_NCR_MAX_TAGS; if (!driver_setup.disconnection) np->target[i].usrflag = UF_NODISC; } @@ -8208,6 +8208,12 @@ if (lp) { XPT_QUEHEAD *qp; /* + ** Keep from using more tags than we can handle. + */ + if (lp->usetags && lp->busyccbs >= lp->maxnxs) + return (ccb_p) 0; + + /* ** Allocate a new CCB if needed. */ if (xpt_que_empty(&lp->free_ccbq)) @@ -10072,19 +10078,20 @@ lp = tp->lp[device->lun]; /* - ** Donnot use more than our maximum. ** Select queue depth from driver setup. ** Donnot use more than configured by user. ** Use 2 for devices that donnot support tags. ** Use at least 2. + ** Donnot use more than our maximum. */ - device->queue_depth = SCSI_NCR_MAX_TAGS; device->queue_depth = device_queue_depth(np, device->id, device->lun); if (device->queue_depth > tp->usrtags) device->queue_depth = tp->usrtags; if (!device->tagged_supported || device->queue_depth < 2) device->queue_depth = 2; + if (device->queue_depth > SCSI_NCR_MAX_TAGS) + device->queue_depth = SCSI_NCR_MAX_TAGS; /* ** Since the queue depth is not tunable under Linux, diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h --- v2.1.128/linux/drivers/scsi/ncr53c8xx.h Sun Nov 8 14:03:02 1998 +++ linux/drivers/scsi/ncr53c8xx.h Wed Nov 18 22:31:57 1998 @@ -45,7 +45,7 @@ /* ** Name and revision of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.1a" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.1b" /* ** Check supported Linux versions diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.128/linux/drivers/scsi/scsi.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/scsi/scsi.c Fri Nov 13 10:16:15 1998 @@ -226,6 +226,7 @@ {"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */ {"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ +{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* Responds to all lun */ {"RODIME","RO3000S","2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 * for aha152x controller, which causes diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c --- v2.1.128/linux/drivers/scsi/scsi_proc.c Tue Jun 23 10:01:24 1998 +++ linux/drivers/scsi/scsi_proc.c Fri Nov 13 10:16:15 1998 @@ -110,14 +110,29 @@ return(-EBADF); } +static void scsi_proc_fill_inode(struct inode *inode, int fill) +{ +Scsi_Host_Template *shpnt; + +shpnt = scsi_hosts; +while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino) + shpnt = shpnt->next; +if (!shpnt || !shpnt->module) + return; +if (fill) + __MOD_INC_USE_COUNT(shpnt->module); +else + __MOD_DEC_USE_COUNT(shpnt->module); +} + void build_proc_dir_entries(Scsi_Host_Template *tpnt) { struct Scsi_Host *hpnt; - struct scsi_dir *scsi_hba_dir; proc_scsi_register(0, tpnt->proc_dir); - + tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode; + hpnt = scsi_hostlist; while (hpnt) { if (tpnt == hpnt->hostt) { diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.1.128/linux/drivers/scsi/sd.c Sun Nov 8 14:03:02 1998 +++ linux/drivers/scsi/sd.c Wed Nov 18 16:42:44 1998 @@ -1758,7 +1758,7 @@ void cleanup_module( void) { - struct gendisk * prev_sdgd; + struct gendisk ** prev_sdgd_link; struct gendisk * sdgd; int i; int removed = 0; @@ -1778,16 +1778,20 @@ scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int)); scsi_init_free((char *) sd, (sd_template.dev_max << 4) * sizeof(struct hd_struct)); + /* * Now remove sd_gendisks from the linked list */ - - for (sdgd = gendisk_head; sdgd; sdgd = sdgd->next) - { - if (sdgd->next >= sd_gendisks && sdgd->next <= LAST_SD_GENDISK.max_nr) - removed++, sdgd->next = sdgd->next->next; - else sdgd = sdgd->next; + prev_sdgd_link = &gendisk_head; + while ((sdgd = *prev_sdgd_link) != NULL) { + if (sdgd >= sd_gendisks && sdgd <= &LAST_SD_GENDISK) { + removed++; + *prev_sdgd_link = sdgd->next; + continue; + } + prev_sdgd_link = &sdgd->next; } + if (removed != N_USED_SD_MAJORS) printk("%s %d sd_gendisks in disk chain", removed > N_USED_SD_MAJORS ? "total" : "just", removed); diff -u --recursive --new-file v2.1.128/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.128/linux/drivers/sound/Makefile Fri Oct 23 22:01:21 1998 +++ linux/drivers/sound/Makefile Mon Nov 16 10:32:58 1998 @@ -41,19 +41,7 @@ # Each configuration option enables a list of files. obj-$(CONFIG_SOUND) += soundcore.o - -ifeq ($(ARCH),m68k) - obj-$(CONFIG_DMASOUND) += dmasound.o - -else - -ifeq ($(CONFIG_PMAC),y) - -obj-$(CONFIG_DMASOUND) += dmasound.o - -else - obj-$(CONFIG_SOUND_OSS) += sound.o obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o @@ -89,9 +77,6 @@ obj-$(CONFIG_SOUND_ES1370) += es1370.o obj-$(CONFIG_SOUND_ES1371) += es1371.o obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o - -endif -endif # Declare multi-part drivers. diff -u --recursive --new-file v2.1.128/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.128/linux/drivers/sound/ad1848.c Thu Nov 12 16:21:21 1998 +++ linux/drivers/sound/ad1848.c Fri Nov 13 10:29:44 1998 @@ -1934,7 +1934,7 @@ if (!share_dma) { - if (irq > 0) + if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */ free_irq(devc->irq, (void *)devc->dev_no); sound_free_dma(audio_devs[dev]->dmap_out->dma); diff -u --recursive --new-file v2.1.128/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.1.128/linux/drivers/sound/dmasound.c Thu Nov 12 16:21:22 1998 +++ linux/drivers/sound/dmasound.c Sun Nov 15 10:51:48 1998 @@ -107,18 +107,17 @@ #include #include #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC #include #include #include -#ifdef CONFIG_PMAC_PBOOK #include +#include #include -#endif /* CONFIG_PMAC_PBOOK */ #include "awacs_defs.h" #include #include -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ #include "dmasound.h" #include @@ -165,7 +164,7 @@ #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC /* * Interrupt numbers and addresses, obtained from the device tree. */ @@ -174,6 +173,8 @@ static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; static int awacs_rate_index; static int awacs_subframe; +static int awacs_revision; +static int awacs_spkr_vol; /* * Space for the DBDMA command blocks. @@ -249,7 +250,7 @@ }; #endif /* CONFIG_PMAC_PBOOK */ -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ /*** Some declarations *******************************************************/ @@ -587,7 +588,7 @@ ssize_t frameLeft); #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft); @@ -618,7 +619,7 @@ static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft); -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ /*** Machine definitions *****************************************************/ @@ -675,7 +676,7 @@ int treble; int gain; int minDev; /* minor device number currently open */ -#if defined(CONFIG_ATARI) || defined(CONFIG_PMAC) +#if defined(CONFIG_ATARI) || defined(CONFIG_PPC) int bal; /* balance factor for expanding (not volume!) */ u_long data; /* data for expanding */ #endif /* CONFIG_ATARI */ @@ -724,7 +725,7 @@ static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static void *PMacAlloc(unsigned int size, int flags) __init; static void PMacFree(void *ptr, unsigned int size) __init; static int PMacIrqInit(void) __init; @@ -743,7 +744,7 @@ static int awacs_volume_setter(int volume, int n, int mute, int lshift); static void awacs_mksound(unsigned int hz, unsigned int ticks); static void awacs_nosound(unsigned long xx); -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ /*** Mid level stuff *********************************************************/ @@ -1777,7 +1778,7 @@ } #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) @@ -2161,7 +2162,7 @@ return stereo? utotal * 4: utotal * 2; } -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ #ifdef CONFIG_ATARI @@ -2191,7 +2192,7 @@ }; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static TRANS transAwacsNormal = { pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8, pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16 @@ -2201,7 +2202,7 @@ pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8, pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16 }; -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ /*** Low level stuff *********************************************************/ @@ -2971,7 +2972,7 @@ } #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC /* * PCI PowerMac, with AWACS and DBDMA. @@ -3226,7 +3227,7 @@ { while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) ; /* XXX should have timeout */ - out_le32(&awacs->codec_ctrl, val); + out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22)); } static void awacs_nosound(unsigned long xx) @@ -3343,7 +3344,38 @@ } #endif /* CONFIG_PMAC_PBOOK */ -#endif /* CONFIG_PMAC */ +/* Turn on sound output, needed on G3 desktop powermacs */ +static void +awacs_enable_amp(int spkr_vol) +{ + struct adb_request req; + + awacs_spkr_vol = spkr_vol; + if (adb_hardware != ADB_VIACUDA) + return; + + /* turn on headphones */ + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x8a, 4, 0); + while (!req.complete) cuda_poll(); + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x8a, 6, 0); + while (!req.complete) cuda_poll(); + + /* turn on speaker */ + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100); + while (!req.complete) cuda_poll(); + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100); + while (!req.complete) cuda_poll(); + + cuda_request(&req, NULL, 5, CUDA_PACKET, + CUDA_GET_SET_IIC, 0x8a, 1, 0x29); + while (!req.complete) cuda_poll(); +} + +#endif /* CONFIG_PPC */ /*** Machine definitions *****************************************************/ @@ -3382,7 +3414,7 @@ }; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static MACHINE machPMac = { DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit, #ifdef MODULE @@ -3683,7 +3715,7 @@ break; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC case DMASND_AWACS: switch (cmd) { case SOUND_MIXER_READ_DEVMASK: @@ -3733,12 +3765,18 @@ IOCTL_IN(arg, data); return IOCTL_OUT(arg, sound_set_volume(data)); case SOUND_MIXER_READ_SPEAKER: - data = (awacs_reg[1] & MASK_CMUTE)? 0: - awacs_get_volume(awacs_reg[4], 6); + if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA) + data = awacs_spkr_vol; + else + data = (awacs_reg[1] & MASK_CMUTE)? 0: + awacs_get_volume(awacs_reg[4], 6); return IOCTL_OUT(arg, data); case SOUND_MIXER_WRITE_SPEAKER: IOCTL_IN(arg, data); - data = awacs_volume_setter(data, 4, MASK_CMUTE, 6); + if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA) + awacs_enable_amp(data); + else + data = awacs_volume_setter(data, 4, MASK_CMUTE, 6); return IOCTL_OUT(arg, data); case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ IOCTL_IN(arg, data); @@ -3862,10 +3900,10 @@ static void sq_setup(int numBufs, int bufSize, char **buffers) { -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC int i; volatile struct dbdma_cmd *cp; -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ sq.max_count = numBufs; sq.max_active = numBufs; @@ -3887,7 +3925,7 @@ sq.block_size_half = sq.block_size>>1; sq.block_size_quarter = sq.block_size_half>>1; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC cp = awacs_tx_cmds; memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd)); for (i = 0; i < numBufs; ++i, ++cp) { @@ -3897,7 +3935,7 @@ st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds)); out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds)); -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ } static void sq_play(void) @@ -4206,11 +4244,11 @@ sound.dsp.speed = 8000; break; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC case DMASND_AWACS: sound.dsp.speed = 8000; break; -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ } /* before the first open to /dev/dsp this wouldn't be set */ @@ -4251,11 +4289,11 @@ mach = "Amiga "; break; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC case DMASND_AWACS: mach = "PowerMac "; break; -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ } len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); @@ -4396,7 +4434,7 @@ { int has_sound = 0; int i; -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC struct device_node *np; #endif @@ -4430,7 +4468,7 @@ } #endif /* __mc68000__ */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC awacs_subframe = 0; np = find_devices("awacs"); if (np == 0) { @@ -4479,6 +4517,13 @@ awacs_write(awacs_reg[2] + MASK_ADDR2); awacs_write(awacs_reg[4] + MASK_ADDR4); + /* Initialize recent versions of the awacs */ + awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf; + if (awacs_revision >= 3) { + awacs_write(0x6000); + awacs_enable_amp(100 * 0x101); + } + /* Initialize beep stuff */ beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1); orig_mksound = kd_mksound; @@ -4492,7 +4537,7 @@ &awacs_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ } -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ if (!has_sound) return; diff -u --recursive --new-file v2.1.128/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.128/linux/drivers/sound/soundcard.c Thu Nov 12 16:21:22 1998 +++ linux/drivers/sound/soundcard.c Fri Nov 13 10:29:44 1998 @@ -292,11 +292,13 @@ return len; } +#ifdef CONFIG_PROC_FS static struct proc_dir_entry proc_root_sound = { PROC_SOUND, 5, "sound", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL, sound_proc_get_info }; +#endif #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -842,8 +844,10 @@ audio_init_devices(); } #endif +#ifdef CONFIG_PROC_FS if (proc_register(&proc_root, &proc_root_sound)) printk(KERN_ERR "sound: registering /proc/sound failed\n"); +#endif } static int sound[20] = { diff -u --recursive --new-file v2.1.128/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.1.128/linux/drivers/video/Config.in Fri Oct 23 22:01:22 1998 +++ linux/drivers/video/Config.in Fri Nov 13 10:10:11 1998 @@ -22,6 +22,7 @@ tristate 'Amiga CyberVision support' CONFIG_FB_CYBER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE + bool 'Amiga CyberVisionPPC support (experimental)' CONFIG_FB_CVPPC tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN fi @@ -55,6 +56,17 @@ bool 'VESA VGA graphics console' CONFIG_FB_VESA define_bool CONFIG_VIDEO_SELECT y fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + tristate 'Matrox acceleration' CONFIG_FB_MATROX + if [ "$CONFIG_FB_MATROX" != "n" ]; then + bool ' Millenium I/II support' CONFIG_FB_MATROX_MILLENIUM + bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE + bool ' G100/G200 support' CONFIG_FB_MATROX_G100 + bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD + fi + fi + fi if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then bool 'SBUS and UPA framebuffers' CONFIG_FB_SBUS if [ "$CONFIG_FB_SBUS" != "n" ]; then @@ -141,8 +153,9 @@ "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \ + "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ - "$CONFIG_FB_IGA" = "y" ]; then + "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" ]; then define_bool CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ @@ -152,8 +165,9 @@ "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \ + "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ - "$CONFIG_FB_IGA" = "y" ]; then + "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" ]; then define_bool CONFIG_FBCON_CFB8 m fi fi @@ -161,36 +175,44 @@ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ - "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then + "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ + "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_MATROX" = "y" ]; then define_bool CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ - "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then + "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ + "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_MATROX" = "m" ]; then define_bool CONFIG_FBCON_CFB16 m fi fi if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ - "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" ]; then + "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ + "$CONFIG_FB_MATROX" = "y" ]; then define_bool CONFIG_FBCON_CFB24 y else if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" ]; then + "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ + "$CONFIG_FB_MATROX" = "m" ]; then define_bool CONFIG_FBCON_CFB24 m fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ - "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then + "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_MATROX" = "y" ]; then define_bool CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ - "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then + "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_MATROX" = "m" ]; then define_bool CONFIG_FBCON_CFB32 m fi fi diff -u --recursive --new-file v2.1.128/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.1.128/linux/drivers/video/Makefile Fri Oct 23 22:01:22 1998 +++ linux/drivers/video/Makefile Fri Nov 13 10:10:11 1998 @@ -123,6 +123,11 @@ endif endif +ifeq ($(CONFIG_FB_CVPPC),y) +L_OBJS += cvppcfb.o +CONFIG_FBGEN_BUILTIN = y +endif + ifeq ($(CONFIG_FB_MAC),y) L_OBJS += macfb.o endif @@ -308,6 +313,14 @@ else ifdef CONFIG_FBGEN_MODULE MX_OBJS += fbgen.o + endif +endif + +ifeq ($(CONFIG_FB_MATROX),y) +L_OBJS += matroxfb.o +else + ifeq ($(CONFIG_FB_MATROX),m) + M_OBJS += matroxfb.o endif endif diff -u --recursive --new-file v2.1.128/linux/drivers/video/amifb.c linux/drivers/video/amifb.c --- v2.1.128/linux/drivers/video/amifb.c Fri Oct 9 13:27:11 1998 +++ linux/drivers/video/amifb.c Fri Nov 13 10:10:11 1998 @@ -60,6 +60,7 @@ #include #include #include +#include #include