diff -u --recursive --new-file v2.4.0-test7/linux/CREDITS linux/CREDITS --- v2.4.0-test7/linux/CREDITS Wed Aug 23 18:36:35 2000 +++ linux/CREDITS Tue Sep 5 14:08:55 2000 @@ -514,6 +514,14 @@ S: University of Michigan S: Ann Arbor, MI +N: Kees Cook +E: cook@cpoint.net +W: http://outflux.net/ +P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D +D: Minor updates to SCSI code for the Communications type +S: (ask for current address) +S: USA + N: Alan Cox W: http://roadrunner.swansea.linux.org.uk/alan.shtml E: alan@lxorguk.ukuu.org.uk @@ -2084,7 +2092,7 @@ D: CDROM driver "sonycd535" (Sony CDU-535/531) N: Frederic Potter -E: Frederic.Potter@masi.ibp.fr +E: fpotter@cirpack.com D: Some PCI kernel support N: Rui Prior diff -u --recursive --new-file v2.4.0-test7/linux/Documentation/Changes linux/Documentation/Changes --- v2.4.0-test7/linux/Documentation/Changes Wed Aug 23 18:36:35 2000 +++ linux/Documentation/Changes Tue Sep 5 13:55:46 2000 @@ -25,7 +25,10 @@ Smotrite file , yavlyaushisya russkim perevodom dannogo documenta. -Last updated: August 15, 2000 +Visite para obtener la traducción +al español de este documento en varios formatos. + +Last updated: August 28, 2000 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -44,10 +47,10 @@ o Gnu C 2.7.2.3 # gcc --version o Gnu make 3.77 # make --version -o binutils 2.9.1.0.22 # ld -v +o binutils 2.9.1.0.25 # ld -v o util-linux 2.10o # kbdrate -v -o modutils 2.3.13 # insmod -V -o e2fsprogs 1.18 # /sbin/tune2fs --version +o modutils 2.3.15 # insmod -V +o e2fsprogs 1.18 # tune2fs --version o pcmcia-cs 3.1.19 # cardmgr -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1beta7 # isdnctrl 2>&1|grep version @@ -257,16 +260,16 @@ ------------ o -2.9.5 series +2.10 series ------------ -o +o System utilities **************** Util-linux ---------- -o +o Ksymoops -------- @@ -274,7 +277,7 @@ Modutils -------- -o +o Mkinitrd -------- @@ -291,7 +294,7 @@ Pcmcia-cs --------- -o +o Jade ---- diff -u --recursive --new-file v2.4.0-test7/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.0-test7/linux/Documentation/Configure.help Wed Aug 23 18:36:35 2000 +++ linux/Documentation/Configure.help Tue Sep 5 12:57:51 2000 @@ -2329,7 +2329,7 @@ AMD Irongate support CONFIG_AGP_AMD This option gives you AGP support for the GLX component of the - XFree86 4.x on Intel AMD Irongate chipset. + XFree86 4.x on AMD Irongate chipset. For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from @@ -7903,6 +7903,25 @@ Documentation/modules.txt. The module will be called comx-hw-mixcom.o. +i810 TCO support +CONFIG_I810_TCO + Hardware driver for the TCO timer built into the Intel i810 and i815 + chipset family. The TCO (Total Cost of Ownership) timer is a watchdog + timer that will reboot the machine after it's second expiration. The + expiration time can be configured by commandline argument + "i810_margin=" where is the counter initial value. It is + decremented every 0.6 secs, the default is 50 which gives a timeout + of 30 seconds and one minute until reset. + + On some motherboards the driver may fail to reset the chipset's + NO_REBOOT flag which prevents the watchdog from rebooting the machine. + If this is the case you will get a kernel message like + "i810tco init: failed to reset NO_REBOOT flag". + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called + i810-tco.o. + MultiGate Cisco-HDLC and synchronous PPP protocol support CONFIG_COMX_PROTO_PPP Cisco-HDLC and synchronous PPP protocol driver for all MultiGate diff -u --recursive --new-file v2.4.0-test7/linux/Documentation/cachetlb.txt linux/Documentation/cachetlb.txt --- v2.4.0-test7/linux/Documentation/cachetlb.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/cachetlb.txt Mon Aug 28 12:02:53 2000 @@ -0,0 +1,319 @@ + Cache and TLB Flushing + Under Linux + + David S. Miller + +This document describes the cache/tlb flushing interfaces called +by the Linux VM subsystem. It enumerates over each interface, +describes it's intended purpose, and what side effect is expected +after the interface is invoked. + +The side effects described below are stated for a uniprocessor +implementation, and what is to happen on that single processor. The +SMP cases are a simple extension, in that you just extend the +definition such that the side effect for a particular interface occurs +on all processors in the system. Don't let this scare you into +thinking SMP cache/tlb flushing must be so inefficient, this is in +fact an area where many optimizations are possible. For example, +if it can be proven that a user address space has never executed +on a cpu (see vma->cpu_vm_mask), one need not perform a flush +for this address space on that cpu. + +First, the TLB flushing interfaces, since they are the simplest. The +"TLB" is abstracted under Linux as something the cpu uses to cache +virtual-->physical address translations obtained from the software +page tables. Meaning that if the software page tables change, it is +possible for stale translations to exist in this "TLB" cache. +Therefore when software page table changes occur, the kernel will +invoke one of the following flush methods _after_ the page table +changes occur: + +1) void flush_tlb_all(void) + + The most severe flush of all. After this interface runs, + any previous page table modification whatsoever will be + visible to the cpu. + + This is usually invoked when the kernel page tables are + changed, since such translations are "global" in nature. + +2) void flush_tlb_mm(struct mm_struct *mm) + + This interface flushes an entire user address space from + the TLB. After running, this interface must make sure that + any previous page table modifications for the address space + 'mm' will be visible to the cpu. That is, after running, + there will be no entries in the TLB for 'mm'. + + This interface is used to handle whole address space + page table operations such as what happens during + fork, exit, and exec. + +3) void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) + + Here we are flushing a specific range of (user) virtual + address translations from the TLB. After running, this + interface must make sure that any previous page table + modifications for the address space 'mm' in the range 'start' + to 'end' will be visible to the cpu. That is, after running, + there will be no entries in the TLB for 'mm' for virtual + addresses in the range 'start' to 'end'. + + Primarily, this is used for munmap() type operations. + + The interface is provided in hopes that the port can find + a suitably efficient method for removing multiple page + sized translations from the TLB, instead of having the kernel + call flush_tlb_page (see below) for each entry which may be + modified. + +4) void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) + + This time we need to remove the PAGE_SIZE sized translation + from the TLB. The 'vma' is the backing structure used by + Linux to keep track of mmap'd regions for a process, the + address space is available via vma->vm_mm. Also, one may + test (vma->vm_flags & VM_EXEC) to see if this region is + executable (and thus could be in the 'instruction TLB' in + split-tlb type setups). + + After running, this interface must make sure that any previous + page table modification for address space 'vma->vm_mm' for + user virtual address 'page' will be visible to the cpu. That + is, after running, there will be no entries in the TLB for + 'vma->vm_mm' for virtual address 'page'. + + This is used primarily during fault processing. + +5) void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) + + The software page tables for address space 'mm' for virtual + addresses in the range 'start' to 'end' are being torn down. + + Some platforms cache the lowest level of the software page tables + in a linear virtually mapped array, to make TLB miss processing + more efficient. On such platforms, since the TLB is caching the + software page table structure, it needs to be flushed when parts + of the software page table tree are unlinked/freed. + + Sparc64 is one example of a platform which does this. + + Usually, when munmap()'ing an area of user virtual address + space, the kernel leaves the page table parts around and just + marks the individual pte's as invalid. However, if very large + portions of the address space are unmapped, the kernel frees up + those portions of the software page tables to prevent potential + excessive kernel memory usage caused by erratic mmap/mmunmap + sequences. It is at these times that flush_tlb_pgtables will + be invoked. + +6) void update_mmu_cache(struct vm_area_struct *vma, + unsigned long address, pte_t pte) + + At the end of every page fault, this routine is invoked to + tell the architecture specific code that a translation + described by "pte" now exists at virtual address "address" + for address space "vma->vm_mm", in the software page tables. + + A port may use this information in any way it so chooses. + For example, it could use this event to pre-load TLB + translations for software managed TLB configurations. + The sparc64 port currently does this. + +Next, we have the cache flushing interfaces. In general, when Linux +is changing an existing virtual-->physical mapping to a new value, +the sequence will be in one of the following forms: + + 1) flush_cache_mm(mm); + change_all_page_tables_of(mm); + flush_tlb_mm(mm); + + 2) flush_cache_range(mm, start, end); + change_range_of_page_tables(mm, start, end); + flush_tlb_range(mm, start, end); + + 3) flush_cache_page(vma, page); + set_pte(pte_pointer, new_pte_val); + flush_tlb_page(vma, page); + +The cache level flush will always be first, because this allows +us to properly handle systems whose caches are strict and require +a virtual-->physical translation to exist for a virtual address +when that virtual address is flushed from the cache. The HyperSparc +cpu is one such cpu with this attribute. + +The cache flushing routines below need only deal with cache flushing +to the extent that it is necessary for a particular cpu. Mostly, +these routines must be implemented for cpus which have virtually +indexed caches which must be flushed when virtual-->physical +translations are changed or removed. So, for example, the physically +indexed physically tagged caches of IA32 processors have no need to +implement these interfaces since the caches are fully synchronized +and have no dependency on translation information. + +Here are the routines, one by one: + +1) void flush_cache_all(void) + + The most severe flush of all. After this interface runs, + the entire cpu cache is flushed. + + This is usually invoked when the kernel page tables are + changed, since such translations are "global" in nature. + +2) void flush_cache_mm(struct mm_struct *mm) + + This interface flushes an entire user address space from + the caches. That is, after running, there will be no cache + lines assosciated with 'mm'. + + This interface is used to handle whole address space + page table operations such as what happens during + fork, exit, and exec. + +3) void flush_cache_range(struct mm_struct *mm, + unsigned long start, unsigned long end) + + Here we are flushing a specific range of (user) virtual + addresses from the cache. After running, there will be no + entries in the cache for 'mm' for virtual addresses in the + range 'start' to 'end'. + + Primarily, this is used for munmap() type operations. + + The interface is provided in hopes that the port can find + a suitably efficient method for removing multiple page + sized regions from the cache, instead of having the kernel + call flush_cache_page (see below) for each entry which may be + modified. + +4) void flush_cache_page(struct vm_area_struct *vma, unsigned long page) + + This time we need to remove a PAGE_SIZE sized range + from the cache. The 'vma' is the backing structure used by + Linux to keep track of mmap'd regions for a process, the + address space is available via vma->vm_mm. Also, one may + test (vma->vm_flags & VM_EXEC) to see if this region is + executable (and thus could be in the 'instruction cache' in + "Harvard" type cache layouts). + + After running, there will be no entries in the cache for + 'vma->vm_mm' for virtual address 'page'. + + This is used primarily during fault processing. + +There exists another whole class of cpu cache issues which currently +require a whole different set of interfaces to handle properly. +The biggest problem is that of virtual aliasing in the data cache +of a processor. + +Is your port subsceptible to virtual aliasing in it's D-cache? +Well, if your D-cache is virtually indexed, is larger in size than +PAGE_SIZE, and does not prevent multiple cache lines for the same +physical address from existing at once, you have this problem. + +If your D-cache has this problem, first define asm/shmparam.h SHMLBA +properly, it should essentially be the size of your virtually +addressed D-cache (or if the size is variable, the largest possible +size). This setting will force the SYSv IPC layer to only allow user +processes to mmap shared memory at address which are a multiple of +this value. + +Next, you have two methods to solve the D-cache aliasing issue for all +other cases. Please keep in mind that fact that, for a given page +mapped into some user address space, there is always at least one more +mapping, that of the kernel in it's linear mapping starting at +PAGE_OFFSET. So immediately, once the first user maps a given +physical page into it's address space, by implication the D-cache +aliasing problem has the potential to exist since the kernel already +maps this page at it's virtual address. + +First, I describe the old method to deal with this problem. I am +describing it for documentation purposes, but it is deprecated and the +latter method I describe next should be used by all new ports and all +existing ports should move over to the new mechanism as well. + + flush_page_to_ram(struct page *page) + + The physical page 'page' is about to be place into the + user address space of a process. If it is possible for + stores done recently by the kernel into this physical + page, to not be visible to an arbitray mapping in userspace, + you must flush this page from the D-cache. + + If the D-cache is writeback in nature, the dirty data (if + any) for this physical page must be written back to main + memory before the cache lines are invalidated. + +Admittedly, the author did not think very much when designing this +interface. It does not give the architecture enough information about +what exactly is going on, and there is not context with which to base +any judgment about whether an alias is possible at all. The new +interfaces to deal with D-cache aliasing are meant to address this by +telling the architecture specific code exactly which is going on at +the proper points in time. + +Here is the new interface: + + void copy_user_page(void *from, void *to, unsigned long address) + void clear_user_page(void *to, unsigned long address) + + These two routines store data in user anonymous or COW + pages. It allows a port to efficiently avoid D-cache alias + issues between userspace and the kernel. + + For example, a port may temporarily map 'from' and 'to' to + kernel virtual addresses during the copy. The virtual address + for these two pages is choosen in such a way that the kernel + load/store instructions happen to virtual addresses which are + of the same "color" as the user mapping of the page. Sparc64 + for example, uses this technique. + + The "address" parameter tells the virtual address where the + user has this page mapped. + + If D-cache aliasing is not an issue, these two routines may + simply call memcpy/memset directly and do nothing more. + + void flush_dcache_page(struct page *page) + + Any time the kernel writes to a page cache page, _OR_ + the kernel is about to read from a page cache page and + user space shared/writable mappings of this page potentially + exist, this routine is called. + + The phrase "kernel writes to a page cache page" means, + specifically, that the kernel executes store instructions + that dirty data in that page at the page->virtual mapping + of that page. It is important to flush here to handle + D-cache aliasing, to make sure these kernel stores are + visible to user space mappings of that page. + + The corollary case is just as important, if there are users + which have shared+writable mappings of this file, we must make + sure that kernel reads of these pages will see the most recent + stores done by the user. + + If D-cache aliasing is not an issue, this routine may + simply be defined as a nop on that architecture. + + TODO: If we set aside a few bits in page->flags as + "architecture private", these interfaces could + be implemented much more efficiently. This would + allow one to "defer" (perhaps indefinitely) the + actual flush if there are currently no user processes + mapping this page. + + The idea is, first at flush_dcache_page() time, if + page->mapping->i_mmap is an empty list, just mark + one of the architecture private page flag bits. + Later, in update_mmu_cache(), a check could be made + of this flag bit, and if set the flush is done + and the flag bit is cleared. + +XXX Not documented: flush_icache_page(), need to talk to Paul + Mackerras, David Mosberger-Tang, et al. + to see what the expected semantics of this + interface are. -DaveM diff -u --recursive --new-file v2.4.0-test7/linux/Documentation/digiboard.txt linux/Documentation/digiboard.txt --- v2.4.0-test7/linux/Documentation/digiboard.txt Wed Aug 23 18:36:35 2000 +++ linux/Documentation/digiboard.txt Mon Aug 28 21:23:02 2000 @@ -8,11 +8,6 @@ switches) You can use up to 4 cards with this driver and it should work on other architectures than intel also. -In case you have problems with this version (1.6.1) of this driver, please -email directly to me as I made the last update. It you have a report about -running it on other architectures than intel, email me, so I can document -it here. - A version of this driver has been taken by Digiboard to make a driver software package which supports also PC/Xem cards and newer PCI cards but it doesn't support the old PC/Xi cards and it isn't yet ported to @@ -154,21 +149,11 @@ ---------------------- Please contact digi directly digilnux@dgii.com. Forward any information of -general interest to me. +general interest to me so that I can include it on the webpage. -Web page (mainly of historical interest): http://lameter.com/digi +Web page: http://lameter.com/digi Christoph Lameter (christoph@lameter.com) Aug 14, 2000. - -Supporting Tools ----------------- - -Some (old) tools and more detailed information can be found at -ftp://lameter.com/digi - -The "ditty" tool described in the Digiboard Manuals for other Unixes -is also available. - Device file creation -------------------- diff -u --recursive --new-file v2.4.0-test7/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt --- v2.4.0-test7/linux/Documentation/kernel-parameters.txt Wed Aug 9 19:19:49 2000 +++ linux/Documentation/kernel-parameters.txt Tue Sep 5 13:51:14 2000 @@ -516,6 +516,8 @@ stram_swap= [HW] + swiotlb= [IA-64] Number of I/O TLB slabs. + switches= [HW, M68K] sym53c416= [HW,SCSI] diff -u --recursive --new-file v2.4.0-test7/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.0-test7/linux/MAINTAINERS Wed Aug 23 18:36:36 2000 +++ linux/MAINTAINERS Tue Sep 5 13:46:15 2000 @@ -540,7 +540,7 @@ IDE/ATAPI CDROM DRIVER P: Jens Axboe -M: axboe@image.dk +M: axboe@suse.de L: linux-kernel@vger.kernel.org W: http://www.kernel.dk S: Maintained @@ -655,10 +655,12 @@ S: Maintained KERNEL NFSD -P: G. Allen Morris III -M: gam3@acm.org +P: Neil Brown +M: neilb@cse.unsw.edu.au L: nfs-devel@linux.kernel.org (Linux NFS) -W: http://csua.berkeley.edu/~gam3/knfsd +L: nfs@lists.sourceforge.net +W: http://nfs.sourceforge.net/ +W: http://www.cse.unsw.edu.au/~neilb/oss/knfsd/ S: Maintained LANMEDIA WAN CARD DRIVER @@ -894,7 +896,7 @@ P: David Hinds M: dhinds@zen.stanford.edu L: linux-kernel@vger.kernel.org -W: http://pcmcia.sourceforge.org +W: http://pcmcia-cs.sourceforge.net S: Maintained PCNET32 NETWORK DRIVER @@ -986,7 +988,7 @@ SCSI CDROM DRIVER P: Jens Axboe -M: axboe@image.dk +M: axboe@suse.de L: linux-scsi@vger.kernel.org W: http://www.kernel.dk S: Maintained @@ -1174,7 +1176,7 @@ UNIFORM CDROM DRIVER P: Jens Axboe -M: axboe@image.dk +M: axboe@suse.de L: linux-kernel@vger.kernel.org W: http://www.kernel.dk S: Maintained diff -u --recursive --new-file v2.4.0-test7/linux/Makefile linux/Makefile --- v2.4.0-test7/linux/Makefile Wed Aug 23 18:36:36 2000 +++ linux/Makefile Wed Aug 23 18:36:46 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -test7 +EXTRAVERSION = -test8 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -u --recursive --new-file v2.4.0-test7/linux/arch/alpha/Makefile linux/arch/alpha/Makefile --- v2.4.0-test7/linux/arch/alpha/Makefile Mon Jul 10 16:47:18 2000 +++ linux/arch/alpha/Makefile Mon Aug 28 21:21:57 2000 @@ -23,6 +23,8 @@ have_mcpu_ev6 := $(shell if $(CC) -mcpu=ev6 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) +have_mcpu_ev67 := $(shell if $(CC) -mcpu=ev67 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) + # Turn on the proper cpu optimizations. ifeq ($(have_mcpu),y) # If GENERIC, make sure to turn off any instruction set extensions that diff -u --recursive --new-file v2.4.0-test7/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- v2.4.0-test7/linux/arch/alpha/kernel/core_cia.c Thu Jul 27 17:37:59 2000 +++ linux/arch/alpha/kernel/core_cia.c Mon Aug 28 21:21:57 2000 @@ -754,6 +754,364 @@ *(vip)CIA_IOC_CIA_ERR; /* re-read to force write. */ } +static void +cia_decode_pci_error(struct el_CIA_sysdata_mcheck *cia, const char *msg) +{ + static const char * const pci_cmd_desc[16] = { + "Interrupt Acknowledge", "Special Cycle", "I/O Read", + "I/O Write", "Reserved 0x4", "Reserved 0x5", "Memory Read", + "Memory Write", "Reserved 0x8", "Reserved 0x9", + "Configuration Read", "Configuration Write", + "Memory Read Multiple", "Dual Address Cycle", + "Memory Read Line", "Memory Write and Invalidate" + }; + + if (cia->cia_err & (CIA_ERR_COR_ERR + | CIA_ERR_UN_COR_ERR + | CIA_ERR_MEM_NEM + | CIA_ERR_PA_PTE_INV)) { + static const char * const window_desc[6] = { + "No window active", "Window 0 hit", "Window 1 hit", + "Window 2 hit", "Window 3 hit", "Monster window hit" + }; + + const char *window; + const char *cmd; + unsigned long addr, tmp; + int lock, dac; + + cmd = pci_cmd_desc[cia->pci_err0 & 0x7]; + lock = (cia->pci_err0 >> 4) & 1; + dac = (cia->pci_err0 >> 5) & 1; + + tmp = (cia->pci_err0 >> 8) & 0x1F; + tmp = ffs(tmp); + window = window_desc[tmp]; + + addr = cia->pci_err1; + if (dac) { + tmp = *(vip)CIA_IOC_PCI_W_DAC & 0xFFUL; + addr |= tmp << 32; + } + + printk(KERN_CRIT "CIA machine check: %s\n", msg); + printk(KERN_CRIT " DMA command: %s\n", cmd); + printk(KERN_CRIT " PCI address: %#010lx\n", addr); + printk(KERN_CRIT " %s, Lock: %d, DAC: %d\n", + window, lock, dac); + } else if (cia->cia_err & (CIA_ERR_PERR + | CIA_ERR_PCI_ADDR_PE + | CIA_ERR_RCVD_MAS_ABT + | CIA_ERR_RCVD_TAR_ABT + | CIA_ERR_IOA_TIMEOUT)) { + static const char * const master_st_desc[16] = { + "Idle", "Drive bus", "Address step cycle", + "Address cycle", "Data cycle", "Last read data cycle", + "Last write data cycle", "Read stop cycle", + "Write stop cycle", "Read turnaround cycle", + "Write turnaround cycle", "Reserved 0xB", + "Reserved 0xC", "Reserved 0xD", "Reserved 0xE", + "Unknown state" + }; + static const char * const target_st_desc[16] = { + "Idle", "Busy", "Read data cycle", "Write data cycle", + "Read stop cycle", "Write stop cycle", + "Read turnaround cycle", "Write turnaround cycle", + "Read wait cycle", "Write wait cycle", + "Reserved 0xA", "Reserved 0xB", "Reserved 0xC", + "Reserved 0xD", "Reserved 0xE", "Unknown state" + }; + + const char *cmd; + const char *master, *target; + unsigned long addr, tmp; + int dac; + + master = master_st_desc[(cia->pci_err0 >> 16) & 0xF]; + target = target_st_desc[(cia->pci_err0 >> 20) & 0xF]; + cmd = pci_cmd_desc[(cia->pci_err0 >> 24) & 0xF]; + dac = (cia->pci_err0 >> 28) & 1; + + addr = cia->pci_err2; + if (dac) { + tmp = *(volatile int *)CIA_IOC_PCI_W_DAC & 0xFFUL; + addr |= tmp << 32; + } + + printk(KERN_CRIT "CIA machine check: %s\n", msg); + printk(KERN_CRIT " PCI command: %s\n", cmd); + printk(KERN_CRIT " Master state: %s, Target state: %s\n", + master, target); + printk(KERN_CRIT " PCI address: %#010lx, DAC: %d\n", + addr, dac); + } else { + printk(KERN_CRIT "CIA machine check: %s\n", msg); + printk(KERN_CRIT " Unknown PCI error\n"); + printk(KERN_CRIT " PCI_ERR0 = %#08lx", cia->pci_err0); + printk(KERN_CRIT " PCI_ERR1 = %#08lx", cia->pci_err1); + printk(KERN_CRIT " PCI_ERR2 = %#08lx", cia->pci_err2); + } +} + +static void +cia_decode_mem_error(struct el_CIA_sysdata_mcheck *cia, const char *msg) +{ + unsigned long mem_port_addr; + unsigned long mem_port_mask; + const char *mem_port_cmd; + const char *seq_state; + const char *set_select; + unsigned long tmp; + + /* If this is a DMA command, also decode the PCI bits. */ + if ((cia->mem_err1 >> 20) & 1) + cia_decode_pci_error(cia, msg); + else + printk(KERN_CRIT "CIA machine check: %s\n", msg); + + mem_port_addr = cia->mem_err0 & 0xfffffff0; + mem_port_addr |= (cia->mem_err1 & 0x83UL) << 32; + + mem_port_mask = (cia->mem_err1 >> 12) & 0xF; + + tmp = (cia->mem_err1 >> 8) & 0xF; + tmp |= ((cia->mem_err1 >> 20) & 1) << 4; + if ((tmp & 0x1E) == 0x06) + mem_port_cmd = "WRITE BLOCK or WRITE BLOCK LOCK"; + else if ((tmp & 0x1C) == 0x08) + mem_port_cmd = "READ MISS or READ MISS MODIFY"; + else if (tmp == 0x1C) + mem_port_cmd = "BC VICTIM"; + else if ((tmp & 0x1E) == 0x0E) + mem_port_cmd = "READ MISS MODIFY"; + else if ((tmp & 0x1C) == 0x18) + mem_port_cmd = "DMA READ or DMA READ MODIFY"; + else if ((tmp & 0x1E) == 0x12) + mem_port_cmd = "DMA WRITE"; + else + mem_port_cmd = "Unknown"; + + tmp = (cia->mem_err1 >> 16) & 0xF; + switch (tmp) { + case 0x0: + seq_state = "Idle"; + break; + case 0x1: + seq_state = "DMA READ or DMA WRITE"; + break; + case 0x2: case 0x3: + seq_state = "READ MISS (or READ MISS MODIFY) with victim"; + break; + case 0x4: case 0x5: case 0x6: + seq_state = "READ MISS (or READ MISS MODIFY) with no victim"; + break; + case 0x8: case 0x9: case 0xB: + seq_state = "Refresh"; + break; + case 0xC: + seq_state = "Idle, waiting for DMA pending read"; + break; + case 0xE: case 0xF: + seq_state = "Idle, ras precharge"; + break; + default: + seq_state = "Unknown"; + break; + } + + tmp = (cia->mem_err1 >> 24) & 0x1F; + switch (tmp) { + case 0x00: set_select = "Set 0 selected"; break; + case 0x01: set_select = "Set 1 selected"; break; + case 0x02: set_select = "Set 2 selected"; break; + case 0x03: set_select = "Set 3 selected"; break; + case 0x04: set_select = "Set 4 selected"; break; + case 0x05: set_select = "Set 5 selected"; break; + case 0x06: set_select = "Set 6 selected"; break; + case 0x07: set_select = "Set 7 selected"; break; + case 0x08: set_select = "Set 8 selected"; break; + case 0x09: set_select = "Set 9 selected"; break; + case 0x0A: set_select = "Set A selected"; break; + case 0x0B: set_select = "Set B selected"; break; + case 0x0C: set_select = "Set C selected"; break; + case 0x0D: set_select = "Set D selected"; break; + case 0x0E: set_select = "Set E selected"; break; + case 0x0F: set_select = "Set F selected"; break; + case 0x10: set_select = "No set selected"; break; + case 0x1F: set_select = "Refresh cycle"; break; + default: set_select = "Unknown"; break; + } + + printk(KERN_CRIT " Memory port command: %s\n", mem_port_cmd); + printk(KERN_CRIT " Memory port address: %#010lx, mask: %#lx\n", + mem_port_addr, mem_port_mask); + printk(KERN_CRIT " Memory sequencer state: %s\n", seq_state); + printk(KERN_CRIT " Memory set: %s\n", set_select); +} + +static void +cia_decode_ecc_error(struct el_CIA_sysdata_mcheck *cia, const char *msg) +{ + long syn; + long i; + const char *fmt; + + cia_decode_mem_error(cia, msg); + + syn = cia->cia_syn & 0xff; + if (syn == (syn & -syn)) { + fmt = KERN_CRIT " ECC syndrome %#x -- check bit %d\n"; + i = ffs(syn) - 1; + } else { + static unsigned char const data_bit[64] = { + 0xCE, 0xCB, 0xD3, 0xD5, + 0xD6, 0xD9, 0xDA, 0xDC, + 0x23, 0x25, 0x26, 0x29, + 0x2A, 0x2C, 0x31, 0x34, + 0x0E, 0x0B, 0x13, 0x15, + 0x16, 0x19, 0x1A, 0x1C, + 0xE3, 0xE5, 0xE6, 0xE9, + 0xEA, 0xEC, 0xF1, 0xF4, + 0x4F, 0x4A, 0x52, 0x54, + 0x57, 0x58, 0x5B, 0x5D, + 0xA2, 0xA4, 0xA7, 0xA8, + 0xAB, 0xAD, 0xB0, 0xB5, + 0x8F, 0x8A, 0x92, 0x94, + 0x97, 0x98, 0x9B, 0x9D, + 0x62, 0x64, 0x67, 0x68, + 0x6B, 0x6D, 0x70, 0x75 + }; + + for (i = 0; i < 64; ++i) + if (data_bit[i] == syn) + break; + + if (i < 64) + fmt = KERN_CRIT " ECC syndrome %#x -- data bit %d\n"; + else + fmt = KERN_CRIT " ECC syndrome %#x -- unknown bit\n"; + } + + printk (fmt, syn, i); +} + +static void +cia_decode_parity_error(struct el_CIA_sysdata_mcheck *cia) +{ + static const char * const cmd_desc[16] = { + "NOP", "LOCK", "FETCH", "FETCH_M", "MEMORY BARRIER", + "SET DIRTY", "WRITE BLOCK", "WRITE BLOCK LOCK", + "READ MISS0", "READ MISS1", "READ MISS MOD0", + "READ MISS MOD1", "BCACHE VICTIM", "Spare", + "READ MISS MOD STC0", "READ MISS MOD STC1" + }; + + unsigned long addr; + unsigned long mask; + const char *cmd; + int par; + + addr = cia->cpu_err0 & 0xfffffff0; + addr |= (cia->cpu_err1 & 0x83UL) << 32; + cmd = cmd_desc[(cia->cpu_err1 >> 8) & 0xF]; + mask = (cia->cpu_err1 >> 12) & 0xF; + par = (cia->cpu_err1 >> 21) & 1; + + printk(KERN_CRIT "CIA machine check: System bus parity error\n"); + printk(KERN_CRIT " Command: %s, Parity bit: %d\n", cmd, par); + printk(KERN_CRIT " Address: %#010lx, Mask: %#lx\n", addr, mask); +} + +static int +cia_decode_mchk(unsigned long la_ptr) +{ + struct el_common *com; + struct el_CIA_sysdata_mcheck *cia; + int which; + + com = (void *)la_ptr; + cia = (void *)(la_ptr + com->sys_offset); + + if ((cia->cia_err & CIA_ERR_VALID) == 0) + return 0; + + which = cia->cia_err & 0xfff; + switch (ffs(which) - 1) { + case 0: /* CIA_ERR_COR_ERR */ + cia_decode_ecc_error(cia, "Corrected ECC error"); + break; + case 1: /* CIA_ERR_UN_COR_ERR */ + cia_decode_ecc_error(cia, "Uncorrected ECC error"); + break; + case 2: /* CIA_ERR_CPU_PE */ + cia_decode_parity_error(cia); + break; + case 3: /* CIA_ERR_MEM_NEM */ + cia_decode_mem_error(cia, "Access to nonexistent memory"); + break; + case 4: /* CIA_ERR_PCI_SERR */ + cia_decode_pci_error(cia, "PCI bus system error"); + break; + case 5: /* CIA_ERR_PERR */ + cia_decode_pci_error(cia, "PCI data parity error"); + break; + case 6: /* CIA_ERR_PCI_ADDR_PE */ + cia_decode_pci_error(cia, "PCI address parity error"); + break; + case 7: /* CIA_ERR_RCVD_MAS_ABT */ + cia_decode_pci_error(cia, "PCI master abort"); + break; + case 8: /* CIA_ERR_RCVD_TAR_ABT */ + cia_decode_pci_error(cia, "PCI target abort"); + break; + case 9: /* CIA_ERR_PA_PTE_INV */ + cia_decode_pci_error(cia, "PCI invalid PTE"); + break; + case 10: /* CIA_ERR_FROM_WRT_ERR */ + cia_decode_mem_error(cia, "Write to flash ROM attempted"); + break; + case 11: /* CIA_ERR_IOA_TIMEOUT */ + cia_decode_pci_error(cia, "I/O timeout"); + break; + } + + if (cia->cia_err & CIA_ERR_LOST_CORR_ERR) + printk(KERN_CRIT "CIA lost machine check: " + "Correctable ECC error\n"); + if (cia->cia_err & CIA_ERR_LOST_UN_CORR_ERR) + printk(KERN_CRIT "CIA lost machine check: " + "Uncorrectable ECC error\n"); + if (cia->cia_err & CIA_ERR_LOST_CPU_PE) + printk(KERN_CRIT "CIA lost machine check: " + "System bus parity error\n"); + if (cia->cia_err & CIA_ERR_LOST_MEM_NEM) + printk(KERN_CRIT "CIA lost machine check: " + "Access to nonexistent memory\n"); + if (cia->cia_err & CIA_ERR_LOST_PERR) + printk(KERN_CRIT "CIA lost machine check: " + "PCI data parity error\n"); + if (cia->cia_err & CIA_ERR_LOST_PCI_ADDR_PE) + printk(KERN_CRIT "CIA lost machine check: " + "PCI address parity error\n"); + if (cia->cia_err & CIA_ERR_LOST_RCVD_MAS_ABT) + printk(KERN_CRIT "CIA lost machine check: " + "PCI master abort\n"); + if (cia->cia_err & CIA_ERR_LOST_RCVD_TAR_ABT) + printk(KERN_CRIT "CIA lost machine check: " + "PCI target abort\n"); + if (cia->cia_err & CIA_ERR_LOST_PA_PTE_INV) + printk(KERN_CRIT "CIA lost machine check: " + "PCI invalid PTE\n"); + if (cia->cia_err & CIA_ERR_LOST_FROM_WRT_ERR) + printk(KERN_CRIT "CIA lost machine check: " + "Write to flash ROM attempted\n"); + if (cia->cia_err & CIA_ERR_LOST_IOA_TIMEOUT) + printk(KERN_CRIT "CIA lost machine check: " + "I/O timeout\n"); + + return 1; +} + void cia_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) @@ -769,30 +1127,7 @@ mb(); expected = mcheck_expected(0); - if (!expected && vector == 0x660) { - struct el_common *com; - struct el_common_EV5_uncorrectable_mcheck *ev5; - struct el_CIA_sysdata_mcheck *cia; - - com = (void *)la_ptr; - ev5 = (void *)(la_ptr + com->proc_offset); - cia = (void *)(la_ptr + com->sys_offset); - - if (com->code == 0x202) { - printk(KERN_CRIT "CIA PCI machine check: code=%x\n" - " cpu_err0=%08x cpu_err1=%08x cia_err=%08x\n" - " cia_stat=%08x err_mask=%08x cia_syn=%08x\n" - " mem_err0=%08x mem_err1=%08x\n" - " pci_err0=%08x pci_err1=%08x pci_err2=%08x\n", - (int) com->code, - (int) cia->cpu_err0, (int) cia->cpu_err1, - (int) cia->cia_err, (int) cia->cia_stat, - (int) cia->err_mask, (int) cia->cia_syn, - (int) cia->mem_err0, (int) cia->mem_err1, - (int) cia->pci_err0, (int) cia->pci_err1, - (int) cia->pci_err2); - expected = 1; - } - } + if (!expected && vector == 0x660) + expected = cia_decode_mchk(la_ptr); process_mcheck_info(vector, la_ptr, regs, "CIA", expected); } diff -u --recursive --new-file v2.4.0-test7/linux/arch/alpha/kernel/core_irongate.c linux/arch/alpha/kernel/core_irongate.c --- v2.4.0-test7/linux/arch/alpha/kernel/core_irongate.c Mon Mar 27 08:08:21 2000 +++ linux/arch/alpha/kernel/core_irongate.c Mon Aug 28 21:21:57 2000 @@ -28,12 +28,7 @@ #include "proto.h" #include "pci_impl.h" - -/* - * NOTE: Herein lie back-to-back mb instructions. They are magic. - * One plausible explanation is that the I/O controller does not properly - * handle the system transaction. Another involves timing. Ho hum. - */ +#undef DEBUG_IRONGATE /* define to enable verbose Irongate debug */ /* * BIOS32-style PCI interface: @@ -200,11 +195,12 @@ write_dword: irongate_write_config_dword }; -#if 0 +#ifdef DEBUG_IRONGATE static void irongate_register_dump(const char *function_name) { printk("%s: Irongate registers:\n" + "\tFunction 0:\n" "\tdev_vendor\t0x%08x\n" "\tstat_cmd\t0x%08x\n" "\tclass\t\t0x%08x\n" @@ -249,7 +245,26 @@ "\tagpstat\t\t0x%08x\n" "\tagpcmd\t\t0x%08x\n" "\tagpva\t\t0x%08x\n" - "\tagpmode\t\t0x%08x\n", + "\tagpmode\t\t0x%08x\n" + + "\n\tFunction 1:\n" + "\tdev_vendor:\t0x%08x\n" + "\tcmd_status:\t0x%08x\n" + "\trevid_etc :\t0x%08x\n" + "\thtype_etc :\t0x%08x\n" + "\trsrvd0[0] :\t0x%08x\n" + "\trsrvd0[1] :\t0x%08x\n" + "\tbus_nmbers:\t0x%08x\n" + "\tio_baselim:\t0x%08x\n" + "\tmem_bselim:\t0x%08x\n" + "\tpf_baselib:\t0x%08x\n" + "\trsrvd1[0] :\t0x%08x\n" + "\trsrvd1[1] :\t0x%08x\n" + "\tio_baselim:\t0x%08x\n" + "\trsrvd2[0] :\t0x%08x\n" + "\trsrvd2[1] :\t0x%08x\n" + "\tinterrupt :\t0x%08x\n", + function_name, IRONGATE0->dev_vendor, IRONGATE0->stat_cmd, @@ -295,7 +310,23 @@ IRONGATE0->agpstat, IRONGATE0->agpcmd, IRONGATE0->agpva, - IRONGATE0->agpmode); + IRONGATE0->agpmode, + IRONGATE1->dev_vendor, + IRONGATE1->stat_cmd, + IRONGATE1->class, + IRONGATE1->htype, + IRONGATE1->rsrvd0[0], + IRONGATE1->rsrvd0[1], + IRONGATE1->busnos, + IRONGATE1->io_baselim_regs, + IRONGATE1->mem_baselim, + IRONGATE1->pfmem_baselim, + IRONGATE1->rsrvd1[0], + IRONGATE1->rsrvd1[1], + IRONGATE1->io_baselim, + IRONGATE1->rsrvd2[0], + IRONGATE1->rsrvd2[1], + IRONGATE1->interrupt ); } #else #define irongate_register_dump(x) diff -u --recursive --new-file v2.4.0-test7/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.4.0-test7/linux/arch/alpha/kernel/entry.S Wed Aug 23 18:36:36 2000 +++ linux/arch/alpha/kernel/entry.S Sun Sep 3 11:36:45 2000 @@ -833,7 +833,7 @@ .quad alpha_ni_syscall .quad alpha_ni_syscall /* 50 */ .quad sys_acct - .quad osf_sigpending + .quad sys_sigpending .quad alpha_ni_syscall .quad sys_ioctl .quad alpha_ni_syscall /* 55 */ diff -u --recursive --new-file v2.4.0-test7/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.4.0-test7/linux/arch/alpha/kernel/process.c Mon Jul 10 16:47:18 2000 +++ linux/arch/alpha/kernel/process.c Tue Sep 5 13:50:02 2000 @@ -276,14 +276,14 @@ { if (!usp) usp = rdusp(); - return do_fork(clone_flags, usp, (struct pt_regs *) (swstack+1)); + return do_fork(clone_flags, usp, (struct pt_regs *) (swstack+1), 0); } int alpha_vfork(struct switch_stack * swstack) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), - (struct pt_regs *) (swstack+1)); + (struct pt_regs *) (swstack+1), 0); } /* @@ -299,6 +299,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, struct task_struct * p, struct pt_regs * regs) { extern void ret_from_sys_call(void); diff -u --recursive --new-file v2.4.0-test7/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.4.0-test7/linux/arch/alpha/kernel/signal.c Fri Jun 23 21:55:07 2000 +++ linux/arch/alpha/kernel/signal.c Sun Sep 3 11:48:33 2000 @@ -170,18 +170,6 @@ return ret; } -asmlinkage int -osf_sigpending(old_sigset_t *set) -{ - sigset_t pending; - - spin_lock_irq(¤t->sigmask_lock); - sigandsets(&pending, ¤t->blocked, ¤t->signal); - spin_unlock_irq(¤t->sigmask_lock); - - return copy_to_user(set, &pending, sizeof(*set)); -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -729,7 +717,7 @@ default: lock_kernel(); - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ diff -u --recursive --new-file v2.4.0-test7/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.4.0-test7/linux/arch/alpha/kernel/smp.c Wed Aug 9 19:19:49 2000 +++ linux/arch/alpha/kernel/smp.c Tue Sep 5 13:50:02 2000 @@ -420,7 +420,7 @@ * don't care about the regs settings since * we'll never reschedule the forked task. */ - return do_fork(CLONE_VM|CLONE_PID, 0, ®s); + return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } /* diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.4.0-test7/linux/arch/arm/Makefile Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/Makefile Sun Sep 3 11:19:11 2000 @@ -32,21 +32,21 @@ GZFLAGS = -9 # Ensure this is ld "2.9.4" or later -NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi) +NEW_LINKER := $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?) -ifneq ($(NEW_LINKER),y) +ifneq ($(NEW_LINKER),0) dummy:; @echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.' @echo '*** Please upgrade your binutils to 2.9.5.' @false endif # GCC 2.7 uses different options to later compilers; sort out which we have -NEW_GCC := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi) +NEW_GCC := $(shell $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; echo $$?) # # select flags depending on the compiler # -ifeq ($(NEW_GCC),y) +ifneq ($(NEW_GCC),0) CFLAGS += -mshort-load-bytes CFLAGS_PROC_CPU_26 := -mcpu=arm3 -mapcs-26 -Os CFLAGS_PROC_CPU_32v3 := -march=armv3 @@ -54,6 +54,7 @@ CFLAGS_ARM6 := -mtune=arm6 CFLAGS_ARM7 := -mtune=arm7 CFLAGS_ARM720 := -mtune=arm7tdmi +CFLAGS_ARM920 := -mtune=arm9tdmi CFLAGS_SA110 := -mtune=strongarm110 else CFLAGS += -DNO_TEXT_SECTIONS @@ -63,6 +64,7 @@ CFLAGS_ARM6 := -m6 CFLAGS_ARM7 := -m6 CFLAGS_ARM720 := -m6 +CFLAGS_ARM920 := -m6 CFLAGS_SA110 := -m6 endif @@ -98,6 +100,9 @@ ifeq ($(CONFIG_CPU_ARM720),y) CFLAGS += $(CFLAGS_ARM720) else + ifeq ($(CONFIG_CPU_ARM920),y) + CFLAGS += $(CFLAGS_ARM920) + else ifeq ($(CONFIG_CPU_SA110),y) CFLAGS += $(CFLAGS_SA110) else @@ -108,6 +113,7 @@ endif endif endif + endif endif LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) @@ -116,51 +122,60 @@ ifeq ($(CONFIG_ARCH_ARCA5K),y) MACHINE = arc -ARCHDIR = arc endif ifeq ($(CONFIG_ARCH_RPC),y) MACHINE = rpc -ARCHDIR = rpc endif ifeq ($(CONFIG_ARCH_EBSA110),y) MACHINE = ebsa110 -ARCHDIR = ebsa110 endif ifeq ($(CONFIG_ARCH_CLPS7500),y) MACHINE = clps7500 -ARCHDIR = cl7500 +INCDIR = cl7500 endif ifeq ($(CONFIG_FOOTBRIDGE),y) MACHINE = footbridge -ARCHDIR = ebsa285 +INCDIR = ebsa285 endif ifeq ($(CONFIG_ARCH_CO285),y) TEXTADDR = 0x60008000 +MACHINE = footbridge +INCDIR = ebsa285 endif ifeq ($(CONFIG_ARCH_NEXUSPCI),y) MACHINE = nexuspci -ARCHDIR = nexuspci endif ifeq ($(CONFIG_ARCH_SHARK),y) MACHINE = shark -ARCHDIR = shark endif ifeq ($(CONFIG_ARCH_SA1100),y) MACHINE = sa1100 -ARCHDIR = sa1100 endif ifeq ($(CONFIG_ARCH_L7200),y) MACHINE = l7200 -ARCHDIR = l7200 +endif + +ifeq ($(CONFIG_ARCH_INTEGRATOR),y) +MACHINE = integrator +endif + +# Only set INCDIR if its not already defined above +INCDIR ?= $(MACHINE) + +# If we have a machine-specific directory, then include it in the build. +MACHDIR := arch/arm/mach-$(MACHINE) +ifeq ($(MACHDIR),$(wildcard $(MACHDIR))) +SUBDIRS += $(MACHDIR) +CORE_FILES := $(MACHDIR)/$(MACHINE).o $(CORE_FILES) endif HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ @@ -193,36 +208,30 @@ # to date before starting compilation $(patsubst %, _dir_%, $(SUBDIRS)) init/main.o init/version.o : \ - constants \ include/asm-arm/mach-types.h -include/asm-arm/mach-types.h: \ - arch/arm/tools/mach-types \ - arch/arm/tools/gen-mach-types +$(patsubst %, _dir_%, $(SUBDIRS)) : constants + +include/asm-arm/mach-types.h: arch/arm/tools/mach-types \ + arch/arm/tools/gen-mach-types @awk -f arch/arm/tools/gen-mach-types arch/arm/tools/mach-types > $@ -constants: $(TOPDIR)/include/asm-arm/proc-fns.h dummy +constants: dummy @$(MAKE) -C arch/arm/lib constants.h symlinks: archsymlinks archsymlinks: $(RM) include/asm-arm/arch include/asm-arm/proc - (cd include/asm-arm; ln -sf arch-$(ARCHDIR) arch; ln -sf proc-$(PROCESSOR) proc) + (cd include/asm-arm; ln -sf arch-$(INCDIR) arch; ln -sf proc-$(PROCESSOR) proc) vmlinux: arch/arm/vmlinux.lds arch/arm/vmlinux.lds: arch/arm/vmlinux-$(PROCESSOR).lds.in dummy @sed 's/TEXTADDR/$(TEXTADDR)/' <$< >$@ -arch/arm/kernel: dummy - $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel - -arch/arm/mm: dummy - $(MAKE) linuxsubdirs SUBDIRS=arch/arm/mm - -arch/arm/lib: dummy - $(MAKE) linuxsubdirs SUBDIRS=arch/arm/lib +arch/arm/kernel arch/arm/mm arch/arm/lib: dummy + $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) bzImage zImage zinstall Image bootpImage install: vmlinux @$(MAKEBOOT) $@ @@ -235,7 +244,7 @@ $(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds $(RM) include/asm-arm/mach-types.h -archdep: symlinks +archdep: archsymlinks @$(MAKEBOOT) dep # My testing targets (that short circuit a few dependencies) @@ -252,7 +261,7 @@ brutus_config victor_config \ empeg_config thinclient_config \ assabet_config lart_config \ - cerf_config + cerf_config lusl7200_config $(CFGS): @( \ @@ -266,7 +275,3 @@ echo "$$CFG does not exist"; \ fi; \ ) - -l7200_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/lusl7200 arch/arm/defconfig diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile --- v2.4.0-test7/linux/arch/arm/boot/Makefile Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/boot/Makefile Sun Sep 3 11:19:11 2000 @@ -105,10 +105,10 @@ @test "$(INITRD)" != "" || (echo You must specify INITRD; exit -1) install: $(CONFIGURE) Image - sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" + sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" zinstall: $(CONFIGURE) zImage - sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" + sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" clean: $(RM) Image zImage bootpImage diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/boot/bootp/Makefile linux/arch/arm/boot/bootp/Makefile --- v2.4.0-test7/linux/arch/arm/boot/bootp/Makefile Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/boot/bootp/Makefile Sun Sep 3 11:19:11 2000 @@ -23,4 +23,4 @@ .PHONY: $(INITRD) $(ZSYSTEM) -clean:; $(RM) bootp bootp.lds +clean:; $(RM) bootp diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/boot/bootp/bootp.lds linux/arch/arm/boot/bootp/bootp.lds --- v2.4.0-test7/linux/arch/arm/boot/bootp/bootp.lds Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/bootp/bootp.lds Sun Sep 3 11:19:11 2000 @@ -0,0 +1,30 @@ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0; + _text = .; + .text : { + _stext = .; + _start = .; + init.o(.start) + kernel_start = .; + kernel.o + kernel_len = . - kernel_start; + . = ALIGN(32); + *(.text) + initrd_start = .; + initrd.o + initrd_len = . - initrd_start; + . = ALIGN(32); + _etext = .; + } + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/boot/compressed/head-ftvpci.S linux/arch/arm/boot/compressed/head-ftvpci.S --- v2.4.0-test7/linux/arch/arm/boot/compressed/head-ftvpci.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/head-ftvpci.S Sun Sep 3 11:19:11 2000 @@ -0,0 +1,40 @@ +/* + * linux/arch/arm/boot/compressed/head-ftvpci.S + * + * Copyright (C) 2000 FutureTV Labs Ltd. + * + * Special startup code for FTV PCI board. + */ + + .section ".start", #alloc, #execinstr +ftv_start: + mcr p15, 0, r0, c7, c5, 0 @ flush I cache + mrc p15, 0, r0, c1, c0 + orr r0, r0, #1 << 12 + mcr p15, 0, r0, c1, c0 @ enable I cache + mov r0, #0 + mcreq p15, 0, r0, c15, c1, 2 @ enable clock switching + + /* check to see if the kernel must be relocated */ + ldr ip, =ftv_start + adr sl, ftv_start + teq ip, sl + beq 2f @ no need to copy + + /* in the wrong place -> presumably, executing out of ROM */ + sub ip, ip, sl @ displacement + ldr lr, =_start @ destination + sub sp, lr, ip @ source + ldr fp, =_edata @ end of copied area +1: ldmia sp!, {r0, r1, r2, r3, r4, r5, r6, r10} + stmia lr!, {r0, r1, r2, r3, r4, r5, r6, r10} + cmp lr, fp + ble 1b + +2: + mov r8, #0 + mov r7, #3 + b 1f +.ltorg +1: + /* fall back into head.S */ diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/boot/compressed/head-nexuspci.S linux/arch/arm/boot/compressed/head-nexuspci.S --- v2.4.0-test7/linux/arch/arm/boot/compressed/head-nexuspci.S Sat Jul 18 11:55:22 1998 +++ linux/arch/arm/boot/compressed/head-nexuspci.S Wed Dec 31 16:00:00 1969 @@ -1,101 +0,0 @@ -/* - * linux/arch/arm/boot/compressed/head-nexuspci.S - * - * Copyright (C) 1996, 1997, 1998 Philip Blundell - * - * NexusPCI is unusual because we don't have a bootloader -- the kernel is - * run directly out of ROM at the moment. Maybe this will change one day and - * then this file can go away. - * - */ - - .text - -.globl _start -_start: b reset - b undefined - b undefined - b undefined - b undefined - b undefined - b undefined - b undefined - b go_uncompress - -reset: mov r2, #0x20000000 @ LED off - mov r1, #0x1a - str r1, [r2] - - mov r2, #0x10000000 @ SCC init - - mov r1, #42 - strb r1, [r2, #8] - - mov r1, #48 - strb r1, [r2, #8] - - mov r1, #16 - strb r1, [r2, #8] - - mov r1, #0x93 - strb r1, [r2, #0] - mov r1, #0x17 - strb r1, [r2, #0] - - mov r1, #0xbb - strb r1, [r2, #0x4] - - mov r1, #0x78 - strb r1, [r2, #0x10] - - mov r1, #160 - strb r1, [r2, #0x8] - - mov r1, #5 - strb r1, [r2, #0x8] - - ldr r2, =_start - ldr r3, =_edata - mov r8, r2 - mov r0, #0 -1: - ldmia r0!, {r4, r5, r6, r7} - stmia r2!, {r4, r5, r6, r7} - cmp r2, r3 - ble 1b - - ldr r3, =_edata - ldr r1, =_end - mov r2, #0 -1: - strb r2, [r3] - cmp r3, r1 - beq 2f - add r3, r3, #1 - b 1b -2: - add pc, r8, #0x20 - -undefined: ldr r4, =undef_msg -1: ldrb r0, [r4], #1 - movs r0, r0 -2: beq 2b - bl _ll_write_char - b 1b - -undef_msg: .ascii "Undefined instruction (or other problem)\000" - .align 4 - -/* - * Uncompress the kernel - */ -go_uncompress: - mov r0, #0x40000000 - ldr sp, =user_stack - add sp, sp, #4096 - bl decompress_kernel - - mov r2, #0x40000000 - mov r0, #0 - mov r1, #3 - add pc, r2, #0x20 @ call via EXEC entry diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.4.0-test7/linux/arch/arm/boot/compressed/head.S Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/boot/compressed/head.S Sun Sep 3 11:19:11 2000 @@ -85,7 +85,7 @@ .word 0x016f2818 @ Magic numbers to help the loader .word start 1: mov r7, r1 @ save architecture ID - mov r8, r0 @ save r0 + mov r8, #0 @ save r0 #ifdef CONFIG_ANGELBOOT /* * Booting from Angel - need to enter SVC mode and disable @@ -198,9 +198,10 @@ 1: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer - bic r3, r3, #0x3f + bic r3, r3, #0x3f00 /* - * Initialise the page tables + * Initialise the page tables, turning on the cacheable and bufferable + * bits for the RAM area only. */ mov r0, r3 mov r8, r0, lsr #18 @@ -217,6 +218,20 @@ add r1, r1, #1048576 teq r0, r2 bne 1b +/* + * If ever we are running from Flash, then we surely want the cache + * to be enabled also for our execution instance... We map 2MB of it + * so there is no map overlap problem for up to 1 MB compressed kernel. + * If the execution is in RAM then we would only be duplicating the above. + */ + mov r1, #0x1e + orr r1, r1, #3 << 10 + mov r2, pc, lsr #20 + orr r1, r1, r2, lsl #20 + add r0, r3, r2, lsl #2 + str r1, [r0], #4 + add r1, r1, #1048576 + str r1, [r0] mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/boot/compressed/setup-sa1100.S linux/arch/arm/boot/compressed/setup-sa1100.S --- v2.4.0-test7/linux/arch/arm/boot/compressed/setup-sa1100.S Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/boot/compressed/setup-sa1100.S Sun Sep 3 11:19:11 2000 @@ -51,6 +51,12 @@ * This is called from decompress_kernel() with the arch_decomp_setup() macro. */ +/* + * void sa1100_setup( int arch_id ); + * + * This is called from decompress_kernel() with the arch_decomp_setup() macro. + */ + ENTRY(sa1100_setup) mov r3, r0 @ keep machine type in r3 @@ -138,7 +144,7 @@ @ The machine type is passed in r0 mov r0, r3 #ifdef CONFIG_SA1100_NANOENGINE - teq r0, #32 @ MACH_TYPE_NANOENGINE + teq r0, #MACH_TYPE_NANOENGINE beq SYMBOL_NAME(bse_setup) #endif diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.4.0-test7/linux/arch/arm/kernel/bios32.c Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/kernel/bios32.c Sun Sep 3 11:19:11 2000 @@ -10,16 +10,14 @@ #include #include +#include /* for BUG() */ #include #include - -#include "bios32.h" +#include static int debug_pci; int have_isa_bridge; -extern void hw_init(void); - void pcibios_report_status(u_int status_mask, int warn) { struct pci_dev *dev; @@ -157,6 +155,14 @@ } } +/* + * Put the DEC21142 to sleep + */ +static void __init pci_fixup_dec21142(struct pci_dev *dev) +{ + pci_write_config_dword(dev, 0x40, 0x80000000); +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, @@ -174,6 +180,10 @@ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases + }, { + PCI_FIXUP_HEADER, + PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, + pci_fixup_dec21142 }, { 0 } }; @@ -277,12 +287,11 @@ * SERR and PERR reporting - this chip doesn't drive the * parity line correctly. */ -#if 1 /* !testing */ if (dev->vendor == PCI_VENDOR_ID_INTERG && dev->device == PCI_DEVICE_ID_INTERG_2000) busdata->features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); -#endif + /* * Calculate the maximum devsel latency. */ @@ -319,18 +328,6 @@ u8 min_gnt, latency; /* - * architecture specific hacks. I don't really want - * this here, but I don't see any other place for it - * to live. Shame the device doesn't support - * capabilities - */ - if (machine_is_netwinder() && - dev->vendor == PCI_VENDOR_ID_DEC && - dev->device == PCI_DEVICE_ID_DEC_21142) - /* Put the chip to sleep in case the driver isn't loaded */ - pci_write_config_dword(dev, 0x40, 0x80000000); - - /* * Calculate this masters latency timer value. * This is rather primitive - it does not take * account of the number of masters in a system @@ -372,184 +369,23 @@ ranges->mem_end -= bus->resource[1]->start; } -static u8 __init no_swizzle(struct pci_dev *dev, u8 *pin) +u8 __init no_swizzle(struct pci_dev *dev, u8 *pin) { return 0; } -/* ebsa285 host-specific stuff */ - -#ifdef CONFIG_ARCH_EBSA285 -static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI }; - -static u8 __init ebsa285_swizzle(struct pci_dev *dev, u8 *pin) -{ - return PCI_SLOT(dev->devfn); -} - -static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - if (dev->vendor == PCI_VENDOR_ID_CONTAQ && - dev->device == PCI_DEVICE_ID_CONTAQ_82C693) - switch (PCI_FUNC(dev->devfn)) { - case 1: return 14; - case 2: return 15; - case 3: return 12; - } - - return irqmap_ebsa285[(slot + pin) & 3]; -} - -static struct hw_pci ebsa285_pci __initdata = { - dc21285_init, - 0x9000, - 0x00100000, - ebsa285_swizzle, - ebsa285_map_irq -}; -#endif - -#ifdef CONFIG_ARCH_CATS -/* cats host-specific stuff */ -static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; - -static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - if (dev->irq >= 128) - return dev->irq & 0x1f; - - if (dev->irq >= 1 && dev->irq <= 4) - return irqmap_cats[dev->irq - 1]; - - if (dev->irq != 0) - printk("PCI: device %02x:%02x has unknown irq line %x\n", - dev->bus->number, dev->devfn, dev->irq); - - return -1; -} - -static struct hw_pci cats_pci __initdata = { - dc21285_init, - 0x9000, - 0x00100000, - no_swizzle, - cats_map_irq -}; -#endif - -#ifdef CONFIG_ARCH_NETWINDER -/* netwinder host-specific stuff */ -static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ -#define DEV(v,d) ((v)<<16|(d)) - switch (DEV(dev->vendor, dev->device)) { - case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): - case DEV(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885): - case DEV(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_YELLOWFIN): - return IRQ_NETWINDER_ETHER100; - - case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a): - return IRQ_NETWINDER_ETHER10; - - case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553): - return 0; - - case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105): - return IRQ_ISA_HARDDISK1; - - case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): - case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010): - case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000): - return IRQ_NETWINDER_VGA; - - case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285): - return 0; - - default: - printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n", - dev->bus->number, dev->devfn, - dev->vendor, dev->device); - return 0; - } -} - -static struct hw_pci netwinder_pci __initdata = { - dc21285_init, - 0x9000, - 0x00100000, - no_swizzle, - netwinder_map_irq -}; -#endif - -#ifdef CONFIG_ARCH_PERSONAL_SERVER -static int irqmap_personal_server[] __initdata = { - IRQ_IN0, IRQ_IN1, IRQ_IN2, IRQ_IN3, 0, 0, 0, - IRQ_DOORBELLHOST, IRQ_DMA1, IRQ_DMA2, IRQ_PCI -}; - -static int __init personal_server_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - unsigned char line; - - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line); - - if (line > 0x40 && line <= 0x5f) { - /* line corresponds to the bit controlling this interrupt - * in the footbridge. Ignore the first 8 interrupt bits, - * look up the rest in the map. IN0 is bit number 8 - */ - return irqmap_personal_server[(line & 0x1f) - 8]; - } else if (line == 0) { - /* no interrupt */ - return 0; - } else - return irqmap_personal_server[(line - 1) & 3]; -} - -static struct hw_pci personal_server_pci __initdata = { - dc21285_init, - 0x9000, - 0x00100000, - no_swizzle, - personal_server_map_irq -}; - -#endif - -#ifdef CONFIG_ARCH_NEXUSPCI -/* - * Owing to a PCB cockup, issue A backplanes are wired thus: - * - * Slot 1 2 3 4 5 Bridge - * IRQ D C B A A - * A D C B B - * B A D C C - * C B A D D - * - * ID A31 A30 A29 A28 A27 A26 - */ - -static int irqmap_ftv[] __initdata = { IRQ_PCI_A, IRQ_PCI_B, IRQ_PCI_C, IRQ_PCI_D }; - -static int __init ftv_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - return irqmap_ftv[(slot + pin) & 3]; -} - -/* ftv host-specific stuff */ -static struct hw_pci ftv_pci __initdata = { - plx90x0_init, - 0x9000, - 0x00100000, - no_swizzle, - ftv_map_irq -}; -#endif +extern struct hw_pci ebsa285_pci; +extern struct hw_pci cats_pci; +extern struct hw_pci netwinder_pci; +extern struct hw_pci personal_server_pci; +extern struct hw_pci ftv_pci; +extern struct hw_pci integrator_pci; void __init pcibios_init(void) { struct hw_pci *hw_pci = NULL; + struct arm_pci_sysdata sysdata; + int i; do { #ifdef CONFIG_ARCH_EBSA285 @@ -582,15 +418,28 @@ break; } #endif - } while (0); +#ifdef CONFIG_ARCH_INTEGRATOR + if (machine_is_integrator()) { + hw_pci = &integrator_pci; + break; + } +#endif + } while (0); if (hw_pci == NULL) return; + for (i = 0; i < MAX_NR_BUS; i++) { + sysdata.bus[i].features = PCI_COMMAND_FAST_BACK | + PCI_COMMAND_SERR | + PCI_COMMAND_PARITY; + sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST; + } + /* * Set up the host bridge, and scan the bus. */ - hw_pci->init(); + hw_pci->init(&sysdata); /* * Other architectures don't seem to do this... should we? @@ -598,8 +447,7 @@ pcibios_claim_resources(); /* - * Assign any unassigned resources. Note that we really ought to - * have min/max stuff here - max mem address is 0x0fffffff + * Assign any unassigned resources. */ pci_assign_unassigned_resources(); pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq); diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/bios32.h linux/arch/arm/kernel/bios32.h --- v2.4.0-test7/linux/arch/arm/kernel/bios32.h Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/kernel/bios32.h Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -#define MAX_NR_BUS 2 - -struct arm_bus_sysdata { - /* - * bitmask of features we can turn. - * See PCI command register for more info. - */ - u16 features; - /* - * Maximum devsel for this bus. - */ - u16 maxdevsel; - /* - * The maximum latency that devices on this - * bus can withstand. - */ - u8 max_lat; -}; - -struct arm_pci_sysdata { - struct arm_bus_sysdata bus[MAX_NR_BUS]; -}; - -struct hw_pci { - void (*init)(void); - unsigned long io_start; - unsigned long mem_start; - u8 (*swizzle)(struct pci_dev *dev, u8 *pin); - int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); -}; - -void __init dc21285_init(void); -void __init plx90x0_init(void); diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.4.0-test7/linux/arch/arm/kernel/dec21285.c Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/kernel/dec21285.c Sun Sep 3 11:19:11 2000 @@ -17,7 +17,7 @@ #include #include -#include "bios32.h" +#include #define MAX_SLOTS 21 @@ -252,7 +252,7 @@ add_timer(timer); } -void __init dc21285_init(void) +void __init dc21285_init(struct arm_pci_sysdata *sysdata) { unsigned long cntl; unsigned int mem_size; @@ -279,19 +279,26 @@ "central function" : "addin"); if (cfn_mode) { - static struct resource csrmem, csrio; - struct arm_pci_sysdata sysdata; - int i; + static struct resource csrmem, csrio, busmem, busmempf; + struct pci_bus *bus; csrio.flags = IORESOURCE_IO; - csrio.name = "DC21285"; + csrio.name = "Footbridge"; csrmem.flags = IORESOURCE_MEM; - csrmem.name = "DC21285"; + csrmem.name = "Footbridge"; + busmem.flags = IORESOURCE_MEM; + busmem.name = "Footbridge non-prefetch"; + busmempf.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; + busmempf.name = "Footbridge prefetch"; allocate_resource(&ioport_resource, &csrio, 128, 0xff00, 0xffff, 128, NULL, NULL); allocate_resource(&iomem_resource, &csrmem, 128, 0xf4000000, 0xf8000000, 128, NULL, NULL); + allocate_resource(&iomem_resource, &busmempf, 0x20000000, + 0x00000000, 0x80000000, 0x20000000, NULL, NULL); + allocate_resource(&iomem_resource, &busmem, 0x40000000, + 0x00000000, 0x80000000, 0x40000000, NULL, NULL); /* * Map our SDRAM at a known address in PCI space, just in case @@ -302,24 +309,24 @@ *CSR_PCICACHELINESIZE = 0x00002008; *CSR_PCICSRBASE = csrmem.start; *CSR_PCICSRIOBASE = csrio.start; - *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); + *CSR_PCISDRAMBASE = __virt_to_bus(PAGE_OFFSET); *CSR_PCIROMBASE = 0; *CSR_PCICMD = pci_cmd | (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); - for (i = 0; i < MAX_NR_BUS; i++) { - sysdata.bus[i].features = PCI_COMMAND_FAST_BACK | - PCI_COMMAND_SERR | - PCI_COMMAND_PARITY; - sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST; - } - - pci_scan_bus(0, &dc21285_ops, &sysdata); + bus = pci_scan_bus(0, &dc21285_ops, sysdata); + /* + * bus->resource[0] is the IO resource for this bus + * bus->resource[1] is the mem resource for this bus + * bus->resource[2] is the prefetch mem resource for this bus + */ + bus->resource[1] = &busmem; + bus->resource[2] = &busmempf; - pci_cmd |= sysdata.bus[0].features; + pci_cmd |= sysdata->bus[0].features; printk("PCI: Fast back to back transfers %sabled\n", - (sysdata.bus[0].features & PCI_COMMAND_FAST_BACK) ? + (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); /* diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.4.0-test7/linux/arch/arm/kernel/ecard.c Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/kernel/ecard.c Sun Sep 3 11:52:27 2000 @@ -318,7 +318,7 @@ * We don't want /any/ signals, not even SIGKILL */ sigfillset(&tsk->blocked); - sigemptyset(&tsk->signal); + sigemptyset(&tsk->pending.signal); recalc_sigpending(tsk); strcpy(tsk->comm, "kecardd"); @@ -335,7 +335,7 @@ req = xchg(&ecard_req, NULL); if (req == NULL) { - sigemptyset(&tsk->signal); + sigemptyset(&tsk->pending.signal); interruptible_sleep_on(&ecard_wait); } } while (req == NULL); diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S --- v2.4.0-test7/linux/arch/arm/kernel/head-armo.S Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/kernel/head-armo.S Sun Sep 3 11:19:11 2000 @@ -72,6 +72,7 @@ mov pc, lr detect_proc_type: + mov ip, lr mov r2, #0xea000000 @ Point undef instr to continuation adr r0, continue - 12 orr r0, r2, r0, lsr #2 @@ -80,8 +81,9 @@ ldr r0, arm2_id swp r2, r2, [r1] @ check for swp (ARM2 can't) ldr r0, arm250_id - mrc 15, 0, r0, c0, c0 @ check for CP#15 (ARM250 can't) + mrc 15, 0, r3, c0, c0 @ check for CP#15 (ARM250 can't) + mov r0, r3 continue: mov r2, #0xeb000000 @ Make undef vector loop sub r2, r2, #2 str r2, [r1, #4] - mov pc, lr + mov pc, ip diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.4.0-test7/linux/arch/arm/kernel/process.c Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/kernel/process.c Tue Sep 5 13:50:01 2000 @@ -280,8 +280,8 @@ void flush_thread(void) { - memset(¤t->thread.debug, 0, sizeof(current->thread.debug)); - memset(¤t->thread.fpstate, 0, sizeof(current->thread.fpstate)); + memset(¤t->thread.debug, 0, sizeof(struct debug_info)); + memset(¤t->thread.fpstate, 0, sizeof(union fp_state)); current->used_math = 0; current->flags &= ~PF_USEDFPU; } @@ -291,6 +291,7 @@ } int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, + unsigned long unused, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; @@ -326,19 +327,21 @@ */ void dump_thread(struct pt_regs * regs, struct user * dump) { + struct task_struct *tsk = current; + dump->magic = CMAGIC; - dump->start_code = current->mm->start_code; + dump->start_code = tsk->mm->start_code; dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1); - dump->u_tsize = (current->mm->end_code - current->mm->start_code) >> PAGE_SHIFT; - dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT; + dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT; + dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT; dump->u_ssize = 0; - dump->u_debugreg[0] = current->thread.debug.bp[0].address; - dump->u_debugreg[1] = current->thread.debug.bp[1].address; - dump->u_debugreg[2] = current->thread.debug.bp[0].insn; - dump->u_debugreg[3] = current->thread.debug.bp[1].insn; - dump->u_debugreg[4] = current->thread.debug.nsaved; + dump->u_debugreg[0] = tsk->thread.debug.bp[0].address; + dump->u_debugreg[1] = tsk->thread.debug.bp[1].address; + dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn; + dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn; + dump->u_debugreg[4] = tsk->thread.debug.nsaved; if (dump->start_stack < 0x04000000) dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT; diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.4.0-test7/linux/arch/arm/kernel/ptrace.c Mon Jul 10 16:47:19 2000 +++ linux/arch/arm/kernel/ptrace.c Sun Sep 3 11:19:11 2000 @@ -61,9 +61,18 @@ static inline int put_stack_long(struct task_struct *task, int offset, long data) { - get_user_regs(task)->uregs[offset] = data; + struct pt_regs newregs, *regs = get_user_regs(task); + int ret = -EINVAL; - return 0; + newregs = *regs; + newregs.uregs[offset] = data; + + if (valid_user_regs(&newregs)) { + regs->uregs[offset] = data; + ret = 0; + } + + return ret; } static inline int @@ -406,7 +415,7 @@ if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) break; - if (addr < sizeof (struct pt_regs)) + if (addr < sizeof(struct pt_regs)) ret = put_stack_long(child, (int)addr >> 2, data); break; @@ -499,12 +508,19 @@ * Set all gp regs in the child. */ case PTRACE_SETREGS: { - struct pt_regs *regs = get_user_regs(child); + struct pt_regs newregs; - ret = 0; - if (copy_from_user(regs, (void *)data, - sizeof(struct pt_regs))) - ret = -EFAULT; + ret = -EFAULT; + if (copy_from_user(&newregs, (void *)data, + sizeof(struct pt_regs)) == 0) { + struct pt_regs *regs = get_user_regs(child); + + ret = -EINVAL; + if (valid_user_regs(&newregs)) { + *regs = newregs; + ret = 0; + } + } break; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.4.0-test7/linux/arch/arm/kernel/signal.c Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/kernel/signal.c Sun Sep 3 11:53:42 2000 @@ -587,7 +587,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c --- v2.4.0-test7/linux/arch/arm/kernel/sys_arm.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/sys_arm.c Tue Sep 5 13:50:01 2000 @@ -203,7 +203,7 @@ */ asmlinkage int sys_fork(struct pt_regs *regs) { - return do_fork(SIGCHLD, regs->ARM_sp, regs); + return do_fork(SIGCHLD, regs->ARM_sp, regs, 0); } /* Clone a task - this clones the calling program thread. @@ -213,12 +213,12 @@ { if (!newsp) newsp = regs->ARM_sp; - return do_fork(clone_flags, newsp, regs); + return do_fork(clone_flags, newsp, regs, 0); } asmlinkage int sys_vfork(struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0); } /* sys_execve() executes a new program. diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.4.0-test7/linux/arch/arm/lib/Makefile Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/lib/Makefile Sun Sep 3 11:19:11 2000 @@ -9,9 +9,9 @@ L_TARGET := lib.a L_OBJS := changebit.o csumipv6.o csumpartial.o csumpartialcopy.o \ csumpartialcopyuser.o clearbit.o copy_page.o findbit.o \ - memchr.o memcpy.o memset.o memzero.o setbit.o strchr.o \ - strrchr.o testchangebit.o testclearbit.o testsetbit.o \ - uaccess.o + memchr.o memcpy.o memset.o memzero.o setbit.o \ + strncpy_from_user.o strnlen_user.o strchr.o strrchr.o \ + testchangebit.o testclearbit.o testsetbit.o uaccess.o O_TARGET := lib.o O_OBJS := backtrace.o delay.o diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/copy_page.S linux/arch/arm/lib/copy_page.S --- v2.4.0-test7/linux/arch/arm/lib/copy_page.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/copy_page.S Sun Sep 3 11:19:11 2000 @@ -10,26 +10,26 @@ #include #include "constants.h" - .text + .text + .align 5 /* * StrongARM optimised copy_page routine - * now 1.72bytes/cycle, was 1.60 bytes/cycle - * (50MHz bus -> 86MB/s) + * now 1.78bytes/cycle, was 1.60 bytes/cycle (50MHz bus -> 89MB/s) + * Note that we probably achieve closer to the 100MB/s target with + * the core clock switching. */ - ENTRY(copy_page) stmfd sp!, {r4, lr} @ 2 mov r2, #PAGE_SZ/64 @ 1 -1: ldmia r1!, {r3, r4, ip, lr} @ 4 - subs r2, r2, #1 @ 1 - stmia r0!, {r3, r4, ip, lr} @ 4 ldmia r1!, {r3, r4, ip, lr} @ 4+1 - stmia r0!, {r3, r4, ip, lr} @ 4 +1: stmia r0!, {r3, r4, ip, lr} @ 4 ldmia r1!, {r3, r4, ip, lr} @ 4+1 stmia r0!, {r3, r4, ip, lr} @ 4 ldmia r1!, {r3, r4, ip, lr} @ 4+1 stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmneia r1!, {r3, r4, ip, lr} @ 4 bne 1b @ 1 LOADREGS(fd, sp!, {r4, pc}) @ 3 - - diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/delay.S linux/arch/arm/lib/delay.S --- v2.4.0-test7/linux/arch/arm/lib/delay.S Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/lib/delay.S Sun Sep 3 11:19:11 2000 @@ -40,4 +40,3 @@ subs r0, r0, #1 bcs SYMBOL_NAME(__delay) RETINSTR(mov,pc,lr) - diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/memchr.S linux/arch/arm/lib/memchr.S --- v2.4.0-test7/linux/arch/arm/lib/memchr.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/memchr.S Sun Sep 3 11:19:11 2000 @@ -1,24 +1,21 @@ /* * linux/arch/arm/lib/memchr.S * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2000 Russell King * * ASM optimised string functions - * */ #include #include -#include "constants.h" - .text + .text + .align 5 ENTRY(memchr) - str lr, [sp, #-4]! -1: ldrb r3, [r0], #1 - teq r3, r1 - beq 2f - subs r2, r2, #1 - bpl 1b -2: movne r0, #0 - subeq r0, r0, #1 - LOADREGS(fd, sp!, {pc}) - +1: ldrb r3, [r0], #1 + teq r3, r1 + beq 2f + subs r2, r2, #1 + bpl 1b +2: movne r0, #0 + subeq r0, r0, #1 + RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S --- v2.4.0-test7/linux/arch/arm/lib/memcpy.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/memcpy.S Sun Sep 3 11:19:11 2000 @@ -4,7 +4,6 @@ * Copyright (C) 1995-1999 Russell King * * ASM optimised string functions - * */ #include #include @@ -314,5 +313,3 @@ b 24b .align - - diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/memset.S linux/arch/arm/lib/memset.S --- v2.4.0-test7/linux/arch/arm/lib/memset.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/memset.S Sun Sep 3 11:19:11 2000 @@ -1,88 +1,76 @@ /* * linux/arch/arm/lib/memset.S * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2000 Russell King * * ASM optimised string functions - * */ #include #include -#include "constants.h" - .text - .align 5 -ENTRY(memset) - mov r3, r0 - cmp r2, #16 - blt 6f - ands ip, r3, #3 - beq 1f - cmp ip, #2 - strltb r1, [r3], #1 @ Align destination - strleb r1, [r3], #1 - strb r1, [r3], #1 - rsb ip, ip, #4 - sub r2, r2, ip -1: orr r1, r1, r1, lsl #8 - orr r1, r1, r1, lsl #16 - cmp r2, #256 - blt 4f - stmfd sp!, {r4, r5, lr} - mov r4, r1 - mov r5, r1 - mov lr, r1 - mov ip, r2, lsr #6 - sub r2, r2, ip, lsl #6 -2: stmia r3!, {r1, r4, r5, lr} @ 64 bytes at a time. - stmia r3!, {r1, r4, r5, lr} - stmia r3!, {r1, r4, r5, lr} - stmia r3!, {r1, r4, r5, lr} - subs ip, ip, #1 - bne 2b - teq r2, #0 - LOADREGS(eqfd, sp!, {r4, r5, pc}) @ Now <64 bytes to go. - tst r2, #32 - stmneia r3!, {r1, r4, r5, lr} - stmneia r3!, {r1, r4, r5, lr} - tst r2, #16 - stmneia r3!, {r1, r4, r5, lr} - ldmia sp!, {r4, r5} -3: tst r2, #8 - stmneia r3!, {r1, lr} - tst r2, #4 - strne r1, [r3], #4 - tst r2, #2 - strneb r1, [r3], #1 - strneb r1, [r3], #1 - tst r2, #1 - strneb r1, [r3], #1 - LOADREGS(fd, sp!, {pc}) + .text + .align 5 + .word 0 -4: movs ip, r2, lsr #3 - beq 3b - sub r2, r2, ip, lsl #3 - str lr, [sp, #-4]! - mov lr, r1 - subs ip, ip, #4 -5: stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - subges ip, ip, #4 - bge 5b - tst ip, #2 - stmneia r3!, {r1, lr} - stmneia r3!, {r1, lr} - tst ip, #1 - stmneia r3!, {r1, lr} - teq r2, #0 - LOADREGS(eqfd, sp!, {pc}) - b 3b +1: subs r2, r2, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strltb r1, [r0], #1 @ 1 + strleb r1, [r0], #1 @ 1 + strb r1, [r0], #1 @ 1 + add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3)) +/* + * The pointer is now aligned and the length is adjusted. Try doing the + * memzero again. + */ -6: subs r2, r2, #1 - strgeb r1, [r3], #1 - bgt 6b - RETINSTR(mov, pc, lr) +ENTRY(memset) + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +/* + * we know that the pointer in r0 is aligned to a word boundary. + */ + orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + mov r3, r1 + cmp r2, #16 + blt 4f +/* + * We need an extra register for this loop - save the return address and + * use the LR + */ + str lr, [sp, #-4]! + mov ip, r1 + mov lr, r1 +2: subs r2, r2, #64 + stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time. + stmgeia r0!, {r1, r3, ip, lr} + stmgeia r0!, {r1, r3, ip, lr} + stmgeia r0!, {r1, r3, ip, lr} + bgt 2b + LOADREGS(eqfd, sp!, {pc}) @ Now <64 bytes to go. +/* + * No need to correct the count; we're only testing bits from now on + */ + tst r2, #32 + stmneia r0!, {r1, r3, ip, lr} + stmneia r0!, {r1, r3, ip, lr} + tst r2, #16 + stmneia r0!, {r1, r3, ip, lr} + ldr lr, [sp], #4 +4: tst r2, #8 + stmneia r0!, {r1, r3} + tst r2, #4 + strne r1, [r0], #4 +/* + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +5: tst r2, #2 + strneb r1, [r0], #1 + strneb r1, [r0], #1 + tst r2, #1 + strneb r1, [r0], #1 + RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/memzero.S linux/arch/arm/lib/memzero.S --- v2.4.0-test7/linux/arch/arm/lib/memzero.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/memzero.S Sun Sep 3 11:19:11 2000 @@ -1,80 +1,76 @@ /* * linux/arch/arm/lib/memzero.S * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2000 Russell King */ #include #include -#include "constants.h" - - .text + .text + .align 5 + .word 0 /* - * Prototype: void memzero(void *d, size_t n) + * Align the pointer in r0. r3 contains the number of bytes that we are + * mis-aligned by, and r1 is the number of bytes. If r1 < 4, then we + * don't bother; we use byte stores instead. + */ +1: subs r1, r1, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strltb r2, [r0], #1 @ 1 + strleb r2, [r0], #1 @ 1 + strb r2, [r0], #1 @ 1 + add r1, r1, r3 @ 1 (r1 = r1 - (4 - r3)) +/* + * The pointer is now aligned and the length is adjusted. Try doing the + * memzero again. */ -1: @ 4 <= r1 - cmp ip, #2 @ 1 - strltb r2, [r0], #1 @ 1 - strleb r2, [r0], #1 @ 1 - strb r2, [r0], #1 @ 1 - rsb ip, ip, #4 @ 1 - sub r1, r1, ip @ 1 - cmp r1, #3 @ 1 - bgt 2f @ 1 @ +8 - b 4f @ 1 @ +9 - - .align 5 ENTRY(__memzero) - mov r2, #0 @ 1 - cmp r1, #4 @ 1 - blt 4f @ 1 @ = 3 - - @ r1 >= 4 - - ands ip, r0, #3 @ 1 - bne 1b @ 1 @ = 5 - -2: @ r1 >= 4 && (r0 & 3) = 0 @ = 5 or 11 - - str lr, [sp, #-4]! @ 1 - mov r3, #0 @ 1 - mov ip, #0 @ 1 - mov lr, #0 @ 1 - - @ 4 <= r1 <= 32 @ = 9 or 15 - -3: subs r1, r1, #32 @ 1 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - bgt 3b @ 1 - LOADREGS(eqfd, sp!, {pc}) @ 1/2 - - @ -28 <= r1 <= -1 - - cmp r1, #-16 @ 1 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - ldr lr, [sp], #4 @ 1 - addlts r1, r1, #16 @ 1 - RETINSTR(moveq,pc,lr) @ 1 - - @ -12 <= r1 <= -1 - - cmp r1, #-8 @ 1 - stmgeia r0!, {r2, r3} @ 2 - addlts r1, r1, #8 @ 1 - RETINSTR(moveq,pc,lr) @ 1 - - @ -4 <= r1 <= -1 - - cmp r1, #-4 @ 1 - strge r2, [r0], #4 @ 1 - adds r1, r1, #4 @ 1 - RETINSTR(moveq,pc,lr) @ 1 - -4: @ 1 <= r1 <= 3 - cmp r1, #2 @ 1 - strgtb r2, [r0], #1 @ 1 - strgeb r2, [r0], #1 @ 1 - strb r2, [r0], #1 @ 1 - RETINSTR(mov,pc,lr) @ 1 + mov r2, #0 @ 1 + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +/* + * r3 = 0, and we know that the pointer in r0 is aligned to a word boundary. + */ + cmp r1, #16 @ 1 we can skip this chunk if we + blt 4f @ 1 have < 16 bytes +/* + * We need an extra register for this loop - save the return address and + * use the LR + */ + str lr, [sp, #-4]! @ 1 + mov ip, r2 @ 1 + mov lr, r2 @ 1 + +3: subs r1, r1, #64 @ 1 write 32 bytes out per loop + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + bgt 3b @ 1 + LOADREGS(eqfd, sp!, {pc}) @ 1/2 quick exit +/* + * No need to correct the count; we're only testing bits from now on + */ + tst r1, #32 @ 1 + stmneia r0!, {r2, r3, ip, lr} @ 4 + stmneia r0!, {r2, r3, ip, lr} @ 4 + tst r1, #16 @ 1 16 bytes or more? + stmneia r0!, {r2, r3, ip, lr} @ 4 + ldr lr, [sp], #4 @ 1 + +4: tst r1, #8 @ 1 8 bytes or more? + stmneia r0!, {r2, r3} @ 2 + tst r1, #4 @ 1 4 bytes or more? + strne r2, [r0], #4 @ 1 +/* + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +5: tst r1, #2 @ 1 2 bytes or more? + strneb r2, [r0], #1 @ 1 + strneb r2, [r0], #1 @ 1 + tst r1, #1 @ 1 a byte left over + strneb r2, [r0], #1 @ 1 + RETINSTR(mov,pc,lr) @ 1 diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/strchr.S linux/arch/arm/lib/strchr.S --- v2.4.0-test7/linux/arch/arm/lib/strchr.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/strchr.S Sun Sep 3 11:19:11 2000 @@ -1,19 +1,16 @@ /* * linux/arch/arm/lib/strchr.S * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2000 Russell King * * ASM optimised string functions - * */ #include #include -#include "constants.h" .text + .align 5 ENTRY(strchr) - str lr, [sp, #-4]! - mov r3, #0 1: ldrb r2, [r0], #1 teq r2, r1 teqne r2, #0 @@ -21,6 +18,4 @@ teq r2, #0 moveq r0, #0 subne r0, r0, #1 - LOADREGS(fd, sp!, {pc}) - - + RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/strncpy_from_user.S linux/arch/arm/lib/strncpy_from_user.S --- v2.4.0-test7/linux/arch/arm/lib/strncpy_from_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/lib/strncpy_from_user.S Sun Sep 3 11:19:11 2000 @@ -0,0 +1,39 @@ +/* + * linux/arch/arm/lib/strncpy_from_user.S + * + * Copyright (C) 1995-2000 Russell King + */ +#include +#include +#include + + .text + .align 5 + +/* + * Copy a string from user space to kernel space. + * r0 = dst, r1 = src, r2 = byte length + * returns the number of characters copied (strlen of copied string), + * -EFAULT on exception, or "len" if we fill the whole buffer + */ +ENTRY(__arch_strncpy_from_user) + save_lr + mov ip, r1 +1: subs r2, r2, #1 +USER( ldrplbt r3, [r1], #1) + bmi 2f + strb r3, [r0], #1 + teq r3, #0 + bne 1b + sub r1, r1, #1 @ take NUL character out of count +2: sub r0, r1, ip + restore_pc + + .section .fixup,"ax" + .align 0 +9001: mov r3, #0 + strb r3, [r0, #0] @ null terminate + mov r0, #-EFAULT + restore_pc + .previous + diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/strnlen_user.S linux/arch/arm/lib/strnlen_user.S --- v2.4.0-test7/linux/arch/arm/lib/strnlen_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/lib/strnlen_user.S Sun Sep 3 11:19:11 2000 @@ -0,0 +1,36 @@ +/* + * linux/arch/arm/lib/strnlen_user.S + * + * Copyright (C) 1995-2000 Russell King + */ +#include +#include +#include + + .text + .align 5 + +/* Prototype: unsigned long __arch_strnlen_user(const char *str, long n) + * Purpose : get length of a string in user memory + * Params : str - address of string in user memory + * Returns : length of string *including terminator* + * or zero on exception, or n + 1 if too long + */ +ENTRY(__arch_strnlen_user) + save_lr + mov r2, r0 +1: +USER( ldrbt r3, [r0], #1) + teq r3, #0 + beq 2f + subs r1, r1, #1 + bne 1b + add r0, r0, #1 +2: sub r0, r0, r2 + restore_pc + + .section .fixup,"ax" + .align 0 +9001: mov r0, #0 + restore_pc + .previous diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/strrchr.S linux/arch/arm/lib/strrchr.S --- v2.4.0-test7/linux/arch/arm/lib/strrchr.S Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/lib/strrchr.S Sun Sep 3 11:19:11 2000 @@ -1,18 +1,16 @@ /* * linux/arch/arm/lib/strrchr.S * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2000 Russell King * * ASM optimised string functions - * */ #include #include -#include "constants.h" .text + .align 5 ENTRY(strrchr) - str lr, [sp, #-4]! mov r3, #0 1: ldrb r2, [r0], #1 teq r2, r1 @@ -20,6 +18,4 @@ teq r2, #0 bne 1b mov r0, r3 - LOADREGS(fd, sp!, {pc}) - - + RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/uaccess-armo.S linux/arch/arm/lib/uaccess-armo.S --- v2.4.0-test7/linux/arch/arm/lib/uaccess-armo.S Fri Oct 22 13:21:44 1999 +++ linux/arch/arm/lib/uaccess-armo.S Sun Sep 3 11:19:11 2000 @@ -11,13 +11,6 @@ .text -#define USER(x...) \ -9999: x; \ - .section __ex_table,"a"; \ - .align 3; \ - .long 9999b,9001f; \ - .previous - .globl SYMBOL_NAME(uaccess_user) SYMBOL_NAME(uaccess_user): .word uaccess_user_put_byte diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S --- v2.4.0-test7/linux/arch/arm/lib/uaccess.S Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/lib/uaccess.S Sun Sep 3 11:19:11 2000 @@ -13,13 +13,6 @@ .text -#define USER(x...) \ -9999: x; \ - .section __ex_table,"a"; \ - .align 3; \ - .long 9999b,9001f; \ - .previous - #define PAGE_SHIFT 12 /* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n) @@ -589,63 +582,4 @@ .align 0 9001: LOADREGS(fd,sp!, {r0, pc}) .previous - -/* Prototype: unsigned long __arch_strnlen_user(const char *str, long n) - * Purpose : get length of a string in user memory - * Params : str - address of string in user memory - * Returns : length of string *including terminator* - * or zero on exception, or n + 1 if too long - */ -ENTRY(__arch_strnlen_user) - str lr, [sp, #-4]! - mov r2, r0 -1: -USER( ldrbt r3, [r0], #1) - teq r3, #0 - beq 2f - subs r1, r1, #1 - bne 1b - add r0, r0, #1 -2: sub r0, r0, r2 - LOADREGS(fd,sp!, {pc}) - - .section .fixup,"ax" - .align 0 -9001: mov r0, #0 - LOADREGS(fd,sp!,{pc}) - .previous - -/* Prototype: size_t __arch_strncpy_from_user(char *dst, char *src, size_t len) - * Purpose : copy a string from user memory to kernel memory - * Params : dst - kernel memory destination - * : src - user memory source - * : len - maximum length of string - * Returns : number of characters copied - */ -ENTRY(__arch_strncpy_from_user) - str lr, [sp, #-4]! - add ip, r1, #1 -1: subs r2, r2, #1 - bmi 2f -USER( ldrbt r3, [r1], #1) - strb r3, [r0], #1 - teq r3, #0 - bne 1b - sub r0, r1, ip - LOADREGS(fd, sp!, {pc}) -2: sub ip, ip, #1 - sub r0, r1, ip - LOADREGS(fd, sp!, {pc}) - - .section .fixup,"ax" - .align 0 -9001: mov ip, #0 -1: strb ip, [r0], #1 - subs r2, r2, #1 - bpl 1b - mov r0, #-EFAULT - LOADREGS(fd, sp!, {pc}) - .previous - - .align diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/Makefile linux/arch/arm/mach-footbridge/Makefile --- v2.4.0-test7/linux/arch/arm/mach-footbridge/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/Makefile Sun Sep 3 11:19:11 2000 @@ -0,0 +1,46 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +O_TARGET := footbridge.o + +# Object file lists. + +obj-y := #arch.o dma.o mm.o +obj-m := +obj-n := +obj- := + +export-objs := netwinder-hw.o + +ifeq ($(CONFIG_PCI),y) +obj-$(CONFIG_ARCH_CATS) += cats-pci.o +obj-$(CONFIG_ARCH_EBSA285) += ebsa285-pci.o +obj-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o +obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o +endif + +ifeq ($(CONFIG_LEDS),y) +#obj-$(CONFIG_ARCH_CO285) += ebsa285-leds.o +#obj-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o +#obj-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o +endif + +#obj-$(CONFIG_ARCH_CATS) += cats-hw.o +#obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o + +# Files that are both resident and modular; remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/arch.c linux/arch/arm/mach-footbridge/arch.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/arch.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/arch.c Sun Sep 3 11:19:11 2000 @@ -0,0 +1,152 @@ +/* + * linux/arch/arm/mach-footbridge/arch.c + * + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +extern void setup_initrd(unsigned int start, unsigned int size); +extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); +extern void __init footbridge_map_io(void); + +#ifdef CONFIG_ARCH_EBSA285 + +static void __init +fixup_ebsa285(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + ORIG_X = params->u1.s.video_x; + ORIG_Y = params->u1.s.video_y; + ORIG_VIDEO_COLS = params->u1.s.video_num_cols; + ORIG_VIDEO_LINES = params->u1.s.video_num_rows; +} + +MACHINE_START(EBSA285, "EBSA285") + MAINTAINER("Russell King") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) + VIDEO(0x000a0000, 0x000bffff) + FIXUP(fixup_ebsa285) + MAPIO(footbridge_map_io) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_NETWINDER +/* + * Older NeTTroms either do not provide a parameters + * page, or they don't supply correct information in + * the parameter page. + */ +static void __init +fixup_netwinder(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ +#ifdef CONFIG_ISAPNP + extern int isapnp_disable; + + /* + * We must not use the kernels ISAPnP code + * on the NetWinder - it will reset the settings + * for the WaveArtist chip and render it inoperable. + */ + isapnp_disable = 1; +#endif + + if (params->u1.s.nr_pages != 0x02000 && + params->u1.s.nr_pages != 0x04000 && + params->u1.s.nr_pages != 0x08000 && + params->u1.s.nr_pages != 0x10000) { + printk(KERN_WARNING "Warning: bad NeTTrom parameters " + "detected, using defaults\n"); + + params->u1.s.nr_pages = 0x2000; /* 32MB */ + params->u1.s.ramdisk_size = 0; + params->u1.s.flags = FLAG_READONLY; + params->u1.s.initrd_start = 0; + params->u1.s.initrd_size = 0; + params->u1.s.rd_start = 0; + } +} + +MACHINE_START(NETWINDER, "Rebel-NetWinder") + MAINTAINER("Russell King/Rebel.com") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) + VIDEO(0x000a0000, 0x000bffff) + DISABLE_PARPORT(0) + DISABLE_PARPORT(2) + FIXUP(fixup_netwinder) + MAPIO(footbridge_map_io) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_CATS +/* + * CATS uses soft-reboot by default, since + * hard reboots fail on early boards. + */ +static void __init +fixup_cats(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + ORIG_VIDEO_LINES = 25; + ORIG_VIDEO_POINTS = 16; + ORIG_Y = 24; +} + +MACHINE_START(CATS, "Chalice-CATS") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + SOFT_REBOOT + FIXUP(fixup_cats) + MAPIO(footbridge_map_io) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_CO285 + +static void __init +fixup_coebsa285(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + extern unsigned long boot_memory_end; + extern char boot_command_line[]; + + mi->nr_banks = 1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].size = boot_memory_end; + mi->bank[0].node = 0; + + *cmdline = boot_command_line; +} + +MACHINE_START(CO285, "co-EBSA285") + MAINTAINER("Mark van Doesburg") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000) + FIXUP(fixup_coebsa285) + MAPIO(footbridge_map_io) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_PERSONAL_SERVER +MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer") + MAINTAINER("Jamey Hicks / George France") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) + MAPIO(footbridge_map_io) +MACHINE_END +#endif diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/cats-hw.c linux/arch/arm/mach-footbridge/cats-hw.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/cats-hw.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/cats-hw.c Sun Sep 3 11:19:11 2000 @@ -0,0 +1,65 @@ +/* + * linux/arch/arm/mach-footbridge/cats-hw.c + * + * CATS machine fixup + * + * Copyright (C) 1998, 1999 Russell King, Phil Blundell + */ +#include +#include +#include +#include + +#include +#include + +#define CFG_PORT 0x370 +#define INDEX_PORT (CFG_PORT) +#define DATA_PORT (CFG_PORT + 1) + +static int __init cats_hw_init(void) +{ + if (machine_is_cats()) { + /* Set Aladdin to CONFIGURE mode */ + outb(0x51, CFG_PORT); + outb(0x23, CFG_PORT); + + /* Select logical device 3 */ + outb(0x07, INDEX_PORT); + outb(0x03, DATA_PORT); + + /* Set parallel port to DMA channel 3, ECP+EPP1.9, + enable EPP timeout */ + outb(0x74, INDEX_PORT); + outb(0x03, DATA_PORT); + + outb(0xf0, INDEX_PORT); + outb(0x0f, DATA_PORT); + + outb(0xf1, INDEX_PORT); + outb(0x07, DATA_PORT); + + /* Select logical device 4 */ + outb(0x07, INDEX_PORT); + outb(0x04, DATA_PORT); + + /* UART1 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Select logical device 5 */ + outb(0x07, INDEX_PORT); + outb(0x05, DATA_PORT); + + /* UART2 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Set Aladdin to RUN mode */ + outb(0xbb, CFG_PORT); + } + + return 0; +} + +__initcall(cats_hw_init); diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/cats-pci.c linux/arch/arm/mach-footbridge/cats-pci.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/cats-pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/cats-pci.c Sun Sep 3 11:19:11 2000 @@ -0,0 +1,37 @@ +/* + * linux/arch/arm/mach-footbridge/cats-pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include +#include +#include + +#include +#include + +/* cats host-specific stuff */ +static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; + +static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (dev->irq >= 128) + return dev->irq & 0x1f; + + if (dev->irq >= 1 && dev->irq <= 4) + return irqmap_cats[dev->irq - 1]; + + if (dev->irq != 0) + printk("PCI: device %02x:%02x has unknown irq line %x\n", + dev->bus->number, dev->devfn, dev->irq); + + return -1; +} + +struct hw_pci cats_pci __initdata = { + init: dc21285_init, + swizzle: no_swizzle, + map_irq: cats_map_irq, +}; diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/ebsa285-leds.c linux/arch/arm/mach-footbridge/ebsa285-leds.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/ebsa285-leds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/ebsa285-leds.c Tue Sep 5 12:56:51 2000 @@ -0,0 +1,137 @@ +/* + * linux/arch/arm/mach-footbridge/ebsa285-leds.c + * + * Copyright (C) 1998-1999 Russell King + * + * EBSA-285 control routines. + * + * The EBSA-285 uses the leds as follows: + * - Green - toggles state every 50 timer interrupts + * - Amber - On if system is not idle + * - Red - currently unused + * + * Changelog: + * 02-05-1999 RMK Various cleanups + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 +static char led_state; +static char hw_led_state; + +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; + +static void ebsa285_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + switch (evt) { + case led_start: + hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN; +#ifndef CONFIG_LEDS_CPU + hw_led_state |= XBUS_LED_AMBER; +#endif + led_state |= LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= XBUS_LED_GREEN; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= XBUS_LED_AMBER; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~XBUS_LED_AMBER; + break; +#endif + + case led_halted: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~XBUS_LED_RED; + break; + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~XBUS_LED_GREEN; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= XBUS_LED_GREEN; + break; + + case led_amber_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~XBUS_LED_AMBER; + break; + + case led_amber_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= XBUS_LED_AMBER; + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~XBUS_LED_RED; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= XBUS_LED_RED; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) + *XBUS_LEDS = hw_led_state; + + spin_unlock_irqrestore(&leds_lock, flags); +} + +static int __init leds_init(void) +{ + if (machine_is_ebsa285() || machine_is_co285()) + leds_event = ebsa285_leds_event; + + leds_event(led_start); + + return 0; +} + +__initcall(leds_init); diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/ebsa285-pci.c linux/arch/arm/mach-footbridge/ebsa285-pci.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/ebsa285-pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/ebsa285-pci.c Sun Sep 3 11:19:11 2000 @@ -0,0 +1,39 @@ +/* + * linux/arch/arm/mach-footbridge/ebsa285-pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include +#include +#include + +#include +#include + +static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI }; + +static u8 __init ebsa285_swizzle(struct pci_dev *dev, u8 *pin) +{ + return PCI_SLOT(dev->devfn); +} + +static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == PCI_DEVICE_ID_CONTAQ_82C693) + switch (PCI_FUNC(dev->devfn)) { + case 1: return 14; + case 2: return 15; + case 3: return 12; + } + + return irqmap_ebsa285[(slot + pin) & 3]; +} + +struct hw_pci ebsa285_pci __initdata = { + init: dc21285_init, + swizzle: ebsa285_swizzle, + map_irq: ebsa285_map_irq, +}; diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/netwinder-hw.c linux/arch/arm/mach-footbridge/netwinder-hw.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/netwinder-hw.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/netwinder-hw.c Tue Sep 5 12:56:51 2000 @@ -0,0 +1,621 @@ +/* + * linux/arch/arm/mach-footbridge/netwinder-hw.c + * + * Netwinder machine fixup + * + * Copyright (C) 1998, 1999 Russell King, Phil Blundell + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define IRDA_IO_BASE 0x180 +#define GP1_IO_BASE 0x338 +#define GP2_IO_BASE 0x33a + + +#ifdef CONFIG_LEDS +#define DEFAULT_LEDS 0 +#else +#define DEFAULT_LEDS GPIO_GREEN_LED +#endif + +/* + * Winbond WB83977F accessibility stuff + */ +static inline void wb977_open(void) +{ + outb(0x87, 0x370); + outb(0x87, 0x370); +} + +static inline void wb977_close(void) +{ + outb(0xaa, 0x370); +} + +static inline void wb977_wb(int reg, int val) +{ + outb(reg, 0x370); + outb(val, 0x371); +} + +static inline void wb977_ww(int reg, int val) +{ + outb(reg, 0x370); + outb(val >> 8, 0x371); + outb(reg + 1, 0x370); + outb(val, 0x371); +} + +#define wb977_device_select(dev) wb977_wb(0x07, dev) +#define wb977_device_disable() wb977_wb(0x30, 0x00) +#define wb977_device_enable() wb977_wb(0x30, 0x01) + +/* + * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE + */ +spinlock_t gpio_lock = SPIN_LOCK_UNLOCKED; + +static unsigned int current_gpio_op = 0; +static unsigned int current_gpio_io = 0; +static unsigned int current_cpld = 0; + +void gpio_modify_op(int mask, int set) +{ + unsigned int new_gpio, changed; + + new_gpio = (current_gpio_op & ~mask) | set; + changed = new_gpio ^ current_gpio_op; + current_gpio_op = new_gpio; + + if (changed & 0xff) + outb(new_gpio, GP1_IO_BASE); + if (changed & 0xff00) + outb(new_gpio >> 8, GP2_IO_BASE); +} + +static inline void __gpio_modify_io(int mask, int in) +{ + unsigned int new_gpio, changed; + int port; + + new_gpio = (current_gpio_io & ~mask) | in; + changed = new_gpio ^ current_gpio_io; + current_gpio_io = new_gpio; + + changed >>= 1; + new_gpio >>= 1; + + wb977_device_select(7); + + for (port = 0xe1; changed && port < 0xe8; changed >>= 1) { + wb977_wb(port, new_gpio & 1); + + port += 1; + new_gpio >>= 1; + } + + wb977_device_select(8); + + for (port = 0xe8; changed && port < 0xec; changed >>= 1) { + wb977_wb(port, new_gpio & 1); + + port += 1; + new_gpio >>= 1; + } +} + +void gpio_modify_io(int mask, int in) +{ + /* Open up the SuperIO chip */ + wb977_open(); + + __gpio_modify_io(mask, in); + + /* Close up the EFER gate */ + wb977_close(); +} + +int gpio_read(void) +{ + return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8; +} + +/* + * Initialise the Winbond W83977F global registers + */ +static inline void wb977_init_global(void) +{ + /* + * Enable R/W config registers + */ + wb977_wb(0x26, 0x40); + + /* + * Power down FDC (not used) + */ + wb977_wb(0x22, 0xfe); + + /* + * GP12, GP11, CIRRX, IRRXH, GP10 + */ + wb977_wb(0x2a, 0xc1); + + /* + * GP23, GP22, GP21, GP20, GP13 + */ + wb977_wb(0x2b, 0x6b); + + /* + * GP17, GP16, GP15, GP14 + */ + wb977_wb(0x2c, 0x55); +} + +/* + * Initialise the Winbond W83977F printer port + */ +static inline void wb977_init_printer(void) +{ + wb977_device_select(1); + + /* + * mode 1 == EPP + */ + wb977_wb(0xf0, 0x01); +} + +/* + * Initialise the Winbond W83977F keyboard controller + */ +static inline void wb977_init_keyboard(void) +{ + wb977_device_select(5); + + /* + * Keyboard controller address + */ + wb977_ww(0x60, 0x0060); + wb977_ww(0x62, 0x0064); + + /* + * Keyboard IRQ 1, active high, edge trigger + */ + wb977_wb(0x70, 1); + wb977_wb(0x71, 0x02); + + /* + * Mouse IRQ 5, active high, edge trigger + */ + wb977_wb(0x72, 5); + wb977_wb(0x73, 0x02); + + /* + * KBC 8MHz + */ + wb977_wb(0xf0, 0x40); + + /* + * Enable device + */ + wb977_device_enable(); +} + +/* + * Initialise the Winbond W83977F Infra-Red device + */ +static inline void wb977_init_irda(void) +{ + wb977_device_select(6); + + /* + * IR base address + */ + wb977_ww(0x60, IRDA_IO_BASE); + + /* + * IRDA IRQ 6, active high, edge trigger + */ + wb977_wb(0x70, 6); + wb977_wb(0x71, 0x02); + + /* + * RX DMA - ISA DMA 0 + */ + wb977_wb(0x74, 0x00); + + /* + * TX DMA - Disable Tx DMA + */ + wb977_wb(0x75, 0x04); + + /* + * Append CRC, Enable bank selection + */ + wb977_wb(0xf0, 0x03); + + /* + * Enable device + */ + wb977_device_enable(); +} + +/* + * Initialise Winbond W83977F general purpose IO + */ +static inline void wb977_init_gpio(void) +{ + unsigned long flags; + + /* + * Set up initial I/O definitions + */ + current_gpio_io = -1; + __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER); + + wb977_device_select(7); + + /* + * Group1 base address + */ + wb977_ww(0x60, GP1_IO_BASE); + wb977_ww(0x62, 0); + wb977_ww(0x64, 0); + + /* + * GP10 (Orage button) IRQ 10, active high, edge trigger + */ + wb977_wb(0x70, 10); + wb977_wb(0x71, 0x02); + + /* + * GP10: Debounce filter enabled, IRQ, input + */ + wb977_wb(0xe0, 0x19); + + /* + * Enable Group1 + */ + wb977_device_enable(); + + wb977_device_select(8); + + /* + * Group2 base address + */ + wb977_ww(0x60, GP2_IO_BASE); + + /* + * Clear watchdog timer regs + * - timer disable + */ + wb977_wb(0xf2, 0x00); + + /* + * - disable LED, no mouse nor keyboard IRQ + */ + wb977_wb(0xf3, 0x00); + + /* + * - timer counting, disable power LED, disable timeouot + */ + wb977_wb(0xf4, 0x00); + + /* + * Enable group2 + */ + wb977_device_enable(); + + /* + * Set Group1/Group2 outputs + */ + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN); + spin_unlock_irqrestore(&gpio_loc, flags); +} + +/* + * Initialise the Winbond W83977F chip. + */ +static void __init wb977_init(void) +{ + request_region(0x370, 2, "W83977AF configuration"); + + /* + * Open up the SuperIO chip + */ + wb977_open(); + + /* + * Initialise the global registers + */ + wb977_init_global(); + + /* + * Initialise the various devices in + * the multi-IO chip. + */ + wb977_init_printer(); + wb977_init_keyboard(); + wb977_init_irda(); + wb977_init_gpio(); + + /* + * Close up the EFER gate + */ + wb977_close(); +} + +void cpld_modify(int mask, int set) +{ + int msk; + + current_cpld = (current_cpld & ~mask) | set; + + gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0); + gpio_modify_op(GPIO_IOLOAD, 0); + + for (msk = 8; msk; msk >>= 1) { + int bit = current_cpld & msk; + + gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0); + gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK); + } + + gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0); + gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK); + gpio_modify_op(GPIO_IOLOAD, 0); +} + +static void __init cpld_init(void) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE); + spin_unlock_irqrestore(&gpio_lock, flags); +} + +static unsigned char rwa_unlock[] __initdata = +{ 0x00, 0x00, 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, + 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74, + 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; + +#ifndef DEBUG +#define dprintk(x...) +#else +#define dprintk(x...) printk(x) +#endif + +#define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0) + +static inline void rwa010_unlock(void) +{ + int i; + + WRITE_RWA(2, 2); + mdelay(10); + + for (i = 0; i < sizeof(rwa_unlock); i++) { + outb(rwa_unlock[i], 0x279); + udelay(10); + } +} + +static inline void rwa010_read_ident(void) +{ + unsigned char si[9]; + int i, j; + + WRITE_RWA(3, 0); + WRITE_RWA(0, 128); + + outb(1, 0x279); + + mdelay(1); + + dprintk("Identifier: "); + for (i = 0; i < 9; i++) { + si[i] = 0; + for (j = 0; j < 8; j++) { + int bit; + udelay(250); + inb(0x203); + udelay(250); + bit = inb(0x203); + dprintk("%02X ", bit); + bit = (bit == 0xaa) ? 1 : 0; + si[i] |= bit << j; + } + dprintk("(%02X) ", si[i]); + } + dprintk("\n"); +} + +static inline void rwa010_global_init(void) +{ + WRITE_RWA(6, 2); // Assign a card no = 2 + + dprintk("Card no = %d\n", inb(0x203)); + + /* disable the modem section of the chip */ + WRITE_RWA(7, 3); + WRITE_RWA(0x30, 0); + + /* disable the cdrom section of the chip */ + WRITE_RWA(7, 4); + WRITE_RWA(0x30, 0); + + /* disable the MPU-401 section of the chip */ + WRITE_RWA(7, 2); + WRITE_RWA(0x30, 0); +} + +static inline void rwa010_game_port_init(void) +{ + int i; + + WRITE_RWA(7, 5); + + dprintk("Slider base: "); + WRITE_RWA(0x61, 1); + i = inb(0x203); + + WRITE_RWA(0x60, 2); + dprintk("%02X%02X (201)\n", inb(0x203), i); + + WRITE_RWA(0x30, 1); +} + +static inline void rwa010_waveartist_init(int base, int irq, int dma) +{ + int i; + + WRITE_RWA(7, 0); + + dprintk("WaveArtist base: "); + WRITE_RWA(0x61, base); + i = inb(0x203); + + WRITE_RWA(0x60, base >> 8); + dprintk("%02X%02X (%X),", inb(0x203), i, base); + + WRITE_RWA(0x70, irq); + dprintk(" irq: %d (%d),", inb(0x203), irq); + + WRITE_RWA(0x74, dma); + dprintk(" dma: %d (%d)\n", inb(0x203), dma); + + WRITE_RWA(0x30, 1); +} + +static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, int dma) +{ + int i; + + WRITE_RWA(7, 1); + + dprintk("SoundBlaster base: "); + WRITE_RWA(0x61, sb_base); + i = inb(0x203); + + WRITE_RWA(0x60, sb_base >> 8); + dprintk("%02X%02X (%X),", inb(0x203), i, sb_base); + + dprintk(" irq: "); + WRITE_RWA(0x70, irq); + dprintk("%d (%d),", inb(0x203), irq); + + dprintk(" 8-bit DMA: "); + WRITE_RWA(0x74, dma); + dprintk("%d (%d)\n", inb(0x203), dma); + + dprintk("AdLib base: "); + WRITE_RWA(0x63, al_base); + i = inb(0x203); + + WRITE_RWA(0x62, al_base >> 8); + dprintk("%02X%02X (%X)\n", inb(0x203), i, al_base); + + WRITE_RWA(0x30, 1); +} + +static void rwa010_soundblaster_reset(void) +{ + int i; + + outb(1, 0x226); + udelay(3); + outb(0, 0x226); + + for (i = 0; i < 5; i++) { + if (inb(0x22e) & 0x80) + break; + mdelay(1); + } + if (i == 5) + printk("SoundBlaster: DSP reset failed\n"); + + dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a)); + + for (i = 0; i < 5; i++) { + if ((inb(0x22c) & 0x80) == 0) + break; + mdelay(1); + } + + if (i == 5) + printk("SoundBlaster: DSP not ready\n"); + else { + outb(0xe1, 0x22c); + + dprintk("SoundBlaster DSP id: "); + i = inb(0x22a); + udelay(1); + i |= inb(0x22a) << 8; + dprintk("%04X\n", i); + + for (i = 0; i < 5; i++) { + if ((inb(0x22c) & 0x80) == 0) + break; + mdelay(1); + } + + if (i == 5) + printk("SoundBlaster: could not turn speaker off\n"); + + outb(0xd3, 0x22c); + } + + /* turn on OPL3 */ + outb(5, 0x38a); + outb(1, 0x38b); +} + +static void __init rwa010_init(void) +{ + rwa010_unlock(); + rwa010_read_ident(); + rwa010_global_init(); + rwa010_game_port_init(); + rwa010_waveartist_init(0x250, 3, 7); + rwa010_soundblaster_init(0x220, 0x388, 3, 1); + rwa010_soundblaster_reset(); +} + +EXPORT_SYMBOL(gpio_lock); +EXPORT_SYMBOL(gpio_modify_op); +EXPORT_SYMBOL(gpio_modify_io); +EXPORT_SYMBOL(cpld_modify); + +/* + * Initialise any other hardware after we've got the PCI bus + * initialised. We may need the PCI bus to talk to this other + * hardware. + */ +static int __init nw_hw_init(void) +{ + if (machine_is_netwinder()) { + unsigned long flags; + + wb977_init(); + cpld_init(); + rwa010_init(); + + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); + spin_unlock_irqrestore(&gpio_lock, flags); + } + return 0; +} + +__initcall(nw_hw_init); diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/netwinder-leds.c linux/arch/arm/mach-footbridge/netwinder-leds.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/netwinder-leds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/netwinder-leds.c Tue Sep 5 12:56:51 2000 @@ -0,0 +1,137 @@ +/* + * linux/arch/arm/mach-footbridge/netwinder-leds.c + * + * Copyright (C) 1998-1999 Russell King + * + * NetWinder LED control routines. + * + * The Netwinder uses the leds as follows: + * - Green - toggles state every 50 timer interrupts + * - Red - On if the system is not idle + * + * Changelog: + * 02-05-1999 RMK Various cleanups + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 +static char led_state; +static char hw_led_state; + +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; +extern spinlock_t gpio_lock; + +static void netwinder_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + switch (evt) { + case led_start: + led_state |= LED_STATE_ENABLED; + hw_led_state = GPIO_GREEN_LED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = 0; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = 0; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= GPIO_GREEN_LED; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~GPIO_RED_LED; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= GPIO_RED_LED; + break; +#endif + + case led_halted: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= GPIO_RED_LED; + break; + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= GPIO_GREEN_LED; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~GPIO_GREEN_LED; + break; + + case led_amber_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED; + break; + + case led_amber_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED); + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= GPIO_RED_LED; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~GPIO_RED_LED; + break; + + default: + break; + } + + spin_unlock_irqrestore(&leds_lock, flags); + + if (led_state & LED_STATE_ENABLED) { + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state); + spin_unlock_irqrestore(&gpio_lock, flags); + } +} + +static int __init leds_init(void) +{ + if (machine_is_netwinder()) + leds_event = netwinder_leds_event; + + leds_event(led_start); + + return 0; +} + +__initcall(leds_init); diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/netwinder-pci.c linux/arch/arm/mach-footbridge/netwinder-pci.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/netwinder-pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/netwinder-pci.c Sun Sep 3 11:19:11 2000 @@ -0,0 +1,54 @@ +/* + * linux/arch/arm/mach-footbridge/netwinder-pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include +#include +#include + +#include +#include + +/* netwinder host-specific stuff */ +static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ +#define DEV(v,d) ((v)<<16|(d)) + switch (DEV(dev->vendor, dev->device)) { + case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): + case DEV(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885): + case DEV(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_YELLOWFIN): + return IRQ_NETWINDER_ETHER100; + + case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a): + return IRQ_NETWINDER_ETHER10; + + case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553): + return 0; + + case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105): + return IRQ_ISA_HARDDISK1; + + case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): + case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010): + case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000): + return IRQ_NETWINDER_VGA; + + case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285): + return 0; + + default: + printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n", + dev->bus->number, dev->devfn, + dev->vendor, dev->device); + return 0; + } +} + +struct hw_pci netwinder_pci __initdata = { + init: dc21285_init, + swizzle: no_swizzle, + map_irq: netwinder_map_irq, +}; diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/mach-footbridge/personal-pci.c linux/arch/arm/mach-footbridge/personal-pci.c --- v2.4.0-test7/linux/arch/arm/mach-footbridge/personal-pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/personal-pci.c Sun Sep 3 11:19:11 2000 @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/mach-footbridge/personal-pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include +#include +#include + +#include +#include + +static int irqmap_personal_server[] __initdata = { + IRQ_IN0, IRQ_IN1, IRQ_IN2, IRQ_IN3, 0, 0, 0, + IRQ_DOORBELLHOST, IRQ_DMA1, IRQ_DMA2, IRQ_PCI +}; + +static int __init personal_server_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + unsigned char line; + + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line); + + if (line > 0x40 && line <= 0x5f) { + /* line corresponds to the bit controlling this interrupt + * in the footbridge. Ignore the first 8 interrupt bits, + * look up the rest in the map. IN0 is bit number 8 + */ + return irqmap_personal_server[(line & 0x1f) - 8]; + } else if (line == 0) { + /* no interrupt */ + return 0; + } else + return irqmap_personal_server[(line - 1) & 3]; +} + +struct hw_pci personal_server_pci __initdata = { + init: dc21285_init, + swizzle: no_swizzle, + map_irq: personal_server_map_irq, +}; diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types --- v2.4.0-test7/linux/arch/arm/tools/mach-types Wed Aug 23 18:36:36 2000 +++ linux/arch/arm/tools/mach-types Sun Sep 3 11:19:11 2000 @@ -37,6 +37,11 @@ xp860 SA1100_XP860 XP860 30 cerf SA1100_CERF CERF 31 nanoengine SA1100_NANOENGINE NANOENGINE 32 +fpic SA1100_FPIC FPIC 33 +extenex1 SA1100_EXTENEX1 EXTENEX1 34 +sherman SA1100_SHERMAN SHERMAN 35 +accelent_sa SA1100_ACCELENT ACCELENT_SA 36 +accelent_l7200 ARCH_L7200_ACCELENT ACCELENT_L7200 37 # The following are unallocated empeg SA1100_EMPEG EMPEG diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/vmlinux-armo.lds.in linux/arch/arm/vmlinux-armo.lds.in --- v2.4.0-test7/linux/arch/arm/vmlinux-armo.lds.in Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/vmlinux-armo.lds.in Sun Sep 3 11:19:11 2000 @@ -79,9 +79,10 @@ .bss : { - __bss_start = .; /* BSS */ + __bss_start = .; /* BSS */ *(.bss) - _end = . ; + *(COMMON) + _end = . ; } /* Stabs debugging sections. */ diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in --- v2.4.0-test7/linux/arch/arm/vmlinux-armv.lds.in Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/vmlinux-armv.lds.in Sun Sep 3 11:19:11 2000 @@ -42,8 +42,8 @@ *(.text.lock) /* out-of-line lock text */ *(.rodata) *(.kstrtab) - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; + . = ALIGN(16); + __start___ex_table = .; /* Exception table */ *(__ex_table) __stop___ex_table = .; diff -u --recursive --new-file v2.4.0-test7/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.0-test7/linux/arch/i386/defconfig Wed Aug 23 18:36:36 2000 +++ linux/arch/i386/defconfig Sat Sep 2 11:45:00 2000 @@ -501,10 +501,6 @@ # # Multimedia devices # - -# -# Video For Linux -# # CONFIG_VIDEO_DEV is not set # diff -u --recursive --new-file v2.4.0-test7/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c --- v2.4.0-test7/linux/arch/i386/kernel/apic.c Wed Aug 23 18:36:36 2000 +++ linux/arch/i386/kernel/apic.c Mon Aug 28 11:57:29 2000 @@ -671,14 +671,7 @@ } #ifdef CONFIG_SMP - /* - * update_process_times() expects us to have done irq_enter(). - * Besides, if we don't timer interrupts ignore the global - * interrupt lock, which is the WrongThing (tm) to do. - */ - irq_enter(cpu, 0); update_process_times(user); - irq_exit(cpu, 0); #endif } @@ -706,17 +699,26 @@ void smp_apic_timer_interrupt(struct pt_regs * regs) { + int cpu = smp_processor_id(); + /* * the NMI deadlock-detector uses this. */ - apic_timer_irqs[smp_processor_id()]++; + apic_timer_irqs[cpu]++; /* * NOTE! We'd better ACK the irq immediately, * because timer handling can be slow. */ ack_APIC_irq(); + /* + * update_process_times() expects us to have done irq_enter(). + * Besides, if we don't timer interrupts ignore the global + * interrupt lock, which is the WrongThing (tm) to do. + */ + irq_enter(cpu, 0); smp_local_timer_interrupt(regs); + irq_exit(cpu, 0); } /* diff -u --recursive --new-file v2.4.0-test7/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.4.0-test7/linux/arch/i386/kernel/io_apic.c Wed Aug 23 18:36:36 2000 +++ linux/arch/i386/kernel/io_apic.c Tue Aug 29 14:10:53 2000 @@ -982,7 +982,10 @@ static void __init setup_ioapic_ids_from_mpc (void) { struct IO_APIC_reg_00 reg_00; + unsigned long phys_id_present_map = phys_cpu_present_map; int apic; + int i; + unsigned char old_id; /* * Set the IOAPIC ID to the value stored in the MPC table. @@ -992,6 +995,8 @@ /* Read the register 0 value */ *(int *)®_00 = io_apic_read(apic, 0); + old_id = mp_ioapics[apic].mpc_apicid; + if (mp_ioapics[apic].mpc_apicid >= 0xf) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", apic, mp_ioapics[apic].mpc_apicid); @@ -1001,20 +1006,40 @@ } /* + * Sanity check, is the ID really free? Every APIC in a + * system must have a unique ID or we get lots of nice + * 'stuck on smp_invalidate_needed IPI wait' messages. + */ + if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) { + printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", + apic, mp_ioapics[apic].mpc_apicid); + for (i = 0; i < 0xf; i++) + if (!(phys_id_present_map & (1 << i))) + break; + if (i >= 0xf) + panic("Max APIC ID exceeded!\n"); + printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", + i); + phys_id_present_map |= 1 << i; + mp_ioapics[apic].mpc_apicid = i; + } + + /* + * We need to adjust the IRQ routing table + * if the ID changed. + */ + if (old_id != mp_ioapics[apic].mpc_apicid) + for (i = 0; i < mp_irq_entries; i++) + if (mp_irqs[i].mpc_dstapic == old_id) + mp_irqs[i].mpc_dstapic + = mp_ioapics[apic].mpc_apicid; + + /* * Read the right value from the MPC table and * write it into the ID register. */ printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", mp_ioapics[apic].mpc_apicid); - - /* - * Sanity check, is the ID really free? Every APIC in the - * system must have a unique ID or we get lots of nice - * 'stuck on smp_invalidate_needed IPI wait' messages. - */ - if (phys_cpu_present_map & (1< GS*4) regno -= 2*4; diff -u --recursive --new-file v2.4.0-test7/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.0-test7/linux/arch/i386/kernel/setup.c Wed Aug 23 18:36:36 2000 +++ linux/arch/i386/kernel/setup.c Wed Sep 6 14:05:57 2000 @@ -1650,6 +1650,7 @@ int i, n; for (n = 0; n < NR_CPUS; n++, c++) { + int fpu_exception; #ifdef CONFIG_SMP if (!(cpu_online_map & (1<x86_capability & X86_FEATURE_SEP) && c->x86_model < 3 && c->x86_mask < 3; - + + /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ + fpu_exception = c->hard_math && (ignore_irq13 | (c->x86_capability & X86_FEATURE_FPU)); p += sprintf(p, "fdiv_bug\t: %s\n" "hlt_bug\t\t: %s\n" "sep_bug\t\t: %s\n" @@ -1739,7 +1742,7 @@ c->f00f_bug ? "yes" : "no", c->coma_bug ? "yes" : "no", c->hard_math ? "yes" : "no", - (c->hard_math && ignore_irq13) ? "yes" : "no", + fpu_exception ? "yes" : "no", c->cpuid_level, c->wp_works_ok ? "yes" : "no"); diff -u --recursive --new-file v2.4.0-test7/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.4.0-test7/linux/arch/i386/kernel/signal.c Mon Jul 10 16:47:19 2000 +++ linux/arch/i386/kernel/signal.c Fri Sep 1 14:10:57 2000 @@ -682,7 +682,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.4.0-test7/linux/arch/i386/kernel/smpboot.c Wed Aug 23 18:36:36 2000 +++ linux/arch/i386/kernel/smpboot.c Tue Sep 5 13:50:02 2000 @@ -497,7 +497,7 @@ * don't care about the eip and regs settings since * we'll never reschedule the forked task. */ - return do_fork(CLONE_VM|CLONE_PID, 0, ®s); + return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } #if APIC_DEBUG diff -u --recursive --new-file v2.4.0-test7/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.4.0-test7/linux/arch/i386/kernel/traps.c Wed Aug 9 19:19:49 2000 +++ linux/arch/i386/kernel/traps.c Wed Sep 6 13:51:55 2000 @@ -641,7 +641,6 @@ */ task = current; save_init_fpu(task); - load_mxcsr(0x1f80); task->thread.trap_no = 19; task->thread.error_code = 0; info.si_signo = SIGFPE; diff -u --recursive --new-file v2.4.0-test7/linux/arch/i386/lib/checksum.S linux/arch/i386/lib/checksum.S --- v2.4.0-test7/linux/arch/i386/lib/checksum.S Mon Mar 27 08:08:21 2000 +++ linux/arch/i386/lib/checksum.S Tue Sep 5 14:01:35 2000 @@ -394,26 +394,32 @@ movl ARGBASE+8(%esp),%edi #dst movl ARGBASE+12(%esp),%ecx #len movl ARGBASE+16(%esp),%eax #sum - movl %ecx, %edx +# movl %ecx, %edx movl %ecx, %ebx + movl %esi, %edx shrl $6, %ecx andl $0x3c, %ebx negl %ebx subl %ebx, %esi subl %ebx, %edi + lea -1(%esi),%edx + andl $-32,%edx lea 3f(%ebx,%ebx), %ebx testl %esi, %esi - jmp *%ebx + jmp *%ebx 1: addl $64,%esi addl $64,%edi + SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl) ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52) ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36) ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20) ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4) 3: adcl $0,%eax + addl $64, %edx dec %ecx jge 1b -4: andl $3, %edx +4: movl ARGBASE+12(%esp),%edx #len + andl $3, %edx jz 7f cmpl $2, %edx jb 5f diff -u --recursive --new-file v2.4.0-test7/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.4.0-test7/linux/arch/ia64/ia32/ia32_entry.S Wed Aug 23 18:36:36 2000 +++ linux/arch/ia64/ia32/ia32_entry.S Tue Sep 5 13:50:01 2000 @@ -91,8 +91,8 @@ UNW(.body) mov out1=0 - mov out2=0 - adds out3=IA64_SWITCH_STACK_SIZE+16,sp + mov out3=0 + adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s br.call.sptk.few rp=do_fork .ret3: mov ar.pfs=loc1 UNW(.restore sp) diff -u --recursive --new-file v2.4.0-test7/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.4.0-test7/linux/arch/ia64/kernel/entry.S Wed Aug 23 18:36:36 2000 +++ linux/arch/ia64/kernel/entry.S Tue Sep 5 13:50:01 2000 @@ -68,8 +68,8 @@ mov loc1=r16 // save ar.pfs across do_fork UNW(.body) mov out1=in1 - mov out2=in2 - adds out3=IA64_SWITCH_STACK_SIZE+16,sp // out3 = ®s + mov out3=in2 + adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags br.call.sptk.few rp=do_fork .ret1: UNW(.restore sp) @@ -87,8 +87,8 @@ mov loc1=r16 // save ar.pfs across do_fork UNW(.body) mov out1=in1 - mov out2=0 - adds out3=IA64_SWITCH_STACK_SIZE+16,sp // out3 = ®s + mov out3=0 + adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags br.call.sptk.few rp=do_fork .ret2: UNW(.restore sp) diff -u --recursive --new-file v2.4.0-test7/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c --- v2.4.0-test7/linux/arch/ia64/kernel/signal.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/signal.c Sun Sep 3 11:53:58 2000 @@ -570,7 +570,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- v2.4.0-test7/linux/arch/m68k/kernel/process.c Mon Jul 10 16:47:19 2000 +++ linux/arch/m68k/kernel/process.c Tue Sep 5 13:50:01 2000 @@ -181,12 +181,12 @@ asmlinkage int m68k_fork(struct pt_regs *regs) { - return do_fork(SIGCHLD, rdusp(), regs); + return do_fork(SIGCHLD, rdusp(), regs, 0); } asmlinkage int m68k_vfork(struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); } asmlinkage int m68k_clone(struct pt_regs *regs) @@ -199,10 +199,11 @@ newsp = regs->d2; if (!newsp) newsp = rdusp(); - return do_fork(clone_flags, newsp, regs); + return do_fork(clone_flags, newsp, regs, 0); } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; diff -u --recursive --new-file v2.4.0-test7/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v2.4.0-test7/linux/arch/m68k/kernel/signal.c Mon Jun 19 16:31:57 2000 +++ linux/arch/m68k/kernel/signal.c Sun Sep 3 11:50:52 2000 @@ -1137,7 +1137,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.4.0-test7/linux/arch/mips/kernel/irixelf.c Fri Jul 14 12:12:05 2000 +++ linux/arch/mips/kernel/irixelf.c Sun Sep 3 11:49:25 2000 @@ -1127,7 +1127,7 @@ notes[0].datasz = sizeof(prstatus); notes[0].data = &prstatus; prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; - prstatus.pr_sigpend = current->signal.sig[0]; + prstatus.pr_sigpend = current->pending.signal.sig[0]; prstatus.pr_sighold = current->blocked.sig[0]; psinfo.pr_pid = prstatus.pr_pid = current->pid; psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c --- v2.4.0-test7/linux/arch/mips/kernel/irixsig.c Mon Jul 10 16:47:19 2000 +++ linux/arch/mips/kernel/irixsig.c Sun Sep 3 11:50:03 2000 @@ -264,7 +264,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); @@ -429,24 +429,7 @@ asmlinkage int irix_sigpending(irix_sigset_t *set) { - int err; - - if (verify_area(VERIFY_WRITE, set, sizeof(*set)) < 0) - return -EFAULT; - - /* fill in "set" with signals pending but blocked. */ - spin_lock_irq(¤t->sigmask_lock); - err = __put_user(current->blocked.sig[0] & current->signal.sig[0], - &set->sig[0]); - err |= __put_user(current->blocked.sig[1] & current->signal.sig[1], - &set->sig[1]); - err |= __put_user(current->blocked.sig[2] & current->signal.sig[2], - &set->sig[2]); - err |= __put_user(current->blocked.sig[3] & current->signal.sig[3], - &set->sig[3]); - spin_unlock_irq(¤t->sigmask_lock); - - return err; + return do_sigpending(set, sizeof(*set)); } asmlinkage int irix_sigprocmask(int how, irix_sigset_t *new, irix_sigset_t *old) @@ -605,7 +588,7 @@ expire = schedule_timeout(expire); for (i=0; i<=4; i++) - tmp |= (current->signal.sig[i] & kset.sig[i]); + tmp |= (current->pending.signal.sig[i] & kset.sig[i]); if (tmp) break; @@ -622,7 +605,7 @@ for(sig = 1; i <= 65 /* IRIX_NSIG */; sig++) { if (sigismember (&kset, sig)) continue; - if (sigismember (¤t->signal, sig)) { + if (sigismember (¤t->pending.signal, sig)) { /* XXX need more than this... */ if (info) info->sig = sig; diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- v2.4.0-test7/linux/arch/mips/kernel/process.c Mon Jul 10 16:47:19 2000 +++ linux/arch/mips/kernel/process.c Tue Sep 5 13:50:02 2000 @@ -72,6 +72,7 @@ } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c --- v2.4.0-test7/linux/arch/mips/kernel/signal.c Mon Jul 10 16:47:19 2000 +++ linux/arch/mips/kernel/signal.c Sun Sep 3 11:49:09 2000 @@ -662,7 +662,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c --- v2.4.0-test7/linux/arch/mips/kernel/syscall.c Mon Jul 10 16:47:19 2000 +++ linux/arch/mips/kernel/syscall.c Tue Sep 5 13:50:02 2000 @@ -97,7 +97,7 @@ int res; save_static(®s); - res = do_fork(SIGCHLD, regs.regs[29], ®s); + res = do_fork(SIGCHLD, regs.regs[29], ®s, 0); return res; } @@ -112,7 +112,7 @@ newsp = regs.regs[5]; if (!newsp) newsp = regs.regs[29]; - res = do_fork(clone_flags, newsp, ®s); + res = do_fork(clone_flags, newsp, ®s, 0); return res; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c --- v2.4.0-test7/linux/arch/mips64/kernel/process.c Fri Jul 14 12:12:05 2000 +++ linux/arch/mips64/kernel/process.c Tue Sep 5 13:50:01 2000 @@ -69,6 +69,7 @@ } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips64/kernel/signal.c linux/arch/mips64/kernel/signal.c --- v2.4.0-test7/linux/arch/mips64/kernel/signal.c Mon Jul 10 16:47:20 2000 +++ linux/arch/mips64/kernel/signal.c Sun Sep 3 11:53:42 2000 @@ -695,7 +695,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips64/kernel/signal32.c linux/arch/mips64/kernel/signal32.c --- v2.4.0-test7/linux/arch/mips64/kernel/signal32.c Fri Jul 14 12:12:05 2000 +++ linux/arch/mips64/kernel/signal32.c Sun Sep 3 11:53:42 2000 @@ -773,7 +773,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/mips64/kernel/syscall.c linux/arch/mips64/kernel/syscall.c --- v2.4.0-test7/linux/arch/mips64/kernel/syscall.c Wed Aug 9 19:19:49 2000 +++ linux/arch/mips64/kernel/syscall.c Tue Sep 5 13:50:01 2000 @@ -77,7 +77,7 @@ int res; save_static(®s); - res = do_fork(SIGCHLD, regs.regs[29], ®s); + res = do_fork(SIGCHLD, regs.regs[29], ®s, 0); return res; } @@ -92,7 +92,7 @@ newsp = regs.regs[5]; if (!newsp) newsp = regs.regs[29]; - res = do_fork(clone_flags, newsp, ®s); + res = do_fork(clone_flags, newsp, ®s, 0); return res; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.4.0-test7/linux/arch/ppc/kernel/process.c Fri Jun 23 21:55:07 2000 +++ linux/arch/ppc/kernel/process.c Tue Sep 5 13:50:02 2000 @@ -315,6 +315,7 @@ */ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, struct task_struct * p, struct pt_regs * regs) { unsigned long msr; @@ -446,7 +447,7 @@ unsigned long clone_flags = p1; int res; lock_kernel(); - res = do_fork(clone_flags, regs->gpr[1], regs); + res = do_fork(clone_flags, regs->gpr[1], regs, 0); #ifdef CONFIG_SMP /* When we clone the idle task we keep the same pid but * the return value of 0 for both causes problems. @@ -465,7 +466,7 @@ int res; - res = do_fork(SIGCHLD, regs->gpr[1], regs); + res = do_fork(SIGCHLD, regs->gpr[1], regs, 0); #ifdef CONFIG_SMP /* When we clone the idle task we keep the same pid but * the return value of 0 for both causes problems. @@ -480,7 +481,7 @@ asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0); } asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, diff -u --recursive --new-file v2.4.0-test7/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.4.0-test7/linux/arch/ppc/kernel/signal.c Fri Jul 14 12:12:06 2000 +++ linux/arch/ppc/kernel/signal.c Sun Sep 3 11:50:26 2000 @@ -646,7 +646,7 @@ default: lock_kernel(); - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.4.0-test7/linux/arch/ppc/kernel/smp.c Fri Jul 14 12:12:06 2000 +++ linux/arch/ppc/kernel/smp.c Tue Sep 5 13:50:02 2000 @@ -347,7 +347,7 @@ /* create a process for the processor */ /* we don't care about the values in regs since we'll never reschedule the forked task. */ - if (do_fork(CLONE_VM|CLONE_PID, 0, ®s) < 0) + if (do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0) < 0) panic("failed fork for CPU %d", i); p = init_task.prev_task; if (!p) diff -u --recursive --new-file v2.4.0-test7/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c --- v2.4.0-test7/linux/arch/s390/kernel/process.c Wed Aug 9 19:19:49 2000 +++ linux/arch/s390/kernel/process.c Tue Sep 5 13:50:01 2000 @@ -264,6 +264,7 @@ } int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, + unsigned long unused, struct task_struct * p, struct pt_regs * regs) { struct stack_frame @@ -313,7 +314,7 @@ int ret; lock_kernel(); - ret = do_fork(SIGCHLD, regs.gprs[15], ®s); + ret = do_fork(SIGCHLD, regs.gprs[15], ®s, 0); unlock_kernel(); return ret; } @@ -329,7 +330,7 @@ newsp = regs.gprs[2]; if (!newsp) newsp = regs.gprs[15]; - ret = do_fork(clone_flags, newsp, ®s); + ret = do_fork(clone_flags, newsp, ®s, 0); unlock_kernel(); return ret; } @@ -347,7 +348,7 @@ asmlinkage int sys_vfork(struct pt_regs regs) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, - regs.gprs[15], ®s); + regs.gprs[15], ®s, 0); } /* diff -u --recursive --new-file v2.4.0-test7/linux/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c --- v2.4.0-test7/linux/arch/s390/kernel/signal.c Fri May 12 14:18:55 2000 +++ linux/arch/s390/kernel/signal.c Sun Sep 3 11:53:42 2000 @@ -528,7 +528,7 @@ default: lock_kernel(); - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c --- v2.4.0-test7/linux/arch/s390/kernel/smp.c Mon Jul 10 16:47:20 2000 +++ linux/arch/s390/kernel/smp.c Tue Sep 5 13:50:01 2000 @@ -528,7 +528,7 @@ /* don't care about the psw and regs settings since we'll never reschedule the forked task. */ memset(®s,sizeof(pt_regs),0); - return do_fork(CLONE_VM|CLONE_PID, 0, ®s); + return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } static void __init do_boot_cpu(int cpu) diff -u --recursive --new-file v2.4.0-test7/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.4.0-test7/linux/arch/sh/kernel/process.c Thu Jul 27 17:37:59 2000 +++ linux/arch/sh/kernel/process.c Tue Sep 5 13:50:01 2000 @@ -211,6 +211,7 @@ asmlinkage void ret_from_fork(void); int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs; @@ -292,7 +293,7 @@ unsigned long r6, unsigned long r7, struct pt_regs regs) { - return do_fork(SIGCHLD, regs.regs[15], ®s); + return do_fork(SIGCHLD, regs.regs[15], ®s, 0); } asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, @@ -301,7 +302,7 @@ { if (!newsp) newsp = regs.regs[15]; - return do_fork(clone_flags, newsp, ®s); + return do_fork(clone_flags, newsp, ®s, 0); } /* @@ -318,7 +319,7 @@ unsigned long r6, unsigned long r7, struct pt_regs regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], ®s); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], ®s, 0); } /* diff -u --recursive --new-file v2.4.0-test7/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c --- v2.4.0-test7/linux/arch/sh/kernel/signal.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sh/kernel/signal.c Sun Sep 3 11:53:42 2000 @@ -672,7 +672,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v2.4.0-test7/linux/arch/sparc/kernel/entry.S Fri Jun 23 21:55:08 2000 +++ linux/arch/sparc/kernel/entry.S Tue Sep 5 13:50:02 2000 @@ -1391,6 +1391,7 @@ mov %fp, %o1 ! arg1: usp std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr + mov 0, %o3 call C_LABEL(do_fork) mov %l5, %o7 @@ -1413,6 +1414,7 @@ 1: std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr + mov 0, %o3 call C_LABEL(do_fork) mov %l5, %o7 @@ -1430,6 +1432,7 @@ mov %fp, %o1 or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 sethi %hi(C_LABEL(do_fork)), %l1 + mov 0, %o3 jmpl %l1 + %lo(C_LABEL(do_fork)), %g0 add %sp, REGWIN_SZ, %o2 diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.4.0-test7/linux/arch/sparc/kernel/irq.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc/kernel/irq.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.106 2000/08/05 10:48:40 davem Exp $ +/* $Id: irq.c,v 1.107 2000/08/26 02:42:28 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -8,7 +8,7 @@ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com) * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) - * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com) */ #include @@ -196,41 +196,29 @@ } #ifdef CONFIG_SMP -/* SMP interrupt locking on Sparc. */ /* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; -/* This protects IRQ's. */ -spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; - -/* Global IRQ locking depth. */ -atomic_t global_irq_count = ATOMIC_INIT(0); - void smp_show_backtrace_all_cpus(void); void show_backtrace(void); -#define MAXCOUNT 100000000 #define VERBOSE_DEBUG_IRQLOCK +#define MAXCOUNT 100000000 static void show(char * str) { - int i; int cpu = smp_processor_id(); + int i; printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [ ", atomic_read(&global_irq_count)); - - for (i = 0; i < NR_CPUS; i++) { - printk("%d ", local_irq_count(i)); - } - printk("]\n"); - - printk("bh: %d [ ", (spin_is_locked(&global_bh_lock) ? 1 : 0)); - - for (i = 0; i < NR_CPUS; i++) { - printk("%d ", local_bh_count(cpu)); - } + printk("irq: %d [ ", irqs_running()); + for (i = 0; i < smp_num_cpus; i++) + printk("%u ", __brlock_array[i][BR_GLOBALIRQ_LOCK]); + printk("]\nbh: %d [ ", + (spin_is_locked(&global_bh_lock) ? 1 : 0)); + for (i = 0; i < smp_num_cpus; i++) + printk("%u ", local_bh_count(i)); printk("]\n"); #ifdef VERBOSE_DEBUG_IRQLOCK @@ -240,48 +228,11 @@ #endif } + /* * We have to allow irqs to arrive between __sti and __cli */ -#define SYNC_OTHER_CORES(x) udelay(x+1) - -static inline void wait_on_irq(int cpu) -{ - int count = MAXCOUNT; - - for (;;) { - /* - * Wait until all interrupts are gone. Wait - * for bottom half handlers unless we're - * already executing in one.. - */ - if (!atomic_read(&global_irq_count)) { - if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) - break; - } - - /* Duh, we have to loop. Release the lock to avoid deadlocks */ - spin_unlock(&global_irq_lock); - - for (;;) { - if (!--count) { - show("wait_on_irq"); - count = ~0; - } - __sti(); - SYNC_OTHER_CORES(cpu); - __cli(); - if (atomic_read(&global_irq_count)) - continue; - if (spin_is_locked (&global_irq_lock)) - continue; - if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) - continue; - if (spin_trylock(&global_irq_lock)) - break; - } - } -} +#define SYNC_OTHER_CORES(x) barrier() /* * This is called when we want to synchronize with @@ -292,8 +243,7 @@ */ void synchronize_irq(void) { - if (atomic_read(&global_irq_count)) { - /* Stupid approach */ + if (irqs_running()) { cli(); sti(); } @@ -301,32 +251,37 @@ static inline void get_irqlock(int cpu) { - int count = MAXCOUNT; + int count; - if (!spin_trylock(&global_irq_lock)) { - /* do we already hold the lock? */ - if ((unsigned char) cpu == global_irq_holder) - return; - /* Uhhuh.. Somebody else got it. Wait.. */ - do { - while (spin_is_locked(&global_irq_lock)) { - if (!--count) { - show("get_irqlock"); - count = ~0; - } - barrier(); + if ((unsigned char)cpu == global_irq_holder) + return; + + count = MAXCOUNT; +again: + br_write_lock(BR_GLOBALIRQ_LOCK); + for (;;) { + spinlock_t *lock; + + if (!irqs_running() && + (local_bh_count(smp_processor_id()) || !spin_is_locked(&global_bh_lock))) + break; + + br_write_unlock(BR_GLOBALIRQ_LOCK); + lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock; + while (irqs_running() || + spin_is_locked(lock) || + (!local_bh_count(smp_processor_id()) && spin_is_locked(&global_bh_lock))) { + if (!--count) { + show("get_irqlock"); + count = (~0 >> 1); } - } while (!spin_trylock(&global_irq_lock)); + __sti(); + SYNC_OTHER_CORES(cpu); + __cli(); + } + goto again; } - /* - * We also to make sure that nobody else is running - * in an interrupt context. - */ - wait_on_irq(cpu); - - /* - * Ok, finally.. - */ + global_irq_holder = cpu; } @@ -344,7 +299,7 @@ */ void __global_cli(void) { - unsigned int flags; + unsigned long flags; __save_flags(flags); @@ -374,9 +329,7 @@ */ unsigned long __global_save_flags(void) { - int retval; - int local_enabled = 0; - unsigned long flags; + unsigned long flags, local_enabled, retval; __save_flags(flags); diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.4.0-test7/linux/arch/sparc/kernel/process.c Fri Jul 14 12:12:07 2000 +++ linux/arch/sparc/kernel/process.c Tue Sep 5 13:50:02 2000 @@ -462,6 +462,7 @@ #endif int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long unused, struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs; diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.4.0-test7/linux/arch/sparc/kernel/signal.c Mon Jul 10 16:47:20 2000 +++ linux/arch/sparc/kernel/signal.c Sun Sep 3 11:48:44 2000 @@ -1282,7 +1282,7 @@ #endif /* fall through */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.4.0-test7/linux/arch/sparc/kernel/sparc_ksyms.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc/kernel/sparc_ksyms.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.102 2000/08/05 10:48:40 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.103 2000/08/26 02:42:28 anton Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -111,13 +111,6 @@ EXPORT_SYMBOL_PRIVATE(_rw_read_exit); EXPORT_SYMBOL_PRIVATE(_rw_write_enter); #endif -#ifdef CONFIG_SMP -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_cli); -#endif - /* rw semaphores */ EXPORT_SYMBOL_NOVERS(___down_read); EXPORT_SYMBOL_NOVERS(___down_write); @@ -137,14 +130,17 @@ EXPORT_SYMBOL_PRIVATE(_set_le_bit); EXPORT_SYMBOL_PRIVATE(_clear_le_bit); -/* IRQ implementation. */ #ifdef CONFIG_SMP +/* Kernel wide locking */ EXPORT_SYMBOL(kernel_flag); + +/* IRQ implementation. */ EXPORT_SYMBOL(global_irq_holder); -EXPORT_SYMBOL(global_irq_lock); -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); #endif EXPORT_SYMBOL(udelay); diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.4.0-test7/linux/arch/sparc/mm/srmmu.c Wed Aug 23 18:36:36 2000 +++ linux/arch/sparc/mm/srmmu.c Tue Aug 29 12:41:12 2000 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.221 2000/08/14 00:46:13 anton Exp $ +/* $Id: srmmu.c,v 1.222 2000/08/29 08:59:23 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1323,8 +1323,8 @@ mapping = file->f_dentry->d_inode->i_mapping; offset = (address & PAGE_MASK) - vma->vm_start; spin_lock(&mapping->i_shared_lock); - vmaring = mapping->i_mmap; - do { + vmaring = mapping->i_mmap_shared; + if (vmaring != NULL) do { /* Do not mistake ourselves as another mapping. */ if(vmaring == vma) continue; diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.4.0-test7/linux/arch/sparc/mm/sun4c.c Wed Aug 23 18:36:36 2000 +++ linux/arch/sparc/mm/sun4c.c Tue Aug 29 12:41:12 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.198 2000/08/14 00:46:13 anton Exp $ +/* $Id: sun4c.c,v 1.199 2000/08/29 08:59:23 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -2404,8 +2404,8 @@ mapping = vma->vm_file->f_dentry->d_inode->i_mapping; spin_lock(&mapping->i_shared_lock); - vmaring = mapping->i_mmap; - do { + vmaring = mapping->i_mmap_shared; + if (vmaring != NULL) do { unsigned long vaddr = vmaring->vm_start + offset; unsigned long start; diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c --- v2.4.0-test7/linux/arch/sparc/prom/console.c Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc/prom/console.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.22 2000/02/08 20:24:23 davem Exp $ +/* $Id: console.c,v 1.23 2000/08/26 02:38:03 anton Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * @@ -30,7 +30,7 @@ int i = -1; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: case PROM_SUN4: @@ -49,7 +49,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return i; /* Ugh, we could spin forever on unsupported proms ;( */ } @@ -63,7 +63,7 @@ unsigned long flags; int i = -1; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: case PROM_SUN4: @@ -82,7 +82,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return i; /* Ugh, we could spin forever on unsupported proms ;( */ } @@ -125,10 +125,10 @@ return PROMDEV_I_UNK; }; case PROM_V3: - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); if(prom_node_has_property(st_p, "keyboard")) return PROMDEV_IKBD; if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) { @@ -174,10 +174,10 @@ break; case PROM_V2: case PROM_V3: - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); if (propl >= 0 && propl == sizeof("display") && strncmp("display", propb, sizeof("display")) == 0) diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/prom/devmap.c linux/arch/sparc/prom/devmap.c --- v2.4.0-test7/linux/arch/sparc/prom/devmap.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/prom/devmap.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: devmap.c,v 1.6 1998/03/09 14:04:23 jj Exp $ +/* $Id: devmap.c,v 1.7 2000/08/26 02:38:03 anton Exp $ * promdevmap.c: Map device/IO areas to virtual addresses. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -29,13 +29,13 @@ unsigned long flags; char *ret; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); if((num_bytes == 0) || (paddr == 0)) ret = (char *) 0x0; else ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr, num_bytes); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return ret; } @@ -46,9 +46,9 @@ unsigned long flags; if(num_bytes == 0x0) return; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); (*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/prom/devops.c linux/arch/sparc/prom/devops.c --- v2.4.0-test7/linux/arch/sparc/prom/devops.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/prom/devops.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: devops.c,v 1.12 2000/01/29 01:09:12 anton Exp $ +/* $Id: devops.c,v 1.13 2000/08/26 02:38:03 anton Exp $ * devops.c: Device operations using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -21,7 +21,7 @@ { int handle; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: handle = (*(romvec->pv_v0devops.v0_devopen))(dstr); @@ -36,7 +36,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return handle; } @@ -46,7 +46,7 @@ prom_devclose(int dhandle) { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: (*(romvec->pv_v0devops.v0_devclose))(dhandle); @@ -59,7 +59,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return 0; } @@ -70,7 +70,7 @@ prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: (*(romvec->pv_v0devops.v0_seekdev))(dhandle, seekhi, seeklo); @@ -83,7 +83,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c --- v2.4.0-test7/linux/arch/sparc/prom/misc.c Tue Aug 4 16:03:35 1998 +++ linux/arch/sparc/prom/misc.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.17 1998/07/21 10:36:22 jj Exp $ +/* $Id: misc.c,v 1.18 2000/08/26 02:38:03 anton Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -15,16 +15,18 @@ extern void restore_current(void); +spinlock_t prom_lock = SPIN_LOCK_UNLOCKED; + /* Reset and reboot the machine with the command 'bcommand'. */ void prom_reboot(char *bcommand) { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); (*(romvec->pv_reboot))(bcommand); /* Never get here. */ restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); } /* Forth evaluate the expression contained in 'fstring'. */ @@ -34,13 +36,13 @@ unsigned long flags; if(!fstring || fstring[0] == 0) return; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); if(prom_vers == PROM_V0) (*(romvec->pv_fortheval.v0_eval))(strlen(fstring), fstring); else (*(romvec->pv_fortheval.v2_eval))(fstring); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); } /* We want to do this more nicely some day. */ @@ -66,10 +68,10 @@ prom_palette (1); #endif install_obp_ticker(); - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); (*(romvec->pv_abort))(); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); install_linux_ticker(); #ifdef CONFIG_SUN_AUXIO TURN_ON_LED; @@ -88,11 +90,11 @@ { unsigned long flags; again: - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); (*(romvec->pv_halt))(); /* Never get here. */ restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); goto again; /* PROM is out to get me -DaveM */ } diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/prom/mp.c linux/arch/sparc/prom/mp.c --- v2.4.0-test7/linux/arch/sparc/prom/mp.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/prom/mp.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: mp.c,v 1.11 2000/01/29 01:09:12 anton Exp $ +/* $Id: mp.c,v 1.12 2000/08/26 02:38:03 anton Exp $ * mp.c: OpenBoot Prom Multiprocessor support routines. Don't call * these on a UP or else you will halt and catch fire. ;) * @@ -25,7 +25,7 @@ int ret; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: case PROM_V2: @@ -37,7 +37,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return ret; } @@ -51,7 +51,7 @@ int ret; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: case PROM_V2: @@ -63,7 +63,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return ret; } @@ -77,7 +77,7 @@ int ret; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: case PROM_V2: @@ -89,7 +89,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return ret; } @@ -103,7 +103,7 @@ int ret; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: case PROM_V2: @@ -115,7 +115,7 @@ break; }; restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return ret; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/prom/segment.c linux/arch/sparc/prom/segment.c --- v2.4.0-test7/linux/arch/sparc/prom/segment.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/prom/segment.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: segment.c,v 1.6 1998/03/09 14:04:27 jj Exp $ +/* $Id: segment.c,v 1.7 2000/08/26 02:38:03 anton Exp $ * segment.c: Prom routine to map segments in other contexts before * a standalone is completely mapped. This is for sun4 and * sun4c architectures only. @@ -21,9 +21,9 @@ prom_putsegment(int ctx, unsigned long vaddr, int segment) { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c --- v2.4.0-test7/linux/arch/sparc/prom/tree.c Sun Oct 4 10:22:43 1998 +++ linux/arch/sparc/prom/tree.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.25 1998/09/17 11:04:58 jj Exp $ +/* $Id: tree.c,v 1.26 2000/08/26 02:38:03 anton Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * @@ -26,10 +26,10 @@ unsigned long flags; int cnode; - save_and_cli(flags); + spin_lock_irqsave(&prom_lock, flags); cnode = prom_nodeops->no_child(node); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return cnode; } @@ -57,10 +57,10 @@ unsigned long flags; int cnode; - save_and_cli(flags); + spin_lock_irqsave(&prom_lock, flags); cnode = prom_nodeops->no_nextnode(node); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return cnode; } @@ -93,10 +93,10 @@ if((!node) || (!prop)) return -1; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); ret = prom_nodeops->no_proplen(node, prop); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return ret; } @@ -113,10 +113,10 @@ if((plen > bufsize) || (plen == 0) || (plen == -1)) return -1; /* Ok, things seem all right. */ - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); ret = prom_nodeops->no_getprop(node, prop, buffer); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return ret; } @@ -226,10 +226,10 @@ unsigned long flags; char *prop; - save_and_cli(flags); + spin_lock_irqsave(&prom_lock, flags); prop = prom_nodeops->no_nextprop(node, oprop); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return prop; } @@ -325,10 +325,10 @@ if(size == 0) return 0; if((pname == 0) || (value == 0)) return 0; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); ret = prom_nodeops->no_setprop(node, pname, value, size); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); return ret; } @@ -337,10 +337,10 @@ int node; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&prom_lock, flags); node = (*romvec->pv_v2devops.v2_inst2pkg)(inst); restore_current(); - restore_flags(flags); + spin_unlock_irqrestore(&prom_lock, flags); if (node == -1) return 0; return node; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.4.0-test7/linux/arch/sparc64/defconfig Wed Aug 23 18:36:36 2000 +++ linux/arch/sparc64/defconfig Mon Aug 28 12:00:08 2000 @@ -158,11 +158,9 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set -# CONFIG_INET_ECN is not set +CONFIG_INET_ECN=y # CONFIG_SYN_COOKIES is not set CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set @@ -345,6 +343,7 @@ CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_BONDING=m +CONFIG_TUN=m CONFIG_PPP=m # CONFIG_PPP_ASYNC is not set # CONFIG_PPP_SYNC_TTY is not set @@ -453,8 +452,7 @@ CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -CONFIG_SMB_FS=m -CONFIG_SMB_NLS_REMOTE="" +# CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.4.0-test7/linux/arch/sparc64/kernel/entry.S Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/entry.S Tue Sep 5 13:50:01 2000 @@ -911,7 +911,7 @@ mov SIGCHLD, %o0 sys_clone: flushw movrz %o1, %fp, %o1 - nop + mov 0, %o3 ba,pt %xcc, do_fork add %sp, STACK_BIAS + REGWIN_SZ, %o2 ret_from_syscall: diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.4.0-test7/linux/arch/sparc64/kernel/irq.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/irq.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.91 2000/08/05 10:48:40 davem Exp $ +/* $Id: irq.c,v 1.92 2000/08/26 02:42:28 anton Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -608,7 +608,7 @@ spin_is_locked(lock) || (!local_bh_count(smp_processor_id()) && spin_is_locked(&global_bh_lock))) { if (!--count) { - show("wait_on_irq"); + show("get_irqlock"); count = (~0 >> 1); } __sti(); diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.4.0-test7/linux/arch/sparc64/kernel/process.c Wed Aug 23 18:36:36 2000 +++ linux/arch/sparc64/kernel/process.c Tue Sep 5 13:50:01 2000 @@ -573,6 +573,7 @@ * do_fork(). */ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long unused, struct task_struct *p, struct pt_regs *regs) { struct thread_struct *t = &p->thread; diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.4.0-test7/linux/arch/sparc64/kernel/signal.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/signal.c Sun Sep 3 11:51:53 2000 @@ -784,7 +784,7 @@ #endif /* fall through */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.4.0-test7/linux/arch/sparc64/kernel/signal32.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/signal32.c Sun Sep 3 11:51:10 2000 @@ -1420,7 +1420,7 @@ #endif /* fall through */ default: - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.4.0-test7/linux/arch/sparc64/kernel/sys_sparc.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/sys_sparc.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.45 2000/07/30 23:12:24 davem Exp $ +/* $Id: sys_sparc.c,v 1.46 2000/08/29 07:01:54 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -398,13 +398,18 @@ return -EINVAL; if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) { if (old_p) { - if (!current->thread.utraps) - put_user_ret(NULL, old_p, -EFAULT); - else - put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT); + if (!current->thread.utraps) { + if (put_user(NULL, old_p)) + return -EFAULT; + } else { + if (put_user((utrap_handler_t)(current->thread.utraps[type]), old_p)) + return -EFAULT; + } + } + if (old_d) { + if (put_user(NULL, old_d)) + return -EFAULT; } - if (old_d) - put_user_ret(NULL, old_d, -EFAULT); return 0; } if (!current->thread.utraps) { @@ -431,11 +436,14 @@ UT_TRAP_INSTRUCTION_31*sizeof(long)); } } - if (old_p) - put_user_ret((utrap_handler_t)(current->thread.utraps[type]), - old_p, -EFAULT); - if (old_d) - put_user_ret(NULL, old_d, -EFAULT); + if (old_p) { + if (put_user((utrap_handler_t)(current->thread.utraps[type]), old_p)) + return -EFAULT; + } + if (old_d) { + if (put_user(NULL, old_d)) + return -EFAULT; + } current->thread.utraps[type] = (long)new_p; return 0; diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c --- v2.4.0-test7/linux/arch/sparc64/solaris/fs.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/solaris/fs.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: fs.c,v 1.22 2000/07/28 12:15:02 davem Exp $ +/* $Id: fs.c,v 1.23 2000/08/29 07:01:54 davem Exp $ * fs.c: fs related syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -612,20 +612,25 @@ case SOL_F_SETLKW: cmd = F_SETLKW; break; } - get_user_ret (f.l_type, &((struct sol_flock *)A(arg))->l_type, -EFAULT); - __get_user_ret (f.l_whence, &((struct sol_flock *)A(arg))->l_whence, -EFAULT); - __get_user_ret (f.l_start, &((struct sol_flock *)A(arg))->l_start, -EFAULT); - __get_user_ret (f.l_len, &((struct sol_flock *)A(arg))->l_len, -EFAULT); - __get_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT); + if (get_user (f.l_type, &((struct sol_flock *)A(arg))->l_type) || + __get_user (f.l_whence, &((struct sol_flock *)A(arg))->l_whence) || + __get_user (f.l_start, &((struct sol_flock *)A(arg))->l_start) || + __get_user (f.l_len, &((struct sol_flock *)A(arg))->l_len) || + __get_user (f.l_pid, &((struct sol_flock *)A(arg))->l_sysid)) + return -EFAULT; + set_fs(KERNEL_DS); ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs(old_fs); - __put_user_ret (f.l_type, &((struct sol_flock *)A(arg))->l_type, -EFAULT); - __put_user_ret (f.l_whence, &((struct sol_flock *)A(arg))->l_whence, -EFAULT); - __put_user_ret (f.l_start, &((struct sol_flock *)A(arg))->l_start, -EFAULT); - __put_user_ret (f.l_len, &((struct sol_flock *)A(arg))->l_len, -EFAULT); - __put_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_pid, -EFAULT); - __put_user_ret (0, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT); + + if (__put_user (f.l_type, &((struct sol_flock *)A(arg))->l_type) || + __put_user (f.l_whence, &((struct sol_flock *)A(arg))->l_whence) || + __put_user (f.l_start, &((struct sol_flock *)A(arg))->l_start) || + __put_user (f.l_len, &((struct sol_flock *)A(arg))->l_len) || + __put_user (f.l_pid, &((struct sol_flock *)A(arg))->l_pid) || + __put_user (0, &((struct sol_flock *)A(arg))->l_sysid)) + return -EFAULT; + return ret; } case SOL_F_FREESP: @@ -634,7 +639,9 @@ int (*sys_newftruncate)(unsigned int, unsigned long)= (int (*)(unsigned int, unsigned long))SYS(ftruncate); - get_user_ret(length, &((struct sol_flock*)A(arg))->l_start, -EFAULT); + if (get_user(length, &((struct sol_flock*)A(arg))->l_start)) + return -EFAULT; + return sys_newftruncate(fd, length); } }; diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c --- v2.4.0-test7/linux/arch/sparc64/solaris/misc.c Wed Aug 23 18:36:36 2000 +++ linux/arch/sparc64/solaris/misc.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.29 2000/08/14 23:50:31 anton Exp $ +/* $Id: misc.c,v 1.30 2000/08/29 07:01:54 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -139,12 +139,14 @@ int i, len = (countfrom) ? \ ((sizeof(to) > sizeof(from) ? \ sizeof(from) : sizeof(to))) : sizeof(to); \ - copy_to_user_ret(to, from, len, -EFAULT); \ + if (copy_to_user(to, from, len)) \ + return -EFAULT; \ if (dotchop) \ for (p=from,i=0; *p && *p != '.' && --len; p++,i++); \ else \ i = len - 1; \ - __put_user_ret('\0', (char *)(to+i), -EFAULT); \ + if (__put_user('\0', (char *)(to+i))) \ + return -EFAULT; \ } struct sol_uname { @@ -297,10 +299,13 @@ } len = strlen(r) + 1; if (count < len) { - copy_to_user_ret((char *)A(buf), r, count - 1, -EFAULT); - __put_user_ret(0, (char *)A(buf) + count - 1, -EFAULT); - } else - copy_to_user_ret((char *)A(buf), r, len, -EFAULT); + if (copy_to_user((char *)A(buf), r, count - 1) || + __put_user(0, (char *)A(buf) + count - 1)) + return -EFAULT; + } else { + if (copy_to_user((char *)A(buf), r, len)) + return -EFAULT; + } return len; } diff -u --recursive --new-file v2.4.0-test7/linux/arch/sparc64/solaris/signal.c linux/arch/sparc64/solaris/signal.c --- v2.4.0-test7/linux/arch/sparc64/solaris/signal.c Mon Jan 12 15:15:44 1998 +++ linux/arch/sparc64/solaris/signal.c Sun Sep 3 11:42:36 2000 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.5 1997/12/15 15:04:59 jj Exp $ +/* $Id: signal.c,v 1.6 2000/08/29 07:01:54 davem Exp $ * signal.c: Signal emulation for Solaris * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -311,7 +311,7 @@ switch (which) { case 1: /* sigpending */ spin_lock_irq(¤t->sigmask_lock); - sigandsets(&s, ¤t->blocked, ¤t->signal); + sigandsets(&s, ¤t->blocked, ¤t->pending.signal); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); break; @@ -368,9 +368,13 @@ if (info) { struct sol_siginfo *s = (struct sol_siginfo *)A(info); - if (get_user (status, (unsigned int *)A(info))) return -EFAULT; - __put_user_ret (SOLARIS_SIGCLD, &s->si_signo, -EFAULT); - __put_user_ret (ret, &s->_data._proc._pid, -EFAULT); + if (get_user (status, (unsigned int *)A(info))) + return -EFAULT; + + if (__put_user (SOLARIS_SIGCLD, &s->si_signo) || + __put_user (ret, &s->_data._proc._pid)) + return -EFAULT; + switch (status & 0xff) { case 0: ret = SOLARIS_CLD_EXITED; status = (status >> 8) & 0xff; @@ -390,8 +394,10 @@ status = linux_to_solaris_signals[status & 0x7f]; break; } - __put_user_ret (ret, &s->si_code, -EFAULT); - __put_user_ret (status, &s->_data._proc._pdata._cld._status, -EFAULT); + + if (__put_user (ret, &s->si_code) || + __put_user (status, &s->_data._proc._pdata._cld._status)) + return -EFAULT; } return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.4.0-test7/linux/drivers/block/floppy.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/floppy.c Mon Aug 28 21:31:47 2000 @@ -118,6 +118,12 @@ * being used to store jiffies, which are unsigned longs). */ +/* + * 2000/08/28 -- Arnaldo Carvalho de Melo + * - get rid of check_region + * - s/suser/capable/ + */ + #define FLOPPY_SANITY_CHECK #undef FLOPPY_SILENT_DCL_CLEAR @@ -3497,7 +3503,7 @@ /* permission checks */ if (((cmd & 0x40) && !(filp->f_mode & 2)) || - ((cmd & 0x80) && !suser())) + ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))) return -EPERM; /* copyin */ @@ -4299,23 +4305,14 @@ for (fdc=0; fdc< N_FDC; fdc++){ if (FDCS->address != -1){ - if (check_region(FDCS->address, 6) < 0 || - check_region(FDCS->address+7, 1) < 0) { + if (!request_region(FDCS->address, 6, "floppy")) { DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address); - fd_free_irq(); - fd_free_dma(); - while(--fdc >= 0) { - release_region(FDCS->address, 6); - release_region(FDCS->address+7, 1); - } - MOD_DEC_USE_COUNT; - spin_lock_irqsave(&floppy_usage_lock, flags); - usage_count--; - spin_unlock_irqrestore(&floppy_usage_lock, flags); - return -1; + goto cleanup1; + } + if (!request_region(FDCS->address + 7, 1, "floppy DIR")) { + DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 7); + goto cleanup2; } - request_region(FDCS->address, 6, "floppy"); - request_region(FDCS->address+7, 1, "floppy DIR"); /* address + 6 is reserved, and may be taken by IDE. * Unfortunately, Adaptec doesn't know this :-(, */ } @@ -4339,6 +4336,20 @@ fdc = 0; irqdma_allocated = 1; return 0; +cleanup2: + release_region(FDCS->address, 6); +cleanup1: + fd_free_irq(); + fd_free_dma(); + while(--fdc >= 0) { + release_region(FDCS->address, 6); + release_region(FDCS->address + 7, 1); + } + MOD_DEC_USE_COUNT; + spin_lock_irqsave(&floppy_usage_lock, flags); + usage_count--; + spin_unlock_irqrestore(&floppy_usage_lock, flags); + return -1; } static void floppy_release_irq_and_dma(void) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.4.0-test7/linux/drivers/block/loop.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/loop.c Tue Sep 5 14:07:30 2000 @@ -357,7 +357,7 @@ if (current_request->cmd == WRITE) { mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } brelse(bh); dest_addr += size; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/block/lvm.c linux/drivers/block/lvm.c --- v2.4.0-test7/linux/drivers/block/lvm.c Fri Jul 14 12:12:08 2000 +++ linux/drivers/block/lvm.c Tue Sep 5 13:56:57 2000 @@ -299,6 +299,11 @@ static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; +static devfs_handle_t lvm_devfs_handle; +static devfs_handle_t vg_devfs_handle[MAX_VG]; +static devfs_handle_t ch_devfs_handle[MAX_VG]; +static devfs_handle_t lv_devfs_handle[MAX_LV]; + static struct file_operations lvm_chr_fops = { owner: THIS_MODULE, @@ -358,13 +363,18 @@ printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); return -EIO; } - if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) - { + if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) { printk("%s -- register_blkdev failed\n", lvm_name); if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); return -EIO; } + + lvm_devfs_handle = devfs_register( + 0 , "lvm", 0, 0, LVM_CHAR_MAJOR, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_chr_fops, NULL); + #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS create_proc_info_entry(LVM_NAME, S_IFREG | S_IRUGO, &proc_root, lvm_proc_get_info_ptr); @@ -422,6 +432,8 @@ { struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL; + devfs_unregister (lvm_devfs_handle); + if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) { printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); } @@ -1625,6 +1637,14 @@ kfree(vg_ptr); return -EFAULT; } + + vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL); + ch_devfs_handle[vg_ptr->vg_number] = devfs_register( + vg_devfs_handle[vg_ptr->vg_number] , "group", + DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_chr_fops, NULL); + /* we are not that active so far... */ vg_ptr->vg_status &= ~VG_ACTIVE; vg[VG_CHR(minor)] = vg_ptr; @@ -1852,6 +1872,9 @@ /* let's go inactive */ vg_ptr->vg_status &= ~VG_ACTIVE; + devfs_unregister (ch_devfs_handle[vg_ptr->vg_number]); + devfs_unregister (vg_devfs_handle[vg_ptr->vg_number]); + /* free LVs */ /* first free snapshot logical volumes */ for (i = 0; i < vg_ptr->lv_max; i++) { @@ -1907,6 +1930,7 @@ { int l, le, l_new, p, size; ulong lv_status_save; + char *lv_tmp, *lv_buf; lv_block_exception_t *lvbe = lv->lv_block_exception; vg_t *vg_ptr = vg[VG_CHR(minor)]; lv_t *lv_ptr = NULL; @@ -2062,6 +2086,17 @@ vg_ptr->lv_cur++; lv_ptr->lv_status = lv_status_save; + strtok(lv->lv_name, "/"); /* /dev */ + + while((lv_tmp = strtok(NULL, "/")) != NULL) + lv_buf = lv_tmp; + + lv_devfs_handle[lv->lv_number] = devfs_register( + vg_devfs_handle[vg_ptr->vg_number], lv_buf, + DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, lv->lv_number, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_blk_dops, NULL); + /* optionally add our new snapshot LV */ if (lv_ptr->lv_access & LV_SNAPSHOT) { /* sync the original logical volume */ @@ -2153,6 +2188,8 @@ lv_ptr->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG; lvm_snapshot_release(lv_ptr); } + + devfs_unregister(lv_devfs_handle[lv_ptr->lv_number]); #ifdef DEBUG_KFREE printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.4.0-test7/linux/drivers/block/md.c Wed Aug 23 18:36:36 2000 +++ linux/drivers/block/md.c Tue Sep 5 14:07:30 2000 @@ -952,7 +952,7 @@ memcpy(sb, rdev->sb, MD_SB_BYTES); mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); wait_on_buffer(bh); brelse(bh); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/block/xor.c linux/drivers/block/xor.c --- v2.4.0-test7/linux/drivers/block/xor.c Wed Aug 23 18:36:36 2000 +++ linux/drivers/block/xor.c Mon Aug 28 21:21:57 2000 @@ -1406,6 +1406,818 @@ } #endif /* __sparc_v[78]__ */ +#ifdef __alpha__ +/* + * High speed xor_block operation for RAID4/5 pipelined for Alpha EV5. + * There is a second version using EV6 prefetch instructions. + * + * Copyright (C) 2000 Richard Henderson (rth@redhat.com) + */ + +XORBLOCK_TEMPLATE(alpha) +{ + long lines = bh_ptr[0]->b_size / sizeof (long) / 8; + long *d = (long *) bh_ptr[0]->b_data; + long *s1 = (long *) bh_ptr[1]->b_data; + long *s2, *s3, *s4; + + if (count == 2) goto two_blocks; + + s2 = (long *) bh_ptr[2]->b_data; + if (count == 3) goto three_blocks; + + s3 = (long *) bh_ptr[3]->b_data; + if (count == 4) goto four_blocks; + + s4 = (long *) bh_ptr[4]->b_data; + goto five_blocks; + +two_blocks: +asm volatile (" + .align 4 +2: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,8(%0) + ldq $3,8(%1) + + ldq $4,16(%0) + ldq $5,16(%1) + ldq $6,24(%0) + ldq $7,24(%1) + + ldq $16,32(%0) + ldq $17,32(%1) + ldq $18,40(%0) + ldq $19,40(%1) + + ldq $20,48(%0) + ldq $21,48(%1) + ldq $22,56(%0) + xor $0,$1,$0 # 7 cycles from $1 load + + ldq $23,56(%1) + xor $2,$3,$2 + stq $0,0(%0) + xor $4,$5,$4 + + stq $2,8(%0) + xor $6,$7,$6 + stq $4,16(%0) + xor $16,$17,$16 + + stq $6,24(%0) + xor $18,$19,$18 + stq $16,32(%0) + xor $20,$21,$20 + + stq $18,40(%0) + xor $22,$23,$22 + stq $20,48(%0) + subq %2,1,%2 + + stq $22,56(%0) + addq %0,64,%0 + addq %1,64,%1 + bgt %2,2b" + : "=r"(d), "=r"(s1), "=r"(lines) + : "0"(d), "1"(s1), "2"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23"); + return; + +three_blocks: +asm volatile (" + .align 4 +3: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,8(%0) + + ldq $4,8(%1) + ldq $6,16(%0) + ldq $7,16(%1) + ldq $17,24(%0) + + ldq $18,24(%1) + ldq $20,32(%0) + ldq $21,32(%1) + ldq $5,8(%2) + + ldq $16,16(%2) + ldq $19,24(%2) + ldq $22,32(%2) + nop + + xor $0,$1,$1 # 8 cycles from $0 load + xor $3,$4,$4 # 6 cycles from $4 load + xor $6,$7,$7 # 6 cycles from $7 load + xor $17,$18,$18 # 5 cycles from $18 load + + xor $1,$2,$2 # 9 cycles from $2 load + xor $20,$21,$21 # 5 cycles from $21 load + stq $2,0(%0) + xor $4,$5,$5 # 6 cycles from $5 load + + stq $5,8(%0) + xor $7,$16,$16 # 7 cycles from $16 load + stq $16,16(%0) + xor $18,$19,$19 # 7 cycles from $19 load + + stq $19,24(%0) + xor $21,$22,$22 # 7 cycles from $22 load + stq $22,32(%0) + nop + + ldq $0,40(%0) + ldq $1,40(%1) + ldq $3,48(%0) + ldq $4,48(%1) + + ldq $6,56(%0) + ldq $7,56(%1) + ldq $2,40(%2) + ldq $5,48(%2) + + ldq $16,56(%2) + xor $0,$1,$1 # 4 cycles from $1 load + xor $3,$4,$4 # 5 cycles from $4 load + xor $6,$7,$7 # 5 cycles from $7 load + + xor $1,$2,$2 # 4 cycles from $2 load + xor $4,$5,$5 # 5 cycles from $5 load + stq $2,40(%0) + xor $7,$16,$16 # 4 cycles from $16 load + + stq $5,48(%0) + subq %3,1,%3 + stq $16,56(%0) + addq %2,64,%2 + + addq %1,64,%1 + addq %0,64,%0 + bgt %3,3b" + : "=r"(d), "=r"(s1), "=r"(s2), "=r"(lines) + : "0"(d), "1"(s1), "2"(s2), "3"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21", "$22"); + return; + +four_blocks: +asm volatile (" + .align 4 +4: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,0(%3) + + ldq $4,8(%0) + ldq $5,8(%1) + ldq $6,8(%2) + ldq $7,8(%3) + + ldq $16,16(%0) + ldq $17,16(%1) + ldq $18,16(%2) + ldq $19,16(%3) + + ldq $20,24(%0) + xor $0,$1,$1 # 6 cycles from $1 load + ldq $21,24(%1) + xor $2,$3,$3 # 6 cycles from $3 load + + ldq $0,24(%2) + xor $1,$3,$3 + ldq $1,24(%3) + xor $4,$5,$5 # 7 cycles from $5 load + + stq $3,0(%0) + xor $6,$7,$7 + xor $16,$17,$17 # 7 cycles from $17 load + xor $5,$7,$7 + + stq $7,8(%0) + xor $18,$19,$19 # 7 cycles from $19 load + ldq $2,32(%0) + xor $17,$19,$19 + + ldq $3,32(%1) + ldq $4,32(%2) + ldq $5,32(%3) + xor $20,$21,$21 # 8 cycles from $21 load + + ldq $6,40(%0) + ldq $7,40(%1) + ldq $16,40(%2) + ldq $17,40(%3) + + stq $19,16(%0) + xor $0,$1,$1 # 9 cycles from $1 load + xor $2,$3,$3 # 5 cycles from $3 load + xor $21,$1,$1 + + ldq $18,48(%0) + xor $4,$5,$5 # 5 cycles from $5 load + ldq $19,48(%1) + xor $3,$5,$5 + + ldq $20,48(%2) + ldq $21,48(%3) + ldq $0,56(%0) + ldq $1,56(%1) + + ldq $2,56(%2) + xor $6,$7,$7 # 8 cycles from $6 load + ldq $3,56(%3) + xor $16,$17,$17 # 8 cycles from $17 load + + xor $7,$17,$17 + xor $18,$19,$19 # 5 cycles from $19 load + xor $20,$21,$21 # 5 cycles from $21 load + xor $19,$21,$21 + + stq $1,24(%0) + xor $0,$1,$1 # 5 cycles from $1 load + stq $5,32(%0) + xor $2,$3,$3 # 4 cycles from $3 load + + stq $17,40(%0) + xor $1,$3,$3 + stq $21,48(%0) + subq %4,1,%4 + + stq $3,56(%0) + addq %3,64,%3 + addq %2,64,%2 + addq %1,64,%1 + + addq %0,64,%0 + bgt %4,4b" + : "=r"(d), "=r"(s1), "=r"(s2), "=r"(s3), "=r"(lines) + : "0"(d), "1"(s1), "2"(s2), "3"(s3), "4"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21"); + return; + +five_blocks: +asm volatile (" + ldq %0,0(%6) + ldq %1,8(%6) + ldq %2,16(%6) + ldq %3,24(%6) + ldq %4,32(%6) + ldq %0,%7(%0) + ldq %1,%7(%1) + ldq %2,%7(%2) + ldq %3,%7(%3) + ldq %4,%7(%4) + .align 4 +5: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,0(%3) + + ldq $4,0(%4) + ldq $5,8(%0) + ldq $6,8(%1) + ldq $7,8(%2) + + ldq $16,8(%3) + ldq $17,8(%4) + ldq $18,16(%0) + ldq $19,16(%1) + + ldq $20,16(%2) + xor $0,$1,$1 # 6 cycles from $1 load + ldq $21,16(%3) + xor $2,$3,$3 # 6 cycles from $3 load + + ldq $0,16(%4) + xor $1,$3,$3 + ldq $1,24(%0) + xor $3,$4,$4 # 7 cycles from $4 load + + stq $4,0(%0) + xor $5,$6,$6 # 7 cycles from $6 load + xor $7,$16,$16 # 7 cycles from $16 load + xor $6,$17,$17 # 7 cycles from $17 load + + ldq $2,24(%1) + xor $16,$17,$17 + ldq $3,24(%2) + xor $18,$19,$19 # 8 cycles from $19 load + + stq $17,8(%0) + xor $19,$20,$20 # 8 cycles from $20 load + ldq $4,24(%3) + xor $21,$0,$0 # 7 cycles from $0 load + + ldq $5,24(%4) + xor $20,$0,$0 + ldq $6,32(%0) + ldq $7,32(%1) + + stq $0,16(%0) + xor $1,$2,$2 # 6 cycles from $2 load + ldq $16,32(%2) + xor $3,$4,$4 # 4 cycles from $4 load + + ldq $17,32(%3) + xor $2,$4,$4 + ldq $18,32(%4) + ldq $19,40(%0) + + ldq $20,40(%1) + ldq $21,40(%2) + ldq $0,40(%3) + xor $4,$5,$5 # 7 cycles from $5 load + + stq $5,24(%0) + xor $6,$7,$7 # 7 cycles from $7 load + ldq $1,40(%4) + ldq $2,48(%0) + + ldq $3,48(%1) + xor $7,$16,$16 # 7 cycles from $16 load + ldq $4,48(%2) + xor $17,$18,$18 # 6 cycles from $18 load + + ldq $5,48(%3) + xor $16,$18,$18 + ldq $6,48(%4) + xor $19,$20,$20 # 7 cycles from $20 load + + stq $18,32(%0) + xor $20,$21,$21 # 8 cycles from $21 load + ldq $7,56(%0) + xor $0,$1,$1 # 6 cycles from $1 load + + ldq $16,56(%1) + ldq $17,56(%2) + ldq $18,56(%3) + ldq $19,56(%4) + + xor $21,$1,$1 + xor $2,$3,$3 # 9 cycles from $3 load + xor $3,$4,$4 # 9 cycles from $4 load + xor $5,$6,$6 # 8 cycles from $6 load + + unop + xor $4,$6,$6 + xor $7,$16,$16 # 7 cycles from $16 load + xor $17,$18,$18 # 6 cycles from $18 load + + stq $6,48(%0) + xor $16,$18,$18 + subq %5,1,%5 + xor $18,$19,$19 # 8 cycles from $19 load + + stq $19,56(%0) + addq %4,64,%4 + addq %3,64,%3 + addq %2,64,%2 + + addq %1,64,%1 + addq %0,64,%0 + bgt %5,5b" + : "=&r"(d), "=&r"(s1), "=&r"(s2), "=&r"(s3), "=r"(s4), "=r"(lines) + /* ARG! We've run out of asm arguments! We've got to reload + all those pointers we just loaded. */ + : "r"(bh_ptr), "i" (&((struct buffer_head *)0)->b_data), "5"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21"); + return; +} + +#define prefetch(base, ofs) \ + asm("ldq $31,%2(%0)" : "=r"(base) : "0"(base), "i"(ofs)) + +XORBLOCK_TEMPLATE(alpha_prefetch) +{ + long lines = bh_ptr[0]->b_size / sizeof (long) / 8; + long *d = (long *) bh_ptr[0]->b_data; + long *s1 = (long *) bh_ptr[1]->b_data; + long *s2, *s3, *s4; + long p; + + p = count == 2; + prefetch(d, 0); + prefetch(s1, 0); + prefetch(d, 64); + prefetch(s1, 64); + prefetch(d, 128); + prefetch(s1, 128); + prefetch(d, 192); + prefetch(s1, 192); + if (p) goto two_blocks; + + s2 = (long *) bh_ptr[2]->b_data; + p = count == 3; + prefetch(s2, 0); + prefetch(s2, 64); + prefetch(s2, 128); + prefetch(s2, 192); + if (p) goto three_blocks; + + s3 = (long *) bh_ptr[3]->b_data; + p = count == 4; + prefetch(s3, 0); + prefetch(s3, 64); + prefetch(s3, 128); + prefetch(s3, 192); + if (p) goto four_blocks; + + s4 = (long *) bh_ptr[4]->b_data; + prefetch(s4, 0); + prefetch(s4, 64); + prefetch(s4, 128); + prefetch(s4, 192); + goto five_blocks; + +two_blocks: +asm volatile (" + .align 4 +2: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,8(%0) + ldq $3,8(%1) + + ldq $4,16(%0) + ldq $5,16(%1) + ldq $6,24(%0) + ldq $7,24(%1) + + ldq $16,32(%0) + ldq $17,32(%1) + ldq $18,40(%0) + ldq $19,40(%1) + + ldq $20,48(%0) + ldq $21,48(%1) + ldq $22,56(%0) + ldq $23,56(%1) + + ldq $31,256(%0) + xor $0,$1,$0 # 8 cycles from $1 load + ldq $31,256(%1) + xor $2,$3,$2 + + stq $0,0(%0) + xor $4,$5,$4 + stq $2,8(%0) + xor $6,$7,$6 + + stq $4,16(%0) + xor $16,$17,$16 + stq $6,24(%0) + xor $18,$19,$18 + + stq $16,32(%0) + xor $20,$21,$20 + stq $18,40(%0) + xor $22,$23,$22 + + stq $20,48(%0) + subq %2,1,%2 + stq $22,56(%0) + addq %0,64,%0 + + addq %1,64,%1 + bgt %2,2b" + : "=r"(d), "=r"(s1), "=r"(lines) + : "0"(d), "1"(s1), "2"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23"); + return; + +three_blocks: +asm volatile (" + .align 4 +3: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,8(%0) + + ldq $4,8(%1) + ldq $6,16(%0) + ldq $7,16(%1) + ldq $17,24(%0) + + ldq $18,24(%1) + ldq $20,32(%0) + ldq $21,32(%1) + ldq $5,8(%2) + + ldq $16,16(%2) + ldq $19,24(%2) + ldq $22,32(%2) + nop + + xor $0,$1,$1 # 8 cycles from $0 load + xor $3,$4,$4 # 7 cycles from $4 load + xor $6,$7,$7 # 6 cycles from $7 load + xor $17,$18,$18 # 5 cycles from $18 load + + xor $1,$2,$2 # 9 cycles from $2 load + xor $20,$21,$21 # 5 cycles from $21 load + stq $2,0(%0) + xor $4,$5,$5 # 6 cycles from $5 load + + stq $5,8(%0) + xor $7,$16,$16 # 7 cycles from $16 load + stq $16,16(%0) + xor $18,$19,$19 # 7 cycles from $19 load + + stq $19,24(%0) + xor $21,$22,$22 # 7 cycles from $22 load + stq $22,32(%0) + nop + + ldq $0,40(%0) + ldq $1,40(%1) + ldq $3,48(%0) + ldq $4,48(%1) + + ldq $6,56(%0) + ldq $7,56(%1) + ldq $2,40(%2) + ldq $5,48(%2) + + ldq $16,56(%2) + ldq $31,256(%0) + ldq $31,256(%1) + ldq $31,256(%2) + + xor $0,$1,$1 # 6 cycles from $1 load + xor $3,$4,$4 # 5 cycles from $4 load + xor $6,$7,$7 # 5 cycles from $7 load + xor $1,$2,$2 # 4 cycles from $2 load + + xor $4,$5,$5 # 5 cycles from $5 load + xor $7,$16,$16 # 4 cycles from $16 load + stq $2,40(%0) + subq %3,1,%3 + + stq $5,48(%0) + addq %2,64,%2 + stq $16,56(%0) + addq %1,64,%1 + + addq %0,64,%0 + bgt %3,3b" + : "=r"(d), "=r"(s1), "=r"(s2), "=r"(lines) + : "0"(d), "1"(s1), "2"(s2), "3"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21", "$22"); + return; + +four_blocks: +asm volatile (" + .align 4 +4: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,0(%3) + + ldq $4,8(%0) + ldq $5,8(%1) + ldq $6,8(%2) + ldq $7,8(%3) + + ldq $16,16(%0) + ldq $17,16(%1) + ldq $18,16(%2) + ldq $19,16(%3) + + ldq $20,24(%0) + xor $0,$1,$1 # 6 cycles from $1 load + ldq $21,24(%1) + xor $2,$3,$3 # 6 cycles from $3 load + + ldq $0,24(%2) + xor $1,$3,$3 + ldq $1,24(%3) + xor $4,$5,$5 # 7 cycles from $5 load + + stq $3,0(%0) + xor $6,$7,$7 + xor $16,$17,$17 # 7 cycles from $17 load + xor $5,$7,$7 + + stq $7,8(%0) + xor $18,$19,$19 # 7 cycles from $19 load + ldq $2,32(%0) + xor $17,$19,$19 + + ldq $3,32(%1) + ldq $4,32(%2) + ldq $5,32(%3) + xor $20,$21,$21 # 8 cycles from $21 load + + ldq $6,40(%0) + ldq $7,40(%1) + ldq $16,40(%2) + ldq $17,40(%3) + + stq $19,16(%0) + xor $0,$1,$1 # 9 cycles from $1 load + xor $2,$3,$3 # 5 cycles from $3 load + xor $21,$1,$1 + + ldq $18,48(%0) + xor $4,$5,$5 # 5 cycles from $5 load + ldq $19,48(%1) + xor $3,$5,$5 + + ldq $20,48(%2) + ldq $21,48(%3) + ldq $0,56(%0) + ldq $1,56(%1) + + ldq $2,56(%2) + xor $6,$7,$7 # 8 cycles from $6 load + ldq $3,56(%3) + xor $16,$17,$17 # 8 cycles from $17 load + + ldq $31,256(%0) + xor $7,$17,$17 + ldq $31,256(%1) + xor $18,$19,$19 # 6 cycles from $19 load + + ldq $31,256(%2) + xor $20,$21,$21 # 6 cycles from $21 load + ldq $31,256(%3) + xor $19,$21,$21 + + stq $1,24(%0) + xor $0,$1,$1 # 7 cycles from $1 load + stq $5,32(%0) + xor $2,$3,$3 # 6 cycles from $3 load + + stq $17,40(%0) + xor $1,$3,$3 + stq $21,48(%0) + subq %4,1,%4 + + stq $3,56(%0) + addq %3,64,%3 + addq %2,64,%2 + addq %1,64,%1 + + addq %0,64,%0 + bgt %4,4b" + : "=r"(d), "=r"(s1), "=r"(s2), "=r"(s3), "=r"(lines) + : "0"(d), "1"(s1), "2"(s2), "3"(s3), "4"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21"); + return; + +five_blocks: +asm volatile (" + ldq %0,0(%6) + ldq %1,8(%6) + ldq %2,16(%6) + ldq %3,24(%6) + ldq %4,32(%6) + ldq %0,%7(%0) + ldq %1,%7(%1) + ldq %2,%7(%2) + ldq %3,%7(%3) + ldq %4,%7(%4) + .align 4 +5: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,0(%3) + + ldq $4,0(%4) + ldq $5,8(%0) + ldq $6,8(%1) + ldq $7,8(%2) + + ldq $16,8(%3) + ldq $17,8(%4) + ldq $18,16(%0) + ldq $19,16(%1) + + ldq $20,16(%2) + xor $0,$1,$1 # 6 cycles from $1 load + ldq $21,16(%3) + xor $2,$3,$3 # 6 cycles from $3 load + + ldq $0,16(%4) + xor $1,$3,$3 + ldq $1,24(%0) + xor $3,$4,$4 # 7 cycles from $4 load + + stq $4,0(%0) + xor $5,$6,$6 # 7 cycles from $6 load + xor $7,$16,$16 # 7 cycles from $16 load + xor $6,$17,$17 # 7 cycles from $17 load + + ldq $2,24(%1) + xor $16,$17,$17 + ldq $3,24(%2) + xor $18,$19,$19 # 8 cycles from $19 load + + stq $17,8(%0) + xor $19,$20,$20 # 8 cycles from $20 load + ldq $4,24(%3) + xor $21,$0,$0 # 7 cycles from $0 load + + ldq $5,24(%4) + xor $20,$0,$0 + ldq $6,32(%0) + ldq $7,32(%1) + + stq $0,16(%0) + xor $1,$2,$2 # 6 cycles from $2 load + ldq $16,32(%2) + xor $3,$4,$4 # 4 cycles from $4 load + + ldq $17,32(%3) + xor $2,$4,$4 + ldq $18,32(%4) + ldq $19,40(%0) + + ldq $20,40(%1) + ldq $21,40(%2) + ldq $0,40(%3) + xor $4,$5,$5 # 7 cycles from $5 load + + stq $5,24(%0) + xor $6,$7,$7 # 7 cycles from $7 load + ldq $1,40(%4) + ldq $2,48(%0) + + ldq $3,48(%1) + xor $7,$16,$16 # 7 cycles from $16 load + ldq $4,48(%2) + xor $17,$18,$18 # 6 cycles from $18 load + + ldq $5,48(%3) + xor $16,$18,$18 + ldq $6,48(%4) + xor $19,$20,$20 # 7 cycles from $20 load + + stq $18,32(%0) + xor $20,$21,$21 # 8 cycles from $21 load + ldq $7,56(%0) + xor $0,$1,$1 # 6 cycles from $1 load + + ldq $16,56(%1) + ldq $17,56(%2) + ldq $18,56(%3) + ldq $19,56(%4) + + ldq $31,256(%0) + xor $21,$1,$1 + ldq $31,256(%1) + xor $2,$3,$3 # 9 cycles from $3 load + + ldq $31,256(%2) + xor $3,$4,$4 # 9 cycles from $4 load + ldq $31,256(%3) + xor $5,$6,$6 # 8 cycles from $6 load + + ldq $31,256(%4) + xor $4,$6,$6 + xor $7,$16,$16 # 7 cycles from $16 load + xor $17,$18,$18 # 6 cycles from $18 load + + stq $6,48(%0) + xor $16,$18,$18 + subq %5,1,%5 + xor $18,$19,$19 # 8 cycles from $19 load + + stq $19,56(%0) + addq %4,64,%4 + addq %3,64,%3 + addq %2,64,%2 + + addq %1,64,%1 + addq %0,64,%0 + bgt %5,5b" + : "=&r"(d), "=&r"(s1), "=&r"(s2), "=&r"(s3), "=r"(s4), "=r"(lines) + /* ARG! We've run out of asm arguments! We've got to reload + all those pointers we just loaded. */ + : "r"(bh_ptr), "i" (&((struct buffer_head *)0)->b_data), "5"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21"); + return; +} + +#undef prefetch + +#endif /* __alpha__ */ + #ifndef __sparc_v9__ /* @@ -1815,9 +2627,22 @@ } #ifdef CONFIG_X86_XMM if (cpu_has_xmm) { + /* we force the use of the KNI xor block because it + can write around l2. we may also be able + to load into the l1 only depending on how + the cpu deals with a load to a line that is + being prefetched. + */ fastest = &t_xor_block_pIII_kni; } #endif +#ifdef __alpha__ + if (implver() == IMPLVER_EV6) { + /* Force the use of alpha_prefetch if EV6, as it + is significantly faster in the cold cache case. */ + fastest = &t_xor_block_alpha_prefetch; + } +#endif xor_block = fastest->xor_block; printk( "using fastest function: %s (%d.%03d MB/sec)\n", fastest->name, fastest->speed / 1000, fastest->speed % 1000); @@ -1854,27 +2679,23 @@ if (cpu_has_xmm) { printk(KERN_INFO "raid5: KNI detected, trying cache-avoiding KNI checksum routine\n"); - /* we force the use of the KNI xor block because it - can write around l2. we may also be able - to load into the l1 only depending on how - the cpu deals with a load to a line that is - being prefetched. - */ xor_speed(&t_xor_block_pIII_kni,&b1,&b2); } #endif /* CONFIG_X86_XMM */ #ifdef __i386__ - if (md_cpu_has_mmx()) { printk(KERN_INFO "raid5: MMX detected, trying high-speed MMX checksum routines\n"); xor_speed(&t_xor_block_pII_mmx,&b1,&b2); xor_speed(&t_xor_block_p5_mmx,&b1,&b2); } - #endif /* __i386__ */ - + +#ifdef __alpha__ + xor_speed(&t_xor_block_alpha,&b1,&b2); + xor_speed(&t_xor_block_alpha_prefetch,&b1,&b2); +#endif xor_speed(&t_xor_block_8regs,&b1,&b2); xor_speed(&t_xor_block_32regs,&b1,&b2); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.4.0-test7/linux/drivers/cdrom/cdrom.c Mon Jul 10 16:47:22 2000 +++ linux/drivers/cdrom/cdrom.c Tue Sep 5 13:46:15 2000 @@ -291,11 +291,13 @@ #endif /* These are used to simplify getting data in from and back to user land */ -#define IOCTL_IN(arg, type, in) \ - copy_from_user_ret(&in, (type *) arg, sizeof in, -EFAULT) +#define IOCTL_IN(arg, type, in) \ + if (copy_from_user(&in, (type *) arg, sizeof in)) \ + return -EFAULT; #define IOCTL_OUT(arg, type, out) \ - copy_to_user_ret((type *) arg, &out, sizeof out, -EFAULT) + if (copy_to_user((type *) arg, &out, sizeof out)) \ + return -EFAULT; /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in a lot of places. This macro makes the code more clear. */ @@ -784,6 +786,8 @@ if (!CDROM_CAN(CDC_SELECT_DISC)) return -EDRIVE_CANT_DO_THIS; + (void) cdi->ops->media_changed(cdi, slot); + if (slot == CDSL_NONE) { /* set media changed bits, on both queues */ cdi->mc_flags = 0x3; @@ -851,8 +855,8 @@ if (cdi == NULL || cdi->ops->media_changed == NULL) return 0; if (!CDROM_CAN(CDC_MEDIA_CHANGED)) - return 0; - return (media_changed(cdi, 0)); + return 0; + return media_changed(cdi, 0); } /* badly broken, I know. Is due for a fixup anytime. */ @@ -872,8 +876,7 @@ return; } /* Grab the TOC header so we can see how many tracks there are */ - ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header); - if (ret) { + if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) { if (ret == -ENOMEDIUM) tracks->error = CDS_NO_DISC; else @@ -1516,12 +1519,13 @@ cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return -ENOSYS; + + /* cannot select disc or select current disc */ if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) - /* cannot select disc or select current disc */ return media_changed(cdi, 1); - if ((unsigned int)arg >= cdi->capacity) { + + if ((unsigned int)arg >= cdi->capacity) return -EINVAL; - } if ((ret = cdrom_read_mech_status(cdi, &info))) return ret; @@ -1570,10 +1574,10 @@ if (!CDROM_CAN(CDC_SELECT_DISC)) return -ENOSYS; - if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE)) { - if ((int)arg >= cdi->capacity) - return -EINVAL; - } + if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE)) + if ((int)arg >= cdi->capacity) + return -EINVAL; + /* cdo->select_disc is a hook to allow a driver-specific * way of seleting disc. However, since there is no * equiv hook for cdrom_slot_status this may not @@ -1601,8 +1605,9 @@ if (!CDROM_CAN(CDC_LOCK)) return -EDRIVE_CANT_DO_THIS; keeplocked = arg ? 1 : 0; - /* don't unlock the door on multiple opens */ - if ((cdi->use_count != 1) && !arg) + /* don't unlock the door on multiple opens,but allow root + * to do so */ + if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN)) return -EBUSY; return cdo->lock_door(cdi, arg); } @@ -1834,7 +1839,6 @@ struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_generic_command cgc; struct modesel_head mh; - int ret; memset(&mh, 0, sizeof(mh)); mh.block_desc_length = 0x08; @@ -1852,14 +1856,7 @@ mh.block_length_med = (size >> 8) & 0xff; mh.block_length_lo = size & 0xff; - ret = cdo->generic_packet(cdi, &cgc); - if (ret) { - printk("switch_blocksize failed, ret %x ", ret); - if (cgc.sense) - printk("sense %02x.%02x.%02x", cgc.sense->sense_key, cgc.sense->asc, cgc.sense->ascq); - printk("\n"); - } - return ret; + return cdo->generic_packet(cdi, &cgc); } static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, @@ -1916,16 +1913,10 @@ } cgc.sense = NULL; ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1); - if (ret) { - printk("read_cd failed, ret %x ", ret); - if (cgc.sense) - printk("sense %02x.%02x.%02x", cgc.sense->sense_key, cgc.sense->asc, cgc.sense->ascq); - printk("\n"); - } ret |= cdrom_switch_blocksize(cdi, blocksize); } if (!ret && copy_to_user((char *)arg, cgc.buffer, blocksize)) - ret = -EFAULT; + ret = -EFAULT; kfree(cgc.buffer); return ret; } @@ -1989,19 +1980,6 @@ IOCTL_OUT(arg, struct cdrom_subchnl, q); /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ return 0; - } - case CDROMPLAYTRKIND: { - struct cdrom_ti ti; - - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); - IOCTL_IN(arg, struct cdrom_ti, ti); - - cgc.cmd[0] = GPCMD_PLAY_AUDIO_TI; - cgc.cmd[4] = ti.cdti_trk0; - cgc.cmd[5] = ti.cdti_ind0; - cgc.cmd[7] = ti.cdti_trk1; - cgc.cmd[8] = ti.cdti_ind1; - return cdo->generic_packet(cdi, &cgc); } case CDROMPLAYMSF: { struct cdrom_msf msf; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.4.0-test7/linux/drivers/cdrom/sbpcd.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/cdrom/sbpcd.c Tue Sep 5 13:46:15 2000 @@ -1,3 +1,5 @@ + + /* * sbpcd.c CD-ROM device driver for the whole family of traditional, * non-ATAPI IDE-style Matsushita/Panasonic CR-5xx drives. @@ -13,7 +15,7 @@ * labelled E2550UA or MK4015 or 2800F). */ -#define VERSION "v4.61 Eberhard Moenkeberg " +#define VERSION "v4.63 Andrew J. Kroll Wed Jul 26 04:24:10 EDT 2000" /* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg * @@ -46,7 +48,7 @@ * * 0.1 initial release, April/May 93, after mcd.c (Martin Harriss) * - * 0.2 the "repeat:"-loop in do_sbpcd_request did not check for + * 0.2 thek "repeat:"-loop in do_sbpcd_request did not check for * end-of-request_queue (resulting in kernel panic). * Flow control seems stable, but throughput is not better. * @@ -312,9 +314,20 @@ * module_init & module_exit. * Torben Mathiasen * + * 4.63 Bug fixes for audio annoyances, new legacy CDROM maintainer. + * Annoying things fixed: + * TOC reread on automated disk changes + * TOC reread on manual cd changes + * Play IOCTL tries to play CD before it's actually ready... sometimes. + * CD_AUDIO_COMPLETED state so workman (and other playes) can repeat play. + * Andrew J. Kroll Wed Jul 26 04:24:10 EDT 2000 + * * * TODO * implement "read all subchannel data" (96 bytes per frame) + * remove alot of the virtual status bits and deal with hardware status + * move the change of cd for audio to a better place + * add debug levels to insmod parameters (trivial) * * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine * elaborated speed-up experiments (and the fabulous results!), for @@ -637,9 +650,9 @@ static u_int maxtim_data= 3000; #endif LONG_TIMING #if DISTRIBUTION -static int n_retries=3; +static int n_retries=6; #else -static int n_retries=1; +static int n_retries=6; #endif /*==========================================================================*/ @@ -2046,7 +2059,9 @@ do { i=GetStatus(); - if ((i<0)&&(i!=-ERR_DISKCHANGE)) return (-2); /* from sta2err */ + if ((i<0)&&(i!=-ERR_DISKCHANGE)) { + return (-2); /* from sta2err */ + } if (!st_caddy_in) break; sbp_sleep(1); } @@ -2343,16 +2358,21 @@ static int sbpcd_tray_move(struct cdrom_device_info *cdi, int position) { - int i; - i = MINOR(cdi->dev); - - switch_drive(i); - if (position == 1) { - cc_SpinDown(); - } else { - return cc_CloseTray(); - } - return 0; + int i; + int retval=0; + i = MINOR(cdi->dev); + switch_drive(i); + /* DUH! --AJK */ + if(D_S[d].CD_changed != 0xFF) { + D_S[d].CD_changed=0xFF; + D_S[d].diskstate_flags &= ~cd_size_bit; + } + if (position == 1) { + cc_SpinDown(); + } else { + retval=cc_CloseTray(); + } + return retval; } /*==========================================================================*/ @@ -4023,6 +4043,7 @@ msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); + #if 0 if (!(D_S[MINOR(cdi->dev)].status_bits & p_door_closed)) return CDS_TRAY_OPEN; if (D_S[MINOR(cdi->dev)].status_bits & p_disk_ok) return CDS_DISC_OK; @@ -4031,8 +4052,11 @@ return CDS_NO_DISC; #else if (D_S[MINOR(cdi->dev)].status_bits & p_spinning) return CDS_DISC_OK; - return CDS_TRAY_OPEN; +/* return CDS_TRAY_OPEN; */ + return CDS_NO_DISC; + #endif + } @@ -4500,7 +4524,7 @@ static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd, void * arg) { - int i, st; + int i, st, j; msg(DBG_IO2,"ioctl(%d, 0x%08lX, 0x%08p)\n", MINOR(cdi->dev), cmd, arg); @@ -4696,19 +4720,68 @@ case CDROMSUBCHNL: /* Get subchannel info */ msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n"); + /* Bogus, I can do better than this! --AJK if ((st_spinning)||(!subq_valid)) { i=cc_ReadSubQ(); if (i<0) RETURN_UP(-EIO); } + */ + i=cc_ReadSubQ(); + if (i<0) { + j=cc_ReadError(); /* clear out error status from drive */ + D_S[d].audio_state=CDROM_AUDIO_NO_STATUS; + /* get and set the disk state here, + probably not the right place, but who cares! + It makes it work properly! --AJK */ + if (D_S[d].CD_changed==0xFF) { + msg(DBG_000,"Disk changed detect\n"); + D_S[d].diskstate_flags &= ~cd_size_bit; + } + RETURN_UP(-EIO); + } + if (D_S[d].CD_changed==0xFF) { + /* reread the TOC because the disk has changed! --AJK */ + msg(DBG_000,"Disk changed STILL detected, rereading TOC!\n"); + i=DiskInfo(); + if(i==0) { + D_S[d].CD_changed=0x00; /* cd has changed, procede, */ + RETURN_UP(-EIO); /* and get TOC, etc on next try! --AJK */ + } else { + RETURN_UP(-EIO); /* we weren't ready yet! --AJK */ + } + } memcpy(&SC, (void *) arg, sizeof(struct cdrom_subchnl)); + /* + This virtual crap is very bogus! + It doesn't detect when the cd is done playing audio! + Lets do this right with proper hardware register reading! + */ + cc_ReadStatus(); + i=ResponseStatus(); + msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); + msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); + msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); + msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); + msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); + msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); + /* st_busy indicates if it's _ACTUALLY_ playing audio */ switch (D_S[d].audio_state) { case audio_playing: - SC.cdsc_audiostatus=CDROM_AUDIO_PLAY; + if(st_busy==0) { + /* CD has stopped playing audio --AJK */ + D_S[d].audio_state=audio_completed; + SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED; + } else { + SC.cdsc_audiostatus=CDROM_AUDIO_PLAY; + } break; case audio_pausing: SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED; break; + case audio_completed: + SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED; + break; default: SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS; break; @@ -5883,6 +5956,14 @@ { D_S[i].CD_changed=0; msg(DBG_CHK,"medium changed (drive %d)\n", i); + /* BUG! Should invalidate buffers! --AJK */ + invalidate_buffers(full_dev); + D_S[d].diskstate_flags &= ~toc_bit; + D_S[d].diskstate_flags &= ~cd_size_bit; +#if SAFE_MIXED + D_S[d].has_data=0; +#endif SAFE_MIXED + return (1); } else diff -u --recursive --new-file v2.4.0-test7/linux/drivers/cdrom/sbpcd.h linux/drivers/cdrom/sbpcd.h --- v2.4.0-test7/linux/drivers/cdrom/sbpcd.h Mon Jan 5 00:06:26 1998 +++ linux/drivers/cdrom/sbpcd.h Tue Sep 5 13:46:15 2000 @@ -412,6 +412,7 @@ /* * audio states: */ +#define audio_completed 3 /* Forgot this one! --AJK */ #define audio_playing 2 #define audio_pausing 1 diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/agpsupport.c linux/drivers/char/drm/agpsupport.c --- v2.4.0-test7/linux/drivers/char/drm/agpsupport.c Wed Aug 23 18:36:36 2000 +++ linux/drivers/char/drm/agpsupport.c Tue Aug 29 14:09:15 2000 @@ -95,7 +95,8 @@ info.id_vendor = kern->device->vendor; info.id_device = kern->device->device; - copy_to_user_ret((drm_agp_info_t *)arg, &info, sizeof(info), -EFAULT); + if (copy_to_user((drm_agp_info_t *)arg, &info, sizeof(info))) + return -EFAULT; return 0; } @@ -134,8 +135,8 @@ if (!dev->agp->acquired || !drm_agp.enable) return -EINVAL; - copy_from_user_ret(&mode, (drm_agp_mode_t *)arg, sizeof(mode), - -EFAULT); + if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode))) + return -EFAULT; dev->agp->mode = mode.mode; (*drm_agp.enable)(mode.mode); @@ -155,8 +156,8 @@ unsigned long pages; u32 type; if (!dev->agp->acquired) return -EINVAL; - copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request), - -EFAULT); + if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) + return -EFAULT; if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) return -ENOMEM; @@ -212,8 +213,8 @@ drm_agp_mem_t *entry; if (!dev->agp->acquired) return -EINVAL; - copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request), - -EFAULT); + if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) + return -EFAULT; if (!(entry = drm_agp_lookup_entry(dev, request.handle))) return -EINVAL; if (!entry->bound) return -EINVAL; @@ -231,8 +232,8 @@ int page; if (!dev->agp->acquired || !drm_agp.bind_memory) return -EINVAL; - copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request), - -EFAULT); + if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) + return -EFAULT; if (!(entry = drm_agp_lookup_entry(dev, request.handle))) return -EINVAL; if (entry->bound) return -EINVAL; @@ -253,8 +254,8 @@ drm_agp_mem_t *entry; if (!dev->agp->acquired) return -EINVAL; - copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request), - -EFAULT); + if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) + return -EFAULT; if (!(entry = drm_agp_lookup_entry(dev, request.handle))) return -EINVAL; if (entry->bound) drm_unbind_agp(entry->memory); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/auth.c linux/drivers/char/drm/auth.c --- v2.4.0-test7/linux/drivers/char/drm/auth.c Wed Aug 23 18:36:36 2000 +++ linux/drivers/char/drm/auth.c Tue Aug 29 14:09:15 2000 @@ -137,7 +137,8 @@ } DRM_DEBUG("%u\n", auth.magic); - copy_to_user_ret((drm_auth_t *)arg, &auth, sizeof(auth), -EFAULT); + if (copy_to_user((drm_auth_t *)arg, &auth, sizeof(auth))) + return -EFAULT; return 0; } @@ -149,7 +150,8 @@ drm_auth_t auth; drm_file_t *file; - copy_from_user_ret(&auth, (drm_auth_t *)arg, sizeof(auth), -EFAULT); + if (copy_from_user(&auth, (drm_auth_t *)arg, sizeof(auth))) + return -EFAULT; DRM_DEBUG("%u\n", auth.magic); if ((file = drm_find_file(dev, auth.magic))) { file->authenticated = 1; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c --- v2.4.0-test7/linux/drivers/char/drm/bufs.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/bufs.c Tue Aug 29 14:09:15 2000 @@ -133,12 +133,13 @@ dev->maplist[dev->map_count-1] = map; up(&dev->struct_sem); - copy_to_user_ret((drm_map_t *)arg, map, sizeof(*map), -EFAULT); + if (copy_to_user((drm_map_t *)arg, map, sizeof(*map))) + return -EFAULT; if (map->type != _DRM_SHM) { - copy_to_user_ret(&((drm_map_t *)arg)->handle, + if (copy_to_user(&((drm_map_t *)arg)->handle, &map->offset, - sizeof(map->offset), - -EFAULT); + sizeof(map->offset))) + return -EFAULT; } return 0; } @@ -166,10 +167,10 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; count = request.count; order = drm_order(request.size); @@ -295,10 +296,10 @@ request.count = entry->buf_count; request.size = size; - copy_to_user_ret((drm_buf_desc_t *)arg, + if (copy_to_user((drm_buf_desc_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; atomic_dec(&dev->buf_alloc); return 0; @@ -324,10 +325,10 @@ ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_info_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { if (dma->bufs[i].buf_count) ++count; @@ -338,28 +339,26 @@ if (request.count >= count) { for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { if (dma->bufs[i].buf_count) { - copy_to_user_ret(&request.list[count].count, + if (copy_to_user(&request.list[count].count, &dma->bufs[i].buf_count, sizeof(dma->bufs[0] - .buf_count), - -EFAULT); - copy_to_user_ret(&request.list[count].size, + .buf_count)) || + copy_to_user(&request.list[count].size, &dma->bufs[i].buf_size, - sizeof(dma->bufs[0].buf_size), - -EFAULT); - copy_to_user_ret(&request.list[count].low_mark, + sizeof(dma->bufs[0].buf_size)) || + copy_to_user(&request.list[count].low_mark, &dma->bufs[i] .freelist.low_mark, sizeof(dma->bufs[0] - .freelist.low_mark), - -EFAULT); - copy_to_user_ret(&request.list[count] + .freelist.low_mark)) || + copy_to_user(&request.list[count] .high_mark, &dma->bufs[i] .freelist.high_mark, sizeof(dma->bufs[0] - .freelist.high_mark), - -EFAULT); + .freelist.high_mark))) + return -EFAULT; + DRM_DEBUG("%d %d %d %d %d\n", i, dma->bufs[i].buf_count, @@ -372,10 +371,10 @@ } request.count = count; - copy_to_user_ret((drm_buf_info_t *)arg, + if (copy_to_user((drm_buf_info_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; return 0; } @@ -392,10 +391,10 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; DRM_DEBUG("%d, %d, %d\n", request.size, request.low_mark, request.high_mark); @@ -427,17 +426,17 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_free_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; DRM_DEBUG("%d\n", request.count); for (i = 0; i < request.count; i++) { - copy_from_user_ret(&idx, + if (copy_from_user(&idx, &request.list[i], - sizeof(idx), - -EFAULT); + sizeof(idx))) + return -EFAULT; if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("Index %d (of %d max)\n", idx, dma->buf_count - 1); @@ -480,10 +479,10 @@ ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_map_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; if (request.count >= dma->buf_count) { down(¤t->mm->mmap_sem); @@ -529,10 +528,10 @@ request.count = dma->buf_count; DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - copy_to_user_ret((drm_buf_map_t *)arg, + if (copy_to_user((drm_buf_map_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; return retcode; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/context.c linux/drivers/char/drm/context.c --- v2.4.0-test7/linux/drivers/char/drm/context.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/context.c Tue Aug 29 14:09:15 2000 @@ -129,19 +129,21 @@ int i; DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); - copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) + return -EFAULT; if (res.count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - copy_to_user_ret(&res.contexts[i], + if (copy_to_user(&res.contexts[i], &i, - sizeof(i), - -EFAULT); + sizeof(i))) + return -EFAULT; } } res.count = DRM_RESERVED_CONTEXTS; - copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) + return -EFAULT; return 0; } @@ -153,7 +155,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { /* Init kernel's context and get a new one. */ drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx); @@ -161,7 +164,8 @@ } drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx); DRM_DEBUG("%d\n", ctx.handle); - copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -173,7 +177,8 @@ drm_ctx_t ctx; drm_queue_t *q; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); @@ -206,7 +211,8 @@ drm_ctx_t ctx; drm_queue_t *q; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); @@ -223,7 +229,8 @@ ctx.flags = q->flags; atomic_dec(&q->use_count); - copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -235,7 +242,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); return drm_context_switch(dev, dev->last_context, ctx.handle); } @@ -247,7 +255,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); drm_context_switch_complete(dev, ctx.handle); @@ -263,7 +272,8 @@ drm_queue_t *q; drm_buf_t *buf; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); if (ctx.handle >= dev->queue_count) return -EINVAL; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/dma.c linux/drivers/char/drm/dma.c --- v2.4.0-test7/linux/drivers/char/drm/dma.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/dma.c Tue Aug 29 14:09:15 2000 @@ -486,14 +486,16 @@ buf->pending); } buf->pid = current->pid; - copy_to_user_ret(&d->request_indices[i], + if (copy_to_user(&d->request_indices[i], &buf->idx, - sizeof(buf->idx), - -EFAULT); - copy_to_user_ret(&d->request_sizes[i], + sizeof(buf->idx))) + return -EFAULT; + + if (copy_to_user(&d->request_sizes[i], &buf->total, - sizeof(buf->total), - -EFAULT); + sizeof(buf->total))) + return -EFAULT; + ++d->granted_count; } return 0; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/drawable.c linux/drivers/char/drm/drawable.c --- v2.4.0-test7/linux/drivers/char/drm/drawable.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/drawable.c Tue Aug 29 14:09:15 2000 @@ -39,7 +39,8 @@ draw.handle = 0; /* NOOP */ DRM_DEBUG("%d\n", draw.handle); - copy_to_user_ret((drm_draw_t *)arg, &draw, sizeof(draw), -EFAULT); + if (copy_to_user((drm_draw_t *)arg, &draw, sizeof(draw))) + return -EFAULT; return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h --- v2.4.0-test7/linux/drivers/char/drm/drmP.h Wed Aug 23 18:36:36 2000 +++ linux/drivers/char/drm/drmP.h Wed Sep 6 15:03:28 2000 @@ -57,10 +57,13 @@ #include #include #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) +#if LINUX_VERSION_CODE >= 0x020100 /* KERNEL_VERSION(2,1,0) */ #include #include #endif +#if LINUX_VERSION_CODE < 0x020400 +#include "compat-pre24.h" +#endif #include "drm.h" #define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then @@ -138,11 +141,6 @@ #endif #ifndef module_exit #define module_exit(x) void cleanup_module(void) { x(); } -#endif - - /* virt_to_page added in 2.4.0-test6 */ -#if LINUX_VERSION_CODE < 0x020400 -#define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr)) #endif /* Generic cmpxchg added in 2.3.x */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/ffb_context.c linux/drivers/char/drm/ffb_context.c --- v2.4.0-test7/linux/drivers/char/drm/ffb_context.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/drm/ffb_context.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: ffb_context.c,v 1.3 2000/06/09 03:46:53 davem Exp $ +/* $Id: ffb_context.c,v 1.4 2000/08/29 07:01:55 davem Exp $ * ffb_context.c: Creator/Creator3D DRI/DRM context switching. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -389,19 +389,21 @@ int i; DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); - copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) + return -EFAULT; if (res.count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - copy_to_user_ret(&res.contexts[i], + if (copy_to_user(&res.contexts[i], &i, - sizeof(i), - -EFAULT); + sizeof(i))) + return -EFAULT; } } res.count = DRM_RESERVED_CONTEXTS; - copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) + return -EFAULT; return 0; } @@ -414,14 +416,16 @@ drm_ctx_t ctx; int idx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; idx = ffb_alloc_queue(dev, (ctx.flags & _DRM_CONTEXT_2DONLY)); if (idx < 0) return -ENFILE; DRM_DEBUG("%d\n", ctx.handle); ctx.handle = idx; - copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -435,7 +439,8 @@ drm_ctx_t ctx; int idx; - copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; idx = ctx.handle; if (idx <= 0 || idx >= FFB_MAX_CTXS) @@ -463,7 +468,8 @@ drm_ctx_t ctx; int idx; - copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; idx = ctx.handle; if (idx <= 0 || idx >= FFB_MAX_CTXS) @@ -478,7 +484,8 @@ else ctx.flags = 0; - copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -490,7 +497,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); return ffb_context_switch(dev, dev->last_context, ctx.handle); } @@ -500,7 +508,8 @@ { drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); return 0; @@ -515,7 +524,8 @@ ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); int idx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); idx = ctx.handle - 1; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/fops.c linux/drivers/char/drm/fops.c --- v2.4.0-test7/linux/drivers/char/drm/fops.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/fops.c Tue Aug 29 14:09:15 2000 @@ -176,7 +176,8 @@ } else { cur = DRM_MIN(send, dev->buf_end - dev->buf_rp); } - copy_to_user_ret(buf, dev->buf_rp, cur, -EINVAL); + if (copy_to_user(buf, dev->buf_rp, cur)) + return -EFAULT; dev->buf_rp += cur; if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf; send -= cur; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/gamma_dma.c linux/drivers/char/drm/gamma_dma.c --- v2.4.0-test7/linux/drivers/char/drm/gamma_dma.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/gamma_dma.c Tue Aug 29 21:09:10 2000 @@ -586,7 +586,8 @@ int retcode = 0; drm_dma_t d; - copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); + if (copy_from_user(&d, (drm_dma_t *)arg, sizeof(d))) + return -EFAULT; DRM_DEBUG("%d %d: %d send, %d req\n", current->pid, d.context, d.send_count, d.request_count); @@ -621,7 +622,8 @@ DRM_DEBUG("%d returning, granted = %d\n", current->pid, d.granted_count); - copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d))) + return -EFAULT; return retcode; } @@ -710,7 +712,8 @@ drm_control_t ctl; int retcode; - copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); + if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl))) + return -EFAULT; switch (ctl.func) { case DRM_INST_HANDLER: @@ -742,7 +745,8 @@ dev->lck_start = start = get_cycles(); #endif - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -804,6 +808,15 @@ drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */ if (!ret) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + if (lock.flags & _DRM_LOCK_READY) gamma_dma_ready(dev); if (lock.flags & _DRM_LOCK_QUIESCENT) { diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/gamma_drv.c linux/drivers/char/drm/gamma_drv.c --- v2.4.0-test7/linux/drivers/char/drm/gamma_drv.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/gamma_drv.c Tue Aug 29 21:09:10 2000 @@ -405,17 +405,18 @@ drm_version_t version; int len; - copy_from_user_ret(&version, + if (copy_from_user(&version, (drm_version_t *)arg, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; #define DRM_COPY(name,value) \ len = strlen(value); \ if (len > name##_len) len = name##_len; \ name##_len = strlen(value); \ if (len && name) { \ - copy_to_user_ret(name, value, len, -EFAULT); \ + if (copy_to_user(name, value, len)) \ + return -EFAULT; \ } version.version_major = GAMMA_MAJOR; @@ -426,10 +427,10 @@ DRM_COPY(version.date, GAMMA_DATE); DRM_COPY(version.desc, GAMMA_DESC); - copy_to_user_ret((drm_version_t *)arg, + if (copy_to_user((drm_version_t *)arg, &version, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; return 0; } @@ -537,7 +538,8 @@ drm_device_t *dev = priv->dev; drm_lock_t lock; - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -564,5 +566,6 @@ - dev->lck_start)]); #endif + unblock_all_signals(); return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/i810_bufs.c linux/drivers/char/drm/i810_bufs.c --- v2.4.0-test7/linux/drivers/char/drm/i810_bufs.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/i810_bufs.c Tue Aug 29 14:09:15 2000 @@ -56,10 +56,10 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; count = request.count; order = drm_order(request.size); @@ -155,10 +155,10 @@ request.count = entry->buf_count; request.size = size; - copy_to_user_ret((drm_buf_desc_t *)arg, + if (copy_to_user((drm_buf_desc_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; atomic_dec(&dev->buf_alloc); dma->flags = _DRM_DMA_USE_AGP; @@ -170,10 +170,10 @@ { drm_buf_desc_t request; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; if(request.flags & _DRM_AGP_BUFFER) return i810_addbufs_agp(inode, filp, cmd, arg); @@ -201,10 +201,10 @@ ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_info_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { if (dma->bufs[i].buf_count) ++count; @@ -215,28 +215,26 @@ if (request.count >= count) { for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { if (dma->bufs[i].buf_count) { - copy_to_user_ret(&request.list[count].count, + if (copy_to_user(&request.list[count].count, &dma->bufs[i].buf_count, sizeof(dma->bufs[0] - .buf_count), - -EFAULT); - copy_to_user_ret(&request.list[count].size, + .buf_count)) || + copy_to_user(&request.list[count].size, &dma->bufs[i].buf_size, - sizeof(dma->bufs[0].buf_size), - -EFAULT); - copy_to_user_ret(&request.list[count].low_mark, + sizeof(dma->bufs[0].buf_size)) || + copy_to_user(&request.list[count].low_mark, &dma->bufs[i] .freelist.low_mark, sizeof(dma->bufs[0] - .freelist.low_mark), - -EFAULT); - copy_to_user_ret(&request.list[count] + .freelist.low_mark)) || + copy_to_user(&request.list[count] .high_mark, &dma->bufs[i] .freelist.high_mark, sizeof(dma->bufs[0] - .freelist.high_mark), - -EFAULT); + .freelist.high_mark))) + return -EFAULT; + DRM_DEBUG("%d %d %d %d %d\n", i, dma->bufs[i].buf_count, @@ -249,10 +247,10 @@ } request.count = count; - copy_to_user_ret((drm_buf_info_t *)arg, + if (copy_to_user((drm_buf_info_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; return 0; } @@ -269,10 +267,10 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; DRM_DEBUG("%d, %d, %d\n", request.size, request.low_mark, request.high_mark); @@ -304,17 +302,17 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_free_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; DRM_DEBUG("%d\n", request.count); for (i = 0; i < request.count; i++) { - copy_from_user_ret(&idx, + if (copy_from_user(&idx, &request.list[i], - sizeof(idx), - -EFAULT); + sizeof(idx))) + return -EFAULT; if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("Index %d (of %d max)\n", idx, dma->buf_count - 1); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/i810_context.c linux/drivers/char/drm/i810_context.c --- v2.4.0-test7/linux/drivers/char/drm/i810_context.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/i810_context.c Tue Aug 29 14:09:15 2000 @@ -103,19 +103,21 @@ int i; DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); - copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) + return -EFAULT; if (res.count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - copy_to_user_ret(&res.contexts[i], + if (copy_to_user(&res.contexts[i], &i, - sizeof(i), - -EFAULT); + sizeof(i))) + return -EFAULT; } } res.count = DRM_RESERVED_CONTEXTS; - copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) + return -EFAULT; return 0; } @@ -126,7 +128,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; if ((ctx.handle = i810_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { /* Skip kernel's context and get a new one. */ ctx.handle = i810_alloc_queue(dev); @@ -137,7 +140,8 @@ return -ENOMEM; } DRM_DEBUG("%d\n", ctx.handle); - copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -153,10 +157,12 @@ { drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; /* This is 0, because we don't hanlde any context flags */ ctx.flags = 0; - copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -167,7 +173,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); return i810_context_switch(dev, dev->last_context, ctx.handle); } @@ -179,7 +186,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); i810_context_switch_complete(dev, ctx.handle); @@ -193,7 +201,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); if(ctx.handle != DRM_KERNEL_CONTEXT) { drm_ctxbitmap_free(dev, ctx.handle); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c --- v2.4.0-test7/linux/drivers/char/drm/i810_dma.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/i810_dma.c Tue Aug 29 21:09:10 2000 @@ -490,8 +490,8 @@ drm_i810_init_t init; int retcode = 0; - copy_from_user_ret(&init, (drm_i810_init_t *)arg, - sizeof(init), -EFAULT); + if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init))) + return -EFAULT; switch(init.func) { case I810_INIT_DMA: @@ -1005,7 +1005,8 @@ DRM_DEBUG( "i810_control\n"); - copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); + if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl))) + return -EFAULT; switch (ctl.func) { case DRM_INST_HANDLER: @@ -1178,7 +1179,8 @@ int ret = 0; drm_lock_t lock; - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -1227,6 +1229,15 @@ } if (!ret) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + if (lock.flags & _DRM_LOCK_QUIESCENT) { DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); DRM_DEBUG("fred\n"); @@ -1266,8 +1277,8 @@ dev_priv->sarea_priv; drm_i810_vertex_t vertex; - copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex), - -EFAULT); + if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex))) + return -EFAULT; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_dma_vertex called without lock held\n"); @@ -1298,8 +1309,8 @@ drm_device_t *dev = priv->dev; drm_i810_clear_t clear; - copy_from_user_ret(&clear, (drm_i810_clear_t *)arg, sizeof(clear), - -EFAULT); + if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear))) + return -EFAULT; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_clear_bufs called without lock held\n"); @@ -1356,7 +1367,8 @@ dev_priv->sarea_priv; DRM_DEBUG("getbuf\n"); - copy_from_user_ret(&d, (drm_i810_dma_t *)arg, sizeof(d), -EFAULT); + if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d))) + return -EFAULT; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_dma called without lock held\n"); @@ -1370,7 +1382,8 @@ DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n", current->pid, retcode, d.granted); - copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d))) + return -EFAULT; sarea_priv->last_dispatch = (int) hw_status[5]; return retcode; @@ -1395,14 +1408,16 @@ return -EINVAL; } - copy_from_user_ret(&d, (drm_i810_copy_t *)arg, sizeof(d), -EFAULT); + if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d))) + return -EFAULT; if(d.idx > dma->buf_count) return -EINVAL; buf = dma->buflist[ d.idx ]; buf_priv = buf->dev_private; if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM; - copy_from_user_ret(buf_priv->virtual, d.address, d.used, -EFAULT); + if (copy_from_user(buf_priv->virtual, d.address, d.used)) + return -EFAULT; sarea_priv->last_dispatch = (int) hw_status[5]; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/i810_drv.c linux/drivers/char/drm/i810_drv.c --- v2.4.0-test7/linux/drivers/char/drm/i810_drv.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/i810_drv.c Tue Sep 5 13:51:30 2000 @@ -428,17 +428,18 @@ drm_version_t version; int len; - copy_from_user_ret(&version, + if (copy_from_user(&version, (drm_version_t *)arg, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; #define DRM_COPY(name,value) \ len = strlen(value); \ if (len > name##_len) len = name##_len; \ name##_len = strlen(value); \ if (len && name) { \ - copy_to_user_ret(name, value, len, -EFAULT); \ + if (copy_to_user(name, value, len)) \ + return -EFAULT; \ } version.version_major = I810_MAJOR; @@ -449,10 +450,10 @@ DRM_COPY(version.date, I810_DATE); DRM_COPY(version.desc, I810_DESC); - copy_to_user_ret((drm_version_t *)arg, + if (copy_to_user((drm_version_t *)arg, &version, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; return 0; } @@ -616,7 +617,8 @@ drm_device_t *dev = priv->dev; drm_lock_t lock; - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -642,5 +644,6 @@ - dev->lck_start)]); #endif + unblock_all_signals(); return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/ioctl.c linux/drivers/char/drm/ioctl.c --- v2.4.0-test7/linux/drivers/char/drm/ioctl.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/ioctl.c Tue Aug 29 14:09:15 2000 @@ -38,13 +38,15 @@ drm_irq_busid_t p; struct pci_dev *dev; - copy_from_user_ret(&p, (drm_irq_busid_t *)arg, sizeof(p), -EFAULT); + if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p))) + return -EFAULT; dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum)); if (dev) p.irq = dev->irq; else p.irq = 0; DRM_DEBUG("%d:%d:%d => IRQ %d\n", p.busnum, p.devnum, p.funcnum, p.irq); - copy_to_user_ret((drm_irq_busid_t *)arg, &p, sizeof(p), -EFAULT); + if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p))) + return -EFAULT; return 0; } @@ -55,13 +57,15 @@ drm_device_t *dev = priv->dev; drm_unique_t u; - copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT); + if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u))) + return -EFAULT; if (u.unique_len >= dev->unique_len) { - copy_to_user_ret(u.unique, dev->unique, dev->unique_len, - -EFAULT); + if (copy_to_user(u.unique, dev->unique, dev->unique_len)) + return -EFAULT; } u.unique_len = dev->unique_len; - copy_to_user_ret((drm_unique_t *)arg, &u, sizeof(u), -EFAULT); + if (copy_to_user((drm_unique_t *)arg, &u, sizeof(u))) + return -EFAULT; return 0; } @@ -72,15 +76,19 @@ drm_device_t *dev = priv->dev; drm_unique_t u; - if (dev->unique_len || dev->unique) return -EBUSY; + if (dev->unique_len || dev->unique) + return -EBUSY; - copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT); - if (!u.unique_len) return -EINVAL; + if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u))) + return -EFAULT; + + if (!u.unique_len) + return -EINVAL; dev->unique_len = u.unique_len; dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER); - copy_from_user_ret(dev->unique, u.unique, dev->unique_len, - -EFAULT); + if (copy_from_user(dev->unique, u.unique, dev->unique_len)) + return -EFAULT; dev->unique[dev->unique_len] = '\0'; dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2, diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/lock.c linux/drivers/char/drm/lock.c --- v2.4.0-test7/linux/drivers/char/drm/lock.c Wed Aug 23 18:36:36 2000 +++ linux/drivers/char/drm/lock.c Tue Aug 29 14:09:15 2000 @@ -218,7 +218,8 @@ DRM_DEBUG("\n"); - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); drm_flush_unblock(dev, lock.context, lock.flags); return ret; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/mga_bufs.c linux/drivers/char/drm/mga_bufs.c --- v2.4.0-test7/linux/drivers/char/drm/mga_bufs.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/mga_bufs.c Tue Aug 29 14:09:15 2000 @@ -57,10 +57,10 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; count = request.count; order = drm_order(request.size); @@ -173,10 +173,10 @@ request.count = entry->buf_count; request.size = size; - copy_to_user_ret((drm_buf_desc_t *)arg, + if (copy_to_user((drm_buf_desc_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; atomic_dec(&dev->buf_alloc); @@ -219,10 +219,10 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; count = request.count; order = drm_order(request.size); @@ -348,10 +348,10 @@ request.count = entry->buf_count; request.size = size; - copy_to_user_ret((drm_buf_desc_t *)arg, + if (copy_to_user((drm_buf_desc_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; atomic_dec(&dev->buf_alloc); return 0; @@ -362,10 +362,10 @@ { drm_buf_desc_t request; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; if(request.flags & _DRM_AGP_BUFFER) return mga_addbufs_agp(inode, filp, cmd, arg); @@ -393,10 +393,10 @@ ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_info_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { if (dma->bufs[i].buf_count) ++count; @@ -407,28 +407,26 @@ if (request.count >= count) { for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { if (dma->bufs[i].buf_count) { - copy_to_user_ret(&request.list[count].count, + if (copy_to_user(&request.list[count].count, &dma->bufs[i].buf_count, sizeof(dma->bufs[0] - .buf_count), - -EFAULT); - copy_to_user_ret(&request.list[count].size, + .buf_count)) || + copy_to_user(&request.list[count].size, &dma->bufs[i].buf_size, - sizeof(dma->bufs[0].buf_size), - -EFAULT); - copy_to_user_ret(&request.list[count].low_mark, + sizeof(dma->bufs[0].buf_size)) || + copy_to_user(&request.list[count].low_mark, &dma->bufs[i] .freelist.low_mark, sizeof(dma->bufs[0] - .freelist.low_mark), - -EFAULT); - copy_to_user_ret(&request.list[count] + .freelist.low_mark)) || + copy_to_user(&request.list[count] .high_mark, &dma->bufs[i] .freelist.high_mark, sizeof(dma->bufs[0] - .freelist.high_mark), - -EFAULT); + .freelist.high_mark))) + return -EFAULT; + DRM_DEBUG("%d %d %d %d %d\n", i, dma->bufs[i].buf_count, @@ -441,10 +439,10 @@ } request.count = count; - copy_to_user_ret((drm_buf_info_t *)arg, + if (copy_to_user((drm_buf_info_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; return 0; } @@ -461,10 +459,10 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; DRM_DEBUG("%d, %d, %d\n", request.size, request.low_mark, request.high_mark); @@ -496,17 +494,17 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_free_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; DRM_DEBUG("%d\n", request.count); for (i = 0; i < request.count; i++) { - copy_from_user_ret(&idx, + if (copy_from_user(&idx, &request.list[i], - sizeof(idx), - -EFAULT); + sizeof(idx))) + return -EFAULT; if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("Index %d (of %d max)\n", idx, dma->buf_count - 1); @@ -550,10 +548,10 @@ ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_map_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; DRM_DEBUG("mga_mapbufs\n"); DRM_DEBUG("dma->flags : %x\n", dma->flags); @@ -628,10 +626,10 @@ request.count = dma->buf_count; DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - copy_to_user_ret((drm_buf_map_t *)arg, + if (copy_to_user((drm_buf_map_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; DRM_DEBUG("retcode : %d\n", retcode); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/mga_context.c linux/drivers/char/drm/mga_context.c --- v2.4.0-test7/linux/drivers/char/drm/mga_context.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/mga_context.c Tue Aug 29 14:09:15 2000 @@ -103,19 +103,21 @@ int i; DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); - copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) + return -EFAULT; if (res.count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - copy_to_user_ret(&res.contexts[i], + if (copy_to_user(&res.contexts[i], &i, - sizeof(i), - -EFAULT); + sizeof(i))) + return -EFAULT; } } res.count = DRM_RESERVED_CONTEXTS; - copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) + return -EFAULT; return 0; } @@ -126,7 +128,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; if ((ctx.handle = mga_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { /* Skip kernel's context and get a new one. */ ctx.handle = mga_alloc_queue(dev); @@ -137,7 +140,8 @@ return -ENOMEM; } DRM_DEBUG("%d\n", ctx.handle); - copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -153,10 +157,12 @@ { drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; /* This is 0, because we don't hanlde any context flags */ ctx.flags = 0; - copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -167,7 +173,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); return mga_context_switch(dev, dev->last_context, ctx.handle); } @@ -179,7 +186,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); mga_context_switch_complete(dev, ctx.handle); @@ -193,7 +201,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); if(ctx.handle != DRM_KERNEL_CONTEXT) { drm_ctxbitmap_free(dev, ctx.handle); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/mga_dma.c linux/drivers/char/drm/mga_dma.c --- v2.4.0-test7/linux/drivers/char/drm/mga_dma.c Wed Aug 23 18:36:36 2000 +++ linux/drivers/char/drm/mga_dma.c Tue Aug 29 21:09:10 2000 @@ -82,6 +82,7 @@ return; } +#ifdef __i386__ void mga_flush_write_combine(void) { int xchangeDummy; @@ -92,6 +93,11 @@ " movl $0,%%eax ; cpuid ; pop %%edx ; pop %%ecx ; pop %%ebx ;" " pop %%eax" : /* no outputs */ : /* no inputs */ ); } +#else +void mga_flush_write_combine(void) +{ +} +#endif /* These are two age tags that will never be sent to * the hardware */ @@ -850,7 +856,8 @@ DRM_DEBUG("%s\n", __FUNCTION__); - copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT); + if (copy_from_user(&init, (drm_mga_init_t *)arg, sizeof(init))) + return -EFAULT; switch(init.func) { case MGA_INIT_DMA: @@ -932,7 +939,8 @@ drm_device_t *dev = priv->dev; drm_control_t ctl; - copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); + if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl))) + return -EFAULT; DRM_DEBUG("%s\n", __FUNCTION__); @@ -1019,7 +1027,8 @@ drm_lock_t lock; DRM_DEBUG("%s\n", __FUNCTION__); - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -1068,6 +1077,15 @@ } if (!ret) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + if (lock.flags & _DRM_LOCK_QUIESCENT) { DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); mga_flush_queue(dev); @@ -1088,7 +1106,8 @@ drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; DRM_DEBUG("%s\n", __FUNCTION__); - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_flush_ioctl called without lock held\n"); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/mga_drv.c linux/drivers/char/drm/mga_drv.c --- v2.4.0-test7/linux/drivers/char/drm/mga_drv.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/mga_drv.c Tue Aug 29 21:09:10 2000 @@ -444,17 +444,18 @@ drm_version_t version; int len; - copy_from_user_ret(&version, + if (copy_from_user(&version, (drm_version_t *)arg, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; #define DRM_COPY(name,value) \ len = strlen(value); \ if (len > name##_len) len = name##_len; \ name##_len = strlen(value); \ if (len && name) { \ - copy_to_user_ret(name, value, len, -EFAULT); \ + if (copy_to_user(name, value, len)) \ + return -EFAULT; \ } version.version_major = MGA_MAJOR; @@ -465,10 +466,10 @@ DRM_COPY(version.date, MGA_DATE); DRM_COPY(version.desc, MGA_DESC); - copy_to_user_ret((drm_version_t *)arg, + if (copy_to_user((drm_version_t *)arg, &version, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; return 0; } @@ -633,7 +634,8 @@ drm_device_t *dev = priv->dev; drm_lock_t lock; - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -655,5 +657,6 @@ DRM_ERROR("\n"); } + unblock_all_signals(); return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/mga_drv.h linux/drivers/char/drm/mga_drv.h --- v2.4.0-test7/linux/drivers/char/drm/mga_drv.h Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/mga_drv.h Tue Aug 29 21:09:10 2000 @@ -39,8 +39,8 @@ typedef struct { u32 buffer_status; - unsigned int num_dwords; - unsigned int max_dwords; + int num_dwords; + int max_dwords; u32 *current_dma_ptr; u32 *head; u32 phys_head; @@ -209,19 +209,27 @@ #define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ int outcount, num_dwords -#define PRIM_OVERFLOW(dev, dev_priv, length) do { \ - drm_mga_prim_buf_t *tmp_buf = \ - dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ - if( test_bit(MGA_BUF_NEEDS_OVERFLOW, \ - &tmp_buf->buffer_status)) { \ - mga_advance_primary(dev); \ - mga_dma_schedule(dev, 1); \ - } else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length ||\ - tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ - set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status); \ - mga_advance_primary(dev); \ - mga_dma_schedule(dev, 1); \ - } \ +#define PRIM_OVERFLOW(dev, dev_priv, length) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if( test_bit(MGA_BUF_NEEDS_OVERFLOW, \ + &tmp_buf->buffer_status)) { \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + tmp_buf = dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + } else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length || \ + tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ + set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status); \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + tmp_buf = dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + } \ + if(MGA_VERBOSE) \ + DRM_DEBUG("PRIMGETPTR in %s\n", __FUNCTION__); \ + dma_ptr = tmp_buf->current_dma_ptr; \ + num_dwords = tmp_buf->num_dwords; \ + phys_head = tmp_buf->phys_head; \ + outcount = 0; \ } while(0) #define PRIMGETPTR(dev_priv) do { \ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/mga_state.c linux/drivers/char/drm/mga_state.c --- v2.4.0-test7/linux/drivers/char/drm/mga_state.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/mga_state.c Tue Aug 29 21:09:10 2000 @@ -34,6 +34,22 @@ #include "mga_drv.h" #include "drm.h" +/* If you change the functions to set state, PLEASE + * change these values + */ + +#define MGAEMITCLIP_SIZE 10 +#define MGAEMITCTX_SIZE 15 +#define MGAG200EMITTEX_SIZE 20 +#define MGAG400EMITTEX0_SIZE 30 +#define MGAG400EMITTEX1_SIZE 25 +#define MGAG400EMITPIPE_SIZE 50 +#define MGAG200EMITPIPE_SIZE 15 + +#define MAX_STATE_SIZE ((MGAEMITCLIP_SIZE * MGA_NR_SAREA_CLIPRECTS) + \ + MGAEMITCTX_SIZE + MGAG400EMITTEX0_SIZE + \ + MGAG400EMITTEX1_SIZE + MGAG400EMITPIPE_SIZE) + static void mgaEmitClipRect(drm_mga_private_t * dev_priv, drm_clip_rect_t * box) { @@ -60,8 +76,8 @@ PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_CXBNDRY, ((box->x2) << 16) | (box->x1)); - PRIMOUTREG(MGAREG_YTOP, box->y1 * dev_priv->stride / 2); - PRIMOUTREG(MGAREG_YBOT, box->y2 * dev_priv->stride / 2); + PRIMOUTREG(MGAREG_YTOP, box->y1 * dev_priv->stride / dev_priv->cpp); + PRIMOUTREG(MGAREG_YBOT, box->y2 * dev_priv->stride / dev_priv->cpp); PRIMADVANCE(dev_priv); } @@ -224,7 +240,6 @@ PRIMADVANCE(dev_priv); } -#define EMIT_PIPE 50 static void mgaG400EmitPipe(drm_mga_private_t * dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -492,7 +507,6 @@ y2 = length / 64; PRIM_OVERFLOW(dev, dev_priv, 30); - PRIMGETPTR(dev_priv); PRIMOUTREG(MGAREG_DSTORG, destOrg); PRIMOUTREG(MGAREG_MACCESS, 0x00000000); @@ -526,7 +540,6 @@ int length = buf->used; int use_agp = PDEA_pagpxfer_enable; int i = 0; - int primary_needed; PRIMLOCALS; DRM_DEBUG("%s\n", __FUNCTION__); @@ -542,9 +555,8 @@ * these numbers (Overestimating this doesn't hurt). */ buf_priv->dispatched = 1; - primary_needed = (50 + 15 + 15 + 30 + 25 + - 10 + 15 * MGA_NR_SAREA_CLIPRECTS); - PRIM_OVERFLOW(dev, dev_priv, primary_needed); + PRIM_OVERFLOW(dev, dev_priv, + (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS))); mgaEmitState(dev_priv); do { if (i < sarea_priv->nbox) { @@ -592,7 +604,6 @@ unsigned int address = (unsigned int) buf->bus_address; int use_agp = PDEA_pagpxfer_enable; int i = 0; - int primary_needed; PRIMLOCALS; DRM_DEBUG("%s\n", __FUNCTION__); @@ -606,9 +617,8 @@ * these numbers (Overestimating this doesn't hurt). */ buf_priv->dispatched = 1; - primary_needed = (50 + 15 + 15 + 30 + 25 + - 10 + 15 * MGA_NR_SAREA_CLIPRECTS); - PRIM_OVERFLOW(dev, dev_priv, primary_needed); + PRIM_OVERFLOW(dev, dev_priv, + (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS))); mgaEmitState(dev_priv); do { @@ -657,7 +667,6 @@ drm_clip_rect_t *pbox = sarea_priv->boxes; unsigned int cmd; int i; - int primary_needed; PRIMLOCALS; DRM_DEBUG("%s\n", __FUNCTION__); @@ -666,11 +675,7 @@ else cmd = MGA_CLEAR_CMD | DC_atype_rstr; - primary_needed = nbox * 70; - if (primary_needed == 0) - primary_needed = 70; - PRIM_OVERFLOW(dev, dev_priv, primary_needed); - PRIMGETPTR(dev_priv); + PRIM_OVERFLOW(dev, dev_priv, 35 * MGA_NR_SAREA_CLIPRECTS); for (i = 0; i < nbox; i++) { unsigned int height = pbox[i].y2 - pbox[i].y1; @@ -741,14 +746,12 @@ int nbox = sarea_priv->nbox; drm_clip_rect_t *pbox = sarea_priv->boxes; int i; - int primary_needed; + int pixel_stride = dev_priv->stride / dev_priv->cpp; + PRIMLOCALS; DRM_DEBUG("%s\n", __FUNCTION__); - primary_needed = nbox * 5; - primary_needed += 65; - PRIM_OVERFLOW(dev, dev_priv, primary_needed); - PRIMGETPTR(dev_priv); + PRIM_OVERFLOW(dev, dev_priv, (MGA_NR_SAREA_CLIPRECTS * 5) + 20); PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); @@ -758,7 +761,7 @@ PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess); PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset); - PRIMOUTREG(MGAREG_AR5, dev_priv->stride / 2); + PRIMOUTREG(MGAREG_AR5, pixel_stride); PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); @@ -767,7 +770,7 @@ for (i = 0; i < nbox; i++) { unsigned int h = pbox[i].y2 - pbox[i].y1; - unsigned int start = pbox[i].y1 * dev_priv->stride / 2; + unsigned int start = pbox[i].y1 * pixel_stride; DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2); @@ -799,8 +802,8 @@ drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_clear_t clear; - copy_from_user_ret(&clear, (drm_mga_clear_t *) arg, sizeof(clear), - -EFAULT); + if (copy_from_user(&clear, (drm_mga_clear_t *) arg, sizeof(clear))) + return -EFAULT; DRM_DEBUG("%s\n", __FUNCTION__); if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { @@ -868,8 +871,8 @@ DRM_DEBUG("%s\n", __FUNCTION__); DRM_DEBUG("Starting Iload\n"); - copy_from_user_ret(&iload, (drm_mga_iload_t *) arg, sizeof(iload), - -EFAULT); + if (copy_from_user(&iload, (drm_mga_iload_t *) arg, sizeof(iload))) + return -EFAULT; if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_iload called without lock held\n"); @@ -913,8 +916,8 @@ drm_mga_vertex_t vertex; DRM_DEBUG("%s\n", __FUNCTION__); - copy_from_user_ret(&vertex, (drm_mga_vertex_t *) arg, - sizeof(vertex), -EFAULT); + if (copy_from_user(&vertex, (drm_mga_vertex_t *) arg, sizeof(vertex))) + return -EFAULT; if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_vertex called without lock held\n"); @@ -962,8 +965,8 @@ drm_mga_indices_t indices; DRM_DEBUG("%s\n", __FUNCTION__); - copy_from_user_ret(&indices, (drm_mga_indices_t *) arg, - sizeof(indices), -EFAULT); + if (copy_from_user(&indices, (drm_mga_indices_t *) arg, sizeof(indices))) + return -EFAULT; if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_indices called without lock held\n"); @@ -1008,10 +1011,11 @@ if (!buf) break; buf->pid = current->pid; - copy_to_user_ret(&d->request_indices[i], - &buf->idx, sizeof(buf->idx), -EFAULT); - copy_to_user_ret(&d->request_sizes[i], - &buf->total, sizeof(buf->total), -EFAULT); + if (copy_to_user(&d->request_indices[i], + &buf->idx, sizeof(buf->idx)) || + copy_to_user(&d->request_sizes[i], + &buf->total, sizeof(buf->total))) + return -EFAULT; ++d->granted_count; } return 0; @@ -1027,7 +1031,8 @@ drm_dma_t d; DRM_DEBUG("%s\n", __FUNCTION__); - copy_from_user_ret(&d, (drm_dma_t *) arg, sizeof(d), -EFAULT); + if (copy_from_user(&d, (drm_dma_t *) arg, sizeof(d))) + return -EFAULT; DRM_DEBUG("%d %d: %d send, %d req\n", current->pid, d.context, d.send_count, d.request_count); @@ -1062,6 +1067,7 @@ DRM_DEBUG("%d returning, granted = %d\n", current->pid, d.granted_count); - copy_to_user_ret((drm_dma_t *) arg, &d, sizeof(d), -EFAULT); + if (copy_to_user((drm_dma_t *) arg, &d, sizeof(d))) + return -EFAULT; return retcode; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/r128_bufs.c linux/drivers/char/drm/r128_bufs.c --- v2.4.0-test7/linux/drivers/char/drm/r128_bufs.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/r128_bufs.c Tue Aug 29 14:09:15 2000 @@ -60,10 +60,10 @@ if (!dma) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; count = request.count; order = drm_order(request.size); @@ -173,10 +173,10 @@ request.count = entry->buf_count; request.size = size; - copy_to_user_ret((drm_buf_desc_t *)arg, + if (copy_to_user((drm_buf_desc_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; dma->flags = _DRM_DMA_USE_AGP; @@ -195,10 +195,10 @@ if (!dev_priv || dev_priv->is_pci) return -EINVAL; - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) if (request.flags & _DRM_AGP_BUFFER) @@ -234,10 +234,10 @@ ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - copy_from_user_ret(&request, + if (copy_from_user(&request, (drm_buf_map_t *)arg, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; if (request.count >= dma->buf_count) { if (dma->flags & _DRM_DMA_USE_AGP) { @@ -300,10 +300,10 @@ request.count = dma->buf_count; DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - copy_to_user_ret((drm_buf_map_t *)arg, + if (copy_to_user((drm_buf_map_t *)arg, &request, - sizeof(request), - -EFAULT); + sizeof(request))) + return -EFAULT; return retcode; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/r128_context.c linux/drivers/char/drm/r128_context.c --- v2.4.0-test7/linux/drivers/char/drm/r128_context.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/r128_context.c Tue Aug 29 14:09:15 2000 @@ -103,19 +103,21 @@ int i; DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); - copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) + return -EFAULT; if (res.count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - copy_to_user_ret(&res.contexts[i], + if (copy_to_user(&res.contexts[i], &i, - sizeof(i), - -EFAULT); + sizeof(i))) + return -EFAULT; } } res.count = DRM_RESERVED_CONTEXTS; - copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) + return -EFAULT; return 0; } @@ -127,7 +129,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; if ((ctx.handle = r128_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { /* Skip kernel's context and get a new one. */ ctx.handle = r128_alloc_queue(dev); @@ -139,7 +142,8 @@ return -ENOMEM; } - copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -148,7 +152,8 @@ { drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; if (ctx.flags==_DRM_CONTEXT_PRESERVED) r128_res_ctx.handle=ctx.handle; return 0; @@ -159,10 +164,12 @@ { drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; /* This is 0, because we don't hanlde any context flags */ ctx.flags = 0; - copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -173,7 +180,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); return r128_context_switch(dev, dev->last_context, ctx.handle); } @@ -185,7 +193,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); r128_context_switch_complete(dev, ctx.handle); @@ -199,7 +208,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); drm_ctxbitmap_free(dev, ctx.handle); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/r128_dma.c linux/drivers/char/drm/r128_dma.c --- v2.4.0-test7/linux/drivers/char/drm/r128_dma.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/r128_dma.c Tue Aug 29 21:09:10 2000 @@ -68,6 +68,7 @@ return R128_READ(R128_CLOCK_CNTL_DATA); } +#ifdef __i386__ static void r128_flush_write_combine(void) { int xchangeDummy; @@ -86,6 +87,11 @@ "pop %%ebx ;" "pop %%eax" : /* no outputs */ : /* no inputs */ ); } +#else +static void r128_flush_write_combine(void) +{ +} +#endif static void r128_status(drm_device_t *dev) { @@ -211,8 +217,8 @@ drm_device_t *dev = priv->dev; drm_r128_init_t init; - copy_from_user_ret(&init, (drm_r128_init_t *)arg, sizeof(init), - -EFAULT); + if (copy_from_user(&init, (drm_r128_init_t *)arg, sizeof(init))) + return -EFAULT; switch (init.func) { case R128_INIT_CCE: @@ -680,8 +686,8 @@ return -EINVAL; } - copy_from_user_ret(&packet, (drm_r128_packet_t *)arg, sizeof(packet), - -EFAULT); + if (copy_from_user(&packet, (drm_r128_packet_t *)arg, sizeof(packet))) + return -EFAULT; c = packet.count; size = c * sizeof(*buffer); @@ -696,7 +702,8 @@ } if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; - copy_from_user_ret(buffer, packet.buffer, size, -EFAULT); + if (copy_from_user(buffer, packet.buffer, size)) + return -EFAULT; if (dev_priv->cce_secure) ret = r128_submit_packets_ring_secure(dev, buffer, &c); @@ -706,7 +713,8 @@ c += left; } else { if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; - copy_from_user_ret(buffer, packet.buffer, size, -EFAULT); + if (copy_from_user(buffer, packet.buffer, size)) + return -EFAULT; if (dev_priv->cce_secure) ret = r128_submit_packets_pio_secure(dev, buffer, &c); @@ -717,8 +725,8 @@ kfree(buffer); packet.count = c; - copy_to_user_ret((drm_r128_packet_t *)arg, &packet, sizeof(packet), - -EFAULT); + if (copy_to_user((drm_r128_packet_t *)arg, &packet, sizeof(packet))) + return -EFAULT; if (ret) return ret; else if (c > 0) return -EAGAIN; @@ -855,14 +863,13 @@ buf = r128_freelist_get(dev); if (!buf) break; buf->pid = current->pid; - copy_to_user_ret(&v->request_indices[i], + if (copy_to_user(&v->request_indices[i], &buf->idx, - sizeof(buf->idx), - -EFAULT); - copy_to_user_ret(&v->request_sizes[i], + sizeof(buf->idx)) || + copy_to_user(&v->request_sizes[i], &buf->total, - sizeof(buf->total), - -EFAULT); + sizeof(buf->total))) + return -EFAULT; ++v->granted_count; } return 0; @@ -889,7 +896,8 @@ return -EINVAL; } - copy_from_user_ret(&v, (drm_r128_vertex_t *)arg, sizeof(v), -EFAULT); + if (copy_from_user(&v, (drm_r128_vertex_t *)arg, sizeof(v))) + return -EFAULT; DRM_DEBUG("%d: %d send, %d req\n", current->pid, v.send_count, v.request_count); @@ -916,7 +924,8 @@ DRM_DEBUG("%d returning, granted = %d\n", current->pid, v.granted_count); - copy_to_user_ret((drm_r128_vertex_t *)arg, &v, sizeof(v), -EFAULT); + if (copy_to_user((drm_r128_vertex_t *)arg, &v, sizeof(v))) + return -EFAULT; return retcode; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/r128_drv.c linux/drivers/char/drm/r128_drv.c --- v2.4.0-test7/linux/drivers/char/drm/r128_drv.c Wed Aug 23 18:36:36 2000 +++ linux/drivers/char/drm/r128_drv.c Tue Aug 29 14:09:15 2000 @@ -420,17 +420,18 @@ drm_version_t version; int len; - copy_from_user_ret(&version, + if (copy_from_user(&version, (drm_version_t *)arg, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; #define DRM_COPY(name,value) \ len = strlen(value); \ if (len > name##_len) len = name##_len; \ name##_len = strlen(value); \ if (len && name) { \ - copy_to_user_ret(name, value, len, -EFAULT); \ + if (copy_to_user(name, value, len)) \ + return -EFAULT; \ } version.version_major = R128_MAJOR; @@ -441,10 +442,10 @@ DRM_COPY(version.date, R128_DATE); DRM_COPY(version.desc, R128_DESC); - copy_to_user_ret((drm_version_t *)arg, + if (copy_to_user((drm_version_t *)arg, &version, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; return 0; } @@ -559,7 +560,8 @@ dev->lck_start = start = get_cycles(); #endif - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -698,7 +700,8 @@ drm_device_t *dev = priv->dev; drm_lock_t lock; - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/tdfx_context.c linux/drivers/char/drm/tdfx_context.c --- v2.4.0-test7/linux/drivers/char/drm/tdfx_context.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/tdfx_context.c Tue Aug 29 14:09:15 2000 @@ -105,19 +105,21 @@ int i; DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); - copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) + return -EFAULT; if (res.count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - copy_to_user_ret(&res.contexts[i], + if (copy_to_user(&res.contexts[i], &i, - sizeof(i), - -EFAULT); + sizeof(i))) + return -EFAULT; } } res.count = DRM_RESERVED_CONTEXTS; - copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) + return -EFAULT; return 0; } @@ -129,7 +131,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; if ((ctx.handle = tdfx_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { /* Skip kernel's context and get a new one. */ ctx.handle = tdfx_alloc_queue(dev); @@ -141,7 +144,8 @@ return -ENOMEM; } - copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -150,7 +154,8 @@ { drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; if (ctx.flags==_DRM_CONTEXT_PRESERVED) tdfx_res_ctx.handle=ctx.handle; return 0; @@ -161,10 +166,12 @@ { drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); - /* This is 0, because we don't hanlde any context flags */ + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; + /* This is 0, because we don't handle any context flags */ ctx.flags = 0; - copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx))) + return -EFAULT; return 0; } @@ -175,7 +182,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); return tdfx_context_switch(dev, dev->last_context, ctx.handle); } @@ -187,7 +195,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); tdfx_context_switch_complete(dev, ctx.handle); @@ -201,7 +210,8 @@ drm_device_t *dev = priv->dev; drm_ctx_t ctx; - copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); drm_ctxbitmap_free(dev, ctx.handle); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/drm/tdfx_drv.c linux/drivers/char/drm/tdfx_drv.c --- v2.4.0-test7/linux/drivers/char/drm/tdfx_drv.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/tdfx_drv.c Tue Aug 29 21:09:10 2000 @@ -379,17 +379,18 @@ drm_version_t version; int len; - copy_from_user_ret(&version, + if (copy_from_user(&version, (drm_version_t *)arg, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; #define DRM_COPY(name,value) \ len = strlen(value); \ if (len > name##_len) len = name##_len; \ name##_len = strlen(value); \ if (len && name) { \ - copy_to_user_ret(name, value, len, -EFAULT); \ + if (copy_to_user(name, value, len)) \ + return -EFAULT; \ } version.version_major = TDFX_MAJOR; @@ -400,10 +401,10 @@ DRM_COPY(version.date, TDFX_DATE); DRM_COPY(version.desc, TDFX_DESC); - copy_to_user_ret((drm_version_t *)arg, + if (copy_to_user((drm_version_t *)arg, &version, - sizeof(version), - -EFAULT); + sizeof(version))) + return -EFAULT; return 0; } @@ -518,7 +519,8 @@ dev->lck_start = start = get_cycles(); #endif - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -615,6 +617,15 @@ #endif if (!ret) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + if (lock.flags & _DRM_LOCK_READY) { /* Wait for space in DMA/FIFO */ } @@ -649,7 +660,8 @@ drm_device_t *dev = priv->dev; drm_lock_t lock; - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", @@ -679,5 +691,6 @@ } #endif + unblock_all_signals(); return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/ftape/lowlevel/ftape-ctl.c linux/drivers/char/ftape/lowlevel/ftape-ctl.c --- v2.4.0-test7/linux/drivers/char/ftape/lowlevel/ftape-ctl.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/ftape/lowlevel/ftape-ctl.c Sun Sep 3 11:47:19 2000 @@ -794,8 +794,8 @@ i, *ft_buffer[i]->address); } } - if (sigtestsetmask(¤t->signal, _DONT_BLOCK) && - !(sigtestsetmask(¤t->signal, _NEVER_BLOCK)) && + if (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK) && + !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK)) && ftape_tape_running) { TRACE(ft_t_warn, "Interrupted by fatal signal and tape still running"); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/ftape/lowlevel/ftape-rw.c linux/drivers/char/ftape/lowlevel/ftape-rw.c --- v2.4.0-test7/linux/drivers/char/ftape/lowlevel/ftape-rw.c Fri Jan 23 17:38:04 1998 +++ linux/drivers/char/ftape/lowlevel/ftape-rw.c Sun Sep 3 11:47:46 2000 @@ -433,7 +433,7 @@ result = ftape_ready_wait(ftape_timeout.pause,&status); } } while (ftape_tape_running - && !(sigtestsetmask(¤t->signal, _NEVER_BLOCK))); + && !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK))); #ifndef TESTING ft_location.known = 0; #endif @@ -661,7 +661,7 @@ * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!! */ if (ftape_read_id() < 0 || !ft_location.known || - sigtestsetmask(¤t->signal, _DONT_BLOCK)) { + sigtestsetmask(¤t->pending.signal, _DONT_BLOCK)) { ft_location.known = 0; if (!ftape_tape_running || ++failures > FT_SECTORS_PER_SEGMENT) { @@ -776,7 +776,7 @@ fast_seek(count, 1); logical_forward(); if (ftape_read_id() < 0 || !ft_location.known || - (sigtestsetmask(¤t->signal, _DONT_BLOCK))) { + (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { if ((!ftape_tape_running && !ft_location.known) || ++failures > FT_SECTORS_PER_SEGMENT) { TRACE_ABORT(-EIO, ft_t_err, @@ -1002,7 +1002,7 @@ while (result < 0 && retry++ <= 5 && !ft_failure && - !(sigtestsetmask(¤t->signal, _DONT_BLOCK))) { + !(sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { if (retry && start_offset < 5) { start_offset ++; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/ftape/lowlevel/ftape-tracing.h linux/drivers/char/ftape/lowlevel/ftape-tracing.h --- v2.4.0-test7/linux/drivers/char/ftape/lowlevel/ftape-tracing.h Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/ftape/lowlevel/ftape-tracing.h Sun Sep 3 11:22:09 2000 @@ -171,7 +171,7 @@ * but rather into ftape-rw.h (maybe) */ #define FT_SIGNAL_EXIT(sig_mask) \ - if (sigtestsetmask(¤t->signal, sig_mask)) { \ + if (sigtestsetmask(¤t->pending.signal, sig_mask)) { \ TRACE_ABORT(-EINTR, \ ft_t_warn, \ "interrupted by non-blockable signal"); \ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/nvram.c linux/drivers/char/nvram.c --- v2.4.0-test7/linux/drivers/char/nvram.c Fri Jul 14 12:12:09 2000 +++ linux/drivers/char/nvram.c Sat Aug 26 16:24:58 2000 @@ -246,7 +246,8 @@ spin_unlock_irq (&rtc_lock); - copy_to_user_ret (buf, contents, tmp - contents, -EFAULT); + if (copy_to_user (buf, contents, tmp - contents)) + return -EFAULT; *ppos = i; @@ -264,10 +265,9 @@ unsigned i = *ppos; char * tmp; - /* could comebody please help me indent this better? */ - copy_from_user_ret (contents, buf, (NVRAM_BYTES - i) < count ? - (NVRAM_BYTES - i) : count, - -EFAULT); + if (copy_from_user (contents, buf, (NVRAM_BYTES - i) < count ? + (NVRAM_BYTES - i) : count)) + return -EFAULT; spin_lock_irq (&rtc_lock); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.4.0-test7/linux/drivers/char/pc_keyb.c Fri Jul 14 12:12:09 2000 +++ linux/drivers/char/pc_keyb.c Mon Aug 28 12:06:33 2000 @@ -62,6 +62,7 @@ static void kbd_write_output_w(int data); #ifdef CONFIG_PSMOUSE static void aux_write_ack(int val); +static void __aux_write_ack(int val); #endif spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; @@ -404,7 +405,7 @@ } else if(scancode == AUX_RECONNECT){ queue->head = queue->tail = 0; /* Flush input queue */ - aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ + __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ return; } @@ -822,11 +823,8 @@ /* * Send a byte to the mouse & handle returned ack */ -static void aux_write_ack(int val) +static void __aux_write_ack(int val) { - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); @@ -834,6 +832,14 @@ /* we expect an ACK in response. */ mouse_reply_expected++; kb_wait(); +} + +static void aux_write_ack(int val) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + __aux_write_ack(val); spin_unlock_irqrestore(&kbd_controller_lock, flags); } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/pcmcia/serial_cb.c linux/drivers/char/pcmcia/serial_cb.c --- v2.4.0-test7/linux/drivers/char/pcmcia/serial_cb.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/pcmcia/serial_cb.c Sat Sep 2 00:15:37 2000 @@ -2,7 +2,7 @@ A driver for CardBus serial devices - serial_cb.c 1.15 1999/11/24 02:52:06 + serial_cb.c 1.20 2000/08/07 19:02:03 Copyright 1998, 1999 by Donald Becker and David Hinds @@ -16,7 +16,7 @@ Donald Becker may be reached as becker@CESDIS.edu, or C/O USRA Center of Excellence in Space Data and Information Sciences Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771 - David Hinds may be reached at dhinds@pcmcia.sourceforge.org + David Hinds may be reached at dahinds@users.sourceforge.net ======================================================================*/ @@ -39,7 +39,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"serial_cb.c 1.15 1999/11/24 02:52:06 (David Hinds)"; +"serial_cb.c 1.20 2000/08/07 19:02:03 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -134,7 +134,7 @@ static void serial_detach(dev_node_t *node) { - DEBUG(0, "serial_detach(tty%02d)\n", node->minor - 0x40); + DEBUG(0, "serial_detach(ttyS%02d)\n", node->minor - 0x40); unregister_serial(node->minor - 0x40); kfree(node); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/pcmcia/serial_cs.c linux/drivers/char/pcmcia/serial_cs.c --- v2.4.0-test7/linux/drivers/char/pcmcia/serial_cs.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/pcmcia/serial_cs.c Sat Sep 2 00:15:37 2000 @@ -2,7 +2,7 @@ A driver for PCMCIA serial devices - serial_cs.c 1.118 2000/05/04 01:29:47 + serial_cs.c 1.123 2000/08/24 18:46:38 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -58,7 +58,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"serial_cs.c 1.118 2000/05/04 01:29:47 (David Hinds)"; +"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -242,12 +242,11 @@ memset(&serial, 0, sizeof(serial)); serial.port = port; serial.irq = irq; - serial.flags = ASYNC_SKIP_TEST; - serial.flags |= (info->multi || info->slave) ? ASYNC_SHARE_IRQ : 0; + serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; line = register_serial(&serial); if (line < 0) { - printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04x, " - "irq %d failed\n", serial.port, serial.irq); + printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx," + " irq %d failed\n", (u_long)serial.port, serial.irq); return -1; } @@ -290,7 +289,7 @@ cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; config_info_t config; - int i, j; + int i, j, try; /* If the card is already configured, look up the port and irq */ i = CardServices(GetConfigurationInfo, handle, &config); @@ -315,22 +314,26 @@ tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - i = first_tuple(handle, &tuple, &parse); - while (i != CS_NO_MORE_ITEMS) { - if (i != CS_SUCCESS) goto next_entry; - if (cf->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = - cf->vpp1.param[CISTPL_POWER_VNOM]/10000; - if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && - (cf->io.win[0].base != 0)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); - if (i == CS_SUCCESS) goto found_port; + /* Two tries: without IO aliases, then with aliases */ + for (try = 0; try < 2; try++) { + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if (i != CS_SUCCESS) goto next_entry; + if (cf->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cf->vpp1.param[CISTPL_POWER_VNOM]/10000; + if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && + (cf->io.win[0].base != 0)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.IOAddrLines = (try == 0) ? + 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) goto found_port; + } + next_entry: + i = next_tuple(handle, &tuple, &parse); } - next_entry: - i = next_tuple(handle, &tuple, &parse); } /* Second pass: try to find an entry that isn't picky about @@ -448,6 +451,9 @@ } setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); + /* The Nokia cards are not really multiport cards */ + if (info->manfid == MANFID_NOKIA) + return 0; for (i = 0; i < info->multi-1; i++) setup_serial(info, base2+(8*i), link->irq.AssignedIRQ); @@ -518,11 +524,13 @@ (parse.funcid.func == CISTPL_FUNCID_MULTI) || (parse.funcid.func == CISTPL_FUNCID_SERIAL))) { tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - if ((first_tuple(handle, &tuple, &parse) == CS_SUCCESS) && - (((cf->io.nwin == 1) && (cf->io.win[0].len == 16)) || - ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && - (cf->io.win[1].len == 8)))) - info->multi = 2; + if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) + info->multi = cf->io.win[0].len >> 3; + if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && + (cf->io.win[1].len == 8)) + info->multi = 2; + } } if (info->multi > 1) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.4.0-test7/linux/drivers/char/pcxx.c Wed Aug 23 18:36:36 2000 +++ linux/drivers/char/pcxx.c Mon Aug 28 21:23:02 2000 @@ -14,8 +14,8 @@ * * This Driver is currently maintained by Christoph Lameter (christoph@lameter.com) * - * Please contact digi for support issues at digilnux@dgii.com. Some - * information (mostly of historical interest) can be found at + * Please contact digi for support issues at digilnux@dgii.com. + * Some more information can be found at * http://lameter.com/digi. * * 1.5.2 Fall 1995 Bug fixes by David Nugent @@ -39,17 +39,13 @@ * and Xeve also. * 1.6.2 August, 7, 2000: Arnaldo Carvalho de Melo * get rid of panics, release previously allocated resources + * 1.6.3 August, 23, 2000: Arnaldo Carvalho de Melo + * cleaned up wrt verify_area. + * Christoph Lameter: Update documentation, email addresses + * and URLs. Remove some obsolete code. * */ -#undef SPEED_HACK -/* If you define SPEED_HACK then you get the following Baudrate translation - 19200 = 57600 - 38400 = 115K - The driver supports the native 57.6K and 115K Baudrates under Linux, but - some distributions like Slackware 3.0 don't like these high baudrates. -*/ - #include #include #include @@ -81,7 +77,7 @@ #include #include -#define VERSION "1.6.2" +#define VERSION "1.6.3" #include "digi.h" #include "fep.h" @@ -713,11 +709,10 @@ tail &= (size - 1); stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1); count = MIN(stlen, count); - if (count) { - if (verify_area(VERIFY_READ, (char*)buf, count)) - count=0; - else copy_from_user(ch->tmp_buf, buf, count); - } + if (count) + if (copy_from_user(ch->tmp_buf, buf, count)) + count = 0; + buf = ch->tmp_buf; memoff(ch); restore_flags(flags); @@ -1896,11 +1891,6 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) { unsigned res = 0; -#ifdef SPEED_HACK - /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */ - if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200; - if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600; -#endif if (cflag & CBAUDEX) { ch->digiext.digi_flags |= DIGI_FAST; @@ -2124,7 +2114,6 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct channel *ch = (struct channel *) tty->driver_data; volatile struct board_chan *bc; int retval; @@ -2163,15 +2152,13 @@ return 0; case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned int *) arg); + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *)arg); case TIOCSSOFTCAR: { unsigned int value; - error = get_user( value, (unsigned int *) arg); - if (error) - return error; + if (get_user(value, (unsigned int *) arg)) + return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0)); } return 0; @@ -2199,18 +2186,16 @@ if(mstat & ch->dcd) mflag |= TIOCM_CD; - error = put_user(mflag, (unsigned int *) arg); - if(error) - return error; + if (put_user(mflag, (unsigned int *) arg)) + return -EFAULT; break; case TIOCMBIS: case TIOCMBIC: case TIOCMODS: case TIOCMSET: - error = get_user(mstat, (unsigned int *) arg); - if(error) - return error; + if (get_user(mstat, (unsigned int *) arg)) + return -EFAULT; mflag = 0; if(mstat & TIOCM_DTR) @@ -2262,10 +2247,8 @@ break; case DIGI_GETA: - if((error=verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t)))) - return(error); - - copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t)); + if (copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t))) + return -EFAULT; break; case DIGI_SETAW: @@ -2282,10 +2265,8 @@ /* Fall Thru */ case DIGI_SETA: - if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t)))) - return(error); - - copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t)); + if (copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t))) + return -EFAULT; #ifdef DEBUG_IOCTL printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags); #endif @@ -2319,10 +2300,8 @@ memoff(ch); restore_flags(flags); - if((error=verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow)))) - return(error); - - copy_to_user((char*)arg, &dflow, sizeof(dflow)); + if (copy_to_user((char*)arg, &dflow, sizeof(dflow))) + return -EFAULT; break; case DIGI_SETAFLOW: @@ -2335,10 +2314,8 @@ stopc = ch->stopca; } - if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(dflow)))) - return(error); - - copy_from_user(&dflow, (char*)arg, sizeof(dflow)); + if (copy_from_user(&dflow, (char*)arg, sizeof(dflow))) + return -EFAULT; if(dflow.startc != startc || dflow.stopc != stopc) { cli(); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/rocket.c linux/drivers/char/rocket.c --- v2.4.0-test7/linux/drivers/char/rocket.c Mon Jul 10 16:47:22 2000 +++ linux/drivers/char/rocket.c Sun Sep 3 11:43:18 2000 @@ -218,7 +218,7 @@ static inline int signal_pending(struct task_struct *p) { - return (p->signal & (~p->blocked != 0)); + return (p->signal & ~p->blocked) != 0; } #else diff -u --recursive --new-file v2.4.0-test7/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.4.0-test7/linux/drivers/char/stallion.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/stallion.c Tue Sep 5 14:03:52 2000 @@ -0,0 +1,5329 @@ +/*****************************************************************************/ + +/* + * stallion.c -- stallion multiport serial driver. + * + * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. + * + * This code is loosely based on the Linux serial driver, written by + * Linus Torvalds, Theodore T'so and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*****************************************************************************/ + +#include +#include +#include /* for linux/stallion.h */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_PCI +#include +#endif + +/*****************************************************************************/ + +/* + * Define different board types. Use the standard Stallion "assigned" + * board numbers. Boards supported in this driver are abbreviated as + * EIO = EasyIO and ECH = EasyConnection 8/32. + */ +#define BRD_EASYIO 20 +#define BRD_ECH 21 +#define BRD_ECHMC 22 +#define BRD_ECHPCI 26 +#define BRD_ECH64PCI 27 +#define BRD_EASYIOPCI 28 + +/* + * Define a configuration structure to hold the board configuration. + * Need to set this up in the code (for now) with the boards that are + * to be configured into the system. This is what needs to be modified + * when adding/removing/modifying boards. Each line entry in the + * stl_brdconf[] array is a board. Each line contains io/irq/memory + * ranges for that board (as well as what type of board it is). + * Some examples: + * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }, + * This line would configure an EasyIO board (4 or 8, no difference), + * at io address 2a0 and irq 10. + * Another example: + * { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 }, + * This line will configure an EasyConnection 8/32 board at primary io + * address 2a8, secondary io address 280 and irq 12. + * Enter as many lines into this array as you want (only the first 4 + * will actually be used!). Any combination of EasyIO and EasyConnection + * boards can be specified. EasyConnection 8/32 boards can share their + * secondary io addresses between each other. + * + * NOTE: there is no need to put any entries in this table for PCI + * boards. They will be found automatically by the driver - provided + * PCI BIOS32 support is compiled into the kernel. + */ + +typedef struct { + int brdtype; + int ioaddr1; + int ioaddr2; + unsigned long memaddr; + int irq; + int irqtype; +} stlconf_t; + +static stlconf_t stl_brdconf[] = { + /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/ +}; + +static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t); + +/*****************************************************************************/ + +/* + * Define some important driver characteristics. Device major numbers + * allocated as per Linux Device Registry. + */ +#ifndef STL_SIOMEMMAJOR +#define STL_SIOMEMMAJOR 28 +#endif +#ifndef STL_SERIALMAJOR +#define STL_SERIALMAJOR 24 +#endif +#ifndef STL_CALLOUTMAJOR +#define STL_CALLOUTMAJOR 25 +#endif + +#define STL_DRVTYPSERIAL 1 +#define STL_DRVTYPCALLOUT 2 + +/* + * Set the TX buffer size. Bigger is better, but we don't want + * to chew too much memory with buffers! + */ +#define STL_TXBUFLOW 512 +#define STL_TXBUFSIZE 4096 + +/*****************************************************************************/ + +/* + * Define our local driver identity first. Set up stuff to deal with + * all the local structures required by a serial tty driver. + */ +static char *stl_drvtitle = "Stallion Multiport Serial Driver"; +static char *stl_drvname = "stallion"; +static char *stl_drvversion = "5.6.0"; +static char *stl_serialname = "ttyE"; +static char *stl_calloutname = "cue"; + +static struct tty_driver stl_serial; +static struct tty_driver stl_callout; +static struct tty_struct *stl_ttys[STL_MAXDEVS]; +static struct termios *stl_termios[STL_MAXDEVS]; +static struct termios *stl_termioslocked[STL_MAXDEVS]; +static int stl_refcount = 0; + +/* + * We will need to allocate a temporary write buffer for chars that + * come direct from user space. The problem is that a copy from user + * space might cause a page fault (typically on a system that is + * swapping!). All ports will share one buffer - since if the system + * is already swapping a shared buffer won't make things any worse. + */ +static char *stl_tmpwritebuf; +static DECLARE_MUTEX(stl_tmpwritesem); + +/* + * Define a local default termios struct. All ports will be created + * with this termios initially. Basically all it defines is a raw port + * at 9600, 8 data bits, 1 stop bit. + */ +static struct termios stl_deftermios = { + 0, + 0, + (B9600 | CS8 | CREAD | HUPCL | CLOCAL), + 0, + 0, + INIT_C_CC +}; + +/* + * Define global stats structures. Not used often, and can be + * re-used for each stats call. + */ +static comstats_t stl_comstats; +static combrd_t stl_brdstats; +static stlbrd_t stl_dummybrd; +static stlport_t stl_dummyport; + +/* + * Define global place to put buffer overflow characters. + */ +static char stl_unwanted[SC26198_RXFIFOSIZE]; + +/* + * Keep track of what interrupts we have requested for us. + * We don't need to request an interrupt twice if it is being + * shared with another Stallion board. + */ +static int stl_gotintrs[STL_MAXBRDS]; +static int stl_numintrs = 0; + +/*****************************************************************************/ + +static stlbrd_t *stl_brds[STL_MAXBRDS]; + +/* + * Per board state flags. Used with the state field of the board struct. + * Not really much here! + */ +#define BRD_FOUND 0x1 + +/* + * Define the port structure istate flags. These set of flags are + * modified at interrupt time - so setting and reseting them needs + * to be atomic. Use the bit clear/setting routines for this. + */ +#define ASYI_TXBUSY 1 +#define ASYI_TXLOW 2 +#define ASYI_DCDCHANGE 3 +#define ASYI_TXFLOWED 4 + +/* + * Define an array of board names as printable strings. Handy for + * referencing boards when printing trace and stuff. + */ +static char *stl_brdnames[] = { + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + "EasyIO", + "EC8/32-AT", + "EC8/32-MC", + (char *) NULL, + (char *) NULL, + (char *) NULL, + "EC8/32-PCI", + "EC8/64-PCI", + "EasyIO-PCI", +}; + +/*****************************************************************************/ + +#ifdef MODULE +/* + * Define some string labels for arguments passed from the module + * load line. These allow for easy board definitions, and easy + * modification of the io, memory and irq resoucres. + */ + +static char *board0[4]; +static char *board1[4]; +static char *board2[4]; +static char *board3[4]; + +static char **stl_brdsp[] = { + (char **) &board0, + (char **) &board1, + (char **) &board2, + (char **) &board3 +}; + +/* + * Define a set of common board names, and types. This is used to + * parse any module arguments. + */ + +typedef struct stlbrdtype { + char *name; + int type; +} stlbrdtype_t; + +static stlbrdtype_t stl_brdstr[] = { + { "easyio", BRD_EASYIO }, + { "eio", BRD_EASYIO }, + { "20", BRD_EASYIO }, + { "ec8/32", BRD_ECH }, + { "ec8/32-at", BRD_ECH }, + { "ec8/32-isa", BRD_ECH }, + { "ech", BRD_ECH }, + { "echat", BRD_ECH }, + { "21", BRD_ECH }, + { "ec8/32-mc", BRD_ECHMC }, + { "ec8/32-mca", BRD_ECHMC }, + { "echmc", BRD_ECHMC }, + { "echmca", BRD_ECHMC }, + { "22", BRD_ECHMC }, + { "ec8/32-pc", BRD_ECHPCI }, + { "ec8/32-pci", BRD_ECHPCI }, + { "26", BRD_ECHPCI }, + { "ec8/64-pc", BRD_ECH64PCI }, + { "ec8/64-pci", BRD_ECH64PCI }, + { "ech-pci", BRD_ECH64PCI }, + { "echpci", BRD_ECH64PCI }, + { "echpc", BRD_ECH64PCI }, + { "27", BRD_ECH64PCI }, + { "easyio-pc", BRD_EASYIOPCI }, + { "easyio-pci", BRD_EASYIOPCI }, + { "eio-pci", BRD_EASYIOPCI }, + { "eiopci", BRD_EASYIOPCI }, + { "28", BRD_EASYIOPCI }, +}; + +/* + * Define the module agruments. + */ +MODULE_AUTHOR("Greg Ungerer"); +MODULE_DESCRIPTION("Stallion Multiport Serial Driver"); + +MODULE_PARM(board0, "1-4s"); +MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board1, "1-4s"); +MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board2, "1-4s"); +MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board3, "1-4s"); +MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]"); + +#endif + +/*****************************************************************************/ + +/* + * Hardware ID bits for the EasyIO and ECH boards. These defines apply + * to the directly accessible io ports of these boards (not the uarts - + * they are in cd1400.h and sc26198.h). + */ +#define EIO_8PORTRS 0x04 +#define EIO_4PORTRS 0x05 +#define EIO_8PORTDI 0x00 +#define EIO_8PORTM 0x06 +#define EIO_MK3 0x03 +#define EIO_IDBITMASK 0x07 + +#define EIO_BRDMASK 0xf0 +#define ID_BRD4 0x10 +#define ID_BRD8 0x20 +#define ID_BRD16 0x30 + +#define EIO_INTRPEND 0x08 +#define EIO_INTEDGE 0x00 +#define EIO_INTLEVEL 0x08 +#define EIO_0WS 0x10 + +#define ECH_ID 0xa0 +#define ECH_IDBITMASK 0xe0 +#define ECH_BRDENABLE 0x08 +#define ECH_BRDDISABLE 0x00 +#define ECH_INTENABLE 0x01 +#define ECH_INTDISABLE 0x00 +#define ECH_INTLEVEL 0x02 +#define ECH_INTEDGE 0x00 +#define ECH_INTRPEND 0x01 +#define ECH_BRDRESET 0x01 + +#define ECHMC_INTENABLE 0x01 +#define ECHMC_BRDRESET 0x02 + +#define ECH_PNLSTATUS 2 +#define ECH_PNL16PORT 0x20 +#define ECH_PNLIDMASK 0x07 +#define ECH_PNLXPID 0x40 +#define ECH_PNLINTRPEND 0x80 + +#define ECH_ADDR2MASK 0x1e0 + +/* + * Define the vector mapping bits for the programmable interrupt board + * hardware. These bits encode the interrupt for the board to use - it + * is software selectable (except the EIO-8M). + */ +static unsigned char stl_vecmap[] = { + 0xff, 0xff, 0xff, 0x04, 0x06, 0x05, 0xff, 0x07, + 0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03 +}; + +/* + * Set up enable and disable macros for the ECH boards. They require + * the secondary io address space to be activated and deactivated. + * This way all ECH boards can share their secondary io region. + * If this is an ECH-PCI board then also need to set the page pointer + * to point to the correct page. + */ +#define BRDENABLE(brdnr,pagenr) \ + if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ + outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDENABLE), \ + stl_brds[(brdnr)]->ioctrl); \ + else if (stl_brds[(brdnr)]->brdtype == BRD_ECHPCI) \ + outb((pagenr), stl_brds[(brdnr)]->ioctrl); + +#define BRDDISABLE(brdnr) \ + if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ + outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE), \ + stl_brds[(brdnr)]->ioctrl); + +#define STL_CD1400MAXBAUD 230400 +#define STL_SC26198MAXBAUD 460800 + +#define STL_BAUDBASE 115200 +#define STL_CLOSEDELAY (5 * HZ / 10) + +/*****************************************************************************/ + +#ifdef CONFIG_PCI + +/* + * Define the Stallion PCI vendor and device IDs. + */ +#ifndef PCI_VENDOR_ID_STALLION +#define PCI_VENDOR_ID_STALLION 0x124d +#endif +#ifndef PCI_DEVICE_ID_ECHPCI832 +#define PCI_DEVICE_ID_ECHPCI832 0x0000 +#endif +#ifndef PCI_DEVICE_ID_ECHPCI864 +#define PCI_DEVICE_ID_ECHPCI864 0x0002 +#endif +#ifndef PCI_DEVICE_ID_EIOPCI +#define PCI_DEVICE_ID_EIOPCI 0x0003 +#endif + +/* + * Define structure to hold all Stallion PCI boards. + */ +typedef struct stlpcibrd { + unsigned short vendid; + unsigned short devid; + int brdtype; +} stlpcibrd_t; + +static stlpcibrd_t stl_pcibrds[] = { + { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI }, + { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI }, + { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI }, + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI }, +}; + +static int stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t); + +#endif + +/*****************************************************************************/ + +/* + * Define macros to extract a brd/port number from a minor number. + */ +#define MINOR2BRD(min) (((min) & 0xc0) >> 6) +#define MINOR2PORT(min) ((min) & 0x3f) + +/* + * Define a baud rate table that converts termios baud rate selector + * into the actual baud rate value. All baud rate calculations are + * based on the actual baud rate required. + */ +static unsigned int stl_baudrates[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 +}; + +/* + * Define some handy local macros... + */ +#undef MIN +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) + +#undef TOLOWER +#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) + +/*****************************************************************************/ + +/* + * Declare all those functions in this driver! + */ + +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +static void stl_argbrds(void); +static int stl_parsebrd(stlconf_t *confp, char **argp); + +static unsigned long stl_atol(char *str); +#endif + +int stl_init(void); +static int stl_open(struct tty_struct *tty, struct file *filp); +static void stl_close(struct tty_struct *tty, struct file *filp); +static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static void stl_putchar(struct tty_struct *tty, unsigned char ch); +static void stl_flushchars(struct tty_struct *tty); +static int stl_writeroom(struct tty_struct *tty); +static int stl_charsinbuffer(struct tty_struct *tty); +static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +static void stl_settermios(struct tty_struct *tty, struct termios *old); +static void stl_throttle(struct tty_struct *tty); +static void stl_unthrottle(struct tty_struct *tty); +static void stl_stop(struct tty_struct *tty); +static void stl_start(struct tty_struct *tty); +static void stl_flushbuffer(struct tty_struct *tty); +static void stl_breakctl(struct tty_struct *tty, int state); +static void stl_waituntilsent(struct tty_struct *tty, int timeout); +static void stl_sendxchar(struct tty_struct *tty, char ch); +static void stl_hangup(struct tty_struct *tty); +static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); +static int stl_portinfo(stlport_t *portp, int portnr, char *pos); +static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data); + +static int stl_brdinit(stlbrd_t *brdp); +static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); +static int stl_mapirq(int irq, char *name); +static void stl_getserial(stlport_t *portp, struct serial_struct *sp); +static int stl_setserial(stlport_t *portp, struct serial_struct *sp); +static int stl_getbrdstats(combrd_t *bp); +static int stl_getportstats(stlport_t *portp, comstats_t *cp); +static int stl_clrportstats(stlport_t *portp, comstats_t *cp); +static int stl_getportstruct(unsigned long arg); +static int stl_getbrdstruct(unsigned long arg); +static int stl_waitcarrier(stlport_t *portp, struct file *filp); +static void stl_delay(int len); +static void stl_intr(int irq, void *dev_id, struct pt_regs *regs); +static void stl_eiointr(stlbrd_t *brdp); +static void stl_echatintr(stlbrd_t *brdp); +static void stl_echmcaintr(stlbrd_t *brdp); +static void stl_echpciintr(stlbrd_t *brdp); +static void stl_echpci64intr(stlbrd_t *brdp); +static void stl_offintr(void *private); +static void *stl_memalloc(int len); +static stlbrd_t *stl_allocbrd(void); +static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); + +static inline int stl_initbrds(void); +static inline int stl_initeio(stlbrd_t *brdp); +static inline int stl_initech(stlbrd_t *brdp); +static inline int stl_getbrdnr(void); + +#ifdef CONFIG_PCI +static inline int stl_findpcibrds(void); +static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp); +#endif + +/* + * CD1400 uart specific handling functions. + */ +static void stl_cd1400setreg(stlport_t *portp, int regnr, int value); +static int stl_cd1400getreg(stlport_t *portp, int regnr); +static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value); +static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp); +static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); +static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp); +static int stl_cd1400getsignals(stlport_t *portp); +static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts); +static void stl_cd1400ccrwait(stlport_t *portp); +static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx); +static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx); +static void stl_cd1400disableintrs(stlport_t *portp); +static void stl_cd1400sendbreak(stlport_t *portp, int len); +static void stl_cd1400flowctrl(stlport_t *portp, int state); +static void stl_cd1400sendflow(stlport_t *portp, int state); +static void stl_cd1400flush(stlport_t *portp); +static int stl_cd1400datastate(stlport_t *portp); +static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase); +static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase); +static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr); +static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr); +static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr); + +static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr); + +/* + * SC26198 uart specific handling functions. + */ +static void stl_sc26198setreg(stlport_t *portp, int regnr, int value); +static int stl_sc26198getreg(stlport_t *portp, int regnr); +static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value); +static int stl_sc26198getglobreg(stlport_t *portp, int regnr); +static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp); +static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); +static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp); +static int stl_sc26198getsignals(stlport_t *portp); +static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts); +static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx); +static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx); +static void stl_sc26198disableintrs(stlport_t *portp); +static void stl_sc26198sendbreak(stlport_t *portp, int len); +static void stl_sc26198flowctrl(stlport_t *portp, int state); +static void stl_sc26198sendflow(stlport_t *portp, int state); +static void stl_sc26198flush(stlport_t *portp); +static int stl_sc26198datastate(stlport_t *portp); +static void stl_sc26198wait(stlport_t *portp); +static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty); +static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase); +static void stl_sc26198txisr(stlport_t *port); +static void stl_sc26198rxisr(stlport_t *port, unsigned int iack); +static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch); +static void stl_sc26198rxbadchars(stlport_t *portp); +static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); + +/*****************************************************************************/ + +/* + * Generic UART support structure. + */ +typedef struct uart { + int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp); + void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); + void (*setport)(stlport_t *portp, struct termios *tiosp); + int (*getsignals)(stlport_t *portp); + void (*setsignals)(stlport_t *portp, int dtr, int rts); + void (*enablerxtx)(stlport_t *portp, int rx, int tx); + void (*startrxtx)(stlport_t *portp, int rx, int tx); + void (*disableintrs)(stlport_t *portp); + void (*sendbreak)(stlport_t *portp, int len); + void (*flowctrl)(stlport_t *portp, int state); + void (*sendflow)(stlport_t *portp, int state); + void (*flush)(stlport_t *portp); + int (*datastate)(stlport_t *portp); + void (*intr)(stlpanel_t *panelp, unsigned int iobase); +} uart_t; + +/* + * Define some macros to make calling these functions nice and clean. + */ +#define stl_panelinit (* ((uart_t *) panelp->uartp)->panelinit) +#define stl_portinit (* ((uart_t *) portp->uartp)->portinit) +#define stl_setport (* ((uart_t *) portp->uartp)->setport) +#define stl_getsignals (* ((uart_t *) portp->uartp)->getsignals) +#define stl_setsignals (* ((uart_t *) portp->uartp)->setsignals) +#define stl_enablerxtx (* ((uart_t *) portp->uartp)->enablerxtx) +#define stl_startrxtx (* ((uart_t *) portp->uartp)->startrxtx) +#define stl_disableintrs (* ((uart_t *) portp->uartp)->disableintrs) +#define stl_sendbreak (* ((uart_t *) portp->uartp)->sendbreak) +#define stl_flowctrl (* ((uart_t *) portp->uartp)->flowctrl) +#define stl_sendflow (* ((uart_t *) portp->uartp)->sendflow) +#define stl_flush (* ((uart_t *) portp->uartp)->flush) +#define stl_datastate (* ((uart_t *) portp->uartp)->datastate) + +/*****************************************************************************/ + +/* + * CD1400 UART specific data initialization. + */ +static uart_t stl_cd1400uart = { + stl_cd1400panelinit, + stl_cd1400portinit, + stl_cd1400setport, + stl_cd1400getsignals, + stl_cd1400setsignals, + stl_cd1400enablerxtx, + stl_cd1400startrxtx, + stl_cd1400disableintrs, + stl_cd1400sendbreak, + stl_cd1400flowctrl, + stl_cd1400sendflow, + stl_cd1400flush, + stl_cd1400datastate, + stl_cd1400eiointr +}; + +/* + * Define the offsets within the register bank of a cd1400 based panel. + * These io address offsets are common to the EasyIO board as well. + */ +#define EREG_ADDR 0 +#define EREG_DATA 4 +#define EREG_RXACK 5 +#define EREG_TXACK 6 +#define EREG_MDACK 7 + +#define EREG_BANKSIZE 8 + +#define CD1400_CLK 25000000 +#define CD1400_CLK8M 20000000 + +/* + * Define the cd1400 baud rate clocks. These are used when calculating + * what clock and divisor to use for the required baud rate. Also + * define the maximum baud rate allowed, and the default base baud. + */ +static int stl_cd1400clkdivs[] = { + CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4 +}; + +/*****************************************************************************/ + +/* + * SC26198 UART specific data initization. + */ +static uart_t stl_sc26198uart = { + stl_sc26198panelinit, + stl_sc26198portinit, + stl_sc26198setport, + stl_sc26198getsignals, + stl_sc26198setsignals, + stl_sc26198enablerxtx, + stl_sc26198startrxtx, + stl_sc26198disableintrs, + stl_sc26198sendbreak, + stl_sc26198flowctrl, + stl_sc26198sendflow, + stl_sc26198flush, + stl_sc26198datastate, + stl_sc26198intr +}; + +/* + * Define the offsets within the register bank of a sc26198 based panel. + */ +#define XP_DATA 0 +#define XP_ADDR 1 +#define XP_MODID 2 +#define XP_STATUS 2 +#define XP_IACK 3 + +#define XP_BANKSIZE 4 + +/* + * Define the sc26198 baud rate table. Offsets within the table + * represent the actual baud rate selector of sc26198 registers. + */ +static unsigned int sc26198_baudtable[] = { + 50, 75, 150, 200, 300, 450, 600, 900, 1200, 1800, 2400, 3600, + 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, + 230400, 460800, 921600 +}; + +#define SC26198_NRBAUDS (sizeof(sc26198_baudtable) / sizeof(unsigned int)) + +/*****************************************************************************/ + +/* + * Define the driver info for a user level control device. Used mainly + * to get at port stats - only not using the port device itself. + */ +static struct file_operations stl_fsiomem = { + owner: THIS_MODULE, + ioctl: stl_memioctl, +}; + +/*****************************************************************************/ + +static devfs_handle_t devfs_handle = NULL; + +#ifdef MODULE + +/* + * Loadable module initialization stuff. + */ + +int init_module() +{ + unsigned long flags; + +#if DEBUG + printk("init_module()\n"); +#endif + + save_flags(flags); + cli(); + stl_init(); + restore_flags(flags); + + return(0); +} + +/*****************************************************************************/ + +void cleanup_module() +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + stlport_t *portp; + unsigned long flags; + int i, j, k; + +#if DEBUG + printk("cleanup_module()\n"); +#endif + + printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, + stl_drvversion); + + save_flags(flags); + cli(); + +/* + * Free up all allocated resources used by the ports. This includes + * memory and interrupts. As part of this process we will also do + * a hangup on every open port - to try to flush out any processes + * hanging onto ports. + */ + i = tty_unregister_driver(&stl_serial); + j = tty_unregister_driver(&stl_callout); + if (i || j) { + printk("STALLION: failed to un-register tty driver, " + "errno=%d,%d\n", -i, -j); + restore_flags(flags); + return; + } + devfs_unregister (devfs_handle); + if ((i = devfs_unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) + printk("STALLION: failed to un-register serial memory device, " + "errno=%d\n", -i); + + if (stl_tmpwritebuf != (char *) NULL) + kfree(stl_tmpwritebuf); + + for (i = 0; (i < stl_nrbrds); i++) { + if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) + continue; + for (j = 0; (j < STL_MAXPANELS); j++) { + panelp = brdp->panels[j]; + if (panelp == (stlpanel_t *) NULL) + continue; + for (k = 0; (k < STL_PORTSPERPANEL); k++) { + portp = panelp->ports[k]; + if (portp == (stlport_t *) NULL) + continue; + if (portp->tty != (struct tty_struct *) NULL) + stl_hangup(portp->tty); + if (portp->tx.buf != (char *) NULL) + kfree(portp->tx.buf); + kfree(portp); + } + kfree(panelp); + } + + release_region(brdp->ioaddr1, brdp->iosize1); + if (brdp->iosize2 > 0) + release_region(brdp->ioaddr2, brdp->iosize2); + + kfree(brdp); + stl_brds[i] = (stlbrd_t *) NULL; + } + + for (i = 0; (i < stl_numintrs); i++) + free_irq(stl_gotintrs[i], NULL); + + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Check for any arguments passed in on the module load command line. + */ + +static void stl_argbrds() +{ + stlconf_t conf; + stlbrd_t *brdp; + int nrargs, i; + +#if DEBUG + printk("stl_argbrds()\n"); +#endif + + nrargs = sizeof(stl_brdsp) / sizeof(char **); + + for (i = stl_nrbrds; (i < nrargs); i++) { + memset(&conf, 0, sizeof(conf)); + if (stl_parsebrd(&conf, stl_brdsp[i]) == 0) + continue; + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) + continue; + stl_nrbrds = i + 1; + brdp->brdnr = i; + brdp->brdtype = conf.brdtype; + brdp->ioaddr1 = conf.ioaddr1; + brdp->ioaddr2 = conf.ioaddr2; + brdp->irq = conf.irq; + brdp->irqtype = conf.irqtype; + stl_brdinit(brdp); + } +} + +/*****************************************************************************/ + +/* + * Convert an ascii string number into an unsigned long. + */ + +static unsigned long stl_atol(char *str) +{ + unsigned long val; + int base, c; + char *sp; + + val = 0; + sp = str; + if ((*sp == '0') && (*(sp+1) == 'x')) { + base = 16; + sp += 2; + } else if (*sp == '0') { + base = 8; + sp++; + } else { + base = 10; + } + + for (; (*sp != 0); sp++) { + c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); + if ((c < 0) || (c >= base)) { + printk("STALLION: invalid argument %s\n", str); + val = 0; + break; + } + val = (val * base) + c; + } + return(val); +} + +/*****************************************************************************/ + +/* + * Parse the supplied argument string, into the board conf struct. + */ + +static int stl_parsebrd(stlconf_t *confp, char **argp) +{ + char *sp; + int nrbrdnames, i; + +#if DEBUG + printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp); +#endif + + if ((argp[0] == (char *) NULL) || (*argp[0] == 0)) + return(0); + + for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) + *sp = TOLOWER(*sp); + + nrbrdnames = sizeof(stl_brdstr) / sizeof(stlbrdtype_t); + for (i = 0; (i < nrbrdnames); i++) { + if (strcmp(stl_brdstr[i].name, argp[0]) == 0) + break; + } + if (i >= nrbrdnames) { + printk("STALLION: unknown board name, %s?\n", argp[0]); + return(0); + } + + confp->brdtype = stl_brdstr[i].type; + + i = 1; + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->ioaddr1 = stl_atol(argp[i]); + i++; + if (confp->brdtype == BRD_ECH) { + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->ioaddr2 = stl_atol(argp[i]); + i++; + } + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->irq = stl_atol(argp[i]); + return(1); +} + +#endif + +/*****************************************************************************/ + +/* + * Local driver kernel memory allocation routine. + */ + +static void *stl_memalloc(int len) +{ + return((void *) kmalloc(len, GFP_KERNEL)); +} + +/*****************************************************************************/ + +/* + * Allocate a new board structure. Fill out the basic info in it. + */ + +static stlbrd_t *stl_allocbrd() +{ + stlbrd_t *brdp; + + brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); + if (brdp == (stlbrd_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", + sizeof(stlbrd_t)); + return((stlbrd_t *) NULL); + } + + memset(brdp, 0, sizeof(stlbrd_t)); + brdp->magic = STL_BOARDMAGIC; + return(brdp); +} + +/*****************************************************************************/ + +static int stl_open(struct tty_struct *tty, struct file *filp) +{ + stlport_t *portp; + stlbrd_t *brdp; + unsigned int minordev; + int brdnr, panelnr, portnr, rc; + +#if DEBUG + printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty, + (int) filp, tty->device); +#endif + + minordev = MINOR(tty->device); + brdnr = MINOR2BRD(minordev); + if (brdnr >= stl_nrbrds) + return(-ENODEV); + brdp = stl_brds[brdnr]; + if (brdp == (stlbrd_t *) NULL) + return(-ENODEV); + minordev = MINOR2PORT(minordev); + for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) { + if (brdp->panels[panelnr] == (stlpanel_t *) NULL) + break; + if (minordev < brdp->panels[panelnr]->nrports) { + portnr = minordev; + break; + } + minordev -= brdp->panels[panelnr]->nrports; + } + if (portnr < 0) + return(-ENODEV); + + portp = brdp->panels[panelnr]->ports[portnr]; + if (portp == (stlport_t *) NULL) + return(-ENODEV); + + MOD_INC_USE_COUNT; + +/* + * On the first open of the device setup the port hardware, and + * initialize the per port data structure. + */ + portp->tty = tty; + tty->driver_data = portp; + portp->refcount++; + + if ((portp->flags & ASYNC_INITIALIZED) == 0) { + if (portp->tx.buf == (char *) NULL) { + portp->tx.buf = (char *) stl_memalloc(STL_TXBUFSIZE); + if (portp->tx.buf == (char *) NULL) + return(-ENOMEM); + portp->tx.head = portp->tx.buf; + portp->tx.tail = portp->tx.buf; + } + stl_setport(portp, tty->termios); + portp->sigs = stl_getsignals(portp); + stl_setsignals(portp, 1, 1); + stl_enablerxtx(portp, 1, 1); + stl_startrxtx(portp, 1, 0); + clear_bit(TTY_IO_ERROR, &tty->flags); + portp->flags |= ASYNC_INITIALIZED; + } + +/* + * Check if this port is in the middle of closing. If so then wait + * until it is closed then return error status, based on flag settings. + * The sleep here does not need interrupt protection since the wakeup + * for it is done with the same context. + */ + if (portp->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&portp->close_wait); + if (portp->flags & ASYNC_HUP_NOTIFY) + return(-EAGAIN); + return(-ERESTARTSYS); + } + +/* + * Based on type of open being done check if it can overlap with any + * previous opens still in effect. If we are a normal serial device + * then also we might have to wait for carrier. + */ + if (tty->driver.subtype == STL_DRVTYPCALLOUT) { + if (portp->flags & ASYNC_NORMAL_ACTIVE) + return(-EBUSY); + if (portp->flags & ASYNC_CALLOUT_ACTIVE) { + if ((portp->flags & ASYNC_SESSION_LOCKOUT) && + (portp->session != current->session)) + return(-EBUSY); + if ((portp->flags & ASYNC_PGRP_LOCKOUT) && + (portp->pgrp != current->pgrp)) + return(-EBUSY); + } + portp->flags |= ASYNC_CALLOUT_ACTIVE; + } else { + if (filp->f_flags & O_NONBLOCK) { + if (portp->flags & ASYNC_CALLOUT_ACTIVE) + return(-EBUSY); + } else { + if ((rc = stl_waitcarrier(portp, filp)) != 0) + return(rc); + } + portp->flags |= ASYNC_NORMAL_ACTIVE; + } + + if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == STL_DRVTYPSERIAL) + *tty->termios = portp->normaltermios; + else + *tty->termios = portp->callouttermios; + stl_setport(portp, tty->termios); + } + + portp->session = current->session; + portp->pgrp = current->pgrp; + return(0); +} + +/*****************************************************************************/ + +/* + * Possibly need to wait for carrier (DCD signal) to come high. Say + * maybe because if we are clocal then we don't need to wait... + */ + +static int stl_waitcarrier(stlport_t *portp, struct file *filp) +{ + unsigned long flags; + int rc, doclocal; + +#if DEBUG + printk("stl_waitcarrier(portp=%x,filp=%x)\n", (int) portp, (int) filp); +#endif + + rc = 0; + doclocal = 0; + + if (portp->flags & ASYNC_CALLOUT_ACTIVE) { + if (portp->normaltermios.c_cflag & CLOCAL) + doclocal++; + } else { + if (portp->tty->termios->c_cflag & CLOCAL) + doclocal++; + } + + save_flags(flags); + cli(); + portp->openwaitcnt++; + if (! tty_hung_up_p(filp)) + portp->refcount--; + + for (;;) { + if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) + stl_setsignals(portp, 1, 1); + if (tty_hung_up_p(filp) || + ((portp->flags & ASYNC_INITIALIZED) == 0)) { + if (portp->flags & ASYNC_HUP_NOTIFY) + rc = -EBUSY; + else + rc = -ERESTARTSYS; + break; + } + if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) && + ((portp->flags & ASYNC_CLOSING) == 0) && + (doclocal || (portp->sigs & TIOCM_CD))) { + break; + } + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + interruptible_sleep_on(&portp->open_wait); + } + + if (! tty_hung_up_p(filp)) + portp->refcount++; + portp->openwaitcnt--; + restore_flags(flags); + + return(rc); +} + +/*****************************************************************************/ + +static void stl_close(struct tty_struct *tty, struct file *filp) +{ + stlport_t *portp; + unsigned long flags; + +#if DEBUG + printk("stl_close(tty=%x,filp=%x)\n", (int) tty, (int) filp); +#endif + + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + save_flags(flags); + cli(); + if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + if ((tty->count == 1) && (portp->refcount != 1)) + portp->refcount = 1; + if (portp->refcount-- > 1) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + + portp->refcount = 0; + portp->flags |= ASYNC_CLOSING; + + if (portp->flags & ASYNC_NORMAL_ACTIVE) + portp->normaltermios = *tty->termios; + if (portp->flags & ASYNC_CALLOUT_ACTIVE) + portp->callouttermios = *tty->termios; + +/* + * May want to wait for any data to drain before closing. The BUSY + * flag keeps track of whether we are still sending or not - it is + * very accurate for the cd1400, not quite so for the sc26198. + * (The sc26198 has no "end-of-data" interrupt only empty FIFO) + */ + tty->closing = 1; + if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, portp->closing_wait); + stl_waituntilsent(tty, (HZ / 2)); + + portp->flags &= ~ASYNC_INITIALIZED; + stl_disableintrs(portp); + if (tty->termios->c_cflag & HUPCL) + stl_setsignals(portp, 0, 0); + stl_enablerxtx(portp, 0, 0); + stl_flushbuffer(tty); + portp->istate = 0; + if (portp->tx.buf != (char *) NULL) { + kfree(portp->tx.buf); + portp->tx.buf = (char *) NULL; + portp->tx.head = (char *) NULL; + portp->tx.tail = (char *) NULL; + } + set_bit(TTY_IO_ERROR, &tty->flags); + if (tty->ldisc.flush_buffer) + (tty->ldisc.flush_buffer)(tty); + + tty->closing = 0; + portp->tty = (struct tty_struct *) NULL; + + if (portp->openwaitcnt) { + if (portp->close_delay) + stl_delay(portp->close_delay); + wake_up_interruptible(&portp->open_wait); + } + + portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | + ASYNC_CLOSING); + wake_up_interruptible(&portp->close_wait); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Wait for a specified delay period, this is not a busy-loop. It will + * give up the processor while waiting. Unfortunately this has some + * rather intimate knowledge of the process management stuff. + */ + +static void stl_delay(int len) +{ +#if DEBUG + printk("stl_delay(len=%d)\n", len); +#endif + if (len > 0) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(len); + current->state = TASK_RUNNING; + } +} + +/*****************************************************************************/ + +/* + * Write routine. Take data and stuff it in to the TX ring queue. + * If transmit interrupts are not running then start them. + */ + +static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) +{ + stlport_t *portp; + unsigned int len, stlen; + unsigned char *chbuf; + char *head, *tail; + +#if DEBUG + printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", + (int) tty, from_user, (int) buf, count); +#endif + + if ((tty == (struct tty_struct *) NULL) || + (stl_tmpwritebuf == (char *) NULL)) + return(0); + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return(0); + if (portp->tx.buf == (char *) NULL) + return(0); + +/* + * If copying direct from user space we must cater for page faults, + * causing us to "sleep" here for a while. To handle this copy in all + * the data we need now, into a local buffer. Then when we got it all + * copy it into the TX buffer. + */ + chbuf = (unsigned char *) buf; + if (from_user) { + head = portp->tx.head; + tail = portp->tx.tail; + len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : + (tail - head - 1); + count = MIN(len, count); + + down(&stl_tmpwritesem); + copy_from_user(stl_tmpwritebuf, chbuf, count); + chbuf = &stl_tmpwritebuf[0]; + } + + head = portp->tx.head; + tail = portp->tx.tail; + if (head >= tail) { + len = STL_TXBUFSIZE - (head - tail) - 1; + stlen = STL_TXBUFSIZE - (head - portp->tx.buf); + } else { + len = tail - head - 1; + stlen = len; + } + + len = MIN(len, count); + count = 0; + while (len > 0) { + stlen = MIN(len, stlen); + memcpy(head, chbuf, stlen); + len -= stlen; + chbuf += stlen; + count += stlen; + head += stlen; + if (head >= (portp->tx.buf + STL_TXBUFSIZE)) { + head = portp->tx.buf; + stlen = tail - head; + } + } + portp->tx.head = head; + + clear_bit(ASYI_TXLOW, &portp->istate); + stl_startrxtx(portp, -1, 1); + + if (from_user) + up(&stl_tmpwritesem); + + return(count); +} + +/*****************************************************************************/ + +static void stl_putchar(struct tty_struct *tty, unsigned char ch) +{ + stlport_t *portp; + unsigned int len; + char *head, *tail; + +#if DEBUG + printk("stl_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + if (portp->tx.buf == (char *) NULL) + return; + + head = portp->tx.head; + tail = portp->tx.tail; + + len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail)) : (tail - head); + len--; + + if (len > 0) { + *head++ = ch; + if (head >= (portp->tx.buf + STL_TXBUFSIZE)) + head = portp->tx.buf; + } + portp->tx.head = head; +} + +/*****************************************************************************/ + +/* + * If there are any characters in the buffer then make sure that TX + * interrupts are on and get'em out. Normally used after the putchar + * routine has been called. + */ + +static void stl_flushchars(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_flushchars(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + if (portp->tx.buf == (char *) NULL) + return; + +#if 0 + if (tty->stopped || tty->hw_stopped || + (portp->tx.head == portp->tx.tail)) + return; +#endif + stl_startrxtx(portp, -1, 1); +} + +/*****************************************************************************/ + +static int stl_writeroom(struct tty_struct *tty) +{ + stlport_t *portp; + char *head, *tail; + +#if DEBUG + printk("stl_writeroom(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return(0); + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return(0); + if (portp->tx.buf == (char *) NULL) + return(0); + + head = portp->tx.head; + tail = portp->tx.tail; + return((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1)); +} + +/*****************************************************************************/ + +/* + * Return number of chars in the TX buffer. Normally we would just + * calculate the number of chars in the buffer and return that, but if + * the buffer is empty and TX interrupts are still on then we return + * that the buffer still has 1 char in it. This way whoever called us + * will not think that ALL chars have drained - since the UART still + * must have some chars in it (we are busy after all). + */ + +static int stl_charsinbuffer(struct tty_struct *tty) +{ + stlport_t *portp; + unsigned int size; + char *head, *tail; + +#if DEBUG + printk("stl_charsinbuffer(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return(0); + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return(0); + if (portp->tx.buf == (char *) NULL) + return(0); + + head = portp->tx.head; + tail = portp->tx.tail; + size = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); + if ((size == 0) && test_bit(ASYI_TXBUSY, &portp->istate)) + size = 1; + return(size); +} + +/*****************************************************************************/ + +/* + * Generate the serial struct info. + */ + +static void stl_getserial(stlport_t *portp, struct serial_struct *sp) +{ + struct serial_struct sio; + stlbrd_t *brdp; + +#if DEBUG + printk("stl_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); +#endif + + memset(&sio, 0, sizeof(struct serial_struct)); + sio.line = portp->portnr; + sio.port = portp->ioaddr; + sio.flags = portp->flags; + sio.baud_base = portp->baud_base; + sio.close_delay = portp->close_delay; + sio.closing_wait = portp->closing_wait; + sio.custom_divisor = portp->custom_divisor; + sio.hub6 = 0; + if (portp->uartp == &stl_cd1400uart) { + sio.type = PORT_CIRRUS; + sio.xmit_fifo_size = CD1400_TXFIFOSIZE; + } else { + sio.type = PORT_UNKNOWN; + sio.xmit_fifo_size = SC26198_TXFIFOSIZE; + } + + brdp = stl_brds[portp->brdnr]; + if (brdp != (stlbrd_t *) NULL) + sio.irq = brdp->irq; + + copy_to_user(sp, &sio, sizeof(struct serial_struct)); +} + +/*****************************************************************************/ + +/* + * Set port according to the serial struct info. + * At this point we do not do any auto-configure stuff, so we will + * just quietly ignore any requests to change irq, etc. + */ + +static int stl_setserial(stlport_t *portp, struct serial_struct *sp) +{ + struct serial_struct sio; + +#if DEBUG + printk("stl_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); +#endif + + copy_from_user(&sio, sp, sizeof(struct serial_struct)); + if (!capable(CAP_SYS_ADMIN)) { + if ((sio.baud_base != portp->baud_base) || + (sio.close_delay != portp->close_delay) || + ((sio.flags & ~ASYNC_USR_MASK) != + (portp->flags & ~ASYNC_USR_MASK))) + return(-EPERM); + } + + portp->flags = (portp->flags & ~ASYNC_USR_MASK) | + (sio.flags & ASYNC_USR_MASK); + portp->baud_base = sio.baud_base; + portp->close_delay = sio.close_delay; + portp->closing_wait = sio.closing_wait; + portp->custom_divisor = sio.custom_divisor; + stl_setport(portp, portp->tty->termios); + return(0); +} + +/*****************************************************************************/ + +static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) +{ + stlport_t *portp; + unsigned int ival; + int rc; + +#if DEBUG + printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", + (int) tty, (int) file, cmd, (int) arg); +#endif + + if (tty == (struct tty_struct *) NULL) + return(-ENODEV); + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return(-ENODEV); + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return(-EIO); + } + + rc = 0; + + switch (cmd) { + case TIOCGSOFTCAR: + rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + (unsigned int *) arg); + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCMGET: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) == 0) { + ival = stl_getsignals(portp); + put_user(ival, (unsigned int *) arg); + } + break; + case TIOCMBIS: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : -1), + ((ival & TIOCM_RTS) ? 1 : -1)); + } + break; + case TIOCMBIC: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 0 : -1), + ((ival & TIOCM_RTS) ? 0 : -1)); + } + break; + case TIOCMSET: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : 0), + ((ival & TIOCM_RTS) ? 1 : 0)); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + stl_getserial(portp, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = stl_setserial(portp, (struct serial_struct *) arg); + break; + case COM_GETPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(comstats_t))) == 0) + rc = stl_getportstats(portp, (comstats_t *) arg); + break; + case COM_CLRPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(comstats_t))) == 0) + rc = stl_clrportstats(portp, (comstats_t *) arg); + break; + case TIOCSERCONFIG: + case TIOCSERGWILD: + case TIOCSERSWILD: + case TIOCSERGETLSR: + case TIOCSERGSTRUCT: + case TIOCSERGETMULTI: + case TIOCSERSETMULTI: + default: + rc = -ENOIOCTLCMD; + break; + } + + return(rc); +} + +/*****************************************************************************/ + +static void stl_settermios(struct tty_struct *tty, struct termios *old) +{ + stlport_t *portp; + struct termios *tiosp; + +#if DEBUG + printk("stl_settermios(tty=%x,old=%x)\n", (int) tty, (int) old); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + tiosp = tty->termios; + if ((tiosp->c_cflag == old->c_cflag) && + (tiosp->c_iflag == old->c_iflag)) + return; + + stl_setport(portp, tiosp); + stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0), + -1); + if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) { + tty->hw_stopped = 0; + stl_start(tty); + } + if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL)) + wake_up_interruptible(&portp->open_wait); +} + +/*****************************************************************************/ + +/* + * Attempt to flow control who ever is sending us data. Based on termios + * settings use software or/and hardware flow control. + */ + +static void stl_throttle(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_throttle(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + stl_flowctrl(portp, 0); +} + +/*****************************************************************************/ + +/* + * Unflow control the device sending us data... + */ + +static void stl_unthrottle(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_unthrottle(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + stl_flowctrl(portp, 1); +} + +/*****************************************************************************/ + +/* + * Stop the transmitter. Basically to do this we will just turn TX + * interrupts off. + */ + +static void stl_stop(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_stop(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + stl_startrxtx(portp, -1, 0); +} + +/*****************************************************************************/ + +/* + * Start the transmitter again. Just turn TX interrupts back on. + */ + +static void stl_start(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_start(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + stl_startrxtx(portp, -1, 1); +} + +/*****************************************************************************/ + +/* + * Hangup this port. This is pretty much like closing the port, only + * a little more brutal. No waiting for data to drain. Shutdown the + * port and maybe drop signals. + */ + +static void stl_hangup(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_hangup(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + portp->flags &= ~ASYNC_INITIALIZED; + stl_disableintrs(portp); + if (tty->termios->c_cflag & HUPCL) + stl_setsignals(portp, 0, 0); + stl_enablerxtx(portp, 0, 0); + stl_flushbuffer(tty); + portp->istate = 0; + set_bit(TTY_IO_ERROR, &tty->flags); + if (portp->tx.buf != (char *) NULL) { + kfree(portp->tx.buf); + portp->tx.buf = (char *) NULL; + portp->tx.head = (char *) NULL; + portp->tx.tail = (char *) NULL; + } + portp->tty = (struct tty_struct *) NULL; + portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + portp->refcount = 0; + wake_up_interruptible(&portp->open_wait); +} + +/*****************************************************************************/ + +static void stl_flushbuffer(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_flushbuffer(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + stl_flush(portp); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/*****************************************************************************/ + +static void stl_breakctl(struct tty_struct *tty, int state) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_breakctl(tty=%x,state=%d)\n", (int) tty, state); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + stl_sendbreak(portp, ((state == -1) ? 1 : 2)); +} + +/*****************************************************************************/ + +static void stl_waituntilsent(struct tty_struct *tty, int timeout) +{ + stlport_t *portp; + unsigned long tend; + +#if DEBUG + printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + if (timeout == 0) + timeout = HZ; + tend = jiffies + timeout; + + while (stl_datastate(portp)) { + if (signal_pending(current)) + break; + stl_delay(2); + if (time_after_eq(jiffies, tend)) + break; + } +} + +/*****************************************************************************/ + +static void stl_sendxchar(struct tty_struct *tty, char ch) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + if (ch == STOP_CHAR(tty)) + stl_sendflow(portp, 0); + else if (ch == START_CHAR(tty)) + stl_sendflow(portp, 1); + else + stl_putchar(tty, ch); +} + +/*****************************************************************************/ + +#define MAXLINE 80 + +/* + * Format info for a specified port. The line is deliberately limited + * to 80 characters. (If it is too long it will be truncated, if too + * short then padded with spaces). + */ + +static int stl_portinfo(stlport_t *portp, int portnr, char *pos) +{ + char *sp; + int sigs, cnt; + + sp = pos; + sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d", + portnr, (portp->hwid == 1) ? "SC26198" : "CD1400", + (int) portp->stats.txtotal, (int) portp->stats.rxtotal); + + if (portp->stats.rxframing) + sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing); + if (portp->stats.rxparity) + sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity); + if (portp->stats.rxbreaks) + sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks); + if (portp->stats.rxoverrun) + sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun); + + sigs = stl_getsignals(portp); + cnt = sprintf(sp, "%s%s%s%s%s ", + (sigs & TIOCM_RTS) ? "|RTS" : "", + (sigs & TIOCM_CTS) ? "|CTS" : "", + (sigs & TIOCM_DTR) ? "|DTR" : "", + (sigs & TIOCM_CD) ? "|DCD" : "", + (sigs & TIOCM_DSR) ? "|DSR" : ""); + *sp = ' '; + sp += cnt; + + for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++) + *sp++ = ' '; + if (cnt >= MAXLINE) + pos[(MAXLINE - 2)] = '+'; + pos[(MAXLINE - 1)] = '\n'; + + return(MAXLINE); +} + +/*****************************************************************************/ + +/* + * Port info, read from the /proc file system. + */ + +static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + stlport_t *portp; + int brdnr, panelnr, portnr, totalport; + int curoff, maxoff; + char *pos; + +#if DEBUG + printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x," + "data=%x\n", (int) page, (int) start, (int) off, count, + (int) eof, (int) data); +#endif + + pos = page; + totalport = 0; + curoff = 0; + + if (off == 0) { + pos += sprintf(pos, "%s: version %s", stl_drvtitle, + stl_drvversion); + while (pos < (page + MAXLINE - 1)) + *pos++ = ' '; + *pos++ = '\n'; + } + curoff = MAXLINE; + +/* + * We scan through for each board, panel and port. The offset is + * calculated on the fly, and irrelevant ports are skipped. + */ + for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) { + brdp = stl_brds[brdnr]; + if (brdp == (stlbrd_t *) NULL) + continue; + if (brdp->state == 0) + continue; + + maxoff = curoff + (brdp->nrports * MAXLINE); + if (off >= maxoff) { + curoff = maxoff; + continue; + } + + totalport = brdnr * STL_MAXPORTS; + for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { + panelp = brdp->panels[panelnr]; + if (panelp == (stlpanel_t *) NULL) + continue; + + maxoff = curoff + (panelp->nrports * MAXLINE); + if (off >= maxoff) { + curoff = maxoff; + totalport += panelp->nrports; + continue; + } + + for (portnr = 0; (portnr < panelp->nrports); portnr++, + totalport++) { + portp = panelp->ports[portnr]; + if (portp == (stlport_t *) NULL) + continue; + if (off >= (curoff += MAXLINE)) + continue; + if ((pos - page + MAXLINE) > count) + goto stl_readdone; + pos += stl_portinfo(portp, totalport, pos); + } + } + } + + *eof = 1; + +stl_readdone: + *start = page; + return(pos - page); +} + +/*****************************************************************************/ + +/* + * All board interrupts are vectored through here first. This code then + * calls off to the approrpriate board interrupt handlers. + */ + +static void stl_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + stlbrd_t *brdp; + int i; + +#if DEBUG + printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); +#endif + + for (i = 0; (i < stl_nrbrds); i++) { + if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) + continue; + if (brdp->state == 0) + continue; + (* brdp->isr)(brdp); + } +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for EasyIO board types. + */ + +static void stl_eiointr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int iobase; + + panelp = brdp->panels[0]; + iobase = panelp->iobase; + while (inb(brdp->iostatus) & EIO_INTRPEND) + (* panelp->isr)(panelp, iobase); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for ECH-AT board types. + */ + +static void stl_echatintr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr; + + outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); + + while (inb(brdp->iostatus) & ECH_INTRPEND) { + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + } + } + } + + outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for ECH-MCA board types. + */ + +static void stl_echmcaintr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr; + + while (inb(brdp->iostatus) & ECH_INTRPEND) { + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + } + } + } +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for ECH-PCI board types. + */ + +static void stl_echpciintr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr, recheck; + + while (1) { + recheck = 0; + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl); + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + recheck++; + } + } + if (! recheck) + break; + } +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for ECH-8/64-PCI board types. + */ + +static void stl_echpci64intr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr; + + while (inb(brdp->ioctrl) & 0x1) { + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + } + } + } +} + +/*****************************************************************************/ + +/* + * Service an off-level request for some channel. + */ +static void stl_offintr(void *private) +{ + stlport_t *portp; + struct tty_struct *tty; + unsigned int oldsigs; + + portp = private; + +#if DEBUG + printk("stl_offintr(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return; + + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + lock_kernel(); + if (test_bit(ASYI_TXLOW, &portp->istate)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { + clear_bit(ASYI_DCDCHANGE, &portp->istate); + oldsigs = portp->sigs; + portp->sigs = stl_getsignals(portp); + if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) + wake_up_interruptible(&portp->open_wait); + if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { + if (portp->flags & ASYNC_CHECK_CD) { + if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && + (portp->flags & ASYNC_CALLOUT_NOHUP))) { + tty_hangup(tty); + } + } + } + } + unlock_kernel(); +} + +/*****************************************************************************/ + +/* + * Map in interrupt vector to this driver. Check that we don't + * already have this vector mapped, we might be sharing this + * interrupt across multiple boards. + */ + +static int __init stl_mapirq(int irq, char *name) +{ + int rc, i; + +#if DEBUG + printk("stl_mapirq(irq=%d,name=%s)\n", irq, name); +#endif + + rc = 0; + for (i = 0; (i < stl_numintrs); i++) { + if (stl_gotintrs[i] == irq) + break; + } + if (i >= stl_numintrs) { + if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) { + printk("STALLION: failed to register interrupt " + "routine for %s irq=%d\n", name, irq); + rc = -ENODEV; + } else { + stl_gotintrs[stl_numintrs++] = irq; + } + } + return(rc); +} + +/*****************************************************************************/ + +/* + * Initialize all the ports on a panel. + */ + +static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) +{ + stlport_t *portp; + int chipmask, i; + +#if DEBUG + printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); +#endif + + chipmask = stl_panelinit(brdp, panelp); + +/* + * All UART's are initialized (if found!). Now go through and setup + * each ports data structures. + */ + for (i = 0; (i < panelp->nrports); i++) { + portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); + if (portp == (stlport_t *) NULL) { + printk("STALLION: failed to allocate memory " + "(size=%d)\n", sizeof(stlport_t)); + break; + } + memset(portp, 0, sizeof(stlport_t)); + + portp->magic = STL_PORTMAGIC; + portp->portnr = i; + portp->brdnr = panelp->brdnr; + portp->panelnr = panelp->panelnr; + portp->uartp = panelp->uartp; + portp->clk = brdp->clk; + portp->baud_base = STL_BAUDBASE; + portp->close_delay = STL_CLOSEDELAY; + portp->closing_wait = 30 * HZ; + portp->normaltermios = stl_deftermios; + portp->callouttermios = stl_deftermios; + portp->tqueue.routine = stl_offintr; + portp->tqueue.data = portp; + init_waitqueue_head(&portp->open_wait); + init_waitqueue_head(&portp->close_wait); + portp->stats.brd = portp->brdnr; + portp->stats.panel = portp->panelnr; + portp->stats.port = portp->portnr; + panelp->ports[i] = portp; + stl_portinit(brdp, panelp, portp); + } + + return(0); +} + +/*****************************************************************************/ + +/* + * Try to find and initialize an EasyIO board. + */ + +static inline int stl_initeio(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int status; + char *name; + int rc; + +#if DEBUG + printk("stl_initeio(brdp=%x)\n", (int) brdp); +#endif + + brdp->ioctrl = brdp->ioaddr1 + 1; + brdp->iostatus = brdp->ioaddr1 + 2; + + status = inb(brdp->iostatus); + if ((status & EIO_IDBITMASK) == EIO_MK3) + brdp->ioctrl++; + +/* + * Handle board specific stuff now. The real difference is PCI + * or not PCI. + */ + if (brdp->brdtype == BRD_EASYIOPCI) { + brdp->iosize1 = 0x80; + brdp->iosize2 = 0x80; + name = "serial(EIO-PCI)"; + outb(0x41, (brdp->ioaddr2 + 0x4c)); + } else { + brdp->iosize1 = 8; + name = "serial(EIO)"; + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", + brdp->irq, brdp->brdnr); + return(-EINVAL); + } + outb((stl_vecmap[brdp->irq] | EIO_0WS | + ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), + brdp->ioctrl); + } + + if (check_region(brdp->ioaddr1, brdp->iosize1)) { + printk("STALLION: Warning, board %d I/O address %x conflicts " + "with another device\n", brdp->brdnr, brdp->ioaddr1); + } + if (brdp->iosize2 > 0) { + if (check_region(brdp->ioaddr2, brdp->iosize2)) { + printk("STALLION: Warning, board %d I/O address %x " + "conflicts with another device\n", + brdp->brdnr, brdp->ioaddr2); + } + } + +/* + * Everything looks OK, so let's go ahead and probe for the hardware. + */ + brdp->clk = CD1400_CLK; + brdp->isr = stl_eiointr; + + switch (status & EIO_IDBITMASK) { + case EIO_8PORTM: + brdp->clk = CD1400_CLK8M; + /* fall thru */ + case EIO_8PORTRS: + case EIO_8PORTDI: + brdp->nrports = 8; + break; + case EIO_4PORTRS: + brdp->nrports = 4; + break; + case EIO_MK3: + switch (status & EIO_BRDMASK) { + case ID_BRD4: + brdp->nrports = 4; + break; + case ID_BRD8: + brdp->nrports = 8; + break; + case ID_BRD16: + brdp->nrports = 16; + break; + default: + return(-ENODEV); + } + break; + default: + return(-ENODEV); + } + +/* + * We have verfied that the board is actually present, so now we + * can complete the setup. + */ + request_region(brdp->ioaddr1, brdp->iosize1, name); + if (brdp->iosize2 > 0) + request_region(brdp->ioaddr2, brdp->iosize2, name); + + panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); + if (panelp == (stlpanel_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", + sizeof(stlpanel_t)); + return(-ENOMEM); + } + memset(panelp, 0, sizeof(stlpanel_t)); + + panelp->magic = STL_PANELMAGIC; + panelp->brdnr = brdp->brdnr; + panelp->panelnr = 0; + panelp->nrports = brdp->nrports; + panelp->iobase = brdp->ioaddr1; + panelp->hwid = status; + if ((status & EIO_IDBITMASK) == EIO_MK3) { + panelp->uartp = (void *) &stl_sc26198uart; + panelp->isr = stl_sc26198intr; + } else { + panelp->uartp = (void *) &stl_cd1400uart; + panelp->isr = stl_cd1400eiointr; + } + + brdp->panels[0] = panelp; + brdp->nrpanels = 1; + brdp->state |= BRD_FOUND; + brdp->hwid = status; + rc = stl_mapirq(brdp->irq, name); + return(rc); +} + +/*****************************************************************************/ + +/* + * Try to find an ECH board and initialize it. This code is capable of + * dealing with all types of ECH board. + */ + +static int inline stl_initech(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int status, nxtid, ioaddr, conflict; + int panelnr, banknr, i; + char *name; + +#if DEBUG + printk("stl_initech(brdp=%x)\n", (int) brdp); +#endif + + status = 0; + conflict = 0; + +/* + * Set up the initial board register contents for boards. This varies a + * bit between the different board types. So we need to handle each + * separately. Also do a check that the supplied IRQ is good. + */ + switch (brdp->brdtype) { + + case BRD_ECH: + brdp->isr = stl_echatintr; + brdp->ioctrl = brdp->ioaddr1 + 1; + brdp->iostatus = brdp->ioaddr1 + 1; + status = inb(brdp->iostatus); + if ((status & ECH_IDBITMASK) != ECH_ID) + return(-ENODEV); + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", + brdp->irq, brdp->brdnr); + return(-EINVAL); + } + status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); + status |= (stl_vecmap[brdp->irq] << 1); + outb((status | ECH_BRDRESET), brdp->ioaddr1); + brdp->ioctrlval = ECH_INTENABLE | + ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); + for (i = 0; (i < 10); i++) + outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); + brdp->iosize1 = 2; + brdp->iosize2 = 32; + name = "serial(EC8/32)"; + outb(status, brdp->ioaddr1); + break; + + case BRD_ECHMC: + brdp->isr = stl_echmcaintr; + brdp->ioctrl = brdp->ioaddr1 + 0x20; + brdp->iostatus = brdp->ioctrl; + status = inb(brdp->iostatus); + if ((status & ECH_IDBITMASK) != ECH_ID) + return(-ENODEV); + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", + brdp->irq, brdp->brdnr); + return(-EINVAL); + } + outb(ECHMC_BRDRESET, brdp->ioctrl); + outb(ECHMC_INTENABLE, brdp->ioctrl); + brdp->iosize1 = 64; + name = "serial(EC8/32-MC)"; + break; + + case BRD_ECHPCI: + brdp->isr = stl_echpciintr; + brdp->ioctrl = brdp->ioaddr1 + 2; + brdp->iosize1 = 4; + brdp->iosize2 = 8; + name = "serial(EC8/32-PCI)"; + break; + + case BRD_ECH64PCI: + brdp->isr = stl_echpci64intr; + brdp->ioctrl = brdp->ioaddr2 + 0x40; + outb(0x43, (brdp->ioaddr1 + 0x4c)); + brdp->iosize1 = 0x80; + brdp->iosize2 = 0x80; + name = "serial(EC8/64-PCI)"; + break; + + default: + printk("STALLION: unknown board type=%d\n", brdp->brdtype); + return(-EINVAL); + break; + } + +/* + * Check boards for possible IO address conflicts. We won't actually + * do anything about it here, just issue a warning... + */ + conflict = check_region(brdp->ioaddr1, brdp->iosize1) ? + brdp->ioaddr1 : 0; + if ((conflict == 0) && (brdp->iosize2 > 0)) + conflict = check_region(brdp->ioaddr2, brdp->iosize2) ? + brdp->ioaddr2 : 0; + if (conflict) { + printk("STALLION: Warning, board %d I/O address %x conflicts " + "with another device\n", brdp->brdnr, conflict); + } + + request_region(brdp->ioaddr1, brdp->iosize1, name); + if (brdp->iosize2 > 0) + request_region(brdp->ioaddr2, brdp->iosize2, name); + +/* + * Scan through the secondary io address space looking for panels. + * As we find'em allocate and initialize panel structures for each. + */ + brdp->clk = CD1400_CLK; + brdp->hwid = status; + + ioaddr = brdp->ioaddr2; + banknr = 0; + panelnr = 0; + nxtid = 0; + + for (i = 0; (i < STL_MAXPANELS); i++) { + if (brdp->brdtype == BRD_ECHPCI) { + outb(nxtid, brdp->ioctrl); + ioaddr = brdp->ioaddr2; + } + status = inb(ioaddr + ECH_PNLSTATUS); + if ((status & ECH_PNLIDMASK) != nxtid) + break; + panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); + if (panelp == (stlpanel_t *) NULL) { + printk("STALLION: failed to allocate memory " + "(size=%d)\n", sizeof(stlpanel_t)); + break; + } + memset(panelp, 0, sizeof(stlpanel_t)); + panelp->magic = STL_PANELMAGIC; + panelp->brdnr = brdp->brdnr; + panelp->panelnr = panelnr; + panelp->iobase = ioaddr; + panelp->pagenr = nxtid; + panelp->hwid = status; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; + + if (status & ECH_PNLXPID) { + panelp->uartp = (void *) &stl_sc26198uart; + panelp->isr = stl_sc26198intr; + if (status & ECH_PNL16PORT) { + panelp->nrports = 16; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + 4 + + ECH_PNLSTATUS; + } else { + panelp->nrports = 8; + } + } else { + panelp->uartp = (void *) &stl_cd1400uart; + panelp->isr = stl_cd1400echintr; + if (status & ECH_PNL16PORT) { + panelp->nrports = 16; + panelp->ackmask = 0x80; + if (brdp->brdtype != BRD_ECHPCI) + ioaddr += EREG_BANKSIZE; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = ++nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + + ECH_PNLSTATUS; + } else { + panelp->nrports = 8; + panelp->ackmask = 0xc0; + } + } + + nxtid++; + ioaddr += EREG_BANKSIZE; + brdp->nrports += panelp->nrports; + brdp->panels[panelnr++] = panelp; + if ((brdp->brdtype != BRD_ECHPCI) && + (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) + break; + } + + brdp->nrpanels = panelnr; + brdp->nrbnks = banknr; + if (brdp->brdtype == BRD_ECH) + outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); + + brdp->state |= BRD_FOUND; + i = stl_mapirq(brdp->irq, name); + return(i); +} + +/*****************************************************************************/ + +/* + * Initialize and configure the specified board. + * Scan through all the boards in the configuration and see what we + * can find. Handle EIO and the ECH boards a little differently here + * since the initial search and setup is very different. + */ + +static int __init stl_brdinit(stlbrd_t *brdp) +{ + int i; + +#if DEBUG + printk("stl_brdinit(brdp=%x)\n", (int) brdp); +#endif + + switch (brdp->brdtype) { + case BRD_EASYIO: + case BRD_EASYIOPCI: + stl_initeio(brdp); + break; + case BRD_ECH: + case BRD_ECHMC: + case BRD_ECHPCI: + case BRD_ECH64PCI: + stl_initech(brdp); + break; + default: + printk("STALLION: board=%d is unknown board type=%d\n", + brdp->brdnr, brdp->brdtype); + return(ENODEV); + } + + stl_brds[brdp->brdnr] = brdp; + if ((brdp->state & BRD_FOUND) == 0) { + printk("STALLION: %s board not found, board=%d io=%x irq=%d\n", + stl_brdnames[brdp->brdtype], brdp->brdnr, + brdp->ioaddr1, brdp->irq); + return(ENODEV); + } + + for (i = 0; (i < STL_MAXPANELS); i++) + if (brdp->panels[i] != (stlpanel_t *) NULL) + stl_initports(brdp, brdp->panels[i]); + + printk("STALLION: %s found, board=%d io=%x irq=%d " + "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], + brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, + brdp->nrports); + return(0); +} + +/*****************************************************************************/ + +/* + * Find the next available board number that is free. + */ + +static inline int stl_getbrdnr() +{ + int i; + + for (i = 0; (i < STL_MAXBRDS); i++) { + if (stl_brds[i] == (stlbrd_t *) NULL) { + if (i >= stl_nrbrds) + stl_nrbrds = i + 1; + return(i); + } + } + return(-1); +} + +/*****************************************************************************/ + +#ifdef CONFIG_PCI + +/* + * We have a Stallion board. Allocate a board structure and + * initialize it. Read its IO and IRQ resources from PCI + * configuration space. + */ + +static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) +{ + stlbrd_t *brdp; + +#if DEBUG + printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, + devp->bus->number, devp->devfn); +#endif + + if (pci_enable_device(devp)) + return(-EIO); + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) + return(-ENOMEM); + if ((brdp->brdnr = stl_getbrdnr()) < 0) { + printk("STALLION: too many boards found, " + "maximum supported %d\n", STL_MAXBRDS); + return(0); + } + brdp->brdtype = brdtype; + +/* + * Different Stallion boards use the BAR registers in different ways, + * so set up io addresses based on board type. + */ +#if DEBUG + printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__, + pci_resource_start(devp, 0), pci_resource_start(devp, 1), + pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq); +#endif + +/* + * We have all resources from the board, so let's setup the actual + * board structure now. + */ + switch (brdtype) { + case BRD_ECHPCI: + brdp->ioaddr2 = pci_resource_start(devp, 0); + brdp->ioaddr1 = pci_resource_start(devp, 1); + break; + case BRD_ECH64PCI: + brdp->ioaddr2 = pci_resource_start(devp, 2); + brdp->ioaddr1 = pci_resource_start(devp, 1); + break; + case BRD_EASYIOPCI: + brdp->ioaddr1 = pci_resource_start(devp, 2); + brdp->ioaddr2 = pci_resource_start(devp, 1); + break; + default: + printk("STALLION: unknown PCI board type=%d\n", brdtype); + break; + } + + brdp->irq = devp->irq; + stl_brdinit(brdp); + + return(0); +} + +/*****************************************************************************/ + +/* + * Find all Stallion PCI boards that might be installed. Initialize each + * one as it is found. + */ + + +static inline int stl_findpcibrds() +{ + struct pci_dev *dev = NULL; + int i, rc; + +#if DEBUG + printk("stl_findpcibrds()\n"); +#endif + + if (! pci_present()) + return(0); + + for (i = 0; (i < stl_nrpcibrds); i++) + while ((dev = pci_find_device(stl_pcibrds[i].vendid, + stl_pcibrds[i].devid, dev))) { + +/* + * Found a device on the PCI bus that has our vendor and + * device ID. Need to check now that it is really us. + */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) + continue; + + rc = stl_initpcibrd(stl_pcibrds[i].brdtype, dev); + if (rc) + return(rc); + } + + return(0); +} + +#endif + +/*****************************************************************************/ + +/* + * Scan through all the boards in the configuration and see what we + * can find. Handle EIO and the ECH boards a little differently here + * since the initial search and setup is too different. + */ + +static inline int stl_initbrds() +{ + stlbrd_t *brdp; + stlconf_t *confp; + int i; + +#if DEBUG + printk("stl_initbrds()\n"); +#endif + + if (stl_nrbrds > STL_MAXBRDS) { + printk("STALLION: too many boards in configuration table, " + "truncating to %d\n", STL_MAXBRDS); + stl_nrbrds = STL_MAXBRDS; + } + +/* + * Firstly scan the list of static boards configured. Allocate + * resources and initialize the boards as found. + */ + for (i = 0; (i < stl_nrbrds); i++) { + confp = &stl_brdconf[i]; +#ifdef MODULE + stl_parsebrd(confp, stl_brdsp[i]); +#endif + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) + return(-ENOMEM); + brdp->brdnr = i; + brdp->brdtype = confp->brdtype; + brdp->ioaddr1 = confp->ioaddr1; + brdp->ioaddr2 = confp->ioaddr2; + brdp->irq = confp->irq; + brdp->irqtype = confp->irqtype; + stl_brdinit(brdp); + } + +/* + * Find any dynamically supported boards. That is via module load + * line options or auto-detected on the PCI bus. + */ +#ifdef MODULE + stl_argbrds(); +#endif +#ifdef CONFIG_PCI + stl_findpcibrds(); +#endif + + return(0); +} + +/*****************************************************************************/ + +/* + * Return the board stats structure to user app. + */ + +static int stl_getbrdstats(combrd_t *bp) +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + int i; + + copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)); + if (stl_brdstats.brd >= STL_MAXBRDS) + return(-ENODEV); + brdp = stl_brds[stl_brdstats.brd]; + if (brdp == (stlbrd_t *) NULL) + return(-ENODEV); + + memset(&stl_brdstats, 0, sizeof(combrd_t)); + stl_brdstats.brd = brdp->brdnr; + stl_brdstats.type = brdp->brdtype; + stl_brdstats.hwid = brdp->hwid; + stl_brdstats.state = brdp->state; + stl_brdstats.ioaddr = brdp->ioaddr1; + stl_brdstats.ioaddr2 = brdp->ioaddr2; + stl_brdstats.irq = brdp->irq; + stl_brdstats.nrpanels = brdp->nrpanels; + stl_brdstats.nrports = brdp->nrports; + for (i = 0; (i < brdp->nrpanels); i++) { + panelp = brdp->panels[i]; + stl_brdstats.panels[i].panel = i; + stl_brdstats.panels[i].hwid = panelp->hwid; + stl_brdstats.panels[i].nrports = panelp->nrports; + } + + copy_to_user(bp, &stl_brdstats, sizeof(combrd_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Resolve the referenced port number into a port struct pointer. + */ + +static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + + if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) + return((stlport_t *) NULL); + brdp = stl_brds[brdnr]; + if (brdp == (stlbrd_t *) NULL) + return((stlport_t *) NULL); + if ((panelnr < 0) || (panelnr >= brdp->nrpanels)) + return((stlport_t *) NULL); + panelp = brdp->panels[panelnr]; + if (panelp == (stlpanel_t *) NULL) + return((stlport_t *) NULL); + if ((portnr < 0) || (portnr >= panelp->nrports)) + return((stlport_t *) NULL); + return(panelp->ports[portnr]); +} + +/*****************************************************************************/ + +/* + * Return the port stats structure to user app. A NULL port struct + * pointer passed in means that we need to find out from the app + * what port to get stats for (used through board control device). + */ + +static int stl_getportstats(stlport_t *portp, comstats_t *cp) +{ + unsigned char *head, *tail; + unsigned long flags; + + if (portp == (stlport_t *) NULL) { + copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); + portp = stl_getport(stl_comstats.brd, stl_comstats.panel, + stl_comstats.port); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + } + + portp->stats.state = portp->istate; + portp->stats.flags = portp->flags; + portp->stats.hwid = portp->hwid; + + portp->stats.ttystate = 0; + portp->stats.cflags = 0; + portp->stats.iflags = 0; + portp->stats.oflags = 0; + portp->stats.lflags = 0; + portp->stats.rxbuffered = 0; + + save_flags(flags); + cli(); + if (portp->tty != (struct tty_struct *) NULL) { + if (portp->tty->driver_data == portp) { + portp->stats.ttystate = portp->tty->flags; + portp->stats.rxbuffered = portp->tty->flip.count; + if (portp->tty->termios != (struct termios *) NULL) { + portp->stats.cflags = portp->tty->termios->c_cflag; + portp->stats.iflags = portp->tty->termios->c_iflag; + portp->stats.oflags = portp->tty->termios->c_oflag; + portp->stats.lflags = portp->tty->termios->c_lflag; + } + } + } + restore_flags(flags); + + head = portp->tx.head; + tail = portp->tx.tail; + portp->stats.txbuffered = ((head >= tail) ? (head - tail) : + (STL_TXBUFSIZE - (tail - head))); + + portp->stats.signals = (unsigned long) stl_getsignals(portp); + + copy_to_user(cp, &portp->stats, sizeof(comstats_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Clear the port stats structure. We also return it zeroed out... + */ + +static int stl_clrportstats(stlport_t *portp, comstats_t *cp) +{ + if (portp == (stlport_t *) NULL) { + copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); + portp = stl_getport(stl_comstats.brd, stl_comstats.panel, + stl_comstats.port); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + } + + memset(&portp->stats, 0, sizeof(comstats_t)); + portp->stats.brd = portp->brdnr; + portp->stats.panel = portp->panelnr; + portp->stats.port = portp->portnr; + copy_to_user(cp, &portp->stats, sizeof(comstats_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Return the entire driver ports structure to a user app. + */ + +static int stl_getportstruct(unsigned long arg) +{ + stlport_t *portp; + + copy_from_user(&stl_dummyport, (void *) arg, sizeof(stlport_t)); + portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr, + stl_dummyport.portnr); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + copy_to_user((void *) arg, portp, sizeof(stlport_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Return the entire driver board structure to a user app. + */ + +static int stl_getbrdstruct(unsigned long arg) +{ + stlbrd_t *brdp; + + copy_from_user(&stl_dummybrd, (void *) arg, sizeof(stlbrd_t)); + if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) + return(-ENODEV); + brdp = stl_brds[stl_dummybrd.brdnr]; + if (brdp == (stlbrd_t *) NULL) + return(-ENODEV); + copy_to_user((void *) arg, brdp, sizeof(stlbrd_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * The "staliomem" device is also required to do some special operations + * on the board and/or ports. In this driver it is mostly used for stats + * collection. + */ + +static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) +{ + int brdnr, rc; + +#if DEBUG + printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, + (int) fp, cmd, (int) arg); +#endif + + brdnr = MINOR(ip->i_rdev); + if (brdnr >= STL_MAXBRDS) + return(-ENODEV); + rc = 0; + + switch (cmd) { + case COM_GETPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(comstats_t))) == 0) + rc = stl_getportstats((stlport_t *) NULL, + (comstats_t *) arg); + break; + case COM_CLRPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(comstats_t))) == 0) + rc = stl_clrportstats((stlport_t *) NULL, + (comstats_t *) arg); + break; + case COM_GETBRDSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(combrd_t))) == 0) + rc = stl_getbrdstats((combrd_t *) arg); + break; + case COM_READPORT: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(stlport_t))) == 0) + rc = stl_getportstruct(arg); + break; + case COM_READBOARD: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(stlbrd_t))) == 0) + rc = stl_getbrdstruct(arg); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + + return(rc); +} + +/*****************************************************************************/ + +int __init stl_init(void) +{ + printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion); + + stl_initbrds(); + +/* + * Allocate a temporary write buffer. + */ + stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE); + if (stl_tmpwritebuf == (char *) NULL) + printk("STALLION: failed to allocate memory (size=%d)\n", + STL_TXBUFSIZE); + +/* + * Set up a character driver for per board stuff. This is mainly used + * to do stats ioctls on the ports. + */ + if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) + printk("STALLION: failed to register serial board device\n"); + devfs_handle = devfs_mk_dir (NULL, "staliomem", NULL); + devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, + STL_SIOMEMMAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR, + &stl_fsiomem, NULL); + +/* + * Set up the tty driver structure and register us as a driver. + * Also setup the callout tty device. + */ + memset(&stl_serial, 0, sizeof(struct tty_driver)); + stl_serial.magic = TTY_DRIVER_MAGIC; + stl_serial.driver_name = stl_drvname; + stl_serial.name = stl_serialname; + stl_serial.major = STL_SERIALMAJOR; + stl_serial.minor_start = 0; + stl_serial.num = STL_MAXBRDS * STL_MAXPORTS; + stl_serial.type = TTY_DRIVER_TYPE_SERIAL; + stl_serial.subtype = STL_DRVTYPSERIAL; + stl_serial.init_termios = stl_deftermios; + stl_serial.flags = TTY_DRIVER_REAL_RAW; + stl_serial.refcount = &stl_refcount; + stl_serial.table = stl_ttys; + stl_serial.termios = stl_termios; + stl_serial.termios_locked = stl_termioslocked; + + stl_serial.open = stl_open; + stl_serial.close = stl_close; + stl_serial.write = stl_write; + stl_serial.put_char = stl_putchar; + stl_serial.flush_chars = stl_flushchars; + stl_serial.write_room = stl_writeroom; + stl_serial.chars_in_buffer = stl_charsinbuffer; + stl_serial.ioctl = stl_ioctl; + stl_serial.set_termios = stl_settermios; + stl_serial.throttle = stl_throttle; + stl_serial.unthrottle = stl_unthrottle; + stl_serial.stop = stl_stop; + stl_serial.start = stl_start; + stl_serial.hangup = stl_hangup; + stl_serial.flush_buffer = stl_flushbuffer; + stl_serial.break_ctl = stl_breakctl; + stl_serial.wait_until_sent = stl_waituntilsent; + stl_serial.send_xchar = stl_sendxchar; + stl_serial.read_proc = stl_readproc; + + stl_callout = stl_serial; + stl_callout.name = stl_calloutname; + stl_callout.major = STL_CALLOUTMAJOR; + stl_callout.subtype = STL_DRVTYPCALLOUT; + stl_callout.read_proc = 0; + + if (tty_register_driver(&stl_serial)) + printk("STALLION: failed to register serial driver\n"); + if (tty_register_driver(&stl_callout)) + printk("STALLION: failed to register callout driver\n"); + + return(0); +} + +/*****************************************************************************/ +/* CD1400 HARDWARE FUNCTIONS */ +/*****************************************************************************/ + +/* + * These functions get/set/update the registers of the cd1400 UARTs. + * Access to the cd1400 registers is via an address/data io port pair. + * (Maybe should make this inline...) + */ + +static int stl_cd1400getreg(stlport_t *portp, int regnr) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + return(inb(portp->ioaddr + EREG_DATA)); +} + +static void stl_cd1400setreg(stlport_t *portp, int regnr, int value) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + outb(value, portp->ioaddr + EREG_DATA); +} + +static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + if (inb(portp->ioaddr + EREG_DATA) != value) { + outb(value, portp->ioaddr + EREG_DATA); + return(1); + } + return(0); +} + +/*****************************************************************************/ + +/* + * Inbitialize the UARTs in a panel. We don't care what sort of board + * these ports are on - since the port io registers are almost + * identical when dealing with ports. + */ + +static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +{ + unsigned int gfrcr; + int chipmask, i, j; + int nrchips, uartaddr, ioaddr; + +#if DEBUG + printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); +#endif + + BRDENABLE(panelp->brdnr, panelp->pagenr); + +/* + * Check that each chip is present and started up OK. + */ + chipmask = 0; + nrchips = panelp->nrports / CD1400_PORTS; + for (i = 0; (i < nrchips); i++) { + if (brdp->brdtype == BRD_ECHPCI) { + outb((panelp->pagenr + (i >> 1)), brdp->ioctrl); + ioaddr = panelp->iobase; + } else { + ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1)); + } + uartaddr = (i & 0x01) ? 0x080 : 0; + outb((GFRCR + uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); + outb((CCR + uartaddr), ioaddr); + outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); + outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); + outb((GFRCR + uartaddr), ioaddr); + for (j = 0; (j < CCR_MAXWAIT); j++) { + if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0) + break; + } + if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) { + printk("STALLION: cd1400 not responding, " + "brd=%d panel=%d chip=%d\n", + panelp->brdnr, panelp->panelnr, i); + continue; + } + chipmask |= (0x1 << i); + outb((PPR + uartaddr), ioaddr); + outb(PPR_SCALAR, (ioaddr + EREG_DATA)); + } + + BRDDISABLE(panelp->brdnr); + return(chipmask); +} + +/*****************************************************************************/ + +/* + * Initialize hardware specific port registers. + */ + +static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +{ +#if DEBUG + printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", + (int) brdp, (int) panelp, (int) portp); +#endif + + if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || + (portp == (stlport_t *) NULL)) + return; + + portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || + (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); + portp->uartaddr = (portp->portnr & 0x04) << 5; + portp->pagenr = panelp->pagenr + (portp->portnr >> 3); + + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); + portp->hwid = stl_cd1400getreg(portp, GFRCR); + BRDDISABLE(portp->brdnr); +} + +/*****************************************************************************/ + +/* + * Wait for the command register to be ready. We will poll this, + * since it won't usually take too long to be ready. + */ + +static void stl_cd1400ccrwait(stlport_t *portp) +{ + int i; + + for (i = 0; (i < CCR_MAXWAIT); i++) { + if (stl_cd1400getreg(portp, CCR) == 0) { + return; + } + } + + printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n", + portp->portnr, portp->panelnr, portp->brdnr); +} + +/*****************************************************************************/ + +/* + * Set up the cd1400 registers for a port based on the termios port + * settings. + */ + +static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) +{ + stlbrd_t *brdp; + unsigned long flags; + unsigned int clkdiv, baudrate; + unsigned char cor1, cor2, cor3; + unsigned char cor4, cor5, ccr; + unsigned char srer, sreron, sreroff; + unsigned char mcor1, mcor2, rtpr; + unsigned char clk, div; + + cor1 = 0; + cor2 = 0; + cor3 = 0; + cor4 = 0; + cor5 = 0; + ccr = 0; + rtpr = 0; + clk = 0; + div = 0; + mcor1 = 0; + mcor2 = 0; + sreron = 0; + sreroff = 0; + + brdp = stl_brds[portp->brdnr]; + if (brdp == (stlbrd_t *) NULL) + return; + +/* + * Set up the RX char ignore mask with those RX error types we + * can ignore. We can get the cd1400 to help us out a little here, + * it will ignore parity errors and breaks for us. + */ + portp->rxignoremsk = 0; + if (tiosp->c_iflag & IGNPAR) { + portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN); + cor1 |= COR1_PARIGNORE; + } + if (tiosp->c_iflag & IGNBRK) { + portp->rxignoremsk |= ST_BREAK; + cor4 |= COR4_IGNBRK; + } + + portp->rxmarkmsk = ST_OVERRUN; + if (tiosp->c_iflag & (INPCK | PARMRK)) + portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING); + if (tiosp->c_iflag & BRKINT) + portp->rxmarkmsk |= ST_BREAK; + +/* + * Go through the char size, parity and stop bits and set all the + * option register appropriately. + */ + switch (tiosp->c_cflag & CSIZE) { + case CS5: + cor1 |= COR1_CHL5; + break; + case CS6: + cor1 |= COR1_CHL6; + break; + case CS7: + cor1 |= COR1_CHL7; + break; + default: + cor1 |= COR1_CHL8; + break; + } + + if (tiosp->c_cflag & CSTOPB) + cor1 |= COR1_STOP2; + else + cor1 |= COR1_STOP1; + + if (tiosp->c_cflag & PARENB) { + if (tiosp->c_cflag & PARODD) + cor1 |= (COR1_PARENB | COR1_PARODD); + else + cor1 |= (COR1_PARENB | COR1_PAREVEN); + } else { + cor1 |= COR1_PARNONE; + } + +/* + * Set the RX FIFO threshold at 6 chars. This gives a bit of breathing + * space for hardware flow control and the like. This should be set to + * VMIN. Also here we will set the RX data timeout to 10ms - this should + * really be based on VTIME. + */ + cor3 |= FIFO_RXTHRESHOLD; + rtpr = 2; + +/* + * Calculate the baud rate timers. For now we will just assume that + * the input and output baud are the same. Could have used a baud + * table here, but this way we can generate virtually any baud rate + * we like! + */ + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 4)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + baudrate = stl_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + baudrate = 230400; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + baudrate = 460800; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (portp->baud_base / portp->custom_divisor); + } + if (baudrate > STL_CD1400MAXBAUD) + baudrate = STL_CD1400MAXBAUD; + + if (baudrate > 0) { + for (clk = 0; (clk < CD1400_NUMCLKS); clk++) { + clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate); + if (clkdiv < 0x100) + break; + } + div = (unsigned char) clkdiv; + } + +/* + * Check what form of modem signaling is required and set it up. + */ + if ((tiosp->c_cflag & CLOCAL) == 0) { + mcor1 |= MCOR1_DCD; + mcor2 |= MCOR2_DCD; + sreron |= SRER_MODEM; + portp->flags |= ASYNC_CHECK_CD; + } else { + portp->flags &= ~ASYNC_CHECK_CD; + } + +/* + * Setup cd1400 enhanced modes if we can. In particular we want to + * handle as much of the flow control as possible automatically. As + * well as saving a few CPU cycles it will also greatly improve flow + * control reliability. + */ + if (tiosp->c_iflag & IXON) { + cor2 |= COR2_TXIBE; + cor3 |= COR3_SCD12; + if (tiosp->c_iflag & IXANY) + cor2 |= COR2_IXM; + } + + if (tiosp->c_cflag & CRTSCTS) { + cor2 |= COR2_CTSAE; + mcor1 |= FIFO_RTSTHRESHOLD; + } + +/* + * All cd1400 register values calculated so go through and set + * them all up. + */ + +#if DEBUG + printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", + portp->portnr, portp->panelnr, portp->brdnr); + printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", + cor1, cor2, cor3, cor4, cor5); + printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", + mcor1, mcor2, rtpr, sreron, sreroff); + printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); + printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", + tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], + tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); + srer = stl_cd1400getreg(portp, SRER); + stl_cd1400setreg(portp, SRER, 0); + if (stl_cd1400updatereg(portp, COR1, cor1)) + ccr = 1; + if (stl_cd1400updatereg(portp, COR2, cor2)) + ccr = 1; + if (stl_cd1400updatereg(portp, COR3, cor3)) + ccr = 1; + if (ccr) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_CORCHANGE); + } + stl_cd1400setreg(portp, COR4, cor4); + stl_cd1400setreg(portp, COR5, cor5); + stl_cd1400setreg(portp, MCOR1, mcor1); + stl_cd1400setreg(portp, MCOR2, mcor2); + if (baudrate > 0) { + stl_cd1400setreg(portp, TCOR, clk); + stl_cd1400setreg(portp, TBPR, div); + stl_cd1400setreg(portp, RCOR, clk); + stl_cd1400setreg(portp, RBPR, div); + } + stl_cd1400setreg(portp, SCHR1, tiosp->c_cc[VSTART]); + stl_cd1400setreg(portp, SCHR2, tiosp->c_cc[VSTOP]); + stl_cd1400setreg(portp, SCHR3, tiosp->c_cc[VSTART]); + stl_cd1400setreg(portp, SCHR4, tiosp->c_cc[VSTOP]); + stl_cd1400setreg(portp, RTPR, rtpr); + mcor1 = stl_cd1400getreg(portp, MSVR1); + if (mcor1 & MSVR1_DCD) + portp->sigs |= TIOCM_CD; + else + portp->sigs &= ~TIOCM_CD; + stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Set the state of the DTR and RTS signals. + */ + +static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) +{ + unsigned char msvr1, msvr2; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n", + (int) portp, dtr, rts); +#endif + + msvr1 = 0; + msvr2 = 0; + if (dtr > 0) + msvr1 = MSVR1_DTR; + if (rts > 0) + msvr2 = MSVR2_RTS; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + if (rts >= 0) + stl_cd1400setreg(portp, MSVR2, msvr2); + if (dtr >= 0) + stl_cd1400setreg(portp, MSVR1, msvr1); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the state of the signals. + */ + +static int stl_cd1400getsignals(stlport_t *portp) +{ + unsigned char msvr1, msvr2; + unsigned long flags; + int sigs; + +#if DEBUG + printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + msvr1 = stl_cd1400getreg(portp, MSVR1); + msvr2 = stl_cd1400getreg(portp, MSVR2); + BRDDISABLE(portp->brdnr); + restore_flags(flags); + + sigs = 0; + sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; + sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0; + sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0; + sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0; +#if 0 + sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0; + sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0; +#else + sigs |= TIOCM_DSR; +#endif + return(sigs); +} + +/*****************************************************************************/ + +/* + * Enable/Disable the Transmitter and/or Receiver. + */ + +static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char ccr; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n", + (int) portp, rx, tx); +#endif + ccr = 0; + + if (tx == 0) + ccr |= CCR_TXDISABLE; + else if (tx > 0) + ccr |= CCR_TXENABLE; + if (rx == 0) + ccr |= CCR_RXDISABLE; + else if (rx > 0) + ccr |= CCR_RXENABLE; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, ccr); + stl_cd1400ccrwait(portp); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Start/stop the Transmitter and/or Receiver. + */ + +static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char sreron, sreroff; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n", + (int) portp, rx, tx); +#endif + + sreron = 0; + sreroff = 0; + if (tx == 0) + sreroff |= (SRER_TXDATA | SRER_TXEMPTY); + else if (tx == 1) + sreron |= SRER_TXDATA; + else if (tx >= 2) + sreron |= SRER_TXEMPTY; + if (rx == 0) + sreroff |= SRER_RXDATA; + else if (rx > 0) + sreron |= SRER_RXDATA; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, SRER, + ((stl_cd1400getreg(portp, SRER) & ~sreroff) | sreron)); + BRDDISABLE(portp->brdnr); + if (tx > 0) + set_bit(ASYI_TXBUSY, &portp->istate); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Disable all interrupts from this port. + */ + +static void stl_cd1400disableintrs(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); +#endif + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, SRER, 0); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_cd1400sendbreak(stlport_t *portp, int len) +{ + unsigned long flags; + +#if DEBUG + printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, SRER, + ((stl_cd1400getreg(portp, SRER) & ~SRER_TXDATA) | + SRER_TXEMPTY)); + BRDDISABLE(portp->brdnr); + portp->brklen = len; + if (len == 1) + portp->stats.txbreaks++; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Take flow control actions... + */ + +static void stl_cd1400flowctrl(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state); +#endif + + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + + if (state) { + if (tty->termios->c_iflag & IXOFF) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); + portp->stats.rxxon++; + stl_cd1400ccrwait(portp); + } +/* + * Question: should we return RTS to what it was before? It may + * have been set by an ioctl... Suppose not, since if you have + * hardware flow control set then it is pretty silly to go and + * set the RTS line by hand. + */ + if (tty->termios->c_cflag & CRTSCTS) { + stl_cd1400setreg(portp, MCOR1, + (stl_cd1400getreg(portp, MCOR1) | + FIFO_RTSTHRESHOLD)); + stl_cd1400setreg(portp, MSVR2, MSVR2_RTS); + portp->stats.rxrtson++; + } + } else { + if (tty->termios->c_iflag & IXOFF) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); + portp->stats.rxxoff++; + stl_cd1400ccrwait(portp); + } + if (tty->termios->c_cflag & CRTSCTS) { + stl_cd1400setreg(portp, MCOR1, + (stl_cd1400getreg(portp, MCOR1) & 0xf0)); + stl_cd1400setreg(portp, MSVR2, 0); + portp->stats.rxrtsoff++; + } + } + + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Send a flow control character... + */ + +static void stl_cd1400sendflow(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state); +#endif + + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + if (state) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); + portp->stats.rxxon++; + stl_cd1400ccrwait(portp); + } else { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); + portp->stats.rxxoff++; + stl_cd1400ccrwait(portp); + } + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_cd1400flush(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_cd1400flush(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_TXFLUSHFIFO); + stl_cd1400ccrwait(portp); + portp->tx.tail = portp->tx.head; + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the current state of data flow on this port. This is only + * really interresting when determining if data has fully completed + * transmission or not... This is easy for the cd1400, it accurately + * maintains the busy port flag. + */ + +static int stl_cd1400datastate(stlport_t *portp) +{ +#if DEBUG + printk("stl_cd1400datastate(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return(0); + + return(test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for cd1400 EasyIO boards. + */ + +static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) +{ + unsigned char svrtype; + +#if DEBUG + printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n", + (int) panelp, iobase); +#endif + + outb(SVRR, iobase); + svrtype = inb(iobase + EREG_DATA); + if (panelp->nrports > 4) { + outb((SVRR + 0x80), iobase); + svrtype |= inb(iobase + EREG_DATA); + } + + if (svrtype & SVRR_RX) + stl_cd1400rxisr(panelp, iobase); + else if (svrtype & SVRR_TX) + stl_cd1400txisr(panelp, iobase); + else if (svrtype & SVRR_MDM) + stl_cd1400mdmisr(panelp, iobase); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for cd1400 panels. + */ + +static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase) +{ + unsigned char svrtype; + +#if DEBUG + printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp, + iobase); +#endif + + outb(SVRR, iobase); + svrtype = inb(iobase + EREG_DATA); + outb((SVRR + 0x80), iobase); + svrtype |= inb(iobase + EREG_DATA); + if (svrtype & SVRR_RX) + stl_cd1400rxisr(panelp, iobase); + else if (svrtype & SVRR_TX) + stl_cd1400txisr(panelp, iobase); + else if (svrtype & SVRR_MDM) + stl_cd1400mdmisr(panelp, iobase); +} + + +/*****************************************************************************/ + +/* + * Unfortunately we need to handle breaks in the TX data stream, since + * this is the only way to generate them on the cd1400. + */ + +static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) +{ + if (portp->brklen == 1) { + outb((COR2 + portp->uartaddr), ioaddr); + outb((inb(ioaddr + EREG_DATA) | COR2_ETC), + (ioaddr + EREG_DATA)); + outb((TDR + portp->uartaddr), ioaddr); + outb(ETC_CMD, (ioaddr + EREG_DATA)); + outb(ETC_STARTBREAK, (ioaddr + EREG_DATA)); + outb((SRER + portp->uartaddr), ioaddr); + outb((inb(ioaddr + EREG_DATA) & ~(SRER_TXDATA | SRER_TXEMPTY)), + (ioaddr + EREG_DATA)); + return(1); + } else if (portp->brklen > 1) { + outb((TDR + portp->uartaddr), ioaddr); + outb(ETC_CMD, (ioaddr + EREG_DATA)); + outb(ETC_STOPBREAK, (ioaddr + EREG_DATA)); + portp->brklen = -1; + return(1); + } else { + outb((COR2 + portp->uartaddr), ioaddr); + outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), + (ioaddr + EREG_DATA)); + portp->brklen = 0; + } + return(0); +} + +/*****************************************************************************/ + +/* + * Transmit interrupt handler. This has gotta be fast! Handling TX + * chars is pretty simple, stuff as many as possible from the TX buffer + * into the cd1400 FIFO. Must also handle TX breaks here, since they + * are embedded as commands in the data stream. Oh no, had to use a goto! + * This could be optimized more, will do when I get time... + * In practice it is possible that interrupts are enabled but that the + * port has been hung up. Need to handle not having any TX buffer here, + * this is done by using the side effect that head and tail will also + * be NULL if the buffer has been freed. + */ + +static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr) +{ + stlport_t *portp; + int len, stlen; + char *head, *tail; + unsigned char ioack, srer; + +#if DEBUG + printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); +#endif + + ioack = inb(ioaddr + EREG_TXACK); + if (((ioack & panelp->ackmask) != 0) || + ((ioack & ACK_TYPMASK) != ACK_TYPTX)) { + printk("STALLION: bad TX interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + +/* + * Unfortunately we need to handle breaks in the data stream, since + * this is the only way to generate them on the cd1400. Do it now if + * a break is to be sent. + */ + if (portp->brklen != 0) + if (stl_cd1400breakisr(portp, ioaddr)) + goto stl_txalldone; + + head = portp->tx.head; + tail = portp->tx.tail; + len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); + if ((len == 0) || ((len < STL_TXBUFLOW) && + (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { + set_bit(ASYI_TXLOW, &portp->istate); + queue_task(&portp->tqueue, &tq_scheduler); + } + + if (len == 0) { + outb((SRER + portp->uartaddr), ioaddr); + srer = inb(ioaddr + EREG_DATA); + if (srer & SRER_TXDATA) { + srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY; + } else { + srer &= ~(SRER_TXDATA | SRER_TXEMPTY); + clear_bit(ASYI_TXBUSY, &portp->istate); + } + outb(srer, (ioaddr + EREG_DATA)); + } else { + len = MIN(len, CD1400_TXFIFOSIZE); + portp->stats.txtotal += len; + stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + outb((TDR + portp->uartaddr), ioaddr); + outsb((ioaddr + EREG_DATA), tail, stlen); + len -= stlen; + tail += stlen; + if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) + tail = portp->tx.buf; + if (len > 0) { + outsb((ioaddr + EREG_DATA), tail, len); + tail += len; + } + portp->tx.tail = tail; + } + +stl_txalldone: + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); +} + +/*****************************************************************************/ + +/* + * Receive character interrupt handler. Determine if we have good chars + * or bad chars and then process appropriately. Good chars are easy + * just shove the lot into the RX buffer and set all status byte to 0. + * If a bad RX char then process as required. This routine needs to be + * fast! In practice it is possible that we get an interrupt on a port + * that is closed. This can happen on hangups - since they completely + * shutdown a port not in user context. Need to handle this case. + */ + +static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) +{ + stlport_t *portp; + struct tty_struct *tty; + unsigned int ioack, len, buflen; + unsigned char status; + char ch; + +#if DEBUG + printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); +#endif + + ioack = inb(ioaddr + EREG_RXACK); + if ((ioack & panelp->ackmask) != 0) { + printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + tty = portp->tty; + + if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { + outb((RDCR + portp->uartaddr), ioaddr); + len = inb(ioaddr + EREG_DATA); + if ((tty == (struct tty_struct *) NULL) || + (tty->flip.char_buf_ptr == (char *) NULL) || + ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + len = MIN(len, sizeof(stl_unwanted)); + outb((RDSR + portp->uartaddr), ioaddr); + insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); + portp->stats.rxlost += len; + portp->stats.rxtotal += len; + } else { + len = MIN(len, buflen); + if (len > 0) { + outb((RDSR + portp->uartaddr), ioaddr); + insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len); + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + tty->flip.char_buf_ptr += len; + tty->flip.count += len; + tty_schedule_flip(tty); + portp->stats.rxtotal += len; + } + } + } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) { + outb((RDSR + portp->uartaddr), ioaddr); + status = inb(ioaddr + EREG_DATA); + ch = inb(ioaddr + EREG_DATA); + if (status & ST_PARITY) + portp->stats.rxparity++; + if (status & ST_FRAMING) + portp->stats.rxframing++; + if (status & ST_OVERRUN) + portp->stats.rxoverrun++; + if (status & ST_BREAK) + portp->stats.rxbreaks++; + if (status & ST_SCHARMASK) { + if ((status & ST_SCHARMASK) == ST_SCHAR1) + portp->stats.txxon++; + if ((status & ST_SCHARMASK) == ST_SCHAR2) + portp->stats.txxoff++; + goto stl_rxalldone; + } + if ((tty != (struct tty_struct *) NULL) && + ((portp->rxignoremsk & status) == 0)) { + if (portp->rxmarkmsk & status) { + if (status & ST_BREAK) { + status = TTY_BREAK; + if (portp->flags & ASYNC_SAK) { + do_SAK(tty); + BRDENABLE(portp->brdnr, portp->pagenr); + } + } else if (status & ST_PARITY) { + status = TTY_PARITY; + } else if (status & ST_FRAMING) { + status = TTY_FRAME; + } else if(status & ST_OVERRUN) { + status = TTY_OVERRUN; + } else { + status = 0; + } + } else { + status = 0; + } + if (tty->flip.char_buf_ptr != (char *) NULL) { + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.flag_buf_ptr++ = status; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + } + tty_schedule_flip(tty); + } + } + } else { + printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + return; + } + +stl_rxalldone: + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); +} + +/*****************************************************************************/ + +/* + * Modem interrupt handler. The is called when the modem signal line + * (DCD) has changed state. Leave most of the work to the off-level + * processing routine. + */ + +static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) +{ + stlport_t *portp; + unsigned int ioack; + unsigned char misr; + +#if DEBUG + printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp); +#endif + + ioack = inb(ioaddr + EREG_MDACK); + if (((ioack & panelp->ackmask) != 0) || + ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) { + printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + + outb((MISR + portp->uartaddr), ioaddr); + misr = inb(ioaddr + EREG_DATA); + if (misr & MISR_DCD) { + set_bit(ASYI_DCDCHANGE, &portp->istate); + queue_task(&portp->tqueue, &tq_scheduler); + portp->stats.modem++; + } + + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); +} + +/*****************************************************************************/ +/* SC26198 HARDWARE FUNCTIONS */ +/*****************************************************************************/ + +/* + * These functions get/set/update the registers of the sc26198 UARTs. + * Access to the sc26198 registers is via an address/data io port pair. + * (Maybe should make this inline...) + */ + +static int stl_sc26198getreg(stlport_t *portp, int regnr) +{ + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + return(inb(portp->ioaddr + XP_DATA)); +} + +static void stl_sc26198setreg(stlport_t *portp, int regnr, int value) +{ + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + outb(value, (portp->ioaddr + XP_DATA)); +} + +static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) +{ + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + if (inb(portp->ioaddr + XP_DATA) != value) { + outb(value, (portp->ioaddr + XP_DATA)); + return(1); + } + return(0); +} + +/*****************************************************************************/ + +/* + * Functions to get and set the sc26198 global registers. + */ + +static int stl_sc26198getglobreg(stlport_t *portp, int regnr) +{ + outb(regnr, (portp->ioaddr + XP_ADDR)); + return(inb(portp->ioaddr + XP_DATA)); +} + +#if 0 +static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) +{ + outb(regnr, (portp->ioaddr + XP_ADDR)); + outb(value, (portp->ioaddr + XP_DATA)); +} +#endif + +/*****************************************************************************/ + +/* + * Inbitialize the UARTs in a panel. We don't care what sort of board + * these ports are on - since the port io registers are almost + * identical when dealing with ports. + */ + +static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +{ + int chipmask, i; + int nrchips, ioaddr; + +#if DEBUG + printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n", + (int) brdp, (int) panelp); +#endif + + BRDENABLE(panelp->brdnr, panelp->pagenr); + +/* + * Check that each chip is present and started up OK. + */ + chipmask = 0; + nrchips = (panelp->nrports + 4) / SC26198_PORTS; + if (brdp->brdtype == BRD_ECHPCI) + outb(panelp->pagenr, brdp->ioctrl); + + for (i = 0; (i < nrchips); i++) { + ioaddr = panelp->iobase + (i * 4); + outb(SCCR, (ioaddr + XP_ADDR)); + outb(CR_RESETALL, (ioaddr + XP_DATA)); + outb(TSTR, (ioaddr + XP_ADDR)); + if (inb(ioaddr + XP_DATA) != 0) { + printk("STALLION: sc26198 not responding, " + "brd=%d panel=%d chip=%d\n", + panelp->brdnr, panelp->panelnr, i); + continue; + } + chipmask |= (0x1 << i); + outb(GCCR, (ioaddr + XP_ADDR)); + outb(GCCR_IVRTYPCHANACK, (ioaddr + XP_DATA)); + outb(WDTRCR, (ioaddr + XP_ADDR)); + outb(0xff, (ioaddr + XP_DATA)); + } + + BRDDISABLE(panelp->brdnr); + return(chipmask); +} + +/*****************************************************************************/ + +/* + * Initialize hardware specific port registers. + */ + +static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +{ +#if DEBUG + printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n", + (int) brdp, (int) panelp, (int) portp); +#endif + + if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || + (portp == (stlport_t *) NULL)) + return; + + portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4); + portp->uartaddr = (portp->portnr & 0x07) << 4; + portp->pagenr = panelp->pagenr; + portp->hwid = 0x1; + + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IOPCR, IOPCR_SETSIGS); + BRDDISABLE(portp->brdnr); +} + +/*****************************************************************************/ + +/* + * Set up the sc26198 registers for a port based on the termios port + * settings. + */ + +static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) +{ + stlbrd_t *brdp; + unsigned long flags; + unsigned int baudrate; + unsigned char mr0, mr1, mr2, clk; + unsigned char imron, imroff, iopr, ipr; + + mr0 = 0; + mr1 = 0; + mr2 = 0; + clk = 0; + iopr = 0; + imron = 0; + imroff = 0; + + brdp = stl_brds[portp->brdnr]; + if (brdp == (stlbrd_t *) NULL) + return; + +/* + * Set up the RX char ignore mask with those RX error types we + * can ignore. + */ + portp->rxignoremsk = 0; + if (tiosp->c_iflag & IGNPAR) + portp->rxignoremsk |= (SR_RXPARITY | SR_RXFRAMING | + SR_RXOVERRUN); + if (tiosp->c_iflag & IGNBRK) + portp->rxignoremsk |= SR_RXBREAK; + + portp->rxmarkmsk = SR_RXOVERRUN; + if (tiosp->c_iflag & (INPCK | PARMRK)) + portp->rxmarkmsk |= (SR_RXPARITY | SR_RXFRAMING); + if (tiosp->c_iflag & BRKINT) + portp->rxmarkmsk |= SR_RXBREAK; + +/* + * Go through the char size, parity and stop bits and set all the + * option register appropriately. + */ + switch (tiosp->c_cflag & CSIZE) { + case CS5: + mr1 |= MR1_CS5; + break; + case CS6: + mr1 |= MR1_CS6; + break; + case CS7: + mr1 |= MR1_CS7; + break; + default: + mr1 |= MR1_CS8; + break; + } + + if (tiosp->c_cflag & CSTOPB) + mr2 |= MR2_STOP2; + else + mr2 |= MR2_STOP1; + + if (tiosp->c_cflag & PARENB) { + if (tiosp->c_cflag & PARODD) + mr1 |= (MR1_PARENB | MR1_PARODD); + else + mr1 |= (MR1_PARENB | MR1_PAREVEN); + } else { + mr1 |= MR1_PARNONE; + } + + mr1 |= MR1_ERRBLOCK; + +/* + * Set the RX FIFO threshold at 8 chars. This gives a bit of breathing + * space for hardware flow control and the like. This should be set to + * VMIN. + */ + mr2 |= MR2_RXFIFOHALF; + +/* + * Calculate the baud rate timers. For now we will just assume that + * the input and output baud are the same. The sc26198 has a fixed + * baud rate table, so only discrete baud rates possible. + */ + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 4)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + baudrate = stl_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + baudrate = 230400; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + baudrate = 460800; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (portp->baud_base / portp->custom_divisor); + } + if (baudrate > STL_SC26198MAXBAUD) + baudrate = STL_SC26198MAXBAUD; + + if (baudrate > 0) { + for (clk = 0; (clk < SC26198_NRBAUDS); clk++) { + if (baudrate <= sc26198_baudtable[clk]) + break; + } + } + +/* + * Check what form of modem signaling is required and set it up. + */ + if (tiosp->c_cflag & CLOCAL) { + portp->flags &= ~ASYNC_CHECK_CD; + } else { + iopr |= IOPR_DCDCOS; + imron |= IR_IOPORT; + portp->flags |= ASYNC_CHECK_CD; + } + +/* + * Setup sc26198 enhanced modes if we can. In particular we want to + * handle as much of the flow control as possible automatically. As + * well as saving a few CPU cycles it will also greatly improve flow + * control reliability. + */ + if (tiosp->c_iflag & IXON) { + mr0 |= MR0_SWFTX | MR0_SWFT; + imron |= IR_XONXOFF; + } else { + imroff |= IR_XONXOFF; + } + if (tiosp->c_iflag & IXOFF) + mr0 |= MR0_SWFRX; + + if (tiosp->c_cflag & CRTSCTS) { + mr2 |= MR2_AUTOCTS; + mr1 |= MR1_AUTORTS; + } + +/* + * All sc26198 register values calculated so go through and set + * them all up. + */ + +#if DEBUG + printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", + portp->portnr, portp->panelnr, portp->brdnr); + printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk); + printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff); + printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", + tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], + tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IMR, 0); + stl_sc26198updatereg(portp, MR0, mr0); + stl_sc26198updatereg(portp, MR1, mr1); + stl_sc26198setreg(portp, SCCR, CR_RXERRBLOCK); + stl_sc26198updatereg(portp, MR2, mr2); + stl_sc26198updatereg(portp, IOPIOR, + ((stl_sc26198getreg(portp, IOPIOR) & ~IPR_CHANGEMASK) | iopr)); + + if (baudrate > 0) { + stl_sc26198setreg(portp, TXCSR, clk); + stl_sc26198setreg(portp, RXCSR, clk); + } + + stl_sc26198setreg(portp, XONCR, tiosp->c_cc[VSTART]); + stl_sc26198setreg(portp, XOFFCR, tiosp->c_cc[VSTOP]); + + ipr = stl_sc26198getreg(portp, IPR); + if (ipr & IPR_DCD) + portp->sigs &= ~TIOCM_CD; + else + portp->sigs |= TIOCM_CD; + + portp->imr = (portp->imr & ~imroff) | imron; + stl_sc26198setreg(portp, IMR, portp->imr); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Set the state of the DTR and RTS signals. + */ + +static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) +{ + unsigned char iopioron, iopioroff; + unsigned long flags; + +#if DEBUG + printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n", + (int) portp, dtr, rts); +#endif + + iopioron = 0; + iopioroff = 0; + if (dtr == 0) + iopioroff |= IPR_DTR; + else if (dtr > 0) + iopioron |= IPR_DTR; + if (rts == 0) + iopioroff |= IPR_RTS; + else if (rts > 0) + iopioron |= IPR_RTS; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IOPIOR, + ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the state of the signals. + */ + +static int stl_sc26198getsignals(stlport_t *portp) +{ + unsigned char ipr; + unsigned long flags; + int sigs; + +#if DEBUG + printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + ipr = stl_sc26198getreg(portp, IPR); + BRDDISABLE(portp->brdnr); + restore_flags(flags); + + sigs = 0; + sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; + sigs |= (ipr & IPR_CTS) ? 0 : TIOCM_CTS; + sigs |= (ipr & IPR_DTR) ? 0: TIOCM_DTR; + sigs |= (ipr & IPR_RTS) ? 0: TIOCM_RTS; + sigs |= TIOCM_DSR; + return(sigs); +} + +/*****************************************************************************/ + +/* + * Enable/Disable the Transmitter and/or Receiver. + */ + +static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char ccr; + unsigned long flags; + +#if DEBUG + printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n", + (int) portp, rx, tx); +#endif + + ccr = portp->crenable; + if (tx == 0) + ccr &= ~CR_TXENABLE; + else if (tx > 0) + ccr |= CR_TXENABLE; + if (rx == 0) + ccr &= ~CR_RXENABLE; + else if (rx > 0) + ccr |= CR_RXENABLE; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, SCCR, ccr); + BRDDISABLE(portp->brdnr); + portp->crenable = ccr; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Start/stop the Transmitter and/or Receiver. + */ + +static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char imr; + unsigned long flags; + +#if DEBUG + printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n", + (int) portp, rx, tx); +#endif + + imr = portp->imr; + if (tx == 0) + imr &= ~IR_TXRDY; + else if (tx == 1) + imr |= IR_TXRDY; + if (rx == 0) + imr &= ~(IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG); + else if (rx > 0) + imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IMR, imr); + BRDDISABLE(portp->brdnr); + portp->imr = imr; + if (tx > 0) + set_bit(ASYI_TXBUSY, &portp->istate); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Disable all interrupts from this port. + */ + +static void stl_sc26198disableintrs(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + portp->imr = 0; + stl_sc26198setreg(portp, IMR, 0); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_sc26198sendbreak(stlport_t *portp, int len) +{ + unsigned long flags; + +#if DEBUG + printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + if (len == 1) { + stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); + portp->stats.txbreaks++; + } else { + stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); + } + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Take flow control actions... + */ + +static void stl_sc26198flowctrl(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + unsigned char mr0; + +#if DEBUG + printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state); +#endif + + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + + if (state) { + if (tty->termios->c_iflag & IXOFF) { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); + mr0 |= MR0_SWFRX; + portp->stats.rxxon++; + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + } +/* + * Question: should we return RTS to what it was before? It may + * have been set by an ioctl... Suppose not, since if you have + * hardware flow control set then it is pretty silly to go and + * set the RTS line by hand. + */ + if (tty->termios->c_cflag & CRTSCTS) { + stl_sc26198setreg(portp, MR1, + (stl_sc26198getreg(portp, MR1) | MR1_AUTORTS)); + stl_sc26198setreg(portp, IOPIOR, + (stl_sc26198getreg(portp, IOPIOR) | IOPR_RTS)); + portp->stats.rxrtson++; + } + } else { + if (tty->termios->c_iflag & IXOFF) { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); + mr0 &= ~MR0_SWFRX; + portp->stats.rxxoff++; + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + } + if (tty->termios->c_cflag & CRTSCTS) { + stl_sc26198setreg(portp, MR1, + (stl_sc26198getreg(portp, MR1) & ~MR1_AUTORTS)); + stl_sc26198setreg(portp, IOPIOR, + (stl_sc26198getreg(portp, IOPIOR) & ~IOPR_RTS)); + portp->stats.rxrtsoff++; + } + } + + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Send a flow control character. + */ + +static void stl_sc26198sendflow(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + unsigned char mr0; + +#if DEBUG + printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state); +#endif + + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + if (state) { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); + mr0 |= MR0_SWFRX; + portp->stats.rxxon++; + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + } else { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); + mr0 &= ~MR0_SWFRX; + portp->stats.rxxoff++; + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + } + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_sc26198flush(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_sc26198flush(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, SCCR, CR_TXRESET); + stl_sc26198setreg(portp, SCCR, portp->crenable); + BRDDISABLE(portp->brdnr); + portp->tx.tail = portp->tx.head; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the current state of data flow on this port. This is only + * really interresting when determining if data has fully completed + * transmission or not... The sc26198 interrupt scheme cannot + * determine when all data has actually drained, so we need to + * check the port statusy register to be sure. + */ + +static int stl_sc26198datastate(stlport_t *portp) +{ + unsigned long flags; + unsigned char sr; + +#if DEBUG + printk("stl_sc26198datastate(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return(0); + if (test_bit(ASYI_TXBUSY, &portp->istate)) + return(1); + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + sr = stl_sc26198getreg(portp, SR); + BRDDISABLE(portp->brdnr); + restore_flags(flags); + + return((sr & SR_TXEMPTY) ? 0 : 1); +} + +/*****************************************************************************/ + +/* + * Delay for a small amount of time, to give the sc26198 a chance + * to process a command... + */ + +static void stl_sc26198wait(stlport_t *portp) +{ + int i; + +#if DEBUG + printk("stl_sc26198wait(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return; + + for (i = 0; (i < 20); i++) + stl_sc26198getglobreg(portp, TSTR); +} + +/*****************************************************************************/ + +/* + * If we are TX flow controlled and in IXANY mode then we may + * need to unflow control here. We gotta do this because of the + * automatic flow control modes of the sc26198. + */ + +static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) +{ + unsigned char mr0; + + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_HOSTXON); + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + clear_bit(ASYI_TXFLOWED, &portp->istate); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for sc26198 panels. + */ + +static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) +{ + stlport_t *portp; + unsigned int iack; + +/* + * Work around bug in sc26198 chip... Cannot have A6 address + * line of UART high, else iack will be returned as 0. + */ + outb(0, (iobase + 1)); + + iack = inb(iobase + XP_IACK); + portp = panelp->ports[(iack & IVR_CHANMASK) + ((iobase & 0x4) << 1)]; + + if (iack & IVR_RXDATA) + stl_sc26198rxisr(portp, iack); + else if (iack & IVR_TXDATA) + stl_sc26198txisr(portp); + else + stl_sc26198otherisr(portp, iack); +} + +/*****************************************************************************/ + +/* + * Transmit interrupt handler. This has gotta be fast! Handling TX + * chars is pretty simple, stuff as many as possible from the TX buffer + * into the sc26198 FIFO. + * In practice it is possible that interrupts are enabled but that the + * port has been hung up. Need to handle not having any TX buffer here, + * this is done by using the side effect that head and tail will also + * be NULL if the buffer has been freed. + */ + +static void stl_sc26198txisr(stlport_t *portp) +{ + unsigned int ioaddr; + unsigned char mr0; + int len, stlen; + char *head, *tail; + +#if DEBUG + printk("stl_sc26198txisr(portp=%x)\n", (int) portp); +#endif + + ioaddr = portp->ioaddr; + head = portp->tx.head; + tail = portp->tx.tail; + len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); + if ((len == 0) || ((len < STL_TXBUFLOW) && + (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { + set_bit(ASYI_TXLOW, &portp->istate); + queue_task(&portp->tqueue, &tq_scheduler); + } + + if (len == 0) { + outb((MR0 | portp->uartaddr), (ioaddr + XP_ADDR)); + mr0 = inb(ioaddr + XP_DATA); + if ((mr0 & MR0_TXMASK) == MR0_TXEMPTY) { + portp->imr &= ~IR_TXRDY; + outb((IMR | portp->uartaddr), (ioaddr + XP_ADDR)); + outb(portp->imr, (ioaddr + XP_DATA)); + clear_bit(ASYI_TXBUSY, &portp->istate); + } else { + mr0 |= ((mr0 & ~MR0_TXMASK) | MR0_TXEMPTY); + outb(mr0, (ioaddr + XP_DATA)); + } + } else { + len = MIN(len, SC26198_TXFIFOSIZE); + portp->stats.txtotal += len; + stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + outb(GTXFIFO, (ioaddr + XP_ADDR)); + outsb((ioaddr + XP_DATA), tail, stlen); + len -= stlen; + tail += stlen; + if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) + tail = portp->tx.buf; + if (len > 0) { + outsb((ioaddr + XP_DATA), tail, len); + tail += len; + } + portp->tx.tail = tail; + } +} + +/*****************************************************************************/ + +/* + * Receive character interrupt handler. Determine if we have good chars + * or bad chars and then process appropriately. Good chars are easy + * just shove the lot into the RX buffer and set all status byte to 0. + * If a bad RX char then process as required. This routine needs to be + * fast! In practice it is possible that we get an interrupt on a port + * that is closed. This can happen on hangups - since they completely + * shutdown a port not in user context. Need to handle this case. + */ + +static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) +{ + struct tty_struct *tty; + unsigned int len, buflen, ioaddr; + +#if DEBUG + printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack); +#endif + + tty = portp->tty; + ioaddr = portp->ioaddr; + outb(GIBCR, (ioaddr + XP_ADDR)); + len = inb(ioaddr + XP_DATA) + 1; + + if ((iack & IVR_TYPEMASK) == IVR_RXDATA) { + if ((tty == (struct tty_struct *) NULL) || + (tty->flip.char_buf_ptr == (char *) NULL) || + ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + len = MIN(len, sizeof(stl_unwanted)); + outb(GRXFIFO, (ioaddr + XP_ADDR)); + insb((ioaddr + XP_DATA), &stl_unwanted[0], len); + portp->stats.rxlost += len; + portp->stats.rxtotal += len; + } else { + len = MIN(len, buflen); + if (len > 0) { + outb(GRXFIFO, (ioaddr + XP_ADDR)); + insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len); + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + tty->flip.char_buf_ptr += len; + tty->flip.count += len; + tty_schedule_flip(tty); + portp->stats.rxtotal += len; + } + } + } else { + stl_sc26198rxbadchars(portp); + } + +/* + * If we are TX flow controlled and in IXANY mode then we may need + * to unflow control here. We gotta do this because of the automatic + * flow control modes of the sc26198. + */ + if (test_bit(ASYI_TXFLOWED, &portp->istate)) { + if ((tty != (struct tty_struct *) NULL) && + (tty->termios != (struct termios *) NULL) && + (tty->termios->c_iflag & IXANY)) { + stl_sc26198txunflow(portp, tty); + } + } +} + +/*****************************************************************************/ + +/* + * Process an RX bad character. + */ + +static void inline stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch) +{ + struct tty_struct *tty; + unsigned int ioaddr; + + tty = portp->tty; + ioaddr = portp->ioaddr; + + if (status & SR_RXPARITY) + portp->stats.rxparity++; + if (status & SR_RXFRAMING) + portp->stats.rxframing++; + if (status & SR_RXOVERRUN) + portp->stats.rxoverrun++; + if (status & SR_RXBREAK) + portp->stats.rxbreaks++; + + if ((tty != (struct tty_struct *) NULL) && + ((portp->rxignoremsk & status) == 0)) { + if (portp->rxmarkmsk & status) { + if (status & SR_RXBREAK) { + status = TTY_BREAK; + if (portp->flags & ASYNC_SAK) { + do_SAK(tty); + BRDENABLE(portp->brdnr, portp->pagenr); + } + } else if (status & SR_RXPARITY) { + status = TTY_PARITY; + } else if (status & SR_RXFRAMING) { + status = TTY_FRAME; + } else if(status & SR_RXOVERRUN) { + status = TTY_OVERRUN; + } else { + status = 0; + } + } else { + status = 0; + } + + if (tty->flip.char_buf_ptr != (char *) NULL) { + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.flag_buf_ptr++ = status; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + } + tty_schedule_flip(tty); + } + + if (status == 0) + portp->stats.rxtotal++; + } +} + +/*****************************************************************************/ + +/* + * Process all characters in the RX FIFO of the UART. Check all char + * status bytes as well, and process as required. We need to check + * all bytes in the FIFO, in case some more enter the FIFO while we + * are here. To get the exact character error type we need to switch + * into CHAR error mode (that is why we need to make sure we empty + * the FIFO). + */ + +static void stl_sc26198rxbadchars(stlport_t *portp) +{ + unsigned char status, mr1; + char ch; + +/* + * To get the precise error type for each character we must switch + * back into CHAR error mode. + */ + mr1 = stl_sc26198getreg(portp, MR1); + stl_sc26198setreg(portp, MR1, (mr1 & ~MR1_ERRBLOCK)); + + while ((status = stl_sc26198getreg(portp, SR)) & SR_RXRDY) { + stl_sc26198setreg(portp, SCCR, CR_CLEARRXERR); + ch = stl_sc26198getreg(portp, RXFIFO); + stl_sc26198rxbadch(portp, status, ch); + } + +/* + * To get correct interrupt class we must switch back into BLOCK + * error mode. + */ + stl_sc26198setreg(portp, MR1, mr1); +} + +/*****************************************************************************/ + +/* + * Other interrupt handler. This includes modem signals, flow + * control actions, etc. Most stuff is left to off-level interrupt + * processing time. + */ + +static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack) +{ + unsigned char cir, ipr, xisr; + +#if DEBUG + printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack); +#endif + + cir = stl_sc26198getglobreg(portp, CIR); + + switch (cir & CIR_SUBTYPEMASK) { + case CIR_SUBCOS: + ipr = stl_sc26198getreg(portp, IPR); + if (ipr & IPR_DCDCHANGE) { + set_bit(ASYI_DCDCHANGE, &portp->istate); + queue_task(&portp->tqueue, &tq_scheduler); + portp->stats.modem++; + } + break; + case CIR_SUBXONXOFF: + xisr = stl_sc26198getreg(portp, XISR); + if (xisr & XISR_RXXONGOT) { + set_bit(ASYI_TXFLOWED, &portp->istate); + portp->stats.txxoff++; + } + if (xisr & XISR_RXXOFFGOT) { + clear_bit(ASYI_TXFLOWED, &portp->istate); + portp->stats.txxon++; + } + break; + case CIR_SUBBREAK: + stl_sc26198setreg(portp, SCCR, CR_BREAKRESET); + stl_sc26198rxbadchars(portp); + break; + default: + break; + } +} + +/*****************************************************************************/ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/i2c/i2c-dev.c linux/drivers/i2c/i2c-dev.c --- v2.4.0-test7/linux/drivers/i2c/i2c-dev.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/i2c/i2c-dev.c Tue Aug 29 14:09:15 2000 @@ -220,10 +220,10 @@ sizeof(unsigned long)))?-EFAULT:0; case I2C_RDWR: - copy_from_user_ret(&rdwr_arg, - (struct i2c_rdwr_ioctl_data *)arg, - sizeof(rdwr_arg), - -EFAULT); + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data *)arg, + sizeof(rdwr_arg))) + return -EFAULT; rdwr_pa = (struct i2c_msg *) kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), @@ -280,10 +280,10 @@ return res; case I2C_SMBUS: - copy_from_user_ret(&data_arg, + if (copy_from_user(&data_arg, (struct i2c_smbus_ioctl_data *) arg, - sizeof(struct i2c_smbus_ioctl_data), - -EFAULT); + sizeof(struct i2c_smbus_ioctl_data))) + return -EFAULT; if ((data_arg.size != I2C_SMBUS_BYTE) && (data_arg.size != I2C_SMBUS_QUICK) && (data_arg.size != I2C_SMBUS_BYTE_DATA) && @@ -336,15 +336,18 @@ datasize = sizeof(data_arg.data->block); if ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_WRITE)) - copy_from_user_ret(&temp,data_arg.data,datasize, - -EFAULT); + (data_arg.read_write == I2C_SMBUS_WRITE)) { + if (copy_from_user(&temp, data_arg.data, datasize)) + return -EFAULT; + } res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, data_arg.read_write, data_arg.command,data_arg.size,&temp); if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_READ))) - copy_to_user_ret(data_arg.data,&temp,datasize,-EFAULT); + (data_arg.read_write == I2C_SMBUS_READ))) { + if (copy_to_user(data_arg.data, &temp, datasize)) + return -EFAULT; + } return res; default: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/ide/Config.in linux/drivers/ide/Config.in --- v2.4.0-test7/linux/drivers/ide/Config.in Fri Jun 23 21:55:08 2000 +++ linux/drivers/ide/Config.in Tue Sep 5 13:08:42 2000 @@ -71,7 +71,6 @@ dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI - dep_mbool ' VIA82CXXX Tuning support (WIP)' CONFIG_VIA82CXXX_TUNING $CONFIG_BLK_DEV_VIA82CXXX $CONFIG_IDEDMA_PCI_WIP fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 diff -u --recursive --new-file v2.4.0-test7/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- v2.4.0-test7/linux/drivers/ide/ide-cd.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/ide/ide-cd.c Tue Sep 5 13:46:15 2000 @@ -542,11 +542,11 @@ /* Returns 0 if the request should be continued. Returns 1 if the request was ended. */ -static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive, int good_stat, - int *stat_ret) +static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive, + int good_stat, int *stat_ret) { struct request *rq = HWGROUP(drive)->rq; - int stat, cmd, err, sense_key; + int stat, err, sense_key; struct packet_command *pc; /* Check for errors. */ @@ -560,103 +560,99 @@ err = GET_ERR(); sense_key = err >> 4; - if (rq == NULL) - printk ("%s: missing request in cdrom_decode_status\n", - drive->name); - else { - cmd = rq->cmd; - - if (cmd == REQUEST_SENSE_COMMAND) { - /* We got an error trying to get sense info - from the drive (probably while trying - to recover from a former error). Just give up. */ - - pc = (struct packet_command *) rq->buffer; - pc->stat = 1; - cdrom_end_request (1, drive); - *startstop = ide_error (drive, "request sense failure", stat); - return 1; - - } else if (cmd == PACKET_COMMAND) { - /* All other functions, except for READ. */ + if (rq == NULL) { + printk("%s: missing rq in cdrom_decode_status\n", drive->name); + *startstop = ide_stopped; + return 1; + } - struct semaphore *sem = NULL; - pc = (struct packet_command *) rq->buffer; + if (rq->cmd == REQUEST_SENSE_COMMAND) { + /* We got an error trying to get sense info + from the drive (probably while trying + to recover from a former error). Just give up. */ - /* Check for tray open. */ - if (sense_key == NOT_READY) { - cdrom_saw_media_change (drive); - } else if (sense_key == UNIT_ATTENTION) { - /* Check for media change. */ - cdrom_saw_media_change (drive); - /*printk("%s: media changed\n",drive->name);*/ - return 0; - } else { - /* Otherwise, print an error. */ - ide_dump_status (drive, "packet command error", - stat); - } - - /* Set the error flag and complete the request. - Then, if we have a CHECK CONDITION status, - queue a request sense command. We must be careful, - though: we don't want the thread in - cdrom_queue_packet_command to wake up until - the request sense has completed. We do this - by transferring the semaphore from the packet - command request to the request sense request. */ - - if ((stat & ERR_STAT) != 0) { - sem = rq->sem; - rq->sem = NULL; - } - - pc->stat = 1; - cdrom_end_request (1, drive); + pc = (struct packet_command *) rq->buffer; + pc->stat = 1; + cdrom_end_request (1, drive); + *startstop = ide_error (drive, "request sense failure", stat); + return 1; - if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, sem, pc->sense, - pc); + } else if (rq->cmd == PACKET_COMMAND) { + /* All other functions, except for READ. */ + struct semaphore *sem = NULL; + pc = (struct packet_command *) rq->buffer; + + /* Check for tray open. */ + if (sense_key == NOT_READY) { + cdrom_saw_media_change (drive); + } else if (sense_key == UNIT_ATTENTION) { + /* Check for media change. */ + cdrom_saw_media_change (drive); + /*printk("%s: media changed\n",drive->name);*/ + return 0; } else { - /* Handle errors from READ requests. */ + /* Otherwise, print an error. */ + ide_dump_status(drive, "packet command error", stat); + } + + /* Set the error flag and complete the request. + Then, if we have a CHECK CONDITION status, + queue a request sense command. We must be careful, + though: we don't want the thread in + cdrom_queue_packet_command to wake up until + the request sense has completed. We do this + by transferring the semaphore from the packet + command request to the request sense request. */ + + if ((stat & ERR_STAT) != 0) { + sem = rq->sem; + rq->sem = NULL; + } - if (sense_key == NOT_READY) { - /* Tray open. */ - cdrom_saw_media_change (drive); + pc->stat = 1; + cdrom_end_request (1, drive); - /* Fail the request. */ - printk ("%s: tray open\n", drive->name); - cdrom_end_request (0, drive); - } else if (sense_key == UNIT_ATTENTION) { - /* Media change. */ - cdrom_saw_media_change (drive); + if ((stat & ERR_STAT) != 0) + cdrom_queue_request_sense(drive, sem, pc->sense, pc); + } else { + /* Handle errors from READ requests. */ - /* Arrange to retry the request. - But be sure to give up if we've retried - too many times. */ - if (++rq->errors > ERROR_MAX) - cdrom_end_request (0, drive); - } else if (sense_key == ILLEGAL_REQUEST || - sense_key == DATA_PROTECT) { - /* No point in retrying after an illegal - request or data protect error.*/ - ide_dump_status (drive, "command error", stat); - cdrom_end_request (0, drive); - } else if ((err & ~ABRT_ERR) != 0) { - /* Go to the default handler - for other errors. */ - *startstop = ide_error (drive, "cdrom_decode_status", stat); - return 1; - } else if ((++rq->errors > ERROR_MAX)) { - /* We've racked up too many retries. Abort. */ - cdrom_end_request (0, drive); - } + if (sense_key == NOT_READY) { + /* Tray open. */ + cdrom_saw_media_change (drive); - /* If we got a CHECK_CONDITION status, - queue a request sense command. */ - if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, NULL, NULL, NULL); + /* Fail the request. */ + printk ("%s: tray open\n", drive->name); + cdrom_end_request (0, drive); + } else if (sense_key == UNIT_ATTENTION) { + /* Media change. */ + cdrom_saw_media_change (drive); + + /* Arrange to retry the request. + But be sure to give up if we've retried + too many times. */ + if (++rq->errors > ERROR_MAX) + cdrom_end_request (0, drive); + } else if (sense_key == ILLEGAL_REQUEST || + sense_key == DATA_PROTECT) { + /* No point in retrying after an illegal + request or data protect error.*/ + ide_dump_status (drive, "command error", stat); + cdrom_end_request (0, drive); + } else if ((err & ~ABRT_ERR) != 0) { + /* Go to the default handler + for other errors. */ + *startstop = ide_error (drive, "cdrom_decode_status", stat); + return 1; + } else if ((++rq->errors > ERROR_MAX)) { + /* We've racked up too many retries. Abort. */ + cdrom_end_request (0, drive); } + + /* If we got a CHECK_CONDITION status, + queue a request sense command. */ + if ((stat & ERR_STAT) != 0) + cdrom_queue_request_sense(drive, NULL, NULL, NULL); } /* Retry, or handle the next request. */ @@ -686,8 +682,9 @@ called when the interrupt from the drive arrives. Otherwise, HANDLER will be called immediately after the drive is prepared for the transfer. */ -static ide_startstop_t cdrom_start_packet_command (ide_drive_t *drive, int xferlen, - ide_handler_t *handler) +static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, + int xferlen, + ide_handler_t *handler) { ide_startstop_t startstop; struct cdrom_info *info = drive->driver_data; @@ -783,7 +780,7 @@ /* If we couldn't get a buffer, don't try to buffer anything... */ if (info->buffer == NULL) - sectors_to_buffer = 0; + sectors_to_buffer = 0; /* If this is the first sector in the buffer, remember its number. */ if (info->nsectors_buffered == 0) @@ -1657,10 +1654,10 @@ /* Check to see if the existing data is still valid. If it is, just return. */ - if (CDROM_STATE_FLAGS (drive)->toc_valid) - (void) cdrom_check_status(drive, sense); + (void) cdrom_check_status(drive, sense); - if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0; + if (CDROM_STATE_FLAGS(drive)->toc_valid) + return 0; /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, @@ -1717,10 +1714,10 @@ toc->hdr.first_track = CDROM_LEADOUT; toc->hdr.last_track = CDROM_LEADOUT; } - } else if (stat) { - return stat; } - if (stat) return stat; + + if (stat) + return stat; toc->hdr.toc_length = ntohs (toc->hdr.toc_length); @@ -1836,6 +1833,20 @@ return cdrom_queue_packet_command(drive, &pc); } +static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end) +{ + struct request_sense sense; + struct packet_command pc; + + memset(&pc, 0, sizeof (pc)); + pc.sense = &sense; + + pc.c[0] = GPCMD_PLAY_AUDIO_10; + put_unaligned(cpu_to_be32(lba_start), (unsigned int *) &pc.c[2]); + put_unaligned(cpu_to_be16(lba_end - lba_start), (unsigned int *) &pc.c[7]); + + return cdrom_queue_packet_command(drive, &pc); +} static int cdrom_get_toc_entry(ide_drive_t *drive, int track, struct atapi_toc_entry **ent) @@ -1844,6 +1855,12 @@ struct atapi_toc *toc = info->toc; int ntracks; + /* + * don't serve cached data, if the toc isn't valid + */ + if (!CDROM_STATE_FLAGS(drive)->toc_valid) + return -EINVAL; + /* Check validity of requested track number. */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0; @@ -1941,6 +1958,34 @@ struct cdrom_info *info = drive->driver_data; switch (cmd) { + /* + * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since + * atapi doesn't support it + */ + case CDROMPLAYTRKIND: { + int stat, lba_start, lba_end; + struct cdrom_ti *ti = (struct cdrom_ti *)arg; + struct atapi_toc_entry *first_toc, *last_toc; + + stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc); + if (stat) + return stat; + + stat = cdrom_get_toc_entry(drive, ti->cdti_trk1, &last_toc); + if (stat) + return stat; + + if (ti->cdti_trk1 != CDROM_LEADOUT) + ++last_toc; + lba_start = first_toc->addr.lba; + lba_end = last_toc->addr.lba; + + if (lba_end <= lba_start) + return -EINVAL; + + return cdrom_play_audio(drive, lba_start, lba_end); + } + case CDROMREADTOCHDR: { int stat; struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; @@ -2287,7 +2332,7 @@ CDROM_CONFIG_FLAGS (drive)->dvd_r = 1; if (cap.audio_play) CDROM_CONFIG_FLAGS (drive)->audio_play = 1; - if (cap.mechtype == 0) + if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup) CDROM_CONFIG_FLAGS (drive)->close_tray = 0; #if ! STANDARD_ATAPI diff -u --recursive --new-file v2.4.0-test7/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.4.0-test7/linux/drivers/ide/ide.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/ide/ide.c Tue Sep 5 13:08:42 2000 @@ -161,10 +161,6 @@ #include #endif /* CONFIG_KMOD */ -#ifdef CONFIG_BLK_DEV_VIA82CXXX -extern byte fifoconfig; /* defined in via82cxxx.c used by ide_setup() */ -#endif /* CONFIG_BLK_DEV_VIA82CXXX */ - static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR }; static int idebus_parameter = 0; /* holds the "idebus=" parameter */ @@ -2851,21 +2847,6 @@ * currently unknown. * "ide=reverse" : Formerly called to pci sub-system, but now local. * - * "splitfifo=betweenChan" - * : FIFO Configuration of VIA 82c586(,"A"or"B"). - * --see what follows... - * "splitfifo=betweenChan,thresholdprim,thresholdsec" - * : FIFO Configuration of VIA 82c586(,"A" or "B"). - * betweenChan = 1(all FIFO's to primary channel) - * , 2(all FIFO's to secondary channel) - * , 3 or 4(evenly shared between them). - * note: without FIFO, a channel is (u)dma disabled! - * thresholdprim = 4, 3, 2 or 1 - * (standing for 1, 3/4, 1/2, 1/4). - * Sets the threshold of FIFO to begin dma - * transfer on the primary channel. - * thresholdsec = cf upper, but for secondary channel. - * * The following are valid ONLY on ide0, (except dc4030) * and the defaults for the base,ctl ports must not be altered. * @@ -2894,9 +2875,6 @@ if (strncmp(s,"ide",3) && strncmp(s,"idebus",6) && -#ifdef CONFIG_BLK_DEV_VIA82CXXX - strncmp(s,"splitfifo",9) && -#endif /* CONFIG_BLK_DEV_VIA82CXXX */ strncmp(s,"hd",2)) /* hdx= & hdxlun= */ return 0; @@ -3012,58 +2990,6 @@ goto bad_option; } } - -#if defined(CONFIG_BLK_DEV_VIA82CXXX) - /* - * Look for drive option "splitfifo=..." - */ - - if (s[0] == 's' && s[1] == 'p' && s[2] == 'l' && - s[3] == 'i' && s[4] == 't' && s[5] == 'f' && - s[6] == 'i' && s[7] == 'f' && s[8] == 'o') { - byte tmp = 0x3a; /* default config byte */ - - i = match_parm(&s[9], NULL, vals, 3); - switch(i) { - case 3: - tmp &= 0xf0; - if ((vals[1] > 0) && (vals[1] < 5)) { - /* sets threshold for primary Channel: */ - byte x = 4 - vals[1]; - tmp |= (x << 2); - } - else - goto bad_option; - if ((vals[2] > 0) && (vals[2] < 5)) { - /* sets threshold for secondary Channel: */ - byte x = 4 - vals[2]; - tmp |= x; - } - else - goto bad_option; - case 1: - /* set the FIFO config between channels to 0: */ - tmp &= 0x9f; - /* set the needed FIFO config between channels: */ - if (vals[0] == 1) /* primary fifo only */ - tmp |= 0x10; - else if (vals[0] == 2) /* secondary fifo only */ - tmp |= 0x70; - else if (vals[0] == 4) /* other shared fifo config */ - tmp |= 0x50; - else if (vals[0] == 3) /* default config */ - tmp |= 0x30; - else - goto bad_option; - break; - default: - goto bad_option; - } - /* set the found option in fifoconfig */ - fifoconfig = tmp; - goto done; - } -#endif /* defined(CONFIG_BLK_DEV_VIA82CXXX) */ if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e') goto bad_option; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c --- v2.4.0-test7/linux/drivers/ide/sis5513.c Fri Jun 23 21:55:09 2000 +++ linux/drivers/ide/sis5513.c Tue Sep 5 13:48:25 2000 @@ -320,36 +320,18 @@ } config_art_rwp_pio(drive, pio); + drive->current_speed = speed; err = ide_config_drive_speed(drive, speed); return err; } -#define SIS5513_TUNEPROC - -#ifdef SIS5513_TUNEPROC -static void sis5513_tune_drive (ide_drive_t *drive, byte pio) +static int sis5513_tune_chipset (ide_drive_t *drive, byte speed) { - (void) config_chipset_for_pio(drive, pio); -} -#endif /* SIS5513_TUNEPROC */ - -#ifdef CONFIG_BLK_DEV_IDEDMA -/* - * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four)) - */ -static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) -{ - struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte drive_pci, test1, test2, mask; - int err; - - unsigned long dma_base = hwif->dma_base; - byte unit = (drive->select.b.unit & 0x01); - byte speed = 0x00, unmask = 0xE0, four_two = 0x00; - byte udma_66 = eighty_ninty_three(drive); + byte drive_pci, test1, test2; + byte unmask, four_two, mask = 0; if (host_dev) { switch(host_dev->device) { @@ -359,9 +341,15 @@ case PCI_DEVICE_ID_SI_630: unmask = 0xF0; four_two = 0x01; + break; default: + unmask = 0xE0; + four_two = 0x00; break; } + } else { + unmask = 0xE0; + four_two = 0x00; } switch(drive->dn) { @@ -375,61 +363,103 @@ pci_read_config_byte(dev, drive_pci, &test1); pci_read_config_byte(dev, drive_pci|0x01, &test2); - if ((!ultra) && (test2 & 0x80)) { + if ((speed <= XFER_MW_DMA_2) && (test2 & 0x80)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~0x80); pci_read_config_byte(dev, drive_pci|0x01, &test2); + } else { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + } + + switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA + case XFER_UDMA_5: /* can not do ultra mode 5 yet */ + case XFER_UDMA_4: mask = 0x90; break; + case XFER_UDMA_3: mask = 0xA0; break; + case XFER_UDMA_2: mask = (four_two) ? 0xB0 : 0xA0; break; + case XFER_UDMA_1: mask = (four_two) ? 0xD0 : 0xC0; break; + case XFER_UDMA_0: mask = unmask; break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + case XFER_SW_DMA_2: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: break; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4)); + case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3)); + case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2)); + case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1)); + case XFER_PIO_0: + default: return((int) config_chipset_for_pio(drive, 0)); } - if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) { - if (!(test2 & 0x90)) { - pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); - pci_write_config_byte(dev, drive_pci|0x01, test2|0x90); + if (speed > XFER_MW_DMA_2) + pci_write_config_byte(dev, drive_pci|0x01, test2|mask); + + drive->current_speed = speed; + return ((int) ide_config_drive_speed(drive, speed)); +} + +static void sis5513_tune_drive (ide_drive_t *drive, byte pio) +{ + (void) config_chipset_for_pio(drive, pio); +} + +#ifdef CONFIG_BLK_DEV_IDEDMA +/* + * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four)) + */ +static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + + byte four_two = 0, speed = 0; + int err; + + byte unit = (drive->select.b.unit & 0x01); + byte udma_66 = eighty_ninty_three(drive); + + if (host_dev) { + switch(host_dev->device) { + case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_540: + case PCI_DEVICE_ID_SI_620: + case PCI_DEVICE_ID_SI_630: + four_two = 0x01; break; + default: + four_two = 0x00; break; } + } + + if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) { - if (!(test2 & 0xA0)) { - pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); - pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0); - } + else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) speed = XFER_UDMA_3; - } else if ((id->dma_ultra & 0x0004) && (ultra)) { - mask = (four_two) ? 0xB0 : 0xA0; - if (!(test2 & mask)) { - pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); - pci_write_config_byte(dev, drive_pci|0x01, test2|mask); - } + else if ((id->dma_ultra & 0x0004) && (ultra)) speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (ultra)) { - mask = (four_two) ? 0xD0 : 0xC0; - if (!(test2 & mask)) { - pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); - pci_write_config_byte(dev, drive_pci|0x01, test2|mask); - } + else if ((id->dma_ultra & 0x0002) && (ultra)) speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (ultra)) { - if (!(test2 & unmask)) { - pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); - pci_write_config_byte(dev, drive_pci|0x01, test2|unmask); - } + else if ((id->dma_ultra & 0x0001) && (ultra)) speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { + else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { + else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { + else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { + else if (id->dma_1word & 0x0004) speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { + else if (id->dma_1word & 0x0002) speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { + else if (id->dma_1word & 0x0001) speed = XFER_SW_DMA_0; - } else { + else return ((int) ide_dma_off_quietly); - } - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - err = ide_config_drive_speed(drive, speed); + outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); + + err = sis5513_tune_chipset(drive, speed); #if SIS5513_DEBUG_DRIVE_INFO printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); @@ -575,9 +605,8 @@ hwif->irq = hwif->channel ? 15 : 14; -#ifdef SIS5513_TUNEPROC hwif->tuneproc = &sis5513_tune_drive; -#endif /* SIS5513_TUNEPROC */ + hwif->speedproc = &sis5513_tune_chipset; if (!(hwif->dma_base)) return; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c --- v2.4.0-test7/linux/drivers/ide/via82cxxx.c Fri Jun 23 21:55:09 2000 +++ linux/drivers/ide/via82cxxx.c Wed Sep 6 08:07:56 2000 @@ -1,80 +1,54 @@ /* - * linux/drivers/ide/via82cxxx.c Version 0.10 June 9, 2000 + * $Id: via82cxxx.c,v 2.1 2000/08/29 01:34:60 vojtech Exp $ * - * Copyright (C) 1998-99 Michel Aubry, Maintainer - * Copyright (C) 1999 Jeff Garzik, MVP4 Support - * (jgarzik@mandrakesoft.com) - * Copyright (C) 1998-2000 Andre Hedrick - * May be copied or modified under the terms of the GNU General Public License - * - * The VIA MVP-4 is reported OK with UDMA. - * The VIA MVP-3 is reported OK with UDMA. - * The TX Pro III is also reported OK with UDMA. - * - * VIA chips also have a single FIFO, with the same 64 bytes deep - * buffer (16 levels of 4 bytes each). - * - * However, VIA chips can have the buffer split either 8:8 levels, - * 16:0 levels or 0:16 levels between both channels. One could think - * of using this feature, as even if no level of FIFO is given to a - * given channel, one can for instance always reach ATAPI drives through - * it, or, if one channel is unused, configuration defaults to - * an even split FIFO levels. - * - * This feature is available only through a kernel command line : - * "splitfifo=Chan,Thr0,Thr1" or "splitfifo=Chan". - * where: Chan =1,2,3 or 4 and Thrx = 1,2,3,or 4. - * - * If Chan == 1: - * gives all the fifo to channel 0, - * sets its threshold to Thr0/4, - * and disables any dma access to channel 1. - * - * If chan == 2: - * gives all the fifo to channel 1, - * sets its threshold to Thr1/4, - * and disables any dma access to channel 0. - * - * If chan == 3 or 4: - * shares evenly fifo between channels, - * gives channel 0 a threshold of Thr0/4, - * and channel 1 a threshold of Thr1/4. - * - * Note that by default (if no command line is provided) and if a channel - * has been disabled in Bios, all the fifo is given to the active channel, - * and its threshold is set to 3/4. - * - * VT82c586B - * - * Offset 4B-48 - Drive Timing Control - * | pio0 | pio1 | pio2 | pio3 | pio4 - * 25.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20 - * 33.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20 - * 37.5 MHz | 0xA9 | 0x76 | 0x76 | 0x32 | 0x21 - * - * Offset 53-50 - UltraDMA Extended Timing Control - * UDMA | NO | 0 | 1 | 2 - * | 0x03 | 0x62 | 0x61 | 0x60 - * - * VT82c596B & VT82c686A - * - * Offset 4B-48 - Drive Timing Control - * | pio0 | pio1 | pio2 | pio3 | pio4 - * 25.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20 - * 33.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20 - * 37.5 MHz | 0xDB | 0x87 | 0x87 | 0x42 | 0x31 - * 41.5 MHz | 0xFE | 0xA8 | 0xA8 | 0x53 | 0x32 - * - * Offset 53-50 - UltraDMA Extended Timing Control - * UDMA | NO | 0 | 1 | 2 - * 33.0 MHz | 0x03 | 0xE2 | 0xE1 | 0xE0 - * 37.5 MHz | 0x03 | 0xE2 | 0xE2 | 0xE1 (1) - * - * Offset 53-50 - UltraDMA Extended Timing Control - * UDMA | NO | 0 | 1 | 2 | 3 | 4 - * 33.0 MHz | (2) | 0xE6 | 0xE4 | 0xE2 | 0xE1 | 0xE0 - * 37.5 MHz | (2) | 0xE6 | 0xE6 | 0xE4 | 0xE2 | 0xE1 (1) + * Copyright (c) 2000 Vojtech Pavlik * + * Based on the work of: + * Michel Aubry + * Jeff Garzik + * Andre Hedrick + * + * Sponsored by SuSE + */ + +/* + * VIA vt82c586 IDE driver for Linux. Supports + * + * vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, vt82c686a, vt8231 + * + * southbridges, which can be found in + * + * VIA Apollo VP, VPX, VPX/97, VP2, VP2/97, VP3, MVP3, MVP4 + * VIA Apollo Pro, Pro Plus, Pro 133, Pro 133A, ProMedia 601, ProSavage 605 + * VIA Apollo KX133, KT133 + * AMD-640, AMD-750 IronGate + * + * chipsets. Supports PIO 0-5, MWDMA 0-2, SWDMA 0-2 and + * UDMA 0-5 (includes UDMA33, 66 and 100) modes. UDMA100 isn't possible + * on any of the supported chipsets yet. + * + * UDMA66 and higher modes are autodetected only in case the BIOS has enabled them. + * To force UDMA66, use 'ide0=ata66' or 'ide1=ata66' on the kernel command line. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ #include @@ -90,712 +64,374 @@ #include #include #include - #include #include "ide_modes.h" -static struct pci_dev *host_dev = NULL; -static struct pci_dev *isa_dev = NULL; - -struct chipset_bus_clock_list_entry { - byte xfer_speed; - - byte ultra_settings_25; - byte chipset_settings_25; - byte ultra_settings_33; - byte chipset_settings_33; - byte ultra_settings_37; - byte chipset_settings_37; - byte ultra_settings_41; - byte chipset_settings_41; -}; +#define VIA_BM_BASE 0x20 +#define VIA_IDE_ENABLE 0x40 +#define VIA_IDE_CONFIG 0x41 +#define VIA_FIFO_CONFIG 0x43 +#define VIA_MISC_1 0x44 +#define VIA_MISC_2 0x45 +#define VIA_MISC_3 0x46 +#define VIA_DRIVE_TIMING 0x48 +#define VIA_ADDRESS_SETUP 0x4c +#define VIA_UDMA_TIMING 0x50 +#define VIA_PRI_SECTOR_SIZE 0x60 +#define VIA_SEC_SECTOR_SIZE 0x68 -static struct chipset_bus_clock_list_entry * via82cxxx_table = NULL; +/* + * VIA SouthBridge chips. + */ -static struct chipset_bus_clock_list_entry via82cxxx_type_one [] = { - /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ -#ifdef CONFIG_BLK_DEV_IDEDMA - { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { XFER_UDMA_2, 0x60, 0x20, 0x60, 0x20, 0x60, 0x21, 0x00, 0x00 }, - { XFER_UDMA_1, 0x61, 0x20, 0x61, 0x20, 0x61, 0x21, 0x00, 0x00 }, - { XFER_UDMA_0, 0x62, 0x20, 0x62, 0x20, 0x62, 0x21, 0x00, 0x00 }, - - { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x21, 0x00, 0x00 }, - { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, - { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, -#endif /* CONFIG_BLK_DEV_IDEDMA */ - { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x21, 0x00, 0x00 }, - { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, - { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x76, 0x00, 0x00 }, - { XFER_PIO_1, 0x03, 0x65, 0x03, 0x65, 0x03, 0x76, 0x00, 0x00 }, - { XFER_PIO_0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xA9, 0x00, 0x00 }, - { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xA9, 0x00, 0x00 } +static const struct { + char *name; + unsigned short id; + unsigned char speed; +} via_isa_bridges[] = { + { "vt8231", PCI_DEVICE_ID_VIA_8231, XFER_UDMA_4 }, + { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, XFER_UDMA_4 }, + { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, XFER_UDMA_4 }, + { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, XFER_UDMA_2 }, + { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, XFER_UDMA_2 }, + { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, XFER_UDMA_2 }, + { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, XFER_MW_DMA_2 }, + { "Unknown SouthBridge", 0, XFER_UDMA_4 }, + { "Unknown SouthBridge", 0, XFER_UDMA_2 }, }; -static struct chipset_bus_clock_list_entry via82cxxx_type_two [] = { - /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ -#ifdef CONFIG_BLK_DEV_IDEDMA - { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { XFER_UDMA_2, 0xE0, 0x20, 0xE0, 0x20, 0xE1, 0x31, 0xE1, 0x32 }, - { XFER_UDMA_1, 0xE1, 0x20, 0xE1, 0x20, 0xE2, 0x31, 0xE2, 0x32 }, - { XFER_UDMA_0, 0xE2, 0x20, 0xE2, 0x20, 0xE2, 0x31, 0xE2, 0x32 }, - - { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, - { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, - { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, -#endif /* CONFIG_BLK_DEV_IDEDMA */ - { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, - { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, - { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, - { XFER_PIO_1, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, - { XFER_PIO_0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE }, - { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE } -}; +static unsigned char via_config; +static unsigned char via_enabled; +static unsigned int via_ata66; -static struct chipset_bus_clock_list_entry via82cxxx_type_three [] = { - /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ -#ifdef CONFIG_BLK_DEV_IDEDMA - { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { XFER_UDMA_2, 0xE0, 0x20, 0xE0, 0x20, 0xE1, 0x31, 0xE1, 0x32 }, - { XFER_UDMA_1, 0xE1, 0x20, 0xE1, 0x20, 0xE2, 0x31, 0xE2, 0x32 }, - { XFER_UDMA_0, 0xE2, 0x20, 0xE2, 0x20, 0xE2, 0x31, 0xE2, 0x32 }, - - { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, - { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, - { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, -#endif /* CONFIG_BLK_DEV_IDEDMA */ - { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, - { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, - { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, - { XFER_PIO_1, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, - { XFER_PIO_0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE }, - { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE } -}; +/* + * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds). + * These were taken from ATA/ATAPI-6 standard, rev 0a, except + * for PIO 5, which is a nonstandard extension. + * + * Dilemma: 8-bit (register) PIO accesses need more relaxed timing. + * Hopefully the chipset is taking care of that. If it doesn't + * do so, define VIA_USE_8_BIT_TIMING to see if it helps. + */ -static struct chipset_bus_clock_list_entry via82cxxx_type_four [] = { - /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ -#ifdef CONFIG_BLK_DEV_IDEDMA - { XFER_UDMA_4, 0x00, 0x00, 0xE0, 0x20, 0xE1, 0x31, 0x00, 0x00 }, - { XFER_UDMA_3, 0x00, 0x00, 0xE1, 0x20, 0xE2, 0x31, 0x00, 0x00 }, - { XFER_UDMA_2, 0x00, 0x00, 0xE2, 0x20, 0xE4, 0x31, 0x00, 0x00 }, - { XFER_UDMA_1, 0x00, 0x00, 0xE4, 0x20, 0xE6, 0x31, 0x00, 0x00 }, - { XFER_UDMA_0, 0x00, 0x00, 0xE6, 0x20, 0xE6, 0x31, 0x00, 0x00 }, - - { XFER_MW_DMA_2, 0x00, 0x00, 0x03, 0x20, 0x03, 0x31, 0x00, 0x00 }, - { XFER_MW_DMA_1, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, - { XFER_MW_DMA_0, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, -#endif /* CONFIG_BLK_DEV_IDEDMA */ - { XFER_PIO_4, 0x00, 0x00, 0x03, 0x20, 0x03, 0x31, 0x00, 0x00 }, - { XFER_PIO_3, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, - { XFER_PIO_2, 0x00, 0x00, 0x03, 0x65, 0x03, 0x87, 0x00, 0x00 }, - { XFER_PIO_1, 0x00, 0x00, 0x03, 0x65, 0x03, 0x87, 0x00, 0x00 }, - { XFER_PIO_0, 0x00, 0x00, 0x03, 0xA8, 0x03, 0xDB, 0x00, 0x00 }, - { 0, 0x00, 0x00, 0x03, 0xA8, 0x03, 0xDB, 0x00, 0x00 } -}; +#ifndef XFER_PIO_5 +#define XFER_PIO_5 0x0d +#endif static const struct { - const char *name; - unsigned short vendor_id; - unsigned short host_id; -} ApolloHostChipInfo[] = { - { "VT 82C585 Apollo VP1/VPX", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C585, }, - { "VT 82C595 Apollo VP2", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C595, }, - { "VT 82C597 Apollo VP3", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, }, - { "VT 82C598 Apollo MVP3", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_0, }, - { "VT 82C598 Apollo MVP3", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_0, }, - { "VT 82C680 Apollo P6", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C680, }, - { "VT 82C691 Apollo Pro", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C691, }, - { "VT 82C693 Apollo Pro Plus", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C693, }, - { "Apollo MVP4", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8501_0, }, - { "VT 8371", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_0, }, - { "VT 8601", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, }, - { "AMD IronGate", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_7006, }, -}; + int mode; + char *name; + short setup; /* t1 */ + short active; /* t2 or tD */ + short recover; /* t2i or tK */ + short cycle; /* t0 */ + short udma; /* t2CYCTYP/2 */ +} via_timing[] = { + { XFER_UDMA_5, "UDMA5", 25, 70, 25, 120, 20 }, + { XFER_UDMA_4, "UDMA4", 25, 70, 25, 120, 30 }, + { XFER_UDMA_3, "UDMA3", 25, 70, 25, 120, 45 }, + + { XFER_UDMA_2, "UDMA2", 25, 70, 25, 120, 60 }, + { XFER_UDMA_1, "UDMA1", 25, 70, 25, 120, 80 }, + { XFER_UDMA_0, "UDMA0", 25, 70, 25, 120, 120 }, + + { XFER_MW_DMA_2, "MDMA2", 25, 70, 25, 120, 0 }, + { XFER_MW_DMA_1, "MDMA1", 45, 80, 50, 150, 0 }, + { XFER_MW_DMA_0, "MDMA0", 60, 215, 215, 480, 0 }, + + { XFER_SW_DMA_0, "SDMA0", 60, 120, 120, 240, 0 }, + { XFER_SW_DMA_0, "SDMA0", 90, 240, 240, 480, 0 }, + { XFER_SW_DMA_0, "SDMA0",120, 480, 480, 960, 0 }, + + { XFER_PIO_5, "PIO5", 20, 50, 30, 100, 0 }, + { XFER_PIO_4, "PIO4", 25, 70, 25, 120, 0 }, + { XFER_PIO_3, "PIO3", 30, 80, 70, 180, 0 }, + +#ifdef VIA_USE_8_BIT_TIMING + { XFER_PIO_2, "PIO2", 30, 290, 60, 330, 0 }, + { XFER_PIO_1, "PIO1", 50, 290, 100, 383, 0 }, + { XFER_PIO_0, "PIO0", 70, 290, 300, 600, 0 }, +#else + { XFER_PIO_2, "PIO2", 30, 100, 90, 240, 0 }, + { XFER_PIO_1, "PIO1", 50, 125, 100, 383, 0 }, + { XFER_PIO_0, "PIO0", 70, 165, 150, 600, 0 }, +#endif -#define NUM_APOLLO_ISA_CHIP_DEVICES 2 -#define VIA_FLAG_NULL 0x00000000 -#define VIA_FLAG_CHECK_REV 0x00000001 -#define VIA_FLAG_ATA_66 0x00000002 - -static const struct { - unsigned short host_id; - unsigned short isa_id; - unsigned int flags; - struct chipset_bus_clock_list_entry * chipset_table; -} ApolloISAChipInfo[] = { - { PCI_DEVICE_ID_VIA_82C585, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, - { PCI_DEVICE_ID_VIA_82C595, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, - { PCI_DEVICE_ID_VIA_82C597_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, - { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, - { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C596, VIA_FLAG_NULL, via82cxxx_type_one }, - { PCI_DEVICE_ID_VIA_82C680, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, - { PCI_DEVICE_ID_VIA_82C691, PCI_DEVICE_ID_VIA_82C596, VIA_FLAG_ATA_66, via82cxxx_type_two }, - { PCI_DEVICE_ID_VIA_82C693, PCI_DEVICE_ID_VIA_82C596, VIA_FLAG_NULL, via82cxxx_type_one }, - { PCI_DEVICE_ID_VIA_8501_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66, via82cxxx_type_two }, - { PCI_DEVICE_ID_VIA_8371_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66, via82cxxx_type_two }, - { PCI_DEVICE_ID_VIA_8601_0, PCI_DEVICE_ID_VIA_8231, VIA_FLAG_ATA_66, via82cxxx_type_two }, - { PCI_DEVICE_ID_AMD_FE_GATE_7006, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66, via82cxxx_type_two }, + { XFER_PIO_SLOW, "SLOW", 120, 290, 240, 960, 0 }, + { 0 } }; -#define arraysize(x) (sizeof(x)/sizeof(*(x))) +/* + * VIA /proc entry. + */ -#define DISPLAY_VIA_TIMINGS +#ifdef CONFIG_PROC_FS -#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) #include #include -static char *FIFO_str[] = { - " 1 ", - "3/4", - "1/2", - "1/4" -}; +int via_proc = 0; +static struct pci_dev *bmide_dev, *isa_dev; +extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -static char *control3_str[] = { - "No limitation", - "64", - "128", - "192" -}; +static char *via_fifo[] = { " 1 ", "3/4", "1/2", "1/4" }; +static char *via_control3[] = { "No limit", "64", "128", "192" }; -static int via_get_info(char *, char **, off_t, int); -extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -static struct pci_dev *bmide_dev; +#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg) +#define via_print_drive(name, format, arg...)\ + p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n"); + +static int via_get_info(char *buffer, char **addr, off_t offset, int count) +{ + short pci_clock, speed[4], cycle[4], setup[4], active[4], recover[4], umul[4], uen[4], udma[4]; + struct pci_dev *dev = bmide_dev; + unsigned int v, u, i, base; + unsigned short c, size0, size1; + unsigned char t, c0, c1; + char *p = buffer; -static char * print_apollo_drive_config (char *buf, struct pci_dev *dev) -{ - int rc; - unsigned int time; - byte tm; - char *p = buf; - - /* Drive Timing Control */ - rc = pci_read_config_dword(dev, 0x48, &time); - p += sprintf(p, "Act Pls Width: %02d %02d %02d %02d\n", - ((time & 0xf0000000)>>28) + 1, - ((time & 0xf00000)>>20) + 1, - ((time & 0xf000)>>12) + 1, - ((time & 0xf0)>>4) + 1 ); - p += sprintf(p, "Recovery Time: %02d %02d %02d %02d\n", - ((time & 0x0f000000)>>24) + 1, - ((time & 0x0f0000)>>16) + 1, - ((time & 0x0f00)>>8) + 1, - (time & 0x0f) + 1 ); - - /* Address Setup Time */ - rc = pci_read_config_byte(dev, 0x4C, &tm); - p += sprintf(p, "Add. Setup T.: %01dT %01dT %01dT %01dT\n", - ((tm & 0xc0)>>6) + 1, - ((tm & 0x30)>>4) + 1, - ((tm & 0x0c)>>2) + 1, - (tm & 0x03) + 1 ); - - /* UltraDMA33 Extended Timing Control */ - rc = pci_read_config_dword(dev, 0x50, &time); - p += sprintf(p, "------------------UDMA-Timing-Control------------------------\n"); - p += sprintf(p, "Enable Meth.: %01d %01d %01d %01d\n", - (time & 0x80000000) ? 1 : 0, - (time & 0x800000) ? 1 : 0, - (time & 0x8000) ? 1 : 0, - (time & 0x80) ? 1 : 0 ); - p += sprintf(p, "Enable: %s %s %s %s\n", - (time & 0x40000000) ? "yes" : "no ", - (time & 0x400000) ? "yes" : "no ", - (time & 0x4000) ? "yes" : "no ", - (time & 0x40) ? "yes" : "no " ); - p += sprintf(p, "Transfer Mode: %s %s %s %s\n", - (time & 0x20000000) ? "PIO" : "DMA", - (time & 0x200000) ? "PIO" : "DMA", - (time & 0x2000) ? "PIO" : "DMA", - (time & 0x20) ? "PIO" : "DMA" ); - p += sprintf(p, "Cycle Time: %01dT %01dT %01dT %01dT\n", - ((time & 0x03000000)>>24) + 2, - ((time & 0x030000)>>16) + 2, - ((time & 0x0300)>>8) + 2, - (time & 0x03) + 2 ); - - return (char *)p; -} + via_print("----------VIA BusMastering IDE Configuration----------------"); -static char * print_apollo_ide_config (char *buf, struct pci_dev *dev) -{ - byte time, tmp; - unsigned short size0, size1; - int rc; - char *p = buf; - - rc = pci_read_config_byte(dev, 0x41, &time); - p += sprintf(p, "Prefetch Buffer : %s %s\n", - (time & 128) ? "on " : "off", - (time & 32) ? "on " : "off" ); - p += sprintf(p, "Post Write Buffer: %s %s\n", - (time & 64) ? "on " : "off", - (time & 16) ? "on " : "off" ); - - /* FIFO configuration */ - rc = pci_read_config_byte(dev, 0x43, &time); - tmp = ((time & 0x20)>>2) + ((time & 0x40)>>3); - p += sprintf(p, "FIFO Conf/Chan. : %02d %02d\n", - 16 - tmp, tmp); - tmp = (time & 0x0F)>>2; - p += sprintf(p, "Threshold Prim. : %s %s\n", - FIFO_str[tmp], - FIFO_str[time & 0x03] ); - - /* chipset Control3 */ - rc = pci_read_config_byte(dev, 0x46, &time); - p += sprintf(p, "Read DMA FIFO flush: %s %s\n", - (time & 0x80) ? "on " : "off", - (time & 0x40) ? "on " : "off" ); - p += sprintf(p, "End Sect. FIFO flush: %s %s\n", - (time & 0x20) ? "on " : "off", - (time & 0x10) ? "on " : "off" ); - p += sprintf(p, "Max DRDY Pulse Width: %s %s\n", - control3_str[(time & 0x03)], - (time & 0x03) ? "PCI clocks" : "" ); - - /* Primary and Secondary sector sizes */ - rc = pci_read_config_word(dev, 0x60, &size0); - rc = pci_read_config_word(dev, 0x68, &size1); - p += sprintf(p, "Bytes Per Sector: %03d %03d\n", - size0 & 0xfff, - size1 & 0xfff ); + via_print("Driver Version: 2.1"); - return (char *)p; -} + pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t); + via_print("South Bridge: VIA %s rev %#x", via_isa_bridges[via_config].name, t); -static char * print_apollo_chipset_control1 (char *buf, struct pci_dev *dev) -{ - byte t; - int rc; - char *p = buf; - unsigned short c; - byte l, l_max; - - rc = pci_read_config_word(dev, 0x04, &c); - rc = pci_read_config_byte(dev, 0x44, &t); - rc = pci_read_config_byte(dev, 0x0d, &l); - rc = pci_read_config_byte(dev, 0x3f, &l_max); - - p += sprintf(p, "Command register = 0x%x\n", c); - p += sprintf(p, "Master Read Cycle IRDY %d Wait State\n", - (t & 64) >>6 ); - p += sprintf(p, "Master Write Cycle IRDY %d Wait State\n", - (t & 32) >> 5 ); - p += sprintf(p, "FIFO Output Data 1/2 Clock Advance: %s\n", - (t & 16) ? "on " : "off" ); - p += sprintf(p, "Bus Master IDE Status Register Read Retry: %s\n", - (t & 8) ? "on " : "off" ); - p += sprintf(p, "Latency timer = %d (max. = %d)\n", - l, l_max); + pci_read_config_word(dev, PCI_COMMAND, &c); + via_print("Command register: %#x", c); - return (char *)p; -} - -static char * print_apollo_chipset_control2 (char *buf, struct pci_dev *dev) -{ - byte t; - int rc; - char *p = buf; - rc = pci_read_config_byte(dev, 0x45, &t); - p += sprintf(p, "Interrupt Steering Swap: %s\n", - (t & 64) ? "on ":"off" ); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &t); + via_print("Latency timer: %d", t); - return (char *)p; -} - -static char * print_apollo_chipset_control3 (char *buf, struct pci_dev *dev, - unsigned short n) -{ - /* - * at that point we can be sure that register 0x20 of the - * chipset contains the right address... - */ - unsigned int bibma; - int rc; - byte c0, c1; - char *p = buf; - - rc = pci_read_config_dword(dev, 0x20, &bibma); - bibma = (bibma & 0xfff0) ; - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb((unsigned short)bibma + 0x02); - c1 = inb((unsigned short)bibma + 0x0a); - - if (n == 0) { - /*p = sprintf(p,"--------------------Primary IDE------------Secondary IDE-----");*/ - p += sprintf(p, "both channels togth: %s %s\n", - (c0&0x80) ? "no" : "yes", - (c1&0x80) ? "no" : "yes" ); - } else { - /*p = sprintf(p,"--------------drive0------drive1-------drive0------drive1----");*/ - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (c0&0x20) ? "yes" : "no ", - (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", - (c1&0x40) ? "yes" : "no " ); - } - - return (char *)p; -} + pci_clock = system_bus_clock(); + via_print("PCI clock: %dMHz", pci_clock); -static int via_get_info (char *buffer, char **addr, off_t offset, int count) -{ - /* - * print what /proc/via displays, - * if required from DISPLAY_APOLLO_TIMINGS - */ - char *p = buffer; - /* Parameter of chipset : */ + pci_read_config_byte(dev, VIA_MISC_1, &t); + via_print("Master Read Cycle IRDY: %dws", (t & 64) >>6 ); + via_print("Master Write Cycle IRDY: %dws", (t & 32) >> 5 ); + via_print("FIFO Output Data 1/2 Clock Advance: %s", (t & 16) ? "on" : "off" ); + via_print("BM IDE Status Register Read Retry: %s", (t & 8) ? "on" : "off" ); - /* Miscellaneous control 1 */ - p = print_apollo_chipset_control1(buffer, bmide_dev); + pci_read_config_byte(dev, VIA_MISC_2, &t); + sprintf(p, "Interrupt Steering Swap: %s", (t & 64) ? "on" : "off"); - /* Miscellaneous control 2 */ - p = print_apollo_chipset_control2(p, bmide_dev); - /* Parameters of drives: */ - - /* Header */ - p += sprintf(p, "------------------Primary IDE------------Secondary IDE-----\n"); - p = print_apollo_chipset_control3(p, bmide_dev, 0); - p = print_apollo_ide_config(p, bmide_dev); - p += sprintf(p, "--------------drive0------drive1-------drive0------drive1----\n"); - p = print_apollo_chipset_control3(p, bmide_dev, 1); - p = print_apollo_drive_config(p, bmide_dev); - - return p-buffer; /* hoping it is less than 4K... */ -} + pci_read_config_byte(dev, VIA_MISC_3, &t); + via_print("Max DRDY Pulse Width: %s%s", via_control3[(t & 0x03)], (t & 0x03) ? "PCI clocks" : ""); -#endif /* defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) */ + via_print("-----------------------Primary IDE-------Secondary IDE------"); + via_print("Read DMA FIFO flush: %10s%20s", (t & 0x80) ? "on" : "off", (t & 0x40) ? "on" : "off" ); + via_print("End Sect. FIFO flush: %10s%20s", (t & 0x20) ? "on" : "off", (t & 0x10) ? "on" : "off" ); -/* - * Used to set Fifo configuration via kernel command line: - */ + pci_read_config_byte(dev, VIA_IDE_CONFIG, &t); + via_print("Prefetch Buffer: %10s%20s", (t & 0x80) ? "on" : "off", (t & 0x20) ? "on" : "off" ); + via_print("Post Write Buffer: %10s%20s", (t & 0x40) ? "on" : "off", (t & 0x10) ? "on" : "off" ); -byte via_proc = 0; -byte fifoconfig = 0; -static byte newfifo = 0; + pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t); + via_print("FIFO size: %10d%20d", 16 - (((t >> 5) & 1) + ((t >> 6) & 1)) * 8, + (((t >> 5) & 1) + ((t >> 6) & 1)) * 8); + via_print("Threshold Prim.: %10s%20s", via_fifo[(t >> 2) & 3], via_fifo[t & 3]); -/* Used to just intialize once Fifo configuration */ -static short int done = 0; + pci_read_config_word(dev, VIA_PRI_SECTOR_SIZE, &size0); + pci_read_config_word(dev, VIA_SEC_SECTOR_SIZE, &size1); + via_print("Bytes Per Sector: %10d%20d", size0 & 0xfff, size1 & 0xfff); -/* - * Set VIA Chipset Timings for (U)DMA modes enabled. - * - * VIA Apollo chipset has complete support for - * setting up the timing parameters. - */ -static void set_via_timings (ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - byte post = hwif->channel ? 0x30 : 0xc0; - byte flush = hwif->channel ? 0x50 : 0xa0; - int mask = hwif->channel ? ((newfifo & 0x60) ? 0 : 1) : - (((newfifo & 0x60) == 0x60) ? 1 : 0); - byte via_config = 0; - int rc = 0, errors = 0; + pci_read_config_dword(dev, VIA_BM_BASE, &base); + base = (base & 0xfff0) ; - printk("%s: VIA Bus-Master ", hwif->name); + c0 = inb((unsigned short)base + 0x02); + c1 = inb((unsigned short)base + 0x0a); - /* - * setting IDE read prefetch buffer and IDE post write buffer. - * (This feature allows prefetched reads and post writes). - */ - if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) - errors++; + via_print("Both channels togth: %10s%20s", (c0 & 0x80) ? "no" : "yes", (c1 & 0x80) ? "no" : "yes" ); - if (mask) { - if ((rc = pci_write_config_byte(dev, 0x41, via_config & ~post))) - errors++; - } else { - if ((rc = pci_write_config_byte(dev, 0x41, via_config | post))) - errors++; - } + via_print("-------------------drive0----drive1----drive2----drive3-----"); - /* - * setting Channel read and End-of-sector FIFO flush. - * (This feature ensures that FIFO flush is enabled: - * - for read DMA when interrupt asserts the given channel. - * - at the end of each sector for the given channel.) - */ - if ((rc = pci_read_config_byte(dev, 0x46, &via_config))) - errors++; - - if (mask) { - if ((rc = pci_write_config_byte(dev, 0x46, via_config & ~flush))) - errors++; - } else { - if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush))) - errors++; - } + via_print("BMDMA enabled: %10s%10s%10s%10s", (c0 & 0x20) ? "yes" : "no", (c0 & 0x40) ? "yes" : "no", + (c1 & 0x20) ? "yes" : "no", (c1 & 0x40) ? "yes" : "no" ); - if (!hwif->dma_base) - printk("Config %s. No DMA Enabled\n", - errors ? "ERROR":"Success"); - else - printk("(U)DMA Timing Config %s\n", - errors ? "ERROR" : "Success"); -} + pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t); + pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v); + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); -/* - * Sets VIA 82cxxx FIFO configuration: - * This chipsets gets a splitable fifo. This can be driven either by command - * line option (eg "splitfifo=2,2,3" which asks this driver to switch all the - * 16 fifo levels to the second drive, and give it a threshold of 3 for (u)dma - * triggering. - */ - -static int via_set_fifoconfig(ide_hwif_t *hwif) -{ - byte fifo; - unsigned int timings; - struct pci_dev *dev = hwif->pci_dev; - - /* read port configuration */ - if (pci_read_config_dword(dev, 0x40, &timings)) - return 1; - - /* first read actual fifo config: */ - if (pci_read_config_byte(dev, 0x43, &fifo)) - return 1; - - /* keep 4 and 7 bit as they seem to differ between chipsets flavors... */ - newfifo = fifo & 0x90; - - if (fifoconfig) { - /* we received a config request from kernel command line: */ - newfifo |= fifoconfig & 0x6f; - } else { - /* If ever just one channel is unused, allocate all fifo levels to it - * and give it a 3/4 threshold for (u)dma transfers. - * Otherwise, share it evenly between channels: - */ - if ((timings & 3) == 2) { - /* only primary channel is enabled - * 16 buf. to prim. chan. thresh=3/4 - */ - newfifo |= 0x06; - } else if ((timings & 3) == 1) { - /* only secondary channel is enabled! - * 16 buffers to sec. ch. thresh=3/4 - */ - newfifo |= 0x69; - } else { - /* fifo evenly distributed: */ - newfifo |= 0x2a; - } + for (i = 0; i < 4; i++) { + setup[i] = ((t >> ((3 - i) << 1) ) & 0x3) + 1; + active[i] = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1; + recover[i] = ((v >> ((3 - i) << 3) ) & 0xf) + 1; + udma[i] = ((u >> ((3 - i) << 3) ) & 0x7) + 2; + umul[i] = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 2 : 1; + uen[i] = ((u >> ((3 - i) << 3)) & 0x20) ? 1 : 0; + speed[i] = uen[i] ? 20 * pci_clock * umul[i] / udma[i] : + 20 * pci_clock / (active[i] + recover[i]); + cycle[i] = uen[i] ? 1000 / (pci_clock * umul[i]) * udma[i] : + 1000 / pci_clock * (active[i] + recover[i]); } - /* write resulting configuration to chipset: */ - if (pci_write_config_byte(dev, 0x43, newfifo)) - return 1; - - /* and then reread it to get the actual one */ - if (pci_read_config_byte(dev, 0x43, &newfifo)) - return 1; - - /* print a kernel report: */ - printk("Split FIFO Configuration: %s Primary buffers, threshold = %s\n", - ((newfifo & 0x60) == 0x60) ? " 0" : - ((newfifo & 0x60) ? " 8" : "16"), - !(newfifo & 0x0c) ? "1" : - (!(newfifo & 0x08) ? "3/4" : - (newfifo & 0x04) ? "1/4" : "1/2")); - - printk(" %s Second. buffers, threshold = %s\n", - ((newfifo & 0x60) == 0x60) ? "16" : - ((newfifo & 0x60) ? " 8" : " 0"), - !(newfifo & 0x03) ? "1" : - (!(newfifo & 0x02) ? "3/4" : - (newfifo & 0x01) ? "1/4" : "1/2")); - return 0; -} + via_print_drive("Transfer Mode: ", "%10s", uen[i] ? "UDMA" : "DMA/PIO"); + via_print_drive("Address Setup: ", "%8dns", (1000 / pci_clock) * setup[i]); + via_print_drive("Active Pulse: ", "%8dns", (1000 / pci_clock) * active[i]); + via_print_drive("Recovery Time: ", "%8dns", (1000 / pci_clock) * recover[i]); + via_print_drive("Cycle Time: ", "%8dns", cycle[i]); + via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 10, speed[i] % 10); -#ifdef CONFIG_VIA82CXXX_TUNING -static byte pci_bus_clock_list (byte speed, int ide_clock, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) { - switch(ide_clock) { - case 25: return chipset_table->chipset_settings_25; - case 33: return chipset_table->chipset_settings_33; - case 37: return chipset_table->chipset_settings_37; - case 41: return chipset_table->chipset_settings_41; - default: break; - } - } - return 0x00; + return p - buffer; /* hoping it is less than 4K... */ } -static byte pci_bus_clock_list_ultra (byte speed, int ide_clock, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) { - switch(ide_clock) { - case 25: return chipset_table->ultra_settings_25; - case 33: return chipset_table->ultra_settings_33; - case 37: return chipset_table->ultra_settings_37; - case 41: return chipset_table->ultra_settings_41; - default: break; - } - } - return 0x00; -} +#endif + +#define FIT(v,min,max) ((v)>(max)?(max):((v)<(min)?(min):(v))) +#define ENOUGH(v,un) (((v)-1)/(un)+1) + +#ifdef DEBUG +#define via_write_config_byte(dev,number,value) do {\ + printk(KERN_DEBUG "VP_IDE: Setting register %#x to %#x\n", number, value);\ + pci_write_config_byte(dev,number,value); } while (0) +#else +#define via_write_config_byte pci_write_config_byte +#endif -static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed) +static int via_set_speed(ide_drive_t *drive, byte speed) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - struct chipset_bus_clock_list_entry * temp_table = NULL; - - byte unit = (drive->select.b.unit & 0x01) ? 1 : 0; - byte ata2_pci = 0x00; - byte ata3_pci = 0x00; - byte timing = 0x00; - byte ultra = 0x00; - int err; - - int bus_speed = system_bus_clock(); - - if (via82cxxx_table == NULL) - return -1; - - switch(drive->dn) { - case 0: ata2_pci = 0x4b; ata3_pci = 0x53; break; - case 1: ata2_pci = 0x4a; ata3_pci = 0x52; break; - case 2: ata2_pci = 0x49; ata3_pci = 0x51; break; - case 3: ata2_pci = 0x48; ata3_pci = 0x50; break; - default: - return -1; - } + struct pci_dev *dev = HWIF(drive)->pci_dev; + int i, T, err = 0; + unsigned char t, setup, active, recover, cycle; + + if (drive->dn > 3) return -1; + + T = 1000 / system_bus_clock(); + + if (speed > via_isa_bridges[via_config].speed) + speed = via_isa_bridges[via_config].speed; + + for (i = 0; via_timing[i].mode && via_timing[i].mode != speed; i++); - if ((via82cxxx_table == via82cxxx_type_four) && - (!(hwif->udma_four)) && - (speed <= XFER_UDMA_2)) { - temp_table = via82cxxx_type_three; - } else { - temp_table = via82cxxx_table; +#ifdef DEBUG + printk(KERN_DEBUG "VP_IDE: Setting drive %d to %s\n", drive->dn, via_timing[i].name); +#endif + + setup = ENOUGH(via_timing[i].setup, T); + active = ENOUGH(via_timing[i].active, T); + recover = ENOUGH(via_timing[i].recover, T); + cycle = ENOUGH(via_timing[i].cycle, T); + + if (active + recover < cycle) { + active += (cycle - (active + recover)) / 2; + recover = cycle - active; } - pci_read_config_byte(dev, ata2_pci, &timing); - timing = pci_bus_clock_list(speed, bus_speed, temp_table); - pci_write_config_byte(dev, ata2_pci, timing); - - pci_read_config_byte(dev, ata3_pci, &ultra); - ultra = pci_bus_clock_list_ultra(speed, bus_speed, temp_table); - if ((unit) && (hwif->udma_four)) - ultra |= 0x04; - pci_write_config_byte(dev, ata3_pci, ultra); +/* + * PIO address setup + */ + + pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t); + t = (t & ~(3 << ((3 - drive->dn) << 1))) | (FIT(setup - 1, 0, 3) << ((3 - drive->dn) << 1)); + via_write_config_byte(dev, VIA_ADDRESS_SETUP, t); - if (!drive->init_speed) - drive->init_speed = speed; +/* + * PIO active & recover + */ + + via_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - drive->dn), + (FIT(active - 1, 0, 0xf) << 4) | FIT(recover - 1, 0, 0xf)); + +/* + * UDMA cycle + */ + + if (via_timing[i].udma) { + t = 0xe8; + if (via_isa_bridges[via_config].speed >= XFER_UDMA_4) + t |= FIT(ENOUGH(via_timing[i].udma, T >> 1) - 2, 0, 7); + else + t |= FIT(ENOUGH(via_timing[i].udma, T ) - 2, 0, 3); + } else t = 0x0b; + + via_write_config_byte(dev, VIA_UDMA_TIMING + (3 - drive->dn), t); - err = ide_config_drive_speed(drive, speed); +/* + * Drive init + */ + if (!drive->init_speed) drive->init_speed = speed; + if ((err = ide_config_drive_speed(drive, speed))) + return err; drive->current_speed = speed; - return(err); + + return 0; } -static void config_chipset_for_pio (ide_drive_t *drive) +static void config_chipset_for_pio(ide_drive_t *drive) { - unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; - unsigned short xfer_pio = drive->id->eide_pio_modes; - byte timing, speed, pio; - - pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - - if (xfer_pio> 4) - xfer_pio = 0; - - if (drive->id->eide_pio_iordy > 0) { - for (xfer_pio = 5; - xfer_pio>0 && - drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; - xfer_pio--); - } else { - xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : - (drive->id->eide_pio_modes & 2) ? 0x04 : - (drive->id->eide_pio_modes & 1) ? 0x03 : - (drive->id->tPIO & 2) ? 0x02 : - (drive->id->tPIO & 1) ? 0x01 : xfer_pio; - } + short eide_pio_timing[] = {600, 383, 240, 180, 120, 100}; + signed char pio, ide_pio; - timing = (xfer_pio >= pio) ? xfer_pio : pio; - switch(timing) { - case 4: speed = XFER_PIO_4; break; - case 3: speed = XFER_PIO_3; break; - case 2: speed = XFER_PIO_2; break; - case 1: speed = XFER_PIO_1; break; - default: - speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - break; + if (drive->id->eide_pio_iordy > 0) { /* Has timing table */ + for (pio = 5; pio >= 0; pio--) + if (drive->id->eide_pio_iordy <= eide_pio_timing[pio]) + break; + } else { /* No timing table -> use mode capabilities */ + pio = (drive->id->eide_pio_modes & 4) ? 5 : + (drive->id->eide_pio_modes & 2) ? 4 : + (drive->id->eide_pio_modes & 1) ? 3 : + (drive->id->tPIO == 2) ? 2 : + (drive->id->tPIO == 1) ? 1 : 0; } - (void) via82cxxx_tune_chipset(drive, speed); + + ide_pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + pio = (pio >= ide_pio) ? pio : ide_pio; /* Phew. What about the blacklist? */ + + if (!pio) pio = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; + else pio += XFER_PIO_0; + + /* Fixup because of broken ide-probe.c */ + drive->dn = HWIF(drive)->channel * 2 + (drive->select.b.unit & 1); + + via_set_speed(drive, pio); } -static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio) +static void via82cxxx_tune_drive(ide_drive_t *drive, byte pio) { - byte speed; - switch(pio) { - case 4: speed = XFER_PIO_4; break; - case 3: speed = XFER_PIO_3; break; - case 2: speed = XFER_PIO_2; break; - case 1: speed = XFER_PIO_1; break; - default: speed = XFER_PIO_0; break; + if (pio == 255) { + config_chipset_for_pio(drive); + return; } - (void) via82cxxx_tune_chipset(drive, speed); + + if (pio > 5) pio = 5; + + via_set_speed(drive, XFER_PIO_0 + pio); } #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_chipset_for_dma (ide_drive_t *drive) + +static int config_chipset_for_dma(ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - byte speed = 0x00; - byte ultra66 = eighty_ninty_three(drive); - byte ultra100 = 0; - int rval; - - if ((id->dma_ultra & 0x0020) && (ultra66) && (ultra100)) { - speed = XFER_UDMA_5; - } else if ((id->dma_ultra & 0x0010) && (ultra66)) { - speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (ultra66)) { - speed = XFER_UDMA_3; - } else if (id->dma_ultra & 0x0004) { - speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0002) { - speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0001) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); - } + struct hd_driveid *id = drive->id; + unsigned char ultra66 = eighty_ninty_three(drive); + unsigned char speed = + + ((id->dma_ultra & 0x0010) && ultra66) ? XFER_UDMA_4 : + ((id->dma_ultra & 0x0008) && ultra66) ? XFER_UDMA_3 : + (id->dma_ultra & 0x0004) ? XFER_UDMA_2 : + (id->dma_ultra & 0x0002) ? XFER_UDMA_1 : + (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : + (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 : + (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 : + (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : + (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 : + (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 : + (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0; + + if (!speed) return (int) ide_dma_off_quietly; - (void) via82cxxx_tune_chipset(drive, speed); + via_set_speed(drive, speed); - rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); - return rval; + return (int) ide_dma_on; } -static int config_drive_xfer_rate (ide_drive_t *drive) +/* + * Almost a library function. + */ + +static int config_drive_xfer_rate(ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_dma_action_t dma_func = ide_dma_on; @@ -843,140 +479,146 @@ return HWIF(drive)->dmaproc(dma_func, drive); } -int via82cxxx_dmaproc (ide_dma_action_t func, ide_drive_t *drive) + +int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - switch (func) { - case ide_dma_check: + if (func == ide_dma_check) return config_drive_xfer_rate(drive); - default: - break; - } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ + return ide_dmaproc(func, drive); } #endif /* CONFIG_BLK_DEV_IDEDMA */ -#endif /* CONFIG_VIA82CXXX_TUNING */ -unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name) { - struct pci_dev *host; - struct pci_dev *isa; - int i, j, ata33, ata66; - - int bus_speed = system_bus_clock(); - byte revision = 0; - - for (i = 0; i < arraysize (ApolloHostChipInfo) && !host_dev; i++) { - host = pci_find_device (ApolloHostChipInfo[i].vendor_id, - ApolloHostChipInfo[i].host_id, - NULL); - if (!host) - continue; - - host_dev = host; - printk(ApolloHostChipInfo[i].name); - printk("\n"); - for (j = 0; j < arraysize (ApolloISAChipInfo) && !isa_dev; j++) { - if (ApolloISAChipInfo[j].host_id != - ApolloHostChipInfo[i].host_id) - continue; - - isa = pci_find_device (PCI_VENDOR_ID_VIA, - ApolloISAChipInfo[j].isa_id, - NULL); - if (!isa) - continue; - - isa_dev = isa; - - ata33 = 1; - ata66 = 0; - - via82cxxx_table = ApolloISAChipInfo[j].chipset_table; - - if (ApolloISAChipInfo[j].flags & VIA_FLAG_CHECK_REV) { - pci_read_config_byte(isa_dev, 0x0d, &revision); - ata33 = (revision >= 0x20) ? 1 : 0; - } else if (ApolloISAChipInfo[j].flags & VIA_FLAG_ATA_66) { - byte ata66_0 = 0, ata66_1 = 0; - ata33 = 0; - ata66 = 1; - pci_read_config_byte(dev, 0x50, &ata66_1); - pci_read_config_byte(dev, 0x52, &ata66_0); - if ((ata66_0 & 0x04) || (ata66_1 & 0x04)) { - via82cxxx_table = (bus_speed == 33 || bus_speed == 37) ? - via82cxxx_type_four : - via82cxxx_type_three; - } - } + struct pci_dev *isa = NULL; + unsigned char f, t, m; + unsigned int u, i; - if (ata33 | ata66) - printk(" Chipset Core ATA-%s", ata66 ? "66" : "33"); - } - printk("\n"); +/* + * Find ISA bridge to see how good the IDE is. + */ + + for (via_config = 0; via_isa_bridges[via_config].id; via_config++) + if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_isa_bridges[via_config].id, NULL))) + break; +/* + * Read revision. + */ + + if (via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C586_0) { + pci_read_config_byte(isa, PCI_REVISION_ID, &t); + if (t < 0x30) via_config++; /* vt82c586a */ + if (t < 0x20) via_config++; /* vt82c586 */ } -#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) +/* + * Check UDMA66 mode set by BIOS. + */ + + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + + for (i = 0; i < 4; i++) { + pci_read_config_byte(dev, VIA_UDMA_TIMING + (3 - i), &t); + if ((u & (0x80000 >> ((i >> 1) << 4))) && ((t & 7) < 2)) via_ata66 |= (1 << (i >> 1)); + } + +#ifdef DEBUG + printk(KERN_DEBUG "VP_IDE: BIOS enabled ATA66: primary: %s, secondary: %s\n", + via_ata66 & 1 ? "yes" : "no", via_ata66 & 2 ? "yes" : "no"); +#endif + +/* + * Set UDMA66 double clock bits. + */ + + pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + + if ((via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C596 || !isa) + && (u & 0x80008) != 0x80008) + via_config++; /* vt82c596a / Unknown UDMA33 */ + +/* + * Set up FIFO, flush, prefetch and post-writes. + */ + + pci_read_config_dword(dev, VIA_IDE_ENABLE, &u); + pci_read_config_byte(dev, VIA_FIFO_CONFIG, &f); + pci_read_config_byte(dev, VIA_IDE_CONFIG, &t); + pci_read_config_byte(dev, VIA_MISC_3, &m); + + f &= 0x90; t &= 0x0f; m &= 0x0f; + + switch (u & 3) { + case 2: via_enabled = 1; f |= 0x06; t |= 0xc0; m |= 0xa0; break; /* primary only, 3/4 */ + case 1: via_enabled = 2; f |= 0x69; t |= 0x30; m |= 0x50; break; /* secondary only, 3/4 */ + case 3: via_enabled = 3; + default: f |= 0x2a; t |= 0xf0; m |= 0xf0; break; /* fifo evenly distributed */ + } + + via_write_config_byte(dev, VIA_FIFO_CONFIG, f); + via_write_config_byte(dev, VIA_IDE_CONFIG, t); + via_write_config_byte(dev, VIA_MISC_3, m); + +/* + * Print the boot message. + */ + + printk(KERN_INFO "VP_IDE: VIA %s IDE %s controller on pci%d:%d.%d\n", + via_isa_bridges[via_config].name, + via_isa_bridges[via_config].speed >= XFER_UDMA_4 ? "UDMA66" : + via_isa_bridges[via_config].speed >= XFER_UDMA_2 ? "UDMA33" : "MWDMA16", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); +/* + * Register /proc/ide/via entry + */ + +#if defined(CONFIG_PROC_FS) if (!via_proc) { via_proc = 1; bmide_dev = dev; + isa_dev = isa; via_display_info = &via_get_info; } -#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ +#endif return 0; } -unsigned int __init ata66_via82cxxx (ide_hwif_t *hwif) -{ - byte ata66 = 0; - byte ata66reg = hwif->channel ? 0x50 : 0x52; - pci_read_config_byte(hwif->pci_dev, ata66reg, &ata66); +/* + * Since we don't have a way to detect the 80-wire ribbon cable + * we rely on the BIOS detection. We also check the IDENTIFY byte + * 93 to check the drive's point of view. I think we could return + * '1' here + */ - return ((ata66 & 0x04) ? 1 : 0); +unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif) +{ + return ((via_enabled && via_ata66) >> hwif->channel) & 1; } -void __init ide_init_via82cxxx (ide_hwif_t *hwif) +void __init ide_init_via82cxxx(ide_hwif_t *hwif) { - set_via_timings(hwif); - -#ifdef CONFIG_VIA82CXXX_TUNING hwif->tuneproc = &via82cxxx_tune_drive; - hwif->speedproc = &via82cxxx_tune_chipset; + hwif->speedproc = &via_set_speed; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0; + #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &via82cxxx_dmaproc; hwif->autodma = 1; } #endif /* CONFIG_BLK_DEV_IDEDMA */ -#endif /* CONFIG_VIA82CXXX_TUNING */ } /* - * ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long) - * checks if channel "channel" of if hwif is dma - * capable or not, according to kernel command line, - * and the new fifo settings. - * It calls "ide_setup_dma" on capable mainboards, and - * bypasses the setup if not capable. + * We allow the BM-DMA driver only work on enabled interfaces. */ -void ide_dmacapable_via82cxxx (ide_hwif_t *hwif, unsigned long dmabase) -{ - if (!done) { - via_set_fifoconfig(hwif); - done = 1; - } - - /* - * check if any fifo is available for requested port: - */ - if (((hwif->channel == 0) && ((newfifo & 0x60) == 0x60)) || - ((hwif->channel == 1) && ((newfifo & 0x60) == 0x00))) { - printk(" %s: VP_IDE Bus-Master DMA disabled (FIFO setting)\n", hwif->name); - } else { +void ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase) +{ + if ((via_enabled >> hwif->channel) & 1) ide_setup_dma(hwif, dmabase, 8); - } } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/media/video/cpia_usb.c linux/drivers/media/video/cpia_usb.c --- v2.4.0-test7/linux/drivers/media/video/cpia_usb.c Wed Aug 23 18:36:37 2000 +++ linux/drivers/media/video/cpia_usb.c Tue Sep 5 13:42:52 2000 @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -594,14 +595,14 @@ kfree(ucpia); } -int usb_cpia_init(void) +static int __init usb_cpia_init(void) { cam_list = NULL; return usb_register(&cpia_driver); } -void usb_cpia_cleanup(void) +static void __exit usb_cpia_cleanup(void) { /* struct cam_data *cam; @@ -613,14 +614,7 @@ usb_deregister(&cpia_driver); } -#ifdef MODULE -int init_module(void) -{ - return usb_cpia_init(); -} -void cleanup_module(void) -{ - usb_cpia_cleanup(); -} -#endif /* !MODULE */ +module_init (usb_cpia_init); +module_exit (usb_cpia_cleanup); + diff -u --recursive --new-file v2.4.0-test7/linux/drivers/media/video/stallion.c linux/drivers/media/video/stallion.c --- v2.4.0-test7/linux/drivers/media/video/stallion.c Wed Aug 23 18:36:37 2000 +++ linux/drivers/media/video/stallion.c Wed Dec 31 16:00:00 1969 @@ -1,5329 +0,0 @@ -/*****************************************************************************/ - -/* - * stallion.c -- stallion multiport serial driver. - * - * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer. - * - * This code is loosely based on the Linux serial driver, written by - * Linus Torvalds, Theodore T'so and others. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*****************************************************************************/ - -#include -#include -#include /* for linux/stallion.h */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_PCI -#include -#endif - -/*****************************************************************************/ - -/* - * Define different board types. Use the standard Stallion "assigned" - * board numbers. Boards supported in this driver are abbreviated as - * EIO = EasyIO and ECH = EasyConnection 8/32. - */ -#define BRD_EASYIO 20 -#define BRD_ECH 21 -#define BRD_ECHMC 22 -#define BRD_ECHPCI 26 -#define BRD_ECH64PCI 27 -#define BRD_EASYIOPCI 28 - -/* - * Define a configuration structure to hold the board configuration. - * Need to set this up in the code (for now) with the boards that are - * to be configured into the system. This is what needs to be modified - * when adding/removing/modifying boards. Each line entry in the - * stl_brdconf[] array is a board. Each line contains io/irq/memory - * ranges for that board (as well as what type of board it is). - * Some examples: - * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }, - * This line would configure an EasyIO board (4 or 8, no difference), - * at io address 2a0 and irq 10. - * Another example: - * { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 }, - * This line will configure an EasyConnection 8/32 board at primary io - * address 2a8, secondary io address 280 and irq 12. - * Enter as many lines into this array as you want (only the first 4 - * will actually be used!). Any combination of EasyIO and EasyConnection - * boards can be specified. EasyConnection 8/32 boards can share their - * secondary io addresses between each other. - * - * NOTE: there is no need to put any entries in this table for PCI - * boards. They will be found automatically by the driver - provided - * PCI BIOS32 support is compiled into the kernel. - */ - -typedef struct { - int brdtype; - int ioaddr1; - int ioaddr2; - unsigned long memaddr; - int irq; - int irqtype; -} stlconf_t; - -static stlconf_t stl_brdconf[] = { - /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/ -}; - -static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t); - -/*****************************************************************************/ - -/* - * Define some important driver characteristics. Device major numbers - * allocated as per Linux Device Registry. - */ -#ifndef STL_SIOMEMMAJOR -#define STL_SIOMEMMAJOR 28 -#endif -#ifndef STL_SERIALMAJOR -#define STL_SERIALMAJOR 24 -#endif -#ifndef STL_CALLOUTMAJOR -#define STL_CALLOUTMAJOR 25 -#endif - -#define STL_DRVTYPSERIAL 1 -#define STL_DRVTYPCALLOUT 2 - -/* - * Set the TX buffer size. Bigger is better, but we don't want - * to chew too much memory with buffers! - */ -#define STL_TXBUFLOW 512 -#define STL_TXBUFSIZE 4096 - -/*****************************************************************************/ - -/* - * Define our local driver identity first. Set up stuff to deal with - * all the local structures required by a serial tty driver. - */ -static char *stl_drvtitle = "Stallion Multiport Serial Driver"; -static char *stl_drvname = "stallion"; -static char *stl_drvversion = "5.6.0"; -static char *stl_serialname = "ttyE"; -static char *stl_calloutname = "cue"; - -static struct tty_driver stl_serial; -static struct tty_driver stl_callout; -static struct tty_struct *stl_ttys[STL_MAXDEVS]; -static struct termios *stl_termios[STL_MAXDEVS]; -static struct termios *stl_termioslocked[STL_MAXDEVS]; -static int stl_refcount = 0; - -/* - * We will need to allocate a temporary write buffer for chars that - * come direct from user space. The problem is that a copy from user - * space might cause a page fault (typically on a system that is - * swapping!). All ports will share one buffer - since if the system - * is already swapping a shared buffer won't make things any worse. - */ -static char *stl_tmpwritebuf; -static DECLARE_MUTEX(stl_tmpwritesem); - -/* - * Define a local default termios struct. All ports will be created - * with this termios initially. Basically all it defines is a raw port - * at 9600, 8 data bits, 1 stop bit. - */ -static struct termios stl_deftermios = { - 0, - 0, - (B9600 | CS8 | CREAD | HUPCL | CLOCAL), - 0, - 0, - INIT_C_CC -}; - -/* - * Define global stats structures. Not used often, and can be - * re-used for each stats call. - */ -static comstats_t stl_comstats; -static combrd_t stl_brdstats; -static stlbrd_t stl_dummybrd; -static stlport_t stl_dummyport; - -/* - * Define global place to put buffer overflow characters. - */ -static char stl_unwanted[SC26198_RXFIFOSIZE]; - -/* - * Keep track of what interrupts we have requested for us. - * We don't need to request an interrupt twice if it is being - * shared with another Stallion board. - */ -static int stl_gotintrs[STL_MAXBRDS]; -static int stl_numintrs = 0; - -/*****************************************************************************/ - -static stlbrd_t *stl_brds[STL_MAXBRDS]; - -/* - * Per board state flags. Used with the state field of the board struct. - * Not really much here! - */ -#define BRD_FOUND 0x1 - -/* - * Define the port structure istate flags. These set of flags are - * modified at interrupt time - so setting and reseting them needs - * to be atomic. Use the bit clear/setting routines for this. - */ -#define ASYI_TXBUSY 1 -#define ASYI_TXLOW 2 -#define ASYI_DCDCHANGE 3 -#define ASYI_TXFLOWED 4 - -/* - * Define an array of board names as printable strings. Handy for - * referencing boards when printing trace and stuff. - */ -static char *stl_brdnames[] = { - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - "EasyIO", - "EC8/32-AT", - "EC8/32-MC", - (char *) NULL, - (char *) NULL, - (char *) NULL, - "EC8/32-PCI", - "EC8/64-PCI", - "EasyIO-PCI", -}; - -/*****************************************************************************/ - -#ifdef MODULE -/* - * Define some string labels for arguments passed from the module - * load line. These allow for easy board definitions, and easy - * modification of the io, memory and irq resoucres. - */ - -static char *board0[4]; -static char *board1[4]; -static char *board2[4]; -static char *board3[4]; - -static char **stl_brdsp[] = { - (char **) &board0, - (char **) &board1, - (char **) &board2, - (char **) &board3 -}; - -/* - * Define a set of common board names, and types. This is used to - * parse any module arguments. - */ - -typedef struct stlbrdtype { - char *name; - int type; -} stlbrdtype_t; - -static stlbrdtype_t stl_brdstr[] = { - { "easyio", BRD_EASYIO }, - { "eio", BRD_EASYIO }, - { "20", BRD_EASYIO }, - { "ec8/32", BRD_ECH }, - { "ec8/32-at", BRD_ECH }, - { "ec8/32-isa", BRD_ECH }, - { "ech", BRD_ECH }, - { "echat", BRD_ECH }, - { "21", BRD_ECH }, - { "ec8/32-mc", BRD_ECHMC }, - { "ec8/32-mca", BRD_ECHMC }, - { "echmc", BRD_ECHMC }, - { "echmca", BRD_ECHMC }, - { "22", BRD_ECHMC }, - { "ec8/32-pc", BRD_ECHPCI }, - { "ec8/32-pci", BRD_ECHPCI }, - { "26", BRD_ECHPCI }, - { "ec8/64-pc", BRD_ECH64PCI }, - { "ec8/64-pci", BRD_ECH64PCI }, - { "ech-pci", BRD_ECH64PCI }, - { "echpci", BRD_ECH64PCI }, - { "echpc", BRD_ECH64PCI }, - { "27", BRD_ECH64PCI }, - { "easyio-pc", BRD_EASYIOPCI }, - { "easyio-pci", BRD_EASYIOPCI }, - { "eio-pci", BRD_EASYIOPCI }, - { "eiopci", BRD_EASYIOPCI }, - { "28", BRD_EASYIOPCI }, -}; - -/* - * Define the module agruments. - */ -MODULE_AUTHOR("Greg Ungerer"); -MODULE_DESCRIPTION("Stallion Multiport Serial Driver"); - -MODULE_PARM(board0, "1-4s"); -MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board1, "1-4s"); -MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board2, "1-4s"); -MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board3, "1-4s"); -MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]"); - -#endif - -/*****************************************************************************/ - -/* - * Hardware ID bits for the EasyIO and ECH boards. These defines apply - * to the directly accessible io ports of these boards (not the uarts - - * they are in cd1400.h and sc26198.h). - */ -#define EIO_8PORTRS 0x04 -#define EIO_4PORTRS 0x05 -#define EIO_8PORTDI 0x00 -#define EIO_8PORTM 0x06 -#define EIO_MK3 0x03 -#define EIO_IDBITMASK 0x07 - -#define EIO_BRDMASK 0xf0 -#define ID_BRD4 0x10 -#define ID_BRD8 0x20 -#define ID_BRD16 0x30 - -#define EIO_INTRPEND 0x08 -#define EIO_INTEDGE 0x00 -#define EIO_INTLEVEL 0x08 -#define EIO_0WS 0x10 - -#define ECH_ID 0xa0 -#define ECH_IDBITMASK 0xe0 -#define ECH_BRDENABLE 0x08 -#define ECH_BRDDISABLE 0x00 -#define ECH_INTENABLE 0x01 -#define ECH_INTDISABLE 0x00 -#define ECH_INTLEVEL 0x02 -#define ECH_INTEDGE 0x00 -#define ECH_INTRPEND 0x01 -#define ECH_BRDRESET 0x01 - -#define ECHMC_INTENABLE 0x01 -#define ECHMC_BRDRESET 0x02 - -#define ECH_PNLSTATUS 2 -#define ECH_PNL16PORT 0x20 -#define ECH_PNLIDMASK 0x07 -#define ECH_PNLXPID 0x40 -#define ECH_PNLINTRPEND 0x80 - -#define ECH_ADDR2MASK 0x1e0 - -/* - * Define the vector mapping bits for the programmable interrupt board - * hardware. These bits encode the interrupt for the board to use - it - * is software selectable (except the EIO-8M). - */ -static unsigned char stl_vecmap[] = { - 0xff, 0xff, 0xff, 0x04, 0x06, 0x05, 0xff, 0x07, - 0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03 -}; - -/* - * Set up enable and disable macros for the ECH boards. They require - * the secondary io address space to be activated and deactivated. - * This way all ECH boards can share their secondary io region. - * If this is an ECH-PCI board then also need to set the page pointer - * to point to the correct page. - */ -#define BRDENABLE(brdnr,pagenr) \ - if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ - outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDENABLE), \ - stl_brds[(brdnr)]->ioctrl); \ - else if (stl_brds[(brdnr)]->brdtype == BRD_ECHPCI) \ - outb((pagenr), stl_brds[(brdnr)]->ioctrl); - -#define BRDDISABLE(brdnr) \ - if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ - outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE), \ - stl_brds[(brdnr)]->ioctrl); - -#define STL_CD1400MAXBAUD 230400 -#define STL_SC26198MAXBAUD 460800 - -#define STL_BAUDBASE 115200 -#define STL_CLOSEDELAY (5 * HZ / 10) - -/*****************************************************************************/ - -#ifdef CONFIG_PCI - -/* - * Define the Stallion PCI vendor and device IDs. - */ -#ifndef PCI_VENDOR_ID_STALLION -#define PCI_VENDOR_ID_STALLION 0x124d -#endif -#ifndef PCI_DEVICE_ID_ECHPCI832 -#define PCI_DEVICE_ID_ECHPCI832 0x0000 -#endif -#ifndef PCI_DEVICE_ID_ECHPCI864 -#define PCI_DEVICE_ID_ECHPCI864 0x0002 -#endif -#ifndef PCI_DEVICE_ID_EIOPCI -#define PCI_DEVICE_ID_EIOPCI 0x0003 -#endif - -/* - * Define structure to hold all Stallion PCI boards. - */ -typedef struct stlpcibrd { - unsigned short vendid; - unsigned short devid; - int brdtype; -} stlpcibrd_t; - -static stlpcibrd_t stl_pcibrds[] = { - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI }, - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI }, - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI }, - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI }, -}; - -static int stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t); - -#endif - -/*****************************************************************************/ - -/* - * Define macros to extract a brd/port number from a minor number. - */ -#define MINOR2BRD(min) (((min) & 0xc0) >> 6) -#define MINOR2PORT(min) ((min) & 0x3f) - -/* - * Define a baud rate table that converts termios baud rate selector - * into the actual baud rate value. All baud rate calculations are - * based on the actual baud rate required. - */ -static unsigned int stl_baudrates[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 -}; - -/* - * Define some handy local macros... - */ -#undef MIN -#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) - -#undef TOLOWER -#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) - -/*****************************************************************************/ - -/* - * Declare all those functions in this driver! - */ - -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -static void stl_argbrds(void); -static int stl_parsebrd(stlconf_t *confp, char **argp); - -static unsigned long stl_atol(char *str); -#endif - -int stl_init(void); -static int stl_open(struct tty_struct *tty, struct file *filp); -static void stl_close(struct tty_struct *tty, struct file *filp); -static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void stl_putchar(struct tty_struct *tty, unsigned char ch); -static void stl_flushchars(struct tty_struct *tty); -static int stl_writeroom(struct tty_struct *tty); -static int stl_charsinbuffer(struct tty_struct *tty); -static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void stl_settermios(struct tty_struct *tty, struct termios *old); -static void stl_throttle(struct tty_struct *tty); -static void stl_unthrottle(struct tty_struct *tty); -static void stl_stop(struct tty_struct *tty); -static void stl_start(struct tty_struct *tty); -static void stl_flushbuffer(struct tty_struct *tty); -static void stl_breakctl(struct tty_struct *tty, int state); -static void stl_waituntilsent(struct tty_struct *tty, int timeout); -static void stl_sendxchar(struct tty_struct *tty, char ch); -static void stl_hangup(struct tty_struct *tty); -static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); -static int stl_portinfo(stlport_t *portp, int portnr, char *pos); -static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data); - -static int stl_brdinit(stlbrd_t *brdp); -static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); -static int stl_mapirq(int irq, char *name); -static void stl_getserial(stlport_t *portp, struct serial_struct *sp); -static int stl_setserial(stlport_t *portp, struct serial_struct *sp); -static int stl_getbrdstats(combrd_t *bp); -static int stl_getportstats(stlport_t *portp, comstats_t *cp); -static int stl_clrportstats(stlport_t *portp, comstats_t *cp); -static int stl_getportstruct(unsigned long arg); -static int stl_getbrdstruct(unsigned long arg); -static int stl_waitcarrier(stlport_t *portp, struct file *filp); -static void stl_delay(int len); -static void stl_intr(int irq, void *dev_id, struct pt_regs *regs); -static void stl_eiointr(stlbrd_t *brdp); -static void stl_echatintr(stlbrd_t *brdp); -static void stl_echmcaintr(stlbrd_t *brdp); -static void stl_echpciintr(stlbrd_t *brdp); -static void stl_echpci64intr(stlbrd_t *brdp); -static void stl_offintr(void *private); -static void *stl_memalloc(int len); -static stlbrd_t *stl_allocbrd(void); -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); - -static inline int stl_initbrds(void); -static inline int stl_initeio(stlbrd_t *brdp); -static inline int stl_initech(stlbrd_t *brdp); -static inline int stl_getbrdnr(void); - -#ifdef CONFIG_PCI -static inline int stl_findpcibrds(void); -static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp); -#endif - -/* - * CD1400 uart specific handling functions. - */ -static void stl_cd1400setreg(stlport_t *portp, int regnr, int value); -static int stl_cd1400getreg(stlport_t *portp, int regnr); -static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value); -static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp); -static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); -static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp); -static int stl_cd1400getsignals(stlport_t *portp); -static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts); -static void stl_cd1400ccrwait(stlport_t *portp); -static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx); -static void stl_cd1400disableintrs(stlport_t *portp); -static void stl_cd1400sendbreak(stlport_t *portp, int len); -static void stl_cd1400flowctrl(stlport_t *portp, int state); -static void stl_cd1400sendflow(stlport_t *portp, int state); -static void stl_cd1400flush(stlport_t *portp); -static int stl_cd1400datastate(stlport_t *portp); -static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase); -static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase); -static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr); -static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr); -static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr); - -static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr); - -/* - * SC26198 uart specific handling functions. - */ -static void stl_sc26198setreg(stlport_t *portp, int regnr, int value); -static int stl_sc26198getreg(stlport_t *portp, int regnr); -static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value); -static int stl_sc26198getglobreg(stlport_t *portp, int regnr); -static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp); -static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); -static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp); -static int stl_sc26198getsignals(stlport_t *portp); -static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts); -static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx); -static void stl_sc26198disableintrs(stlport_t *portp); -static void stl_sc26198sendbreak(stlport_t *portp, int len); -static void stl_sc26198flowctrl(stlport_t *portp, int state); -static void stl_sc26198sendflow(stlport_t *portp, int state); -static void stl_sc26198flush(stlport_t *portp); -static int stl_sc26198datastate(stlport_t *portp); -static void stl_sc26198wait(stlport_t *portp); -static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty); -static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase); -static void stl_sc26198txisr(stlport_t *port); -static void stl_sc26198rxisr(stlport_t *port, unsigned int iack); -static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch); -static void stl_sc26198rxbadchars(stlport_t *portp); -static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); - -/*****************************************************************************/ - -/* - * Generic UART support structure. - */ -typedef struct uart { - int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp); - void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); - void (*setport)(stlport_t *portp, struct termios *tiosp); - int (*getsignals)(stlport_t *portp); - void (*setsignals)(stlport_t *portp, int dtr, int rts); - void (*enablerxtx)(stlport_t *portp, int rx, int tx); - void (*startrxtx)(stlport_t *portp, int rx, int tx); - void (*disableintrs)(stlport_t *portp); - void (*sendbreak)(stlport_t *portp, int len); - void (*flowctrl)(stlport_t *portp, int state); - void (*sendflow)(stlport_t *portp, int state); - void (*flush)(stlport_t *portp); - int (*datastate)(stlport_t *portp); - void (*intr)(stlpanel_t *panelp, unsigned int iobase); -} uart_t; - -/* - * Define some macros to make calling these functions nice and clean. - */ -#define stl_panelinit (* ((uart_t *) panelp->uartp)->panelinit) -#define stl_portinit (* ((uart_t *) portp->uartp)->portinit) -#define stl_setport (* ((uart_t *) portp->uartp)->setport) -#define stl_getsignals (* ((uart_t *) portp->uartp)->getsignals) -#define stl_setsignals (* ((uart_t *) portp->uartp)->setsignals) -#define stl_enablerxtx (* ((uart_t *) portp->uartp)->enablerxtx) -#define stl_startrxtx (* ((uart_t *) portp->uartp)->startrxtx) -#define stl_disableintrs (* ((uart_t *) portp->uartp)->disableintrs) -#define stl_sendbreak (* ((uart_t *) portp->uartp)->sendbreak) -#define stl_flowctrl (* ((uart_t *) portp->uartp)->flowctrl) -#define stl_sendflow (* ((uart_t *) portp->uartp)->sendflow) -#define stl_flush (* ((uart_t *) portp->uartp)->flush) -#define stl_datastate (* ((uart_t *) portp->uartp)->datastate) - -/*****************************************************************************/ - -/* - * CD1400 UART specific data initialization. - */ -static uart_t stl_cd1400uart = { - stl_cd1400panelinit, - stl_cd1400portinit, - stl_cd1400setport, - stl_cd1400getsignals, - stl_cd1400setsignals, - stl_cd1400enablerxtx, - stl_cd1400startrxtx, - stl_cd1400disableintrs, - stl_cd1400sendbreak, - stl_cd1400flowctrl, - stl_cd1400sendflow, - stl_cd1400flush, - stl_cd1400datastate, - stl_cd1400eiointr -}; - -/* - * Define the offsets within the register bank of a cd1400 based panel. - * These io address offsets are common to the EasyIO board as well. - */ -#define EREG_ADDR 0 -#define EREG_DATA 4 -#define EREG_RXACK 5 -#define EREG_TXACK 6 -#define EREG_MDACK 7 - -#define EREG_BANKSIZE 8 - -#define CD1400_CLK 25000000 -#define CD1400_CLK8M 20000000 - -/* - * Define the cd1400 baud rate clocks. These are used when calculating - * what clock and divisor to use for the required baud rate. Also - * define the maximum baud rate allowed, and the default base baud. - */ -static int stl_cd1400clkdivs[] = { - CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4 -}; - -/*****************************************************************************/ - -/* - * SC26198 UART specific data initization. - */ -static uart_t stl_sc26198uart = { - stl_sc26198panelinit, - stl_sc26198portinit, - stl_sc26198setport, - stl_sc26198getsignals, - stl_sc26198setsignals, - stl_sc26198enablerxtx, - stl_sc26198startrxtx, - stl_sc26198disableintrs, - stl_sc26198sendbreak, - stl_sc26198flowctrl, - stl_sc26198sendflow, - stl_sc26198flush, - stl_sc26198datastate, - stl_sc26198intr -}; - -/* - * Define the offsets within the register bank of a sc26198 based panel. - */ -#define XP_DATA 0 -#define XP_ADDR 1 -#define XP_MODID 2 -#define XP_STATUS 2 -#define XP_IACK 3 - -#define XP_BANKSIZE 4 - -/* - * Define the sc26198 baud rate table. Offsets within the table - * represent the actual baud rate selector of sc26198 registers. - */ -static unsigned int sc26198_baudtable[] = { - 50, 75, 150, 200, 300, 450, 600, 900, 1200, 1800, 2400, 3600, - 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, - 230400, 460800, 921600 -}; - -#define SC26198_NRBAUDS (sizeof(sc26198_baudtable) / sizeof(unsigned int)) - -/*****************************************************************************/ - -/* - * Define the driver info for a user level control device. Used mainly - * to get at port stats - only not using the port device itself. - */ -static struct file_operations stl_fsiomem = { - owner: THIS_MODULE, - ioctl: stl_memioctl, -}; - -/*****************************************************************************/ - -static devfs_handle_t devfs_handle = NULL; - -#ifdef MODULE - -/* - * Loadable module initialization stuff. - */ - -int init_module() -{ - unsigned long flags; - -#if DEBUG - printk("init_module()\n"); -#endif - - save_flags(flags); - cli(); - stl_init(); - restore_flags(flags); - - return(0); -} - -/*****************************************************************************/ - -void cleanup_module() -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - stlport_t *portp; - unsigned long flags; - int i, j, k; - -#if DEBUG - printk("cleanup_module()\n"); -#endif - - printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, - stl_drvversion); - - save_flags(flags); - cli(); - -/* - * Free up all allocated resources used by the ports. This includes - * memory and interrupts. As part of this process we will also do - * a hangup on every open port - to try to flush out any processes - * hanging onto ports. - */ - i = tty_unregister_driver(&stl_serial); - j = tty_unregister_driver(&stl_callout); - if (i || j) { - printk("STALLION: failed to un-register tty driver, " - "errno=%d,%d\n", -i, -j); - restore_flags(flags); - return; - } - devfs_unregister (devfs_handle); - if ((i = devfs_unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) - printk("STALLION: failed to un-register serial memory device, " - "errno=%d\n", -i); - - if (stl_tmpwritebuf != (char *) NULL) - kfree(stl_tmpwritebuf); - - for (i = 0; (i < stl_nrbrds); i++) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) - continue; - for (j = 0; (j < STL_MAXPANELS); j++) { - panelp = brdp->panels[j]; - if (panelp == (stlpanel_t *) NULL) - continue; - for (k = 0; (k < STL_PORTSPERPANEL); k++) { - portp = panelp->ports[k]; - if (portp == (stlport_t *) NULL) - continue; - if (portp->tty != (struct tty_struct *) NULL) - stl_hangup(portp->tty); - if (portp->tx.buf != (char *) NULL) - kfree(portp->tx.buf); - kfree(portp); - } - kfree(panelp); - } - - release_region(brdp->ioaddr1, brdp->iosize1); - if (brdp->iosize2 > 0) - release_region(brdp->ioaddr2, brdp->iosize2); - - kfree(brdp); - stl_brds[i] = (stlbrd_t *) NULL; - } - - for (i = 0; (i < stl_numintrs); i++) - free_irq(stl_gotintrs[i], NULL); - - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Check for any arguments passed in on the module load command line. - */ - -static void stl_argbrds() -{ - stlconf_t conf; - stlbrd_t *brdp; - int nrargs, i; - -#if DEBUG - printk("stl_argbrds()\n"); -#endif - - nrargs = sizeof(stl_brdsp) / sizeof(char **); - - for (i = stl_nrbrds; (i < nrargs); i++) { - memset(&conf, 0, sizeof(conf)); - if (stl_parsebrd(&conf, stl_brdsp[i]) == 0) - continue; - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - continue; - stl_nrbrds = i + 1; - brdp->brdnr = i; - brdp->brdtype = conf.brdtype; - brdp->ioaddr1 = conf.ioaddr1; - brdp->ioaddr2 = conf.ioaddr2; - brdp->irq = conf.irq; - brdp->irqtype = conf.irqtype; - stl_brdinit(brdp); - } -} - -/*****************************************************************************/ - -/* - * Convert an ascii string number into an unsigned long. - */ - -static unsigned long stl_atol(char *str) -{ - unsigned long val; - int base, c; - char *sp; - - val = 0; - sp = str; - if ((*sp == '0') && (*(sp+1) == 'x')) { - base = 16; - sp += 2; - } else if (*sp == '0') { - base = 8; - sp++; - } else { - base = 10; - } - - for (; (*sp != 0); sp++) { - c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); - if ((c < 0) || (c >= base)) { - printk("STALLION: invalid argument %s\n", str); - val = 0; - break; - } - val = (val * base) + c; - } - return(val); -} - -/*****************************************************************************/ - -/* - * Parse the supplied argument string, into the board conf struct. - */ - -static int stl_parsebrd(stlconf_t *confp, char **argp) -{ - char *sp; - int nrbrdnames, i; - -#if DEBUG - printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp); -#endif - - if ((argp[0] == (char *) NULL) || (*argp[0] == 0)) - return(0); - - for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) - *sp = TOLOWER(*sp); - - nrbrdnames = sizeof(stl_brdstr) / sizeof(stlbrdtype_t); - for (i = 0; (i < nrbrdnames); i++) { - if (strcmp(stl_brdstr[i].name, argp[0]) == 0) - break; - } - if (i >= nrbrdnames) { - printk("STALLION: unknown board name, %s?\n", argp[0]); - return(0); - } - - confp->brdtype = stl_brdstr[i].type; - - i = 1; - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->ioaddr1 = stl_atol(argp[i]); - i++; - if (confp->brdtype == BRD_ECH) { - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->ioaddr2 = stl_atol(argp[i]); - i++; - } - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->irq = stl_atol(argp[i]); - return(1); -} - -#endif - -/*****************************************************************************/ - -/* - * Local driver kernel memory allocation routine. - */ - -static void *stl_memalloc(int len) -{ - return((void *) kmalloc(len, GFP_KERNEL)); -} - -/*****************************************************************************/ - -/* - * Allocate a new board structure. Fill out the basic info in it. - */ - -static stlbrd_t *stl_allocbrd() -{ - stlbrd_t *brdp; - - brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); - if (brdp == (stlbrd_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlbrd_t)); - return((stlbrd_t *) NULL); - } - - memset(brdp, 0, sizeof(stlbrd_t)); - brdp->magic = STL_BOARDMAGIC; - return(brdp); -} - -/*****************************************************************************/ - -static int stl_open(struct tty_struct *tty, struct file *filp) -{ - stlport_t *portp; - stlbrd_t *brdp; - unsigned int minordev; - int brdnr, panelnr, portnr, rc; - -#if DEBUG - printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty, - (int) filp, tty->device); -#endif - - minordev = MINOR(tty->device); - brdnr = MINOR2BRD(minordev); - if (brdnr >= stl_nrbrds) - return(-ENODEV); - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - minordev = MINOR2PORT(minordev); - for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) { - if (brdp->panels[panelnr] == (stlpanel_t *) NULL) - break; - if (minordev < brdp->panels[panelnr]->nrports) { - portnr = minordev; - break; - } - minordev -= brdp->panels[panelnr]->nrports; - } - if (portnr < 0) - return(-ENODEV); - - portp = brdp->panels[panelnr]->ports[portnr]; - if (portp == (stlport_t *) NULL) - return(-ENODEV); - - MOD_INC_USE_COUNT; - -/* - * On the first open of the device setup the port hardware, and - * initialize the per port data structure. - */ - portp->tty = tty; - tty->driver_data = portp; - portp->refcount++; - - if ((portp->flags & ASYNC_INITIALIZED) == 0) { - if (portp->tx.buf == (char *) NULL) { - portp->tx.buf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (portp->tx.buf == (char *) NULL) - return(-ENOMEM); - portp->tx.head = portp->tx.buf; - portp->tx.tail = portp->tx.buf; - } - stl_setport(portp, tty->termios); - portp->sigs = stl_getsignals(portp); - stl_setsignals(portp, 1, 1); - stl_enablerxtx(portp, 1, 1); - stl_startrxtx(portp, 1, 0); - clear_bit(TTY_IO_ERROR, &tty->flags); - portp->flags |= ASYNC_INITIALIZED; - } - -/* - * Check if this port is in the middle of closing. If so then wait - * until it is closed then return error status, based on flag settings. - * The sleep here does not need interrupt protection since the wakeup - * for it is done with the same context. - */ - if (portp->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&portp->close_wait); - if (portp->flags & ASYNC_HUP_NOTIFY) - return(-EAGAIN); - return(-ERESTARTSYS); - } - -/* - * Based on type of open being done check if it can overlap with any - * previous opens still in effect. If we are a normal serial device - * then also we might have to wait for carrier. - */ - if (tty->driver.subtype == STL_DRVTYPCALLOUT) { - if (portp->flags & ASYNC_NORMAL_ACTIVE) - return(-EBUSY); - if (portp->flags & ASYNC_CALLOUT_ACTIVE) { - if ((portp->flags & ASYNC_SESSION_LOCKOUT) && - (portp->session != current->session)) - return(-EBUSY); - if ((portp->flags & ASYNC_PGRP_LOCKOUT) && - (portp->pgrp != current->pgrp)) - return(-EBUSY); - } - portp->flags |= ASYNC_CALLOUT_ACTIVE; - } else { - if (filp->f_flags & O_NONBLOCK) { - if (portp->flags & ASYNC_CALLOUT_ACTIVE) - return(-EBUSY); - } else { - if ((rc = stl_waitcarrier(portp, filp)) != 0) - return(rc); - } - portp->flags |= ASYNC_NORMAL_ACTIVE; - } - - if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver.subtype == STL_DRVTYPSERIAL) - *tty->termios = portp->normaltermios; - else - *tty->termios = portp->callouttermios; - stl_setport(portp, tty->termios); - } - - portp->session = current->session; - portp->pgrp = current->pgrp; - return(0); -} - -/*****************************************************************************/ - -/* - * Possibly need to wait for carrier (DCD signal) to come high. Say - * maybe because if we are clocal then we don't need to wait... - */ - -static int stl_waitcarrier(stlport_t *portp, struct file *filp) -{ - unsigned long flags; - int rc, doclocal; - -#if DEBUG - printk("stl_waitcarrier(portp=%x,filp=%x)\n", (int) portp, (int) filp); -#endif - - rc = 0; - doclocal = 0; - - if (portp->flags & ASYNC_CALLOUT_ACTIVE) { - if (portp->normaltermios.c_cflag & CLOCAL) - doclocal++; - } else { - if (portp->tty->termios->c_cflag & CLOCAL) - doclocal++; - } - - save_flags(flags); - cli(); - portp->openwaitcnt++; - if (! tty_hung_up_p(filp)) - portp->refcount--; - - for (;;) { - if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) - stl_setsignals(portp, 1, 1); - if (tty_hung_up_p(filp) || - ((portp->flags & ASYNC_INITIALIZED) == 0)) { - if (portp->flags & ASYNC_HUP_NOTIFY) - rc = -EBUSY; - else - rc = -ERESTARTSYS; - break; - } - if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) && - ((portp->flags & ASYNC_CLOSING) == 0) && - (doclocal || (portp->sigs & TIOCM_CD))) { - break; - } - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - interruptible_sleep_on(&portp->open_wait); - } - - if (! tty_hung_up_p(filp)) - portp->refcount++; - portp->openwaitcnt--; - restore_flags(flags); - - return(rc); -} - -/*****************************************************************************/ - -static void stl_close(struct tty_struct *tty, struct file *filp) -{ - stlport_t *portp; - unsigned long flags; - -#if DEBUG - printk("stl_close(tty=%x,filp=%x)\n", (int) tty, (int) filp); -#endif - - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - save_flags(flags); - cli(); - if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - if ((tty->count == 1) && (portp->refcount != 1)) - portp->refcount = 1; - if (portp->refcount-- > 1) { - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - - portp->refcount = 0; - portp->flags |= ASYNC_CLOSING; - - if (portp->flags & ASYNC_NORMAL_ACTIVE) - portp->normaltermios = *tty->termios; - if (portp->flags & ASYNC_CALLOUT_ACTIVE) - portp->callouttermios = *tty->termios; - -/* - * May want to wait for any data to drain before closing. The BUSY - * flag keeps track of whether we are still sending or not - it is - * very accurate for the cd1400, not quite so for the sc26198. - * (The sc26198 has no "end-of-data" interrupt only empty FIFO) - */ - tty->closing = 1; - if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, portp->closing_wait); - stl_waituntilsent(tty, (HZ / 2)); - - portp->flags &= ~ASYNC_INITIALIZED; - stl_disableintrs(portp); - if (tty->termios->c_cflag & HUPCL) - stl_setsignals(portp, 0, 0); - stl_enablerxtx(portp, 0, 0); - stl_flushbuffer(tty); - portp->istate = 0; - if (portp->tx.buf != (char *) NULL) { - kfree(portp->tx.buf); - portp->tx.buf = (char *) NULL; - portp->tx.head = (char *) NULL; - portp->tx.tail = (char *) NULL; - } - set_bit(TTY_IO_ERROR, &tty->flags); - if (tty->ldisc.flush_buffer) - (tty->ldisc.flush_buffer)(tty); - - tty->closing = 0; - portp->tty = (struct tty_struct *) NULL; - - if (portp->openwaitcnt) { - if (portp->close_delay) - stl_delay(portp->close_delay); - wake_up_interruptible(&portp->open_wait); - } - - portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | - ASYNC_CLOSING); - wake_up_interruptible(&portp->close_wait); - MOD_DEC_USE_COUNT; - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Wait for a specified delay period, this is not a busy-loop. It will - * give up the processor while waiting. Unfortunately this has some - * rather intimate knowledge of the process management stuff. - */ - -static void stl_delay(int len) -{ -#if DEBUG - printk("stl_delay(len=%d)\n", len); -#endif - if (len > 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(len); - current->state = TASK_RUNNING; - } -} - -/*****************************************************************************/ - -/* - * Write routine. Take data and stuff it in to the TX ring queue. - * If transmit interrupts are not running then start them. - */ - -static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) -{ - stlport_t *portp; - unsigned int len, stlen; - unsigned char *chbuf; - char *head, *tail; - -#if DEBUG - printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", - (int) tty, from_user, (int) buf, count); -#endif - - if ((tty == (struct tty_struct *) NULL) || - (stl_tmpwritebuf == (char *) NULL)) - return(0); - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); - -/* - * If copying direct from user space we must cater for page faults, - * causing us to "sleep" here for a while. To handle this copy in all - * the data we need now, into a local buffer. Then when we got it all - * copy it into the TX buffer. - */ - chbuf = (unsigned char *) buf; - if (from_user) { - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : - (tail - head - 1); - count = MIN(len, count); - - down(&stl_tmpwritesem); - copy_from_user(stl_tmpwritebuf, chbuf, count); - chbuf = &stl_tmpwritebuf[0]; - } - - head = portp->tx.head; - tail = portp->tx.tail; - if (head >= tail) { - len = STL_TXBUFSIZE - (head - tail) - 1; - stlen = STL_TXBUFSIZE - (head - portp->tx.buf); - } else { - len = tail - head - 1; - stlen = len; - } - - len = MIN(len, count); - count = 0; - while (len > 0) { - stlen = MIN(len, stlen); - memcpy(head, chbuf, stlen); - len -= stlen; - chbuf += stlen; - count += stlen; - head += stlen; - if (head >= (portp->tx.buf + STL_TXBUFSIZE)) { - head = portp->tx.buf; - stlen = tail - head; - } - } - portp->tx.head = head; - - clear_bit(ASYI_TXLOW, &portp->istate); - stl_startrxtx(portp, -1, 1); - - if (from_user) - up(&stl_tmpwritesem); - - return(count); -} - -/*****************************************************************************/ - -static void stl_putchar(struct tty_struct *tty, unsigned char ch) -{ - stlport_t *portp; - unsigned int len; - char *head, *tail; - -#if DEBUG - printk("stl_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - if (portp->tx.buf == (char *) NULL) - return; - - head = portp->tx.head; - tail = portp->tx.tail; - - len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail)) : (tail - head); - len--; - - if (len > 0) { - *head++ = ch; - if (head >= (portp->tx.buf + STL_TXBUFSIZE)) - head = portp->tx.buf; - } - portp->tx.head = head; -} - -/*****************************************************************************/ - -/* - * If there are any characters in the buffer then make sure that TX - * interrupts are on and get'em out. Normally used after the putchar - * routine has been called. - */ - -static void stl_flushchars(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_flushchars(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - if (portp->tx.buf == (char *) NULL) - return; - -#if 0 - if (tty->stopped || tty->hw_stopped || - (portp->tx.head == portp->tx.tail)) - return; -#endif - stl_startrxtx(portp, -1, 1); -} - -/*****************************************************************************/ - -static int stl_writeroom(struct tty_struct *tty) -{ - stlport_t *portp; - char *head, *tail; - -#if DEBUG - printk("stl_writeroom(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return(0); - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); - - head = portp->tx.head; - tail = portp->tx.tail; - return((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1)); -} - -/*****************************************************************************/ - -/* - * Return number of chars in the TX buffer. Normally we would just - * calculate the number of chars in the buffer and return that, but if - * the buffer is empty and TX interrupts are still on then we return - * that the buffer still has 1 char in it. This way whoever called us - * will not think that ALL chars have drained - since the UART still - * must have some chars in it (we are busy after all). - */ - -static int stl_charsinbuffer(struct tty_struct *tty) -{ - stlport_t *portp; - unsigned int size; - char *head, *tail; - -#if DEBUG - printk("stl_charsinbuffer(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return(0); - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); - - head = portp->tx.head; - tail = portp->tx.tail; - size = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); - if ((size == 0) && test_bit(ASYI_TXBUSY, &portp->istate)) - size = 1; - return(size); -} - -/*****************************************************************************/ - -/* - * Generate the serial struct info. - */ - -static void stl_getserial(stlport_t *portp, struct serial_struct *sp) -{ - struct serial_struct sio; - stlbrd_t *brdp; - -#if DEBUG - printk("stl_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); -#endif - - memset(&sio, 0, sizeof(struct serial_struct)); - sio.line = portp->portnr; - sio.port = portp->ioaddr; - sio.flags = portp->flags; - sio.baud_base = portp->baud_base; - sio.close_delay = portp->close_delay; - sio.closing_wait = portp->closing_wait; - sio.custom_divisor = portp->custom_divisor; - sio.hub6 = 0; - if (portp->uartp == &stl_cd1400uart) { - sio.type = PORT_CIRRUS; - sio.xmit_fifo_size = CD1400_TXFIFOSIZE; - } else { - sio.type = PORT_UNKNOWN; - sio.xmit_fifo_size = SC26198_TXFIFOSIZE; - } - - brdp = stl_brds[portp->brdnr]; - if (brdp != (stlbrd_t *) NULL) - sio.irq = brdp->irq; - - copy_to_user(sp, &sio, sizeof(struct serial_struct)); -} - -/*****************************************************************************/ - -/* - * Set port according to the serial struct info. - * At this point we do not do any auto-configure stuff, so we will - * just quietly ignore any requests to change irq, etc. - */ - -static int stl_setserial(stlport_t *portp, struct serial_struct *sp) -{ - struct serial_struct sio; - -#if DEBUG - printk("stl_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); -#endif - - copy_from_user(&sio, sp, sizeof(struct serial_struct)); - if (!capable(CAP_SYS_ADMIN)) { - if ((sio.baud_base != portp->baud_base) || - (sio.close_delay != portp->close_delay) || - ((sio.flags & ~ASYNC_USR_MASK) != - (portp->flags & ~ASYNC_USR_MASK))) - return(-EPERM); - } - - portp->flags = (portp->flags & ~ASYNC_USR_MASK) | - (sio.flags & ASYNC_USR_MASK); - portp->baud_base = sio.baud_base; - portp->close_delay = sio.close_delay; - portp->closing_wait = sio.closing_wait; - portp->custom_divisor = sio.custom_divisor; - stl_setport(portp, portp->tty->termios); - return(0); -} - -/*****************************************************************************/ - -static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) -{ - stlport_t *portp; - unsigned int ival; - int rc; - -#if DEBUG - printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", - (int) tty, (int) file, cmd, (int) arg); -#endif - - if (tty == (struct tty_struct *) NULL) - return(-ENODEV); - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(-ENODEV); - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return(-EIO); - } - - rc = 0; - - switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), - (unsigned int *) arg); - break; - case TIOCSSOFTCAR: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(int))) == 0) { - get_user(ival, (unsigned int *) arg); - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - } - break; - case TIOCMGET: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int))) == 0) { - ival = stl_getsignals(portp); - put_user(ival, (unsigned int *) arg); - } - break; - case TIOCMBIS: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); - stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : -1), - ((ival & TIOCM_RTS) ? 1 : -1)); - } - break; - case TIOCMBIC: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); - stl_setsignals(portp, ((ival & TIOCM_DTR) ? 0 : -1), - ((ival & TIOCM_RTS) ? 0 : -1)); - } - break; - case TIOCMSET: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); - stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : 0), - ((ival & TIOCM_RTS) ? 1 : 0)); - } - break; - case TIOCGSERIAL: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) == 0) - stl_getserial(portp, (struct serial_struct *) arg); - break; - case TIOCSSERIAL: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(struct serial_struct))) == 0) - rc = stl_setserial(portp, (struct serial_struct *) arg); - break; - case COM_GETPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stl_getportstats(portp, (comstats_t *) arg); - break; - case COM_CLRPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stl_clrportstats(portp, (comstats_t *) arg); - break; - case TIOCSERCONFIG: - case TIOCSERGWILD: - case TIOCSERSWILD: - case TIOCSERGETLSR: - case TIOCSERGSTRUCT: - case TIOCSERGETMULTI: - case TIOCSERSETMULTI: - default: - rc = -ENOIOCTLCMD; - break; - } - - return(rc); -} - -/*****************************************************************************/ - -static void stl_settermios(struct tty_struct *tty, struct termios *old) -{ - stlport_t *portp; - struct termios *tiosp; - -#if DEBUG - printk("stl_settermios(tty=%x,old=%x)\n", (int) tty, (int) old); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - tiosp = tty->termios; - if ((tiosp->c_cflag == old->c_cflag) && - (tiosp->c_iflag == old->c_iflag)) - return; - - stl_setport(portp, tiosp); - stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0), - -1); - if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) { - tty->hw_stopped = 0; - stl_start(tty); - } - if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL)) - wake_up_interruptible(&portp->open_wait); -} - -/*****************************************************************************/ - -/* - * Attempt to flow control who ever is sending us data. Based on termios - * settings use software or/and hardware flow control. - */ - -static void stl_throttle(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_throttle(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_flowctrl(portp, 0); -} - -/*****************************************************************************/ - -/* - * Unflow control the device sending us data... - */ - -static void stl_unthrottle(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_unthrottle(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_flowctrl(portp, 1); -} - -/*****************************************************************************/ - -/* - * Stop the transmitter. Basically to do this we will just turn TX - * interrupts off. - */ - -static void stl_stop(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_stop(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_startrxtx(portp, -1, 0); -} - -/*****************************************************************************/ - -/* - * Start the transmitter again. Just turn TX interrupts back on. - */ - -static void stl_start(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_start(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_startrxtx(portp, -1, 1); -} - -/*****************************************************************************/ - -/* - * Hangup this port. This is pretty much like closing the port, only - * a little more brutal. No waiting for data to drain. Shutdown the - * port and maybe drop signals. - */ - -static void stl_hangup(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_hangup(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - portp->flags &= ~ASYNC_INITIALIZED; - stl_disableintrs(portp); - if (tty->termios->c_cflag & HUPCL) - stl_setsignals(portp, 0, 0); - stl_enablerxtx(portp, 0, 0); - stl_flushbuffer(tty); - portp->istate = 0; - set_bit(TTY_IO_ERROR, &tty->flags); - if (portp->tx.buf != (char *) NULL) { - kfree(portp->tx.buf); - portp->tx.buf = (char *) NULL; - portp->tx.head = (char *) NULL; - portp->tx.tail = (char *) NULL; - } - portp->tty = (struct tty_struct *) NULL; - portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); - portp->refcount = 0; - wake_up_interruptible(&portp->open_wait); -} - -/*****************************************************************************/ - -static void stl_flushbuffer(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_flushbuffer(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - stl_flush(portp); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); -} - -/*****************************************************************************/ - -static void stl_breakctl(struct tty_struct *tty, int state) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_breakctl(tty=%x,state=%d)\n", (int) tty, state); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - stl_sendbreak(portp, ((state == -1) ? 1 : 2)); -} - -/*****************************************************************************/ - -static void stl_waituntilsent(struct tty_struct *tty, int timeout) -{ - stlport_t *portp; - unsigned long tend; - -#if DEBUG - printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - if (timeout == 0) - timeout = HZ; - tend = jiffies + timeout; - - while (stl_datastate(portp)) { - if (signal_pending(current)) - break; - stl_delay(2); - if (time_after_eq(jiffies, tend)) - break; - } -} - -/*****************************************************************************/ - -static void stl_sendxchar(struct tty_struct *tty, char ch) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - if (ch == STOP_CHAR(tty)) - stl_sendflow(portp, 0); - else if (ch == START_CHAR(tty)) - stl_sendflow(portp, 1); - else - stl_putchar(tty, ch); -} - -/*****************************************************************************/ - -#define MAXLINE 80 - -/* - * Format info for a specified port. The line is deliberately limited - * to 80 characters. (If it is too long it will be truncated, if too - * short then padded with spaces). - */ - -static int stl_portinfo(stlport_t *portp, int portnr, char *pos) -{ - char *sp; - int sigs, cnt; - - sp = pos; - sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d", - portnr, (portp->hwid == 1) ? "SC26198" : "CD1400", - (int) portp->stats.txtotal, (int) portp->stats.rxtotal); - - if (portp->stats.rxframing) - sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing); - if (portp->stats.rxparity) - sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity); - if (portp->stats.rxbreaks) - sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks); - if (portp->stats.rxoverrun) - sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun); - - sigs = stl_getsignals(portp); - cnt = sprintf(sp, "%s%s%s%s%s ", - (sigs & TIOCM_RTS) ? "|RTS" : "", - (sigs & TIOCM_CTS) ? "|CTS" : "", - (sigs & TIOCM_DTR) ? "|DTR" : "", - (sigs & TIOCM_CD) ? "|DCD" : "", - (sigs & TIOCM_DSR) ? "|DSR" : ""); - *sp = ' '; - sp += cnt; - - for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++) - *sp++ = ' '; - if (cnt >= MAXLINE) - pos[(MAXLINE - 2)] = '+'; - pos[(MAXLINE - 1)] = '\n'; - - return(MAXLINE); -} - -/*****************************************************************************/ - -/* - * Port info, read from the /proc file system. - */ - -static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - stlport_t *portp; - int brdnr, panelnr, portnr, totalport; - int curoff, maxoff; - char *pos; - -#if DEBUG - printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x," - "data=%x\n", (int) page, (int) start, (int) off, count, - (int) eof, (int) data); -#endif - - pos = page; - totalport = 0; - curoff = 0; - - if (off == 0) { - pos += sprintf(pos, "%s: version %s", stl_drvtitle, - stl_drvversion); - while (pos < (page + MAXLINE - 1)) - *pos++ = ' '; - *pos++ = '\n'; - } - curoff = MAXLINE; - -/* - * We scan through for each board, panel and port. The offset is - * calculated on the fly, and irrelevant ports are skipped. - */ - for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) { - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - continue; - if (brdp->state == 0) - continue; - - maxoff = curoff + (brdp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - continue; - } - - totalport = brdnr * STL_MAXPORTS; - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { - panelp = brdp->panels[panelnr]; - if (panelp == (stlpanel_t *) NULL) - continue; - - maxoff = curoff + (panelp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - totalport += panelp->nrports; - continue; - } - - for (portnr = 0; (portnr < panelp->nrports); portnr++, - totalport++) { - portp = panelp->ports[portnr]; - if (portp == (stlport_t *) NULL) - continue; - if (off >= (curoff += MAXLINE)) - continue; - if ((pos - page + MAXLINE) > count) - goto stl_readdone; - pos += stl_portinfo(portp, totalport, pos); - } - } - } - - *eof = 1; - -stl_readdone: - *start = page; - return(pos - page); -} - -/*****************************************************************************/ - -/* - * All board interrupts are vectored through here first. This code then - * calls off to the approrpriate board interrupt handlers. - */ - -static void stl_intr(int irq, void *dev_id, struct pt_regs *regs) -{ - stlbrd_t *brdp; - int i; - -#if DEBUG - printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); -#endif - - for (i = 0; (i < stl_nrbrds); i++) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) - continue; - if (brdp->state == 0) - continue; - (* brdp->isr)(brdp); - } -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for EasyIO board types. - */ - -static void stl_eiointr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int iobase; - - panelp = brdp->panels[0]; - iobase = panelp->iobase; - while (inb(brdp->iostatus) & EIO_INTRPEND) - (* panelp->isr)(panelp, iobase); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for ECH-AT board types. - */ - -static void stl_echatintr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; - - outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); - - while (inb(brdp->iostatus) & ECH_INTRPEND) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { - ioaddr = brdp->bnkstataddr[bnknr]; - if (inb(ioaddr) & ECH_PNLINTRPEND) { - panelp = brdp->bnk2panel[bnknr]; - (* panelp->isr)(panelp, (ioaddr & 0xfffc)); - } - } - } - - outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for ECH-MCA board types. - */ - -static void stl_echmcaintr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; - - while (inb(brdp->iostatus) & ECH_INTRPEND) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { - ioaddr = brdp->bnkstataddr[bnknr]; - if (inb(ioaddr) & ECH_PNLINTRPEND) { - panelp = brdp->bnk2panel[bnknr]; - (* panelp->isr)(panelp, (ioaddr & 0xfffc)); - } - } - } -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for ECH-PCI board types. - */ - -static void stl_echpciintr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr, recheck; - - while (1) { - recheck = 0; - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { - outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl); - ioaddr = brdp->bnkstataddr[bnknr]; - if (inb(ioaddr) & ECH_PNLINTRPEND) { - panelp = brdp->bnk2panel[bnknr]; - (* panelp->isr)(panelp, (ioaddr & 0xfffc)); - recheck++; - } - } - if (! recheck) - break; - } -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for ECH-8/64-PCI board types. - */ - -static void stl_echpci64intr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; - - while (inb(brdp->ioctrl) & 0x1) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { - ioaddr = brdp->bnkstataddr[bnknr]; - if (inb(ioaddr) & ECH_PNLINTRPEND) { - panelp = brdp->bnk2panel[bnknr]; - (* panelp->isr)(panelp, (ioaddr & 0xfffc)); - } - } - } -} - -/*****************************************************************************/ - -/* - * Service an off-level request for some channel. - */ -static void stl_offintr(void *private) -{ - stlport_t *portp; - struct tty_struct *tty; - unsigned int oldsigs; - - portp = private; - -#if DEBUG - printk("stl_offintr(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return; - - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - lock_kernel(); - if (test_bit(ASYI_TXLOW, &portp->istate)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } - if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { - clear_bit(ASYI_DCDCHANGE, &portp->istate); - oldsigs = portp->sigs; - portp->sigs = stl_getsignals(portp); - if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) - wake_up_interruptible(&portp->open_wait); - if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { - if (portp->flags & ASYNC_CHECK_CD) { - if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && - (portp->flags & ASYNC_CALLOUT_NOHUP))) { - tty_hangup(tty); - } - } - } - } - unlock_kernel(); -} - -/*****************************************************************************/ - -/* - * Map in interrupt vector to this driver. Check that we don't - * already have this vector mapped, we might be sharing this - * interrupt across multiple boards. - */ - -static int __init stl_mapirq(int irq, char *name) -{ - int rc, i; - -#if DEBUG - printk("stl_mapirq(irq=%d,name=%s)\n", irq, name); -#endif - - rc = 0; - for (i = 0; (i < stl_numintrs); i++) { - if (stl_gotintrs[i] == irq) - break; - } - if (i >= stl_numintrs) { - if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) { - printk("STALLION: failed to register interrupt " - "routine for %s irq=%d\n", name, irq); - rc = -ENODEV; - } else { - stl_gotintrs[stl_numintrs++] = irq; - } - } - return(rc); -} - -/*****************************************************************************/ - -/* - * Initialize all the ports on a panel. - */ - -static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) -{ - stlport_t *portp; - int chipmask, i; - -#if DEBUG - printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); -#endif - - chipmask = stl_panelinit(brdp, panelp); - -/* - * All UART's are initialized (if found!). Now go through and setup - * each ports data structures. - */ - for (i = 0; (i < panelp->nrports); i++) { - portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); - if (portp == (stlport_t *) NULL) { - printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlport_t)); - break; - } - memset(portp, 0, sizeof(stlport_t)); - - portp->magic = STL_PORTMAGIC; - portp->portnr = i; - portp->brdnr = panelp->brdnr; - portp->panelnr = panelp->panelnr; - portp->uartp = panelp->uartp; - portp->clk = brdp->clk; - portp->baud_base = STL_BAUDBASE; - portp->close_delay = STL_CLOSEDELAY; - portp->closing_wait = 30 * HZ; - portp->normaltermios = stl_deftermios; - portp->callouttermios = stl_deftermios; - portp->tqueue.routine = stl_offintr; - portp->tqueue.data = portp; - init_waitqueue_head(&portp->open_wait); - init_waitqueue_head(&portp->close_wait); - portp->stats.brd = portp->brdnr; - portp->stats.panel = portp->panelnr; - portp->stats.port = portp->portnr; - panelp->ports[i] = portp; - stl_portinit(brdp, panelp, portp); - } - - return(0); -} - -/*****************************************************************************/ - -/* - * Try to find and initialize an EasyIO board. - */ - -static inline int stl_initeio(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int status; - char *name; - int rc; - -#if DEBUG - printk("stl_initeio(brdp=%x)\n", (int) brdp); -#endif - - brdp->ioctrl = brdp->ioaddr1 + 1; - brdp->iostatus = brdp->ioaddr1 + 2; - - status = inb(brdp->iostatus); - if ((status & EIO_IDBITMASK) == EIO_MK3) - brdp->ioctrl++; - -/* - * Handle board specific stuff now. The real difference is PCI - * or not PCI. - */ - if (brdp->brdtype == BRD_EASYIOPCI) { - brdp->iosize1 = 0x80; - brdp->iosize2 = 0x80; - name = "serial(EIO-PCI)"; - outb(0x41, (brdp->ioaddr2 + 0x4c)); - } else { - brdp->iosize1 = 8; - name = "serial(EIO)"; - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", - brdp->irq, brdp->brdnr); - return(-EINVAL); - } - outb((stl_vecmap[brdp->irq] | EIO_0WS | - ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), - brdp->ioctrl); - } - - if (check_region(brdp->ioaddr1, brdp->iosize1)) { - printk("STALLION: Warning, board %d I/O address %x conflicts " - "with another device\n", brdp->brdnr, brdp->ioaddr1); - } - if (brdp->iosize2 > 0) { - if (check_region(brdp->ioaddr2, brdp->iosize2)) { - printk("STALLION: Warning, board %d I/O address %x " - "conflicts with another device\n", - brdp->brdnr, brdp->ioaddr2); - } - } - -/* - * Everything looks OK, so let's go ahead and probe for the hardware. - */ - brdp->clk = CD1400_CLK; - brdp->isr = stl_eiointr; - - switch (status & EIO_IDBITMASK) { - case EIO_8PORTM: - brdp->clk = CD1400_CLK8M; - /* fall thru */ - case EIO_8PORTRS: - case EIO_8PORTDI: - brdp->nrports = 8; - break; - case EIO_4PORTRS: - brdp->nrports = 4; - break; - case EIO_MK3: - switch (status & EIO_BRDMASK) { - case ID_BRD4: - brdp->nrports = 4; - break; - case ID_BRD8: - brdp->nrports = 8; - break; - case ID_BRD16: - brdp->nrports = 16; - break; - default: - return(-ENODEV); - } - break; - default: - return(-ENODEV); - } - -/* - * We have verfied that the board is actually present, so now we - * can complete the setup. - */ - request_region(brdp->ioaddr1, brdp->iosize1, name); - if (brdp->iosize2 > 0) - request_region(brdp->ioaddr2, brdp->iosize2, name); - - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlpanel_t)); - return(-ENOMEM); - } - memset(panelp, 0, sizeof(stlpanel_t)); - - panelp->magic = STL_PANELMAGIC; - panelp->brdnr = brdp->brdnr; - panelp->panelnr = 0; - panelp->nrports = brdp->nrports; - panelp->iobase = brdp->ioaddr1; - panelp->hwid = status; - if ((status & EIO_IDBITMASK) == EIO_MK3) { - panelp->uartp = (void *) &stl_sc26198uart; - panelp->isr = stl_sc26198intr; - } else { - panelp->uartp = (void *) &stl_cd1400uart; - panelp->isr = stl_cd1400eiointr; - } - - brdp->panels[0] = panelp; - brdp->nrpanels = 1; - brdp->state |= BRD_FOUND; - brdp->hwid = status; - rc = stl_mapirq(brdp->irq, name); - return(rc); -} - -/*****************************************************************************/ - -/* - * Try to find an ECH board and initialize it. This code is capable of - * dealing with all types of ECH board. - */ - -static int inline stl_initech(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int status, nxtid, ioaddr, conflict; - int panelnr, banknr, i; - char *name; - -#if DEBUG - printk("stl_initech(brdp=%x)\n", (int) brdp); -#endif - - status = 0; - conflict = 0; - -/* - * Set up the initial board register contents for boards. This varies a - * bit between the different board types. So we need to handle each - * separately. Also do a check that the supplied IRQ is good. - */ - switch (brdp->brdtype) { - - case BRD_ECH: - brdp->isr = stl_echatintr; - brdp->ioctrl = brdp->ioaddr1 + 1; - brdp->iostatus = brdp->ioaddr1 + 1; - status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(-ENODEV); - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", - brdp->irq, brdp->brdnr); - return(-EINVAL); - } - status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); - status |= (stl_vecmap[brdp->irq] << 1); - outb((status | ECH_BRDRESET), brdp->ioaddr1); - brdp->ioctrlval = ECH_INTENABLE | - ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); - for (i = 0; (i < 10); i++) - outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); - brdp->iosize1 = 2; - brdp->iosize2 = 32; - name = "serial(EC8/32)"; - outb(status, brdp->ioaddr1); - break; - - case BRD_ECHMC: - brdp->isr = stl_echmcaintr; - brdp->ioctrl = brdp->ioaddr1 + 0x20; - brdp->iostatus = brdp->ioctrl; - status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(-ENODEV); - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", - brdp->irq, brdp->brdnr); - return(-EINVAL); - } - outb(ECHMC_BRDRESET, brdp->ioctrl); - outb(ECHMC_INTENABLE, brdp->ioctrl); - brdp->iosize1 = 64; - name = "serial(EC8/32-MC)"; - break; - - case BRD_ECHPCI: - brdp->isr = stl_echpciintr; - brdp->ioctrl = brdp->ioaddr1 + 2; - brdp->iosize1 = 4; - brdp->iosize2 = 8; - name = "serial(EC8/32-PCI)"; - break; - - case BRD_ECH64PCI: - brdp->isr = stl_echpci64intr; - brdp->ioctrl = brdp->ioaddr2 + 0x40; - outb(0x43, (brdp->ioaddr1 + 0x4c)); - brdp->iosize1 = 0x80; - brdp->iosize2 = 0x80; - name = "serial(EC8/64-PCI)"; - break; - - default: - printk("STALLION: unknown board type=%d\n", brdp->brdtype); - return(-EINVAL); - break; - } - -/* - * Check boards for possible IO address conflicts. We won't actually - * do anything about it here, just issue a warning... - */ - conflict = check_region(brdp->ioaddr1, brdp->iosize1) ? - brdp->ioaddr1 : 0; - if ((conflict == 0) && (brdp->iosize2 > 0)) - conflict = check_region(brdp->ioaddr2, brdp->iosize2) ? - brdp->ioaddr2 : 0; - if (conflict) { - printk("STALLION: Warning, board %d I/O address %x conflicts " - "with another device\n", brdp->brdnr, conflict); - } - - request_region(brdp->ioaddr1, brdp->iosize1, name); - if (brdp->iosize2 > 0) - request_region(brdp->ioaddr2, brdp->iosize2, name); - -/* - * Scan through the secondary io address space looking for panels. - * As we find'em allocate and initialize panel structures for each. - */ - brdp->clk = CD1400_CLK; - brdp->hwid = status; - - ioaddr = brdp->ioaddr2; - banknr = 0; - panelnr = 0; - nxtid = 0; - - for (i = 0; (i < STL_MAXPANELS); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb(nxtid, brdp->ioctrl); - ioaddr = brdp->ioaddr2; - } - status = inb(ioaddr + ECH_PNLSTATUS); - if ((status & ECH_PNLIDMASK) != nxtid) - break; - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { - printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlpanel_t)); - break; - } - memset(panelp, 0, sizeof(stlpanel_t)); - panelp->magic = STL_PANELMAGIC; - panelp->brdnr = brdp->brdnr; - panelp->panelnr = panelnr; - panelp->iobase = ioaddr; - panelp->pagenr = nxtid; - panelp->hwid = status; - brdp->bnk2panel[banknr] = panelp; - brdp->bnkpageaddr[banknr] = nxtid; - brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; - - if (status & ECH_PNLXPID) { - panelp->uartp = (void *) &stl_sc26198uart; - panelp->isr = stl_sc26198intr; - if (status & ECH_PNL16PORT) { - panelp->nrports = 16; - brdp->bnk2panel[banknr] = panelp; - brdp->bnkpageaddr[banknr] = nxtid; - brdp->bnkstataddr[banknr++] = ioaddr + 4 + - ECH_PNLSTATUS; - } else { - panelp->nrports = 8; - } - } else { - panelp->uartp = (void *) &stl_cd1400uart; - panelp->isr = stl_cd1400echintr; - if (status & ECH_PNL16PORT) { - panelp->nrports = 16; - panelp->ackmask = 0x80; - if (brdp->brdtype != BRD_ECHPCI) - ioaddr += EREG_BANKSIZE; - brdp->bnk2panel[banknr] = panelp; - brdp->bnkpageaddr[banknr] = ++nxtid; - brdp->bnkstataddr[banknr++] = ioaddr + - ECH_PNLSTATUS; - } else { - panelp->nrports = 8; - panelp->ackmask = 0xc0; - } - } - - nxtid++; - ioaddr += EREG_BANKSIZE; - brdp->nrports += panelp->nrports; - brdp->panels[panelnr++] = panelp; - if ((brdp->brdtype != BRD_ECHPCI) && - (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) - break; - } - - brdp->nrpanels = panelnr; - brdp->nrbnks = banknr; - if (brdp->brdtype == BRD_ECH) - outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); - - brdp->state |= BRD_FOUND; - i = stl_mapirq(brdp->irq, name); - return(i); -} - -/*****************************************************************************/ - -/* - * Initialize and configure the specified board. - * Scan through all the boards in the configuration and see what we - * can find. Handle EIO and the ECH boards a little differently here - * since the initial search and setup is very different. - */ - -static int __init stl_brdinit(stlbrd_t *brdp) -{ - int i; - -#if DEBUG - printk("stl_brdinit(brdp=%x)\n", (int) brdp); -#endif - - switch (brdp->brdtype) { - case BRD_EASYIO: - case BRD_EASYIOPCI: - stl_initeio(brdp); - break; - case BRD_ECH: - case BRD_ECHMC: - case BRD_ECHPCI: - case BRD_ECH64PCI: - stl_initech(brdp); - break; - default: - printk("STALLION: board=%d is unknown board type=%d\n", - brdp->brdnr, brdp->brdtype); - return(ENODEV); - } - - stl_brds[brdp->brdnr] = brdp; - if ((brdp->state & BRD_FOUND) == 0) { - printk("STALLION: %s board not found, board=%d io=%x irq=%d\n", - stl_brdnames[brdp->brdtype], brdp->brdnr, - brdp->ioaddr1, brdp->irq); - return(ENODEV); - } - - for (i = 0; (i < STL_MAXPANELS); i++) - if (brdp->panels[i] != (stlpanel_t *) NULL) - stl_initports(brdp, brdp->panels[i]); - - printk("STALLION: %s found, board=%d io=%x irq=%d " - "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], - brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, - brdp->nrports); - return(0); -} - -/*****************************************************************************/ - -/* - * Find the next available board number that is free. - */ - -static inline int stl_getbrdnr() -{ - int i; - - for (i = 0; (i < STL_MAXBRDS); i++) { - if (stl_brds[i] == (stlbrd_t *) NULL) { - if (i >= stl_nrbrds) - stl_nrbrds = i + 1; - return(i); - } - } - return(-1); -} - -/*****************************************************************************/ - -#ifdef CONFIG_PCI - -/* - * We have a Stallion board. Allocate a board structure and - * initialize it. Read its IO and IRQ resources from PCI - * configuration space. - */ - -static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) -{ - stlbrd_t *brdp; - -#if DEBUG - printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, - devp->bus->number, devp->devfn); -#endif - - if (pci_enable_device(devp)) - return(-EIO); - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - return(-ENOMEM); - if ((brdp->brdnr = stl_getbrdnr()) < 0) { - printk("STALLION: too many boards found, " - "maximum supported %d\n", STL_MAXBRDS); - return(0); - } - brdp->brdtype = brdtype; - -/* - * Different Stallion boards use the BAR registers in different ways, - * so set up io addresses based on board type. - */ -#if DEBUG - printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__, - pci_resource_start(devp, 0), pci_resource_start(devp, 1), - pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq); -#endif - -/* - * We have all resources from the board, so let's setup the actual - * board structure now. - */ - switch (brdtype) { - case BRD_ECHPCI: - brdp->ioaddr2 = pci_resource_start(devp, 0); - brdp->ioaddr1 = pci_resource_start(devp, 1); - break; - case BRD_ECH64PCI: - brdp->ioaddr2 = pci_resource_start(devp, 2); - brdp->ioaddr1 = pci_resource_start(devp, 1); - break; - case BRD_EASYIOPCI: - brdp->ioaddr1 = pci_resource_start(devp, 2); - brdp->ioaddr2 = pci_resource_start(devp, 1); - break; - default: - printk("STALLION: unknown PCI board type=%d\n", brdtype); - break; - } - - brdp->irq = devp->irq; - stl_brdinit(brdp); - - return(0); -} - -/*****************************************************************************/ - -/* - * Find all Stallion PCI boards that might be installed. Initialize each - * one as it is found. - */ - - -static inline int stl_findpcibrds() -{ - struct pci_dev *dev = NULL; - int i, rc; - -#if DEBUG - printk("stl_findpcibrds()\n"); -#endif - - if (! pci_present()) - return(0); - - for (i = 0; (i < stl_nrpcibrds); i++) - while ((dev = pci_find_device(stl_pcibrds[i].vendid, - stl_pcibrds[i].devid, dev))) { - -/* - * Found a device on the PCI bus that has our vendor and - * device ID. Need to check now that it is really us. - */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) - continue; - - rc = stl_initpcibrd(stl_pcibrds[i].brdtype, dev); - if (rc) - return(rc); - } - - return(0); -} - -#endif - -/*****************************************************************************/ - -/* - * Scan through all the boards in the configuration and see what we - * can find. Handle EIO and the ECH boards a little differently here - * since the initial search and setup is too different. - */ - -static inline int stl_initbrds() -{ - stlbrd_t *brdp; - stlconf_t *confp; - int i; - -#if DEBUG - printk("stl_initbrds()\n"); -#endif - - if (stl_nrbrds > STL_MAXBRDS) { - printk("STALLION: too many boards in configuration table, " - "truncating to %d\n", STL_MAXBRDS); - stl_nrbrds = STL_MAXBRDS; - } - -/* - * Firstly scan the list of static boards configured. Allocate - * resources and initialize the boards as found. - */ - for (i = 0; (i < stl_nrbrds); i++) { - confp = &stl_brdconf[i]; -#ifdef MODULE - stl_parsebrd(confp, stl_brdsp[i]); -#endif - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - return(-ENOMEM); - brdp->brdnr = i; - brdp->brdtype = confp->brdtype; - brdp->ioaddr1 = confp->ioaddr1; - brdp->ioaddr2 = confp->ioaddr2; - brdp->irq = confp->irq; - brdp->irqtype = confp->irqtype; - stl_brdinit(brdp); - } - -/* - * Find any dynamically supported boards. That is via module load - * line options or auto-detected on the PCI bus. - */ -#ifdef MODULE - stl_argbrds(); -#endif -#ifdef CONFIG_PCI - stl_findpcibrds(); -#endif - - return(0); -} - -/*****************************************************************************/ - -/* - * Return the board stats structure to user app. - */ - -static int stl_getbrdstats(combrd_t *bp) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - int i; - - copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)); - if (stl_brdstats.brd >= STL_MAXBRDS) - return(-ENODEV); - brdp = stl_brds[stl_brdstats.brd]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - - memset(&stl_brdstats, 0, sizeof(combrd_t)); - stl_brdstats.brd = brdp->brdnr; - stl_brdstats.type = brdp->brdtype; - stl_brdstats.hwid = brdp->hwid; - stl_brdstats.state = brdp->state; - stl_brdstats.ioaddr = brdp->ioaddr1; - stl_brdstats.ioaddr2 = brdp->ioaddr2; - stl_brdstats.irq = brdp->irq; - stl_brdstats.nrpanels = brdp->nrpanels; - stl_brdstats.nrports = brdp->nrports; - for (i = 0; (i < brdp->nrpanels); i++) { - panelp = brdp->panels[i]; - stl_brdstats.panels[i].panel = i; - stl_brdstats.panels[i].hwid = panelp->hwid; - stl_brdstats.panels[i].nrports = panelp->nrports; - } - - copy_to_user(bp, &stl_brdstats, sizeof(combrd_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * Resolve the referenced port number into a port struct pointer. - */ - -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - - if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) - return((stlport_t *) NULL); - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return((stlport_t *) NULL); - if ((panelnr < 0) || (panelnr >= brdp->nrpanels)) - return((stlport_t *) NULL); - panelp = brdp->panels[panelnr]; - if (panelp == (stlpanel_t *) NULL) - return((stlport_t *) NULL); - if ((portnr < 0) || (portnr >= panelp->nrports)) - return((stlport_t *) NULL); - return(panelp->ports[portnr]); -} - -/*****************************************************************************/ - -/* - * Return the port stats structure to user app. A NULL port struct - * pointer passed in means that we need to find out from the app - * what port to get stats for (used through board control device). - */ - -static int stl_getportstats(stlport_t *portp, comstats_t *cp) -{ - unsigned char *head, *tail; - unsigned long flags; - - if (portp == (stlport_t *) NULL) { - copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); - portp = stl_getport(stl_comstats.brd, stl_comstats.panel, - stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - } - - portp->stats.state = portp->istate; - portp->stats.flags = portp->flags; - portp->stats.hwid = portp->hwid; - - portp->stats.ttystate = 0; - portp->stats.cflags = 0; - portp->stats.iflags = 0; - portp->stats.oflags = 0; - portp->stats.lflags = 0; - portp->stats.rxbuffered = 0; - - save_flags(flags); - cli(); - if (portp->tty != (struct tty_struct *) NULL) { - if (portp->tty->driver_data == portp) { - portp->stats.ttystate = portp->tty->flags; - portp->stats.rxbuffered = portp->tty->flip.count; - if (portp->tty->termios != (struct termios *) NULL) { - portp->stats.cflags = portp->tty->termios->c_cflag; - portp->stats.iflags = portp->tty->termios->c_iflag; - portp->stats.oflags = portp->tty->termios->c_oflag; - portp->stats.lflags = portp->tty->termios->c_lflag; - } - } - } - restore_flags(flags); - - head = portp->tx.head; - tail = portp->tx.tail; - portp->stats.txbuffered = ((head >= tail) ? (head - tail) : - (STL_TXBUFSIZE - (tail - head))); - - portp->stats.signals = (unsigned long) stl_getsignals(portp); - - copy_to_user(cp, &portp->stats, sizeof(comstats_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * Clear the port stats structure. We also return it zeroed out... - */ - -static int stl_clrportstats(stlport_t *portp, comstats_t *cp) -{ - if (portp == (stlport_t *) NULL) { - copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); - portp = stl_getport(stl_comstats.brd, stl_comstats.panel, - stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - } - - memset(&portp->stats, 0, sizeof(comstats_t)); - portp->stats.brd = portp->brdnr; - portp->stats.panel = portp->panelnr; - portp->stats.port = portp->portnr; - copy_to_user(cp, &portp->stats, sizeof(comstats_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * Return the entire driver ports structure to a user app. - */ - -static int stl_getportstruct(unsigned long arg) -{ - stlport_t *portp; - - copy_from_user(&stl_dummyport, (void *) arg, sizeof(stlport_t)); - portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr, - stl_dummyport.portnr); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - copy_to_user((void *) arg, portp, sizeof(stlport_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * Return the entire driver board structure to a user app. - */ - -static int stl_getbrdstruct(unsigned long arg) -{ - stlbrd_t *brdp; - - copy_from_user(&stl_dummybrd, (void *) arg, sizeof(stlbrd_t)); - if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) - return(-ENODEV); - brdp = stl_brds[stl_dummybrd.brdnr]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - copy_to_user((void *) arg, brdp, sizeof(stlbrd_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * The "staliomem" device is also required to do some special operations - * on the board and/or ports. In this driver it is mostly used for stats - * collection. - */ - -static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) -{ - int brdnr, rc; - -#if DEBUG - printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, - (int) fp, cmd, (int) arg); -#endif - - brdnr = MINOR(ip->i_rdev); - if (brdnr >= STL_MAXBRDS) - return(-ENODEV); - rc = 0; - - switch (cmd) { - case COM_GETPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stl_getportstats((stlport_t *) NULL, - (comstats_t *) arg); - break; - case COM_CLRPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stl_clrportstats((stlport_t *) NULL, - (comstats_t *) arg); - break; - case COM_GETBRDSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(combrd_t))) == 0) - rc = stl_getbrdstats((combrd_t *) arg); - break; - case COM_READPORT: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(stlport_t))) == 0) - rc = stl_getportstruct(arg); - break; - case COM_READBOARD: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(stlbrd_t))) == 0) - rc = stl_getbrdstruct(arg); - break; - default: - rc = -ENOIOCTLCMD; - break; - } - - return(rc); -} - -/*****************************************************************************/ - -int __init stl_init(void) -{ - printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion); - - stl_initbrds(); - -/* - * Allocate a temporary write buffer. - */ - stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (stl_tmpwritebuf == (char *) NULL) - printk("STALLION: failed to allocate memory (size=%d)\n", - STL_TXBUFSIZE); - -/* - * Set up a character driver for per board stuff. This is mainly used - * to do stats ioctls on the ports. - */ - if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) - printk("STALLION: failed to register serial board device\n"); - devfs_handle = devfs_mk_dir (NULL, "staliomem", NULL); - devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, - STL_SIOMEMMAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, - &stl_fsiomem, NULL); - -/* - * Set up the tty driver structure and register us as a driver. - * Also setup the callout tty device. - */ - memset(&stl_serial, 0, sizeof(struct tty_driver)); - stl_serial.magic = TTY_DRIVER_MAGIC; - stl_serial.driver_name = stl_drvname; - stl_serial.name = stl_serialname; - stl_serial.major = STL_SERIALMAJOR; - stl_serial.minor_start = 0; - stl_serial.num = STL_MAXBRDS * STL_MAXPORTS; - stl_serial.type = TTY_DRIVER_TYPE_SERIAL; - stl_serial.subtype = STL_DRVTYPSERIAL; - stl_serial.init_termios = stl_deftermios; - stl_serial.flags = TTY_DRIVER_REAL_RAW; - stl_serial.refcount = &stl_refcount; - stl_serial.table = stl_ttys; - stl_serial.termios = stl_termios; - stl_serial.termios_locked = stl_termioslocked; - - stl_serial.open = stl_open; - stl_serial.close = stl_close; - stl_serial.write = stl_write; - stl_serial.put_char = stl_putchar; - stl_serial.flush_chars = stl_flushchars; - stl_serial.write_room = stl_writeroom; - stl_serial.chars_in_buffer = stl_charsinbuffer; - stl_serial.ioctl = stl_ioctl; - stl_serial.set_termios = stl_settermios; - stl_serial.throttle = stl_throttle; - stl_serial.unthrottle = stl_unthrottle; - stl_serial.stop = stl_stop; - stl_serial.start = stl_start; - stl_serial.hangup = stl_hangup; - stl_serial.flush_buffer = stl_flushbuffer; - stl_serial.break_ctl = stl_breakctl; - stl_serial.wait_until_sent = stl_waituntilsent; - stl_serial.send_xchar = stl_sendxchar; - stl_serial.read_proc = stl_readproc; - - stl_callout = stl_serial; - stl_callout.name = stl_calloutname; - stl_callout.major = STL_CALLOUTMAJOR; - stl_callout.subtype = STL_DRVTYPCALLOUT; - stl_callout.read_proc = 0; - - if (tty_register_driver(&stl_serial)) - printk("STALLION: failed to register serial driver\n"); - if (tty_register_driver(&stl_callout)) - printk("STALLION: failed to register callout driver\n"); - - return(0); -} - -/*****************************************************************************/ -/* CD1400 HARDWARE FUNCTIONS */ -/*****************************************************************************/ - -/* - * These functions get/set/update the registers of the cd1400 UARTs. - * Access to the cd1400 registers is via an address/data io port pair. - * (Maybe should make this inline...) - */ - -static int stl_cd1400getreg(stlport_t *portp, int regnr) -{ - outb((regnr + portp->uartaddr), portp->ioaddr); - return(inb(portp->ioaddr + EREG_DATA)); -} - -static void stl_cd1400setreg(stlport_t *portp, int regnr, int value) -{ - outb((regnr + portp->uartaddr), portp->ioaddr); - outb(value, portp->ioaddr + EREG_DATA); -} - -static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) -{ - outb((regnr + portp->uartaddr), portp->ioaddr); - if (inb(portp->ioaddr + EREG_DATA) != value) { - outb(value, portp->ioaddr + EREG_DATA); - return(1); - } - return(0); -} - -/*****************************************************************************/ - -/* - * Inbitialize the UARTs in a panel. We don't care what sort of board - * these ports are on - since the port io registers are almost - * identical when dealing with ports. - */ - -static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) -{ - unsigned int gfrcr; - int chipmask, i, j; - int nrchips, uartaddr, ioaddr; - -#if DEBUG - printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); -#endif - - BRDENABLE(panelp->brdnr, panelp->pagenr); - -/* - * Check that each chip is present and started up OK. - */ - chipmask = 0; - nrchips = panelp->nrports / CD1400_PORTS; - for (i = 0; (i < nrchips); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb((panelp->pagenr + (i >> 1)), brdp->ioctrl); - ioaddr = panelp->iobase; - } else { - ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1)); - } - uartaddr = (i & 0x01) ? 0x080 : 0; - outb((GFRCR + uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); - outb((CCR + uartaddr), ioaddr); - outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); - outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); - outb((GFRCR + uartaddr), ioaddr); - for (j = 0; (j < CCR_MAXWAIT); j++) { - if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0) - break; - } - if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) { - printk("STALLION: cd1400 not responding, " - "brd=%d panel=%d chip=%d\n", - panelp->brdnr, panelp->panelnr, i); - continue; - } - chipmask |= (0x1 << i); - outb((PPR + uartaddr), ioaddr); - outb(PPR_SCALAR, (ioaddr + EREG_DATA)); - } - - BRDDISABLE(panelp->brdnr); - return(chipmask); -} - -/*****************************************************************************/ - -/* - * Initialize hardware specific port registers. - */ - -static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) -{ -#if DEBUG - printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", - (int) brdp, (int) panelp, (int) portp); -#endif - - if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || - (portp == (stlport_t *) NULL)) - return; - - portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || - (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); - portp->uartaddr = (portp->portnr & 0x04) << 5; - portp->pagenr = panelp->pagenr + (portp->portnr >> 3); - - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); - portp->hwid = stl_cd1400getreg(portp, GFRCR); - BRDDISABLE(portp->brdnr); -} - -/*****************************************************************************/ - -/* - * Wait for the command register to be ready. We will poll this, - * since it won't usually take too long to be ready. - */ - -static void stl_cd1400ccrwait(stlport_t *portp) -{ - int i; - - for (i = 0; (i < CCR_MAXWAIT); i++) { - if (stl_cd1400getreg(portp, CCR) == 0) { - return; - } - } - - printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n", - portp->portnr, portp->panelnr, portp->brdnr); -} - -/*****************************************************************************/ - -/* - * Set up the cd1400 registers for a port based on the termios port - * settings. - */ - -static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) -{ - stlbrd_t *brdp; - unsigned long flags; - unsigned int clkdiv, baudrate; - unsigned char cor1, cor2, cor3; - unsigned char cor4, cor5, ccr; - unsigned char srer, sreron, sreroff; - unsigned char mcor1, mcor2, rtpr; - unsigned char clk, div; - - cor1 = 0; - cor2 = 0; - cor3 = 0; - cor4 = 0; - cor5 = 0; - ccr = 0; - rtpr = 0; - clk = 0; - div = 0; - mcor1 = 0; - mcor2 = 0; - sreron = 0; - sreroff = 0; - - brdp = stl_brds[portp->brdnr]; - if (brdp == (stlbrd_t *) NULL) - return; - -/* - * Set up the RX char ignore mask with those RX error types we - * can ignore. We can get the cd1400 to help us out a little here, - * it will ignore parity errors and breaks for us. - */ - portp->rxignoremsk = 0; - if (tiosp->c_iflag & IGNPAR) { - portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN); - cor1 |= COR1_PARIGNORE; - } - if (tiosp->c_iflag & IGNBRK) { - portp->rxignoremsk |= ST_BREAK; - cor4 |= COR4_IGNBRK; - } - - portp->rxmarkmsk = ST_OVERRUN; - if (tiosp->c_iflag & (INPCK | PARMRK)) - portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING); - if (tiosp->c_iflag & BRKINT) - portp->rxmarkmsk |= ST_BREAK; - -/* - * Go through the char size, parity and stop bits and set all the - * option register appropriately. - */ - switch (tiosp->c_cflag & CSIZE) { - case CS5: - cor1 |= COR1_CHL5; - break; - case CS6: - cor1 |= COR1_CHL6; - break; - case CS7: - cor1 |= COR1_CHL7; - break; - default: - cor1 |= COR1_CHL8; - break; - } - - if (tiosp->c_cflag & CSTOPB) - cor1 |= COR1_STOP2; - else - cor1 |= COR1_STOP1; - - if (tiosp->c_cflag & PARENB) { - if (tiosp->c_cflag & PARODD) - cor1 |= (COR1_PARENB | COR1_PARODD); - else - cor1 |= (COR1_PARENB | COR1_PAREVEN); - } else { - cor1 |= COR1_PARNONE; - } - -/* - * Set the RX FIFO threshold at 6 chars. This gives a bit of breathing - * space for hardware flow control and the like. This should be set to - * VMIN. Also here we will set the RX data timeout to 10ms - this should - * really be based on VTIME. - */ - cor3 |= FIFO_RXTHRESHOLD; - rtpr = 2; - -/* - * Calculate the baud rate timers. For now we will just assume that - * the input and output baud are the same. Could have used a baud - * table here, but this way we can generate virtually any baud rate - * we like! - */ - baudrate = tiosp->c_cflag & CBAUD; - if (baudrate & CBAUDEX) { - baudrate &= ~CBAUDEX; - if ((baudrate < 1) || (baudrate > 4)) - tiosp->c_cflag &= ~CBAUDEX; - else - baudrate += 15; - } - baudrate = stl_baudrates[baudrate]; - if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - baudrate = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - baudrate = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) - baudrate = (portp->baud_base / portp->custom_divisor); - } - if (baudrate > STL_CD1400MAXBAUD) - baudrate = STL_CD1400MAXBAUD; - - if (baudrate > 0) { - for (clk = 0; (clk < CD1400_NUMCLKS); clk++) { - clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate); - if (clkdiv < 0x100) - break; - } - div = (unsigned char) clkdiv; - } - -/* - * Check what form of modem signaling is required and set it up. - */ - if ((tiosp->c_cflag & CLOCAL) == 0) { - mcor1 |= MCOR1_DCD; - mcor2 |= MCOR2_DCD; - sreron |= SRER_MODEM; - portp->flags |= ASYNC_CHECK_CD; - } else { - portp->flags &= ~ASYNC_CHECK_CD; - } - -/* - * Setup cd1400 enhanced modes if we can. In particular we want to - * handle as much of the flow control as possible automatically. As - * well as saving a few CPU cycles it will also greatly improve flow - * control reliability. - */ - if (tiosp->c_iflag & IXON) { - cor2 |= COR2_TXIBE; - cor3 |= COR3_SCD12; - if (tiosp->c_iflag & IXANY) - cor2 |= COR2_IXM; - } - - if (tiosp->c_cflag & CRTSCTS) { - cor2 |= COR2_CTSAE; - mcor1 |= FIFO_RTSTHRESHOLD; - } - -/* - * All cd1400 register values calculated so go through and set - * them all up. - */ - -#if DEBUG - printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", - portp->portnr, portp->panelnr, portp->brdnr); - printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", - cor1, cor2, cor3, cor4, cor5); - printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", - mcor1, mcor2, rtpr, sreron, sreroff); - printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); - printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); - srer = stl_cd1400getreg(portp, SRER); - stl_cd1400setreg(portp, SRER, 0); - if (stl_cd1400updatereg(portp, COR1, cor1)) - ccr = 1; - if (stl_cd1400updatereg(portp, COR2, cor2)) - ccr = 1; - if (stl_cd1400updatereg(portp, COR3, cor3)) - ccr = 1; - if (ccr) { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_CORCHANGE); - } - stl_cd1400setreg(portp, COR4, cor4); - stl_cd1400setreg(portp, COR5, cor5); - stl_cd1400setreg(portp, MCOR1, mcor1); - stl_cd1400setreg(portp, MCOR2, mcor2); - if (baudrate > 0) { - stl_cd1400setreg(portp, TCOR, clk); - stl_cd1400setreg(portp, TBPR, div); - stl_cd1400setreg(portp, RCOR, clk); - stl_cd1400setreg(portp, RBPR, div); - } - stl_cd1400setreg(portp, SCHR1, tiosp->c_cc[VSTART]); - stl_cd1400setreg(portp, SCHR2, tiosp->c_cc[VSTOP]); - stl_cd1400setreg(portp, SCHR3, tiosp->c_cc[VSTART]); - stl_cd1400setreg(portp, SCHR4, tiosp->c_cc[VSTOP]); - stl_cd1400setreg(portp, RTPR, rtpr); - mcor1 = stl_cd1400getreg(portp, MSVR1); - if (mcor1 & MSVR1_DCD) - portp->sigs |= TIOCM_CD; - else - portp->sigs &= ~TIOCM_CD; - stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Set the state of the DTR and RTS signals. - */ - -static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) -{ - unsigned char msvr1, msvr2; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n", - (int) portp, dtr, rts); -#endif - - msvr1 = 0; - msvr2 = 0; - if (dtr > 0) - msvr1 = MSVR1_DTR; - if (rts > 0) - msvr2 = MSVR2_RTS; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - if (rts >= 0) - stl_cd1400setreg(portp, MSVR2, msvr2); - if (dtr >= 0) - stl_cd1400setreg(portp, MSVR1, msvr1); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Return the state of the signals. - */ - -static int stl_cd1400getsignals(stlport_t *portp) -{ - unsigned char msvr1, msvr2; - unsigned long flags; - int sigs; - -#if DEBUG - printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - msvr1 = stl_cd1400getreg(portp, MSVR1); - msvr2 = stl_cd1400getreg(portp, MSVR2); - BRDDISABLE(portp->brdnr); - restore_flags(flags); - - sigs = 0; - sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; - sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0; - sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0; - sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0; -#if 0 - sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0; - sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0; -#else - sigs |= TIOCM_DSR; -#endif - return(sigs); -} - -/*****************************************************************************/ - -/* - * Enable/Disable the Transmitter and/or Receiver. - */ - -static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char ccr; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif - ccr = 0; - - if (tx == 0) - ccr |= CCR_TXDISABLE; - else if (tx > 0) - ccr |= CCR_TXENABLE; - if (rx == 0) - ccr |= CCR_RXDISABLE; - else if (rx > 0) - ccr |= CCR_RXENABLE; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, ccr); - stl_cd1400ccrwait(portp); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Start/stop the Transmitter and/or Receiver. - */ - -static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char sreron, sreroff; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif - - sreron = 0; - sreroff = 0; - if (tx == 0) - sreroff |= (SRER_TXDATA | SRER_TXEMPTY); - else if (tx == 1) - sreron |= SRER_TXDATA; - else if (tx >= 2) - sreron |= SRER_TXEMPTY; - if (rx == 0) - sreroff |= SRER_RXDATA; - else if (rx > 0) - sreron |= SRER_RXDATA; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400setreg(portp, SRER, - ((stl_cd1400getreg(portp, SRER) & ~sreroff) | sreron)); - BRDDISABLE(portp->brdnr); - if (tx > 0) - set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Disable all interrupts from this port. - */ - -static void stl_cd1400disableintrs(stlport_t *portp) -{ - unsigned long flags; - -#if DEBUG - printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); -#endif - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400setreg(portp, SRER, 0); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -static void stl_cd1400sendbreak(stlport_t *portp, int len) -{ - unsigned long flags; - -#if DEBUG - printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400setreg(portp, SRER, - ((stl_cd1400getreg(portp, SRER) & ~SRER_TXDATA) | - SRER_TXEMPTY)); - BRDDISABLE(portp->brdnr); - portp->brklen = len; - if (len == 1) - portp->stats.txbreaks++; - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Take flow control actions... - */ - -static void stl_cd1400flowctrl(stlport_t *portp, int state) -{ - struct tty_struct *tty; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state); -#endif - - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - - if (state) { - if (tty->termios->c_iflag & IXOFF) { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); - portp->stats.rxxon++; - stl_cd1400ccrwait(portp); - } -/* - * Question: should we return RTS to what it was before? It may - * have been set by an ioctl... Suppose not, since if you have - * hardware flow control set then it is pretty silly to go and - * set the RTS line by hand. - */ - if (tty->termios->c_cflag & CRTSCTS) { - stl_cd1400setreg(portp, MCOR1, - (stl_cd1400getreg(portp, MCOR1) | - FIFO_RTSTHRESHOLD)); - stl_cd1400setreg(portp, MSVR2, MSVR2_RTS); - portp->stats.rxrtson++; - } - } else { - if (tty->termios->c_iflag & IXOFF) { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); - portp->stats.rxxoff++; - stl_cd1400ccrwait(portp); - } - if (tty->termios->c_cflag & CRTSCTS) { - stl_cd1400setreg(portp, MCOR1, - (stl_cd1400getreg(portp, MCOR1) & 0xf0)); - stl_cd1400setreg(portp, MSVR2, 0); - portp->stats.rxrtsoff++; - } - } - - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Send a flow control character... - */ - -static void stl_cd1400sendflow(stlport_t *portp, int state) -{ - struct tty_struct *tty; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state); -#endif - - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - if (state) { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); - portp->stats.rxxon++; - stl_cd1400ccrwait(portp); - } else { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); - portp->stats.rxxoff++; - stl_cd1400ccrwait(portp); - } - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -static void stl_cd1400flush(stlport_t *portp) -{ - unsigned long flags; - -#if DEBUG - printk("stl_cd1400flush(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_TXFLUSHFIFO); - stl_cd1400ccrwait(portp); - portp->tx.tail = portp->tx.head; - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Return the current state of data flow on this port. This is only - * really interresting when determining if data has fully completed - * transmission or not... This is easy for the cd1400, it accurately - * maintains the busy port flag. - */ - -static int stl_cd1400datastate(stlport_t *portp) -{ -#if DEBUG - printk("stl_cd1400datastate(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return(0); - - return(test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for cd1400 EasyIO boards. - */ - -static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) -{ - unsigned char svrtype; - -#if DEBUG - printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n", - (int) panelp, iobase); -#endif - - outb(SVRR, iobase); - svrtype = inb(iobase + EREG_DATA); - if (panelp->nrports > 4) { - outb((SVRR + 0x80), iobase); - svrtype |= inb(iobase + EREG_DATA); - } - - if (svrtype & SVRR_RX) - stl_cd1400rxisr(panelp, iobase); - else if (svrtype & SVRR_TX) - stl_cd1400txisr(panelp, iobase); - else if (svrtype & SVRR_MDM) - stl_cd1400mdmisr(panelp, iobase); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for cd1400 panels. - */ - -static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase) -{ - unsigned char svrtype; - -#if DEBUG - printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp, - iobase); -#endif - - outb(SVRR, iobase); - svrtype = inb(iobase + EREG_DATA); - outb((SVRR + 0x80), iobase); - svrtype |= inb(iobase + EREG_DATA); - if (svrtype & SVRR_RX) - stl_cd1400rxisr(panelp, iobase); - else if (svrtype & SVRR_TX) - stl_cd1400txisr(panelp, iobase); - else if (svrtype & SVRR_MDM) - stl_cd1400mdmisr(panelp, iobase); -} - - -/*****************************************************************************/ - -/* - * Unfortunately we need to handle breaks in the TX data stream, since - * this is the only way to generate them on the cd1400. - */ - -static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) -{ - if (portp->brklen == 1) { - outb((COR2 + portp->uartaddr), ioaddr); - outb((inb(ioaddr + EREG_DATA) | COR2_ETC), - (ioaddr + EREG_DATA)); - outb((TDR + portp->uartaddr), ioaddr); - outb(ETC_CMD, (ioaddr + EREG_DATA)); - outb(ETC_STARTBREAK, (ioaddr + EREG_DATA)); - outb((SRER + portp->uartaddr), ioaddr); - outb((inb(ioaddr + EREG_DATA) & ~(SRER_TXDATA | SRER_TXEMPTY)), - (ioaddr + EREG_DATA)); - return(1); - } else if (portp->brklen > 1) { - outb((TDR + portp->uartaddr), ioaddr); - outb(ETC_CMD, (ioaddr + EREG_DATA)); - outb(ETC_STOPBREAK, (ioaddr + EREG_DATA)); - portp->brklen = -1; - return(1); - } else { - outb((COR2 + portp->uartaddr), ioaddr); - outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), - (ioaddr + EREG_DATA)); - portp->brklen = 0; - } - return(0); -} - -/*****************************************************************************/ - -/* - * Transmit interrupt handler. This has gotta be fast! Handling TX - * chars is pretty simple, stuff as many as possible from the TX buffer - * into the cd1400 FIFO. Must also handle TX breaks here, since they - * are embedded as commands in the data stream. Oh no, had to use a goto! - * This could be optimized more, will do when I get time... - * In practice it is possible that interrupts are enabled but that the - * port has been hung up. Need to handle not having any TX buffer here, - * this is done by using the side effect that head and tail will also - * be NULL if the buffer has been freed. - */ - -static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - int len, stlen; - char *head, *tail; - unsigned char ioack, srer; - -#if DEBUG - printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif - - ioack = inb(ioaddr + EREG_TXACK); - if (((ioack & panelp->ackmask) != 0) || - ((ioack & ACK_TYPMASK) != ACK_TYPTX)) { - printk("STALLION: bad TX interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - -/* - * Unfortunately we need to handle breaks in the data stream, since - * this is the only way to generate them on the cd1400. Do it now if - * a break is to be sent. - */ - if (portp->brklen != 0) - if (stl_cd1400breakisr(portp, ioaddr)) - goto stl_txalldone; - - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); - if ((len == 0) || ((len < STL_TXBUFLOW) && - (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { - set_bit(ASYI_TXLOW, &portp->istate); - queue_task(&portp->tqueue, &tq_scheduler); - } - - if (len == 0) { - outb((SRER + portp->uartaddr), ioaddr); - srer = inb(ioaddr + EREG_DATA); - if (srer & SRER_TXDATA) { - srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY; - } else { - srer &= ~(SRER_TXDATA | SRER_TXEMPTY); - clear_bit(ASYI_TXBUSY, &portp->istate); - } - outb(srer, (ioaddr + EREG_DATA)); - } else { - len = MIN(len, CD1400_TXFIFOSIZE); - portp->stats.txtotal += len; - stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); - outb((TDR + portp->uartaddr), ioaddr); - outsb((ioaddr + EREG_DATA), tail, stlen); - len -= stlen; - tail += stlen; - if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) - tail = portp->tx.buf; - if (len > 0) { - outsb((ioaddr + EREG_DATA), tail, len); - tail += len; - } - portp->tx.tail = tail; - } - -stl_txalldone: - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); -} - -/*****************************************************************************/ - -/* - * Receive character interrupt handler. Determine if we have good chars - * or bad chars and then process appropriately. Good chars are easy - * just shove the lot into the RX buffer and set all status byte to 0. - * If a bad RX char then process as required. This routine needs to be - * fast! In practice it is possible that we get an interrupt on a port - * that is closed. This can happen on hangups - since they completely - * shutdown a port not in user context. Need to handle this case. - */ - -static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - struct tty_struct *tty; - unsigned int ioack, len, buflen; - unsigned char status; - char ch; - -#if DEBUG - printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif - - ioack = inb(ioaddr + EREG_RXACK); - if ((ioack & panelp->ackmask) != 0) { - printk("STALLION: bad RX interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - tty = portp->tty; - - if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { - outb((RDCR + portp->uartaddr), ioaddr); - len = inb(ioaddr + EREG_DATA); - if ((tty == (struct tty_struct *) NULL) || - (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { - len = MIN(len, sizeof(stl_unwanted)); - outb((RDSR + portp->uartaddr), ioaddr); - insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); - portp->stats.rxlost += len; - portp->stats.rxtotal += len; - } else { - len = MIN(len, buflen); - if (len > 0) { - outb((RDSR + portp->uartaddr), ioaddr); - insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; - tty_schedule_flip(tty); - portp->stats.rxtotal += len; - } - } - } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) { - outb((RDSR + portp->uartaddr), ioaddr); - status = inb(ioaddr + EREG_DATA); - ch = inb(ioaddr + EREG_DATA); - if (status & ST_PARITY) - portp->stats.rxparity++; - if (status & ST_FRAMING) - portp->stats.rxframing++; - if (status & ST_OVERRUN) - portp->stats.rxoverrun++; - if (status & ST_BREAK) - portp->stats.rxbreaks++; - if (status & ST_SCHARMASK) { - if ((status & ST_SCHARMASK) == ST_SCHAR1) - portp->stats.txxon++; - if ((status & ST_SCHARMASK) == ST_SCHAR2) - portp->stats.txxoff++; - goto stl_rxalldone; - } - if ((tty != (struct tty_struct *) NULL) && - ((portp->rxignoremsk & status) == 0)) { - if (portp->rxmarkmsk & status) { - if (status & ST_BREAK) { - status = TTY_BREAK; - if (portp->flags & ASYNC_SAK) { - do_SAK(tty); - BRDENABLE(portp->brdnr, portp->pagenr); - } - } else if (status & ST_PARITY) { - status = TTY_PARITY; - } else if (status & ST_FRAMING) { - status = TTY_FRAME; - } else if(status & ST_OVERRUN) { - status = TTY_OVERRUN; - } else { - status = 0; - } - } else { - status = 0; - } - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - } - tty_schedule_flip(tty); - } - } - } else { - printk("STALLION: bad RX interrupt ack value=%x\n", ioack); - return; - } - -stl_rxalldone: - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); -} - -/*****************************************************************************/ - -/* - * Modem interrupt handler. The is called when the modem signal line - * (DCD) has changed state. Leave most of the work to the off-level - * processing routine. - */ - -static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - unsigned int ioack; - unsigned char misr; - -#if DEBUG - printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp); -#endif - - ioack = inb(ioaddr + EREG_MDACK); - if (((ioack & panelp->ackmask) != 0) || - ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) { - printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - - outb((MISR + portp->uartaddr), ioaddr); - misr = inb(ioaddr + EREG_DATA); - if (misr & MISR_DCD) { - set_bit(ASYI_DCDCHANGE, &portp->istate); - queue_task(&portp->tqueue, &tq_scheduler); - portp->stats.modem++; - } - - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); -} - -/*****************************************************************************/ -/* SC26198 HARDWARE FUNCTIONS */ -/*****************************************************************************/ - -/* - * These functions get/set/update the registers of the sc26198 UARTs. - * Access to the sc26198 registers is via an address/data io port pair. - * (Maybe should make this inline...) - */ - -static int stl_sc26198getreg(stlport_t *portp, int regnr) -{ - outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); - return(inb(portp->ioaddr + XP_DATA)); -} - -static void stl_sc26198setreg(stlport_t *portp, int regnr, int value) -{ - outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); - outb(value, (portp->ioaddr + XP_DATA)); -} - -static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) -{ - outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); - if (inb(portp->ioaddr + XP_DATA) != value) { - outb(value, (portp->ioaddr + XP_DATA)); - return(1); - } - return(0); -} - -/*****************************************************************************/ - -/* - * Functions to get and set the sc26198 global registers. - */ - -static int stl_sc26198getglobreg(stlport_t *portp, int regnr) -{ - outb(regnr, (portp->ioaddr + XP_ADDR)); - return(inb(portp->ioaddr + XP_DATA)); -} - -#if 0 -static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) -{ - outb(regnr, (portp->ioaddr + XP_ADDR)); - outb(value, (portp->ioaddr + XP_DATA)); -} -#endif - -/*****************************************************************************/ - -/* - * Inbitialize the UARTs in a panel. We don't care what sort of board - * these ports are on - since the port io registers are almost - * identical when dealing with ports. - */ - -static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) -{ - int chipmask, i; - int nrchips, ioaddr; - -#if DEBUG - printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n", - (int) brdp, (int) panelp); -#endif - - BRDENABLE(panelp->brdnr, panelp->pagenr); - -/* - * Check that each chip is present and started up OK. - */ - chipmask = 0; - nrchips = (panelp->nrports + 4) / SC26198_PORTS; - if (brdp->brdtype == BRD_ECHPCI) - outb(panelp->pagenr, brdp->ioctrl); - - for (i = 0; (i < nrchips); i++) { - ioaddr = panelp->iobase + (i * 4); - outb(SCCR, (ioaddr + XP_ADDR)); - outb(CR_RESETALL, (ioaddr + XP_DATA)); - outb(TSTR, (ioaddr + XP_ADDR)); - if (inb(ioaddr + XP_DATA) != 0) { - printk("STALLION: sc26198 not responding, " - "brd=%d panel=%d chip=%d\n", - panelp->brdnr, panelp->panelnr, i); - continue; - } - chipmask |= (0x1 << i); - outb(GCCR, (ioaddr + XP_ADDR)); - outb(GCCR_IVRTYPCHANACK, (ioaddr + XP_DATA)); - outb(WDTRCR, (ioaddr + XP_ADDR)); - outb(0xff, (ioaddr + XP_DATA)); - } - - BRDDISABLE(panelp->brdnr); - return(chipmask); -} - -/*****************************************************************************/ - -/* - * Initialize hardware specific port registers. - */ - -static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) -{ -#if DEBUG - printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n", - (int) brdp, (int) panelp, (int) portp); -#endif - - if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || - (portp == (stlport_t *) NULL)) - return; - - portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4); - portp->uartaddr = (portp->portnr & 0x07) << 4; - portp->pagenr = panelp->pagenr; - portp->hwid = 0x1; - - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, IOPCR, IOPCR_SETSIGS); - BRDDISABLE(portp->brdnr); -} - -/*****************************************************************************/ - -/* - * Set up the sc26198 registers for a port based on the termios port - * settings. - */ - -static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) -{ - stlbrd_t *brdp; - unsigned long flags; - unsigned int baudrate; - unsigned char mr0, mr1, mr2, clk; - unsigned char imron, imroff, iopr, ipr; - - mr0 = 0; - mr1 = 0; - mr2 = 0; - clk = 0; - iopr = 0; - imron = 0; - imroff = 0; - - brdp = stl_brds[portp->brdnr]; - if (brdp == (stlbrd_t *) NULL) - return; - -/* - * Set up the RX char ignore mask with those RX error types we - * can ignore. - */ - portp->rxignoremsk = 0; - if (tiosp->c_iflag & IGNPAR) - portp->rxignoremsk |= (SR_RXPARITY | SR_RXFRAMING | - SR_RXOVERRUN); - if (tiosp->c_iflag & IGNBRK) - portp->rxignoremsk |= SR_RXBREAK; - - portp->rxmarkmsk = SR_RXOVERRUN; - if (tiosp->c_iflag & (INPCK | PARMRK)) - portp->rxmarkmsk |= (SR_RXPARITY | SR_RXFRAMING); - if (tiosp->c_iflag & BRKINT) - portp->rxmarkmsk |= SR_RXBREAK; - -/* - * Go through the char size, parity and stop bits and set all the - * option register appropriately. - */ - switch (tiosp->c_cflag & CSIZE) { - case CS5: - mr1 |= MR1_CS5; - break; - case CS6: - mr1 |= MR1_CS6; - break; - case CS7: - mr1 |= MR1_CS7; - break; - default: - mr1 |= MR1_CS8; - break; - } - - if (tiosp->c_cflag & CSTOPB) - mr2 |= MR2_STOP2; - else - mr2 |= MR2_STOP1; - - if (tiosp->c_cflag & PARENB) { - if (tiosp->c_cflag & PARODD) - mr1 |= (MR1_PARENB | MR1_PARODD); - else - mr1 |= (MR1_PARENB | MR1_PAREVEN); - } else { - mr1 |= MR1_PARNONE; - } - - mr1 |= MR1_ERRBLOCK; - -/* - * Set the RX FIFO threshold at 8 chars. This gives a bit of breathing - * space for hardware flow control and the like. This should be set to - * VMIN. - */ - mr2 |= MR2_RXFIFOHALF; - -/* - * Calculate the baud rate timers. For now we will just assume that - * the input and output baud are the same. The sc26198 has a fixed - * baud rate table, so only discrete baud rates possible. - */ - baudrate = tiosp->c_cflag & CBAUD; - if (baudrate & CBAUDEX) { - baudrate &= ~CBAUDEX; - if ((baudrate < 1) || (baudrate > 4)) - tiosp->c_cflag &= ~CBAUDEX; - else - baudrate += 15; - } - baudrate = stl_baudrates[baudrate]; - if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - baudrate = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - baudrate = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) - baudrate = (portp->baud_base / portp->custom_divisor); - } - if (baudrate > STL_SC26198MAXBAUD) - baudrate = STL_SC26198MAXBAUD; - - if (baudrate > 0) { - for (clk = 0; (clk < SC26198_NRBAUDS); clk++) { - if (baudrate <= sc26198_baudtable[clk]) - break; - } - } - -/* - * Check what form of modem signaling is required and set it up. - */ - if (tiosp->c_cflag & CLOCAL) { - portp->flags &= ~ASYNC_CHECK_CD; - } else { - iopr |= IOPR_DCDCOS; - imron |= IR_IOPORT; - portp->flags |= ASYNC_CHECK_CD; - } - -/* - * Setup sc26198 enhanced modes if we can. In particular we want to - * handle as much of the flow control as possible automatically. As - * well as saving a few CPU cycles it will also greatly improve flow - * control reliability. - */ - if (tiosp->c_iflag & IXON) { - mr0 |= MR0_SWFTX | MR0_SWFT; - imron |= IR_XONXOFF; - } else { - imroff |= IR_XONXOFF; - } - if (tiosp->c_iflag & IXOFF) - mr0 |= MR0_SWFRX; - - if (tiosp->c_cflag & CRTSCTS) { - mr2 |= MR2_AUTOCTS; - mr1 |= MR1_AUTORTS; - } - -/* - * All sc26198 register values calculated so go through and set - * them all up. - */ - -#if DEBUG - printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", - portp->portnr, portp->panelnr, portp->brdnr); - printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk); - printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff); - printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, IMR, 0); - stl_sc26198updatereg(portp, MR0, mr0); - stl_sc26198updatereg(portp, MR1, mr1); - stl_sc26198setreg(portp, SCCR, CR_RXERRBLOCK); - stl_sc26198updatereg(portp, MR2, mr2); - stl_sc26198updatereg(portp, IOPIOR, - ((stl_sc26198getreg(portp, IOPIOR) & ~IPR_CHANGEMASK) | iopr)); - - if (baudrate > 0) { - stl_sc26198setreg(portp, TXCSR, clk); - stl_sc26198setreg(portp, RXCSR, clk); - } - - stl_sc26198setreg(portp, XONCR, tiosp->c_cc[VSTART]); - stl_sc26198setreg(portp, XOFFCR, tiosp->c_cc[VSTOP]); - - ipr = stl_sc26198getreg(portp, IPR); - if (ipr & IPR_DCD) - portp->sigs &= ~TIOCM_CD; - else - portp->sigs |= TIOCM_CD; - - portp->imr = (portp->imr & ~imroff) | imron; - stl_sc26198setreg(portp, IMR, portp->imr); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Set the state of the DTR and RTS signals. - */ - -static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) -{ - unsigned char iopioron, iopioroff; - unsigned long flags; - -#if DEBUG - printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n", - (int) portp, dtr, rts); -#endif - - iopioron = 0; - iopioroff = 0; - if (dtr == 0) - iopioroff |= IPR_DTR; - else if (dtr > 0) - iopioron |= IPR_DTR; - if (rts == 0) - iopioroff |= IPR_RTS; - else if (rts > 0) - iopioron |= IPR_RTS; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, IOPIOR, - ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Return the state of the signals. - */ - -static int stl_sc26198getsignals(stlport_t *portp) -{ - unsigned char ipr; - unsigned long flags; - int sigs; - -#if DEBUG - printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - ipr = stl_sc26198getreg(portp, IPR); - BRDDISABLE(portp->brdnr); - restore_flags(flags); - - sigs = 0; - sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; - sigs |= (ipr & IPR_CTS) ? 0 : TIOCM_CTS; - sigs |= (ipr & IPR_DTR) ? 0: TIOCM_DTR; - sigs |= (ipr & IPR_RTS) ? 0: TIOCM_RTS; - sigs |= TIOCM_DSR; - return(sigs); -} - -/*****************************************************************************/ - -/* - * Enable/Disable the Transmitter and/or Receiver. - */ - -static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char ccr; - unsigned long flags; - -#if DEBUG - printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif - - ccr = portp->crenable; - if (tx == 0) - ccr &= ~CR_TXENABLE; - else if (tx > 0) - ccr |= CR_TXENABLE; - if (rx == 0) - ccr &= ~CR_RXENABLE; - else if (rx > 0) - ccr |= CR_RXENABLE; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, SCCR, ccr); - BRDDISABLE(portp->brdnr); - portp->crenable = ccr; - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Start/stop the Transmitter and/or Receiver. - */ - -static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char imr; - unsigned long flags; - -#if DEBUG - printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif - - imr = portp->imr; - if (tx == 0) - imr &= ~IR_TXRDY; - else if (tx == 1) - imr |= IR_TXRDY; - if (rx == 0) - imr &= ~(IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG); - else if (rx > 0) - imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, IMR, imr); - BRDDISABLE(portp->brdnr); - portp->imr = imr; - if (tx > 0) - set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Disable all interrupts from this port. - */ - -static void stl_sc26198disableintrs(stlport_t *portp) -{ - unsigned long flags; - -#if DEBUG - printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - portp->imr = 0; - stl_sc26198setreg(portp, IMR, 0); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -static void stl_sc26198sendbreak(stlport_t *portp, int len) -{ - unsigned long flags; - -#if DEBUG - printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - if (len == 1) { - stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); - portp->stats.txbreaks++; - } else { - stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); - } - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Take flow control actions... - */ - -static void stl_sc26198flowctrl(stlport_t *portp, int state) -{ - struct tty_struct *tty; - unsigned long flags; - unsigned char mr0; - -#if DEBUG - printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state); -#endif - - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - - if (state) { - if (tty->termios->c_iflag & IXOFF) { - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); - mr0 |= MR0_SWFRX; - portp->stats.rxxon++; - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - } -/* - * Question: should we return RTS to what it was before? It may - * have been set by an ioctl... Suppose not, since if you have - * hardware flow control set then it is pretty silly to go and - * set the RTS line by hand. - */ - if (tty->termios->c_cflag & CRTSCTS) { - stl_sc26198setreg(portp, MR1, - (stl_sc26198getreg(portp, MR1) | MR1_AUTORTS)); - stl_sc26198setreg(portp, IOPIOR, - (stl_sc26198getreg(portp, IOPIOR) | IOPR_RTS)); - portp->stats.rxrtson++; - } - } else { - if (tty->termios->c_iflag & IXOFF) { - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); - mr0 &= ~MR0_SWFRX; - portp->stats.rxxoff++; - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - } - if (tty->termios->c_cflag & CRTSCTS) { - stl_sc26198setreg(portp, MR1, - (stl_sc26198getreg(portp, MR1) & ~MR1_AUTORTS)); - stl_sc26198setreg(portp, IOPIOR, - (stl_sc26198getreg(portp, IOPIOR) & ~IOPR_RTS)); - portp->stats.rxrtsoff++; - } - } - - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Send a flow control character. - */ - -static void stl_sc26198sendflow(stlport_t *portp, int state) -{ - struct tty_struct *tty; - unsigned long flags; - unsigned char mr0; - -#if DEBUG - printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state); -#endif - - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - if (state) { - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); - mr0 |= MR0_SWFRX; - portp->stats.rxxon++; - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - } else { - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); - mr0 &= ~MR0_SWFRX; - portp->stats.rxxoff++; - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - } - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -static void stl_sc26198flush(stlport_t *portp) -{ - unsigned long flags; - -#if DEBUG - printk("stl_sc26198flush(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, SCCR, CR_TXRESET); - stl_sc26198setreg(portp, SCCR, portp->crenable); - BRDDISABLE(portp->brdnr); - portp->tx.tail = portp->tx.head; - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Return the current state of data flow on this port. This is only - * really interresting when determining if data has fully completed - * transmission or not... The sc26198 interrupt scheme cannot - * determine when all data has actually drained, so we need to - * check the port statusy register to be sure. - */ - -static int stl_sc26198datastate(stlport_t *portp) -{ - unsigned long flags; - unsigned char sr; - -#if DEBUG - printk("stl_sc26198datastate(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return(0); - if (test_bit(ASYI_TXBUSY, &portp->istate)) - return(1); - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - sr = stl_sc26198getreg(portp, SR); - BRDDISABLE(portp->brdnr); - restore_flags(flags); - - return((sr & SR_TXEMPTY) ? 0 : 1); -} - -/*****************************************************************************/ - -/* - * Delay for a small amount of time, to give the sc26198 a chance - * to process a command... - */ - -static void stl_sc26198wait(stlport_t *portp) -{ - int i; - -#if DEBUG - printk("stl_sc26198wait(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return; - - for (i = 0; (i < 20); i++) - stl_sc26198getglobreg(portp, TSTR); -} - -/*****************************************************************************/ - -/* - * If we are TX flow controlled and in IXANY mode then we may - * need to unflow control here. We gotta do this because of the - * automatic flow control modes of the sc26198. - */ - -static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) -{ - unsigned char mr0; - - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_HOSTXON); - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - clear_bit(ASYI_TXFLOWED, &portp->istate); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for sc26198 panels. - */ - -static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) -{ - stlport_t *portp; - unsigned int iack; - -/* - * Work around bug in sc26198 chip... Cannot have A6 address - * line of UART high, else iack will be returned as 0. - */ - outb(0, (iobase + 1)); - - iack = inb(iobase + XP_IACK); - portp = panelp->ports[(iack & IVR_CHANMASK) + ((iobase & 0x4) << 1)]; - - if (iack & IVR_RXDATA) - stl_sc26198rxisr(portp, iack); - else if (iack & IVR_TXDATA) - stl_sc26198txisr(portp); - else - stl_sc26198otherisr(portp, iack); -} - -/*****************************************************************************/ - -/* - * Transmit interrupt handler. This has gotta be fast! Handling TX - * chars is pretty simple, stuff as many as possible from the TX buffer - * into the sc26198 FIFO. - * In practice it is possible that interrupts are enabled but that the - * port has been hung up. Need to handle not having any TX buffer here, - * this is done by using the side effect that head and tail will also - * be NULL if the buffer has been freed. - */ - -static void stl_sc26198txisr(stlport_t *portp) -{ - unsigned int ioaddr; - unsigned char mr0; - int len, stlen; - char *head, *tail; - -#if DEBUG - printk("stl_sc26198txisr(portp=%x)\n", (int) portp); -#endif - - ioaddr = portp->ioaddr; - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); - if ((len == 0) || ((len < STL_TXBUFLOW) && - (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { - set_bit(ASYI_TXLOW, &portp->istate); - queue_task(&portp->tqueue, &tq_scheduler); - } - - if (len == 0) { - outb((MR0 | portp->uartaddr), (ioaddr + XP_ADDR)); - mr0 = inb(ioaddr + XP_DATA); - if ((mr0 & MR0_TXMASK) == MR0_TXEMPTY) { - portp->imr &= ~IR_TXRDY; - outb((IMR | portp->uartaddr), (ioaddr + XP_ADDR)); - outb(portp->imr, (ioaddr + XP_DATA)); - clear_bit(ASYI_TXBUSY, &portp->istate); - } else { - mr0 |= ((mr0 & ~MR0_TXMASK) | MR0_TXEMPTY); - outb(mr0, (ioaddr + XP_DATA)); - } - } else { - len = MIN(len, SC26198_TXFIFOSIZE); - portp->stats.txtotal += len; - stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); - outb(GTXFIFO, (ioaddr + XP_ADDR)); - outsb((ioaddr + XP_DATA), tail, stlen); - len -= stlen; - tail += stlen; - if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) - tail = portp->tx.buf; - if (len > 0) { - outsb((ioaddr + XP_DATA), tail, len); - tail += len; - } - portp->tx.tail = tail; - } -} - -/*****************************************************************************/ - -/* - * Receive character interrupt handler. Determine if we have good chars - * or bad chars and then process appropriately. Good chars are easy - * just shove the lot into the RX buffer and set all status byte to 0. - * If a bad RX char then process as required. This routine needs to be - * fast! In practice it is possible that we get an interrupt on a port - * that is closed. This can happen on hangups - since they completely - * shutdown a port not in user context. Need to handle this case. - */ - -static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) -{ - struct tty_struct *tty; - unsigned int len, buflen, ioaddr; - -#if DEBUG - printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack); -#endif - - tty = portp->tty; - ioaddr = portp->ioaddr; - outb(GIBCR, (ioaddr + XP_ADDR)); - len = inb(ioaddr + XP_DATA) + 1; - - if ((iack & IVR_TYPEMASK) == IVR_RXDATA) { - if ((tty == (struct tty_struct *) NULL) || - (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { - len = MIN(len, sizeof(stl_unwanted)); - outb(GRXFIFO, (ioaddr + XP_ADDR)); - insb((ioaddr + XP_DATA), &stl_unwanted[0], len); - portp->stats.rxlost += len; - portp->stats.rxtotal += len; - } else { - len = MIN(len, buflen); - if (len > 0) { - outb(GRXFIFO, (ioaddr + XP_ADDR)); - insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; - tty_schedule_flip(tty); - portp->stats.rxtotal += len; - } - } - } else { - stl_sc26198rxbadchars(portp); - } - -/* - * If we are TX flow controlled and in IXANY mode then we may need - * to unflow control here. We gotta do this because of the automatic - * flow control modes of the sc26198. - */ - if (test_bit(ASYI_TXFLOWED, &portp->istate)) { - if ((tty != (struct tty_struct *) NULL) && - (tty->termios != (struct termios *) NULL) && - (tty->termios->c_iflag & IXANY)) { - stl_sc26198txunflow(portp, tty); - } - } -} - -/*****************************************************************************/ - -/* - * Process an RX bad character. - */ - -static void inline stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch) -{ - struct tty_struct *tty; - unsigned int ioaddr; - - tty = portp->tty; - ioaddr = portp->ioaddr; - - if (status & SR_RXPARITY) - portp->stats.rxparity++; - if (status & SR_RXFRAMING) - portp->stats.rxframing++; - if (status & SR_RXOVERRUN) - portp->stats.rxoverrun++; - if (status & SR_RXBREAK) - portp->stats.rxbreaks++; - - if ((tty != (struct tty_struct *) NULL) && - ((portp->rxignoremsk & status) == 0)) { - if (portp->rxmarkmsk & status) { - if (status & SR_RXBREAK) { - status = TTY_BREAK; - if (portp->flags & ASYNC_SAK) { - do_SAK(tty); - BRDENABLE(portp->brdnr, portp->pagenr); - } - } else if (status & SR_RXPARITY) { - status = TTY_PARITY; - } else if (status & SR_RXFRAMING) { - status = TTY_FRAME; - } else if(status & SR_RXOVERRUN) { - status = TTY_OVERRUN; - } else { - status = 0; - } - } else { - status = 0; - } - - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - } - tty_schedule_flip(tty); - } - - if (status == 0) - portp->stats.rxtotal++; - } -} - -/*****************************************************************************/ - -/* - * Process all characters in the RX FIFO of the UART. Check all char - * status bytes as well, and process as required. We need to check - * all bytes in the FIFO, in case some more enter the FIFO while we - * are here. To get the exact character error type we need to switch - * into CHAR error mode (that is why we need to make sure we empty - * the FIFO). - */ - -static void stl_sc26198rxbadchars(stlport_t *portp) -{ - unsigned char status, mr1; - char ch; - -/* - * To get the precise error type for each character we must switch - * back into CHAR error mode. - */ - mr1 = stl_sc26198getreg(portp, MR1); - stl_sc26198setreg(portp, MR1, (mr1 & ~MR1_ERRBLOCK)); - - while ((status = stl_sc26198getreg(portp, SR)) & SR_RXRDY) { - stl_sc26198setreg(portp, SCCR, CR_CLEARRXERR); - ch = stl_sc26198getreg(portp, RXFIFO); - stl_sc26198rxbadch(portp, status, ch); - } - -/* - * To get correct interrupt class we must switch back into BLOCK - * error mode. - */ - stl_sc26198setreg(portp, MR1, mr1); -} - -/*****************************************************************************/ - -/* - * Other interrupt handler. This includes modem signals, flow - * control actions, etc. Most stuff is left to off-level interrupt - * processing time. - */ - -static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack) -{ - unsigned char cir, ipr, xisr; - -#if DEBUG - printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack); -#endif - - cir = stl_sc26198getglobreg(portp, CIR); - - switch (cir & CIR_SUBTYPEMASK) { - case CIR_SUBCOS: - ipr = stl_sc26198getreg(portp, IPR); - if (ipr & IPR_DCDCHANGE) { - set_bit(ASYI_DCDCHANGE, &portp->istate); - queue_task(&portp->tqueue, &tq_scheduler); - portp->stats.modem++; - } - break; - case CIR_SUBXONXOFF: - xisr = stl_sc26198getreg(portp, XISR); - if (xisr & XISR_RXXONGOT) { - set_bit(ASYI_TXFLOWED, &portp->istate); - portp->stats.txxoff++; - } - if (xisr & XISR_RXXOFFGOT) { - clear_bit(ASYI_TXFLOWED, &portp->istate); - portp->stats.txxon++; - } - break; - case CIR_SUBBREAK: - stl_sc26198setreg(portp, SCCR, CR_BREAKRESET); - stl_sc26198rxbadchars(portp); - break; - default: - break; - } -} - -/*****************************************************************************/ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c --- v2.4.0-test7/linux/drivers/media/video/zr36120.c Wed Aug 23 18:36:37 2000 +++ linux/drivers/media/video/zr36120.c Tue Aug 29 14:09:15 2000 @@ -1242,7 +1242,8 @@ case VIDIOCCAPTURE: { int v; - get_user_ret(v,(int*)arg, -EFAULT); + if (get_user(v, (int *)arg)) + return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v)); if (v==0) { @@ -1314,7 +1315,8 @@ case VIDIOCSYNC: { int i; - get_user_ret(i,(int*)arg, -EFAULT); + if (get_user(i, (int *) arg)) + return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i)); if (i<0 || i>ZORAN_MAX_FBUFFERS) return -EINVAL; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v2.4.0-test7/linux/drivers/net/3c503.c Fri Jun 23 21:55:09 2000 +++ linux/drivers/net/3c503.c Tue Sep 5 12:57:51 2000 @@ -190,6 +190,9 @@ if (dev == NULL) { printk("3c503.c: Passed a NULL device.\n"); dev = init_etherdev(0, 0); + + if (!dev) + return -ENOMEM; } if (ei_debug && version_printed++ == 0) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c --- v2.4.0-test7/linux/drivers/net/ac3200.c Fri Jun 23 21:55:09 2000 +++ linux/drivers/net/ac3200.c Tue Sep 5 12:56:51 2000 @@ -139,6 +139,9 @@ if (dev == NULL) { printk("ac3200.c: Passed a NULL device.\n"); dev = init_etherdev(0, 0); + + if (!dev) + return -ENOMEM; } printk("AC3200 in EISA slot %d, node", ioaddr/0x1000); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.4.0-test7/linux/drivers/net/defxx.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/net/defxx.c Tue Sep 5 12:57:51 2000 @@ -194,6 +194,7 @@ * Mar 2000 AC Did various cleanups for 2.3.x * Jun 2000 jgarzik PCI and resource alloc cleanups * Jul 2000 tjeerd Much cleanup and some bug fixes + * Sep 2000 tjeerd Fix leak on unload, cosmetic code cleanup */ /* Include files */ @@ -224,7 +225,7 @@ /* Version information string - should be updated prior to each new release!!! */ static char version[] __devinitdata = - "defxx.c:v1.05c 2000/07/14 Lawrence V. Stefani and others\n"; + "defxx.c:v1.05d 2000/09/05 Lawrence V. Stefani and others\n"; #define DYNAMIC_BUFFERS 1 @@ -891,7 +892,7 @@ #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); - top_v = (char *) kmalloc(alloc_size, GFP_KERNEL); + bp->kmalloced = top_v = (char *) kmalloc(alloc_size, GFP_KERNEL); if (top_v == NULL) { printk("%s: Could not allocate memory for host buffers and structures!\n", dev->name); @@ -957,7 +958,7 @@ DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n", dev->name, (long)bp->cmd_req_virt, bp->cmd_req_phys); DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n", dev->name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys); DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->rcv_block_virt, bp->rcv_block_phys); - DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->cons_block_virt, bp->cons_block_phys); + DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->cons_block_virt, bp->cons_block_phys); return(DFX_K_SUCCESS); } @@ -3259,10 +3260,13 @@ return; } -static void __devexit dfx_remove_device(struct pci_dev *pdev, struct net_device *dev) +static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev) { + DFX_board_t *bp = (DFX_board_t*)dev->priv; + unregister_netdev(dev); release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN ); + if (bp->kmalloced) kfree(bp->kmalloced); kfree(dev); } @@ -3270,7 +3274,7 @@ { struct net_device *dev = pdev->driver_data; - dfx_remove_device(pdev, dev); + dfx_remove_one_pci_or_eisa(pdev, dev); } static struct pci_device_id dfx_pci_tbl[] __devinitdata = { @@ -3301,7 +3305,7 @@ bp = (DFX_board_t*)dev->priv; tmp = bp->next; - dfx_remove_device(NULL, dev); + dfx_remove_one_pci_or_eisa(NULL, dev); dev = tmp; } } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/defxx.h linux/drivers/net/defxx.h --- v2.4.0-test7/linux/drivers/net/defxx.h Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/defxx.h Tue Sep 5 12:57:51 2000 @@ -1469,9 +1469,9 @@ /* Define EISA controller register offsets */ -#define PI_ESIC_K_BURST_HOLDOFF 0x040 +#define PI_ESIC_K_BURST_HOLDOFF 0x040 #define PI_ESIC_K_SLOT_ID 0xC80 -#define PI_ESIC_K_SLOT_CNTRL 0xC84 +#define PI_ESIC_K_SLOT_CNTRL 0xC84 #define PI_ESIC_K_MEM_ADD_CMP_0 0xC85 #define PI_ESIC_K_MEM_ADD_CMP_1 0xC86 #define PI_ESIC_K_MEM_ADD_CMP_2 0xC87 @@ -1484,14 +1484,14 @@ #define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E #define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F #define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90 -#define PI_ESIC_K_IO_CMP_0_0 0xC91 -#define PI_ESIC_K_IO_CMP_0_1 0xC92 -#define PI_ESIC_K_IO_CMP_1_0 0xC93 -#define PI_ESIC_K_IO_CMP_1_1 0xC94 -#define PI_ESIC_K_IO_CMP_2_0 0xC95 -#define PI_ESIC_K_IO_CMP_2_1 0xC96 -#define PI_ESIC_K_IO_CMP_3_0 0xC97 -#define PI_ESIC_K_IO_CMP_3_1 0xC98 +#define PI_ESIC_K_IO_CMP_0_0 0xC91 +#define PI_ESIC_K_IO_CMP_0_1 0xC92 +#define PI_ESIC_K_IO_CMP_1_0 0xC93 +#define PI_ESIC_K_IO_CMP_1_1 0xC94 +#define PI_ESIC_K_IO_CMP_2_0 0xC95 +#define PI_ESIC_K_IO_CMP_2_1 0xC96 +#define PI_ESIC_K_IO_CMP_3_0 0xC97 +#define PI_ESIC_K_IO_CMP_3_1 0xC98 #define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99 #define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A #define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B @@ -1500,21 +1500,21 @@ #define PI_ESIC_K_IO_ADD_MASK_2_1 0xC9E #define PI_ESIC_K_IO_ADD_MASK_3_0 0xC9F #define PI_ESIC_K_IO_ADD_MASK_3_1 0xCA0 -#define PI_ESIC_K_MOD_CONFIG_1 0xCA1 -#define PI_ESIC_K_MOD_CONFIG_2 0xCA2 -#define PI_ESIC_K_MOD_CONFIG_3 0xCA3 -#define PI_ESIC_K_MOD_CONFIG_4 0xCA4 -#define PI_ESIC_K_MOD_CONFIG_5 0xCA5 -#define PI_ESIC_K_MOD_CONFIG_6 0xCA6 -#define PI_ESIC_K_MOD_CONFIG_7 0xCA7 +#define PI_ESIC_K_MOD_CONFIG_1 0xCA1 +#define PI_ESIC_K_MOD_CONFIG_2 0xCA2 +#define PI_ESIC_K_MOD_CONFIG_3 0xCA3 +#define PI_ESIC_K_MOD_CONFIG_4 0xCA4 +#define PI_ESIC_K_MOD_CONFIG_5 0xCA5 +#define PI_ESIC_K_MOD_CONFIG_6 0xCA6 +#define PI_ESIC_K_MOD_CONFIG_7 0xCA7 #define PI_ESIC_K_DIP_SWITCH 0xCA8 #define PI_ESIC_K_IO_CONFIG_STAT_0 0xCA9 #define PI_ESIC_K_IO_CONFIG_STAT_1 0xCAA #define PI_ESIC_K_DMA_CONFIG 0xCAB #define PI_ESIC_K_INPUT_PORT 0xCAC #define PI_ESIC_K_OUTPUT_PORT 0xCAD -#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE -#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */ +#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE +#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */ /* Define the value all drivers must write to the function control register. */ @@ -1524,7 +1524,7 @@ #define PI_SLOT_CNTRL_M_RESET 0x04 /* Don't use. */ #define PI_SLOT_CNTRL_M_ERROR 0x02 /* Not implemented. */ -#define PI_SLOT_CNTRL_M_ENB 0x01 /* Must be set. */ +#define PI_SLOT_CNTRL_M_ENB 0x01 /* Must be set. */ /* Define the bits in the burst holdoff register. */ @@ -1590,24 +1590,24 @@ #define PFI_K_REG_RESERVED_0 0X00000038 #define PFI_K_REG_RESERVED_1 0X0000003C -#define PFI_K_REG_MODE_CTRL 0X00000040 -#define PFI_K_REG_STATUS 0X00000044 +#define PFI_K_REG_MODE_CTRL 0X00000040 +#define PFI_K_REG_STATUS 0X00000044 #define PFI_K_REG_FIFO_WRITE 0X00000048 -#define PFI_K_REG_FIFO_READ 0X0000004C +#define PFI_K_REG_FIFO_READ 0X0000004C /* PFI Mode Control Register Constants */ -#define PFI_MODE_M_RESERVED 0XFFFFFFF0 +#define PFI_MODE_M_RESERVED 0XFFFFFFF0 #define PFI_MODE_M_TGT_ABORT_ENB 0X00000008 #define PFI_MODE_M_PDQ_INT_ENB 0X00000004 #define PFI_MODE_M_PFI_INT_ENB 0X00000002 -#define PFI_MODE_M_DMA_ENB 0X00000001 +#define PFI_MODE_M_DMA_ENB 0X00000001 -#define PFI_MODE_V_RESERVED 4 +#define PFI_MODE_V_RESERVED 4 #define PFI_MODE_V_TGT_ABORT_ENB 3 #define PFI_MODE_V_PDQ_INT_ENB 2 #define PFI_MODE_V_PFI_INT_ENB 1 -#define PFI_MODE_V_DMA_ENB 0 +#define PFI_MODE_V_DMA_ENB 0 #define PFI_MODE_K_ALL_DISABLE 0X00000000 @@ -1619,10 +1619,10 @@ #define PFI_STATUS_M_PDQ_DMA_ABORT 0X00000008 #define PFI_STATUS_M_FIFO_FULL 0X00000004 #define PFI_STATUS_M_FIFO_EMPTY 0X00000002 -#define PFI_STATUS_M_DMA_IN_PROGRESS 0X00000001 +#define PFI_STATUS_M_DMA_IN_PROGRESS 0X00000001 #define PFI_STATUS_V_RESERVED 6 -#define PFI_STATUS_V_PFI_ERROR 5 /* only valid in rev 1 or later PFI */ +#define PFI_STATUS_V_PFI_ERROR 5 /* only valid in rev 1 or later PFI */ #define PFI_STATUS_V_PDQ_INT 4 #define PFI_STATUS_V_PDQ_DMA_ABORT 3 #define PFI_STATUS_V_FIFO_FULL 2 @@ -1635,7 +1635,7 @@ #define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */ #define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */ -#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ +#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ #define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */ #define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */ #define DFX_PRH2_BYTE 0x00 /* Packet Request Header byte 2 */ @@ -1691,7 +1691,7 @@ /* Define constants for masking/unmasking interrupts */ #define DFX_MASK_INTERRUPTS 1 -#define DFX_UNMASK_INTERRUPTS 0 +#define DFX_UNMASK_INTERRUPTS 0 /* Define structure for driver transmit descriptor block */ @@ -1704,16 +1704,17 @@ { /* Keep virtual and physical pointers to locked, physically contiguous memory */ + char *kmalloced; /* kfree this on unload */ PI_DESCR_BLOCK *descr_block_virt; /* PDQ descriptor block virt address */ - u32 descr_block_phys; /* PDQ descriptor block phys address */ + u32 descr_block_phys; /* PDQ descriptor block phys address */ PI_DMA_CMD_REQ *cmd_req_virt; /* Command request buffer virt address */ - u32 cmd_req_phys; /* Command request buffer phys address */ + u32 cmd_req_phys; /* Command request buffer phys address */ PI_DMA_CMD_RSP *cmd_rsp_virt; /* Command response buffer virt address */ - u32 cmd_rsp_phys; /* Command response buffer phys address */ - char *rcv_block_virt; /* LLC host receive queue buf blk virt */ - u32 rcv_block_phys; /* LLC host receive queue buf blk phys */ + u32 cmd_rsp_phys; /* Command response buffer phys address */ + char *rcv_block_virt; /* LLC host receive queue buf blk virt */ + u32 rcv_block_phys; /* LLC host receive queue buf blk phys */ PI_CONSUMER_BLOCK *cons_block_virt; /* PDQ consumer block virt address */ - u32 cons_block_phys; /* PDQ consumer block phys address */ + u32 cons_block_phys; /* PDQ consumer block phys address */ /* Keep local copies of Type 1 and Type 2 register data */ @@ -1723,27 +1724,27 @@ /* Storage for unicast and multicast address entries in adapter CAM */ - u8 uc_table[1*FDDI_K_ALEN]; - u32 uc_count; /* number of unicast addresses */ - u8 mc_table[PI_CMD_ADDR_FILTER_K_SIZE*FDDI_K_ALEN]; - u32 mc_count; /* number of multicast addresses */ + u8 uc_table[1*FDDI_K_ALEN]; + u32 uc_count; /* number of unicast addresses */ + u8 mc_table[PI_CMD_ADDR_FILTER_K_SIZE*FDDI_K_ALEN]; + u32 mc_count; /* number of multicast addresses */ /* Current packet filter settings */ - u32 ind_group_prom; /* LLC individual & group frame prom mode */ - u32 group_prom; /* LLC group (multicast) frame prom mode */ + u32 ind_group_prom; /* LLC individual & group frame prom mode */ + u32 group_prom; /* LLC group (multicast) frame prom mode */ /* Link available flag needed to determine whether to drop outgoing packet requests */ - u32 link_available; /* is link available? */ + u32 link_available; /* is link available? */ /* Resources to indicate reset type when resetting adapter */ - u32 reset_type; /* skip or rerun diagnostics */ + u32 reset_type; /* skip or rerun diagnostics */ /* Store pointers to receive buffers for queue processing code */ - char *p_rcv_buff_va[PI_RCV_DATA_K_NUM_ENTRIES]; + char *p_rcv_buff_va[PI_RCV_DATA_K_NUM_ENTRIES]; /* Store pointers to transmit buffers for transmit completion code */ @@ -1755,33 +1756,33 @@ /* Store device, bus-specific, and parameter information for this adapter */ - struct net_device *dev; /* pointer to device structure */ - struct net_device *next; - u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ - u16 base_addr; /* base I/O address (same as dev->base_addr) */ - struct pci_dev * pci_dev; - u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */ - u32 req_ttrt; /* requested TTRT value (in 80ns units) */ - u32 burst_size; /* adapter burst size (enumerated) */ - u32 rcv_bufs_to_post; /* receive buffers to post for LLC host queue */ - u8 factory_mac_addr[FDDI_K_ALEN]; /* factory (on-board) MAC address */ + struct net_device *dev; /* pointer to device structure */ + struct net_device *next; + u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ + u16 base_addr; /* base I/O address (same as dev->base_addr) */ + struct pci_dev * pci_dev; + u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */ + u32 req_ttrt; /* requested TTRT value (in 80ns units) */ + u32 burst_size; /* adapter burst size (enumerated) */ + u32 rcv_bufs_to_post; /* receive buffers to post for LLC host queue */ + u8 factory_mac_addr[FDDI_K_ALEN]; /* factory (on-board) MAC address */ /* Common FDDI statistics structure and private counters */ struct fddi_statistics stats; - u32 rcv_discards; - u32 rcv_crc_errors; - u32 rcv_frame_status_errors; - u32 rcv_length_errors; - u32 rcv_total_frames; - u32 rcv_multicast_frames; - u32 rcv_total_bytes; - - u32 xmt_discards; - u32 xmt_length_errors; - u32 xmt_total_frames; - u32 xmt_total_bytes; + u32 rcv_discards; + u32 rcv_crc_errors; + u32 rcv_frame_status_errors; + u32 rcv_length_errors; + u32 rcv_total_frames; + u32 rcv_multicast_frames; + u32 rcv_total_bytes; + + u32 xmt_discards; + u32 xmt_length_errors; + u32 xmt_total_frames; + u32 xmt_total_bytes; } DFX_board_t; #endif /* #ifndef _DEFXX_H_ */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.4.0-test7/linux/drivers/net/epic100.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/net/epic100.c Wed Sep 6 11:40:33 2000 @@ -199,7 +199,8 @@ static struct pci_device_id epic_pci_tbl[] __devinitdata = { { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 }, { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 }, - { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C175 }, + { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, SMSC_83C175 }, { 0,} }; MODULE_DEVICE_TABLE (pci, epic_pci_tbl); @@ -401,6 +402,12 @@ dev->base_addr = ioaddr; dev->irq = pdev->irq; + + ep = dev->priv; + ep->pci_dev = pdev; + ep->chip_flags = ci->drv_flags; + spin_lock_init (&ep->lock); + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, ci->name, ioaddr, dev->irq); @@ -430,10 +437,6 @@ i % 16 == 15 ? "\n" : ""); } - ep = dev->priv; - ep->pci_dev = pdev; - ep->chip_flags = ci->drv_flags; - /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes much time and no cards have external MII. */ @@ -486,11 +489,13 @@ return 0; +err_out_iounmap: #ifndef USE_IO_OPS + iounmap ((void*) ioaddr); err_out_free_mmio: +#endif release_mem_region (pci_resource_start (pdev, 1), pci_resource_len (pdev, 1)); -#endif err_out_free_pio: release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); @@ -936,8 +941,7 @@ long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; - if (!spin_trylock(&ep->lock)) - return; + spin_lock(&ep->lock); do { status = inl(ioaddr + INTSTAT); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c --- v2.4.0-test7/linux/drivers/net/natsemi.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/net/natsemi.c Tue Sep 5 12:57:51 2000 @@ -17,6 +17,14 @@ Support information and updates available at http://www.scyld.com/network/netsemi.html + + + Linux kernel modifications: + + Version 1.0.1: + - Spinlock fixes + - Bug fixes and better intr performance (Tjeerd) + */ /* These identify the driver base version and may not be removed. */ @@ -25,7 +33,7 @@ static const char version2[] = " http://www.scyld.com/network/natsemi.html\n"; static const char version3[] = -" (unofficial 2.4.x kernel port, version 1.0.0, August 10, 2000)\n"; +" (unofficial 2.4.x kernel port, version 1.0.1, September 5, 2000 Jeff Garzik, Tjeerd Mulder)\n"; /* Updated to recommendations in pci-skeleton v2.03. */ /* Automatically extracted configuration info: @@ -193,7 +201,8 @@ http://www.scyld.com/expert/100mbps.html http://www.scyld.com/expert/NWay.html -No NatSemi datasheet was publically available at the initial release date. +Datasheet is available from: +http://www.national.com/pf/DP/DP83815.html IVc. Errata @@ -237,7 +246,7 @@ ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C, IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18, TxRingPtr=0x20, TxConfig=0x24, - RxRingPtr=0x30, RxConfig=0x34, + RxRingPtr=0x30, RxConfig=0x34, ClkRun=0x3C, WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, @@ -259,15 +268,19 @@ WOLPkt=0x2000, RxResetDone=0x1000000, TxResetDone=0x2000000, IntrPCIErr=0x00f00000, - IntrNormalSummary=0x0251, IntrAbnormalSummary=0xCD20, + IntrAbnormalSummary=0xCD20, }; /* Bits in the RxMode register. */ enum rx_mode_bits { - AcceptErr=0x20, AcceptRunt=0x10, - AcceptBroadcast=0xC0000000, - AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000, - AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000, + EnableFilter = 0x80000000, + AcceptBroadcast = 0x40000000, + AcceptAllMulticast = 0x20000000, + AcceptAllPhys = 0x10000000, + AcceptMyPhys = 0x08000000, + AcceptMulticast = 0x00200000, + AcceptErr=0x20, /* these 2 are in another register */ + AcceptRunt=0x10,/* and are not used in this driver */ }; /* The Rx and Tx buffer descriptors. */ @@ -315,6 +328,8 @@ u32 rx_filter[16]; /* FIFO and PCI burst thresholds. */ int tx_config, rx_config; + /* original contents of ClkRun register */ + int SavedClkRun; /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ @@ -349,7 +364,7 @@ int i, option, irq = pdev->irq, chip_idx = ent->driver_data; static int find_cnt = -1; static int printed_version; - unsigned long ioaddr; + unsigned long ioaddr, iosize; const int pcibar = 1; /* PCI base address register */ if ((debug <= 1) && !printed_version++) @@ -359,6 +374,7 @@ find_cnt++; option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; ioaddr = pci_resource_start(pdev, pcibar); + iosize = pci_resource_len(pdev, pcibar); if (pci_enable_device(pdev)) return -EIO; @@ -371,15 +387,14 @@ { void *mmio; - if (request_mem_region(ioaddr, pci_resource_len (pdev, pcibar), - dev->name) == NULL) { + if (request_mem_region(ioaddr, iosize, dev->name) == NULL) { unregister_netdev(dev); kfree(dev); return -EBUSY; } - mmio = ioremap (ioaddr, pci_resource_len (pdev, pcibar)); + mmio = ioremap (ioaddr, iosize); if (!mmio) { - release_mem_region(ioaddr, pci_resource_len (pdev, pcibar)); + release_mem_region(ioaddr, iosize); unregister_netdev(dev); kfree(dev); return -ENOMEM; @@ -390,9 +405,9 @@ printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, natsemi_pci_info[chip_idx].name, ioaddr); - for (i = 0; i < 3; i++) + for (i = 0; i < ETH_ALEN/2; i++) ((u16 *)dev->dev_addr)[i] = be16_to_cpu(eeprom_read(ioaddr, i + 7)); - for (i = 0; i < 5; i++) + for (i = 0; i < ETH_ALEN-1; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); @@ -413,7 +428,8 @@ np->pci_dev = pdev; pdev->driver_data = dev; - np->iosize = pci_resource_len(pdev, pcibar); + np->iosize = iosize; + spin_lock_init(&np->lock); if (dev->mem_start) option = dev->mem_start; @@ -551,7 +567,7 @@ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); - for (i = 0; i < 6; i += 2) { + for (i = 0; i < ETH_ALEN; i += 2) { writel(i, ioaddr + RxFilterAddr); writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8), ioaddr + RxFilterData); @@ -560,21 +576,32 @@ /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ /* Configure for standard, in-spec Ethernet. */ - np->tx_config = 0x10800802; + np->tx_config = (1<<28) + /* Automatic transmit padding */ + (1<<23) + /* Excessive collision retry */ + (0x0<<20) + /* Max DMA burst = 512 byte */ + (8<<8) + /* fill threshold = 256 byte */ + 2; /* drain threshold = 64 byte */ writel(np->tx_config, ioaddr + TxConfig); - np->rx_config = 0x0020; + np->rx_config = (0x0<<20) /* Max DMA burst = 512 byte */ + + (0x8<<1); /* Drain Threshold = 64 byte */ writel(np->rx_config, ioaddr + RxConfig); if (dev->if_port == 0) dev->if_port = np->default_port; + /* Disable PME */ + np->SavedClkRun = readl(ioaddr + ClkRun); + writel(np->SavedClkRun & ~0x100, ioaddr + ClkRun); + netif_start_queue(dev); check_duplex(dev); set_rx_mode(dev); - /* Enable interrupts by setting the interrupt mask. */ - writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask); + /* Enable interrupts by setting the interrupt mask. + * We don't listen for TxDone interrupts and rely on TxIdle. */ + writel(IntrAbnormalSummary | IntrTxIdle | IntrRxIdle | IntrRxDone, + ioaddr + IntrMask); writel(1, ioaddr + IntrEnable); writel(RxOn | TxOn, ioaddr + ChipCmd); @@ -616,8 +643,8 @@ np->rx_config &= ~0x10000000; np->tx_config &= ~0xC0000000; } - writew(np->tx_config, ioaddr + TxConfig); - writew(np->rx_config, ioaddr + RxConfig); + writel(np->tx_config, ioaddr + TxConfig); + writel(np->rx_config, ioaddr + RxConfig); } } @@ -700,7 +727,7 @@ skb->dev = dev; /* Mark as being used by this device. */ np->rx_ring[i].addr = virt_to_le32desc(skb->tail); np->rx_ring[i].cmd_status = - cpu_to_le32(DescIntr | np->rx_buf_sz); + cpu_to_le32(np->rx_buf_sz); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -727,7 +754,7 @@ np->tx_skbuff[entry] = skb; np->tx_ring[entry].addr = virt_to_le32desc(skb->data); - np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len); + np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len); np->cur_tx++; /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ @@ -768,8 +795,7 @@ ioaddr = dev->base_addr; np = (struct netdev_private *)dev->priv; - if (!spin_trylock(&np->lock)) - return; + spin_lock(&np->lock); do { u32 intr_status = readl(ioaddr + IntrStatus); @@ -784,7 +810,7 @@ if (intr_status == 0) break; - if (intr_status & (IntrRxDone | IntrRxIntr)) + if (intr_status & (IntrRxDone | IntrRxErr | IntrRxIdle | IntrRxOverrun)) netdev_rx(dev); for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { @@ -805,7 +831,7 @@ np->stats.tx_errors++; } /* Free the original skb. */ - dev_kfree_skb(np->tx_skbuff[entry]); + dev_kfree_skb_irq(np->tx_skbuff[entry]); np->tx_skbuff[entry] = 0; } if (np->tx_full @@ -862,6 +888,7 @@ entry, desc_status); if (--boguscnt < 0) break; + if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { if (desc_status & DescMore) { printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " @@ -947,7 +974,7 @@ np->rx_ring[entry].addr = virt_to_le32desc(skb->tail); } np->rx_ring[entry].cmd_status = - cpu_to_le32(DescIntr | np->rx_buf_sz); + cpu_to_le32(np->rx_buf_sz); } /* Restart Rx engine if stopped. */ @@ -1045,13 +1072,13 @@ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, mc_filter); } - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; for (i = 0; i < 32; i++) { writew(0x200 + (i<<1), ioaddr + RxFilterAddr); writew(cpu_to_be16(mc_filter[i]), ioaddr + RxFilterData); } + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } - writel(rx_mode, ioaddr + RxFilterAddr); + writel(rx_mode | EnableFilter, ioaddr + RxFilterAddr); np->cur_rx_mode = rx_mode; } @@ -1138,7 +1165,8 @@ dev_kfree_skb(np->tx_skbuff[i]); np->tx_skbuff[i] = 0; } - + /* Restore PME enable bit */ + writel(np->SavedClkRun, ioaddr + ClkRun); #if 0 writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */ #endif @@ -1153,9 +1181,10 @@ { struct net_device *dev = pdev->driver_data; struct netdev_private *np = (struct netdev_private *)dev->priv; + const int pcibar = 1; /* PCI base address register */ unregister_netdev (dev); - release_mem_region(dev->base_addr, np->iosize); + release_mem_region(pci_resource_start(pdev, pcibar), np->iosize); iounmap ((char *) dev->base_addr); kfree (dev); } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c --- v2.4.0-test7/linux/drivers/net/ncr885e.c Mon Jul 10 16:47:23 2000 +++ linux/drivers/net/ncr885e.c Tue Sep 5 12:57:51 2000 @@ -1367,13 +1367,7 @@ #endif /* NCR885E_DEBUG_MII */ -int -init_module(void) -{ - return ncr885e_probe(); -} - -static void __exit cleanup_module(void) +static void __exit ncr885e_cleanup(void) { if ( root_dev ) { unregister_netdev( root_dev ); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c --- v2.4.0-test7/linux/drivers/net/pcmcia/3c574_cs.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/pcmcia/3c574_cs.c Sat Sep 2 00:15:37 2000 @@ -2,7 +2,7 @@ Written 1993-1998 by Donald Becker, becker@cesdis.gsfc.nasa.gov, (driver core) and - David Hinds, dhinds@pcmcia.sourceforge.org (from his PC card code). + David Hinds, dahinds@users.sourceforge.net (from his PC card code). This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -327,7 +327,7 @@ dev->stop = &el3_close; dev->tx_timeout = el3_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - + /* Register with Card Services */ link->next = dev_list; dev_list = link; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c --- v2.4.0-test7/linux/drivers/net/pcmcia/3c589_cs.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/pcmcia/3c589_cs.c Sat Sep 2 00:15:37 2000 @@ -2,9 +2,9 @@ A PCMCIA ethernet driver for the 3com 3c589 card. - Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org + Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - 3c589_cs.c 1.151 2000/05/08 22:03:18 + 3c589_cs.c 1.153 2000/06/12 21:27:25 The network driver code is based on Donald Becker's 3c589 code: @@ -117,7 +117,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c589_cs.c 1.151 2000/05/08 22:03:18 (David Hinds)"; +"3c589_cs.c 1.153 2000/06/12 21:27:25 (David Hinds)"; #else #define DEBUG(n, args...) #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c --- v2.4.0-test7/linux/drivers/net/pcmcia/netwave_cs.c Fri Jul 14 12:12:10 2000 +++ linux/drivers/net/pcmcia/netwave_cs.c Sat Sep 2 00:15:37 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Authors: John Markus Bjørndalen * Dag Brattli - * David Hinds + * David Hinds * Created at: A long time ago! * Modified at: Mon Nov 10 11:54:37 1997 * Modified by: Dag Brattli @@ -63,7 +63,7 @@ #ifdef CONFIG_NET_PCMCIA_RADIO #include -#endif /* CONFIG_NET_PCMCIA_RADIO */ +#endif #include #include @@ -130,8 +130,7 @@ #define NETWAVE_ASR_RXRDY 0x80 #define NETWAVE_ASR_TXBA 0x01 -#define TX_TIMEOUT 20 -#define WATCHDOG_JIFFIES 32 +#define TX_TIMEOUT ((32*HZ)/100) static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */ static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */ @@ -151,8 +150,6 @@ static const unsigned int txConfKey = 0x02; /* Scramble data packets */ static const unsigned int txConfLoop = 0x01; /* Loopback mode */ -static int netwave_debug = 0; - /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not define PCMCIA_DEBUG at all, all the debug code will be @@ -223,7 +220,6 @@ static int netwave_open(struct net_device *dev); /* Open the device */ static int netwave_close(struct net_device *dev); /* Close the device */ static int netwave_config(struct net_device *dev, struct ifmap *map); -static void netwave_tx_timeout (struct net_device *dev); /* Packet transmission and Packet reception */ static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev); @@ -231,7 +227,7 @@ /* Interrupt routines */ static void netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void netwave_watchdog(u_long); /* Transmission watchdog */ +static void netwave_watchdog(struct net_device *); /* Statistics */ static void update_stats(struct net_device *dev); @@ -309,7 +305,6 @@ u_char *ramBase; int timeoutCounter; int lastExec; - spinlock_t lock; struct timer_list watchdog; /* To avoid blocking state */ struct site_survey nss; struct net_device_stats stats; @@ -417,18 +412,6 @@ #endif /* - * Function netwave_init (dev) - * - * We never need to do anything when a device is "initialized" - * by the net software, because we only register already-found cards. - */ -int netwave_init(struct net_device *dev) -{ - /* We do all the initialization of this in netwave_attach instead */ - return 0; -} - -/* * Function netwave_attach (void) * * Creates an "instance" of the driver, allocating local data @@ -456,7 +439,6 @@ priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return NULL; memset(priv, 0, sizeof(*priv)); - priv->lock = SPIN_LOCK_UNLOCKED; link = &priv->link; dev = &priv->dev; link->priv = dev->priv = priv; link->release.function = &netwave_release; @@ -486,10 +468,6 @@ link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; - /* Set the watchdog timer */ - priv->watchdog.function = &netwave_watchdog; - priv->watchdog.data = (unsigned long) dev; - /* Netwave specific entries in the device structure */ dev->hard_start_xmit = &netwave_start_xmit; dev->set_config = &netwave_config; @@ -501,14 +479,12 @@ #endif dev->do_ioctl = &netwave_ioctl; + dev->tx_timeout = &netwave_watchdog; + dev->watchdog_timeo = TX_TIMEOUT; + ether_setup(dev); - strcpy(dev->name, priv->node.dev_name); - dev->init = &netwave_init; dev->open = &netwave_open; dev->stop = &netwave_close; - dev->tx_timeout = netwave_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - netif_start_queue (dev); link->irq.Instance = dev; /* Register with Card Services */ @@ -545,30 +521,21 @@ { netwave_private *priv = link->priv; dev_link_t **linkp; - long flags; DEBUG(0, "netwave_detach(0x%p)\n", link); - save_flags(flags); - if (link->state & DEV_RELEASE_PENDING) { - del_timer(&link->release); - link->state &= ~DEV_RELEASE_PENDING; - } - cli(); - restore_flags(flags); - /* If the device is currently configured and active, we won't actually delete it yet. Instead, it is marked so that when the release() function is called, that will trigger a proper detach(). */ + del_timer(&link->release); if (link->state & DEV_CONFIG) { netwave_release((u_long) link); if (link->state & DEV_STALE_CONFIG) { DEBUG(1, "netwave_cs: detach postponed, '%s' still " "locked\n", link->dev->dev_name); - link->state |= DEV_STALE_LINK; return; } @@ -641,7 +608,7 @@ struct iwreq *wrq = (struct iwreq *) rq; #endif - DEBUG( 0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); + DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); /* Disable interrupts & save flags */ save_flags(flags); @@ -840,7 +807,7 @@ struct net_device *dev = &priv->dev; tuple_t tuple; cisparse_t parse; - int i=0, j, last_ret, last_fn; + int i, j, last_ret, last_fn; u_char buf[64]; win_req_t req; memreq_t mem; @@ -862,16 +829,16 @@ CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - + /* Configure card */ link->state |= DEV_CONFIG; - + /* * Try allocating IO ports. This tries a few fixed addresses. * If you want, you can also read the card's config table to * pick addresses -- see the serial driver for an example. */ - for (j = 0x0; j < 0x400; j += 0x20) { + for (i = j = 0x0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; @@ -880,19 +847,19 @@ cs_error(link->handle, RequestIO, i); goto failed; } - + /* * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ CS_CHECK(RequestIRQ, handle, &link->irq); - + /* * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping. */ CS_CHECK(RequestConfiguration, handle, &link->conf); - + /* * Allocate a 32K memory window. Note that the dev_link_t * structure provides space for one window handle -- if your @@ -900,7 +867,7 @@ * the handles in your private data structure, link->priv. */ DEBUG(1, "Setting mem speed of %d\n", mem_speed); - + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = mem_speed; @@ -908,26 +875,25 @@ CS_CHECK(RequestWindow, &link->win, &req); mem.CardOffset = 0x20000; mem.Page = 0; CS_CHECK(MapMemPage, link->win, &mem); - + /* Store base address of the common window frame */ ramBase = ioremap(req.Base, 0x8000); ((netwave_private*)dev->priv)->ramBase = ramBase; - + dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - netif_start_queue (dev); if (register_netdev(dev) != 0) { printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); goto failed; } - + + strcpy(priv->node.dev_name, dev->name); + link->dev = &priv->node; link->state &= ~DEV_CONFIG_PENDING; - - link->dev = &((netwave_private *)dev->priv)->node; /* Reset card before reading physical address */ netwave_doreset(dev->base_addr, ramBase); - + /* Read the ethernet address and fill in the Netwave registers. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); @@ -949,7 +915,6 @@ cs_error(link->handle, last_fn, last_ret); failed: netwave_release((u_long)link); - return; } /* netwave_pcmcia_config */ /* @@ -975,7 +940,7 @@ link->state |= DEV_STALE_CONFIG; return; } - + /* Don't bother checking to see if these succeed or not */ if (link->win) { iounmap(priv->ramBase); @@ -984,9 +949,9 @@ CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); - - link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG); - + + link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG); + } /* netwave_release */ /* @@ -1020,8 +985,7 @@ link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_device_detach(dev); - link->release.expires = jiffies + 5; - add_timer(&link->release); + mod_timer(&link->release, jiffies + HZ/20); } break; case CS_EVENT_CARD_INSERTION: @@ -1035,7 +999,6 @@ if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); - CardServices(ReleaseConfiguration, link->handle); } break; @@ -1082,10 +1045,7 @@ DEBUG(0, "netwave_reset: Done with hardware reset\n"); priv->timeoutCounter = 0; - - /* If watchdog was activated, kill it ! */ - del_timer(&priv->watchdog); - + /* Reset card */ netwave_doreset(iobase, ramBase); printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n"); @@ -1172,7 +1132,7 @@ netwave_private *priv = (netwave_private *) dev->priv; u_char* ramBase = priv->ramBase; ioaddr_t iobase = dev->base_addr; - + /* Disable interrupts & save flags */ save_flags(flags); cli(); @@ -1183,9 +1143,10 @@ /* No buffers available */ printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n", dev->name); + restore_flags(flags); return 1; } - + priv->stats.tx_bytes += len; DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n", @@ -1222,29 +1183,11 @@ writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1); writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - - /* If watchdog not already active, activate it... */ - if (!timer_pending(&priv->watchdog)) { - /* set timer to expire in WATCHDOG_JIFFIES */ - priv->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&priv->watchdog); - } + restore_flags( flags); return 0; } - -static void netwave_tx_timeout (struct net_device *dev) -{ - if (netwave_debug > 0) - printk (KERN_DEBUG "%s timed out.\n", dev->name); - netwave_reset (dev); - dev->trans_start = jiffies; - netif_start_queue (dev); -} - - - static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { /* This flag indicate that the hardware can't perform a transmission. * Theoritically, NET3 check it before sending a packet to the driver, @@ -1252,23 +1195,15 @@ * As the watchdog will abort too long transmissions, we are quite safe... */ - /* Sending a NULL skb means some higher layer thinks we've missed an - * tx-done interrupt. Caution: dev_tint() handles the cli()/sti() - * itself. - */ + netif_stop_queue(dev); - /* Block a timer-based transmit from overlapping. This could - * better be done with atomic_swap(1, dev->tbusy, but set_bit() - * works as well - */ - netif_stop_queue (dev); - if (1) { + { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char* buf = skb->data; if (netwave_hw_xmit( buf, length, dev) == 1) { /* Some error, let's make them call us another time? */ - netif_start_queue (dev); + netif_start_queue(dev); } dev->trans_start = jiffies; } @@ -1295,11 +1230,9 @@ dev_link_t *link = &priv->link; int i; - if ((dev == NULL) || !netif_device_present(dev)) + if (!netif_device_present(dev)) return; - spin_lock (&priv->lock); - iobase = dev->base_addr; ramBase = priv->ramBase; @@ -1313,9 +1246,9 @@ status = inb(iobase + NETWAVE_REG_ASR); - if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) { - DEBUG( 1, "netwave_interupt: Interrupt with status 0x%x " - "from removed or suspended card!\n", status); + if (!DEV_OK(link)) { + DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x " + "from removed or suspended card!\n", status); break; } @@ -1393,21 +1326,15 @@ DEBUG(3, "New status is TSER %x ASR %x\n", readb(ramBase + NETWAVE_EREG_TSER), inb(iobase + NETWAVE_REG_ASR)); - - /* If watchdog was activated, kill it ! */ - del_timer(&priv->watchdog); - netif_wake_queue (dev); + netif_wake_queue(dev); } /* TxBA, this would trigger on all error packets received */ /* if (status & 0x01) { - if (netwave_debug > 3) - printk(KERN_DEBUG "Transmit buffers available, %x\n", status); - } + DEBUG(4, "Transmit buffers available, %x\n", status); + } */ } - /* done.. */ - spin_unlock (&priv->lock); } /* netwave_interrupt */ /* @@ -1418,20 +1345,12 @@ * it expire, we reset the card. * */ -static void netwave_watchdog(u_long a) { - struct net_device *dev; - ioaddr_t iobase; - - dev = (struct net_device *) a; - iobase = dev->base_addr; - - DEBUG( 1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name); - - netwave_reset(dev); - - /* We are not waiting anymore... */ - netif_start_queue (dev); - +static void netwave_watchdog(struct net_device *dev) { + + DEBUG(1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name); + netwave_reset(dev); + dev->trans_start = jiffies; + netif_start_queue(dev); } /* netwave_watchdog */ static struct net_device_stats *netwave_get_stats(struct net_device *dev) { @@ -1569,8 +1488,8 @@ link->open++; MOD_INC_USE_COUNT; - - netif_start_queue (dev); + + netif_start_queue(dev); netwave_reset(dev); return 0; @@ -1582,17 +1501,10 @@ DEBUG(1, "netwave_close: finishing.\n"); - netif_stop_queue (dev); - - /* If watchdog was activated, kill it ! */ - del_timer(&priv->watchdog); - link->open--; - if (link->state & DEV_STALE_CONFIG) { - link->release.expires = jiffies + 5; - link->state |= DEV_RELEASE_PENDING; - add_timer(&link->release); - } + netif_stop_queue(dev); + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); MOD_DEC_USE_COUNT; return 0; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c --- v2.4.0-test7/linux/drivers/net/pcmcia/nmclan_cs.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/pcmcia/nmclan_cs.c Sat Sep 2 00:15:37 2000 @@ -28,7 +28,7 @@ Dean Siasoyco, New Media Corporation Ken Lesniak, Silicon Graphics, Inc. Donald Becker - David Hinds + David Hinds The Linux client driver is based on the 3c589_cs.c client driver by David Hinds. diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c --- v2.4.0-test7/linux/drivers/net/pcmcia/pcnet_cs.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/pcmcia/pcnet_cs.c Sat Sep 2 00:15:37 2000 @@ -9,9 +9,9 @@ Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory mode. It will also handle the Socket EA card in either mode. - Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org + Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - pcnet_cs.c 1.117 2000/05/04 01:29:47 + pcnet_cs.c 1.124 2000/07/21 19:47:31 The network driver code is based on Donald Becker's NE2000 code: @@ -72,7 +72,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"pcnet_cs.c 1.117 2000/05/04 01:29:47 (David Hinds)"; +"pcnet_cs.c 1.124 2000/07/21 19:47:31 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -153,7 +153,8 @@ #define USE_BIG_BUF 0x04 #define HAS_IBM_MISC 0x08 #define IS_DL10019 0x10 -#define IS_AX88190 0x20 +#define IS_DL10022 0x20 +#define IS_AX88190 0x40 #define USE_SHMEM 0x80 /* autodetected */ static hw_info_t hw_info[] = { @@ -219,10 +220,9 @@ #define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) -static hw_info_t default_info = -{ /* Unknown NE2000 Clone */ 0x00, 0x00, 0x00, 0x00, 0 }; -static hw_info_t dl10019_info = -{ /* D-Link DL10019 chipset */ 0x00, 0x00, 0x00, 0x00, IS_DL10019 }; +static hw_info_t default_info = { 0, 0, 0, 0, 0 }; +static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019 }; +static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10019|IS_DL10022 }; typedef struct pcnet_dev_t { struct net_device dev; /* so &dev == &pcnet_dev_t */ @@ -232,7 +232,7 @@ caddr_t base; struct timer_list watchdog; int stale, fast_poll; - u_char link_status; + u_short link_status; } pcnet_dev_t; /*====================================================================== @@ -504,7 +504,8 @@ return NULL; for (i = 0; i < 6; i++) dev->dev_addr[i] = inb_p(dev->base_addr + 0x14 + i); - return &dl10019_info; + i = inb(dev->base_addr + 0x1f); + return ((i == 0x91)||(i == 0x99)) ? &dl10022_info : &dl10019_info; } /*====================================================================== @@ -723,14 +724,18 @@ hw_info = get_hwired(link); if (hw_info == NULL) { - printk(KERN_NOTICE "pcnet_cs: unable to read hardware net address\n"); - goto config_undo; + printk(KERN_NOTICE "pcnet_cs: unable to read hardware net" + " address for io base %#3lx\n", dev->base_addr); + unregister_netdev(dev); + goto failed; } info->flags = hw_info->flags; /* Check for user overrides */ info->flags |= (delay_output) ? DELAY_OUTPUT : 0; - if ((manfid == MANFID_SOCKET) && (prodid == PRODID_SOCKET_LPE)) + if ((manfid == MANFID_SOCKET) && + ((prodid == PRODID_SOCKET_LPE) || + (prodid == PRODID_SOCKET_EIO))) info->flags &= ~USE_BIG_BUF; if (!use_big_buf) info->flags &= ~USE_BIG_BUF; @@ -760,8 +765,9 @@ if (info->flags & IS_DL10019) { dev->do_ioctl = &do_ioctl; - printk(KERN_INFO "%s: NE2000 (DL10019 rev %02x): ", - dev->name, inb(dev->base_addr + 0x1a)); + printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ", + dev->name, ((info->flags & IS_DL10022) ? 22 : 19), + inb(dev->base_addr + 0x1a)); } else if (info->flags & IS_AX88190) { printk(KERN_INFO "%s: NE2000 (AX88190): ", dev->name); } else @@ -776,9 +782,6 @@ printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); return; -config_undo: - unregister_netdev(dev); - goto failed; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: @@ -876,6 +879,79 @@ return 0; } /* pcnet_event */ +/*====================================================================== + + MII interface support for DL10019 and DL10022 based cards + + On the DL10019, the MII IO direction bit is 0x10; on the DL10022 + it is 0x20. Setting both bits seems to work on both card types. + +======================================================================*/ + +#define DLINK_GPIO 0x1c +#define DLINK_DIAG 0x1d +#define MDIO_SHIFT_CLK 0x80 +#define MDIO_DATA_OUT 0x40 +#define MDIO_DIR_WRITE 0x30 +#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE) +#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT) +#define MDIO_DATA_READ 0x10 +#define MDIO_MASK 0x0f + +static void mdio_sync(ioaddr_t addr) +{ + int bits, mask = inb(addr) & MDIO_MASK; + for (bits = 0; bits < 32; bits++) { + outb(mask | MDIO_DATA_WRITE1, addr); + outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr); + } +} + +static int mdio_read(ioaddr_t addr, int phy_id, int loc) +{ + u_int cmd = (0x06<<10)|(phy_id<<5)|loc; + int i, retval = 0, mask = inb(addr) & MDIO_MASK; + + mdio_sync(addr); + for (i = 13; i >= 0; i--) { + int dat = (cmd&(1< 0; i--) { + outb(mask, addr); + retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0); + outb(mask | MDIO_SHIFT_CLK, addr); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value) +{ + u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; + int i, mask = inb(addr) & MDIO_MASK; + + mdio_sync(addr); + for (i = 31; i >= 0; i--) { + int dat = (cmd&(1<= 0; i--) { + outb(mask, addr); + outb(mask | MDIO_SHIFT_CLK, addr); + } +} + +static void mdio_reset(ioaddr_t addr, int phy_id) +{ + outb_p(0x08, addr); + outb_p(0x0c, addr); + outb_p(0x08, addr); + outb_p(0x0c, addr); + outb_p(0x00, addr); +} + /*====================================================================*/ static void set_misc_reg(struct net_device *dev) @@ -894,6 +970,12 @@ tmp |= 8; outb_p(tmp, nic_base + PCNET_MISC); } + if (info->flags & IS_DL10022) { + mdio_reset(nic_base + DLINK_GPIO, 0); + /* Restart MII autonegotiation */ + mdio_write(nic_base + DLINK_GPIO, 0, 0, 0x0000); + mdio_write(nic_base + DLINK_GPIO, 0, 0, 0x1200); + } } /*====================================================================*/ @@ -914,8 +996,7 @@ set_misc_reg(dev); request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev); - /* Start by assuming the link is bad */ - info->link_status = 1; + info->link_status = 0x00; info->watchdog.function = &ei_watchdog; info->watchdog.data = (u_long)info; info->watchdog.expires = jiffies + HZ; @@ -1008,13 +1089,14 @@ pcnet_dev_t *info = (pcnet_dev_t *)(arg); struct net_device *dev = &info->dev; ioaddr_t nic_base = dev->base_addr; + u_short link; if (!netif_device_present(dev)) goto reschedule; /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ outb_p(E8390_NODMA+E8390_PAGE0, nic_base + E8390_CMD); - if (info->stale++ && inb_p(nic_base + EN0_ISR)) { + if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) { if (!info->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); ei_irq_wrapper(dev->irq, dev, NULL); @@ -1027,15 +1109,30 @@ return; } - if (info->flags & IS_DL10019) { - u_char link = inb(dev->base_addr+0x1c) & 0x01; - if (link != info->link_status) { - printk(KERN_INFO "%s: %s link beat\n", dev->name, - (link) ? "lost" : "found"); - if (!link) - NS8390_init(dev, 1); - info->link_status = link; + if (!(info->flags & IS_DL10019)) + goto reschedule; + + link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1) & 0x0004; + if (link != info->link_status) { + u_short p = mdio_read(dev->base_addr + DLINK_GPIO, 0, 5); + printk(KERN_INFO "%s: %s link beat\n", dev->name, + (link) ? "found" : "lost"); + if (link && (info->flags & IS_DL10022)) { + /* Disable collision detection on full duplex links */ + outb((p & 0x0140) ? 4 : 0, dev->base_addr + DLINK_DIAG); + } + if (link) { + if (p) + printk(KERN_INFO "%s: autonegotiation complete: " + "%sbaseT-%cD selected\n", dev->name, + ((p & 0x0180) ? "100" : "10"), + ((p & 0x0140) ? 'F' : 'H')); + else + printk(KERN_INFO "%s: link partner did not autonegotiate\n", + dev->name); + NS8390_init(dev, 1); } + info->link_status = link; } reschedule: @@ -1043,83 +1140,22 @@ add_timer(&info->watchdog); } -/*====================================================================== - - MII interface support for DL10019 based cards - - There are two types of DL10019 based cards. Some have the MII IO - direction bit as 0x10, others as 0x20; setting both bits seems to - work on all cards. - -======================================================================*/ - -#define MDIO_SHIFT_CLK 0x80 -#define MDIO_DATA_OUT 0x40 -#define MDIO_DIR_WRITE 0x30 -#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE) -#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT) -#define MDIO_DATA_READ 0x10 -#define MDIO_MASK 0x0f - -static void mdio_sync(ioaddr_t addr) -{ - int bits, mask = inb(addr) & MDIO_MASK; - for (bits = 0; bits < 32; bits++) { - outb(mask | MDIO_DATA_WRITE1, addr); - outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr); - } -} - -static int mdio_read(ioaddr_t addr, int phy_id, int loc) -{ - u_int cmd = (0x06<<10)|(phy_id<<5)|loc; - int i, retval = 0, mask = inb(addr) & MDIO_MASK; - - mdio_sync(addr); - for (i = 13; i >= 0; i--) { - int dat = (cmd&(1< 0; i--) { - outb(mask, addr); - retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0); - outb(mask | MDIO_SHIFT_CLK, addr); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value) -{ - u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; - int i, mask = inb(addr) & MDIO_MASK; - - mdio_sync(addr); - for (i = 31; i >= 0; i--) { - int dat = (cmd&(1<= 0; i--) { - outb(mask, addr); - outb(mask | MDIO_SHIFT_CLK, addr); - } -} +/*====================================================================*/ static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { u16 *data = (u16 *)&rq->ifr_data; - ioaddr_t addr = dev->base_addr + 0x1c; + ioaddr_t addr = dev->base_addr + DLINK_GPIO; switch (cmd) { case SIOCDEVPRIVATE: data[0] = 0; case SIOCDEVPRIVATE+1: - data[3] = mdio_read(addr, 0, data[1] & 0x1f); + data[3] = mdio_read(addr, data[0], data[1] & 0x1f); return 0; case SIOCDEVPRIVATE+2: if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(addr, 0, data[1] & 0x1f, data[2]); + mdio_write(addr, data[0], data[1] & 0x1f, data[2]); return 0; } return -EOPNOTSUPP; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c --- v2.4.0-test7/linux/drivers/net/pcmcia/ray_cs.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/pcmcia/ray_cs.c Sat Sep 2 00:15:37 2000 @@ -318,6 +318,23 @@ error_info_t err = { func, ret }; pcmcia_report_error(handle, &err); } +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + +======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + ray_detach(link); + } +} /*============================================================================= ray_attach() creates an "instance" of the driver, allocating @@ -336,6 +353,7 @@ struct net_device *dev; DEBUG(1, "ray_attach()\n"); + flush_stale_links(); /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); @@ -384,7 +402,6 @@ dev->priv = local; local->finder = link; - link->dev = &local->node; local->card_status = CARD_INSERTED; local->authentication_state = UNAUTHENTICATED; local->num_multi = 0; @@ -451,8 +468,6 @@ static void ray_detach(dev_link_t *link) { dev_link_t **linkp; - struct net_device *dev; - long flags; DEBUG(1, "ray_detach(0x%p)\n", link); @@ -462,19 +477,12 @@ if (*linkp == NULL) return; - save_flags(flags); - cli(); - if (link->state & DEV_RELEASE_PENDING) { - del_timer(&link->release); - link->state &= ~DEV_RELEASE_PENDING; - } - restore_flags(flags); - /* If the device is currently configured and active, we won't actually delete it yet. Instead, it is marked so that when the release() function is called, that will trigger a proper detach(). */ + del_timer(&link->release); if (link->state & DEV_CONFIG) { ray_release((u_long)link); if(link->state & DEV_STALE_CONFIG) { @@ -490,10 +498,10 @@ /* Unlink device structure, free pieces */ *linkp = link->next; if (link->priv) { - dev = link->priv; + struct net_device *dev = link->priv; + if (link->dev) unregister_netdev(dev); if (dev->priv) kfree(dev->priv); - kfree(link->priv); } kfree(link); @@ -606,6 +614,7 @@ } strcpy(local->node.dev_name, dev->name); + link->dev = &local->node; link->state &= ~DEV_CONFIG_PENDING; printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ", @@ -907,9 +916,7 @@ return; } del_timer(&local->timer); - if (link->dev != '\0') unregister_netdev(dev); - /* Unlink the device chain */ - link->dev = NULL; + link->state &= ~DEV_CONFIG; iounmap(local->sram); iounmap(local->rmem); @@ -926,8 +933,6 @@ i = pcmcia_release_irq(link->handle, &link->irq); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i); - link->state &= ~DEV_CONFIG; - if (link->state & DEV_STALE_LINK) ray_detach(link); DEBUG(2,"ray_release ending\n"); } /* ray_release */ /*============================================================================= @@ -954,8 +959,7 @@ link->state &= ~DEV_PRESENT; netif_device_detach(dev); if (link->state & DEV_CONFIG) { - link->release.expires = jiffies + HZ/20; - add_timer(&link->release); + mod_timer(&link->release, jiffies + HZ/20); del_timer(&local->timer); } break; @@ -1006,7 +1010,7 @@ if ( (i = dl_startup_params(dev)) < 0) { printk(KERN_INFO "ray_dev_init dl_startup_params failed - " - "returns 0x%x/n",i); + "returns 0x%x\n",i); return -1; } @@ -1554,11 +1558,8 @@ link->open--; netif_stop_queue(dev); - if (link->state & DEV_STALE_CONFIG) { - link->release.expires = jiffies + HZ/20; - link->state |= DEV_RELEASE_PENDING; - add_timer(&link->release); - } + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); MOD_DEC_USE_COUNT; @@ -2773,10 +2774,9 @@ #endif unregister_pcmcia_driver(&dev_info); - while (dev_list != NULL) { - if (dev_list->state & DEV_CONFIG) ray_release((u_long)dev_list); + while (dev_list != NULL) ray_detach(dev_list); - } + #ifdef CONFIG_PROC_FS remove_proc_entry("driver/ray_cs/ray_cs", NULL); remove_proc_entry("driver/ray_cs/essid", NULL); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c --- v2.4.0-test7/linux/drivers/net/pcmcia/smc91c92_cs.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/pcmcia/smc91c92_cs.c Sat Sep 2 00:15:37 2000 @@ -6,13 +6,13 @@ Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem multifunction cards. - Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org + Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - smc91c92_cs.c 1.96 2000/05/09 02:35:58 + smc91c92_cs.c 1.104 2000/08/31 21:25:13 This driver contains code written by Donald Becker (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au), - David Hinds (dhinds@pcmcia.sourceforge.org), and Erik Stahlman + David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman (erik@vt.edu). Donald wrote the SMC 91c92 code using parts of Erik's SMC 91c94 driver. Rowan wrote a similar driver, and I've incorporated some parts of his driver here. I (Dave) wrote most @@ -635,11 +635,12 @@ mdelay(100); } -static int mot_setup(dev_link_t *link) { +static int mot_setup(dev_link_t *link) +{ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; ioaddr_t ioaddr = dev->base_addr; - int i, wait=0, loop; + int i, wait, loop; u_int addr; /* Read Ethernet address from Serial EEPROM */ @@ -650,7 +651,7 @@ SMC_SELECT_BANK(1); outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL); - for (loop = 0; loop < 200; loop++) { + for (loop = wait = 0; loop < 200; loop++) { udelay(10); wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL)); if (wait == 0) break; @@ -751,7 +752,7 @@ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; - int i=0, j; + int i, j; link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; @@ -765,7 +766,7 @@ /* Enable Hard Decode, LAN, Modem */ link->conf.ConfigIndex = 0x23; - for (j = 0; j < 4; j++) { + for (i = j = 0; j < 4; j++) { link->io.BasePort2 = com[j]; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; @@ -808,15 +809,16 @@ for (i = 0; i < 6; i++) dev->dev_addr[i] = buf[i+2]; - if (manfid != MANFID_OSITECH) return 0; - - if (cardid == PRODID_OSITECH_SEVEN) { + if (((manfid == MANFID_OSITECH) && + (cardid == PRODID_OSITECH_SEVEN)) || + ((manfid == MANFID_PSION) && + (cardid == PRODID_PSION_NET100))) { /* Download the Seven of Diamonds firmware */ for (i = 0; i < sizeof(__Xilinx7OD); i++) { outb(__Xilinx7OD[i], link->io.BasePort1+2); udelay(50); } - } else { + } else if (manfid == MANFID_OSITECH) { /* Make sure both functions are powered up */ set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR); /* Now, turn on the interrupt for both card functions */ @@ -927,7 +929,8 @@ /* Configure card */ link->state |= DEV_CONFIG; - if (smc->manfid == MANFID_OSITECH) { + if ((smc->manfid == MANFID_OSITECH) && + (smc->cardid != PRODID_OSITECH_SEVEN)) { i = osi_config(link); } else if ((smc->manfid == MANFID_MOTOROLA) || ((smc->manfid == MANFID_MEGAHERTZ) && @@ -1001,7 +1004,7 @@ for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); if (rev > 0) { - u_long mir, mcr, mii; + u_long mir, mcr; ioaddr_t ioaddr = dev->base_addr; SMC_SELECT_BANK(0); mir = inw(ioaddr + MEMINFO) & 0xff; @@ -1014,8 +1017,14 @@ else printk(KERN_INFO " %lu kb", mir>>10); SMC_SELECT_BANK(1); - mii = inw(ioaddr + CONFIG) & CFG_MII_SELECT; - printk(" buffer, %s xcvr\n", mii ? "MII" : if_names[dev->if_port]); + smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; + smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC; + if (smc->manfid == MANFID_OSITECH) + smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0; + if ((rev >> 4) >= 7) + smc->cfg |= CFG_MII_SELECT; + printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ? + "MII" : if_names[dev->if_port]); } return; @@ -1321,7 +1330,7 @@ DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called," " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2)); - + if (smc->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ smc->stats.tx_aborted_errors++; @@ -1808,9 +1817,6 @@ Accept link errors, counter and Tx error interrupts. */ outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, ioaddr + CONTROL); - smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; - smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC | - (smc->manfid == MANFID_OSITECH ? (CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0) : 0); smc_set_xcvr(dev, dev->if_port); if ((smc->manfid == MANFID_OSITECH) && (smc->cardid != PRODID_OSITECH_SEVEN)) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c --- v2.4.0-test7/linux/drivers/net/pcmcia/xirc2ps_cs.c Fri Jul 14 12:12:11 2000 +++ linux/drivers/net/pcmcia/xirc2ps_cs.c Sat Sep 2 00:15:37 2000 @@ -2,43 +2,14 @@ * Xircom CreditCard Ethernet Adapter IIps driver * Xircom Realport 10/100 (RE-100) driver * - * This driver originally was made by Werner Koch. Since the driver was left - * unmaintained for some time, there have been some improvements and changes - * since. These include supporting some of the "Realport" cards and develop- - * ing enhancements to support the new ones. - * It is made for CE2, CEM28, CEM33, CE33 and - * CEM56 cards. The CEM56 cards work both with their modem and ethernet - * interface. The RealPort 10/100 Modem and similar cards are supported but - * with some bugs which are being corrected as they are detected. + * This driver supports various Xircom CreditCard Ethernet adapters + * including the CE2, CE IIps, RE-10, CEM28, CEM33, CE33, CEM56, + * CE3-100, CE3B, RE-100, REM10BT, and REM56G-100. * - * Code revised and maintained by Allan Baker Ortegon - * al527261@prodigy.net.mx * Written originally by Werner Koch based on David Hinds' skeleton of the - * PCMCIA driver. The code has been modified as to make the newer cards - * available. + * PCMCIA driver. * - * The latest code for the driver, information on the development project - * for the Xircom RealPort and CE cards for the PCMCIA driver, and other - * related material, can be found at the following URL, which is underway: - * - * "http://xirc2ps.linuxbox.com/index.html" - * - * Any bugs regarding this driver, please send them to: - * alanyuu@linuxbox.com - * - * The driver is still evolving and there are many cards which will benefit - * from having alpha testers. If you have a particular card and would like - * to be involved in this ongoing effort, please send mail to the maintainer. - * - * Special thanks to David Hinds, to Xircom for the specifications and their - * software development kit, and all others who may have colaborated in the - * development of the driver: Koen Van Herck (Koen.Van.Herck@xircom.com), - * 4PC GmbH Duesseldorf, David Luger, et al. - * - * - ************************************************************************ * Copyright (c) 1997,1998 Werner Koch (dd9jn) - * Copyright (c) 1999 Allan Baker Ortegon * * This driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -87,9 +58,6 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* Enable the bug fix for CEM56 to use modem and ethernet simultaneously */ -#define CEM56_FIX - #include #include #include @@ -118,16 +86,10 @@ #include #include -#ifndef MANFID_XIRCOM - #define MANFID_XIRCOM 0x0105 -#endif #ifndef MANFID_COMPAQ #define MANFID_COMPAQ 0x0138 #define MANFID_COMPAQ2 0x0183 /* is this correct? */ #endif -#ifndef MANFID_INTEL - #define MANFID_INTEL 0x0089 -#endif #include @@ -936,26 +898,26 @@ switch(parse.manfid.manf) { case MANFID_XIRCOM: local->manf_str = "Xircom"; - DEBUG(0, "found xircom card\n"); break; case MANFID_ACCTON: local->manf_str = "Accton"; - DEBUG(0, "found Accton card\n"); break; case MANFID_COMPAQ: case MANFID_COMPAQ2: local->manf_str = "Compaq"; - DEBUG(0, "found Compaq card\n"); break; case MANFID_INTEL: local->manf_str = "Intel"; - DEBUG(0, "found Intel card\n"); + break; + case MANFID_TOSHIBA: + local->manf_str = "Toshiba"; break; default: printk(KNOT_XIRC "Unknown Card Manufacturer ID: 0x%04x\n", (unsigned)parse.manfid.manf); goto failure; } + DEBUG(0, "found %s card\n", local->manf_str); if (!set_card_type(link, buf)) { printk(KNOT_XIRC "this card is not supported\n"); @@ -1120,13 +1082,10 @@ } if (local->dingo) { - #ifdef CEM56_FIX conf_reg_t reg; - #endif win_req_t req; memreq_t mem; - #ifdef CEM56_FIX /* Reset the modem's BAR to the correct value * This is necessary because in the RequestConfiguration call, * the base address of the ethernet port (BasePort1) is written @@ -1148,7 +1107,6 @@ cs_error(link->handle, AccessConfigurationRegister, err); goto config_error; } - #endif /* There is no config entry for the Ethernet part which * is at 0x0800. So we allocate a window into the attribute @@ -1227,9 +1185,9 @@ goto config_error; } - link->state &= ~DEV_CONFIG_PENDING; strcpy(local->node.dev_name, dev->name); link->dev = &local->node; + link->state &= ~DEV_CONFIG_PENDING; if (local->dingo) do_reset(dev, 1); /* a kludge to make the cem56 work */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c --- v2.4.0-test7/linux/drivers/net/wan/cosa.c Fri Jul 14 12:12:11 2000 +++ linux/drivers/net/wan/cosa.c Tue Aug 29 14:09:15 2000 @@ -1043,9 +1043,10 @@ return -EPERM; } - get_user_ret(addr, &(d->addr), -EFAULT); - get_user_ret(len, &(d->len), -EFAULT); - get_user_ret(code, &(d->code), -EFAULT); + if (get_user(addr, &(d->addr)) || + __get_user(len, &(d->len)) || + __get_user(code, &(d->code))) + return -EFAULT; if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE) return -EINVAL; @@ -1083,9 +1084,10 @@ return -EPERM; } - get_user_ret(addr, &(d->addr), -EFAULT); - get_user_ret(len, &(d->len), -EFAULT); - get_user_ret(code, &(d->code), -EFAULT); + if (get_user(addr, &(d->addr)) || + __get_user(len, &(d->len)) || + __get_user(code, &(d->code))) + return -EFAULT; /* If something fails, force the user to reset the card */ cosa->firmware_status &= ~COSA_FW_RESET; @@ -1133,7 +1135,8 @@ static inline int cosa_getidstr(struct cosa_data *cosa, char *string) { int l = strlen(cosa->id_string)+1; - copy_to_user_ret(string, cosa->id_string, l, -EFAULT); + if (copy_to_user(string, cosa->id_string, l)) + return -EFAULT; return l; } @@ -1141,7 +1144,8 @@ static inline int cosa_gettype(struct cosa_data *cosa, char *string) { int l = strlen(cosa->type)+1; - copy_to_user_ret(string, cosa->type, l, -EFAULT); + if (copy_to_user(string, cosa->type, l)) + return -EFAULT; return l; } @@ -1429,7 +1433,8 @@ while (length--) { char c; #ifndef SRP_DOWNLOAD_AT_BOOT - get_user_ret(c,microcode, -23); + if (get_user(c, microcode)) + return -23; /* ??? */ #else c = *microcode; #endif @@ -1507,7 +1512,8 @@ } c=i; #if 1 - put_user_ret(c,microcode, -23); + if (put_user(c, microcode)) + return -23; /* ??? */ #else *microcode = c; #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c --- v2.4.0-test7/linux/drivers/pcmcia/bulkmem.c Thu May 11 15:30:07 2000 +++ linux/drivers/pcmcia/bulkmem.c Sat Sep 2 00:13:49 2000 @@ -2,7 +2,7 @@ PCMCIA Bulk Memory Services - bulkmem.c 1.34 1999/11/17 01:37:55 + bulkmem.c 1.37 2000/06/12 21:29:35 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -62,7 +62,7 @@ static int do_mtd_request(memory_handle_t handle, mtd_request_t *req, caddr_t buf) { - int ret=0, tries; + int ret, tries; client_t *mtd; socket_info_t *s; @@ -70,7 +70,7 @@ if (mtd == NULL) return CS_GENERAL_FAILURE; s = SOCKET(mtd); - for (tries = 0; tries < 100; tries++) { + for (ret = tries = 0; tries < 100; tries++) { mtd->event_callback_args.mtdrequest = req; mtd->event_callback_args.buffer = buf; ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c --- v2.4.0-test7/linux/drivers/pcmcia/cardbus.c Thu May 11 15:30:07 2000 +++ linux/drivers/pcmcia/cardbus.c Tue Sep 5 12:56:51 2000 @@ -50,7 +50,6 @@ #include #include -#include #include #include #include @@ -232,21 +231,6 @@ =====================================================================*/ -static int cb_assign_irq(u32 mask) -{ - int irq, try; - - for (try = 0; try < 2; try++) { - for (irq = 1; irq < 32; irq++) { - if ((mask >> irq) & 1) { - if (try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0) - return irq; - } - } - } - return 0; -} - int cb_alloc(socket_info_t * s) { struct pci_bus *bus; @@ -310,8 +294,6 @@ /* Does this function have an interrupt at all? */ pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin); if (irq_pin) { - if (!irq) - irq = cb_assign_irq(s->cap.irq_mask); dev->irq = irq; pci_writeb(dev, PCI_INTERRUPT_LINE, irq); } @@ -369,14 +351,7 @@ void cb_release(socket_info_t * s) { - cb_config_t *c = s->cb_config; - DEBUG(0, "cs: cb_release(bus %d)\n", s->cap.cb_dev->subordinate->number); - -#ifdef CONFIG_ISA - if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq)) - undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq); -#endif } /*===================================================================== diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/cb_enabler.c linux/drivers/pcmcia/cb_enabler.c --- v2.4.0-test7/linux/drivers/pcmcia/cb_enabler.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/pcmcia/cb_enabler.c Sat Sep 2 00:13:49 2000 @@ -2,7 +2,7 @@ CardBus device enabler - cb_enabler.c 1.28 1999/12/09 20:57:37 + cb_enabler.c 1.31 2000/06/12 21:29:36 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -58,12 +58,12 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"cb_enabler.c 1.28 1999/12/09 20:57:37 (David Hinds)"; +"cb_enabler.c 1.31 2000/06/12 21:29:36 (David Hinds)"; #else #define DEBUG(n, args...) do { } while (0) #endif -MODULE_AUTHOR("David Hinds "); +MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("CardBus stub enabler module"); /*====================================================================*/ @@ -168,9 +168,9 @@ driver_info_t *dev = link->priv; dev_link_t **linkp; bus_info_t *b = (void *)link->win; - + DEBUG(0, "cb_detach(0x%p)\n", link); - + /* Locate device structure */ for (linkp = &dev->dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; @@ -179,16 +179,16 @@ if (link->state & DEV_CONFIG) cb_release((u_long)link); - + /* Don't drop Card Services connection if we are the bus owner */ - if ((b->flags != 0) && (link == b->owner)) { + if (b && (b->flags != 0) && (link == b->owner)) { link->state |= DEV_STALE_LINK; return; } - + if (link->handle) pcmcia_deregister_client(link->handle); - + *linkp = link->next; kfree(link); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c --- v2.4.0-test7/linux/drivers/pcmcia/cistpl.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/pcmcia/cistpl.c Sat Sep 2 00:13:49 2000 @@ -2,7 +2,7 @@ PCMCIA Card Information Structure parser - cistpl.c 1.77 2000/01/16 19:19:01 + cistpl.c 1.90 2000/08/30 20:23:47 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -77,6 +77,14 @@ /* Upper limit on reasonable # of tuples */ #define MAX_TUPLES 200 +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") + +INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */ + /*====================================================================== Low-level functions to read and write CIS memory. I think the @@ -88,6 +96,17 @@ #define IS_ATTR 1 #define IS_INDIRECT 8 +static void set_cis_map(socket_info_t *s, pccard_mem_map *mem) +{ + s->ss_entry->set_mem_map(s->sock, mem); + if (s->cap.features & SS_CAP_STATIC_MAP) { + if (s->cis_virt) + bus_iounmap(s->cap.bus, s->cis_virt); + s->cis_virt = bus_ioremap(s->cap.bus, mem->sys_start, + s->cap.map_size); + } +} + void read_cis_mem(socket_info_t *s, int attr, u_int addr, u_int len, void *ptr) { @@ -99,16 +118,17 @@ memset(ptr, 0xff, len); return; } - mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB; - sys = s->cis_virt; + mem->flags = MAP_ACTIVE; + if (cis_width) mem->flags |= MAP_16BIT; if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed locations in common memory */ u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } - mem->card_start = 0; - s->ss_entry->set_mem_map(s->sock, mem); + mem->card_start = 0; mem->flags = MAP_ACTIVE; + set_cis_map(s, mem); + sys = s->cis_virt; bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0); bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0); bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1); @@ -121,14 +141,15 @@ if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } sys += (addr & (s->cap.map_size-1)); mem->card_start = addr & ~(s->cap.map_size-1); - - for (; len > 0; sys = s->cis_virt) { - s->ss_entry->set_mem_map(s->sock, mem); + while (len) { + set_cis_map(s, mem); + sys = s->cis_virt + (addr & (s->cap.map_size-1)); for ( ; len > 0; len--, buf++, sys += inc) { if (sys == s->cis_virt+s->cap.map_size) break; *buf = bus_readb(s->cap.bus, sys); } mem->card_start += s->cap.map_size; + addr = 0; } } DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x ...\n", @@ -144,16 +165,17 @@ DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); if (setup_cis_mem(s) != 0) return; - mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB; - sys = s->cis_virt; + mem->flags = MAP_ACTIVE; + if (cis_width) mem->flags |= MAP_16BIT; if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed locations in common memory */ u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } - mem->card_start = 0; - s->ss_entry->set_mem_map(s->sock, mem); + mem->card_start = 0; mem->flags = MAP_ACTIVE; + set_cis_map(s, mem); + sys = s->cis_virt; bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0); bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0); bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1); @@ -164,16 +186,16 @@ } else { int inc = 1; if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } - sys += (addr & (s->cap.map_size-1)); mem->card_start = addr & ~(s->cap.map_size-1); - - for (; len > 0; sys = s->cis_virt) { - s->ss_entry->set_mem_map(s->sock, mem); + while (len) { + set_cis_map(s, mem); + sys = s->cis_virt + (addr & (s->cap.map_size-1)); for ( ; len > 0; len--, buf++, sys += inc) { if (sys == s->cis_virt+s->cap.map_size) break; bus_writeb(s->cap.bus, *buf, sys); } mem->card_start += s->cap.map_size; + addr = 0; } } } @@ -238,7 +260,8 @@ int setup_cis_mem(socket_info_t *s) { - if (s->cis_mem.sys_start == 0) { + if (!(s->cap.features & SS_CAP_STATIC_MAP) && + (s->cis_mem.sys_start == 0)) { int low = !(s->cap.features & SS_CAP_PAGE_REGS); vs = s; validate_mem(cis_readable, checksum_match, low); @@ -262,9 +285,11 @@ if (s->cis_mem.sys_start != 0) { s->cis_mem.flags &= ~MAP_ACTIVE; s->ss_entry->set_mem_map(s->sock, &s->cis_mem); - release_mem_region(s->cis_mem.sys_start, s->cap.map_size); + if (!(s->cap.features & SS_CAP_STATIC_MAP)) + release_mem_region(s->cis_mem.sys_start, s->cap.map_size); bus_iounmap(s->cap.bus, s->cis_virt); s->cis_mem.sys_start = 0; + s->cis_virt = NULL; } } @@ -1278,6 +1303,25 @@ /*====================================================================*/ +static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) +{ + u_char *p; + + if (tuple->TupleDataLen < 10) + return CS_BAD_TUPLE; + + p = tuple->TupleData; + + fmt->type = p[0]; + fmt->edc = p[1]; + fmt->offset = le32_to_cpu(*(u_int *)(p+2)); + fmt->length = le32_to_cpu(*(u_int *)(p+6)); + + return CS_SUCCESS; +} + +/*====================================================================*/ + int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { int ret = CS_SUCCESS; @@ -1345,6 +1389,10 @@ case CISTPL_ORG: ret = parse_org(tuple, &parse->org); break; + case CISTPL_FORMAT: + case CISTPL_FORMAT_A: + ret = parse_format(tuple, &parse->format); + break; case CISTPL_NO_LINK: case CISTPL_LINKTARGET: ret = CS_SUCCESS; @@ -1395,34 +1443,36 @@ { tuple_t tuple; cisparse_t p; - int ret, reserved, errors; - + int ret, reserved, dev_ok = 0, ident_ok = 0; + if (CHECK_HANDLE(handle)) return CS_BAD_HANDLE; - - info->Chains = reserved = errors = 0; + + info->Chains = reserved = 0; tuple.DesiredTuple = RETURN_FIRST_TUPLE; tuple.Attributes = TUPLE_RETURN_COMMON; ret = pcmcia_get_first_tuple(handle, &tuple); if (ret != CS_SUCCESS) return CS_SUCCESS; - /* First tuple should be DEVICE */ - if (tuple.TupleCode != CISTPL_DEVICE) - errors++; - /* All cards should have a MANFID tuple */ - if (read_tuple(handle, CISTPL_MANFID, &p) != CS_SUCCESS) - errors++; - /* All cards should have either a VERS_1 or a VERS_2 tuple. But - at worst, we'll accept a CFTABLE_ENTRY that parses. */ - if ((read_tuple(handle, CISTPL_VERS_1, &p) != CS_SUCCESS) && - (read_tuple(handle, CISTPL_VERS_2, &p) != CS_SUCCESS) && - (read_tuple(handle, CISTPL_CFTABLE_ENTRY, &p) != CS_SUCCESS) && - (read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, &p) != CS_SUCCESS)) - errors++; - if (errors > 1) + /* First tuple should be DEVICE; we should really have either that + or a CFTABLE_ENTRY of some sort */ + if ((tuple.TupleCode == CISTPL_DEVICE) || + (read_tuple(handle, CISTPL_CFTABLE_ENTRY, &p) == CS_SUCCESS) || + (read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, &p) == CS_SUCCESS)) + dev_ok++; + + /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 + tuple, for card identification. Certain old D-Link and Linksys + cards have only a broken VERS_2 tuple; hence the bogus test. */ + if ((read_tuple(handle, CISTPL_MANFID, &p) == CS_SUCCESS) || + (read_tuple(handle, CISTPL_VERS_1, &p) == CS_SUCCESS) || + (read_tuple(handle, CISTPL_VERS_2, &p) != CS_NO_MORE_ITEMS)) + ident_ok++; + + if (!dev_ok && !ident_ok) return CS_SUCCESS; - + for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) { ret = pcmcia_get_next_tuple(handle, &tuple); if (ret != CS_SUCCESS) break; @@ -1431,9 +1481,10 @@ ((tuple.TupleCode > 0x90) && (tuple.TupleCode < 0xff))) reserved++; } - if ((info->Chains == MAX_TUPLES) || (reserved > 5)) + if ((info->Chains == MAX_TUPLES) || (reserved > 5) || + ((!dev_ok || !ident_ok) && (info->Chains > 10))) info->Chains = 0; - + return CS_SUCCESS; } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- v2.4.0-test7/linux/drivers/pcmcia/cs.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/pcmcia/cs.c Sat Sep 2 00:13:49 2000 @@ -2,7 +2,7 @@ PCMCIA Card Services -- core services - cs.c 1.249 2000/02/10 23:26:11 + cs.c 1.267 2000/08/30 22:07:31 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -66,7 +66,7 @@ int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); static const char *version = -"cs.c 1.249 2000/02/10 23:26:11 (David Hinds)"; +"cs.c 1.267 2000/08/30 22:07:31 (David Hinds)"; #endif #ifdef CONFIG_PCI @@ -93,7 +93,7 @@ static const char *release = "Linux PCMCIA Card Services " CS_RELEASE; static const char *options = "options: " OPTIONS; -MODULE_AUTHOR("David Hinds "); +MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("Linux PCMCIA Card Services " CS_RELEASE "\n options:" OPTIONS); @@ -773,6 +773,13 @@ *base, align); align = 0; } + /* Check for an already-allocated window that must conflict with + what was asked for. It is a hack because it does not catch all + potential conflicts, just the most obvious ones. */ + for (i = 0; i < MAX_IO_WIN; i++) + if ((s->io[i].NumPorts != 0) && + ((s->io[i].BasePort & (align-1)) == *base)) + return 1; for (i = 0; i < MAX_IO_WIN; i++) { if (s->io[i].NumPorts == 0) { if (find_io_region(base, num, align, name) == 0) { @@ -1676,11 +1683,13 @@ write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy); } if (req->Present & PRESENT_OPTION) { - if (s->functions == 1) + if (s->functions == 1) { c->Option = req->ConfigIndex & COR_CONFIG_MASK; - else { + } else { c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK; - c->Option |= COR_FUNC_ENA|COR_ADDR_DECODE|COR_IREQ_ENA; + c->Option |= COR_FUNC_ENA|COR_IREQ_ENA; + if (req->Present & PRESENT_IOBASE_0) + c->Option |= COR_ADDR_DECODE; } if (c->state & CONFIG_IRQ_REQ) if (!(c->irq.Attributes & IRQ_FORCED_PULSE)) @@ -1829,8 +1838,8 @@ if (c->state & CONFIG_IRQ_REQ) return CS_IN_USE; - /* Short cut: if the interrupt is PCI, there are no options */ - if (s->cap.irq_mask == (1 << s->cap.pci_irq)) + /* Short cut: if there are no ISA interrupts, then it is PCI */ + if (!s->cap.irq_mask) irq = s->cap.pci_irq; #ifdef CONFIG_ISA else if (s->irq.AssignedIRQ != 0) { @@ -1845,7 +1854,6 @@ ret = CS_IN_USE; if (req->IRQInfo1 & IRQ_INFO2_VALID) { mask = req->IRQInfo2 & s->cap.irq_mask; - mask &= ~(1 << s->cap.pci_irq); for (try = 0; try < 2; try++) { for (irq = 0; irq < 32; irq++) if ((mask >> irq) & 1) { @@ -1910,11 +1918,12 @@ req->Size : s->cap.map_size); if (req->Size & (s->cap.map_size-1)) return CS_BAD_SIZE; - if (req->Base & (align-1)) + if ((req->Base && (s->cap.features & SS_CAP_STATIC_MAP)) || + (req->Base & (align-1))) return CS_BAD_BASE; if (req->Base) align = 0; - + /* Allocate system memory window */ for (w = 0; w < MAX_WIN; w++) if (!(s->state & SOCKET_WIN_REQ(w))) break; @@ -1928,13 +1937,13 @@ win->sock = s; win->base = req->Base; win->size = req->Size; - - if (find_mem_region(&win->base, win->size, align, + + if (!(s->cap.features & SS_CAP_STATIC_MAP) && + find_mem_region(&win->base, win->size, align, (req->Attributes & WIN_MAP_BELOW_1MB) || !(s->cap.features & SS_CAP_PAGE_REGS), (*handle)->dev_info)) return CS_IN_USE; - req->Base = win->base; (*handle)->state |= CLIENT_WIN_REQ(w); /* Configure the socket controller */ @@ -1949,14 +1958,15 @@ win->ctl.flags |= MAP_16BIT; if (req->Attributes & WIN_USE_WAIT) win->ctl.flags |= MAP_USE_WAIT; - win->ctl.sys_start = req->Base; - win->ctl.sys_stop = req->Base + req->Size-1; + win->ctl.sys_start = win->base; + win->ctl.sys_stop = win->base + win->size-1; win->ctl.card_start = 0; if (set_mem_map(s, &win->ctl) != 0) return CS_BAD_ARGS; s->state |= SOCKET_WIN_REQ(w); /* Return window handle */ + req->Base = win->ctl.sys_start; *wh = win; return CS_SUCCESS; @@ -2168,7 +2178,7 @@ { #ifdef PCMCIA_DEBUG - if (pc_debug > 1) { + if (pc_debug > 2) { int i; for (i = 0; i < SERVICE_COUNT; i++) if (service_table[i].key == func) break; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h --- v2.4.0-test7/linux/drivers/pcmcia/cs_internal.h Thu Jul 27 17:38:01 2000 +++ linux/drivers/pcmcia/cs_internal.h Wed Sep 6 14:50:25 2000 @@ -1,5 +1,5 @@ /* - * cs_internal.h 1.46 1999/11/08 20:46:49 + * cs_internal.h 1.52 2000/06/12 21:29:37 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c --- v2.4.0-test7/linux/drivers/pcmcia/ds.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/pcmcia/ds.c Sat Sep 2 00:13:49 2000 @@ -2,7 +2,7 @@ PC Card Driver Services - ds.c 1.104 2000/01/11 01:18:02 + ds.c 1.108 2000/08/07 19:06:15 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -61,12 +61,12 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static const char *version = -"ds.c 1.104 2000/01/11 01:18:02 (David Hinds)"; +"ds.c 1.108 2000/08/07 19:06:15 (David Hinds)"; #else #define DEBUG(n, args...) #endif -MODULE_AUTHOR("David Hinds "); +MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE); /*====================================================================*/ @@ -81,6 +81,7 @@ typedef struct socket_bind_t { driver_info_t *driver; + u_char function; dev_link_t *instance; struct socket_bind_t *next; } socket_bind_t; @@ -391,7 +392,8 @@ } for (b = s->bind; b; b = b->next) - if (driver == b->driver) + if ((driver == b->driver) && + (bind_info->function == b->function)) break; if (b != NULL) { bind_info->instance = b->instance; @@ -413,6 +415,7 @@ driver->use_count++; b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL); b->driver = driver; + b->function = bind_info->function; b->instance = NULL; b->next = s->bind; s->bind = b; @@ -475,16 +478,14 @@ #endif for (b = s->bind; b; b = b->next) - if (strcmp((char *)b->driver->dev_info, - (char *)bind_info->dev_info) == 0) + if ((strcmp((char *)b->driver->dev_info, + (char *)bind_info->dev_info) == 0) && + (b->function == bind_info->function)) break; if (b == NULL) return -ENODEV; - - if (b->instance == NULL) - return -EAGAIN; - if (b->instance->state & DEV_CONFIG_PENDING) + if ((b->instance == NULL) || + (b->instance->state & DEV_CONFIG_PENDING)) return -EAGAIN; - if (first) node = b->instance->dev; else @@ -511,8 +512,9 @@ DEBUG(2, "unbind_request(%d, '%s')\n", i, (char *)bind_info->dev_info); for (b = &s->bind; *b; b = &(*b)->next) - if (strcmp((char *)(*b)->driver->dev_info, - (char *)bind_info->dev_info) == 0) + if ((strcmp((char *)(*b)->driver->dev_info, + (char *)bind_info->dev_info) == 0) && + ((*b)->function == bind_info->function)) break; if (*b == NULL) return -ENODEV; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c --- v2.4.0-test7/linux/drivers/pcmcia/rsrc_mgr.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/pcmcia/rsrc_mgr.c Sat Sep 2 00:13:49 2000 @@ -2,7 +2,7 @@ Resource management routines - rsrc_mgr.c 1.77 1999/11/16 03:32:59 + rsrc_mgr.c 1.79 2000/08/30 20:23:58 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -58,14 +58,12 @@ /* Parameters that can be set with 'insmod' */ -/* Should we probe resources for conflicts? */ -static int probe_mem = 1; -MODULE_PARM(probe_mem, "i"); +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") + +INT_MODULE_PARM(probe_mem, 1); /* memory probe? */ #ifdef CONFIG_ISA -static int probe_io = 1; -static int mem_limit = 0x10000; -MODULE_PARM(probe_io, "i"); -MODULE_PARM(mem_limit, "i"); +INT_MODULE_PARM(probe_io, 1); /* IO port probe? */ +INT_MODULE_PARM(mem_limit, 0x10000); #endif /*====================================================================== diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/rsrc_mgr.h linux/drivers/pcmcia/rsrc_mgr.h --- v2.4.0-test7/linux/drivers/pcmcia/rsrc_mgr.h Thu Nov 11 20:11:43 1999 +++ linux/drivers/pcmcia/rsrc_mgr.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * rsrc_mgr.h 1.19 1999/10/25 20:03:34 + * rsrc_mgr.h 1.20 2000/06/12 21:29:37 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.4.0-test7/linux/drivers/pcmcia/yenta.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/pcmcia/yenta.c Wed Sep 6 11:48:58 2000 @@ -438,7 +438,7 @@ u8 csc; u32 cb_event; unsigned int events; - + /* Clear interrupt status for the event */ cb_event = cb_readl(socket, CB_SOCKET_EVENT); cb_writel(socket, CB_SOCKET_EVENT, cb_event); @@ -552,6 +552,12 @@ daemonize(); strcpy(current->comm, "CardBus Watcher"); + if (request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->name, socket)) { + printk ("Yenta: unable to register irq %d\n", socket->cb_irq); + MOD_DEC_USE_COUNT; + return (1); + } + /* Figure out what the dang thing can do for the PCMCIA layer... */ yenta_get_socket_capabilities(socket, isa_interrupts); printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); @@ -808,8 +814,7 @@ /* Set up the bridge regions.. */ yenta_allocate_resources(socket); - if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket)) - socket->cb_irq = dev->irq; + socket->cb_irq = dev->irq; /* Do we have special options for the device? */ for (i = 0; i < NR_OVERRIDES; i++) { diff -u --recursive --new-file v2.4.0-test7/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.4.0-test7/linux/drivers/pnp/isapnp.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/pnp/isapnp.c Mon Aug 28 22:13:12 2000 @@ -529,7 +529,7 @@ (*res)->irq = irq; #ifdef CONFIG_PCI for (i=0; i<16; i++) - if (irq->map & i) + if (irq->map & (1< 0) { unsigned char byte; - get_user_ret(byte, c, -EFAULT); + if (get_user(byte, c)) + return -EFAULT; c += 1; rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor); @@ -735,7 +739,8 @@ unsigned char byte; int rc; - get_user_ret(byte, c, -EFAULT); + if (get_user(byte, c)) + return -EFAULT; rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor); if (rc == -1) return -ETIMEDOUT; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sbus/char/display7seg.c linux/drivers/sbus/char/display7seg.c --- v2.4.0-test7/linux/drivers/sbus/char/display7seg.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/sbus/char/display7seg.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: display7seg.c,v 1.2 2000/08/02 06:22:35 davem Exp $ +/* $Id: display7seg.c,v 1.3 2000/08/29 07:01:55 davem Exp $ * * display7seg - Driver implementation for the 7-segment display * present on Sun Microsystems CP1400 and CP1500 @@ -18,7 +18,7 @@ #include /* request_region, check_region */ #include /* EBus device */ #include /* OpenProm Library */ -#include /* put_/get_user_ret */ +#include /* put_/get_user */ #include @@ -132,7 +132,8 @@ /* assign device register values * we mask-out D7S_FLIP if in sol_compat mode */ - get_user_ret(ireg, (int *) arg, -EFAULT); + if (get_user(ireg, (int *) arg)) + return -EFAULT; if (0 != sol_compat) { (regs & D7S_FLIP) ? (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP); @@ -147,7 +148,8 @@ * This driver will not misinform you about the state * of your hardware while in sol_compat mode */ - put_user_ret(regs, (int *) arg, -EFAULT); + if (put_user(regs, (int *) arg)) + return -EFAULT; break; case D7SIOCTM: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c --- v2.4.0-test7/linux/drivers/sbus/char/openprom.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/sbus/char/openprom.c Tue Aug 29 14:09:15 2000 @@ -73,7 +73,8 @@ if (!info || !opp_p) return -EFAULT; - get_user_ret(bufsize, &info->oprom_size, -EFAULT); + if (get_user(bufsize, &info->oprom_size)) + return -EFAULT; if (bufsize == 0) return -EINVAL; @@ -132,7 +133,8 @@ */ static int copyout(void *info, struct openpromio *opp, int len) { - copy_to_user_ret(info, opp, len, -EFAULT); + if (copy_to_user(info, opp, len)) + return -EFAULT; return 0; } @@ -364,7 +366,8 @@ switch (cmd) { case OPIOCGET: - copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT); + if (copy_from_user(&op, (void *)arg, sizeof(op))) + return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; @@ -386,9 +389,10 @@ if (len <= 0) { kfree(str); - /* Verified by the above copy_from_user_ret */ - __copy_to_user_ret((void *)arg, &op, - sizeof(op), -EFAULT); + /* Verified by the above copy_from_user */ + if (__copy_to_user((void *)arg, &op, + sizeof(op))) + return -EFAULT; return 0; } @@ -414,7 +418,8 @@ return error; case OPIOCNEXTPROP: - copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT); + if (copy_from_user(&op, (void *)arg, sizeof(op))) + return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; @@ -457,7 +462,8 @@ return error; case OPIOCSET: - copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT); + if (copy_from_user(&op, (void *)arg, sizeof(op))) + return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; @@ -485,13 +491,14 @@ return 0; case OPIOCGETOPTNODE: - copy_to_user_ret((void *)arg, &options_node, - sizeof(int), -EFAULT); + if (copy_to_user((void *)arg, &options_node, sizeof(int))) + return -EFAULT; return 0; case OPIOCGETNEXT: case OPIOCGETCHILD: - copy_from_user_ret(&node, (void *)arg, sizeof(int), -EFAULT); + if (copy_from_user(&node, (void *)arg, sizeof(int))) + return -EFAULT; save_and_cli(flags); if (cmd == OPIOCGETNEXT) @@ -500,7 +507,8 @@ node = __prom_getchild(node); restore_flags(flags); - __copy_to_user_ret((void *)arg, &node, sizeof(int), -EFAULT); + if (__copy_to_user((void *)arg, &node, sizeof(int))) + return -EFAULT; return 0; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.4.0-test7/linux/drivers/sbus/char/rtc.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sbus/char/rtc.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.22 2000/08/22 06:56:33 davem Exp $ +/* $Id: rtc.c,v 1.23 2000/08/29 07:01:55 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -97,7 +97,8 @@ case RTCGET: get_rtc_time(&rtc_tm); - copy_to_user_ret((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time), -EFAULT); + if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) + return -EFAULT; return 0; @@ -106,7 +107,8 @@ if (!capable(CAP_SYS_TIME)) return -EPERM; - copy_from_user_ret(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time), -EFAULT); + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + return -EFAULT; set_rtc_time(&rtc_tm); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.4.0-test7/linux/drivers/sbus/char/sunkbd.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/sbus/char/sunkbd.c Tue Aug 29 14:09:15 2000 @@ -1346,19 +1346,22 @@ #ifdef CONFIG_SPARC32_COMPAT if (current->thread.flags & SPARC_FLAG_32BIT) { - copy_to_user_ret((Firm_event *)p, &this_event, - sizeof(Firm_event)-sizeof(struct timeval), - -EFAULT); + if (copy_to_user((Firm_event *)p, &this_event, + sizeof(Firm_event)-sizeof(struct timeval))) + return -EFAULT; p += sizeof(Firm_event)-sizeof(struct timeval); - __put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT); + if (__put_user(this_event.time.tv_sec, (u32 *)p)) + return -EFAULT; p += sizeof(u32); - __put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT); + if (__put_user(this_event.time.tv_usec, (u32 *)p)) + return -EFAULT; p += sizeof(u32); } else #endif { - copy_to_user_ret((Firm_event *)p, &this_event, - sizeof(Firm_event), -EFAULT); + if (copy_to_user((Firm_event *)p, &this_event, + sizeof(Firm_event))) + return -EFAULT; p += sizeof (Firm_event); } #ifdef KBD_DEBUG @@ -1401,22 +1404,27 @@ switch (cmd){ case KIOCTYPE: /* return keyboard type */ - put_user_ret(sunkbd_type, (int *) arg, -EFAULT); + if (put_user(sunkbd_type, (int *) arg)) + return -EFAULT; break; case KIOCGTRANS: - put_user_ret(TR_UNTRANS_EVENT, (int *) arg, -EFAULT); + if (put_user(TR_UNTRANS_EVENT, (int *) arg)) + return -EFAULT; break; case KIOCTRANS: - get_user_ret(value, (int *) arg, -EFAULT); + if (get_user(value, (int *) arg)) + return -EFAULT; if (value != TR_UNTRANS_EVENT) return -EINVAL; break; case KIOCLAYOUT: - put_user_ret(sunkbd_layout, (int *) arg, -EFAULT); + if (put_user(sunkbd_layout, (int *) arg)) + return -EFAULT; break; case KIOCSDIRECT: #ifndef CODING_NEW_DRIVER - get_user_ret(value, (int *) arg, -EFAULT); + if (get_user(value, (int *) arg)) + return -EFAULT; if(value) kbd_redirected = fg_console + 1; else @@ -1425,7 +1433,8 @@ #endif break; case KIOCCMD: - get_user_ret(value, (int *) arg, -EFAULT); + if (get_user(value, (int *) arg)) + return -EFAULT; c = (unsigned char) value; switch (c) { case SKBDCMD_CLICK: @@ -1444,8 +1453,9 @@ return -EINVAL; } case KIOCSLED: - get_user_ret(c, (unsigned char *) arg, -EFAULT); - + if (get_user(c, (unsigned char *) arg)) + return -EFAULT; + if (c & LED_SCRLCK) leds |= (1 << VC_SCROLLOCK); if (c & LED_NLOCK) leds |= (1 << VC_NUMLOCK); if (c & LED_CLOCK) leds |= (1 << VC_CAPSLOCK); @@ -1453,7 +1463,8 @@ sun_setledstate(kbd_table + fg_console, leds); break; case KIOCGLED: - put_user_ret(vcleds_to_sunkbd(getleds()), (unsigned char *) arg, -EFAULT); + if (put_user(vcleds_to_sunkbd(getleds()), (unsigned char *) arg)) + return -EFAULT; break; case KIOCGRATE: { @@ -1465,8 +1476,9 @@ else rate.rate = 0; - copy_to_user_ret((struct kbd_rate *)arg, &rate, - sizeof(struct kbd_rate), -EFAULT); + if (copy_to_user((struct kbd_rate *)arg, &rate, + sizeof(struct kbd_rate))) + return -EFAULT; return 0; } @@ -1495,7 +1507,8 @@ int count; count = kbd_head - kbd_tail; - put_user_ret((count < 0) ? KBD_QSIZE - count : count, (int *) arg, -EFAULT); + if (put_user((count < 0) ? KBD_QSIZE - count : count, (int *) arg)) + return -EFAULT; return 0; } default: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.4.0-test7/linux/drivers/sbus/char/sunmouse.c Fri Jul 14 12:12:12 2000 +++ linux/drivers/sbus/char/sunmouse.c Tue Aug 29 14:09:15 2000 @@ -462,21 +462,24 @@ ((sizeof(Firm_event) - sizeof(struct timeval) + (sizeof(u32) * 2)))) break; - copy_to_user_ret((Firm_event *)p, &this_event, - sizeof(Firm_event)-sizeof(struct timeval), - -EFAULT); + if (copy_to_user((Firm_event *)p, &this_event, + sizeof(Firm_event)-sizeof(struct timeval))) + return -EFAULT; p += sizeof(Firm_event)-sizeof(struct timeval); - __put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT); + if (__put_user(this_event.time.tv_sec, (u32 *)p)) + return -EFAULT; p += sizeof(u32); - __put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT); + if (__put_user(this_event.time.tv_usec, (u32 *)p)) + return -EFAULT; p += sizeof(u32); } else #endif { if ((end - p) < sizeof(Firm_event)) break; - copy_to_user_ret((Firm_event *)p, &this_event, - sizeof(Firm_event), -EFAULT); + if (copy_to_user((Firm_event *)p, &this_event, + sizeof(Firm_event))) + return -EFAULT; p += sizeof (Firm_event); } spin_lock_irqsave(&sunmouse.lock, flags); @@ -540,16 +543,19 @@ switch (cmd){ /* VUIDGFORMAT - Get input device byte stream format */ case _IOR('v', 2, int): - put_user_ret(sunmouse.vuid_mode, (int *) arg, -EFAULT); + if (put_user(sunmouse.vuid_mode, (int *) arg)) + return -EFAULT; break; /* VUIDSFORMAT - Set input device byte stream format*/ case _IOW('v', 1, int): - get_user_ret(i, (int *) arg, -EFAULT); + if (get_user(i, (int *) arg)) + return -EFAULT; if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){ int value; - get_user_ret(value, (int *)arg, -EFAULT); + if (get_user(value, (int *)arg)) + return -EFAULT; spin_lock_irq(&sunmouse.lock); sunmouse.vuid_mode = value; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.4.0-test7/linux/drivers/sbus/char/zs.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/sbus/char/zs.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.58 2000/07/06 01:41:38 davem Exp $ +/* $Id: zs.c,v 1.59 2000/08/29 07:01:55 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1319,7 +1319,8 @@ tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.custom_divisor = info->custom_divisor; - copy_to_user_ret(retinfo,&tmp,sizeof(*retinfo), -EFAULT); + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; return 0; } @@ -1390,7 +1391,8 @@ ZSDELAY(); ZSLOG(REGCTRL, status, 0); sti(); - put_user_ret(status, value, -EFAULT); + if (put_user(status, value)) + return -EFAULT; return 0; } @@ -1409,7 +1411,8 @@ | ((status & DCD) ? TIOCM_CAR : 0) | ((status & SYNC) ? TIOCM_DSR : 0) | ((status & CTS) ? TIOCM_CTS : 0); - put_user_ret(result, value, -EFAULT); + if (put_user(result, value)) + return -EFAULT; return 0; } @@ -1418,7 +1421,8 @@ { unsigned int arg; - get_user_ret(arg, value, -EFAULT); + if (get_user(arg, value)) + return -EFAULT; switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) @@ -1494,11 +1498,13 @@ send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: - put_user_ret(C_CLOCAL(tty) ? 1 : 0, - (unsigned long *) arg, -EFAULT); + if (put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg)) + return -EFAULT; return 0; case TIOCSSOFTCAR: - get_user_ret(arg, (unsigned long *) arg, -EFAULT); + if (get_user(arg, (unsigned long *) arg)) + return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); @@ -1519,8 +1525,9 @@ return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: - copy_to_user_ret((struct sun_serial *) arg, - info, sizeof(struct sun_serial), -EFAULT); + if (copy_to_user((struct sun_serial *) arg, + info, sizeof(struct sun_serial))) + return -EFAULT; return 0; default: @@ -1906,7 +1913,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.58 $"; + char *revision = "$Revision: 1.59 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v2.4.0-test7/linux/drivers/scsi/esp.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/esp.c Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: esp.c,v 1.94 2000/03/30 02:09:10 davem Exp $ +/* $Id: esp.c,v 1.96 2000/08/24 03:51:26 davem Exp $ * esp.c: EnhancedScsiProcessor Sun SCSI driver code. * * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) @@ -32,13 +32,16 @@ #include #include #include -#include #include #include #include #include #include + +#ifndef __sparc_v9__ +#include #include +#endif #include @@ -1596,7 +1599,9 @@ if (SDptr->sync) { /* this targets sync is known */ +#ifndef __sparc_v9__ do_sync_known: +#endif if (SDptr->disconnect) *cmdp++ = IDENTIFY(1, lun); else @@ -1634,6 +1639,7 @@ */ int cdrom_hwbug_wkaround = 0; +#ifndef __sparc_v9__ /* Never allow disconnects or synchronous transfers on * SparcStation1 and SparcStation1+. Allowing those * to be enabled seems to lockup the machine completely. @@ -1654,6 +1660,7 @@ esp->snip = 0; goto do_sync_known; } +#endif /* !(__sparc_v9__) */ /* We've talked to this guy before, * but never negotiated. Let's try, @@ -2578,6 +2585,8 @@ esp_advance_phase(SCptr, thisphase); ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT")); hmuch = dma_can_transfer(esp, SCptr); + if (hmuch > (64 * 1024) && (esp->erev != fashme)) + hmuch = (64 * 1024); ESPDATA(("hmuch<%d> ", hmuch)); esp->current_transfer_size = hmuch; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/ips.h linux/drivers/scsi/ips.h --- v2.4.0-test7/linux/drivers/scsi/ips.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/scsi/ips.h Wed Sep 6 14:51:17 2000 @@ -96,10 +96,6 @@ #define __PUT_USER __put_user #endif - #ifndef PUT_USER_RET - #define PUT_USER_RET put_user_ret - #endif - #ifndef GET_USER #define GET_USER get_user #endif @@ -108,10 +104,6 @@ #define __GET_USER __get_user #endif - #ifndef GET_USER_RET - #define GET_USER_RET get_user_ret - #endif - /* * Lock macros */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/pcmcia/aha152x_stub.c linux/drivers/scsi/pcmcia/aha152x_stub.c --- v2.4.0-test7/linux/drivers/scsi/pcmcia/aha152x_stub.c Thu May 11 15:30:07 2000 +++ linux/drivers/scsi/pcmcia/aha152x_stub.c Sat Sep 2 00:15:37 2000 @@ -5,7 +5,7 @@ This driver supports the Adaptec AHA-1460, the New Media Bus Toaster, and the New Media Toast & Jam. - aha152x_cs.c 1.53 2000/05/04 01:30:00 + aha152x_cs.c 1.54 2000/06/12 21:27:25 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -18,7 +18,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -62,7 +62,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"aha152x_cs.c 1.53 2000/05/04 01:30:00 (David Hinds)"; +"aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)"; #else #define DEBUG(n, args...) #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/pcmcia/apa1480_stub.c linux/drivers/scsi/pcmcia/apa1480_stub.c --- v2.4.0-test7/linux/drivers/scsi/pcmcia/apa1480_stub.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/pcmcia/apa1480_stub.c Sat Sep 2 00:15:37 2000 @@ -2,7 +2,7 @@ A driver for the Adaptec APA1480 CardBus SCSI Host Adapter - apa1480_cb.c 1.19 2000/02/14 22:39:25 + apa1480_cb.c 1.22 2000/06/12 21:27:25 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -55,7 +55,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"apa1480_cb.c 1.19 2000/02/14 22:39:25 (David Hinds)"; +"apa1480_cb.c 1.22 2000/06/12 21:27:25 (David Hinds)"; #else #define DEBUG(n, args...) #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/pcmcia/fdomain_stub.c linux/drivers/scsi/pcmcia/fdomain_stub.c --- v2.4.0-test7/linux/drivers/scsi/pcmcia/fdomain_stub.c Thu May 11 15:30:07 2000 +++ linux/drivers/scsi/pcmcia/fdomain_stub.c Sat Sep 2 00:15:37 2000 @@ -2,7 +2,7 @@ A driver for Future Domain-compatible PCMCIA SCSI cards - fdomain_cs.c 1.42 2000/05/04 01:30:00 + fdomain_cs.c 1.43 2000/06/12 21:27:25 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -59,7 +59,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"fdomain_cs.c 1.42 2000/05/04 01:30:00 (David Hinds)"; +"fdomain_cs.c 1.43 2000/06/12 21:27:25 (David Hinds)"; #else #define DEBUG(n, args...) #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/pcmcia/qlogic_stub.c linux/drivers/scsi/pcmcia/qlogic_stub.c --- v2.4.0-test7/linux/drivers/scsi/pcmcia/qlogic_stub.c Thu May 11 15:30:07 2000 +++ linux/drivers/scsi/pcmcia/qlogic_stub.c Sat Sep 2 00:15:37 2000 @@ -2,7 +2,7 @@ A driver for the Qlogic SCSI card - qlogic_cs.c 1.78 2000/05/04 01:30:00 + qlogic_cs.c 1.79 2000/06/12 21:27:26 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -15,7 +15,7 @@ rights and limitations under the License. The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds + . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the @@ -66,7 +66,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"qlogic_cs.c 1.78 2000/05/04 01:30:00 (David Hinds)"; +"qlogic_cs.c 1.79 2000/06/12 21:27:26 (David Hinds)"; #else #define DEBUG(n, args...) #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.4.0-test7/linux/drivers/scsi/qlogicpti.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/qlogicpti.c Mon Aug 28 12:00:08 2000 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/scsi_dma.c linux/drivers/scsi/scsi_dma.c --- v2.4.0-test7/linux/drivers/scsi/scsi_dma.c Fri Mar 10 16:40:43 2000 +++ linux/drivers/scsi/scsi_dma.c Tue Sep 5 14:08:55 2000 @@ -260,6 +260,7 @@ new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth; } else if (SDpnt->type == TYPE_SCANNER || SDpnt->type == TYPE_PROCESSOR || + SDpnt->type == TYPE_COMM || SDpnt->type == TYPE_MEDIUM_CHANGER || SDpnt->type == TYPE_ENCLOSURE) { new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c --- v2.4.0-test7/linux/drivers/scsi/scsi_scan.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/scsi/scsi_scan.c Tue Sep 5 14:08:55 2000 @@ -578,6 +578,7 @@ case TYPE_SCANNER: case TYPE_MEDIUM_CHANGER: case TYPE_ENCLOSURE: + case TYPE_COMM: SDpnt->writeable = 1; break; case TYPE_WORM: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.4.0-test7/linux/drivers/scsi/sd.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/scsi/sd.c Tue Sep 5 14:40:38 2000 @@ -957,17 +957,23 @@ /* FLOPTICAL */ /* - * for removable scsi disk ( FLOPTICAL ) we have to recognise - * the Write Protect Flag. This flag is kept in the Scsi_Disk struct - * and tested at open ! + * For removable scsi disk ( FLOPTICAL ) we have to recognise + * the Write Protect Flag. This flag is kept in the Scsi_Disk + * struct and tested at open ! * Daniel Roche ( dan@lectra.fr ) + * + * Changed to get all pages (0x3f) rather than page 1 to + * get around devices which do not have a page 1. Since + * we're only interested in the header anyway, this should + * be fine. + * -- Matthew Dharm (mdharm-scsi@one-eyed-alien.net) */ memset((void *) &cmd[0], 0, 8); cmd[0] = MODE_SENSE; cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; - cmd[2] = 1; /* page code 1 ?? */ - cmd[4] = 12; + cmd[2] = 0x3f; /* Get all pages */ + cmd[4] = 8; /* But we only want the 8 byte header */ SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[2] = 0; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.4.0-test7/linux/drivers/scsi/sr.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/scsi/sr.c Tue Sep 5 13:46:15 2000 @@ -28,6 +28,9 @@ * Modified by Jens Axboe - support DVD-RAM * transparently and loose the GHOST hack * + * Modified by Arnaldo Carvalho de Melo + * check resource allocation in sr_init and some cleanups + * */ #include @@ -82,11 +85,11 @@ init_command:sr_init_command }; -Scsi_CD *scsi_CDs = NULL; -static int *sr_sizes = NULL; +Scsi_CD *scsi_CDs; +static int *sr_sizes; -static int *sr_blocksizes = NULL; -static int *sr_hardsizes = NULL; +static int *sr_blocksizes; +static int *sr_hardsizes; static int sr_open(struct cdrom_device_info *, int); void get_sectorsize(int); @@ -710,30 +713,45 @@ } if (scsi_CDs) return 0; - sr_template.dev_max = - sr_template.dev_noticed + SR_EXTRA_DEVS; - scsi_CDs = (Scsi_CD *) kmalloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); + + sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS; + scsi_CDs = kmalloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); + if (!scsi_CDs) + goto cleanup_devfs; memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); - sr_sizes = (int *) kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + sr_sizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + if (!sr_sizes) + goto cleanup_cds; memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); - sr_blocksizes = (int *) kmalloc(sr_template.dev_max * - sizeof(int), GFP_ATOMIC); - - sr_hardsizes = (int *) kmalloc(sr_template.dev_max * - sizeof(int), GFP_ATOMIC); + sr_blocksizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + if (!sr_blocksizes) + goto cleanup_sizes; + + sr_hardsizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + if (!sr_hardsizes) + goto cleanup_blocksizes; /* * These are good guesses for the time being. */ - for (i = 0; i < sr_template.dev_max; i++) - { + for (i = 0; i < sr_template.dev_max; i++) { sr_blocksizes[i] = 2048; sr_hardsizes[i] = 2048; } blksize_size[MAJOR_NR] = sr_blocksizes; hardsect_size[MAJOR_NR] = sr_hardsizes; return 0; +cleanup_blocksizes: + kfree(sr_blocksizes); +cleanup_sizes: + kfree(sr_sizes); +cleanup_cds: + kfree(scsi_CDs); +cleanup_devfs: + devfs_unregister_blkdev(MAJOR_NR, "sr"); + sr_registered--; + return 1; } void sr_finish() @@ -830,29 +848,26 @@ return; } - -#ifdef MODULE - -int init_module(void) +int init_sr(void) { - sr_template.module = &__this_module; + sr_template.module = THIS_MODULE; return scsi_register_module(MODULE_SCSI_DEV, &sr_template); } -void cleanup_module(void) +void exit_sr(void) { scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); devfs_unregister_blkdev(MAJOR_NR, "sr"); sr_registered--; if (scsi_CDs != NULL) { - kfree((char *) scsi_CDs); + kfree(scsi_CDs); - kfree((char *) sr_sizes); + kfree(sr_sizes); sr_sizes = NULL; - kfree((char *) sr_blocksizes); + kfree(sr_blocksizes); sr_blocksizes = NULL; - kfree((char *) sr_hardsizes); + kfree(sr_hardsizes); sr_hardsizes = NULL; } blksize_size[MAJOR_NR] = NULL; @@ -863,23 +878,5 @@ sr_template.dev_max = 0; } -#endif /* MODULE */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ +module_init(init_sr); +module_exit(exit_sr); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.4.0-test7/linux/drivers/scsi/sr_ioctl.c Sat Feb 26 22:31:48 2000 +++ linux/drivers/scsi/sr_ioctl.c Tue Sep 5 13:46:15 2000 @@ -284,6 +284,8 @@ int result, target = MINOR(cdi->dev); unsigned char buffer[32]; + memset(sr_cmd, 0, sizeof(sr_cmd)); + switch (cmd) { case CDROMREADTOCHDR: { @@ -292,10 +294,7 @@ sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - sr_cmd[6] = 0; - sr_cmd[7] = 0; /* MSB of length (12) */ sr_cmd[8] = 12; /* LSB of length */ - sr_cmd[9] = 0; result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ); @@ -314,9 +313,7 @@ (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; sr_cmd[6] = tocentry->cdte_track; - sr_cmd[7] = 0; /* MSB of length (12) */ sr_cmd[8] = 12; /* LSB of length */ - sr_cmd[9] = 0; result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ); @@ -333,6 +330,20 @@ break; } + + case CDROMPLAYTRKIND: { + struct cdrom_ti* ti = (struct cdrom_ti*)arg; + + sr_cmd[0] = GPCMD_PLAYAUDIO_TI; + sr_cmd[1] = scsi_CDs[target].device->lun << 5; + sr_cmd[4] = ti->cdti_trk0; + sr_cmd[5] = ti->cdti_ind0; + sr_cmd[7] = ti->cdti_trk1; + sr_cmd[8] = ti->cdti_ind1; + + result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0, SCSI_DATA_NONE); + break; + } default: return -EINVAL; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.4.0-test7/linux/drivers/scsi/st.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/scsi/st.c Wed Sep 6 12:53:14 2000 @@ -3486,6 +3486,8 @@ if (tmp_da == NULL || tmp_ba == NULL) { if (tmp_da != NULL) kfree(tmp_da); + if (tmp_ba != NULL) + kfree(tmp_ba); SDp->attached--; write_unlock_irqrestore(&st_dev_arr_lock, flags); printk(KERN_ERR "st: Can't extend device array.\n"); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h --- v2.4.0-test7/linux/drivers/scsi/tmscsim.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/tmscsim.h Tue Sep 5 14:08:55 2000 @@ -442,7 +442,6 @@ /* see include/scsi/scsi.h for the rest */ #define TYPE_PRINTER 0x02 /* Printer device */ -#define TYPE_COMM 0x09 /* Communications device */ /* ** Inquiry flag definitions (Inq data byte 7) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c --- v2.4.0-test7/linux/drivers/sgi/char/graphics.c Fri Jul 14 12:12:12 2000 +++ linux/drivers/sgi/char/graphics.c Tue Aug 29 14:09:15 2000 @@ -100,9 +100,10 @@ i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct gfx_getboardinfo_args)); if (i) return i; - __get_user_ret (board, &bia->board, -EFAULT); - __get_user_ret (dest_buf, &bia->buf, -EFAULT); - __get_user_ret (max_len, &bia->len, -EFAULT); + if (__get_user (board, &bia->board) || + __get_user (dest_buf, &bia->buf) || + __get_user (max_len, &bia->len)) + return -EFAULT; if (board >= boards) return -EINVAL; @@ -125,8 +126,9 @@ i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct gfx_attach_board_args)); if (i) return i; - __get_user_ret (board, &att->board, -EFAULT); - __get_user_ret (vaddr, &att->vaddr, -EFAULT); + if (__get_user (board, &att->board) || + __get_user (vaddr, &att->vaddr)) + return -EFAULT; /* Ok for now we are assuming /dev/graphicsN -> head N even * if the ioctl api suggests that this is not quite the case. diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sgi/char/rrm.c linux/drivers/sgi/char/rrm.c --- v2.4.0-test7/linux/drivers/sgi/char/rrm.c Fri Jun 25 17:39:34 1999 +++ linux/drivers/sgi/char/rrm.c Tue Aug 29 14:09:15 2000 @@ -60,7 +60,8 @@ i = verify_area (VERIFY_READ, arg, rrm_functions [cmd].arg_size); if (i) return i; - __get_user_ret (rnid, (int *) arg, -EFAULT); + if (__get_user (rnid, (int *) arg)) + return -EFAULT; return (*(rrm_functions [cmd].r_fn))(rnid, arg); } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c --- v2.4.0-test7/linux/drivers/sound/ac97_codec.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/ac97_codec.c Tue Aug 29 14:09:15 2000 @@ -419,7 +419,8 @@ if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) { codec->modcnt++; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.4.0-test7/linux/drivers/sound/cmpci.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/cmpci.c Tue Aug 29 14:09:15 2000 @@ -1038,7 +1038,8 @@ s->mix.modcnt++; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; i = hweight32(val); for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!(val & (1 << i))) @@ -1056,7 +1057,8 @@ return 0; case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!(val & (1 << i))) continue; @@ -1075,7 +1077,8 @@ i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; l = val & 0xff; r = (val >> 8) & 0xff; if (l > 100) @@ -1469,7 +1472,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1485,7 +1489,8 @@ return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { @@ -1508,7 +1513,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { fmtd = 0; fmtm = ~0; @@ -1537,7 +1543,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { fmtd = 0; fmtm = ~0; @@ -1574,7 +1581,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) @@ -1671,7 +1679,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1698,7 +1707,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c --- v2.4.0-test7/linux/drivers/sound/cs46xx.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/cs46xx.c Tue Aug 29 14:09:15 2000 @@ -1233,7 +1233,8 @@ return 0; case SNDCTL_DSP_SPEED: /* set smaple rate */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1249,7 +1250,8 @@ return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_WRITE) { stop_dac(state); dmabuf->ready = 0; @@ -1291,7 +1293,8 @@ return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if(val==AFMT_S16_LE/* || val==AFMT_U8*/) { @@ -1315,7 +1318,8 @@ return put_user(AFMT_U8, (int *)arg); case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1340,14 +1344,16 @@ case SNDCTL_DSP_SUBDIVIDE: if (dmabuf->subdivision) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2) return -EINVAL; dmabuf->subdivision = val; return 0; case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; dmabuf->ossfragshift = val & 0xffff; dmabuf->ossmaxfrags = (val >> 16) & 0xffff; @@ -1408,7 +1414,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/dmasound/dmasound_core.c linux/drivers/sound/dmasound/dmasound_core.c --- v2.4.0-test7/linux/drivers/sound/dmasound/dmasound_core.c Fri Jul 14 12:12:12 2000 +++ linux/drivers/sound/dmasound/dmasound_core.c Tue Aug 29 14:09:15 2000 @@ -523,7 +523,8 @@ strncpy(info.name, dmasound.mach.name2, sizeof(info.name)); info.name[sizeof(info.name)-1] = 0; info.modify_counter = mixer.modify_counter; - copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT); + if (copy_to_user((int *)arg, &info, sizeof(info))) + return -EFAULT; return 0; } } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c --- v2.4.0-test7/linux/drivers/sound/emu10k1/audio.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/emu10k1/audio.c Tue Aug 29 14:09:15 2000 @@ -361,7 +361,8 @@ case SNDCTL_DSP_SPEED: DPF(2, "SNDCTL_DSP_SPEED:\n"); - get_user_ret(val, (int *) arg, -EFAULT); + if (get_user(val, (int *) arg)) + return -EFAULT; DPD(2, "val is %d\n", val); if (val > 0) { @@ -415,7 +416,8 @@ case SNDCTL_DSP_STEREO: DPF(2, "SNDCTL_DSP_STEREO:\n"); - get_user_ret(val, (int *) arg, -EFAULT); + if (get_user(val, (int *) arg)) + return -EFAULT; DPD(2, " val is %d\n", val); if (file->f_mode & FMODE_READ) { @@ -460,7 +462,8 @@ case SNDCTL_DSP_CHANNELS: DPF(2, "SNDCTL_DSP_CHANNELS:\n"); - get_user_ret(val, (int *) arg, -EFAULT); + if (get_user(val, (int *) arg)) + return -EFAULT; DPD(2, " val is %d\n", val); if (val > 0) { @@ -522,7 +525,8 @@ case SNDCTL_DSP_SETFMT: /* Same as SNDCTL_DSP_SAMPLESIZE */ DPF(2, "SNDCTL_DSP_SETFMT:\n"); - get_user_ret(val, (int *) arg, -EFAULT); + if (get_user(val, (int *) arg)) + return -EFAULT; DPD(2, " val is %d\n", val); if (val != AFMT_QUERY) { @@ -624,7 +628,8 @@ case SNDCTL_DSP_SETTRIGGER: DPF(2, "SNDCTL_DSP_SETTRIGGER:\n"); - get_user_ret(val, (int *) arg, -EFAULT); + if (get_user(val, (int *) arg)) + return -EFAULT; if (file->f_mode & FMODE_WRITE) { spin_lock_irqsave(&woinst->lock, flags); @@ -850,7 +855,8 @@ case SNDCTL_DSP_SETFRAGMENT: DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n"); - get_user_ret(val, (int *) arg, -EFAULT); + if (get_user(val, (int *) arg)) + return -EFAULT; DPD(2, "val is 0x%x\n", val); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/emu10k1/mixer.c linux/drivers/sound/emu10k1/mixer.c --- v2.4.0-test7/linux/drivers/sound/emu10k1/mixer.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/emu10k1/mixer.c Tue Aug 29 14:09:15 2000 @@ -1038,7 +1038,8 @@ if (card->isaps) return -EINVAL; - get_user_ret(val, (int *) arg, -EFAULT); + if (get_user(val, (int *) arg)) + return -EFAULT; i = hweight32(val); if (i == 0) return 0; /* val = mixer_recmask(s); */ @@ -1062,7 +1063,8 @@ if (i >= SOUND_MIXER_NRDEVICES) return -EINVAL; - get_user_ret(val, (int *) arg, -EFAULT); + if (get_user(val, (int *) arg)) + return -EFAULT; if (emu10k1_mixer_wrch(card, i, val)) return -EINVAL; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.4.0-test7/linux/drivers/sound/es1370.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/es1370.c Tue Aug 29 14:09:15 2000 @@ -842,7 +842,8 @@ VALIDATE_STATE(s); if (cmd == SOUND_MIXER_PRIVATE1) { /* enable/disable/query mixer preamp */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != -1) { s->mix.micpreamp = !!val; wrcodec(s, 0x19, s->mix.micpreamp); @@ -851,7 +852,8 @@ } if (cmd == SOUND_MIXER_PRIVATE2) { /* enable/disable/query use of linein as second lineout */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != -1) { spin_lock_irqsave(&s->lock, flags); if (val) @@ -865,7 +867,8 @@ } if (cmd == SOUND_MIXER_PRIVATE3) { /* enable/disable/query microphone impedance setting */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != -1) { spin_lock_irqsave(&s->lock, flags); if (val) @@ -941,12 +944,14 @@ switch (_IOC_NR(cmd)) { case SOUND_MIXER_IMIX: - get_user_ret(s->mix.imix, (int *)arg, -EFAULT); + if (get_user(s->mix.imix, (int *)arg)) + return -EFAULT; set_recsrc(s, s->mix.recsrc); return 0; case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; set_recsrc(s, val); return 0; @@ -954,7 +959,8 @@ i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; l = val & 0xff; if (l > 100) l = 100; @@ -1382,7 +1388,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE)) return -EINVAL; @@ -1401,7 +1408,8 @@ return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; @@ -1427,7 +1435,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1458,7 +1467,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1498,7 +1508,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) @@ -1609,7 +1620,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1636,7 +1648,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -1916,7 +1929,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -1931,7 +1945,8 @@ return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; stop_dac1(s); s->dma_dac1.ready = 0; spin_lock_irqsave(&s->lock, flags); @@ -1944,7 +1959,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (s->dma_dac1.mapped) return -EINVAL; @@ -1964,7 +1980,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -1985,7 +2002,8 @@ return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) return ret; @@ -2044,7 +2062,8 @@ return put_user(s->dma_dac1.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; s->dma_dac1.ossfragshift = val & 0xffff; s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff; if (s->dma_dac1.ossfragshift < 4) @@ -2058,7 +2077,8 @@ case SNDCTL_DSP_SUBDIVIDE: if (s->dma_dac1.subdivision) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; s->dma_dac1.subdivision = val; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.4.0-test7/linux/drivers/sound/es1371.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/es1371.c Tue Aug 29 14:09:15 2000 @@ -1165,7 +1165,8 @@ return 0; case SOUND_MIXER_WRITE_PCM: /* use SRC for PCM volume */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; right = ((val >> 8) & 0xff); left = (val & 0xff); if (right > 100) @@ -1570,7 +1571,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1586,7 +1588,8 @@ return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; @@ -1612,7 +1615,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1643,7 +1647,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1683,7 +1688,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) @@ -1794,7 +1800,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1821,7 +1828,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -2100,7 +2108,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -2109,7 +2118,8 @@ return put_user(s->dac1rate, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; stop_dac1(s); s->dma_dac1.ready = 0; spin_lock_irqsave(&s->lock, flags); @@ -2122,7 +2132,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -2140,7 +2151,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -2161,7 +2173,8 @@ return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) return ret; @@ -2220,7 +2233,8 @@ return put_user(s->dma_dac1.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; s->dma_dac1.ossfragshift = val & 0xffff; s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff; if (s->dma_dac1.ossfragshift < 4) @@ -2234,7 +2248,8 @@ case SNDCTL_DSP_SUBDIVIDE: if (s->dma_dac1.subdivision) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; s->dma_dac1.subdivision = val; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.4.0-test7/linux/drivers/sound/esssolo1.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/esssolo1.c Tue Aug 29 14:09:15 2000 @@ -686,7 +686,8 @@ if (cmd == SOUND_MIXER_PRIVATE1) { /* enable/disable/query mixer preamp */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != -1) { val = val ? 0xff : 0xf7; write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val); @@ -696,7 +697,8 @@ } if (cmd == SOUND_MIXER_PRIVATE2) { /* enable/disable/query spatializer */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != -1) { val &= 0x3f; write_mixer(s, 0x52, val); @@ -773,7 +775,8 @@ 0xb4, read_ctrl(s, 0xb4)); } #endif - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; i = hweight32(val); if (i == 0) return 0; @@ -789,7 +792,8 @@ return 0; case SOUND_MIXER_VOLUME: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; l = val & 0xff; if (l > 100) l = 100; @@ -820,7 +824,8 @@ return put_user(s->mix.vol[9], (int *)arg); case SOUND_MIXER_SPEAKER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; l = val & 0xff; if (l > 100) l = 100; @@ -837,7 +842,8 @@ return put_user(s->mix.vol[7], (int *)arg); case SOUND_MIXER_RECLEV: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; l = (val << 1) & 0x1fe; if (l > 200) l = 200; @@ -864,7 +870,8 @@ i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; l = (val << 1) & 0x1fe; if (l > 200) l = 200; @@ -1268,7 +1275,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { stop_adc(s); stop_dac(s); @@ -1295,7 +1303,8 @@ return put_user(s->rate, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; stop_adc(s); stop_dac(s); s->dma_adc.ready = s->dma_dac.ready = 0; @@ -1305,7 +1314,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { stop_adc(s); stop_dac(s); @@ -1320,7 +1330,8 @@ return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { stop_adc(s); stop_dac(s); @@ -1346,7 +1357,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) @@ -1459,7 +1471,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1486,7 +1499,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.4.0-test7/linux/drivers/sound/i810_audio.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/i810_audio.c Tue Aug 29 14:09:15 2000 @@ -1300,7 +1300,8 @@ return 0; case SNDCTL_DSP_SPEED: /* set smaple rate */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1320,7 +1321,8 @@ return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if(val==0) return -EINVAL; if (file->f_mode & FMODE_WRITE) { @@ -1351,7 +1353,8 @@ return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1365,7 +1368,8 @@ return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1385,14 +1389,16 @@ case SNDCTL_DSP_SUBDIVIDE: if (dmabuf->subdivision) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; dmabuf->subdivision = val; return 0; case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; dmabuf->ossfragshift = val & 0xffff; dmabuf->ossmaxfrags = (val >> 16) & 0xffff; @@ -1450,7 +1456,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.4.0-test7/linux/drivers/sound/maestro.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/maestro.c Tue Aug 29 14:09:15 2000 @@ -2034,7 +2034,8 @@ card->mix.modcnt++; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ @@ -2502,7 +2503,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -2518,7 +2520,8 @@ return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { @@ -2541,7 +2544,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { fmtd = 0; fmtm = ~0; @@ -2570,7 +2574,8 @@ return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { fmtd = 0; fmtm = ~0; @@ -2615,7 +2620,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) @@ -2712,7 +2718,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; M_printk("maestro: SETFRAGMENT: %0x\n",val); if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; @@ -2740,7 +2747,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c --- v2.4.0-test7/linux/drivers/sound/nm256_audio.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/nm256_audio.c Sun Sep 3 20:59:57 2000 @@ -1419,7 +1419,8 @@ switch (cmd) { case SOUND_PCM_WRITE_RATE: - get_user_ret(ret, (int *) arg, -EFAULT); + if (get_user(ret, (int *) arg)) + return -EFAULT; if (ret != 0) { oldinfo = card->sinfo[w].samplerate; @@ -1437,7 +1438,8 @@ break; case SNDCTL_DSP_STEREO: - get_user_ret(ret, (int *) arg, -EFAULT); + if (get_user(ret, (int *) arg)) + return -EFAULT; card->sinfo[w].stereo = ret ? 1 : 0; ret = nm256_setInfo (dev, card); @@ -1447,7 +1449,8 @@ break; case SOUND_PCM_WRITE_CHANNELS: - get_user_ret(ret, (int *) arg, -EFAULT); + if (get_user(ret, (int *) arg)) + return -EFAULT; if (ret < 1 || ret > 3) ret = card->sinfo[w].stereo + 1; @@ -1464,7 +1467,8 @@ break; case SNDCTL_DSP_SETFMT: - get_user_ret(ret, (int *) arg, -EFAULT); + if (get_user(ret, (int *) arg)) + return -EFAULT; if (ret != 0) { oldinfo = card->sinfo[w].bits; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.4.0-test7/linux/drivers/sound/sonicvibes.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/sonicvibes.c Tue Aug 29 14:09:15 2000 @@ -1051,7 +1051,8 @@ if (cmd == OSS_GETVERSION) return put_user(SOUND_VERSION, (int *)arg); if (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; spin_lock_irqsave(&s->lock, flags); if (val & 1) { if (val & 2) { @@ -1119,7 +1120,8 @@ s->mix.modcnt++; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; i = hweight32(val); if (i == 0) return 0; /*val = mixer_recmask(s);*/ @@ -1143,7 +1145,8 @@ i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; l = val & 0xff; r = (val >> 8) & 0xff; if (mixtable[i].type == MT_4MUTEMONO) @@ -1582,7 +1585,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1598,7 +1602,8 @@ return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { @@ -1621,7 +1626,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { fmtd = 0; fmtm = ~0; @@ -1650,7 +1656,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { fmtd = 0; fmtm = ~0; @@ -1687,7 +1694,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) @@ -1798,7 +1806,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1825,7 +1834,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.4.0-test7/linux/drivers/sound/sound_core.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/sound/sound_core.c Mon Aug 28 15:03:42 2000 @@ -456,7 +456,11 @@ static struct file_operations soundcore_fops= { - owner: THIS_MODULE, +/* owner: THIS_MODULE, * this is a bug: if we have an owner, the kernel + generates a MOD_INC_USE_COUNT - thus + the module cannot be unloaded since the device + is never released here ! - solution: owner + has to be NULL. Patch by Peter Wahl */ open: soundcore_open, }; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.0-test7/linux/drivers/sound/trident.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/trident.c Tue Aug 29 14:09:15 2000 @@ -1633,7 +1633,8 @@ return 0; case SNDCTL_DSP_SPEED: /* set smaple rate */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1653,7 +1654,8 @@ return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_WRITE) { stop_dac(state); dmabuf->ready = 0; @@ -1688,7 +1690,8 @@ return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1711,7 +1714,8 @@ AFMT_S16_LE : AFMT_U8, (int *)arg); case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1740,14 +1744,16 @@ case SNDCTL_DSP_SUBDIVIDE: if (dmabuf->subdivision) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; dmabuf->subdivision = val; return 0; case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; dmabuf->ossfragshift = val & 0xffff; dmabuf->ossmaxfrags = (val >> 16) & 0xffff; @@ -1805,7 +1811,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) @@ -1881,7 +1888,8 @@ if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val == DSP_BIND_QUERY) { val = dmabuf->channel->attribute | 0x3c00; val = attr2mask[val >> 8]; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.4.0-test7/linux/drivers/sound/via82cxxx_audio.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/via82cxxx_audio.c Tue Aug 29 14:09:15 2000 @@ -1900,7 +1900,8 @@ /* query or set current channel's PCM data format */ case SNDCTL_DSP_SETFMT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { rc = 0; @@ -1928,7 +1929,8 @@ /* query or set number of channels (1=mono, 2=stereo) */ case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { rc = 0; spin_lock_irq (&card->lock); @@ -1954,7 +1956,8 @@ /* enable (val is not zero) or disable (val == 0) stereo */ case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; rc = 0; spin_lock_irq (&card->lock); if (rc == 0 && rd) @@ -1969,7 +1972,8 @@ /* query or set sampling rate */ case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val < 0) return -EINVAL; if (val > 0) { @@ -2061,7 +2065,8 @@ /* set fragment size. implemented as a successful no-op for now */ case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n", val & 0xFFFF, diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/vwsnd.c linux/drivers/sound/vwsnd.c --- v2.4.0-test7/linux/drivers/sound/vwsnd.c Fri Jul 14 12:12:13 2000 +++ linux/drivers/sound/vwsnd.c Tue Aug 29 14:09:15 2000 @@ -2476,7 +2476,8 @@ return put_user(ival, (int *) arg); case SNDCTL_DSP_SPEED: /* _SIOWR('P', 2, int) */ - get_user_ret(ival, (int *) arg, -EFAULT); + if (get_user(ival, (int *) arg)) + return -EFAULT; DBGX("SNDCTL_DSP_SPEED %d\n", ival); if (ival) { if (aport->swstate != SW_INITIAL) { @@ -2497,7 +2498,8 @@ return put_user(ival, (int *) arg); case SNDCTL_DSP_STEREO: /* _SIOWR('P', 3, int) */ - get_user_ret(ival, (int *) arg, -EFAULT); + if (get_user(ival, (int *) arg)) + return -EFAULT; DBGX("SNDCTL_DSP_STEREO %d\n", ival); if (ival != 0 && ival != 1) return -EINVAL; @@ -2510,7 +2512,8 @@ return put_user(ival, (int *) arg); case SNDCTL_DSP_CHANNELS: /* _SIOWR('P', 6, int) */ - get_user_ret(ival, (int *) arg, -EFAULT); + if (get_user(ival, (int *) arg)) + return -EFAULT; DBGX("SNDCTL_DSP_CHANNELS %d\n", ival); if (ival != 1 && ival != 2) return -EINVAL; @@ -2533,7 +2536,8 @@ return put_user(ival, (int *) arg); case SNDCTL_DSP_SETFRAGMENT: /* _SIOWR('P',10, int) */ - get_user_ret(ival, (int *) arg, -EFAULT); + if (get_user(ival, (int *) arg)) + return -EFAULT; DBGX("SNDCTL_DSP_SETFRAGMENT %d:%d\n", ival >> 16, ival & 0xFFFF); if (aport->swstate != SW_INITIAL) @@ -2571,7 +2575,8 @@ return put_user(ival, (int *) arg); case SNDCTL_DSP_SUBDIVIDE: /* _SIOWR('P', 9, int) */ - get_user_ret(ival, (int *) arg, -EFAULT); + if (get_user(ival, (int *) arg)) + return -EFAULT; DBGX("SNDCTL_DSP_SUBDIVIDE %d\n", ival); if (aport->swstate != SW_INITIAL) return -EINVAL; @@ -2601,7 +2606,8 @@ return 0; case SNDCTL_DSP_SETFMT: /* _SIOWR('P',5, int) */ - get_user_ret(ival, (int *) arg, -EFAULT); + if (get_user(ival, (int *) arg)) + return -EFAULT; DBGX("SNDCTL_DSP_SETFMT %d\n", ival); if (ival != AFMT_QUERY) { if (aport->swstate != SW_INITIAL) { @@ -2809,7 +2815,8 @@ return put_user(ival, (int *) arg); case SNDCTL_DSP_SETTRIGGER: /* _SIOW ('P',16, int) */ - get_user_ret(ival, (int *) arg, -EFAULT); + if (get_user(ival, (int *) arg)) + return -EFAULT; DBGX("SNDCTL_DSP_SETTRIGGER %d\n", ival); /* diff -u --recursive --new-file v2.4.0-test7/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c --- v2.4.0-test7/linux/drivers/sound/waveartist.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/sound/waveartist.c Tue Aug 29 14:09:15 2000 @@ -1628,7 +1628,8 @@ u_int prev_spkr_mute, prev_line_mute, prev_auto_state; int val; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; /* check if parameter is logical */ if (val & ~(VNC_MUTE_INTERNAL_SPKR | @@ -1657,7 +1658,8 @@ } case SOUND_MIXER_PRIVATE2: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; switch (val) { #define VNC_SOUND_PAUSE 0x53 //to pause the DSP @@ -1681,8 +1683,10 @@ unsigned long flags; int mixer_reg[15], i, val; - get_user_ret(val, (int *)arg, -EFAULT); - copy_from_user_ret(mixer_reg, (void *)val, sizeof(mixer_reg), -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; + if (copy_from_user(mixer_reg, (void *)val, sizeof(mixer_reg))) + return -EFAULT; switch (mixer_reg[14]) { case MIXER_PRIVATE3_RESET: @@ -1708,7 +1712,8 @@ spin_unlock_irqrestore(&waveartist_lock, flags); - copy_to_user_ret((void *)val, mixer_reg, sizeof(mixer_reg), -EFAULT); + if (copy_to_user((void *)val, mixer_reg, sizeof(mixer_reg))) + return -EFAULT; break; default: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.4.0-test7/linux/drivers/usb/Makefile Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/Makefile Mon Aug 28 16:59:14 2000 @@ -79,7 +79,7 @@ ifeq ($(CONFIG_USB_STORAGE),y) SUB_DIRS += storage - obj-y += storage/usb-storage.o + obj-y += storage/storage.o else ifeq ($(CONFIG_USB_STORAGE),m) MOD_IN_SUB_DIRS += storage diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.4.0-test7/linux/drivers/usb/audio.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/audio.c Tue Sep 5 13:42:52 2000 @@ -559,7 +559,8 @@ rem = db->dmasize - ptr; if (pgrem > rem) pgrem = rem; - copy_from_user_ret((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem, -EFAULT); + if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem)) + return -EFAULT; size -= pgrem; (char *)buffer += pgrem; ptr += pgrem; @@ -583,7 +584,8 @@ rem = db->dmasize - ptr; if (pgrem > rem) pgrem = rem; - copy_to_user_ret(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem, -EFAULT); + if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem)) + return -EFAULT; size -= pgrem; (char *)buffer += pgrem; ptr += pgrem; @@ -2029,7 +2031,8 @@ ms->modcnt++; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; return set_rec_src(ms, val); default: @@ -2039,7 +2042,8 @@ for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++); if (j >= ms->numch) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (wrmixer(ms, j, val)) return -EIO; return put_user(ms->ch[j].value, (int *)arg); @@ -2352,7 +2356,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (val < 4000) val = 4000; @@ -2370,7 +2375,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; if (val == 1) @@ -2388,7 +2394,8 @@ AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if (hweight32(val) != 1) return -EINVAL; @@ -2415,7 +2422,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as))) @@ -2509,7 +2517,8 @@ return put_user(as->usbin.dma.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { as->usbin.dma.ossfragshift = val & 0xffff; as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff; @@ -2536,7 +2545,8 @@ if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) || (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -3715,23 +3725,21 @@ wake_up(&open_wait); } -int usb_audio_init(void) +static int __init usb_audio_init(void) { usb_register(&usb_audio_driver); return 0; } -#ifdef MODULE -int init_module(void) -{ - return usb_audio_init(); -} -void cleanup_module(void) +static void __exit usb_audio_cleanup(void) { usb_deregister(&usb_audio_driver); } +module_init(usb_audio_init); +module_exit(usb_audio_cleanup); + MODULE_AUTHOR("Alan Cox , Thomas Sailer (sailer@ife.ee.ethz.ch)"); MODULE_DESCRIPTION("USB Audio Class driver"); -#endif + diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c --- v2.4.0-test7/linux/drivers/usb/dabusb.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/dabusb.c Tue Sep 5 13:42:52 2000 @@ -802,7 +802,7 @@ /* --------------------------------------------------------------------- */ -int __init dabusb_init (void) +static int __init dabusb_init (void) { unsigned u; @@ -828,7 +828,7 @@ return 0; } -void __exit dabusb_cleanup (void) +static void __exit dabusb_cleanup (void) { dbg("dabusb_cleanup"); @@ -843,15 +843,9 @@ MODULE_PARM (buffers, "i"); MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); -int __init init_module (void) -{ - return dabusb_init (); -} +module_init (dabusb_init); +module_exit (dabusb_cleanup); -void __exit cleanup_module (void) -{ - dabusb_cleanup (); -} #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.4.0-test7/linux/drivers/usb/devio.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/devio.c Tue Aug 29 14:09:15 2000 @@ -607,7 +607,8 @@ unsigned char *tbuf; int i, ret; - copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT); + if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) + return -EFAULT; switch (ctrl.requesttype & 0x1f) { case USB_RECIP_ENDPOINT: if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0) @@ -636,11 +637,13 @@ i = my_usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, ctrl.value, ctrl.index, tbuf, ctrl.length, tmo); if ((i > 0) && ctrl.length) { - copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT); + if (copy_to_user(ctrl.data, tbuf, ctrl.length)) + return -EFAULT; } } else { if (ctrl.length) { - copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT); + if (copy_from_user(tbuf, ctrl.data, ctrl.length)) + return -EFAULT; } i = my_usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, ctrl.value, ctrl.index, tbuf, ctrl.length, tmo); @@ -662,7 +665,8 @@ unsigned char *tbuf; int i, ret; - copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT); + if (copy_from_user(&bulk, (void *)arg, sizeof(bulk))) + return -EFAULT; if ((ret = findintfep(ps->dev, bulk.ep)) < 0) return ret; if ((ret = checkintf(ps, ret))) @@ -686,11 +690,13 @@ } i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); if (!i && len2) { - copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT); + if (copy_to_user(bulk.data, tbuf, len2)) + return -EFAULT; } } else { if (len1) { - copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT); + if (copy_from_user(tbuf, bulk.data, len1)) + return -EFAULT; } i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); } @@ -708,7 +714,8 @@ unsigned int ep; int ret; - get_user_ret(ep, (unsigned int *)arg, -EFAULT); + if (get_user(ep, (unsigned int *)arg)) + return -EFAULT; if ((ret = findintfep(ps->dev, ep)) < 0) return ret; if ((ret = checkintf(ps, ret))) @@ -723,7 +730,8 @@ int pipe; int ret; - get_user_ret(ep, (unsigned int *)arg, -EFAULT); + if (get_user(ep, (unsigned int *)arg)) + return -EFAULT; if ((ret = findintfep(ps->dev, ep)) < 0) return ret; if ((ret = checkintf(ps, ret))) @@ -743,7 +751,8 @@ struct usb_interface *interface; int ret; - copy_from_user_ret(&gd, arg, sizeof(gd), -EFAULT); + if (copy_from_user(&gd, arg, sizeof(gd))) + return -EFAULT; if ((ret = findintfif(ps->dev, gd.interface)) < 0) return ret; interface = usb_ifnum_to_if(ps->dev, gd.interface); @@ -752,7 +761,8 @@ if (!interface->driver) return -ENODATA; strcpy(gd.driver, interface->driver->name); - copy_to_user_ret(arg, &gd, sizeof(gd), -EFAULT); + if (copy_to_user(arg, &gd, sizeof(gd))) + return -EFAULT; return 0; } @@ -762,7 +772,8 @@ ci.devnum = ps->dev->devnum; ci.slow = ps->dev->slow; - copy_to_user_ret(arg, &ci, sizeof(ci), -EFAULT); + if (copy_to_user(arg, &ci, sizeof(ci))) + return -EFAULT; return 0; } @@ -798,7 +809,8 @@ struct usb_interface *interface; int ret; - copy_from_user_ret(&setintf, arg, sizeof(setintf), -EFAULT); + if (copy_from_user(&setintf, arg, sizeof(setintf))) + return -EFAULT; if ((ret = findintfif(ps->dev, setintf.interface)) < 0) return ret; interface = usb_ifnum_to_if(ps->dev, setintf.interface); @@ -817,7 +829,8 @@ { unsigned int u; - get_user_ret(u, (unsigned int *)arg, -EFAULT); + if (get_user(u, (unsigned int *)arg)) + return -EFAULT; if (usb_set_configuration(ps->dev, u) < 0) return -EINVAL; return 0; @@ -831,7 +844,8 @@ unsigned int u, totlen, isofrmlen; int ret; - copy_from_user_ret(&uurb, arg, sizeof(uurb), -EFAULT); + if (copy_from_user(&uurb, arg, sizeof(uurb))) + return -EFAULT; if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD)) return -EINVAL; if (!uurb.buffer) @@ -948,18 +962,22 @@ if (as->userbuffer) if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length)) return -EFAULT; - put_user_ret(as->urb.status, &((struct usbdevfs_urb *)as->userurb)->status, -EFAULT); - put_user_ret(as->urb.actual_length, &((struct usbdevfs_urb *)as->userurb)->actual_length, -EFAULT); - put_user_ret(as->urb.error_count, &((struct usbdevfs_urb *)as->userurb)->error_count, -EFAULT); + if (put_user(as->urb.status, + &((struct usbdevfs_urb *)as->userurb)->status) || + __put_user(as->urb.actual_length, + &((struct usbdevfs_urb *)as->userurb)->actual_length) || + __put_user(as->urb.error_count, + &((struct usbdevfs_urb *)as->userurb)->error_count)) + return -EFAULT; + if (!(usb_pipeisoc(as->urb.pipe))) return 0; for (i = 0; i < as->urb.number_of_packets; i++) { - put_user_ret(as->urb.iso_frame_desc[i].actual_length, - &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length, - -EFAULT); - put_user_ret(as->urb.iso_frame_desc[i].status, - &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status, - -EFAULT); + if (put_user(as->urb.iso_frame_desc[i].actual_length, + &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length) || + __put_user(as->urb.iso_frame_desc[i].status, + &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status)) + return -EFAULT; } return 0; } @@ -990,7 +1008,8 @@ free_async(as); if (ret) return ret; - put_user_ret(addr, (void **)arg, -EFAULT); + if (put_user(addr, (void **)arg)) + return -EFAULT; return 0; } if (signal_pending(current)) @@ -1011,7 +1030,8 @@ free_async(as); if (ret) return ret; - put_user_ret(addr, (void **)arg, -EFAULT); + if (put_user(addr, (void **)arg)) + return -EFAULT; return 0; } @@ -1019,7 +1039,8 @@ { struct usbdevfs_disconnectsignal ds; - copy_from_user_ret(&ds, arg, sizeof(ds), -EFAULT); + if (copy_from_user(&ds, arg, sizeof(ds))) + return -EFAULT; if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX)) return -EINVAL; ps->discsignr = ds.signr; @@ -1032,7 +1053,8 @@ unsigned int intf; int ret; - get_user_ret(intf, (unsigned int *)arg, -EFAULT); + if (get_user(intf, (unsigned int *)arg)) + return -EFAULT; if ((ret = findintfif(ps->dev, intf)) < 0) return ret; return claimintf(ps, ret); @@ -1043,7 +1065,8 @@ unsigned int intf; int ret; - get_user_ret(intf, (unsigned int *)arg, -EFAULT); + if (get_user(intf, (unsigned int *)arg)) + return -EFAULT; if ((ret = findintfif(ps->dev, intf)) < 0) return ret; return releaseintf(ps, intf); @@ -1057,7 +1080,8 @@ int retval = 0; /* get input parameters and alloc buffer */ - copy_from_user_ret (&ctrl, (void *) arg, sizeof (ctrl), -EFAULT); + if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl))) + return -EFAULT; if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { if ((buf = kmalloc (size, GFP_KERNEL)) == 0) return -ENOMEM; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c --- v2.4.0-test7/linux/drivers/usb/dsbr100.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/dsbr100.c Tue Sep 5 13:42:52 2000 @@ -321,7 +321,7 @@ MOD_DEC_USE_COUNT; } -int __init dsbr100_init(void) +static int __init dsbr100_init(void) { usb_dsbr100_radio.priv = NULL; usb_register(&usb_dsbr100_driver); @@ -332,12 +332,7 @@ return 0; } -int __init init_module(void) -{ - return dsbr100_init(); -} - -void cleanup_module(void) +static void __exit dsbr100_exit(void) { usb_dsbr100 *radio=usb_dsbr100_radio.priv; @@ -346,6 +341,9 @@ video_unregister_device(&usb_dsbr100_radio); usb_deregister(&usb_dsbr100_driver); } + +module_init (dsbr100_init); +module_exit (dsbr100_exit); MODULE_AUTHOR("Markus Demleitner "); MODULE_DESCRIPTION("D-Link DSB-R100 USB radio driver"); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.4.0-test7/linux/drivers/usb/hub.c Fri Jul 14 12:12:13 2000 +++ linux/drivers/usb/hub.c Tue Sep 5 13:41:53 2000 @@ -758,6 +758,7 @@ ret = usb_get_configuration(dev); if (ret < 0) { err("unable to get configuration (error=%d)", ret); + usb_destroy_configuration(dev); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/ibmcam.c linux/drivers/usb/ibmcam.c --- v2.4.0-test7/linux/drivers/usb/ibmcam.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/ibmcam.c Tue Sep 5 13:42:52 2000 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -3138,7 +3139,7 @@ * History: * 1/27/00 Reworked to use statically allocated usb_ibmcam structures. */ -int usb_ibmcam_init(void) +static int __init usb_ibmcam_init(void) { unsigned u; @@ -3150,19 +3151,12 @@ return usb_register(&ibmcam_driver); } -void usb_ibmcam_cleanup(void) +static void __exit usb_ibmcam_cleanup(void) { usb_deregister(&ibmcam_driver); } -#ifdef MODULE -int init_module(void) -{ - return usb_ibmcam_init(); -} +module_init(usb_ibmcam_init); +module_exit(usb_ibmcam_cleanup); + -void cleanup_module(void) -{ - usb_ibmcam_cleanup(); -} -#endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/plusb.c linux/drivers/usb/plusb.c --- v2.4.0-test7/linux/drivers/usb/plusb.c Thu May 11 15:30:08 2000 +++ linux/drivers/usb/plusb.c Tue Sep 5 13:42:52 2000 @@ -557,7 +557,7 @@ /* --------------------------------------------------------------------- */ -int __init plusb_init (void) +static int __init plusb_init (void) { unsigned u; dbg("plusb_init"); @@ -583,7 +583,7 @@ /* --------------------------------------------------------------------- */ -void __exit plusb_cleanup (void) +static void __exit plusb_cleanup (void) { unsigned u; @@ -601,21 +601,11 @@ /* --------------------------------------------------------------------- */ -#ifdef MODULE MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de"); MODULE_DESCRIPTION ("PL-2302 USB Interface Driver for Linux (c)2000"); -/* --------------------------------------------------------------------- */ -int __init init_module (void) -{ - return plusb_init (); -} -/* --------------------------------------------------------------------- */ -void __exit cleanup_module (void) -{ - plusb_cleanup (); -} -#endif +module_init (plusb_init); +module_exit (plusb_cleanup); /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/rio500.c linux/drivers/usb/rio500.c --- v2.4.0-test7/linux/drivers/usb/rio500.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/rio500.c Tue Aug 29 14:09:15 2000 @@ -113,15 +113,15 @@ data = (void *) arg; if (data == NULL) break; - copy_from_user_ret(&rio_cmd, data, sizeof(struct RioCommand), - -EFAULT); + if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) + return -EFAULT; if (rio_cmd.length > PAGE_SIZE) return -EINVAL; buffer = (unsigned char *) __get_free_page(GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - copy_from_user_ret(buffer, rio_cmd.buffer, rio_cmd.length, - -EFAULT); + if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) + return -EFAULT; requesttype = rio_cmd.requesttype | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; @@ -150,8 +150,9 @@ dbg("Executed ioctl. Result = %d (data=%04x)", le32_to_cpu(result), le32_to_cpu(*((long *) buffer))); - copy_to_user_ret(rio_cmd.buffer, buffer, - rio_cmd.length, -EFAULT); + if (copy_to_user(rio_cmd.buffer, buffer, + rio_cmd.length)) + return -EFAULT; retries = 0; } @@ -170,15 +171,15 @@ data = (void *) arg; if (data == NULL) break; - copy_from_user_ret(&rio_cmd, data, sizeof(struct RioCommand), - -EFAULT); + if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) + return -EFAULT; if (rio_cmd.length > PAGE_SIZE) return -EINVAL; buffer = (unsigned char *) __get_free_page(GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - copy_from_user_ret(buffer, rio_cmd.buffer, rio_cmd.length, - -EFAULT); + if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) + return -EFAULT; requesttype = rio_cmd.requesttype | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c --- v2.4.0-test7/linux/drivers/usb/serial/digi_acceleport.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/serial/digi_acceleport.c Tue Sep 5 13:42:52 2000 @@ -2014,7 +2014,7 @@ } -int digi_init (void) +static int __init digi_init (void) { usb_serial_register (&digi_acceleport_2_device); usb_serial_register (&digi_acceleport_4_device); @@ -2022,7 +2022,7 @@ } -void digi_exit (void) +static void __exit digi_exit (void) { usb_serial_deregister (&digi_acceleport_2_device); usb_serial_deregister (&digi_acceleport_4_device); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c --- v2.4.0-test7/linux/drivers/usb/serial/ftdi_sio.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/serial/ftdi_sio.c Tue Sep 5 13:42:52 2000 @@ -725,14 +725,14 @@ } /* ftdi_sio_ioctl */ -int ftdi_sio_init (void) +static int __init ftdi_sio_init (void) { usb_serial_register (&ftdi_sio_device); return 0; } -void ftdi_sio_exit (void) +static void __exit ftdi_sio_exit (void) { usb_serial_deregister (&ftdi_sio_device); } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c --- v2.4.0-test7/linux/drivers/usb/serial/keyspan.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/serial/keyspan.c Tue Sep 5 13:42:52 2000 @@ -687,7 +687,7 @@ } -int keyspan_init (void) +static int __init keyspan_init (void) { usb_serial_register (&keyspan_usa18x_pre_device); usb_serial_register (&keyspan_usa19_pre_device); @@ -703,7 +703,7 @@ } -void keyspan_exit (void) +static void __exit keyspan_exit (void) { usb_serial_deregister (&keyspan_usa18x_pre_device); usb_serial_deregister (&keyspan_usa19_pre_device); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c --- v2.4.0-test7/linux/drivers/usb/serial/keyspan_pda.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/serial/keyspan_pda.c Tue Sep 5 13:42:52 2000 @@ -12,6 +12,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/28/2000) gkh + * Added locks for SMP safeness. + * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more + * than once. + * * (07/20/2000) borchers * - keyspan_pda_write no longer sleeps if it is called on interrupt time; * PPP and the line discipline with stty echo on can call write on @@ -416,6 +421,7 @@ int request_unthrottle = 0; int rc = 0; struct keyspan_pda_private *priv; + unsigned long flags; priv = (struct keyspan_pda_private *)(port->private); /* guess how much room is left in the device's ring buffer, and if we @@ -445,6 +451,7 @@ finished). Also, the tx process is not throttled. So we are ready to write. */ + spin_lock_irqsave (&port->port_lock, flags); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; /* Check if we might overrun the Tx buffer. If so, ask the @@ -464,10 +471,12 @@ 2*HZ); if (rc < 0) { dbg(" roomquery failed"); + spin_unlock_irqrestore (&port->port_lock, flags); return rc; /* failed */ } if (rc == 0) { dbg(" roomquery returned 0 bytes"); + spin_unlock_irqrestore (&port->port_lock, flags); return -EIO; /* device didn't return any data */ } dbg(" roomquery says %d", room); @@ -484,8 +493,10 @@ /* now transfer data */ if (from_user) { if( copy_from_user(port->write_urb->transfer_buffer, - buf, count) ) + buf, count) ) { + spin_unlock_irqrestore (&port->port_lock, flags); return( -EFAULT ); + } } else { memcpy (port->write_urb->transfer_buffer, buf, count); @@ -495,8 +506,11 @@ priv->tx_room -= count; - if (usb_submit_urb(port->write_urb)) + if (usb_submit_urb(port->write_urb)) { dbg(" usb_submit_urb(write bulk) failed"); + spin_unlock_irqrestore (&port->port_lock, flags); + return (0); + } } else { /* There wasn't any room left, so we are throttled until @@ -509,6 +523,7 @@ queue_task( &priv->unthrottle_task, &tq_scheduler ); } + spin_unlock_irqrestore (&port->port_lock, flags); return (count); } @@ -568,61 +583,92 @@ unsigned char room; int rc; struct keyspan_pda_private *priv; - priv = (struct keyspan_pda_private *)(port->private); + unsigned long flags; - if (port->active) { - return -EINVAL; - } - port->active = 1; + spin_lock_irqsave (&port->port_lock, flags); + + MOD_INC_USE_COUNT; + ++port->open_count; + + if (!port->active) { + port->active = 1; - /* find out how much room is in the Tx ring */ - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 6, /* write_room */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_IN, - 0, /* value */ - 0, /* index */ - &room, - 1, - 2*HZ); - if (rc < 0) { - dbg(" roomquery failed"); - return rc; /* failed */ - } - if (rc == 0) { - dbg(" roomquery returned 0 bytes"); - return -EIO; /* device didn't return any data */ - } - priv->tx_room = room; - priv->tx_throttled = room ? 0 : 1; - - /* the normal serial device seems to always turn on DTR and RTS here, - so do the same */ - if (port->tty->termios->c_cflag & CBAUD) - keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) ); - else - keyspan_pda_set_modem_info(serial, 0); + /* find out how much room is in the Tx ring */ + spin_unlock_irqrestore (&port->port_lock, flags); + rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 6, /* write_room */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_IN, + 0, /* value */ + 0, /* index */ + &room, + 1, + 2*HZ); + spin_lock_irqsave (&port->port_lock, flags); + if (rc < 0) { + dbg(__FUNCTION__" - roomquery failed"); + goto error; + } + if (rc == 0) { + dbg(__FUNCTION__" - roomquery returned 0 bytes"); + rc = -EIO; + goto error; + } + priv = (struct keyspan_pda_private *)(port->private); + priv->tx_room = room; + priv->tx_throttled = room ? 0 : 1; + + /* the normal serial device seems to always turn on DTR and RTS here, + so do the same */ + spin_unlock_irqrestore (&port->port_lock, flags); + if (port->tty->termios->c_cflag & CBAUD) + keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) ); + else + keyspan_pda_set_modem_info(serial, 0); + + /*Start reading from the device*/ + if (usb_submit_urb(port->interrupt_in_urb)) + dbg(__FUNCTION__" - usb_submit_urb(read int) failed"); + } else { + spin_unlock_irqrestore (&port->port_lock, flags); + } - /*Start reading from the device*/ - if (usb_submit_urb(port->interrupt_in_urb)) - dbg(" usb_submit_urb(read int) failed"); return (0); +error: + --port->open_count; + port->active = 0; + MOD_DEC_USE_COUNT; + spin_unlock_irqrestore (&port->port_lock, flags); + return rc; } static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; + unsigned long flags; - /* the normal serial device seems to always shut off DTR and RTS now */ - if (port->tty->termios->c_cflag & HUPCL) - keyspan_pda_set_modem_info(serial, 0); - - /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->interrupt_in_urb); - port->active = 0; + spin_lock_irqsave (&port->port_lock, flags); + + --port->open_count; + MOD_DEC_USE_COUNT; + + if (port->open_count <= 0) { + /* the normal serial device seems to always shut off DTR and RTS now */ + spin_unlock_irqrestore (&port->port_lock, flags); + if (port->tty->termios->c_cflag & HUPCL) + keyspan_pda_set_modem_info(serial, 0); + spin_lock_irqsave (&port->port_lock, flags); + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->interrupt_in_urb); + port->active = 0; + port->open_count = 0; + } + + spin_unlock_irqrestore (&port->port_lock, flags); } @@ -683,6 +729,11 @@ static void keyspan_pda_shutdown (struct usb_serial *serial) { + dbg (__FUNCTION__); + + while (serial->port[0].open_count > 0) { + keyspan_pda_close (&serial->port[0], NULL); + } kfree(serial->port[0].private); } @@ -728,7 +779,7 @@ }; -int keyspan_pda_init (void) +static int __init keyspan_pda_init (void) { usb_serial_register (&keyspan_pda_fake_device); usb_serial_register (&keyspan_pda_device); @@ -736,7 +787,7 @@ } -void keyspan_pda_exit (void) +static void __exit keyspan_pda_exit (void) { usb_serial_deregister (&keyspan_pda_fake_device); usb_serial_deregister (&keyspan_pda_device); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c --- v2.4.0-test7/linux/drivers/usb/serial/omninet.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/usb/serial/omninet.c Tue Sep 5 13:42:52 2000 @@ -10,6 +10,12 @@ * * Please report both successes and troubles to the author at omninet@kroah.com * + * (08/28/2000) gkh + * Added locks for SMP safeness. + * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more + * than once. + * Fixed potential race in omninet_write_bulk_callback + * * (07/19/2000) gkh * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. @@ -54,6 +60,7 @@ static void omninet_write_bulk_callback (struct urb *urb); static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); static int omninet_write_room (struct usb_serial_port *port); +static void omninet_shutdown (struct usb_serial *serial); /* All of the device info needed for the omni.net */ static __u16 zyxel_vendor_id = ZYXEL_VENDOR_ID; @@ -76,6 +83,7 @@ write_room: omninet_write_room, read_bulk_callback: omninet_read_bulk_callback, write_bulk_callback: omninet_write_bulk_callback, + shutdown: omninet_shutdown, }; @@ -117,52 +125,87 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport = &serial->port[1]; - struct omninet_data *od; - - dbg("omninet_open port %d", port->number); - - if (port->active) { - dbg ("device already open"); - return -EINVAL; - } - port->active = 1; + struct usb_serial *serial; + struct usb_serial_port *wport; + struct omninet_data *od; + unsigned long flags; + + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; + + dbg(__FUNCTION__ " - port %d", port->number); + + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return -ENODEV; + + spin_lock_irqsave (&port->port_lock, flags); + + MOD_INC_USE_COUNT; + ++port->open_count; + + if (!port->active) { + port->active = 1; + + od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); + if( !od ) { + err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct omninet_data)); + --port->open_count; + port->active = 0; + spin_unlock_irqrestore (&port->port_lock, flags); + MOD_DEC_USE_COUNT; + return -ENOMEM; + } - od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); + port->private = od; + wport = &serial->port[1]; + wport->tty = port->tty; - if( !od ) - { - err("omninet_open: kmalloc(%d) failed.", sizeof(struct omninet_data)); - return -ENOMEM; + /* Start reading from the device */ + if (usb_submit_urb(port->read_urb)) + dbg(__FUNCTION__" - read bulk (%p) failed", port->read_urb); } - port->private = od; - - /* Start reading from the device */ - if (usb_submit_urb(port->read_urb)) - dbg("usb_submit_urb(read bulk, %p) failed", port->read_urb); - - wport->tty = port->tty; + spin_unlock_irqrestore (&port->port_lock, flags); return (0); } static void omninet_close (struct usb_serial_port *port, struct file * filp) { - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport = &serial->port[1]; - struct omninet_data *od = (struct omninet_data *) port->private; + struct usb_serial *serial; + struct usb_serial_port *wport; + struct omninet_data *od; + unsigned long flags; - port->active = 0; + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return; + spin_lock_irqsave (&port->port_lock, flags); - dbg("zyxel_close port %d", port->number); + --port->open_count; + MOD_DEC_USE_COUNT; - usb_unlink_urb (wport->write_urb); - usb_unlink_urb (port->read_urb); + if (port->open_count <= 0) { + od = (struct omninet_data *)port->private; + wport = &serial->port[1]; - if(od) kfree(od); + usb_unlink_urb (wport->write_urb); + usb_unlink_urb (port->read_urb); + + port->active = 0; + port->open_count = 0; + if (od) + kfree(od); + } + + spin_unlock_irqrestore (&port->port_lock, flags); } @@ -173,7 +216,7 @@ static void omninet_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = port->serial; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); unsigned char *data = urb->transfer_buffer; struct omninet_header *header = (struct omninet_header *) &data[0]; @@ -182,22 +225,18 @@ // dbg("omninet_read_bulk_callback"); - if (port_paranoia_check (port, "omninet_read_bulk_callback")) { - return; - } - - if (serial_paranoia_check (serial, "omninet_read_bulk_callback")) { + if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); return; } if (urb->status) { - dbg("nonzero read bulk status received: %d", urb->status); + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); return; } #ifdef DEBUG - if(header->oh_xxx != 0x30) - { + if(header->oh_xxx != 0x30) { if (urb->actual_length) { printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len); for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) { @@ -208,8 +247,7 @@ } #endif - if (urb->actual_length && header->oh_len) - { + if (urb->actual_length && header->oh_len) { for (i = 0; i < header->oh_len; i++) { tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0); } @@ -218,7 +256,7 @@ /* Continue trying to always read */ if (usb_submit_urb(urb)) - dbg("failed resubmitting read urb"); + dbg(__FUNCTION__" - failed resubmitting read urb"); return; } @@ -230,6 +268,8 @@ struct omninet_data *od = (struct omninet_data *) port->private; struct omninet_header *header = (struct omninet_header *) wport->write_urb->transfer_buffer; + + unsigned long flags; /* #ifdef DEBUG int i; @@ -239,7 +279,7 @@ // dbg("omninet_write port %d", port->number); if (count == 0) { - dbg("write request of 0 bytes"); + dbg(__FUNCTION__" - write request of 0 bytes"); return (0); } /* @@ -255,10 +295,12 @@ #endif */ if (wport->write_urb->status == -EINPROGRESS) { - dbg ("already writing"); + dbg (__FUNCTION__" - already writing"); return (0); } + spin_lock_irqsave (&port->port_lock, flags); + count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; if (from_user) { @@ -277,11 +319,15 @@ /* send the data out the bulk port, always 64 bytes */ wport->write_urb->transfer_buffer_length = 64; - if (usb_submit_urb(wport->write_urb)) - dbg("usb_submit_urb(write bulk) failed"); + if (usb_submit_urb(wport->write_urb)) { + dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed"); + spin_unlock_irqrestore (&port->port_lock, flags); + return 0; + } // dbg("omninet_write returns %d", count); + spin_unlock_irqrestore (&port->port_lock, flags); return (count); } @@ -306,31 +352,26 @@ /* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */ struct usb_serial_port *port = (struct usb_serial_port *) urb->context; struct usb_serial *serial; - struct tty_struct *tty; // dbg("omninet_write_bulk_callback, port %0x\n", port); - if (port_paranoia_check (port, "omninet_write_bulk_callback")) { + if (port_paranoia_check (port, __FUNCTION__)) { return; } serial = port->serial; - if (serial_paranoia_check (serial, "omninet_write_bulk_callback")) { + if (serial_paranoia_check (serial, __FUNCTION__)) { return; } if (urb->status) { - dbg("nonzero write bulk status received: %d", urb->status); + dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status); return; } - tty = port->tty; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - wake_up_interruptible(&tty->write_wait); + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); // dbg("omninet_write_bulk_callback, tty %0x\n", tty); @@ -338,14 +379,24 @@ } -int omninet_init (void) +static void omninet_shutdown (struct usb_serial *serial) +{ + dbg (__FUNCTION__); + + while (serial->port[0].open_count > 0) { + omninet_close (&serial->port[0], NULL); + } +} + + +static int __init omninet_init (void) { usb_serial_register (&zyxel_omninet_device); return 0; } -void omninet_exit (void) +static void __exit omninet_exit (void) { usb_serial_deregister (&zyxel_omninet_device); } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h --- v2.4.0-test7/linux/drivers/usb/serial/usb-serial.h Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/serial/usb-serial.h Tue Sep 5 13:19:08 2000 @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/28/2000) gkh + * Added port_lock to port structure. + * * (08/08/2000) gkh * Added open_count to port structure. * @@ -63,6 +66,7 @@ struct tq_struct tqueue; /* task queue for line discipline waking up */ int open_count; /* number of times this port has been opened */ + spinlock_t port_lock; void * private; /* data private to the specific port */ }; @@ -184,6 +188,22 @@ return 0; } + + +static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) +{ + /* if no port was specified, or it fails a paranoia check */ + if (!port || + port_paranoia_check (port, function) || + serial_paranoia_check (port->serial, function)) { + /* then say that we dont have a valid usb_serial thing, which will + * end up genrating -ENODEV return values */ + return NULL; + } + + return port->serial; +} + #endif /* ifdef __LINUX_USB_SERIAL_H */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.4.0-test7/linux/drivers/usb/serial/usbserial.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/usb/serial/usbserial.c Tue Sep 5 13:19:08 2000 @@ -15,6 +15,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/28/2000) gkh + * Added port_lock to port structure. + * Added locks for SMP safeness to generic driver + * Fixed the ability to open a generic device's port more than once. + * * (07/23/2000) gkh * Added bulk_out_endpointAddress to port structure. * @@ -264,6 +269,7 @@ static int generic_chars_in_buffer (struct usb_serial_port *port); static void generic_read_bulk_callback (struct urb *urb); static void generic_write_bulk_callback (struct urb *urb); +static void generic_shutdown (struct usb_serial *serial); #ifdef CONFIG_USB_SERIAL_GENERIC @@ -287,6 +293,7 @@ num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, num_ports: 1, + shutdown: generic_shutdown, }; #endif @@ -321,21 +328,6 @@ LIST_HEAD(usb_serial_driver_list); -static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) -{ - /* if no port was specified, or it fails a paranoia check */ - if (!port || - port_paranoia_check (port, function) || - serial_paranoia_check (port->serial, function)) { - /* then say that we dont have a valid usb_serial thing, which will - * end up genrating -ENODEV return values */ - return NULL; - } - - return port->serial; -} - - static struct usb_serial *get_serial_by_minor (int minor) { return serial_table[minor]; @@ -697,47 +689,65 @@ static int generic_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; + unsigned long flags; + + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; dbg(__FUNCTION__ " - port %d", port->number); - if (port->active) { - dbg (__FUNCTION__ " - device already open"); - return -EINVAL; - } - port->active = 1; - - /* if we have a bulk interrupt, start reading from it */ - if (serial->num_bulk_in) { - /*Start reading from the device*/ - if (usb_submit_urb(port->read_urb)) - dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); - } + spin_lock_irqsave (&port->port_lock, flags); + + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + port->active = 1; - return (0); + /* if we have a bulk interrupt, start reading from it */ + if (serial->num_bulk_in) { + /*Start reading from the device*/ + if (usb_submit_urb(port->read_urb)) + dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + } + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + return 0; } static void generic_close (struct usb_serial_port *port, struct file * filp) { struct usb_serial *serial = port->serial; + unsigned long flags; dbg(__FUNCTION__ " - port %d", port->number); - - /* shutdown any bulk reads that might be going on */ - if (serial->num_bulk_out) { - usb_unlink_urb (port->write_urb); - } - if (serial->num_bulk_in) { - usb_unlink_urb (port->read_urb); + + spin_lock_irqsave (&port->port_lock, flags); + + --port->open_count; + + if (port->open_count <= 0) { + /* shutdown any bulk reads that might be going on */ + if (serial->num_bulk_out) + usb_unlink_urb (port->write_urb); + if (serial->num_bulk_in) + usb_unlink_urb (port->read_urb); + + port->active = 0; + port->open_count = 0; } - port->active = 0; + spin_unlock_irqrestore (&port->port_lock, flags); } static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { struct usb_serial *serial = port->serial; + unsigned long flags; dbg(__FUNCTION__ " - port %d", port->number); @@ -753,6 +763,7 @@ return (0); } + spin_lock_irqsave (&port->port_lock, flags); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; #ifdef DEBUG @@ -776,9 +787,13 @@ /* send the data out the bulk port */ port->write_urb->transfer_buffer_length = count; - if (usb_submit_urb(port->write_urb)) + if (usb_submit_urb(port->write_urb)) { dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed"); + spin_unlock_irqrestore (&port->port_lock, flags); + return 0; + } + spin_unlock_irqrestore (&port->port_lock, flags); return (count); } @@ -889,6 +904,21 @@ } +static void generic_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + generic_close (&serial->port[i], NULL); + } + } +} + + static void port_softint(void *private) { struct usb_serial_port *port = (struct usb_serial_port *)private; @@ -1127,6 +1157,7 @@ port->magic = USB_SERIAL_PORT_MAGIC; port->tqueue.routine = port_softint; port->tqueue.data = port; + spin_lock_init (&port->port_lock); } /* initialize the devfs nodes for this device and let the user know what ports we are bound to */ diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c --- v2.4.0-test7/linux/drivers/usb/serial/visor.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/serial/visor.c Tue Sep 5 13:42:52 2000 @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/28/2000) gkh + * Added locks for SMP safeness. + * * (08/08/2000) gkh * Fixed endian problem in visor_startup. * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more @@ -109,21 +112,23 @@ #define NUM_URBS 24 -static struct urb *write_urb_pool[NUM_URBS]; - +static struct urb *write_urb_pool[NUM_URBS]; +static spinlock_t write_urb_pool_lock; /****************************************************************************** * Handspring Visor specific driver functions ******************************************************************************/ static int visor_open (struct usb_serial_port *port, struct file *filp) { - dbg(__FUNCTION__ " - port %d", port->number); + unsigned long flags; - if (port->active) { - dbg (__FUNCTION__ " - device already open"); - return -EINVAL; - } + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; + + dbg(__FUNCTION__ " - port %d", port->number); + spin_lock_irqsave (&port->port_lock, flags); + ++port->open_count; MOD_INC_USE_COUNT; @@ -135,21 +140,34 @@ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); } + spin_unlock_irqrestore (&port->port_lock, flags); + return 0; } static void visor_close (struct usb_serial_port *port, struct file * filp) { - struct usb_serial *serial = port->serial; - unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL); + struct usb_serial *serial; + unsigned char *transfer_buffer; + unsigned long flags; + + if (port_paranoia_check (port, __FUNCTION__)) + return; dbg(__FUNCTION__ " - port %d", port->number); + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return; + + spin_lock_irqsave (&port->port_lock, flags); + --port->open_count; MOD_DEC_USE_COUNT; if (port->open_count <= 0) { + transfer_buffer = kmalloc (0x12, GFP_KERNEL); if (!transfer_buffer) { err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); } else { @@ -164,6 +182,8 @@ port->active = 0; port->open_count = 0; } + + spin_unlock_irqrestore (&port->port_lock, flags); } @@ -174,6 +194,7 @@ unsigned char *buffer = NULL; int status; int i; + unsigned long flags; dbg(__FUNCTION__ " - port %d", port->number); @@ -183,12 +204,14 @@ } /* try to find a free urb in our list of them */ + spin_lock_irqsave (&write_urb_pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { if (write_urb_pool[i]->status != -EINPROGRESS) { urb = write_urb_pool[i]; break; } } + spin_unlock_irqrestore (&write_urb_pool_lock, flags); if (urb == NULL) { dbg (__FUNCTION__ " - no free urbs"); return 0; @@ -256,21 +279,33 @@ static void visor_throttle (struct usb_serial_port *port) { + unsigned long flags; + dbg(__FUNCTION__ " - port %d", port->number); + spin_lock_irqsave (&port->port_lock, flags); + usb_unlink_urb (port->read_urb); + spin_unlock_irqrestore (&port->port_lock, flags); + return; } static void visor_unthrottle (struct usb_serial_port *port) { + unsigned long flags; + dbg(__FUNCTION__ " - port %d", port->number); + spin_lock_irqsave (&port->port_lock, flags); + if (usb_submit_urb (port->read_urb)) dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + spin_unlock_irqrestore (&port->port_lock, flags); + return; } @@ -429,13 +464,14 @@ } -int visor_init (void) +static int __init visor_init (void) { int i; usb_serial_register (&handspring_device); /* create our write urb pool */ + spin_lock_init (&write_urb_pool_lock); for (i = 0; i < NUM_URBS; ++i) { struct urb *urb = usb_alloc_urb(0); if (urb == NULL) { @@ -450,18 +486,23 @@ } -void visor_exit (void) +static void __exit visor_exit (void) { int i; + unsigned long flags; usb_serial_deregister (&handspring_device); - + + spin_lock_irqsave (&write_urb_pool_lock, flags); + for (i = 0; i < NUM_URBS; ++i) { usb_unlink_urb(write_urb_pool[i]); if (write_urb_pool[i]->transfer_buffer) kfree(write_urb_pool[i]->transfer_buffer); usb_free_urb (write_urb_pool[i]); } + + spin_unlock_irqrestore (&write_urb_pool_lock, flags); } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c --- v2.4.0-test7/linux/drivers/usb/serial/whiteheat.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/serial/whiteheat.c Tue Sep 5 13:42:52 2000 @@ -531,7 +531,7 @@ } -int whiteheat_init (void) +static int __init whiteheat_init (void) { usb_serial_register (&whiteheat_fake_device); usb_serial_register (&whiteheat_device); @@ -539,7 +539,7 @@ } -void whiteheat_exit (void) +static void __exit whiteheat_exit (void) { usb_serial_deregister (&whiteheat_fake_device); usb_serial_deregister (&whiteheat_device); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/Makefile linux/drivers/usb/storage/Makefile --- v2.4.0-test7/linux/drivers/usb/storage/Makefile Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/Makefile Mon Aug 28 16:59:14 2000 @@ -1,47 +1,44 @@ # # Makefile for the USB Mass Storage device drivers. # +# 15 Aug 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# + +O_TARGET := storage.o +EXTRA_CFLAGS := -I../../scsi/ + +list-multi := usb-storage.o + +obj-$(CONFIG_USB_STORAGE) += usb-storage.o + +usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o +usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e) += shuttle_usbat.o +usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o +usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o +usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA) += shuttle_sm.o +usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH) += shuttle_cf.o +usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o + +usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ + $(usb-storage-obj-y) + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Take multi-part drivers out of obj-y and put components in. +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. +O_OBJS := $(obj-y) +M_OBJS := $(obj-m) +MI_OBJS := $(int-m) -O_TARGET := usb-storage.o -M_OBJS := usb-storage.o -O_OBJS := scsiglue.o protocol.o transport.o usb.o -MOD_LIST_NAME := USB_STORAGE_MODULES - -CFLAGS_scsiglue.o:= -I../../scsi/ -CFLAGS_protocol.o:= -I../../scsi/ -CFLAGS_transport.o:= -I../../scsi/ -CFLAGS_debug.o:= -I../../scsi/ -CFLAGS_usb.o:= -I../../scsi/ -CFLAGS_shuttle_usbat.o:= -I../../scsi/ -CFLAGS_sddr09.o:= -I../../scsi/ -CFLAGS_dpcm.o:= -I../../scsi/ - -ifeq ($(CONFIG_USB_STORAGE_DEBUG),y) - O_OBJS += debug.o -endif - -ifeq ($(CONFIG_USB_STORAGE_HP8200e),y) - O_OBJS += shuttle_usbat.o -endif - -ifeq ($(CONFIG_USB_STORAGE_SDDR09),y) - O_OBJS += sddr09.o -endif - -ifeq ($(CONFIG_USB_STORAGE_FREECOM),y) - O_OBJS += freecom.o -endif - -ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA),y) - O_OBJS += shuttle_sm.o -endif - -ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH),y) - O_OBJS += shuttle_cf.o -endif - -ifeq ($(CONFIG_USB_STORAGE_DPCM),y) - O_OBJS += dpcm.o -endif - include $(TOPDIR)/Rules.make + +usb-storage.o: $(usb-storage-objs) + $(LD) -r -o $@ $(usb-storage-objs) diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/debug.c linux/drivers/usb/storage/debug.c --- v2.4.0-test7/linux/drivers/usb/storage/debug.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/usb/storage/debug.c Mon Aug 28 16:59:14 2000 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * Debugging Functions Source Code File * - * $Id: debug.c,v 1.2 2000/07/19 17:21:39 groovyjava Exp $ + * $Id: debug.c,v 1.3 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Initial work by: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/debug.h linux/drivers/usb/storage/debug.h --- v2.4.0-test7/linux/drivers/usb/storage/debug.h Thu Jul 27 17:38:01 2000 +++ linux/drivers/usb/storage/debug.h Mon Aug 28 16:59:14 2000 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * Debugging Functions Header File * - * $Id: debug.h,v 1.3 2000/07/19 19:34:48 groovyjava Exp $ + * $Id: debug.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Initial work by: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/dpcm.c linux/drivers/usb/storage/dpcm.c --- v2.4.0-test7/linux/drivers/usb/storage/dpcm.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/dpcm.c Mon Aug 28 16:59:14 2000 @@ -1,12 +1,12 @@ /* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader * - * $Id: dpcm.c,v 1.1 2000/08/08 01:26:12 webbb Exp $ + * $Id: dpcm.c,v 1.3 2000/08/25 00:13:51 mdharm Exp $ * * DPCM driver v0.1: * * First release * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 2000 Brian Webb (webbb@earthlink.net) * * This device contains both a CompactFlash card reader, which @@ -36,7 +36,6 @@ #include "debug.h" #include "dpcm.h" #include "sddr09.h" - /* * Transport for the Microtech DPCM-USB diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/dpcm.h linux/drivers/usb/storage/dpcm.h --- v2.4.0-test7/linux/drivers/usb/storage/dpcm.h Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/dpcm.h Mon Aug 28 16:59:14 2000 @@ -1,12 +1,12 @@ /* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader * - * $Id: dpcm.h,v 1.1 2000/08/08 01:26:12 webbb Exp $ + * $Id: dpcm.h,v 1.2 2000/08/25 00:13:51 mdharm Exp $ * * DPCM driver v0.1: * * First release * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 2000 Brian Webb (webbb@earthlink.net) * * See dpcm.c for more explanation diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/freecom.c linux/drivers/usb/storage/freecom.c --- v2.4.0-test7/linux/drivers/usb/storage/freecom.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/storage/freecom.c Tue Sep 5 12:56:51 2000 @@ -0,0 +1,374 @@ +/* Driver for Freecom USB/IDE adaptor + * + * $Id: freecom.c,v 1.7 2000/08/25 00:13:51 mdharm Exp $ + * + * Freecom v0.1: + * + * First release + * + * Current development and maintenance by: + * (C) 2000 David Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This driver was developed with information provided in FREECOM's USB + * Programmers Reference Guide. For further information contact Freecom + * (http://www.freecom.de/) + */ + +#include "transport.h" +#include "protocol.h" +#include "usb.h" +#include "debug.h" +#include "freecom.h" + +static void pdump (void *, int); + +struct freecom_udata { + __u8 buffer[64]; /* Common command block. */ +}; +typedef struct freecom_udata *freecom_udata_t; + +/* All of the outgoing packets are 64 bytes long. */ +struct freecom_cb_wrap { + __u8 Type; /* Command type. */ + __u8 Timeout; /* Timeout in seconds. */ + __u8 Atapi[12]; /* An ATAPI packet. */ + __u8 Filler[50]; /* Padding Data. */ +}; + +struct freecom_xfer_wrap { + __u8 Type; /* Command type. */ + __u8 Timeout; /* Timeout in seconds. */ + __u32 Count; /* Number of bytes to transfer. */ + __u8 Pad[58]; +}; + +struct freecom_status { + __u8 Status; + __u8 Reason; + __u16 Count; + __u8 Pad[60]; +}; + +/* These are the packet types. The low bit indicates that this command + * should wait for an interrupt. */ +#define FCM_PACKET_ATAPI 0x21 + +/* Receive data from the IDE interface. The ATAPI packet has already + * waited, so the data should be immediately available. */ +#define FCM_PACKET_INPUT 0x90 + +/* All packets (except for status) are 64 bytes long. */ +#define FCM_PACKET_LENGTH 64 + +static int +freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, + int ipipe, int opipe, int count) +{ + freecom_udata_t extra = (freecom_udata_t) us->extra; + struct freecom_xfer_wrap *fxfr = + (struct freecom_xfer_wrap *) extra->buffer; + int result, partial; + int offset; + __u8 *buffer = extra->buffer; + + fxfr->Type = FCM_PACKET_INPUT | 0x00; + fxfr->Timeout = 0; /* Short timeout for debugging. */ + fxfr->Count = cpu_to_le32 (count); + memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); + + printk (KERN_DEBUG "Read data Freecom! (c=%d)\n", count); + + /* Issue the transfer command. */ + result = usb_stor_bulk_msg (us, fxfr, opipe, + FCM_PACKET_LENGTH, &partial); + if (result != 0) { + US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n", + result, partial); + + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("us_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + return USB_STOR_TRANSPORT_ERROR; + } + printk (KERN_DEBUG "Done issuing read request: %d %d\n", + result, partial); + + /* Now transfer all of our blocks. */ + if (srb->use_sg) { + US_DEBUGP ("Need to implement scatter-gather\n"); + return USB_STOR_TRANSPORT_ERROR; + } else { + offset = 0; + + while (offset < count) { + printk (KERN_DEBUG "Start of read\n"); + /* Use the given buffer directly, but only if there + * is space for an entire packet. */ + + if (offset + 64 <= srb->request_bufflen) { + result = usb_stor_bulk_msg ( + us, srb->request_buffer+offset, + ipipe, 64, &partial); + printk (KERN_DEBUG "Read111 = %d, %d\n", + result, partial); + pdump (srb->request_buffer+offset, + partial); + } else { + result = usb_stor_bulk_msg ( + us, buffer, + ipipe, 64, &partial); + printk (KERN_DEBUG "Read112 = %d, %d\n", + result, partial); + memcpy (srb->request_buffer+offset, + buffer, + srb->request_bufflen - offset); + pdump (srb->request_buffer+offset, + srb->request_bufflen - offset); + } + + if (result != 0) { + US_DEBUGP ("Freecom readblock r=%d, p=%d\n", + result, partial); + + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("us_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + return USB_STOR_TRANSPORT_ERROR; + } + + offset += 64; + } + } + + printk (KERN_DEBUG "freecom_readdata done!\n"); + return USB_STOR_TRANSPORT_GOOD; +} + +/* + * Transport for the Freecom USB/IDE adaptor. + * + */ +int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) +{ + struct freecom_cb_wrap *fcb; + struct freecom_status *fst; + int ipipe, opipe; /* We need both pipes. */ + int result; + int partial; + int length; + freecom_udata_t extra; + + /* Allocate a buffer for us. The upper usb transport code will + * free this for us when cleaning up. */ + if (us->extra == NULL) { + us->extra = kmalloc (sizeof (struct freecom_udata), + GFP_KERNEL); + if (us->extra == NULL) { + printk (KERN_WARNING USB_STORAGE "Out of memory\n"); + return USB_STOR_TRANSPORT_ERROR; + } + } + + extra = (freecom_udata_t) us->extra; + + fcb = (struct freecom_cb_wrap *) extra->buffer; + fst = (struct freecom_status *) extra->buffer; + + printk (KERN_DEBUG "Freecom TRANSPORT STARTED\n"); + + /* Get handles for both transports. */ + opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); + ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in); + +#if 0 + /* Yuck, let's see if this helps us. Artificially increase the + * length on this. */ + if (srb->cmnd[0] == 0x03 && srb->cmnd[4] == 0x12) + srb->cmnd[4] = 0x0E; +#endif + + /* The ATAPI Command always goes out first. */ + fcb->Type = FCM_PACKET_ATAPI; + fcb->Timeout = 0; + memcpy (fcb->Atapi, srb->cmnd, 12); + memset (fcb->Filler, 0, sizeof (fcb->Filler)); + + pdump (srb->cmnd, 12); + + /* Send it out. */ + result = usb_stor_bulk_msg (us, fcb, opipe, + FCM_PACKET_LENGTH, &partial); + + /* The Freecom device will only fail if there is something wrong in + * USB land. It returns the status in its own registers, which + * come back in the bulk pipe. */ + if (result != 0) { + US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", + result, partial); + + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("us_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + return USB_STOR_TRANSPORT_ERROR; + } + + /* There are times we can optimize out this status read, but it + * doesn't hurt us to always do it now. */ + result = usb_stor_bulk_msg (us, fst, ipipe, + FCM_PACKET_LENGTH, &partial); + printk (KERN_DEBUG "foo Status result %d %d\n", result, partial); + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("us_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + pdump ((void *) fst, partial); + if (partial != 4 || result != 0) { + return USB_STOR_TRANSPORT_ERROR; + } + if ((fst->Reason & 1) != 0) { + printk (KERN_DEBUG "operation failed\n"); + return USB_STOR_TRANSPORT_FAILED; + } + + /* The device might not have as much data available as we + * requested. If you ask for more than the device has, this reads + * and such will hang. */ + printk (KERN_DEBUG "Device indicates that it has %d bytes available\n", + le16_to_cpu (fst->Count)); + + /* Find the length we desire to read. It is the lesser of the SCSI + * layer's requested length, and the length the device claims to + * have available. */ + length = us_transfer_length (srb); + printk (KERN_DEBUG "SCSI requested %d\n", length); + if (length > le16_to_cpu (fst->Count)) + length = le16_to_cpu (fst->Count); + + /* What we do now depends on what direction the data is supposed to + * move in. */ + + switch (us->srb->sc_data_direction) { + case SCSI_DATA_READ: + result = freecom_readdata (srb, us, ipipe, opipe, length); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + break; + + default: + US_DEBUGP ("freecom unimplemented direction: %d\n", + us->srb->sc_data_direction); + // Return fail, SCSI seems to handle this better. + return USB_STOR_TRANSPORT_FAILED; + break; + } + +#if 0 + /* After the transfer, we can read our status register. */ + printk (KERN_DEBUG "Going to read status register\n"); + result = usb_stor_bulk_msg (us, &fst, ipipe, + FCM_PACKET_LENGTH, &partial); + printk (KERN_DEBUG "Result from read %d %d\n", result, partial); + if (result != 0) { + return USB_STOR_TRANSPORT_ERROR; + } + if ((fst.Reason & 1) != 0) { + return USB_STOR_TRANSPORT_FAILED; + } +#endif + + return USB_STOR_TRANSPORT_GOOD; + + printk (KERN_DEBUG "Freecom: transfer_length = %d\n", + us_transfer_length (srb)); + + printk (KERN_DEBUG "Freecom: direction = %d\n", + srb->sc_data_direction); + + return USB_STOR_TRANSPORT_ERROR; +} + +int usb_stor_freecom_reset(struct us_data *us) +{ + printk (KERN_DEBUG "freecom reset called\n"); + + /* We don't really have this feature. */ + return USB_STOR_TRANSPORT_ERROR; +} + +static void pdump (void *ibuffer, int length) +{ + static char line[80]; + int offset = 0; + unsigned char *buffer = (unsigned char *) ibuffer; + int i, j; + int from, base; + + offset = 0; + for (i = 0; i < length; i++) { + if ((i & 15) == 0) { + if (i > 0) { + offset += sprintf (line+offset, " - "); + for (j = i - 16; j < i; j++) { + if (buffer[j] >= 32 && buffer[j] <= 126) + line[offset++] = buffer[j]; + else + line[offset++] = '.'; + } + line[offset] = 0; + printk (KERN_DEBUG "%s\n", line); + offset = 0; + } + offset += sprintf (line+offset, "%08x:", i); + } + else if ((i & 7) == 0) { + offset += sprintf (line+offset, " -"); + } + offset += sprintf (line+offset, " %02x", buffer[i] & 0xff); + } + + /* Add the last "chunk" of data. */ + from = (length - 1) % 16; + base = ((length - 1) / 16) * 16; + + for (i = from + 1; i < 16; i++) + offset += sprintf (line+offset, " "); + if (from < 8) + offset += sprintf (line+offset, " "); + offset += sprintf (line+offset, " - "); + + for (i = 0; i <= from; i++) { + if (buffer[base+i] >= 32 && buffer[base+i] <= 126) + line[offset++] = buffer[base+i]; + else + line[offset++] = '.'; + } + line[offset] = 0; + printk (KERN_DEBUG "%s\n", line); + offset = 0; +} + diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/freecom.h linux/drivers/usb/storage/freecom.h --- v2.4.0-test7/linux/drivers/usb/storage/freecom.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/storage/freecom.h Mon Aug 28 16:59:14 2000 @@ -0,0 +1,35 @@ +/* Driver for Freecom USB/IDE adaptor + * + * $Id: freecom.h,v 1.3 2000/08/25 00:13:51 mdharm Exp $ + * + * Freecom v0.1: + * + * First release + * + * Current development and maintenance by: + * (c) 2000 David Brown + * + * See freecom.c for more explanation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _FREECOM_USB_H +#define _FREECOM_USB_H + +extern int freecom_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int usb_stor_freecom_reset(struct us_data *us); + +#endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/protocol.c linux/drivers/usb/storage/protocol.c --- v2.4.0-test7/linux/drivers/usb/storage/protocol.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/protocol.c Mon Aug 28 16:59:14 2000 @@ -1,8 +1,8 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: protocol.c,v 1.4 2000/08/01 22:01:19 mdharm Exp $ + * $Id: protocol.c,v 1.5 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/protocol.h linux/drivers/usb/storage/protocol.h --- v2.4.0-test7/linux/drivers/usb/storage/protocol.h Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/protocol.h Mon Aug 28 16:59:14 2000 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * Protocol Functions Header File * - * $Id: protocol.h,v 1.2 2000/08/01 22:01:19 mdharm Exp $ + * $Id: protocol.h,v 1.3 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * This driver is based on the 'USB Mass Storage Class' document. This diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/scsiglue.c linux/drivers/usb/storage/scsiglue.c --- v2.4.0-test7/linux/drivers/usb/storage/scsiglue.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/scsiglue.c Mon Aug 28 16:59:14 2000 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * SCSI layer glue code * - * $Id: scsiglue.c,v 1.8 2000/08/11 23:15:05 mdharm Exp $ + * $Id: scsiglue.c,v 1.9 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/scsiglue.h linux/drivers/usb/storage/scsiglue.h --- v2.4.0-test7/linux/drivers/usb/storage/scsiglue.h Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/scsiglue.h Mon Aug 28 16:59:14 2000 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * SCSI Connecting Glue Header File * - * $Id: scsiglue.h,v 1.3 2000/07/25 23:04:47 mdharm Exp $ + * $Id: scsiglue.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * This driver is based on the 'USB Mass Storage Class' document. This diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/sddr09.c linux/drivers/usb/storage/sddr09.c --- v2.4.0-test7/linux/drivers/usb/storage/sddr09.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/sddr09.c Mon Aug 28 16:59:14 2000 @@ -1,10 +1,12 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * + * $Id: sddr09.c,v 1.10 2000/08/25 00:13:51 mdharm Exp $ + * * SDDR09 driver v0.1: * * First release * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 2000 Robert Baruch (autophile@dol.net) * * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. @@ -316,9 +318,9 @@ // Figure out the initial LBA and page - pba = (address/info->pagesize)>>4; + pba = address >> (info->pageshift + info->blockshift); lba = info->pba_to_lba[pba]; - page = (address/info->pagesize)&0x0F; + page = (address >> info->pageshift) & info->blockmask; // This could be made much more efficient by checking for // contiguous LBA's. Another exercise left to the student. @@ -329,15 +331,16 @@ // Read as many sectors as possible in this block - pages = 0x10-page; + pages = info->blocksize - page; if (pages > sectors) pages = sectors; - US_DEBUGP("Read %01X pages, from PBA %04X" - " (LBA %04X) page %01X\n", + US_DEBUGP("Read %02X pages, from PBA %04X" + " (LBA %04X) page %02X\n", pages, pba, lba, page); - address = ((pba<<4)+page)*info->pagesize; + address = ( (pba << info->blockshift) + page ) << + info->pageshift; // Unlike in the documentation, the address is in // words of 2 bytes. @@ -370,7 +373,7 @@ result = sddr09_bulk_transport(us, SCSI_DATA_READ, ptr, - pages*info->pagesize, 0); + pages<pageshift, 0); if (result != USB_STOR_TRANSPORT_GOOD) { if (use_sg) @@ -381,7 +384,7 @@ page = 0; lba++; sectors -= pages; - ptr += pages*info->pagesize; + ptr += (pages << info->pageshift); } if (use_sg) { @@ -435,7 +438,7 @@ result = sddr09_bulk_transport(us, SCSI_DATA_READ, content, - blocks*0x40, use_sg); + blocks<<6, use_sg); // 0x40 bytes per block US_DEBUGP("Result for bulk read in read_control %d\n", result); @@ -525,7 +528,7 @@ } unsigned long sddr09_get_capacity(struct us_data *us, - unsigned int *pagesize) { + unsigned int *pagesize, unsigned int *blocksize) { unsigned char manufacturerID; unsigned char deviceID; @@ -547,6 +550,7 @@ US_DEBUGP("Manuf ID = %02X\n", manufacturerID); *pagesize = 512; + *blocksize = 16; switch (deviceID) { @@ -556,8 +560,8 @@ *pagesize = 256; return 0x00100000; - case 0x5d: // 2MB - case 0xea: + case 0xea: // 2MB + case 0x5d: // 5d is a ROM card with pagesize 512. case 0x64: if (deviceID!=0x5D) *pagesize = 256; @@ -574,9 +578,11 @@ return 0x00800000; case 0x73: // 16MB + *blocksize = 32; return 0x01000000; case 0x75: // 32MB + *blocksize = 32; return 0x02000000; default: // unknown @@ -587,7 +593,7 @@ int sddr09_read_map(struct us_data *us) { - unsigned char *control; + struct scatterlist *sg; struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra); int numblocks; int i; @@ -599,25 +605,60 @@ 1, 0, 0, 1, 0, 1, 1, 0 }; int result; + int alloc_len; + int alloc_blocks; if (!info->capacity) return -1; - /* read 64 (2^6) bytes for every block (8192 (2^13) bytes) - of capacity: - 64*(capacity/8192) = capacity*(2^6)*(2^-13) = - capacity*2^(6-13) = capacity*(2^-7) - */ - - control = kmalloc(info->capacity>>7, GFP_KERNEL); + // read 64 (1<<6) bytes for every block + // ( 1 << ( blockshift + pageshift ) bytes) + // of capacity: + // (1<<6)*capacity/(1<<(b+p)) = + // ((1<<6)*capacity)>>(b+p) = + // capacity>>(b+p-6) + + alloc_len = info->capacity >> + (info->blockshift + info->pageshift - 6); + + // Allocate a number of scatterlist structures according to + // the number of 128k blocks in the alloc_len. Adding 128k-1 + // and then dividing by 128k gives the correct number of blocks. + // 128k = 1<<17 + + alloc_blocks = (alloc_len + (1<<17) - 1) >> 17; + sg = kmalloc(alloc_blocks*sizeof(struct scatterlist), + GFP_KERNEL); + if (sg == NULL) + return 0; + for (i=0; icapacity>>13; + numblocks = info->capacity >> (info->blockshift + info->pageshift); if ( (result = sddr09_read_control(us, 0, numblocks, - control, 0)) != + (unsigned char *)sg, alloc_blocks)) != USB_STOR_TRANSPORT_GOOD) { - kfree(control); + for (i=0; ipba_to_lba); info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL); info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL); + + if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { + if (info->lba_to_pba != NULL) + kfree(info->lba_to_pba); + if (info->pba_to_lba != NULL) + kfree(info->pba_to_lba); + info->lba_to_pba = NULL; + info->pba_to_lba = NULL; + for (i=0; ilba_to_pba, 0, numblocks*sizeof(int)); memset(info->pba_to_lba, 0, numblocks*sizeof(int)); + // Each block is 64 bytes of control data, so block i is located in + // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11) + for (i=0; i>11].address+(i<<6); if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF || ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF) continue; @@ -655,20 +713,30 @@ lba = (lba&0x07FF)>>1; + /* Every 1024 physical blocks, the LBA numbers + * go back to zero, but are within a higher + * block of LBA's. In other words, in blocks + * 1024-2047 you will find LBA 0-1023 which are + * really LBA 1024-2047. + */ + + lba += (i&~0x3FF); + if (lba>=numblocks) { US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i); continue; } - if (i<0x10) - US_DEBUGP("LBA %04X <-> PBA %04X\n", - lba, i); + if (lba<0x10) + US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i); info->pba_to_lba[i] = lba; info->lba_to_pba[lba] = i; } - kfree(control); + for (i=0; iextra); -/* - if (us->flags & US_FL_NEED_INIT) { - US_DEBUGP("SDDR-09: initializing\n"); - init_sddr09(us); - us->flags &= ~US_FL_NEED_INIT; - } -*/ - if (!us->extra) { us->extra = kmalloc( sizeof(struct sddr09_card_info), GFP_KERNEL); + if (!us->extra) + return USB_STOR_TRANSPORT_ERROR; memset(us->extra, 0, sizeof(struct sddr09_card_info)); us->extra_destructor = sddr09_card_info_destructor; } @@ -779,14 +840,29 @@ respond to INQUIRY commands */ if (srb->cmnd[0] == INQUIRY) { - memcpy(ptr, inquiry_response, 36); + memset(inquiry_response+8, 0, 28); + fill_inquiry_response(us, inquiry_response, 36); return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == READ_CAPACITY) { - capacity = sddr09_get_capacity(us, &info->pagesize); + capacity = sddr09_get_capacity(us, &info->pagesize, + &info->blocksize); + + if (!capacity) + return USB_STOR_TRANSPORT_FAILED; + info->capacity = capacity; + for (info->pageshift=1; + (info->pagesize>>info->pageshift); + info->pageshift++); + info->pageshift--; + for (info->blockshift=1; + (info->blocksize>>info->blockshift); + info->blockshift++); + info->blockshift--; + info->blockmask = (1<blockshift)-1; // Last page in the card @@ -836,12 +912,14 @@ // convert page to block and page-within-block - lba = page>>4; - page = page&0x0F; + lba = page >> info->blockshift; + page = page & info->blockmask; // locate physical block corresponding to logical block - if (lba>=(info->capacity>>13)) { + if (lba >= + (info->capacity >> + (info->pageshift + info->blockshift) ) ) { // FIXME: sense buffer? @@ -866,8 +944,8 @@ pba, lba, page, pages); return sddr09_read_data(us, - ((pba<<4)+page)*info->pagesize, pages, - ptr, srb->use_sg); + ( (pba << info->blockshift) + page) << info->pageshift, + pages, ptr, srb->use_sg); } // Pass TEST_UNIT_READY and REQUEST_SENSE through diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/sddr09.h linux/drivers/usb/storage/sddr09.h --- v2.4.0-test7/linux/drivers/usb/storage/sddr09.h Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/sddr09.h Mon Aug 28 16:59:14 2000 @@ -1,7 +1,9 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * Header File * - * Current development and maintainance by: + * $Id: sddr09.h,v 1.5 2000/08/25 00:13:51 mdharm Exp $ + * + * Current development and maintenance by: * (c) 2000 Robert Baruch (autophile@dol.net) * * See sddr09.c for more explanation @@ -29,10 +31,14 @@ extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us); struct sddr09_card_info { - unsigned long capacity; /* Size of card in bytes */ - int pagesize; /* Size of page in bytes */ - int *lba_to_pba; /* logical to physical map */ - int *pba_to_lba; /* physical to logical map */ + unsigned long capacity; /* Size of card in bytes */ + int pagesize; /* Size of page in bytes */ + int pageshift; /* log2 of pagesize */ + int blocksize; /* Size of block in pages */ + int blockshift; /* log2 of blocksize */ + int blockmask; /* 2^blockshift - 1 */ + int *lba_to_pba; /* logical to physical map */ + int *pba_to_lba; /* physical to logical map */ }; #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/shuttle_usbat.c linux/drivers/usb/storage/shuttle_usbat.c --- v2.4.0-test7/linux/drivers/usb/storage/shuttle_usbat.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/shuttle_usbat.c Mon Aug 28 16:59:14 2000 @@ -1,6 +1,6 @@ /* Driver for SCM Microsystems USB-ATAPI cable * - * $Id: shuttle_usbat.c,v 1.2 2000/08/03 00:03:39 groovyjava Exp $ + * $Id: shuttle_usbat.c,v 1.4 2000/08/25 00:13:51 mdharm Exp $ * * SCM driver v0.2: * @@ -14,7 +14,7 @@ * * First release - hp8200e. * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 2000 Robert Baruch (autophile@dol.net) * * Many originally ATAPI devices were slightly modified to meet the USB @@ -734,7 +734,7 @@ return result; } -static int init_8200e(struct us_data *us) { +int init_8200e(struct us_data *us) { int result; unsigned char status; @@ -895,11 +895,11 @@ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */ "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */ - if (us->flags & US_FL_NEED_INIT) { +/* if (us->flags & US_FL_NEED_INIT) { US_DEBUGP("8200e: initializing\n"); init_8200e(us); us->flags &= ~US_FL_NEED_INIT; - } + } */ len = srb->request_bufflen; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/shuttle_usbat.h linux/drivers/usb/storage/shuttle_usbat.h --- v2.4.0-test7/linux/drivers/usb/storage/shuttle_usbat.h Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/shuttle_usbat.h Mon Aug 28 16:59:14 2000 @@ -1,9 +1,9 @@ /* Driver for SCM Microsystems USB-ATAPI cable * Header File * - * $Id: shuttle_usbat.h,v 1.2 2000/08/03 00:03:39 groovyjava Exp $ + * $Id: shuttle_usbat.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 2000 Robert Baruch (autophile@dol.net) * * See scm.c for more explanation @@ -74,5 +74,6 @@ /* HP 8200e stuff */ extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int init_8200e(struct us_data *us); #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/transport.c linux/drivers/usb/storage/transport.c --- v2.4.0-test7/linux/drivers/usb/storage/transport.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/transport.c Mon Aug 28 16:59:14 2000 @@ -1,8 +1,8 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.12 2000/08/08 15:22:38 gowdy Exp $ + * $Id: transport.c,v 1.18 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: @@ -59,43 +59,7 @@ /* Calculate the length of the data transfer (not the command) for any * given SCSI command */ -static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us) -{ - int i; - unsigned int total = 0; - struct scatterlist *sg; - - /* support those devices which need the length calculated - * differently - */ - if (srb->cmnd[0] == INQUIRY) { - srb->cmnd[4] = 36; - } - - if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) - return srb->cmnd[4]; - - if (srb->cmnd[0] == TEST_UNIT_READY) - return 0; - - /* Are we going to scatter gather? */ - if (srb->use_sg) { - /* Add up the sizes of all the scatter-gather segments */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) - total += sg[i].length; - - return total; - } - else - /* Just return the length of the buffer */ - return srb->request_bufflen; -} - -/* Calculate the length of the data transfer (not the command) for any - * given SCSI command - */ -static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us) +static unsigned int us_transfer_length(Scsi_Cmnd *srb) { int i; int doDefault = 0; @@ -245,10 +209,6 @@ WRITE_SAME 41 */ - /* Not sure this is right as an INQUIRY can contain nonstandard info */ - if (srb->cmnd[0] == INQUIRY) - srb->cmnd[4] = 36; - if (srb->sc_data_direction == SCSI_DATA_WRITE) { doDefault = 1; } @@ -611,6 +571,16 @@ int i; int result = -1; struct scatterlist *sg; + unsigned int total_transferred = 0; + unsigned int transfer_amount; + + /* calculate how much we want to transfer */ + transfer_amount = us_transfer_length(srb); + + /* was someone foolish enough to request more data than available + * buffer space? */ + if (transfer_amount > srb->request_bufflen) + transfer_amount = srb->request_bufflen; /* are we scatter-gathering? */ if (srb->use_sg) { @@ -620,8 +590,19 @@ */ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { - result = us_transfer_partial(us, sg[i].address, - sg[i].length); + + /* transfer the lesser of the next buffer or the + * remaining data */ + if (transfer_amount - total_transferred >= + sg[i].length) { + result = us_transfer_partial(us, sg[i].address, + sg[i].length); + total_transferred += sg[i].length; + } else + result = us_transfer_partial(us, sg[i].address, + transfer_amount - total_transferred); + + /* if we get an error, end the loop here */ if (result) break; } @@ -629,7 +610,7 @@ else /* no scatter-gather, just make the request */ result = us_transfer_partial(us, srb->request_buffer, - srb->request_bufflen); + transfer_amount); /* return the result in the data structure itself */ srb->result = result; @@ -874,7 +855,7 @@ /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (us_transfer_length(srb, us)) { + if (us_transfer_length(srb)) { us_transfer(srb, us); US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); @@ -975,7 +956,7 @@ /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (us_transfer_length(srb, us)) { + if (us_transfer_length(srb)) { us_transfer(srb, us); US_DEBUGP("CB data stage result is 0x%x\n", srb->result); @@ -1039,10 +1020,12 @@ /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us)); + bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb)); bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; bcb.Tag = srb->serial_number; bcb.Lun = srb->cmnd[1] >> 5; + if (us->flags & US_FL_SCM_MULT_TARG) + bcb.Lun |= srb->target << 4; bcb.Length = srb->cmd_len; /* construct the pipe handle */ @@ -1053,8 +1036,9 @@ memcpy(bcb.CDB, srb->cmnd, bcb.Length); /* send it to out endpoint */ - US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n", - le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun, + US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", + le32_to_cpu(bcb.Signature), bcb.Tag, + (bcb.Lun >> 4), (bcb.Lun & 0xFF), bcb.DataTransferLength, bcb.Flags, bcb.Length); result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, &partial); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/transport.h linux/drivers/usb/storage/transport.h --- v2.4.0-test7/linux/drivers/usb/storage/transport.h Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/transport.h Mon Aug 28 16:59:14 2000 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * Transport Functions Header File * - * $Id: transport.h,v 1.8 2000/08/08 01:23:55 webbb Exp $ + * $Id: transport.h,v 1.11 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * This driver is based on the 'USB Mass Storage Class' document. This @@ -41,8 +41,8 @@ #ifndef _TRANSPORT_H_ #define _TRANSPORT_H_ -#include #include +#include #include "usb.h" #include "scsi.h" @@ -59,6 +59,10 @@ SDDR-09 */ #endif #define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ + +#ifdef CONFIG_USB_STORAGE_FREECOM +#define US_PR_FREECOM 0xf1 /* Freecom */ +#endif /* * Bulk only data structures diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c --- v2.4.0-test7/linux/drivers/usb/storage/usb.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/usb.c Tue Sep 5 12:56:51 2000 @@ -1,8 +1,8 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.23 2000/08/08 20:46:45 mdharm Exp $ + * $Id: usb.c,v 1.33 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: @@ -58,6 +58,9 @@ #ifdef CONFIG_USB_STORAGE_DPCM #include "dpcm.h" #endif +#ifdef CONFIG_USB_STORAGE_FREECOM +#include "freecom.h" +#endif #include #include @@ -213,8 +216,20 @@ /* reject if target != 0 or if LUN is higher than * the maximum known LUN */ - if (us->srb->target || (us->srb->lun > us->max_lun)) { - US_DEBUGP("Bad device number (%d/%d)\n", + if (us->srb->target && + !(us->flags & US_FL_SCM_MULT_TARG)) { + US_DEBUGP("Bad target number (%d/%d)\n", + us->srb->target, us->srb->lun); + us->srb->result = DID_BAD_TARGET << 16; + + set_current_state(TASK_INTERRUPTIBLE); + us->srb->scsi_done(us->srb); + us->srb = NULL; + break; + } + + if (us->srb->lun > us->max_lun) { + US_DEBUGP("Bad LUN (%d/%d)\n", us->srb->target, us->srb->lun); us->srb->result = DID_BAD_TARGET << 16; @@ -314,6 +329,19 @@ * are free to use as many characters as you like. */ +int euscsi_init(struct us_data *us) +{ + unsigned char bar = 0x1; + int result; + + US_DEBUGP("Attempting to init eUSCSI bridge...\n"); + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), + 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, + 0x01, 0x0, &bar, 0x1, 5*HZ); + US_DEBUGP("-- result is %d\n", result); + US_DEBUGP("-- bar afterwards is %d\n", bar); +} + static struct us_unusual_dev us_unusual_dev_list[] = { { 0x03f0, 0x0107, 0x0200, 0x0200, @@ -339,15 +367,61 @@ { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle", "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, NULL, - 0 }, + US_SC_SCSI, US_PR_BULK, euscsi_init, + US_FL_SCM_MULT_TARG }, - { 0x04e6, 0x0006, 0x0100, 0x0100, +#ifdef CONFIG_USB_STORAGE_SDDR09 + { 0x04e6, 0x0003, 0x0000, 0x9999, + "Sandisk", + "ImageMate SDDR09", + US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP }, +#endif + +#ifdef CONFIG_USB_STORAGE_DPCM + { 0x0436, 0x0005, 0x0100, 0x0100, + "Microtech", + "CameraMate (DPCM_USB)", + US_SC_SCSI, US_PR_DPCM_USB, NULL, + US_FL_START_STOP }, +#endif + + { 0x04e6, 0x0006, 0x0100, 0x0200, "Shuttle", "eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN}, + { 0x04e6, 0x0009, 0x0200, 0x0200, + "Shuttle", + "ATA/ATAPI Bridge", + US_SC_8020, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x04e6, 0x000A, 0x0200, 0x0200, + "Shuttle", + "Compact Flash Reader", + US_SC_8020, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x04e6, 0x000B, 0x0100, 0x0100, + "Shuttle", + "eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, euscsi_init, + US_FL_SCM_MULT_TARG }, + + { 0x04e6, 0x000C, 0x0100, 0x0100, + "Shuttle", + "eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, euscsi_init, + US_FL_SCM_MULT_TARG }, + + { 0x04e6, 0x0101, 0x0200, 0x0200, + "Shuttle", + "CD-RW Device", + US_SC_8020, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + { 0x054c, 0x0010, 0x0210, 0x0210, "Sony", "DSC-S30/S70", @@ -372,6 +446,24 @@ US_SC_UFI, US_PR_CBI, NULL, US_FL_SINGLE_LUN}, + { 0x059f, 0xa601, 0x0200, 0x0200, + "LaCie", + "USB Hard Disk", + US_SC_RBC, US_PR_CB, NULL, + 0 }, + + { 0x05ab, 0x0031, 0x0100, 0x0100, + "In-System", + "USB/IDE Bridge", + US_SC_8070, US_PR_BULK, NULL, + 0 }, + + { 0x0693, 0x0005, 0x0100, 0x0100, + "Hagiwara", + "Flashgate", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara", "FlashGate SmartMedia", @@ -401,14 +493,21 @@ { 0x07af, 0x0004, 0x0100, 0x0100, "Microtech", "USB-SCSI-DB25", - US_SC_SCSI, US_PR_BULK, NULL, - 0 }, + US_SC_SCSI, US_PR_BULK, euscsi_init, + US_FL_SCM_MULT_TARG }, - { 0x059f, 0xa601, 0x0200, 0x0200, - "LaCie", - "USB Hard Disk", - US_SC_RBC, US_PR_CB, NULL, - 0 }, +#ifdef CONFIG_USB_STORAGE_FREECOM + { 0x07ab, 0xfc01, 0x0921, 0x0921, + "Freecom", + "USB-IDE", + US_SC_8070, US_PR_FREECOM, NULL, US_FL_SINGLE_LUN }, +#endif + + { 0x07af, 0x0005, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-HD50", + US_SC_SCSI, US_PR_BULK, euscsi_init, + US_FL_SCM_MULT_TARG }, #ifdef CONFIG_USB_STORAGE_DPCM { 0x07af, 0x0006, 0x0100, 0x0100, @@ -417,25 +516,6 @@ US_SC_SCSI, US_PR_DPCM_USB, NULL, US_FL_START_STOP }, #endif - - { 0x07af, 0x0005, 0x0100, 0x0100, - "Microtech", - "USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, NULL, - 0 }, - - { 0x05ab, 0x0031, 0x0100, 0x0100, - "In-System", - "USB/IDE Bridge", - US_SC_8070, US_PR_BULK, NULL, - 0 }, - - { 0x0693, 0x0005, 0x0100, 0x0100, - "Hagiwara", - "Flashgate", - US_SC_SCSI, US_PR_BULK, NULL, - 0 }, - { 0 } }; @@ -615,15 +695,10 @@ /* set the interface -- STALL is an acceptable response here */ #ifdef CONFIG_USB_STORAGE_SDDR09 - if (protocol != US_PR_EUSB_SDDR09) - result = usb_set_interface(dev, - altsetting->bInterfaceNumber, 0); - else + if (protocol == US_PR_EUSB_SDDR09) result = usb_set_configuration(dev, 1); -#else - result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0); -#endif - US_DEBUGP("Result from usb_set_interface is %d\n", result); + + US_DEBUGP("Result from usb_set_configuration is %d\n", result); if (result == -EPIPE) { US_DEBUGP("-- clearing stall on control interface\n"); usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); @@ -632,6 +707,7 @@ US_DEBUGP("-- Unknown error. Rejecting device\n"); return NULL; } +#endif /* Do some basic sanity checks, and bail if we find a problem */ if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) { @@ -702,7 +778,7 @@ /* Re-Initialize the device if it needs it */ if (unusual_dev && unusual_dev->initFunction) - (*unusual_dev->initFunction)(ss); + (unusual_dev->initFunction)(ss); } else { /* New device -- allocate memory and initialize */ @@ -828,6 +904,15 @@ ss->max_lun = 1; break; #endif + +#ifdef CONFIG_USB_STORAGE_FREECOM + case US_PR_FREECOM: + ss->transport_name = "Freecom"; + ss->transport = freecom_transport; + ss->transport_reset = usb_stor_freecom_reset; + ss->max_lun = 0; + break; +#endif default: ss->transport_name = "Unknown"; @@ -909,7 +994,7 @@ /* Just before we start our control thread, initialize * the device if it needs initialization */ if (unusual_dev && unusual_dev->initFunction) - (*unusual_dev->initFunction)(ss); + (unusual_dev->initFunction)(ss); /* start up our control thread */ ss->pid = kernel_thread(usb_stor_control_thread, ss, diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/storage/usb.h linux/drivers/usb/storage/usb.h --- v2.4.0-test7/linux/drivers/usb/storage/usb.h Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/storage/usb.h Mon Aug 28 16:59:14 2000 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * Main Header File * - * $Id: usb.h,v 1.7 2000/08/15 00:06:38 mdharm Exp $ + * $Id: usb.h,v 1.8 2000/08/25 00:13:51 mdharm Exp $ * - * Current development and maintainance by: + * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Initial work by: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.4.0-test7/linux/drivers/usb/usb-core.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/usb-core.c Tue Sep 5 13:42:52 2000 @@ -25,16 +25,6 @@ int usb_major_init(void); void usb_major_cleanup(void); -/* - * USB device drivers - */ - -int usb_cpia_init(void); -int usb_audio_init(void); -int usb_ibmcam_init(void); -int dabusb_init(void); -int plusb_init(void); -int dsbr100_init(void); /* * HCI drivers @@ -65,24 +55,6 @@ usb_hub_init(); #ifndef CONFIG_USB_MODULE -#ifdef CONFIG_VIDEO_CPIA_USB - usb_cpia_init(); -#endif -#ifdef CONFIG_USB_AUDIO - usb_audio_init(); -#endif -#ifdef CONFIG_USB_IBMCAM - usb_ibmcam_init(); -#endif -#ifdef CONFIG_USB_DABUSB - dabusb_init(); -#endif -#ifdef CONFIG_USB_DSBR - dsbr100_init(); -#endif -#ifdef CONFIG_USB_PLUSB - plusb_init(); -#endif #ifdef CONFIG_USB_UHCI uhci_init(); #endif diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.4.0-test7/linux/drivers/usb/usb.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/usb/usb.c Tue Sep 5 13:41:53 2000 @@ -1945,6 +1945,7 @@ err = usb_get_configuration(dev); if (err < 0) { err("unable to get configuration (error=%d)", err); + usb_destroy_configuration(dev); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.4.0-test7/linux/drivers/video/atyfb.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/video/atyfb.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.146 2000/07/26 23:02:51 davem Exp $ +/* $Id: atyfb.c,v 1.147 2000/08/29 07:01:56 davem Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven @@ -3010,7 +3010,8 @@ fbtyp.fb_depth = info->current_par.crtc.bpp; fbtyp.fb_cmsize = disp->cmap.len; fbtyp.fb_size = info->total_vram; - copy_to_user_ret((struct fbtype *)arg, &fbtyp, sizeof(fbtyp), -EFAULT); + if (copy_to_user((struct fbtype *)arg, &fbtyp, sizeof(fbtyp))) + return -EFAULT; break; #endif /* __sparc__ */ #ifdef DEBUG @@ -3031,8 +3032,8 @@ clk.dsp_precision = (dsp_config>>20) & 7; clk.dsp_on = dsp_on_off & 0x7ff; clk.dsp_off = (dsp_on_off>>16) & 0x7ff; - copy_to_user_ret((struct atyclk *)arg, &clk, sizeof(clk), - -EFAULT); + if (copy_to_user((struct atyclk *)arg, &clk, sizeof(clk))) + return -EFAULT; } else return -EINVAL; break; @@ -3040,8 +3041,8 @@ if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) { struct atyclk clk; struct pll_ct *pll = &info->current_par.pll.ct; - copy_from_user_ret(&clk, (struct atyclk *)arg, sizeof(clk), - -EFAULT); + if (copy_from_user(&clk, (struct atyclk *)arg, sizeof(clk))) + return -EFAULT; info->ref_clk_per = clk.ref_clk_per; pll->pll_ref_div = clk.pll_ref_div; pll->mclk_fb_div = clk.mclk_fb_div; diff -u --recursive --new-file v2.4.0-test7/linux/drivers/video/cgfourteenfb.c linux/drivers/video/cgfourteenfb.c --- v2.4.0-test7/linux/drivers/video/cgfourteenfb.c Wed Dec 29 13:13:20 1999 +++ linux/drivers/video/cgfourteenfb.c Tue Aug 29 14:09:15 2000 @@ -1,4 +1,4 @@ -/* $Id: cgfourteenfb.c,v 1.7 1999/11/19 09:57:01 davem Exp $ +/* $Id: cgfourteenfb.c,v 1.8 2000/08/29 07:01:56 davem Exp $ * cgfourteenfb.c: CGfourteen frame buffer driver * * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -299,15 +299,17 @@ break; case MDI_GET_CFGINFO: mdii = (struct mdi_cfginfo *)arg; - put_user_ret(FBTYPE_MDICOLOR, &mdii->mdi_type, -EFAULT); - __put_user_ret(fb->type.fb_height, &mdii->mdi_height, -EFAULT); - __put_user_ret(fb->type.fb_width, &mdii->mdi_width, -EFAULT); - __put_user_ret(fb->s.cg14.mode, &mdii->mdi_mode, -EFAULT); - __put_user_ret(72, &mdii->mdi_pixfreq, -EFAULT); /* FIXME */ - __put_user_ret(fb->s.cg14.ramsize, &mdii->mdi_size, -EFAULT); + if (put_user(FBTYPE_MDICOLOR, &mdii->mdi_type) || + __put_user(fb->type.fb_height, &mdii->mdi_height) || + __put_user(fb->type.fb_width, &mdii->mdi_width) || + __put_user(fb->s.cg14.mode, &mdii->mdi_mode) || + __put_user(72, &mdii->mdi_pixfreq) || /* FIXME */ + __put_user(fb->s.cg14.ramsize, &mdii->mdi_size)) + return -EFAULT; break; case MDI_SET_PIXELMODE: - get_user_ret(mode, (int *)arg, -EFAULT); + if (get_user(mode, (int *)arg)) + return -EFAULT; spin_lock_irqsave(&fb->lock, flags); tmp = sbus_readb(mcr); diff -u --recursive --new-file v2.4.0-test7/linux/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c --- v2.4.0-test7/linux/drivers/video/matrox/matroxfb_base.c Wed Aug 23 18:36:38 2000 +++ linux/drivers/video/matrox/matroxfb_base.c Tue Aug 29 14:09:15 2000 @@ -1030,7 +1030,8 @@ err = matroxfb_get_vblank(PMINFO &vblank); if (err) return err; - copy_to_user_ret((struct fb_vblank*)arg, &vblank, sizeof(vblank), -EFAULT); + if (copy_to_user((struct fb_vblank*)arg, &vblank, sizeof(vblank))) + return -EFAULT; return 0; } case MATROXFB_SET_OUTPUT_MODE: @@ -1038,7 +1039,8 @@ struct matroxioc_output_mode mom; int val; - copy_from_user_ret(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom), -EFAULT); + if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom))) + return -EFAULT; if (mom.output >= sizeof(u_int32_t)) return -EINVAL; switch (mom.output) { @@ -1084,7 +1086,8 @@ struct matroxioc_output_mode mom; int val; - copy_from_user_ret(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom), -EFAULT); + if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom))) + return -EFAULT; if (mom.output >= sizeof(u_int32_t)) return -EINVAL; switch (mom.output) { @@ -1108,14 +1111,16 @@ default: return -EINVAL; } - copy_to_user_ret((struct matroxioc_output_mode*)arg, &mom, sizeof(mom), -EFAULT); + if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom))) + return -EFAULT; return 0; } case MATROXFB_SET_OUTPUT_CONNECTION: { u_int32_t tmp; - copy_from_user_ret(&tmp, (u_int32_t*)arg, sizeof(tmp), -EFAULT); + if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp))) + return -EFAULT; if (tmp & ~ACCESS_FBINFO(output.all)) return -EINVAL; if (tmp & ACCESS_FBINFO(output.sh)) @@ -1134,7 +1139,8 @@ } case MATROXFB_GET_OUTPUT_CONNECTION: { - put_user_ret(ACCESS_FBINFO(output.ph), (u_int32_t*)arg, -EFAULT); + if (put_user(ACCESS_FBINFO(output.ph), (u_int32_t*)arg)) + return -EFAULT; return 0; } case MATROXFB_GET_AVAILABLE_OUTPUTS: @@ -1146,12 +1152,14 @@ tmp &= ~MATROXFB_OUTPUT_CONN_SECONDARY; if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) tmp &= ~MATROXFB_OUTPUT_CONN_DFP; - put_user_ret(tmp, (u_int32_t*)arg, -EFAULT); + if (put_user(tmp, (u_int32_t*)arg)) + return -EFAULT; return 0; } case MATROXFB_GET_ALL_OUTPUTS: { - put_user_ret(ACCESS_FBINFO(output.all), (u_int32_t*)arg, -EFAULT); + if (put_user(ACCESS_FBINFO(output.all), (u_int32_t*)arg)) + return -EFAULT; return 0; } } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/video/matrox/matroxfb_crtc2.c linux/drivers/video/matrox/matroxfb_crtc2.c --- v2.4.0-test7/linux/drivers/video/matrox/matroxfb_crtc2.c Mon Jul 10 16:47:25 2000 +++ linux/drivers/video/matrox/matroxfb_crtc2.c Tue Aug 29 14:09:15 2000 @@ -509,7 +509,8 @@ err = matroxfb_dh_get_vblank(m2info, &vblank); if (err) return err; - copy_to_user_ret((struct fb_vblank*)arg, &vblank, sizeof(vblank), -EFAULT); + if (copy_to_user((struct fb_vblank*)arg, &vblank, sizeof(vblank))) + return -EFAULT; return 0; } case MATROXFB_SET_OUTPUT_MODE: @@ -522,7 +523,8 @@ { u_int32_t tmp; - get_user_ret(tmp, (u_int32_t*)arg, -EFAULT); + if (get_user(tmp, (u_int32_t*)arg)) + return -EFAULT; if (tmp & ~ACCESS_FBINFO(output.all)) return -EINVAL; if (tmp & ACCESS_FBINFO(output.ph)) @@ -539,7 +541,8 @@ } case MATROXFB_GET_OUTPUT_CONNECTION: { - put_user_ret(ACCESS_FBINFO(output.sh), (u_int32_t*)arg, -EFAULT); + if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg)) + return -EFAULT; return 0; } case MATROXFB_GET_AVAILABLE_OUTPUTS: @@ -551,7 +554,8 @@ /* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) tmp = 0; - put_user_ret(tmp, (u_int32_t*)arg, -EFAULT); + if (put_user(tmp, (u_int32_t*)arg)) + return -EFAULT; return 0; } } diff -u --recursive --new-file v2.4.0-test7/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c --- v2.4.0-test7/linux/drivers/video/sbusfb.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/video/sbusfb.c Tue Aug 29 14:09:15 2000 @@ -584,22 +584,26 @@ switch (cmd){ case FBIOGTYPE: /* return frame buffer type */ - copy_to_user_ret((struct fbtype *)arg, &fb->type, sizeof(struct fbtype), -EFAULT); + if (copy_to_user((struct fbtype *)arg, &fb->type, sizeof(struct fbtype))) + return -EFAULT; break; case FBIOGATTR: { struct fbgattr *fba = (struct fbgattr *) arg; i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr)); if (i) return i; - __put_user_ret(fb->emulations[0], &fba->real_type, -EFAULT); - __put_user_ret(0, &fba->owner, -EFAULT); - __copy_to_user_ret(&fba->fbtype, &fb->type, - sizeof(struct fbtype), -EFAULT); - __put_user_ret(0, &fba->sattr.flags, -EFAULT); - __put_user_ret(fb->type.fb_type, &fba->sattr.emu_type, -EFAULT); - __put_user_ret(-1, &fba->sattr.dev_specific[0], -EFAULT); - for (i = 0; i < 4; i++) - put_user_ret(fb->emulations[i], &fba->emu_types[i], -EFAULT); + if (__put_user(fb->emulations[0], &fba->real_type) || + __put_user(0, &fba->owner) || + __copy_to_user(&fba->fbtype, &fb->type, + sizeof(struct fbtype)) || + __put_user(0, &fba->sattr.flags) || + __put_user(fb->type.fb_type, &fba->sattr.emu_type) || + __put_user(-1, &fba->sattr.dev_specific[0])) + return -EFAULT; + for (i = 0; i < 4; i++) { + if (put_user(fb->emulations[i], &fba->emu_types[i])) + return -EFAULT; + } break; } case FBIOSATTR: @@ -612,7 +616,8 @@ if (vt_cons[lastconsole]->vc_mode == KD_TEXT) break; } - get_user_ret(i, (int *)arg, -EFAULT); + if (get_user(i, (int *)arg)) + return -EFAULT; if (i){ if (!fb->blanked || !fb->unblank) break; @@ -627,7 +632,8 @@ } break; case FBIOGVIDEO: - put_user_ret(fb->blanked, (int *) arg, -EFAULT); + if (put_user(fb->blanked, (int *) arg)) + return -EFAULT; break; case FBIOGETCMAP_SPARC: { char *rp, *gp, *bp; @@ -639,23 +645,29 @@ i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap)); if (i) return i; cmap = (struct fbcmap *) arg; - __get_user_ret(count, &cmap->count, -EFAULT); - __get_user_ret(index, &cmap->index, -EFAULT); + if (__get_user(count, &cmap->count) || + __get_user(index, &cmap->index)) + return -EFAULT; if ((index < 0) || (index > 255)) return -EINVAL; if (index + count > 256) count = 256 - index; - __get_user_ret(rp, &cmap->red, -EFAULT); - __get_user_ret(gp, &cmap->green, -EFAULT); - __get_user_ret(bp, &cmap->blue, -EFAULT); - if(verify_area (VERIFY_WRITE, rp, count)) return -EFAULT; - if(verify_area (VERIFY_WRITE, gp, count)) return -EFAULT; - if(verify_area (VERIFY_WRITE, bp, count)) return -EFAULT; + if (__get_user(rp, &cmap->red) || + __get_user(gp, &cmap->green) || + __get_user(bp, &cmap->blue)) + return -EFAULT; + if (verify_area (VERIFY_WRITE, rp, count)) + return -EFAULT; + if (verify_area (VERIFY_WRITE, gp, count)) + return -EFAULT; + if (verify_area (VERIFY_WRITE, bp, count)) + return -EFAULT; end = index + count; for (i = index; i < end; i++){ - __put_user_ret(fb->color_map CM(i,0), rp, -EFAULT); - __put_user_ret(fb->color_map CM(i,1), gp, -EFAULT); - __put_user_ret(fb->color_map CM(i,2), bp, -EFAULT); + if (__put_user(fb->color_map CM(i,0), rp) || + __put_user(fb->color_map CM(i,1), gp) || + __put_user(fb->color_map CM(i,2), bp)) + return -EFAULT; rp++; gp++; bp++; } (*fb->loadcmap)(fb, NULL, index, count); @@ -671,24 +683,32 @@ i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap)); if (i) return i; cmap = (struct fbcmap *) arg; - __get_user_ret(count, &cmap->count, -EFAULT); - __get_user_ret(index, &cmap->index, -EFAULT); + if (__get_user(count, &cmap->count) || + __get_user(index, &cmap->index)) + return -EFAULT; if ((index < 0) || (index > 255)) return -EINVAL; if (index + count > 256) count = 256 - index; - __get_user_ret(rp, &cmap->red, -EFAULT); - __get_user_ret(gp, &cmap->green, -EFAULT); - __get_user_ret(bp, &cmap->blue, -EFAULT); - if(verify_area (VERIFY_READ, rp, count)) return -EFAULT; - if(verify_area (VERIFY_READ, gp, count)) return -EFAULT; - if(verify_area (VERIFY_READ, bp, count)) return -EFAULT; + if (__get_user(rp, &cmap->red) || + __get_user(gp, &cmap->green) || + __get_user(bp, &cmap->blue)) + return -EFAULT; + if (verify_area (VERIFY_READ, rp, count)) + return -EFAULT; + if (verify_area (VERIFY_READ, gp, count)) + return -EFAULT; + if (verify_area (VERIFY_READ, bp, count)) + return -EFAULT; end = index + count; for (i = index; i < end; i++){ - __get_user_ret(fb->color_map CM(i,0), rp, -EFAULT); - __get_user_ret(fb->color_map CM(i,1), gp, -EFAULT); - __get_user_ret(fb->color_map CM(i,2), bp, -EFAULT); + if (__get_user(fb->color_map CM(i,0), rp)) + return -EFAULT; + if (__get_user(fb->color_map CM(i,1), gp)) + return -EFAULT; + if (__get_user(fb->color_map CM(i,2), bp)) + return -EFAULT; rp++; gp++; bp++; } (*fb->loadcmap)(fb, NULL, index, count); @@ -699,8 +719,9 @@ if (!fb->setcursor) return -EINVAL; if(verify_area (VERIFY_WRITE, p, sizeof (struct fbcurpos))) return -EFAULT; - __put_user_ret(fb->cursor.hwsize.fbx, &p->fbx, -EFAULT); - __put_user_ret(fb->cursor.hwsize.fby, &p->fby, -EFAULT); + if (__put_user(fb->cursor.hwsize.fbx, &p->fbx) || + __put_user(fb->cursor.hwsize.fby, &p->fby)) + return -EFAULT; break; } case FBIOSCURSOR: diff -u --recursive --new-file v2.4.0-test7/linux/drivers/video/sisfb.c linux/drivers/video/sisfb.c --- v2.4.0-test7/linux/drivers/video/sisfb.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/video/sisfb.c Mon Aug 28 21:25:25 2000 @@ -1,5 +1,5 @@ /* - * SiS 300/630/540 frame buffer device For Kernal 2.3.x + * SiS 300/630/540 frame buffer device For Kernal 2.4.x * * This driver is partly based on the VBE 2.0 compliant graphic * boards framebuffer driver, which is @@ -10,6 +10,7 @@ #define EXPORT_SYMTAB #undef SISFBDEBUG +#undef CONFIG_FB_SIS_LINUXBIOS #include #include @@ -174,11 +175,10 @@ u16 vendor, device; const char *name; } dev_list[] = { - { - PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, { - PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5300, "SIS 540"}, { - PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_6300, "SIS 630"}, { - 0, 0, NULL} + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"}, + {0, 0, NULL} }; /* card parameters */ @@ -192,9 +192,16 @@ static int sisfb_off = 0; static struct fb_var_screeninfo default_var = { - 0, 0, 0, 0, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, + 0, + 0, + {0, 8, 0}, + {0, 8, 0}, + {0, 8, 0}, + {0, 0, 0}, + 0, + FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, FB_VMODE_NONINTERLACED, {0, 0, 0, 0, 0, 0} @@ -202,9 +209,11 @@ static struct display disp; static struct fb_info fb_info; + static struct { u16 blue, green, red, pad; } palette[256]; + static union { #ifdef FBCON_HAS_CFB16 u16 cfb16[16]; @@ -230,7 +239,7 @@ u16 CRT1VCLKLen; u16 flag_clearbuffer; u16 CRT1VCLKLen; -int ModeIDOffset, StandTable, CRT1Table, ScreenOffset, MCLKData, ECLKData; +int ModeIDOffset, StandTable, CRT1Table, ScreenOffset; int REFIndex, ModeType; int VCLKData; int RAMType; @@ -249,26 +258,25 @@ u16 cols; u16 rows; } sisbios_mode[] = { - { - "640x480x8", 0x2E, 640, 480, 8, 1, 80, 30}, { - "640x480x16", 0x44, 640, 480, 16, 1, 80, 30}, { - "640x480x32", 0x62, 640, 480, 32, 1, 80, 30}, { - "800x600x8", 0x30, 800, 600, 8, 2, 100, 37}, { - "800x600x16", 0x47, 800, 600, 16, 2, 100, 37}, { - "800x600x32", 0x63, 800, 600, 32, 2, 100, 37}, { - "1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48}, { - "1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48}, { - "1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48}, { - "1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64}, { - "1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64}, { - "1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64}, { - "1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75}, { - "1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75}, { - "1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75}, { - "1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75}, { - "1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75}, { - "1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75}, { - "\0", 0x00, 0, 0, 0, 0, 0, 0} + {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30}, + {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30}, + {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30}, + {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37}, + {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37}, + {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37}, + {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48}, + {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48}, + {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48}, + {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64}, + {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64}, + {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64}, + {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75}, + {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75}, + {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75}, + {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75}, + {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75}, + {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75}, + {"\0", 0x00, 0, 0, 0, 0, 0, 0} }; static struct _vrate { @@ -277,57 +285,33 @@ u16 yres; u16 refresh; } vrate[] = { - { - 1, 640, 480, 60}, { - 2, 640, 480, 72}, { - 3, 640, 480, 75}, { - 4, 640, 480, 85}, { - 5, 640, 480, 100}, { - 6, 640, 480, 120}, { - 7, 640, 480, 160}, { - 8, 640, 480, 200}, { - 1, 800, 600, 56}, { - 2, 800, 600, 60}, { - 3, 800, 600, 72}, { - 4, 800, 600, 75}, { - 5, 800, 600, 85}, { - 6, 800, 600, 100}, { - 7, 800, 600, 120}, { - 8, 800, 600, 160}, { - 1, 1024, 768, 56}, { - 2, 1024, 768, 60}, { - 3, 1024, 768, 72}, { - 4, 1024, 768, 75}, { - 5, 1024, 768, 85}, { - 6, 1024, 768, 100}, { - 7, 1024, 768, 120}, { - 1, 1280, 1024, 43}, { - 2, 1280, 1024, 60}, { - 3, 1280, 1024, 75}, { - 4, 1280, 1024, 85}, { - 1, 1600, 1200, 60}, { - 2, 1600, 1200, 65}, { - 3, 1600, 1200, 70}, { - 4, 1600, 1200, 75}, { - 5, 1600, 1200, 85}, { - 1, 1920, 1440, 60}, { - 0, 0, 0, 0} + {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85}, + {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200}, + {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75}, + {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160}, + {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75}, + {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120}, + {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85}, + {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75}, + {5, 1600, 1200, 85}, + {1, 1920, 1440, 60}, + {0, 0, 0, 0} }; - -u16 DRAMType[17][5] = - { {0x0C, 0x0A, 0x02, 0x40, 0x39}, {0x0D, 0x0A, 0x01, 0x40, 0x48}, -{0x0C, 0x09, 0x02, 0x20, 0x35}, {0x0D, 0x09, 0x01, 0x20, 0x44}, -{0x0C, 0x08, 0x02, 0x10, 0x31}, {0x0D, 0x08, 0x01, 0x10, 0x40}, -{0x0C, 0x0A, 0x01, 0x20, 0x34}, {0x0C, 0x09, 0x01, 0x08, 0x32}, -{0x0B, 0x08, 0x02, 0x08, 0x21}, {0x0C, 0x08, 0x01, 0x08, 0x30}, -{0x0A, 0x08, 0x02, 0x04, 0x11}, {0x0B, 0x0A, 0x01, 0x10, 0x28}, -{0x09, 0x08, 0x02, 0x02, 0x01}, {0x0B, 0x09, 0x01, 0x08, 0x24}, -{0x0B, 0x08, 0x01, 0x04, 0x20}, {0x0A, 0x08, 0x01, 0x02, 0x10}, -{0x09, 0x08, 0x01, 0x01, 0x00} +u16 DRAMType[17][5] = { + {0x0C, 0x0A, 0x02, 0x40, 0x39}, {0x0D, 0x0A, 0x01, 0x40, 0x48}, + {0x0C, 0x09, 0x02, 0x20, 0x35}, {0x0D, 0x09, 0x01, 0x20, 0x44}, + {0x0C, 0x08, 0x02, 0x10, 0x31}, {0x0D, 0x08, 0x01, 0x10, 0x40}, + {0x0C, 0x0A, 0x01, 0x20, 0x34}, {0x0C, 0x09, 0x01, 0x08, 0x32}, + {0x0B, 0x08, 0x02, 0x08, 0x21}, {0x0C, 0x08, 0x01, 0x08, 0x30}, + {0x0A, 0x08, 0x02, 0x04, 0x11}, {0x0B, 0x0A, 0x01, 0x10, 0x28}, + {0x09, 0x08, 0x02, 0x02, 0x01}, {0x0B, 0x09, 0x01, 0x08, 0x24}, + {0x0B, 0x08, 0x01, 0x04, 0x20}, {0x0A, 0x08, 0x01, 0x02, 0x10}, + {0x09, 0x08, 0x01, 0x01, 0x00} }; -u16 MDA_DAC[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +u16 MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, @@ -337,7 +321,8 @@ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F }; -u16 CGA_DAC[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, +u16 CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, @@ -347,7 +332,8 @@ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -u16 EGA_DAC[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, +u16 EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, @@ -357,7 +343,8 @@ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -u16 VGA_DAC[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, +u16 VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, @@ -369,6 +356,55 @@ 0x0B, 0x0C, 0x0D, 0x0F, 0x10 }; +#ifdef CONFIG_FB_SIS_LINUXBIOS + +#define Monitor1Sense 0x20 + +unsigned char SRegsInit[] = { + 0x03, 0x00, 0x03, 0x00, 0x02, 0xa1, 0x00, 0x13, + 0x2f, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa1, 0x76, 0xb2, 0xf6, 0x0d, 0x00, 0x00, 0x00, + 0x37, 0x61, 0x80, 0x1b, 0xe1, 0x01, 0x55, 0x43, + 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff +}; + +unsigned char SRegs[] = { + 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13, + 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x0B, 0x0F, 0x00, 0x00, 0x4F, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00, + 0xA1, 0xB6, 0xB2, 0xF6, 0x0D, 0x00, 0xF8, 0xF0, + 0x37, 0x61, 0x80, 0x1B, 0xE1, 0x80, 0x55, 0x43, + 0x80, 0x00, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF, + 0x8E, 0x40, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xFF +}; + +unsigned char CRegs[] = { + 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x0b, 0xdf, 0x50, 0x40, 0xe7, 0x04, 0xa3, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff +}; // clear CR11[7] + +unsigned char GRegs[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, 0x00 +}; + +unsigned char ARegs[] = { + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +unsigned char MReg = 0x6f; + +#endif + + /* HEAP stuff */ struct OH { @@ -463,6 +499,7 @@ static void set_reg4(u16 port, unsigned long data); static u8 get_reg1(u16 port, u16 index); static u8 get_reg2(u16 port); +//#ifndef CONFIG_FB_SIS_LINUXBIOS static u32 get_reg3(u16 port); static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo); static int search_modeID(unsigned long ROMAddr, u16 ModeNo); @@ -488,6 +525,7 @@ static void set_crt1_FIFO2(unsigned long ROMAddr); static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo); static void set_interlace(unsigned long ROMAddr, u16 ModeNo); +//#endif static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh); static void load_DAC(unsigned long ROMAddr); static void display_on(void); @@ -781,6 +819,7 @@ sw = &fbcon_cfb8; break; #endif + #ifdef FBCON_HAS_CFB16 case 15: case 16: @@ -788,18 +827,21 @@ display->dispsw_data = fbcon_cmap.cfb16; break; #endif + #ifdef FBCON_HAS_CFB24 case 24: sw = &fbcon_cfb24; display->dispsw_data = fbcon_cmap.cfb24; break; #endif + #ifdef FBCON_HAS_CFB32 case 32: sw = &fbcon_cfb32; display->dispsw_data = fbcon_cmap.cfb32; break; #endif + default: sw = &fbcon_dummy; return; @@ -810,7 +852,6 @@ display->scrollmode = SCROLL_YREDRAW; sisfb_sw.bmove = fbcon_redraw_bmove; - } /* @@ -818,9 +859,8 @@ * Return != 0 for invalid regno. */ -static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, - struct fb_info *fb_info) +static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *fb_info) { if (regno >= video_cmap_len) return 1; @@ -838,9 +878,8 @@ * entries in the var structure). Return != 0 for invalid regno. */ -static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info) +static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *fb_info) { if (regno >= video_cmap_len) @@ -949,14 +988,13 @@ return 1; } - if (search_refresh_rate(ivideo.refresh_rate) == 0) { /* not supported rate */ + if (search_refresh_rate(ivideo.refresh_rate) == 0) { + /* not supported rate */ rate_idx = sisbios_mode[mode_idx].rate_idx; ivideo.refresh_rate = 60; } - - if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) - && isactive) { + if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) { pre_setmode(); if (SiSSetMode(mode_no)) { @@ -1020,7 +1058,8 @@ struct OH *poh; u8 jTemp, tq_state; - if(ivideo.video_size > 0x800000) /* video ram is large than 8M */ + if (ivideo.video_size > 0x800000) + /* video ram is large than 8M */ heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M; else heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M; @@ -1401,22 +1440,28 @@ static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo) { -#if 0 unsigned char ModeID; u16 modeidlength; u16 usModeIDOffset; + unsigned short PreviousWord,CurrentWord; - modeidlength = 0; - usModeIDOffset = *((u16 *) (ROMAddr + 0x20A)); - ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset)); - while (ModeID != 0x2E) { - modeidlength++; - usModeIDOffset = usModeIDOffset + 1; - ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset)); - } - return (modeidlength); -#endif return(10); + + modeidlength=0; + usModeIDOffset=*((unsigned short *)(ROMAddr+0x20A)); // Get EModeIDTable + + CurrentWord=*((unsigned short *)(ROMAddr+usModeIDOffset)); // Offset 0x20A + PreviousWord=*((unsigned short *)(ROMAddr+usModeIDOffset-2)); // Offset 0x20A + while((CurrentWord!=0x2E07)||(PreviousWord!=0x0801)) + { + modeidlength++; + usModeIDOffset=usModeIDOffset+1; // 10 <= ExtStructSize + CurrentWord=*((unsigned short *)(ROMAddr+usModeIDOffset)); + PreviousWord=*((unsigned short *)(ROMAddr+usModeIDOffset-2)); + } + modeidlength++; + + return(modeidlength); } static int search_modeID(unsigned long ROMAddr, u16 ModeNo) @@ -1470,8 +1515,7 @@ StandTable = *((u16 *) (ROMAddr + 0x202)); if (ModeNo <= 13) - index = - *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03)); + index = *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03)); else { if (ModeType <= 0x02) index = 0x1B; @@ -1488,26 +1532,40 @@ unsigned char SRdata; u16 i; +#ifdef CONFIG_FB_SIS_LINUXBIOS + SRdata = SRegs[0x01]; +#else set_reg1(P3c4, 0x00, 0x03); StandTable = StandTable + 0x05; SRdata = *((unsigned char *) (ROMAddr + StandTable)); +#endif + SRdata = SRdata | 0x20; set_reg1(P3c4, 0x01, SRdata); + for (i = 02; i <= 04; i++) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + SRdata = SRegs[i]; +#else StandTable++; SRdata = *((unsigned char *) (ROMAddr + StandTable)); +#endif set_reg1(P3c4, i, SRdata); } } static void set_misc_regs(unsigned long ROMAddr) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg3(P3c2, 0x23); +#else unsigned char Miscdata; StandTable++; Miscdata = *((unsigned char *) (ROMAddr + StandTable)); set_reg3(P3c2, Miscdata); +#endif } static void set_crtc_regs(unsigned long ROMAddr) @@ -1516,13 +1574,19 @@ u16 i; CRTCdata = (unsigned char) get_reg1(P3d4, 0x11); +#ifndef CONFIG_FB_SIS_LINUXBIOS CRTCdata = CRTCdata & 0x7f; +#endif set_reg1(P3d4, 0x11, CRTCdata); for (i = 0; i <= 0x18; i++) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg1(P3d4, i, CRegs[i]); +#else StandTable++; CRTCdata = *((unsigned char *) (ROMAddr + StandTable)); set_reg1(P3d4, i, CRTCdata); +#endif } } @@ -1532,17 +1596,23 @@ u16 i; for (i = 0; i <= 0x13; i++) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + get_reg2(P3da); + set_reg3(P3c0, i); + set_reg3(P3c0, ARegs[i]); +#else StandTable++; ARdata = *((unsigned char *) (ROMAddr + StandTable)); get_reg2(P3da); set_reg3(P3c0, i); set_reg3(P3c0, ARdata); +#endif } + get_reg2(P3da); set_reg3(P3c0, 0x14); set_reg3(P3c0, 0x00); - get_reg2(P3da); set_reg3(P3c0, 0x20); } @@ -1553,15 +1623,22 @@ u16 i; for (i = 0; i <= 0x08; i++) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg1(P3ce, i, GRegs[i]); +#else StandTable++; GRdata = *((unsigned char *) (ROMAddr + StandTable)); set_reg1(P3ce, i, GRdata); +#endif } + +#ifndef CONFIG_FB_SIS_LINUXBIOS if (ModeType > ModeVGA) { GRdata = (unsigned char) get_reg1(P3ce, 0x05); GRdata = GRdata & 0xBF; set_reg1(P3ce, 0x05, GRdata); } +#endif } static void ClearExt1Regs(void) @@ -1637,6 +1714,9 @@ static void set_sync(unsigned long ROMAddr) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg3(P3c2, MReg); +#else u16 sync; u16 temp; @@ -1645,10 +1725,33 @@ temp = 0x2F; temp = temp | sync; set_reg3(P3c2, temp); +#endif } static void set_crt1_crtc(unsigned long ROMAddr) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + unsigned char data; + u16 i; + + data = (unsigned char) get_reg1(P3d4, 0x11); + data = data & 0x7F; + set_reg1(P3d4, 0x11, data); + + for (i = 0; i <= 0x07; i++) + set_reg1(P3d4, i, CRegs[i]); + for (i = 0x10; i <= 0x12; i++) + set_reg1(P3d4, i, CRegs[i]); + for (i = 0x15; i <= 0x16; i++) + set_reg1(P3d4, i, CRegs[i]); + for (i = 0x0A; i <= 0x0C; i++) + set_reg1(P3c4, i, SRegs[i]); + + data = SRegs[0x0E] & 0xE0; + set_reg1(P3c4, 0x0E, data); + + set_reg1(P3d4, 0x09, CRegs[0x09]); +#else unsigned char index; unsigned char data; u16 i; @@ -1707,10 +1810,16 @@ if (ModeType > 0x03) set_reg1(P3d4, 0x14, 0x4F); +#endif } + static void set_crt1_offset(unsigned long ROMAddr) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg1(P3c4, 0x0E, SRegs[0x0E]); + set_reg1(P3c4, 0x10, SRegs[0x10]); +#else u16 temp, ah, al; u16 temp2, i; u16 DisplayUnit; @@ -1773,6 +1882,7 @@ else ah = ah + 2; set_reg1(P3c4, 0x10, ah); +#endif } static u16 get_vclk_len(unsigned long ROMAddr) @@ -1792,31 +1902,44 @@ static void set_crt1_vclk(unsigned long ROMAddr) { u16 i; + +#ifndef CONFIG_FB_SIS_LINUXBIOS unsigned char index, data; index = *((unsigned char *) (ROMAddr + REFIndex + 0x03)); + index &= 0x03F; CRT1VCLKLen = get_vclk_len(ROMAddr); data = index * CRT1VCLKLen; VCLKData = *((u16 *) (ROMAddr + 0x208)); VCLKData = VCLKData + data; +#endif set_reg1(P3c4, 0x31, 0); for (i = 0x2B; i <= 0x2C; i++) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg1(P3c4, i, SRegs[i]); +#else data = *((unsigned char *) (ROMAddr + VCLKData)); set_reg1(P3c4, i, data); VCLKData++; +#endif } set_reg1(P3c4, 0x2D, 0x80); } - static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg1(P3c4, 0x32, SRegs[0x32]); + set_reg1(P3c4, 0x07, SRegs[0x07]); +#else + u16 data, data2; u16 VCLK; unsigned char index; index = *((unsigned char *) (ROMAddr + REFIndex + 0x03)); + index &= 0x3F; CRT1VCLKLen = get_vclk_len(ROMAddr); data = index * CRT1VCLKLen; VCLKData = *((u16 *) (ROMAddr + 0x208)); @@ -1849,6 +1972,7 @@ data = data & 0xFC; data = data | data2; set_reg1(P3c4, 0x07, data); +#endif } static u16 calc_delay2(unsigned long ROMAddr, u16 key) @@ -1926,6 +2050,7 @@ u16 ah, bl, A, B; index = *((unsigned char *) (ROMAddr + REFIndex + 0x03)); + index &= 0x3F; CRT1VCLKLen = get_vclk_len(ROMAddr); data = index * CRT1VCLKLen; VCLKData = *((u16 *) (ROMAddr + 0x208)); @@ -2017,14 +2142,26 @@ set_reg1(P3c4, 0x09, data2); } - static void set_crt1_FIFO2(unsigned long ROMAddr) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg1(P3c4, 0x15, SRegs[0x15]); + + set_reg4(0xcf8, 0x80000050); + set_reg4(0xcfc, 0xc5041e04); + + set_reg1(P3c4, 0x08, SRegs[0x08]); + set_reg1(P3c4, 0x0F, SRegs[0x0F]); + set_reg1(P3c4, 0x3b, 0x00); + set_reg1(P3c4, 0x09, SRegs[0x09]); +#else + u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1; u16 ah, bl, B; unsigned long eax; index = *((unsigned char *) (ROMAddr + REFIndex + 0x03)); + index &= 0x3F; CRT1VCLKLen = get_vclk_len(ROMAddr); data = index * CRT1VCLKLen; VCLKData = *((u16 *) (ROMAddr + 0x208)); @@ -2115,10 +2252,17 @@ data2 = data2 & 0xF0; data2 = data2 | data; set_reg1(P3c4, 0x09, data2); +#endif } static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg1(P3c4, 0x06, SRegs[0x06]); + set_reg1(P3c4, 0x01, SRegs[0x01]); + set_reg1(P3c4, 0x0F, SRegs[0x0F]); + set_reg1(P3c4, 0x21, SRegs[0x21]); +#else u16 data, data2, data3; @@ -2166,11 +2310,16 @@ else data = data | 0xA0; set_reg1(P3c4, 0x21, data); +#endif } - static void set_interlace(unsigned long ROMAddr, u16 ModeNo) { +#ifdef CONFIG_FB_SIS_LINUXBIOS + set_reg1(P3d4, 0x19, CRegs[0x19]); + set_reg1(P3d4, 0x1A, CRegs[0x1A]); +#else + unsigned long Temp; u16 data, Temp2; @@ -2201,6 +2350,7 @@ if (ModeNo == 0x37) Temp2 = Temp2 | 0x40; set_reg1(P3d4, 0x1A, (u16) Temp2); +#endif } static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh) @@ -2239,6 +2389,7 @@ u16 al, ah, dh; u16 *table = VGA_DAC; +#ifndef CONFIG_FB_SIS_LINUXBIOS data = *((u16 *) (ROMAddr + ModeIDOffset + 0x01)); data = data & DACInfoFlag; time = 64; @@ -2252,6 +2403,11 @@ time = 256; table = VGA_DAC; } +#else + time = 256; + table = VGA_DAC; +#endif + if (time == 256) j = 16; else @@ -2316,12 +2472,339 @@ set_reg1(P3c4, 0x01, data); } +void SetMemoryClock(void) +{ + unsigned char i; + int idx; + + u8 MCLK[] = { + 0x5A, 0x64, 0x80, 0x66, 0x00, // SDRAM + 0xB3, 0x45, 0x80, 0x83, 0x00, // SGRAM + 0x37, 0x61, 0x80, 0x00, 0x01, // ESDRAM + 0x37, 0x22, 0x80, 0x33, 0x01, + 0x37, 0x61, 0x80, 0x00, 0x01, + 0x37, 0x61, 0x80, 0x00, 0x01, + 0x37, 0x61, 0x80, 0x00, 0x01, + 0x37, 0x61, 0x80, 0x00, 0x01 + }; + + u8 ECLK[] = { + 0x54, 0x43, 0x80, 0x00, 0x01, + 0x53, 0x43, 0x80, 0x00, 0x01, + 0x55, 0x43, 0x80, 0x00, 0x01, + 0x52, 0x43, 0x80, 0x00, 0x01, + 0x3f, 0x42, 0x80, 0x00, 0x01, + 0x54, 0x43, 0x80, 0x00, 0x01, + 0x54, 0x43, 0x80, 0x00, 0x01, + 0x54, 0x43, 0x80, 0x00, 0x01 + }; + + idx = RAMType * 5; + + for (i = 0x28; i <= 0x2A; i++) { // Set MCLK + set_reg1(P3c4, i, MCLK[idx]); + idx++; + } + + idx = RAMType * 5; + for (i = 0x2E; i <= 0x30; i++) { // Set ECLK + set_reg1(P3c4, i, ECLK[idx]); + idx++; + } +} + +void ClearDAC(u16 port) +{ + int i; + + set_reg3(P3c8, 0x00); + for (i = 0; i < (256 * 3); i++) + set_reg3(P3c9, 0x00); +} + +void ClearALLBuffer(void) +{ + unsigned long AdapterMemorySize; + + AdapterMemorySize = get_reg1(P3c4, 0x14); + AdapterMemorySize = AdapterMemorySize & 0x3F; + AdapterMemorySize++; + + memset((char *) ivideo.video_vbase, 0, AdapterMemorySize); +} + +void LongWait(void) +{ + unsigned long temp; + + for (temp = 1; temp > 0;) { + temp = get_reg2(P3da); + temp = temp & 0x08; + } + for (; temp == 0;) { + temp = get_reg2(P3da); + temp = temp & 0x08; + } +} + +void WaitDisplay(void) +{ + unsigned short temp; + + for (temp = 0; temp == 0;) { + temp = get_reg2(P3da); + temp = temp & 0x01; + } + for (; temp == 1;) { + temp = get_reg2(P3da); + temp = temp & 0x01; + } +} + +int TestMonitorType(unsigned short d1, unsigned short d2, unsigned short d3) +{ + unsigned short temp; + set_reg3(P3c6, 0xFF); + set_reg3(P3c8, 0x00); + set_reg3(P3c9, d1); + set_reg3(P3c9, d2); + set_reg3(P3c9, d3); + WaitDisplay(); //wait horizontal retrace + temp = get_reg2(P3c2); + if (temp & 0x10) + return 1; + else + return 0; +} + +void SetRegANDOR(unsigned short Port, unsigned short Index, + unsigned short DataAND, unsigned short DataOR) +{ + unsigned short temp1; + temp1 = get_reg1(Port, Index); //part1port index 02 + temp1 = (temp1 & (DataAND)) | DataOR; + set_reg1(Port, Index, temp1); +} + + +int DetectMonitor(void) +{ + unsigned short flag1; + unsigned short DAC_TEST_PARMS[3] = { 0x0F, 0x0F, 0x0F }; + unsigned short DAC_CLR_PARMS[3] = { 0x00, 0x00, 0x00 }; + + flag1 = get_reg1(P3c4, 0x38); //call BridgeisOn + if ((flag1 & 0x20)) { + set_reg1(P3d4, 0x30, 0x41); + } + + SiSSetMode(0x2E); //set mode to 0x2E instead of 0x3 + + ClearDAC(P3c8); + ClearALLBuffer(); + + LongWait(); + LongWait(); + + flag1 = TestMonitorType(DAC_TEST_PARMS[0], DAC_TEST_PARMS[1], + DAC_TEST_PARMS[2]); + if (flag1 == 0) { + flag1 = TestMonitorType(DAC_TEST_PARMS[0], DAC_TEST_PARMS[1], + DAC_TEST_PARMS[2]); + } + + if (flag1 == 1) { + SetRegANDOR(P3d4, 0x32, ~Monitor1Sense, Monitor1Sense); + } else { + SetRegANDOR(P3d4, 0x32, ~Monitor1Sense, 0x0); + } + + TestMonitorType(DAC_CLR_PARMS[0], DAC_CLR_PARMS[1], + DAC_CLR_PARMS[2]); + + set_reg1(P3d4, 0x34, 0x4A); + + return 1; +} + +int SiSInit300(void) +{ + //unsigned long ROMAddr = rom_vbase; + u16 BaseAddr = (u16) ivideo.vga_base; + unsigned char i, temp, AGP; + unsigned long j, k, ulTemp; + unsigned char SR11, SR19, SR1A, SR21, SR22; + unsigned char SR14; + unsigned long Temp; + + P3c4 = BaseAddr + 0x14; + P3d4 = BaseAddr + 0x24; + P3c0 = BaseAddr + 0x10; + P3ce = BaseAddr + 0x1e; + P3c2 = BaseAddr + 0x12; + P3ca = BaseAddr + 0x1a; + P3c6 = BaseAddr + 0x16; + P3c7 = BaseAddr + 0x17; + P3c8 = BaseAddr + 0x18; + P3c9 = BaseAddr + 0x19; + P3da = BaseAddr + 0x2A; + + set_reg1(P3c4, 0x05, 0x86); // 1.Openkey + + SR14 = (unsigned char) get_reg1(P3c4, 0x14); + SR19 = (unsigned char) get_reg1(P3c4, 0x19); + SR1A = (unsigned char) get_reg1(P3c4, 0x1A); + + for (i = 0x06; i < 0x20; i++) + set_reg1(P3c4, i, 0); // 2.Reset Extended register + for (i = 0x21; i <= 0x27; i++) + set_reg1(P3c4, i, 0); // Reset Extended register + for (i = 0x31; i <= 0x3D; i++) + set_reg1(P3c4, i, 0); + for (i = 0x30; i <= 0x37; i++) + set_reg1(P3d4, i, 0); + +#if 0 + if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan)) + // 3.Set Define Extended register + temp = (unsigned char) SR1A; + else { + temp = *((unsigned char *) (ROMAddr + SoftSettingAddr)); + if ((temp & SoftDRAMType) == 0) { + // 3.Set Define Extended register + temp = (unsigned char) get_reg1(P3c4, 0x3A); + } + } +#endif + + // 3.Set Define Extended register + temp = (unsigned char) SR1A; + + RAMType = temp & 0x07; + SetMemoryClock(); + for (k = 0; k < 5; k++) + for (j = 0; j < 0xffff; j++) + ulTemp = (unsigned long) get_reg1(P3c4, 0x05); + + Temp = (unsigned long) get_reg1(P3c4, 0x3C); + Temp = Temp | 0x01; + set_reg1(P3c4, 0x3C, (unsigned short) Temp); + for (k = 0; k < 5; k++) + for (j = 0; j < 0xffff; j++) + Temp = (unsigned long) get_reg1(P3c4, 0x05); + + Temp = (unsigned long) get_reg1(P3c4, 0x3C); + Temp = Temp & 0xFE; + set_reg1(P3c4, 0x3C, (unsigned short) Temp); + for (k = 0; k < 5; k++) + for (j = 0; j < 0xffff; j++) + Temp = (unsigned long) get_reg1(P3c4, 0x05); + + //SR07=*((unsigned char *)(ROMAddr+0xA4)); // todo + set_reg1(P3c4, 0x07, SRegsInit[0x07]); +#if 0 + if (HwDeviceExtension->jChipID == SIS_Glamour) + for (i = 0x15; i <= 0x1C; i++) { + temp = *((unsigned char *) (ROMAddr + 0xA5 + ((i - 0x15) * 8) + RAMType)); + set_reg1(P3c4, i, temp); + } +#endif + + //SR1F=*((unsigned char *)(ROMAddr+0xE5)); + set_reg1(P3c4, 0x1F, SRegsInit[0x1F]); + + // Get AGP + AGP = 1; + temp = (unsigned char) get_reg1(P3c4, 0x3A); + temp = temp & 0x30; + if (temp == 0x30) + // PCI + AGP = 0; + + //SR21=*((unsigned char *)(ROMAddr+0xE6)); + SR21 = SRegsInit[0x21]; + if (AGP == 0) + SR21 = SR21 & 0xEF; // PCI + set_reg1(P3c4, 0x21, SR21); + + //SR22=*((unsigned char *)(ROMAddr+0xE7)); + SR22 = SRegsInit[0x22]; + if (AGP == 1) + SR22 = SR22 & 0x20; // AGP + set_reg1(P3c4, 0x22, SR22); + + //SR23=*((unsigned char *)(ROMAddr+0xE8)); + set_reg1(P3c4, 0x23, SRegsInit[0x23]); + + //SR24=*((unsigned char *)(ROMAddr+0xE9)); + set_reg1(P3c4, 0x24, SRegsInit[0x24]); + + //SR25=*((unsigned char *)(ROMAddr+0xEA)); + set_reg1(P3c4, 0x25, SRegsInit[0x25]); + + //SR32=*((unsigned char *)(ROMAddr+0xEB)); + set_reg1(P3c4, 0x32, SRegsInit[0x32]); + + SR11 = 0x0F; + set_reg1(P3c4, 0x11, SR11); + +#if 0 + if (IF_DEF_LVDS == 1) { + //LVDS + temp = ExtChipLVDS; + } else if (IF_DEF_TRUMPION == 1) { + //Trumpion + temp = ExtChipTrumpion; + } else { + //301 + temp = ExtChip301; + } +#endif + + // 301; + temp = 0x02; + set_reg1(P3d4, 0x37, temp); + +#if 0 + //09/07/99 modify by domao for 630/540 MM + if (HwDeviceExtension->jChipID == SIS_Glamour) { + //For SiS 300 Chip + SetDRAMSize(HwDeviceExtension); + SetDRAMSize(HwDeviceExtension); + } else { + //For SiS 630/540 Chip + //Restore SR14, SR19 and SR1A + set_reg1(P3c4, 0x14, SR14); + set_reg1(P3c4, 0x19, SR19); + set_reg1(P3c4, 0x1A, SR1A); + } +#endif + + set_reg1(P3c4, 0x14, SR14); + set_reg1(P3c4, 0x19, SR19); + set_reg1(P3c4, 0x1A, SR1A); + set_reg3(P3c6, 0xff); + ClearDAC(P3c8); + DetectMonitor(); + +#if 0 + //sense CRT2 + GetSenseStatus(HwDeviceExtension, BaseAddr, ROMAddr); +#endif + + return (TRUE); +} + static int SiSSetMode(u16 ModeNo) { + //#ifndef CONFIG_FB_SIS_LINUXBIOS unsigned long temp; + //#endif + u16 cr30flag, cr31flag; unsigned long ROMAddr = rom_vbase; u16 BaseAddr = (u16) ivideo.vga_base; + u_short i; P3c4 = BaseAddr + 0x14; P3d4 = BaseAddr + 0x24; @@ -2335,6 +2818,7 @@ P3c9 = BaseAddr + 0x19; P3da = BaseAddr + 0x2A; +#ifndef CONFIG_FB_SIS_LINUXBIOS temp = search_modeID(ROMAddr, ModeNo); if (temp == 0) @@ -2343,39 +2827,186 @@ temp = check_memory_size(ROMAddr); if (temp == 0) return (0); +#endif +#if 1 cr30flag = (unsigned char) get_reg1(P3d4, 0x30); if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) { +#ifndef CONFIG_FB_SIS_LINUXBIOS get_mode_ptr(ROMAddr, ModeNo); +#endif set_seq_regs(ROMAddr); set_misc_regs(ROMAddr); set_crtc_regs(ROMAddr); set_attregs(ROMAddr); set_grc_regs(ROMAddr); ClearExt1Regs(); + +#ifndef CONFIG_FB_SIS_LINUXBIOS temp = get_rate_ptr(ROMAddr, ModeNo); if (temp) { +#endif set_sync(ROMAddr); set_crt1_crtc(ROMAddr); set_crt1_offset(ROMAddr); set_crt1_vclk(ROMAddr); set_vclk_state(ROMAddr, ModeNo); - if ((ivideo.chip_id == SIS_Trojan) - || (ivideo.chip_id == SIS_Spartan)) + + if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan)) set_crt1_FIFO2(ROMAddr); else /* SiS 300 */ set_crt1_FIFO(ROMAddr); +#ifndef CONFIG_FB_SIS_LINUXBIOS } +#endif set_crt1_mode_regs(ROMAddr, ModeNo); + if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan)) + set_interlace(ROMAddr, ModeNo); + load_DAC(ROMAddr); + + /* clear OnScreen */ + memset((char *) ivideo.video_vbase, 0, + video_linelength * ivideo.video_height); + } +#else + cr30flag = (unsigned char) get_reg1(P3d4, 0x30); + if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) { + //set_seq_regs(ROMAddr); + { + unsigned char SRdata; + SRdata = SRegs[0x01] | 0x20; + set_reg1(P3c4, 0x01, SRdata); + + for (i = 02; i <= 04; i++) + set_reg1(P3c4, i, SRegs[i]); + } + + //set_misc_regs(ROMAddr); + { + set_reg3(P3c2, 0x23); + } + + //set_crtc_regs(ROMAddr); + { + unsigned char CRTCdata; + + CRTCdata = (unsigned char) get_reg1(P3d4, 0x11); + set_reg1(P3d4, 0x11, CRTCdata); + + for (i = 0; i <= 0x18; i++) + set_reg1(P3d4, i, CRegs[i]); + } + + //set_attregs(ROMAddr); + { + for (i = 0; i <= 0x13; i++) { + get_reg2(P3da); + set_reg3(P3c0, i); + set_reg3(P3c0, ARegs[i]); + } + get_reg2(P3da); + set_reg3(P3c0, 0x14); + set_reg3(P3c0, 0x00); + get_reg2(P3da); + set_reg3(P3c0, 0x20); + } + + //set_grc_regs(ROMAddr); + { + for (i = 0; i <= 0x08; i++) + set_reg1(P3ce, i, GRegs[i]); + } + + //ClearExt1Regs(); + { + for (i = 0x0A; i <= 0x0E; i++) + set_reg1(P3c4, i, 0x00); + } + + //set_sync(ROMAddr); + { + set_reg3(P3c2, MReg); + } + + //set_crt1_crtc(ROMAddr); + { + unsigned char data; + + data = (unsigned char) get_reg1(P3d4, 0x11); + data = data & 0x7F; + set_reg1(P3d4, 0x11, data); + + for (i = 0; i <= 0x07; i++) + set_reg1(P3d4, i, CRegs[i]); + for (i = 0x10; i <= 0x12; i++) + set_reg1(P3d4, i, CRegs[i]); + for (i = 0x15; i <= 0x16; i++) + set_reg1(P3d4, i, CRegs[i]); + for (i = 0x0A; i <= 0x0C; i++) + set_reg1(P3c4, i, SRegs[i]); + + data = SRegs[0x0E] & 0xE0; + set_reg1(P3c4, 0x0E, data); + + set_reg1(P3d4, 0x09, CRegs[0x09]); + + } + + //set_crt1_offset(ROMAddr); + { + set_reg1(P3c4, 0x0E, SRegs[0x0E]); + set_reg1(P3c4, 0x10, SRegs[0x10]); + } + + //set_crt1_vclk(ROMAddr); + { + set_reg1(P3c4, 0x31, 0); + + for (i = 0x2B; i <= 0x2C; i++) + set_reg1(P3c4, i, SRegs[i]); + set_reg1(P3c4, 0x2D, 0x80); + } + + //set_vclk_state(ROMAddr, ModeNo); + { + set_reg1(P3c4, 0x32, SRegs[0x32]); + set_reg1(P3c4, 0x07, SRegs[0x07]); + } + if ((ivideo.chip_id == SIS_Trojan) - || (ivideo.chip_id == - SIS_Spartan)) set_interlace(ROMAddr, ModeNo); + || (ivideo.chip_id == SIS_Spartan)) { + //set_crt1_FIFO2(ROMAddr); + set_reg1(P3c4, 0x15, SRegs[0x15]); + + set_reg4(0xcf8, 0x80000050); + set_reg4(0xcfc, 0xc5041e04); + + set_reg1(P3c4, 0x08, SRegs[0x08]); + set_reg1(P3c4, 0x0F, SRegs[0x0F]); + set_reg1(P3c4, 0x3b, 0x00); + set_reg1(P3c4, 0x09, SRegs[0x09]); + } + + //set_crt1_mode_regs(ROMAddr, ModeNo); + { + set_reg1(P3c4, 0x06, SRegs[0x06]); + set_reg1(P3c4, 0x01, SRegs[0x01]); + set_reg1(P3c4, 0x0F, SRegs[0x0F]); + set_reg1(P3c4, 0x21, SRegs[0x21]); + } + + if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan)) { + //set_interlace(ROMAddr, ModeNo); + set_reg1(P3d4, 0x19, CRegs[0x19]); + set_reg1(P3d4, 0x1A, CRegs[0x1A]); + } load_DAC(ROMAddr); /* clear OnScreen */ memset((char *) ivideo.video_vbase, 0, video_linelength * ivideo.video_height); } +#endif cr31flag = (unsigned char) get_reg1(P3d4, 0x31); display_on(); @@ -2508,8 +3139,7 @@ DPRINTK("sisfb: sisfb_get_var:[%d]\n", con); if (con == -1) - memcpy(var, &default_var, - sizeof(struct fb_var_screeninfo)); + memcpy(var, &default_var, sizeof(struct fb_var_screeninfo)); else *var = fb_display[con].var; return 0; @@ -2570,8 +3200,8 @@ else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else - fb_copy_cmap(fb_default_cmap(video_cmap_len), - cmap, kspc ? 0 : 2); + fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2); + return 0; } @@ -2602,12 +3232,12 @@ { switch (cmd) { case FBIO_ALLOC: - if(!capable(CAP_SYS_RAWIO)) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; sis_malloc((struct sis_memreq *) arg); break; case FBIO_FREE: - if(!capable(CAP_SYS_RAWIO)) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; sis_free(*(unsigned long *) arg); break; @@ -2668,9 +3298,9 @@ if (boot_cpu_data.x86 > 3) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; #endif - if (io_remap_page_range(vma->vm_start, off, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) return -EAGAIN; + if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; return 0; } @@ -2695,7 +3325,7 @@ if (!options || !*options) return 0; - for (this_opt = strtok(options, ","); this_opt; + for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) { if (!*this_opt) continue; @@ -2786,10 +3416,13 @@ int __init sisfb_init(void) { - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; struct board *b; int pdev_valid = 0; unsigned char jTemp; + u32 cmd; + + outb(0x77, 0x80); if (sisfb_off) return -ENXIO; @@ -2814,12 +3447,45 @@ if (!pdev_valid) return -1; - ivideo.video_base = pdev->resource[0].start & ~0x7FFFFF; - ivideo.mmio_base = pdev->resource[1].start & ~0x3FFF; - ivideo.vga_base = (pdev->resource[2].start & 0xFFFFFC) + 0x30; - rom_base = 0x000C0000; +#ifdef CONFIG_FB_SIS_LINUXBIOS + pci_read_config_dword(pdev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_IO; + cmd |= PCI_COMMAND_MEMORY; + pci_write_config_dword(pdev, PCI_COMMAND, cmd); +#endif + ivideo.video_base = pci_resource_start(pdev, 0); + if (!request_mem_region(ivideo.video_base, pci_resource_len(pdev, 0), + "sisfb FB")) { + printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n"); + return -ENODEV; + } + ivideo.mmio_base = pci_resource_start(pdev, 1); + if (!request_mem_region(ivideo.mmio_base, pci_resource_len(pdev, 1), + "sisfb MMIO")) { + printk(KERN_ERR "sisfb: cannot reserve MMIO region\n"); + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + return -ENODEV; + } + ivideo.vga_base = pci_resource_start(pdev, 2); + if (!request_region(ivideo.vga_base, pci_resource_len(pdev, 2), + "sisfb IO")) { + printk(KERN_ERR "sisfb: cannot reserve I/O ports\n"); + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + return -ENODEV; + } + ivideo.vga_base += 0x30; + +#ifndef CONFIG_FB_SIS_LINUXBIOS + rom_base = 0x000C0000; request_region(rom_base, 32, "sisfb"); +#else + rom_base = 0x0; +#endif /* set passwd */ vgawb(SEQ_ADR, IND_SIS_PASSWORD); @@ -2839,13 +3505,21 @@ if (mode_idx < 0) mode_idx = DEFAULT_MODE; /* 0:640x480x8 */ +#ifdef CONFIG_FB_SIS_LINUXBIOS + mode_idx = DEFAULT_MODE; + rate_idx = sisbios_mode[mode_idx].rate_idx; + /* set to default refresh rate 60MHz */ + ivideo.refresh_rate = 60; +#endif + mode_no = sisbios_mode[mode_idx].mode_no; if (ivideo.refresh_rate != 0) search_refresh_rate(ivideo.refresh_rate); if (rate_idx == 0) { - rate_idx = sisbios_mode[mode_idx].rate_idx; /* set to default refresh rate 60MHz */ + rate_idx = sisbios_mode[mode_idx].rate_idx; + /* set to default refresh rate 60MHz */ ivideo.refresh_rate = 60; } @@ -2854,25 +3528,14 @@ ivideo.video_height = sisbios_mode[mode_idx].yres; video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3); - if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) - { - printk(KERN_ERR - "sisfb: abort, cannot reserve video memory at 0x%lx\n", - ivideo.video_base); - return -1; - } - - if (!request_mem_region(ivideo.mmio_base, MMIO_SIZE, "sisfb MMIO")) - { - printk(KERN_ERR - "sisfb: abort, cannot reserve mmio memory at 0x%lx\n", - ivideo.mmio_base); - return -1; - } - ivideo.video_vbase = ioremap(ivideo.video_base, ivideo.video_size); ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE); + +#ifndef CONFIG_FB_SIS_LINUXBIOS rom_vbase = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN); +#endif + + SiSInit300(); printk(KERN_INFO "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", diff -u --recursive --new-file v2.4.0-test7/linux/fs/Makefile linux/fs/Makefile --- v2.4.0-test7/linux/fs/Makefile Wed Aug 9 19:19:51 2000 +++ linux/fs/Makefile Mon Aug 28 21:27:39 2000 @@ -11,9 +11,10 @@ O_TARGET := fs.o O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ - ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ + ioctl.o readdir.o select.o fifo.o locks.o \ dcache.o inode.o attr.o bad_inode.o file.o iobuf.o \ $(BINFMTS) $(FILESYSTEMS) +OX_OBJS := filesystems.o ALL_SUB_DIRS := coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \ diff -u --recursive --new-file v2.4.0-test7/linux/fs/adfs/dir_f.c linux/fs/adfs/dir_f.c --- v2.4.0-test7/linux/fs/adfs/dir_f.c Fri Jun 23 21:55:10 2000 +++ linux/fs/adfs/dir_f.c Tue Sep 5 14:07:29 2000 @@ -437,7 +437,7 @@ } #endif for (i = dir->nr_buffers - 1; i >= 0; i--) - mark_buffer_dirty(dir->bh[i], 1); + mark_buffer_dirty(dir->bh[i]); ret = 0; out: diff -u --recursive --new-file v2.4.0-test7/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c --- v2.4.0-test7/linux/fs/affs/amigaffs.c Wed Jun 24 14:30:09 1998 +++ linux/fs/affs/amigaffs.c Tue Sep 5 14:07:29 2000 @@ -79,7 +79,7 @@ DIR_END(file->b_data,inode)->hash_chain = cpu_to_be32(next); ((s32 *)bh->b_data)[offset] = cpu_to_be32(ino); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); affs_brelse(bh); return 0; @@ -130,7 +130,7 @@ if (ownkey == key) { ((s32 *)bh->b_data)[offset] = FILE_END(dbh->b_data,inode)->hash_chain; affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); affs_brelse(bh); retval = 0; break; @@ -178,7 +178,7 @@ FILE_END(bh->b_data,inode)->link_chain = FILE_END(dbh->b_data,inode)->link_chain; affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); affs_brelse(bh); retval = 0; break; @@ -261,7 +261,7 @@ return error; } affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); affs_brelse(link_bh); affs_free_block(inode->i_sb,link_ino); /* Mark the link's parent dir as changed, too. */ diff -u --recursive --new-file v2.4.0-test7/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c --- v2.4.0-test7/linux/fs/affs/bitmap.c Wed Apr 26 16:34:08 2000 +++ linux/fs/affs/bitmap.c Tue Sep 5 14:07:29 2000 @@ -93,7 +93,7 @@ else { sb->u.affs_sb.s_alloc[zone_no].az_free++; ((u32 *)bm->bm_bh->b_data)[0] = cpu_to_be32(be32_to_cpu(((u32 *)bm->bm_bh->b_data)[0]) - blk); - mark_buffer_dirty(bm->bm_bh,1); + mark_buffer_dirty(bm->bm_bh); sb->s_dirt = 1; } if (--bm->bm_count == 0) { @@ -176,7 +176,7 @@ w = ~w - be32_to_cpu(bm[i]); bm[0] = cpu_to_be32(be32_to_cpu(bm[0]) + w); unlock_super(sb); - mark_buffer_dirty(zone->z_bm->bm_bh,1); + mark_buffer_dirty(zone->z_bm->bm_bh); sb->s_dirt = 1; zone->z_lru_time = jiffies; diff -u --recursive --new-file v2.4.0-test7/linux/fs/affs/file.c linux/fs/affs/file.c --- v2.4.0-test7/linux/fs/affs/file.c Thu May 11 15:30:08 2000 +++ linux/fs/affs/file.c Tue Sep 5 14:07:29 2000 @@ -447,12 +447,12 @@ DATA_FRONT(ebh)->header_key = cpu_to_be32(inode->i_ino); DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1); affs_fix_checksum(AFFS_I2BSIZE(inode), ebh->b_data, 5); - mark_buffer_dirty(ebh, 0); + mark_buffer_dirty(ebh); if (pbh) { DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24); DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey); affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5); - mark_buffer_dirty(pbh,0); + mark_buffer_dirty(pbh); affs_brelse(pbh); } pbh = ebh; @@ -466,7 +466,7 @@ fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0); fdp->block_count = cpu_to_be32(j); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); } if (block < j) { @@ -495,10 +495,10 @@ FILE_END(ebh->b_data,inode)->secondary_type = cpu_to_be32(ST_FILE); FILE_END(ebh->b_data,inode)->parent = cpu_to_be32(inode->i_ino); affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5); - mark_buffer_dirty(ebh, 1); + mark_buffer_dirty(ebh); FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); affs_brelse(bh); bh = ebh; } @@ -678,7 +678,7 @@ rem = do_div(tmp, net_blocksize); DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize); affs_fix_checksum(blocksize,bh->b_data,5); - mark_buffer_dirty(bh,0); + mark_buffer_dirty(bh); } goto out_truncate; } @@ -733,7 +733,7 @@ first = 0; *keyp = 0; affs_fix_checksum(blocksize,bh->b_data,5); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); } else first -= AFFS_I2HSIZE(inode); affs_brelse(bh); @@ -766,7 +766,7 @@ ((struct data_front *)bh->b_data)->next_data = 0; affs_fix_checksum(blocksize,bh->b_data,5); } - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); } else affs_error(inode->i_sb,"truncate","Cannot read block %d",block); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v2.4.0-test7/linux/fs/affs/inode.c Mon Jul 10 16:47:25 2000 +++ linux/fs/affs/inode.c Tue Sep 5 14:07:29 2000 @@ -232,7 +232,7 @@ } } affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); brelse(bh); unlock_kernel(); } @@ -392,7 +392,7 @@ affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5); link->i_version = ++event; mark_inode_dirty(link); - mark_buffer_dirty(link_bh,1); + mark_buffer_dirty(link_bh); } affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5); affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5); @@ -402,8 +402,8 @@ mark_inode_dirty(dir); mark_inode_dirty(inode); - mark_buffer_dirty(dir_bh,1); - mark_buffer_dirty(inode_bh,1); + mark_buffer_dirty(dir_bh); + mark_buffer_dirty(inode_bh); addentry_done: affs_brelse(dir_bh); diff -u --recursive --new-file v2.4.0-test7/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v2.4.0-test7/linux/fs/affs/namei.c Fri Jun 23 21:55:10 2000 +++ linux/fs/affs/namei.c Tue Sep 5 14:07:29 2000 @@ -440,7 +440,7 @@ symname++; } *p = 0; - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); affs_brelse(bh); mark_inode_dirty(inode); @@ -592,7 +592,7 @@ retval = 0; mark_inode_dirty(new_dir); mark_inode_dirty(old_dir); - mark_buffer_dirty(old_bh,1); + mark_buffer_dirty(old_bh); end_rename: affs_brelse(old_bh); diff -u --recursive --new-file v2.4.0-test7/linux/fs/affs/super.c linux/fs/affs/super.c --- v2.4.0-test7/linux/fs/affs/super.c Tue Mar 14 19:10:40 2000 +++ linux/fs/affs/super.c Tue Sep 5 14:07:29 2000 @@ -52,7 +52,7 @@ secs_to_datestamp(CURRENT_TIME, &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + mark_buffer_dirty(sb->u.affs_sb.s_root_bh); } if (sb->u.affs_sb.s_prefix) @@ -88,7 +88,7 @@ secs_to_datestamp(CURRENT_TIME, &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + mark_buffer_dirty(sb->u.affs_sb.s_root_bh); sb->s_dirt = !clean; /* redo until bitmap synced */ } else sb->s_dirt = 0; @@ -491,7 +491,7 @@ chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key)); ((u32 *)bb->b_data)[ptype] &= chksum; affs_fix_checksum(s->s_blocksize,bb->b_data,0); - mark_buffer_dirty(bb,1); + mark_buffer_dirty(bb); bmalt = 1; } ptype = (size + 31) & ~0x1F; @@ -553,7 +553,7 @@ secs_to_datestamp(CURRENT_TIME,&ROOT_END( s->u.affs_sb.s_root_bh->b_data,root_inode)->disk_altered); affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(s->u.affs_sb.s_root_bh,1); + mark_buffer_dirty(s->u.affs_sb.s_root_bh); } affs_make_zones(s); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c --- v2.4.0-test7/linux/fs/autofs/waitq.c Tue May 11 14:57:04 1999 +++ linux/fs/autofs/waitq.c Fri Sep 1 14:35:04 2000 @@ -53,7 +53,7 @@ /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/ - sigpipe = sigismember(¤t->signal, SIGPIPE); + sigpipe = sigismember(¤t->pending.signal, SIGPIPE); /* Save pointer to user space and point back to kernel space */ fs = get_fs(); @@ -71,7 +71,7 @@ SIGPIPE unless it was already supposed to get one */ if (wr == -EPIPE && !sigpipe) { spin_lock_irqsave(¤t->sigmask_lock, flags); - sigdelset(¤t->signal, SIGPIPE); + sigdelset(¤t->pending.signal, SIGPIPE); recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/autofs4/waitq.c linux/fs/autofs4/waitq.c --- v2.4.0-test7/linux/fs/autofs4/waitq.c Wed Apr 26 16:34:09 2000 +++ linux/fs/autofs4/waitq.c Fri Sep 1 14:35:16 2000 @@ -57,7 +57,7 @@ /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/ - sigpipe = sigismember(¤t->signal, SIGPIPE); + sigpipe = sigismember(¤t->pending.signal, SIGPIPE); /* Save pointer to user space and point back to kernel space */ fs = get_fs(); @@ -75,7 +75,7 @@ SIGPIPE unless it was already supposed to get one */ if (wr == -EPIPE && !sigpipe) { spin_lock_irqsave(¤t->sigmask_lock, flags); - sigdelset(¤t->signal, SIGPIPE); + sigdelset(¤t->pending.signal, SIGPIPE); recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/bfs/dir.c linux/fs/bfs/dir.c --- v2.4.0-test7/linux/fs/bfs/dir.c Wed Aug 23 18:36:38 2000 +++ linux/fs/bfs/dir.c Tue Sep 5 14:07:29 2000 @@ -177,7 +177,7 @@ } de->ino = 0; dir->i_version = ++event; - mark_buffer_dirty(bh, 0); + mark_buffer_dirty(bh); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); inode->i_nlink--; @@ -236,7 +236,7 @@ new_inode->i_ctime = CURRENT_TIME; mark_inode_dirty(new_inode); } - mark_buffer_dirty(old_bh, 0); + mark_buffer_dirty(old_bh); error = 0; end_rename: @@ -288,7 +288,7 @@ de->ino = ino; for (i=0; iname[i] = (i < namelen) ? name[i] : 0; - mark_buffer_dirty(bh, 0); + mark_buffer_dirty(bh); brelse(bh); return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/fs/bfs/file.c linux/fs/bfs/file.c --- v2.4.0-test7/linux/fs/bfs/file.c Thu May 11 15:30:08 2000 +++ linux/fs/bfs/file.c Tue Sep 5 14:07:29 2000 @@ -33,7 +33,7 @@ return -EIO; new = getblk(dev, to, BFS_BSIZE); memcpy(new->b_data, bh->b_data, bh->b_size); - mark_buffer_dirty(new, 0); + mark_buffer_dirty(new); bforget(bh); brelse(new); return 0; @@ -98,7 +98,7 @@ bh_result->b_state |= (1UL << BH_Mapped); s->su_lf_eblk = inode->iu_eblock = inode->iu_sblock + block; mark_inode_dirty(inode); - mark_buffer_dirty(s->su_sbh, 1); + mark_buffer_dirty(s->su_sbh); err = 0; goto out; } @@ -118,7 +118,7 @@ inode->iu_sblock = next_free_block; s->su_lf_eblk = inode->iu_eblock = next_free_block + block; mark_inode_dirty(inode); - mark_buffer_dirty(s->su_sbh, 1); + mark_buffer_dirty(s->su_sbh); bh_result->b_dev = inode->i_dev; bh_result->b_blocknr = inode->iu_sblock + block; bh_result->b_state |= (1UL << BH_Mapped); diff -u --recursive --new-file v2.4.0-test7/linux/fs/bfs/inode.c linux/fs/bfs/inode.c --- v2.4.0-test7/linux/fs/bfs/inode.c Mon Jul 10 16:47:25 2000 +++ linux/fs/bfs/inode.c Tue Sep 5 14:07:29 2000 @@ -127,7 +127,7 @@ di->i_eblock = inode->iu_eblock; di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1; - mark_buffer_dirty(bh, 0); + mark_buffer_dirty(bh); brelse(bh); unlock_kernel(); } @@ -169,7 +169,7 @@ } di->i_ino = 0; di->i_sblock = 0; - mark_buffer_dirty(bh, 0); + mark_buffer_dirty(bh); brelse(bh); /* if this was the last file, make the previous @@ -177,7 +177,7 @@ saves us 1 gap */ if (s->su_lf_eblk == inode->iu_eblock) { s->su_lf_eblk = inode->iu_sblock - 1; - mark_buffer_dirty(s->su_sbh, 1); + mark_buffer_dirty(s->su_sbh); } unlock_kernel(); clear_inode(inode); @@ -205,7 +205,7 @@ static void bfs_write_super(struct super_block *s) { if (!(s->s_flags & MS_RDONLY)) - mark_buffer_dirty(s->su_sbh, 1); + mark_buffer_dirty(s->su_sbh); s->s_dirt = 0; } @@ -314,7 +314,7 @@ iput(inode); } if (!(s->s_flags & MS_RDONLY)) { - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); s->s_dirt = 1; } dump_imap("read_super", s); diff -u --recursive --new-file v2.4.0-test7/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.4.0-test7/linux/fs/binfmt_elf.c Wed Aug 9 19:19:51 2000 +++ linux/fs/binfmt_elf.c Fri Sep 1 14:37:15 2000 @@ -1045,7 +1045,7 @@ notes[0].datasz = sizeof(prstatus); notes[0].data = &prstatus; prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; - prstatus.pr_sigpend = current->signal.sig[0]; + prstatus.pr_sigpend = current->pending.signal.sig[0]; prstatus.pr_sighold = current->blocked.sig[0]; psinfo.pr_pid = prstatus.pr_pid = current->pid; psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; diff -u --recursive --new-file v2.4.0-test7/linux/fs/block_dev.c linux/fs/block_dev.c --- v2.4.0-test7/linux/fs/block_dev.c Wed Aug 23 18:36:38 2000 +++ linux/fs/block_dev.c Tue Sep 5 14:07:31 2000 @@ -129,7 +129,7 @@ p += chars; buf += chars; mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 0); + mark_buffer_dirty(bh); if (filp->f_flags & O_SYNC) bufferlist[buffercount++] = bh; else diff -u --recursive --new-file v2.4.0-test7/linux/fs/buffer.c linux/fs/buffer.c --- v2.4.0-test7/linux/fs/buffer.c Wed Aug 23 18:36:38 2000 +++ linux/fs/buffer.c Wed Sep 6 08:29:45 2000 @@ -892,7 +892,7 @@ wakeup_bdflush(state); } -static __inline__ void __mark_dirty(struct buffer_head *bh, int flag) +static __inline__ void __mark_dirty(struct buffer_head *bh) { bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer; refile_buffer(bh); @@ -900,15 +900,15 @@ /* atomic version, the user must call balance_dirty() by hand as soon as it become possible to block */ -void __mark_buffer_dirty(struct buffer_head *bh, int flag) +void __mark_buffer_dirty(struct buffer_head *bh) { if (!atomic_set_buffer_dirty(bh)) - __mark_dirty(bh, flag); + __mark_dirty(bh); } -void mark_buffer_dirty(struct buffer_head *bh, int flag) +void mark_buffer_dirty(struct buffer_head *bh) { - __mark_buffer_dirty(bh, flag); + __mark_buffer_dirty(bh); balance_dirty(bh->b_dev); } @@ -1419,7 +1419,7 @@ } set_bit(BH_Uptodate, &bh->b_state); if (!atomic_set_buffer_dirty(bh)) { - __mark_dirty(bh, 0); + __mark_dirty(bh); need_balance_dirty = 1; } @@ -1520,7 +1520,7 @@ } else { set_bit(BH_Uptodate, &bh->b_state); if (!atomic_set_buffer_dirty(bh)) { - __mark_dirty(bh, 0); + __mark_dirty(bh); need_balance_dirty = 1; } } @@ -1721,6 +1721,72 @@ return 0; } +int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t *get_block) +{ + unsigned long index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_CACHE_SIZE-1); + unsigned blocksize, iblock, length, pos; + struct inode *inode = (struct inode *)mapping->host; + struct page *page; + struct buffer_head *bh; + int err; + + blocksize = inode->i_sb->s_blocksize; + length = offset & (blocksize - 1); + + /* Block boundary? Nothing to do */ + if (!length) + return 0; + + length = blocksize - length; + iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); + + page = grab_cache_page(mapping, index); + err = PTR_ERR(page); + if (IS_ERR(page)) + goto out; + + if (!page->buffers) + create_empty_buffers(page, inode, blocksize); + + /* Find the buffer that contains "offset" */ + bh = page->buffers; + pos = blocksize; + while (offset >= pos) { + bh = bh->b_this_page; + iblock++; + pos += blocksize; + } + + if (!buffer_uptodate(bh)) { + err = 0; + if (!buffer_mapped(bh)) { + get_block(inode, iblock, bh, 0); + if (!buffer_mapped(bh)) + goto unlock; + } + err = -EIO; + bh->b_end_io = end_buffer_io_sync; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) + goto unlock; + } + + memset((char *) kmap(page) + offset, 0, length); + flush_dcache_page(page); + kunmap(page); + + mark_buffer_dirty(bh); + err = 0; + +unlock: + UnlockPage(page); + page_cache_release(page); +out: + return err; +} + int block_write_full_page(struct page *page, get_block_t *get_block) { struct inode *inode = (struct inode*)page->mapping->host; @@ -2606,8 +2672,8 @@ if (signal_pending(tsk)) { int stopped = 0; spin_lock_irq(&tsk->sigmask_lock); - if (sigismember(&tsk->signal, SIGSTOP)) { - sigdelset(&tsk->signal, SIGSTOP); + if (sigismember(&tsk->pending.signal, SIGSTOP)) { + sigdelset(&tsk->pending.signal, SIGSTOP); stopped = 1; } recalc_sigpending(tsk); @@ -2625,9 +2691,9 @@ static int __init bdflush_init(void) { DECLARE_MUTEX_LOCKED(sem); - kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); down(&sem); - kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); down(&sem); return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/fs/coda/upcall.c linux/fs/coda/upcall.c --- v2.4.0-test7/linux/fs/coda/upcall.c Mon Jul 10 16:47:25 2000 +++ linux/fs/coda/upcall.c Sun Sep 3 11:46:40 2000 @@ -634,8 +634,8 @@ if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) { /* if this process really wants to die, let it go */ - if ( sigismember(&(current->signal), SIGKILL) || - sigismember(&(current->signal), SIGINT) ) + if ( sigismember(&(current->pending.signal), SIGKILL) || + sigismember(&(current->pending.signal), SIGINT) ) break; /* signal is present: after timeout always return really smart idea, probably useless ... */ diff -u --recursive --new-file v2.4.0-test7/linux/fs/dquot.c linux/fs/dquot.c --- v2.4.0-test7/linux/fs/dquot.c Thu Jul 27 17:38:01 2000 +++ linux/fs/dquot.c Tue Sep 5 13:59:18 2000 @@ -1214,14 +1214,6 @@ lock_kernel(); /* - * Find out if this filesystem uses i_blocks. - */ - if (!inode->i_sb->s_blocksize) - blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS); - else - blocks = (inode->i_blocks >> 1); - - /* * Build the transfer_from and transfer_to lists and check quotas to see * if operation is permitted. */ @@ -1280,13 +1272,25 @@ * dqget() could block and so the first structure might got * invalidated or locked... */ - if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb || - check_idq(transfer_to[cnt], 1) == NO_QUOTA || - check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) { + if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb) { cnt++; goto put_all; } } + + /* + * Find out if this filesystem uses i_blocks. + */ + if (!inode->i_sb->s_blocksize) + blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS); + else + blocks = (inode->i_blocks >> 1); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (check_idq(transfer_to[cnt], 1) == NO_QUOTA || + check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) { + cnt = MAXQUOTAS; + goto put_all; + } if ((error = notify_change(dentry, iattr))) goto put_all; diff -u --recursive --new-file v2.4.0-test7/linux/fs/exec.c linux/fs/exec.c --- v2.4.0-test7/linux/fs/exec.c Wed Aug 23 18:36:38 2000 +++ linux/fs/exec.c Sun Sep 3 22:49:25 2000 @@ -427,7 +427,7 @@ * This function makes sure the current process has its own signal table, * so that flush_signal_handlers can later reset the handlers without * disturbing other processes. (Other processes might share the signal - * table via the CLONE_SIGHAND option to clone().) + * table via the CLONE_SIGNAL option to clone().) */ static inline int make_private_signals(void) @@ -496,6 +496,27 @@ write_unlock(&files->file_lock); } +/* + * An execve() will automatically "de-thread" the process. + * Note: we don't have to hold the tasklist_lock to test + * whether we migth need to do this. If we're not part of + * a thread group, there is no way we can become one + * dynamically. And if we are, we only need to protect the + * unlink - even if we race with the last other thread exit, + * at worst the list_del_init() might end up being a no-op. + */ +static inline void de_thread(struct task_struct *tsk) +{ + if (!list_empty(&tsk->thread_group)) { + write_lock_irq(&tasklist_lock); + list_del_init(&tsk->thread_group); + write_unlock_irq(&tasklist_lock); + } + + /* Minor oddity: this might stay the same. */ + tsk->tgid = tsk->pid; +} + int flush_old_exec(struct linux_binprm * bprm) { char * name; @@ -533,6 +554,8 @@ current->comm[i] = '\0'; flush_thread(); + + de_thread(current); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->file->f_dentry->d_inode,MAY_READ)) diff -u --recursive --new-file v2.4.0-test7/linux/fs/ext2/Makefile linux/fs/ext2/Makefile --- v2.4.0-test7/linux/fs/ext2/Makefile Sun Sep 22 22:38:18 1996 +++ linux/fs/ext2/Makefile Sat Sep 2 11:24:57 2000 @@ -9,7 +9,7 @@ O_TARGET := ext2.o O_OBJS := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o truncate.o + ioctl.o namei.o super.o symlink.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test7/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.4.0-test7/linux/fs/ext2/balloc.c Wed Aug 9 19:19:51 2000 +++ linux/fs/ext2/balloc.c Tue Sep 5 14:07:29 2000 @@ -325,10 +325,10 @@ } } - mark_buffer_dirty(bh2, 1); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(bh2); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -582,7 +582,7 @@ j = tmp; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -600,9 +600,9 @@ "Goal hits %d of %d.\n", j, goal_hits, goal_attempts); gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); - mark_buffer_dirty(bh2, 1); + mark_buffer_dirty(bh2); es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); sb->s_dirt = 1; unlock_super (sb); *err = 0; diff -u --recursive --new-file v2.4.0-test7/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v2.4.0-test7/linux/fs/ext2/ialloc.c Wed Aug 9 19:19:51 2000 +++ linux/fs/ext2/ialloc.c Tue Sep 5 14:07:29 2000 @@ -230,12 +230,12 @@ gdp->bg_used_dirs_count = cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1); } - mark_buffer_dirty(bh2, 1); + mark_buffer_dirty(bh2); es->s_free_inodes_count = cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -388,7 +388,7 @@ "bit already set for inode %d", j); goto repeat; } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -398,9 +398,13 @@ ext2_error (sb, "ext2_new_inode", "Free inodes count corrupted in group %d", i); - unlock_super (sb); - iput (inode); - return NULL; + if (sb->s_flags & MS_RDONLY) { + unlock_super (sb); + iput (inode); + return NULL; + } + gdp->bg_free_inodes_count = 0; + mark_buffer_dirty(bh2); } goto repeat; } @@ -411,6 +415,7 @@ "block_group = %d,inode=%d", i, j); unlock_super (sb); iput (inode); + *err = -EIO; return NULL; } gdp->bg_free_inodes_count = @@ -418,10 +423,10 @@ if (S_ISDIR(mode)) gdp->bg_used_dirs_count = cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); - mark_buffer_dirty(bh2, 1); + mark_buffer_dirty(bh2); es->s_free_inodes_count = cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); sb->s_dirt = 1; inode->i_mode = mode; inode->i_sb = sb; diff -u --recursive --new-file v2.4.0-test7/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.4.0-test7/linux/fs/ext2/inode.c Wed Aug 9 19:19:51 2000 +++ linux/fs/ext2/inode.c Tue Sep 5 19:01:29 2000 @@ -245,47 +245,17 @@ add_chain (chain, NULL, inode->u.ext2_i.i_data + *offsets); if (!p->key) goto no_block; - /* - * switch below is merely an unrolled loop - body should be - * repeated depth-1 times. Maybe loop would be actually better, - * but that way we get straight execution path in normal cases. - * Easy to change, anyway - all cases in switch are literally - * identical. - */ - switch (depth) { - case 4: - bh = bread(dev, le32_to_cpu(p->key), size); - if (!bh) - goto failure; - /* Reader: pointers */ - if (!verify_chain(chain, p)) - goto changed; - add_chain(++p, bh, (u32*)bh->b_data + *++offsets); - /* Reader: end */ - if (!p->key) - goto no_block; - case 3: - bh = bread(dev, le32_to_cpu(p->key), size); - if (!bh) - goto failure; - /* Reader: pointers */ - if (!verify_chain(chain, p)) - goto changed; - add_chain(++p, bh, (u32*)bh->b_data + *++offsets); - /* Reader: end */ - if (!p->key) - goto no_block; - case 2: - bh = bread(dev, le32_to_cpu(p->key), size); - if (!bh) - goto failure; - /* Reader: pointers */ - if (!verify_chain(chain, p)) - goto changed; - add_chain(++p, bh, (u32*)bh->b_data + *++offsets); - /* Reader: end */ - if (!p->key) - goto no_block; + while (--depth) { + bh = bread(dev, le32_to_cpu(p->key), size); + if (!bh) + goto failure; + /* Reader: pointers */ + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (u32*)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; } return NULL; @@ -433,7 +403,7 @@ branch[n].p = (u32*) bh->b_data + offsets[n]; *branch[n].p = branch[n].key; mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -498,7 +468,7 @@ /* had we spliced it onto indirect block? */ if (where->bh) { - mark_buffer_dirty(where->bh, 1); + mark_buffer_dirty(where->bh); if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) { ll_rw_block (WRITE, 1, &where->bh); wait_on_buffer(where->bh); @@ -620,7 +590,7 @@ wait_on_buffer(bh); memset(bh->b_data, 0, inode->i_sb->s_blocksize); mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } return bh; } @@ -704,6 +674,289 @@ bmap: ext2_bmap }; +/* + * Probably it should be a library function... search for first non-zero word + * or memcmp with zero_page, whatever is better for particular architecture. + * Linus? + */ +static inline int all_zeroes(u32 *p, u32 *q) +{ + while (p < q) + if (*p++) + return 0; + return 1; +} + +/** + * ext2_find_shared - find the indirect blocks for partial truncation. + * @inode: inode in question + * @depth: depth of the affected branch + * @offsets: offsets of pointers in that branch (see ext2_block_to_path) + * @chain: place to store the pointers to partial indirect blocks + * @top: place to the (detached) top of branch + * + * This is a helper function used by ext2_truncate(). + * + * When we do truncate() we may have to clean the ends of several indirect + * blocks but leave the blocks themselves alive. Block is partially + * truncated if some data below the new i_size is refered from it (and + * it is on the path to the first completely truncated data block, indeed). + * We have to free the top of that path along with everything to the right + * of the path. Since no allocation past the truncation point is possible + * until ext2_truncate() finishes, we may safely do the latter, but top + * of branch may require special attention - pageout below the truncation + * point might try to populate it. + * + * We atomically detach the top of branch from the tree, store the block + * number of its root in *@top, pointers to buffer_heads of partially + * truncated blocks - in @chain[].bh and pointers to their last elements + * that should not be removed - in @chain[].p. Return value is the pointer + * to last filled element of @chain. + * + * The work left to caller to do the actual freeing of subtrees: + * a) free the subtree starting from *@top + * b) free the subtrees whose roots are stored in + * (@chain[i].p+1 .. end of @chain[i].bh->b_data) + * c) free the subtrees growing from the inode past the @chain[0].p + * (no partially truncated stuff there). + */ + +static Indirect *ext2_find_shared(struct inode *inode, + int depth, + int offsets[4], + Indirect chain[4], + u32 *top) +{ + Indirect *partial, *p; + int k, err; + + *top = 0; + for (k = depth; k > 1 && !offsets[k-1]; k--) + ; + partial = ext2_get_branch(inode, k, offsets, chain, &err); + /* Writer: pointers */ + if (!partial) + partial = chain + k-1; + /* + * If the branch acquired continuation since we've looked at it - + * fine, it should all survive and (new) top doesn't belong to us. + */ + if (!partial->key && *partial->p) + /* Writer: end */ + goto no_top; + for (p=partial; p>chain && all_zeroes((u32*)p->bh->b_data,p->p); p--) + ; + /* + * OK, we've found the last block that must survive. The rest of our + * branch should be detached before unlocking. However, if that rest + * of branch is all ours and does not grow immediately from the inode + * it's easier to cheat and just decrement partial->p. + */ + if (p == chain + k - 1 && p > chain) { + p->p--; + } else { + *top = *p->p; + *p->p = 0; + } + /* Writer: end */ + + while(partial > p) + { + brelse(partial->bh); + partial--; + } +no_top: + return partial; +} + +/** + * ext2_free_data - free a list of data blocks + * @inode: inode we are dealing with + * @p: array of block numbers + * @q: points immediately past the end of array + * + * We are freeing all blocks refered from that array (numbers are + * stored as little-endian 32-bit) and updating @inode->i_blocks + * appropriately. + */ +static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q) +{ + int blocks = inode->i_sb->s_blocksize / 512; + unsigned long block_to_free = 0, count = 0; + unsigned long nr; + + for ( ; p < q ; p++) { + nr = le32_to_cpu(*p); + if (nr) { + *p = 0; + /* accumulate blocks to free if they're contiguous */ + if (count == 0) + goto free_this; + else if (block_to_free == nr - count) + count++; + else { + /* Writer: ->i_blocks */ + inode->i_blocks -= blocks * count; + /* Writer: end */ + ext2_free_blocks (inode, block_to_free, count); + mark_inode_dirty(inode); + free_this: + block_to_free = nr; + count = 1; + } + } + } + if (count > 0) { + /* Writer: ->i_blocks */ + inode->i_blocks -= blocks * count; + /* Writer: end */ + ext2_free_blocks (inode, block_to_free, count); + mark_inode_dirty(inode); + } +} + +/** + * ext2_free_branches - free an array of branches + * @inode: inode we are dealing with + * @p: array of block numbers + * @q: pointer immediately past the end of array + * @depth: depth of the branches to free + * + * We are freeing all blocks refered from these branches (numbers are + * stored as little-endian 32-bit) and updating @inode->i_blocks + * appropriately. + */ +static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth) +{ + struct buffer_head * bh; + unsigned long nr; + + if (depth--) { + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + for ( ; p < q ; p++) { + nr = le32_to_cpu(*p); + if (!nr) + continue; + *p = 0; + bh = bread (inode->i_dev, nr, inode->i_sb->s_blocksize); + /* + * A read failure? Report error and clear slot + * (should be rare). + */ + if (!bh) { + ext2_error(inode->i_sb, "ext2_free_branches", + "Read failure, inode=%ld, block=%ld", + inode->i_ino, nr); + continue; + } + ext2_free_branches(inode, + (u32*)bh->b_data, + (u32*)bh->b_data + addr_per_block, + depth); + bforget(bh); + /* Writer: ->i_blocks */ + inode->i_blocks -= inode->i_sb->s_blocksize / 512; + /* Writer: end */ + ext2_free_blocks(inode, nr, 1); + mark_inode_dirty(inode); + } + } else + ext2_free_data(inode, p, q); +} + +void ext2_truncate (struct inode * inode) +{ + u32 *i_data = inode->u.ext2_i.i_data; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int offsets[4]; + Indirect chain[4]; + Indirect *partial; + int nr = 0; + int n; + long iblock; + unsigned blocksize; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + + ext2_discard_prealloc(inode); + + blocksize = inode->i_sb->s_blocksize; + iblock = (inode->i_size + blocksize-1) + >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); + + block_truncate_page(inode->i_mapping, inode->i_size, ext2_get_block); + + n = ext2_block_to_path(inode, iblock, offsets); + if (n == 0) + return; + + if (n == 1) { + ext2_free_data(inode, i_data+offsets[0], + i_data + EXT2_NDIR_BLOCKS); + goto do_indirects; + } + + partial = ext2_find_shared(inode, n, offsets, chain, &nr); + /* Kill the top of shared branch (already detached) */ + if (nr) { + if (partial == chain) + mark_inode_dirty(inode); + else + mark_buffer_dirty(partial->bh); + ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial); + } + /* Clear the ends of indirect blocks on the shared branch */ + while (partial > chain) { + ext2_free_branches(inode, + partial->p + 1, + (u32*)partial->bh->b_data + addr_per_block, + (chain+n-1) - partial); + mark_buffer_dirty(partial->bh); + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &partial->bh); + wait_on_buffer (partial->bh); + } + brelse (partial->bh); + partial--; + } +do_indirects: + /* Kill the remaining (whole) subtrees */ + switch (offsets[0]) { + default: + nr = i_data[EXT2_IND_BLOCK]; + if (nr) { + i_data[EXT2_IND_BLOCK] = 0; + mark_inode_dirty(inode); + ext2_free_branches(inode, &nr, &nr+1, 1); + } + case EXT2_IND_BLOCK: + nr = i_data[EXT2_DIND_BLOCK]; + if (nr) { + i_data[EXT2_DIND_BLOCK] = 0; + mark_inode_dirty(inode); + ext2_free_branches(inode, &nr, &nr+1, 2); + } + case EXT2_DIND_BLOCK: + nr = i_data[EXT2_TIND_BLOCK]; + if (nr) { + i_data[EXT2_TIND_BLOCK] = 0; + mark_inode_dirty(inode); + ext2_free_branches(inode, &nr, &nr+1, 3); + } + case EXT2_TIND_BLOCK: + ; + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + if (IS_SYNC(inode)) + ext2_sync_inode (inode); + else + mark_inode_dirty(inode); +} + void ext2_read_inode (struct inode * inode) { struct buffer_head * bh; @@ -781,30 +1034,22 @@ inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); inode->i_version = ++event; - inode->u.ext2_i.i_new_inode = 0; inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags); inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr); inode->u.ext2_i.i_frag_no = raw_inode->i_frag; inode->u.ext2_i.i_frag_size = raw_inode->i_fsize; - inode->u.ext2_i.i_osync = 0; inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl); if (S_ISDIR(inode->i_mode)) inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); else { - inode->u.ext2_i.i_dir_acl = 0; inode->u.ext2_i.i_high_size = le32_to_cpu(raw_inode->i_size_high); inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; } inode->i_generation = le32_to_cpu(raw_inode->i_generation); inode->u.ext2_i.i_block_group = block_group; - inode->u.ext2_i.i_next_alloc_block = 0; - inode->u.ext2_i.i_next_alloc_goal = 0; - if (inode->u.ext2_i.i_prealloc_count) - ext2_error (inode->i_sb, "ext2_read_inode", - "New inode has non-zero prealloc count!"); /* - * NOTE! The in-memory inode i_blocks array is in little-endian order + * NOTE! The in-memory inode i_data array is in little-endian order * even on big-endian machines: we do NOT byteswap the block numbers! */ for (block = 0; block < EXT2_N_BLOCKS; block++) @@ -940,15 +1185,29 @@ raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl); if (S_ISDIR(inode->i_mode)) raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl); - else + else { raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32); - + if (raw_inode->i_size_high) { + struct super_block *sb = inode->i_sb; + struct ext2_super_block *es = sb->u.ext2_sb.s_es; + if (!(es->s_feature_ro_compat & cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) { + /* If this is the first large file + * created, add a flag to the superblock. + */ + lock_kernel(); + es->s_feature_ro_compat |= cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE); + unlock_kernel(); + ext2_write_super(sb); + } + } + } + raw_inode->i_generation = cpu_to_le32(inode->i_generation); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev)); else for (block = 0; block < EXT2_N_BLOCKS; block++) raw_inode->i_block[block] = inode->u.ext2_i.i_data[block]; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (do_sync) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -966,7 +1225,7 @@ void ext2_write_inode (struct inode * inode, int wait) { lock_kernel(); - ext2_update_inode (inode, 0); + ext2_update_inode (inode, wait); unlock_kernel(); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v2.4.0-test7/linux/fs/ext2/namei.c Fri Jun 23 21:55:10 2000 +++ linux/fs/ext2/namei.c Tue Sep 5 14:07:29 2000 @@ -298,7 +298,7 @@ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(dir); dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -339,7 +339,7 @@ else de->inode = 0; dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -366,12 +366,9 @@ struct inode * inode; int err; - /* - * N.B. Several error exits in ext2_new_inode don't set err. - */ inode = ext2_new_inode (dir, mode, &err); if (!inode) - return -EIO; + return err; inode->i_op = &ext2_file_inode_operations; inode->i_fop = &ext2_file_operations; @@ -397,7 +394,7 @@ inode = ext2_new_inode (dir, mode, &err); if (!inode) - return -EIO; + return err; inode->i_uid = current->fsuid; init_special_inode(inode, mode, rdev); @@ -428,7 +425,7 @@ inode = ext2_new_inode (dir, S_IFDIR, &err); if (!inode) - return -EIO; + return err; inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; @@ -454,7 +451,7 @@ strcpy (de->name, ".."); ext2_set_de_type(dir->i_sb, de, S_IFDIR); inode->i_nlink = 2; - mark_buffer_dirty(dir_block, 1); + mark_buffer_dirty(dir_block); brelse (dir_block); inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) @@ -634,7 +631,7 @@ return -ENAMETOOLONG; if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) - return -EIO; + return err; inode->i_mode = S_IFLNK | S_IRWXUGO; @@ -760,7 +757,7 @@ EXT2_FEATURE_INCOMPAT_FILETYPE)) new_de->file_type = old_de->file_type; new_dir->i_version = ++event; - mark_buffer_dirty(new_bh, 1); + mark_buffer_dirty(new_bh); if (IS_SYNC(new_dir)) { ll_rw_block (WRITE, 1, &new_bh); wait_on_buffer (new_bh); @@ -791,7 +788,7 @@ mark_inode_dirty(old_dir); if (dir_bh) { PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino); - mark_buffer_dirty(dir_bh, 1); + mark_buffer_dirty(dir_bh); old_dir->i_nlink--; mark_inode_dirty(old_dir); if (new_inode) { diff -u --recursive --new-file v2.4.0-test7/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v2.4.0-test7/linux/fs/ext2/super.c Wed Aug 9 19:19:51 2000 +++ linux/fs/ext2/super.c Tue Sep 5 14:07:29 2000 @@ -38,7 +38,7 @@ sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; sb->u.ext2_sb.s_es->s_state = cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); sb->s_dirt = 1; } va_start (args, fmt); @@ -68,7 +68,7 @@ sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; sb->u.ext2_sb.s_es->s_state = cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); sb->s_dirt = 1; } va_start (args, fmt); @@ -101,7 +101,7 @@ if (!(sb->s_flags & MS_RDONLY)) { sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); } db_count = sb->u.ext2_sb.s_db_per_group; for (i = 0; i < db_count; i++) @@ -286,7 +286,7 @@ es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); es->s_mtime = cpu_to_le32(CURRENT_TIME); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); sb->s_dirt = 1; if (test_opt (sb, DEBUG)) printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " @@ -612,7 +612,7 @@ struct ext2_super_block * es) { es->s_wtime = cpu_to_le32(CURRENT_TIME); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); sb->s_dirt = 0; } @@ -677,7 +677,7 @@ */ es->s_state = cpu_to_le16(sb->u.ext2_sb.s_mount_state); es->s_mtime = cpu_to_le32(CURRENT_TIME); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); sb->s_dirt = 1; ext2_commit_super (sb, es); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c --- v2.4.0-test7/linux/fs/ext2/truncate.c Tue Dec 7 09:32:47 1999 +++ linux/fs/ext2/truncate.c Wed Dec 31 16:00:00 1969 @@ -1,382 +0,0 @@ -/* - * linux/fs/ext2/truncate.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/truncate.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * - * General cleanup and race fixes, wsh, 1998 - */ - -#include -#include - - -/* - * Real random numbers for secure rm added 94/02/18 - * Idea from Pierre del Perugia - */ - -#if 0 - -/* - * Secure deletion currently doesn't work. It interacts very badly - * with buffers shared with memory mappings, and for that reason - * can't be done in the truncate() routines. It should instead be - * done separately in "release()" before calling the truncate routines - * that will release the actual file blocks. - * - * Linus - */ -static int ext2_secrm_seed = 152; /* Random generator base */ - -#define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1) -#endif - -/* - * Macros to return the block number for the inode size and offset. - * Currently we always hold the inode semaphore during truncate, so - * there's no need to test for changes during the operation. - */ -#define DIRECT_BLOCK(inode) \ - ((unsigned long) ((inode->i_size + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits)) -#define INDIRECT_BLOCK(inode,offset) ((int)DIRECT_BLOCK(inode) - offset) -#define DINDIRECT_BLOCK(inode,offset) \ - (INDIRECT_BLOCK(inode,offset) / addr_per_block) -#define TINDIRECT_BLOCK(inode,offset) \ - (INDIRECT_BLOCK(inode,offset) / (addr_per_block*addr_per_block)) - -/* - * Truncate has the most races in the whole filesystem: coding it is - * a pain in the a**. Especially as I don't do any locking... - * - * The code may look a bit weird, but that's just because I've tried to - * handle things like file-size changes in a somewhat graceful manner. - * Anyway, truncating a file at the same time somebody else writes to it - * is likely to result in pretty weird behaviour... - * - * The new code handles normal truncates (size = 0) as well as the more - * general case (size = XXX). I hope. - * - * - * Truncate operations have been rewritten to avoid various races. The - * previous code was allowing blocking operations to precede a call to - * bforget(), possible allowing the buffer to be used again. - * - * We now ensure that b_count == 1 before calling bforget() and that the - * parent buffer (if any) is unlocked before clearing the block pointer. - * The operations are always performed in this order: - * (1) Make sure that the parent buffer is unlocked. - * (2) Use find_buffer() to find the block buffer without blocking, - * and set 'retry' if the buffer is locked or b_count > 1. - * (3) Clear the block pointer in the parent (buffer or inode). - * (4) Update the inode block count and mark the inode dirty. - * (5) Forget the block buffer, if any. This call won't block, as - * we know the buffer is unlocked from (2). - * (6) If the block pointer is in a (parent) buffer, mark the buffer - * dirty. (Note that this can block on a loop device.) - * (7) Accumulate the blocks to free and/or update the block bitmap. - * (This operation will frequently block.) - * - * The requirement that parent buffers be unlocked follows from the general - * principle of not modifying a buffer that may be undergoing I/O. With the - * the present kernels there's no problem with modifying a locked inode, as - * the I_DIRTY bit is cleared before setting I_LOCK. - * -- WSH, 1998 - */ - -/* - * Check whether any of the slots in an indirect block are - * still in use, and if not free the block. - */ -static int check_block_empty(struct inode *inode, struct buffer_head *bh, - u32 *p, struct buffer_head *ind_bh) -{ - int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - u32 * ind = (u32 *) bh->b_data; - int i, retry; - - /* Make sure both buffers are unlocked */ - do { - retry = 0; - if (buffer_locked(bh)) { - __wait_on_buffer(bh); - retry = 1; - } - if (ind_bh && buffer_locked(ind_bh)) { - __wait_on_buffer(ind_bh); - retry = 1; - } - } while (retry); - - for (i = 0; i < addr_per_block; i++) - if (*(ind++)) - goto in_use; - - if (atomic_read(&bh->b_count) == 1) { - int tmp; - tmp = le32_to_cpu(*p); - *p = 0; - inode->i_blocks -= (inode->i_sb->s_blocksize / 512); - mark_inode_dirty(inode); - /* - * Forget the buffer, then mark the parent buffer dirty. - */ - bforget(bh); - if (ind_bh) - mark_buffer_dirty(ind_bh, 1); - ext2_free_blocks(inode, tmp, 1); - goto out; - } - retry = 1; - -in_use: - if (IS_SYNC(inode) && buffer_dirty(bh)) { - ll_rw_block (WRITE, 1, &bh); - wait_on_buffer (bh); - } - brelse (bh); - -out: - return retry; -} - -#define DATA_BUFFER_USED(bh) \ - (atomic_read(&bh->b_count) || buffer_locked(bh)) - -static int trunc_direct (struct inode * inode) -{ - int i, retry = 0; - unsigned long block_to_free = 0, free_count = 0; - int blocks = inode->i_sb->s_blocksize / 512; - int direct_block = DIRECT_BLOCK(inode); - - for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) { - u32 * p = inode->u.ext2_i.i_data + i; - int tmp = le32_to_cpu(*p); - - if (!tmp) - continue; - - *p = 0; - inode->i_blocks -= blocks; - mark_inode_dirty(inode); - - /* accumulate blocks to free if they're contiguous */ - if (free_count == 0) - goto free_this; - else if (block_to_free == tmp - free_count) - free_count++; - else { - ext2_free_blocks (inode, block_to_free, free_count); - free_this: - block_to_free = tmp; - free_count = 1; - } - } - if (free_count > 0) - ext2_free_blocks (inode, block_to_free, free_count); - return retry; -} - -static int trunc_indirect (struct inode * inode, int offset, u32 * p, struct buffer_head *dind_bh) -{ - struct buffer_head * ind_bh; - int i, tmp, retry = 0; - unsigned long block_to_free = 0, free_count = 0; - int indirect_block, addr_per_block, blocks; - - tmp = le32_to_cpu(*p); - if (!tmp) - return 0; - ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (tmp != le32_to_cpu(*p)) { - brelse (ind_bh); - return 1; - } - /* A read failure? Report error and clear slot (should be rare). */ - if (!ind_bh) { - ext2_error(inode->i_sb, "trunc_indirect", - "Read failure, inode=%ld, block=%d", - inode->i_ino, tmp); - *p = 0; - if (dind_bh) - mark_buffer_dirty(dind_bh, 1); - else - mark_inode_dirty(inode); - return 0; - } - - blocks = inode->i_sb->s_blocksize / 512; - addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - indirect_block = INDIRECT_BLOCK(inode, offset); - if (indirect_block < 0) - indirect_block = 0; - for (i = indirect_block ; i < addr_per_block ; i++) { - u32 * ind = i + (u32 *) ind_bh->b_data; - - wait_on_buffer(ind_bh); - tmp = le32_to_cpu(*ind); - if (!tmp) - continue; - - *ind = 0; - inode->i_blocks -= blocks; - mark_inode_dirty(inode); - mark_buffer_dirty(ind_bh, 1); - - /* accumulate blocks to free if they're contiguous */ - if (free_count == 0) - goto free_this; - else if (block_to_free == tmp - free_count) - free_count++; - else { - ext2_free_blocks (inode, block_to_free, free_count); - free_this: - block_to_free = tmp; - free_count = 1; - } - } - if (free_count > 0) - ext2_free_blocks (inode, block_to_free, free_count); - /* - * Check the block and dispose of the ind_bh buffer. - */ - retry |= check_block_empty(inode, ind_bh, p, dind_bh); - - return retry; -} - -static int trunc_dindirect (struct inode * inode, int offset, u32 * p, - struct buffer_head * tind_bh) -{ - struct buffer_head * dind_bh; - int i, tmp, retry = 0; - int dindirect_block, addr_per_block; - - tmp = le32_to_cpu(*p); - if (!tmp) - return 0; - dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (tmp != le32_to_cpu(*p)) { - brelse (dind_bh); - return 1; - } - /* A read failure? Report error and clear slot (should be rare). */ - if (!dind_bh) { - ext2_error(inode->i_sb, "trunc_dindirect", - "Read failure, inode=%ld, block=%d", - inode->i_ino, tmp); - *p = 0; - if (tind_bh) - mark_buffer_dirty(tind_bh, 1); - else - mark_inode_dirty(inode); - return 0; - } - - addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - dindirect_block = DINDIRECT_BLOCK(inode, offset); - if (dindirect_block < 0) - dindirect_block = 0; - for (i = dindirect_block ; i < addr_per_block ; i++) { - u32 * dind = i + (u32 *) dind_bh->b_data; - - retry |= trunc_indirect(inode, - offset + (i * addr_per_block), - dind, dind_bh); - } - /* - * Check the block and dispose of the dind_bh buffer. - */ - retry |= check_block_empty(inode, dind_bh, p, tind_bh); - - return retry; -} - -static int trunc_tindirect (struct inode * inode) -{ - u32 * p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK; - struct buffer_head * tind_bh; - int i, tmp, retry = 0; - int tindirect_block, addr_per_block, offset; - - tmp = le32_to_cpu(*p); - if (!tmp) - return 0; - tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (tmp != le32_to_cpu(*p)) { - brelse (tind_bh); - return 1; - } - /* A read failure? Report error and clear slot (should be rare). */ - if (!tind_bh) { - ext2_error(inode->i_sb, "trunc_tindirect", - "Read failure, inode=%ld, block=%d", - inode->i_ino, tmp); - *p = 0; - mark_inode_dirty(inode); - return 0; - } - - addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - offset = EXT2_NDIR_BLOCKS + addr_per_block + - (addr_per_block * addr_per_block); - tindirect_block = TINDIRECT_BLOCK(inode, offset); - if (tindirect_block < 0) - tindirect_block = 0; - for (i = tindirect_block ; i < addr_per_block ; i++) { - u32 * tind = i + (u32 *) tind_bh->b_data; - - retry |= trunc_dindirect(inode, - offset + (i * addr_per_block * addr_per_block), - tind, tind_bh); - } - /* - * Check the block and dispose of the tind_bh buffer. - */ - retry |= check_block_empty(inode, tind_bh, p, NULL); - - return retry; -} - -void ext2_truncate (struct inode * inode) -{ - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; - ext2_discard_prealloc(inode); - while (1) { - int retry = trunc_direct(inode); - retry |= trunc_indirect (inode, - EXT2_IND_BLOCK, - (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK], - NULL); - retry |= trunc_dindirect (inode, - EXT2_IND_BLOCK+EXT2_ADDR_PER_BLOCK(inode->i_sb), - (u32 *)&inode->u.ext2_i.i_data[EXT2_DIND_BLOCK], - NULL); - retry |= trunc_tindirect (inode); - if (!retry) - break; - if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) - ext2_sync_inode (inode); - run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - schedule(); - } - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); -} diff -u --recursive --new-file v2.4.0-test7/linux/fs/fat/buffer.c linux/fs/fat/buffer.c --- v2.4.0-test7/linux/fs/fat/buffer.c Mon Aug 9 11:43:49 1999 +++ linux/fs/fat/buffer.c Tue Sep 5 14:07:29 2000 @@ -32,10 +32,9 @@ } void fat_mark_buffer_dirty ( struct super_block *sb, - struct buffer_head *bh, - int dirty) + struct buffer_head *bh) { - MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty); + MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh); } void fat_set_uptodate ( struct super_block *sb, @@ -71,10 +70,9 @@ } void default_fat_mark_buffer_dirty ( struct super_block *sb, - struct buffer_head *bh, - int dirty) + struct buffer_head *bh) { - mark_buffer_dirty (bh,dirty); + mark_buffer_dirty (bh); } void default_fat_set_uptodate ( struct super_block *sb, @@ -170,10 +168,9 @@ void bigblock_fat_mark_buffer_dirty ( struct super_block *sb, - struct buffer_head *bh, - int dirty) + struct buffer_head *bh) { - mark_buffer_dirty (bh->b_next,dirty); + mark_buffer_dirty (bh->b_next); } void bigblock_fat_set_uptodate ( diff -u --recursive --new-file v2.4.0-test7/linux/fs/fat/cache.c linux/fs/fat/cache.c --- v2.4.0-test7/linux/fs/fat/cache.c Thu Jul 27 17:38:01 2000 +++ linux/fs/fat/cache.c Tue Sep 5 14:07:29 2000 @@ -106,16 +106,16 @@ *p_first = new_value & 0xff; *p_last = (*p_last & 0xf0) | (new_value >> 8); } - fat_mark_buffer_dirty(sb, bh2, 1); + fat_mark_buffer_dirty(sb, bh2); } - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) { b = MSDOS_SB(sb)->fat_start + (first >> SECTOR_BITS) + MSDOS_SB(sb)->fat_length * copy; if (!(c_bh = fat_bread(sb, b))) break; memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE); - fat_mark_buffer_dirty(sb, c_bh, 1); + fat_mark_buffer_dirty(sb, c_bh); if (bh != bh2) { if (!(c_bh2 = fat_bread(sb, b+1))) { fat_brelse(sb, c_bh); diff -u --recursive --new-file v2.4.0-test7/linux/fs/fat/cvf.c linux/fs/fat/cvf.c --- v2.4.0-test7/linux/fs/fat/cvf.c Mon Aug 9 11:43:49 1999 +++ linux/fs/fat/cvf.c Tue Sep 5 14:07:29 2000 @@ -27,9 +27,9 @@ void default_fat_brelse(struct super_block *, struct buffer_head *); void bigblock_fat_brelse(struct super_block *, struct buffer_head *); void default_fat_mark_buffer_dirty (struct super_block *, - struct buffer_head *, int); + struct buffer_head *); void bigblock_fat_mark_buffer_dirty (struct super_block *, - struct buffer_head *, int); + struct buffer_head *); void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int); void bigblock_fat_set_uptodate (struct super_block *, struct buffer_head *,int); int default_fat_is_uptodate(struct super_block *, struct buffer_head *); diff -u --recursive --new-file v2.4.0-test7/linux/fs/fat/dir.c linux/fs/fat/dir.c --- v2.4.0-test7/linux/fs/fat/dir.c Wed Aug 23 18:36:38 2000 +++ linux/fs/fat/dir.c Tue Sep 5 14:07:29 2000 @@ -679,7 +679,7 @@ de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16); de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart); de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16); - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); fat_brelse(sb, bh); dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); diff -u --recursive --new-file v2.4.0-test7/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v2.4.0-test7/linux/fs/fat/inode.c Thu Jul 27 17:38:01 2000 +++ linux/fs/fat/inode.c Tue Sep 5 14:07:29 2000 @@ -898,7 +898,7 @@ raw_entry->cdate = CT_LE_W(raw_entry->cdate); } spin_unlock(&fat_inode_lock); - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); fat_brelse(sb, bh); unlock_kernel(); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/fat/misc.c linux/fs/fat/misc.c --- v2.4.0-test7/linux/fs/fat/misc.c Thu Feb 10 17:11:17 2000 +++ linux/fs/fat/misc.c Tue Sep 5 14:07:29 2000 @@ -129,7 +129,7 @@ return; } fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters); - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); fat_brelse(sb, bh); } @@ -291,7 +291,7 @@ else { memset(bh->b_data,0,SECTOR_SIZE); fat_set_uptodate(sb, bh, 1); - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); if (!res) res=bh; else diff -u --recursive --new-file v2.4.0-test7/linux/fs/fat/msbuffer.h linux/fs/fat/msbuffer.h --- v2.4.0-test7/linux/fs/fat/msbuffer.h Thu May 9 21:54:52 1996 +++ linux/fs/fat/msbuffer.h Tue Sep 5 14:07:29 2000 @@ -5,8 +5,7 @@ struct buffer_head *fat_getblk (struct super_block *sb, int block); void fat_brelse (struct super_block *sb, struct buffer_head *bh); void fat_mark_buffer_dirty (struct super_block *sb, - struct buffer_head *bh, - int dirty_val); + struct buffer_head *bh); void fat_set_uptodate (struct super_block *sb, struct buffer_head *bh, int val); diff -u --recursive --new-file v2.4.0-test7/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.4.0-test7/linux/fs/filesystems.c Mon Jul 10 16:47:25 2000 +++ linux/fs/filesystems.c Sat Sep 2 11:33:30 2000 @@ -16,12 +16,10 @@ #include #include #include -#ifdef CONFIG_KMOD #include -#endif -#include -#include #include +#include +#include #ifdef CONFIG_CODA_FS extern int init_coda(void); @@ -48,32 +46,28 @@ #endif } -#ifndef CONFIG_NFSD -#ifdef CONFIG_NFSD_MODULE -long (*do_nfsservctl)(int, void *, void *); -#endif +#if defined(CONFIG_NFSD_MODULE) +struct nfsd_linkage *nfsd_linkage = NULL; + long asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp) { -#ifndef CONFIG_NFSD_MODULE - return -ENOSYS; -#else int ret = -ENOSYS; lock_kernel(); - if (do_nfsservctl) { - ret = do_nfsservctl(cmd, argp, resp); - goto out; - } -#ifdef CONFIG_KMOD - if (request_module ("nfsd") == 0) { - if (do_nfsservctl) - ret = do_nfsservctl(cmd, argp, resp); - } -#endif /* CONFIG_KMOD */ -out: + + if (nfsd_linkage || + (request_module ("nfsd") == 0 && nfsd_linkage)) + ret = nfsd_linkage->do_nfsservctl(cmd, argp, resp); + unlock_kernel(); return ret; -#endif /* CONFIG_NFSD_MODULE */ +} +EXPORT_SYMBOL(nfsd_linkage); + +#elif ! defined (CONFIG_NFSD) +asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp) +{ + return -ENOSYS; } #endif /* CONFIG_NFSD */ diff -u --recursive --new-file v2.4.0-test7/linux/fs/hfs/file.c linux/fs/hfs/file.c --- v2.4.0-test7/linux/fs/hfs/file.c Sat Feb 26 22:31:52 2000 +++ linux/fs/hfs/file.c Tue Sep 5 14:07:29 2000 @@ -489,7 +489,7 @@ written += c; buf += c; mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 0); + mark_buffer_dirty(bh); brelse(bh); } if (written > 0) { diff -u --recursive --new-file v2.4.0-test7/linux/fs/hpfs/anode.c linux/fs/hpfs/anode.c --- v2.4.0-test7/linux/fs/hpfs/anode.c Fri Oct 22 13:21:52 1999 +++ linux/fs/hpfs/anode.c Tue Sep 5 14:07:29 2000 @@ -84,7 +84,7 @@ if (btree->internal) { a = btree->u.internal[n].down; btree->u.internal[n].file_secno = -1; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); if (s->s_hpfs_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_add_sector_to_btree #1")) return -1; @@ -102,7 +102,7 @@ } if (hpfs_alloc_if_possible(s, se = btree->u.external[n].disk_secno + btree->u.external[n].length)) { btree->u.external[n].length++; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); return se; } @@ -139,7 +139,7 @@ btree->first_free = (char *)&(btree->u.internal[1]) - (char *)btree; btree->u.internal[0].file_secno = -1; btree->u.internal[0].down = na; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } else if (!(ranode = hpfs_alloc_anode(s, /*a*/0, &ra, &bh2))) { brelse(bh); brelse(bh1); @@ -156,7 +156,7 @@ btree->u.external[n].disk_secno = se; btree->u.external[n].file_secno = fs; btree->u.external[n].length = 1; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); if ((a == node && fnod) || na == -1) return se; c2 = 0; @@ -176,14 +176,14 @@ btree->u.internal[n].file_secno = -1; btree->u.internal[n].down = na; btree->u.internal[n-1].file_secno = fs; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); brelse(bh2); hpfs_free_sectors(s, ra, 1); if ((anode = hpfs_map_anode(s, na, &bh))) { anode->up = up; anode->btree.fnode_parent = up == node && fnod; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } return se; @@ -191,7 +191,7 @@ up = up != node ? anode->up : -1; btree->u.internal[btree->n_used_nodes - 1].file_secno = /*fs*/-1; if (up == -1) anode->up = ra; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); a = na; if ((anode = hpfs_alloc_anode(s, a, &na, &bh))) { @@ -202,11 +202,11 @@ anode->btree.first_free = 16; anode->btree.u.internal[0].down = a; anode->btree.u.internal[0].file_secno = -1; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); if ((anode = hpfs_map_anode(s, a, &bh))) { anode->up = na; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } } else na = a; @@ -214,7 +214,7 @@ if ((anode = hpfs_map_anode(s, na, &bh))) { anode->up = node; if (fnod) anode->btree.fnode_parent = 1; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } if (!fnod) { @@ -239,7 +239,7 @@ if ((unode = hpfs_map_anode(s, ranode->u.internal[n].down, &bh1))) { unode->up = ra; unode->btree.fnode_parent = 0; - mark_buffer_dirty(bh1, 1); + mark_buffer_dirty(bh1); brelse(bh1); } } @@ -251,9 +251,9 @@ btree->u.internal[0].down = ra; btree->u.internal[1].file_secno = -1; btree->u.internal[1].down = na; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); - mark_buffer_dirty(bh2, 1); + mark_buffer_dirty(bh2); brelse(bh2); return se; } @@ -367,7 +367,7 @@ return -1; l = 0x200 - (pos & 0x1ff); if (l > len) l = len; memcpy(data + (pos & 0x1ff), buf, l); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); buf += l; pos += l; len -= l; } @@ -411,7 +411,7 @@ btree->n_used_nodes = 0; btree->first_free = 8; btree->internal = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } else hpfs_free_sectors(s, f, 1); brelse(bh); return; @@ -429,7 +429,7 @@ btree->n_used_nodes = i + 1; btree->n_free_nodes = nodes - btree->n_used_nodes; btree->first_free = 8 + 8 * btree->n_used_nodes; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (btree->u.internal[i].file_secno == secs) { brelse(bh); return; @@ -463,7 +463,7 @@ btree->n_used_nodes = i + 1; btree->n_free_nodes = nodes - btree->n_used_nodes; btree->first_free = 8 + 12 * btree->n_used_nodes; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/hpfs/buffer.c linux/fs/hpfs/buffer.c --- v2.4.0-test7/linux/fs/hpfs/buffer.c Thu Jul 27 17:38:01 2000 +++ linux/fs/hpfs/buffer.c Tue Sep 5 14:07:29 2000 @@ -261,8 +261,8 @@ memcpy(qbh->bh[1]->b_data, qbh->data + 512, 512); memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512); memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512); - mark_buffer_dirty(qbh->bh[0],1); - mark_buffer_dirty(qbh->bh[1],1); - mark_buffer_dirty(qbh->bh[2],1); - mark_buffer_dirty(qbh->bh[3],1); + mark_buffer_dirty(qbh->bh[0]); + mark_buffer_dirty(qbh->bh[1]); + mark_buffer_dirty(qbh->bh[2]); + mark_buffer_dirty(qbh->bh[3]); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/hpfs/dnode.c linux/fs/hpfs/dnode.c --- v2.4.0-test7/linux/fs/hpfs/dnode.c Fri Oct 22 13:21:52 1999 +++ linux/fs/hpfs/dnode.c Tue Sep 5 14:07:29 2000 @@ -337,7 +337,7 @@ return 1; } fnode->u.external[0].disk_secno = rdno; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); d->up = ad->up = i->i_hpfs_dno = rdno; d->root_dnode = ad->root_dnode = 0; @@ -535,7 +535,7 @@ } if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) { fnode->u.external[0].disk_secno = down; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } i->i_hpfs_dno = down; diff -u --recursive --new-file v2.4.0-test7/linux/fs/hpfs/ea.c linux/fs/hpfs/ea.c --- v2.4.0-test7/linux/fs/hpfs/ea.c Tue Dec 14 01:27:24 1999 +++ linux/fs/hpfs/ea.c Tue Sep 5 14:07:29 2000 @@ -277,7 +277,7 @@ fnode->ea_size_s = 0; fnode->ea_secno = n; fnode->ea_anode = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } pos = fnode->ea_size_l + 5 + strlen(key) + size; @@ -307,7 +307,7 @@ anode->u.external[0].disk_secno = fnode->ea_secno; anode->u.external[0].file_secno = 0; anode->u.external[0].length = len; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); fnode->ea_anode = 1; fnode->ea_secno = a_s;*/ @@ -329,7 +329,7 @@ } memcpy(b2, b1, 512); brelse(bh1); - mark_buffer_dirty(bh2, 1); + mark_buffer_dirty(bh2); brelse(bh2); } hpfs_free_sectors(s, fnode->ea_secno, len); diff -u --recursive --new-file v2.4.0-test7/linux/fs/hpfs/inode.c linux/fs/hpfs/inode.c --- v2.4.0-test7/linux/fs/hpfs/inode.c Mon Jul 10 16:47:25 2000 +++ linux/fs/hpfs/inode.c Tue Sep 5 14:07:29 2000 @@ -291,7 +291,7 @@ hpfs_brelse4(&qbh); } else hpfs_error(i->i_sb, "directory %08x doesn't have '.' entry", i->i_ino); } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/hpfs/namei.c linux/fs/hpfs/namei.c --- v2.4.0-test7/linux/fs/hpfs/namei.c Mon Jul 10 16:47:25 2000 +++ linux/fs/hpfs/namei.c Tue Sep 5 14:07:29 2000 @@ -62,7 +62,7 @@ de->first = de->directory = 1; /*de->hidden = de->system = 0;*/ de->fnode = fno; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); hpfs_mark_4buffers_dirty(&qbh0); hpfs_brelse4(&qbh0); @@ -128,7 +128,7 @@ fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = dir->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); hpfs_lock_iget(dir->i_sb, 2); if ((result = iget(dir->i_sb, fno))) { @@ -196,7 +196,7 @@ fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = dir->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); hpfs_lock_iget(dir->i_sb, 2); if ((result = iget(dir->i_sb, fno))) { result->i_hpfs_parent_dir = dir->i_ino; @@ -258,7 +258,7 @@ fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = dir->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); hpfs_lock_iget(dir->i_sb, 2); if ((result = iget(dir->i_sb, fno))) { @@ -276,7 +276,7 @@ result->i_data.a_ops = &hpfs_symlink_aops; if ((fnode = hpfs_map_fnode(dir->i_sb, fno, &bh))) { hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink)); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } hpfs_write_inode_nolock(result); @@ -523,7 +523,7 @@ fnode->len = new_len; memcpy(fnode->name, new_name, new_len>15?15:new_len); if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } i->i_hpfs_conv = i->i_sb->s_hpfs_conv; diff -u --recursive --new-file v2.4.0-test7/linux/fs/hpfs/super.c linux/fs/hpfs/super.c --- v2.4.0-test7/linux/fs/hpfs/super.c Tue Mar 14 19:10:40 2000 +++ linux/fs/hpfs/super.c Tue Sep 5 14:07:30 2000 @@ -21,7 +21,7 @@ if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { sb->dirty = 1; sb->old_wrote = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } } @@ -38,7 +38,7 @@ if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { sb->dirty = s->s_hpfs_chkdsk > 1 - s->s_hpfs_was_error; sb->old_wrote = s->s_hpfs_chkdsk >= 2 && !s->s_hpfs_was_error; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); } } @@ -466,7 +466,7 @@ if (!(s->s_flags & MS_RDONLY)) { spareblock->dirty = 1; spareblock->old_wrote = 0; - mark_buffer_dirty(bh2, 1); + mark_buffer_dirty(bh2); } if (spareblock->hotfixes_used || spareblock->n_spares_used) { diff -u --recursive --new-file v2.4.0-test7/linux/fs/locks.c linux/fs/locks.c --- v2.4.0-test7/linux/fs/locks.c Wed Aug 23 18:36:38 2000 +++ linux/fs/locks.c Tue Aug 29 12:41:12 2000 @@ -1040,17 +1040,12 @@ */ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { - struct vm_area_struct *vma; struct address_space *mapping = inode->i_mapping; - spin_lock(&mapping->i_shared_lock); - for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) { - if (!(vma->vm_flags & VM_MAYSHARE)) - continue; - spin_unlock(&mapping->i_shared_lock); + + if (mapping->i_mmap_shared != NULL) { error = -EAGAIN; goto out_putf; } - spin_unlock(&mapping->i_shared_lock); } error = -EINVAL; @@ -1199,17 +1194,12 @@ */ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { - struct vm_area_struct *vma; struct address_space *mapping = inode->i_mapping; - spin_lock(&mapping->i_shared_lock); - for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) { - if (!(vma->vm_flags & VM_MAYSHARE)) - continue; - spin_unlock(&mapping->i_shared_lock); + + if (mapping->i_mmap_shared != NULL) { error = -EAGAIN; goto out_putf; } - spin_unlock(&mapping->i_shared_lock); } error = -EINVAL; diff -u --recursive --new-file v2.4.0-test7/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c --- v2.4.0-test7/linux/fs/minix/bitmap.c Mon Jul 10 16:47:26 2000 +++ linux/fs/minix/bitmap.c Tue Sep 5 14:07:30 2000 @@ -85,7 +85,7 @@ kdevname(sb->s_dev), block); else DQUOT_FREE_BLOCK(sb, inode, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); return; } @@ -117,7 +117,7 @@ DQUOT_FREE_BLOCK(sb, inode, 1); goto repeat; } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); j += i*8192 + sb->u.minix_sb.s_firstdatazone-1; if (j < sb->u.minix_sb.s_firstdatazone || j >= sb->u.minix_sb.s_nzones) @@ -156,7 +156,7 @@ (ino - 1) % MINIX_INODES_PER_BLOCK); raw_inode->i_nlinks = 0; raw_inode->i_mode = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); return bh; } @@ -184,7 +184,7 @@ (ino - 1) % MINIX2_INODES_PER_BLOCK); raw_inode->i_nlinks = 0; raw_inode->i_mode = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); return bh; } @@ -223,7 +223,7 @@ clear_inode(inode); if (!minix_test_and_clear_bit(ino & 8191, bh->b_data)) printk("free_inode: bit %lu already cleared.\n",ino); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } struct inode * minix_new_inode(const struct inode * dir, int * error) @@ -258,7 +258,7 @@ unlock_super(sb); return NULL; } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); j += i*8192; if (!j || j > inode->i_sb->u.minix_sb.s_ninodes) { iput(inode); diff -u --recursive --new-file v2.4.0-test7/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v2.4.0-test7/linux/fs/minix/inode.c Thu Jul 27 17:38:01 2000 +++ linux/fs/minix/inode.c Tue Sep 5 14:07:30 2000 @@ -45,7 +45,7 @@ static void minix_commit_super(struct super_block * sb) { - mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.minix_sb.s_sbh); sb->s_dirt = 0; } @@ -70,7 +70,7 @@ if (!(sb->s_flags & MS_RDONLY)) { sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state; - mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.minix_sb.s_sbh); } for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++) brelse(sb->u.minix_sb.s_imap[i]); @@ -105,7 +105,7 @@ return 0; /* Mounting a rw partition read-only. */ ms->s_state = sb->u.minix_sb.s_mount_state; - mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.minix_sb.s_sbh); sb->s_dirt = 1; minix_commit_super(sb); } @@ -113,7 +113,7 @@ /* Mount a partition which is read-only, read-write. */ sb->u.minix_sb.s_mount_state = ms->s_state; ms->s_state &= ~MINIX_VALID_FS; - mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.minix_sb.s_sbh); sb->s_dirt = 1; if (!(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS)) @@ -279,7 +279,7 @@ if (!(s->s_flags & MS_RDONLY)) { ms->s_state &= ~MINIX_VALID_FS; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); s->s_dirt = 1; } if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS)) @@ -520,7 +520,7 @@ } memset(result->b_data, 0, BLOCK_SIZE); mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result, 1); + mark_buffer_dirty(result); } else { if (*p) { /* @@ -588,7 +588,7 @@ } memset(result->b_data, 0, BLOCK_SIZE); mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result, 1); + mark_buffer_dirty(result); } else { *phys = tmp; *new = 1; @@ -600,7 +600,7 @@ } *p = tmp; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); *err = 0; out: brelse(bh); @@ -731,7 +731,7 @@ } memset(result->b_data, 0, BLOCK_SIZE); mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result, 1); + mark_buffer_dirty(result); } else { if (*p) { /* @@ -799,7 +799,7 @@ } memset(result->b_data, 0, BLOCK_SIZE); mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result, 1); + mark_buffer_dirty(result); } else { *phys = tmp; *new = 1; @@ -811,7 +811,7 @@ } *p = tmp; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); *err = 0; out: brelse(bh); @@ -934,7 +934,7 @@ if (buffer_new(&dummy)) { memset(bh->b_data, 0, BLOCK_SIZE); mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } return bh; } @@ -1130,7 +1130,7 @@ raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev); else for (block = 0; block < 9; block++) raw_inode->i_zone[block] = inode->u.minix_i.u.i1_data[block]; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); return bh; } @@ -1170,7 +1170,7 @@ raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev); else for (block = 0; block < 10; block++) raw_inode->i_zone[block] = inode->u.minix_i.u.i2_data[block]; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); return bh; } diff -u --recursive --new-file v2.4.0-test7/linux/fs/minix/namei.c linux/fs/minix/namei.c --- v2.4.0-test7/linux/fs/minix/namei.c Fri Jun 23 21:55:10 2000 +++ linux/fs/minix/namei.c Tue Sep 5 14:07:30 2000 @@ -187,7 +187,7 @@ for (i = 0; i < info->s_namelen ; i++) de->name[i] = (i < namelen) ? name[i] : 0; dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); *res_dir = de; break; } @@ -228,7 +228,7 @@ return error; } de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); d_instantiate(dentry, inode); return 0; @@ -257,7 +257,7 @@ return error; } de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); d_instantiate(dentry, inode); return 0; @@ -296,7 +296,7 @@ de->inode = dir->i_ino; strcpy(de->name,".."); inode->i_nlink = 2; - mark_buffer_dirty(dir_block, 1); + mark_buffer_dirty(dir_block); brelse(dir_block); inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) @@ -310,7 +310,7 @@ return error; } de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); dir->i_nlink++; mark_inode_dirty(dir); brelse(bh); @@ -403,7 +403,7 @@ printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); de->inode = 0; dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); inode->i_nlink=0; mark_inode_dirty(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; @@ -437,7 +437,7 @@ } de->inode = 0; dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); inode->i_nlink--; @@ -482,7 +482,7 @@ goto fail; de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); d_instantiate(dentry, inode); out: @@ -515,7 +515,7 @@ return error; } de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); inode->i_nlink++; inode->i_ctime = CURRENT_TIME; @@ -600,11 +600,11 @@ new_inode->i_ctime = CURRENT_TIME; mark_inode_dirty(new_inode); } - mark_buffer_dirty(old_bh, 1); - mark_buffer_dirty(new_bh, 1); + mark_buffer_dirty(old_bh); + mark_buffer_dirty(new_bh); if (dir_bh) { PARENT_INO(dir_bh->b_data) = new_dir->i_ino; - mark_buffer_dirty(dir_bh, 1); + mark_buffer_dirty(dir_bh); old_dir->i_nlink--; mark_inode_dirty(old_dir); if (new_inode) { diff -u --recursive --new-file v2.4.0-test7/linux/fs/minix/truncate.c linux/fs/minix/truncate.c --- v2.4.0-test7/linux/fs/minix/truncate.c Fri Oct 22 13:21:52 1999 +++ linux/fs/minix/truncate.c Tue Sep 5 14:07:30 2000 @@ -109,7 +109,7 @@ continue; } *ind = 0; - mark_buffer_dirty(ind_bh, 1); + mark_buffer_dirty(ind_bh); bforget(bh); minix_free_block(inode,tmp); } @@ -156,7 +156,7 @@ goto repeat; dind = i+(unsigned short *) dind_bh->b_data; retry |= V1_trunc_indirect(inode,offset+(i<<9),dind); - mark_buffer_dirty(dind_bh, 1); + mark_buffer_dirty(dind_bh); } dind = (unsigned short *) dind_bh->b_data; for (i = 0; i < 512; i++) @@ -270,7 +270,7 @@ continue; } *ind = 0; - mark_buffer_dirty(ind_bh, 1); + mark_buffer_dirty(ind_bh); bforget(bh); minix_free_block(inode,tmp); } @@ -317,7 +317,7 @@ goto repeat; dind = i+(unsigned long *) dind_bh->b_data; retry |= V2_trunc_indirect(inode,offset+(i<<8),dind); - mark_buffer_dirty(dind_bh, 1); + mark_buffer_dirty(dind_bh); } dind = (unsigned long *) dind_bh->b_data; for (i = 0; i < 256; i++) @@ -363,7 +363,7 @@ goto repeat; tind = i+(unsigned long *) tind_bh->b_data; retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind); - mark_buffer_dirty(tind_bh, 1); + mark_buffer_dirty(tind_bh); } tind = (unsigned long *) tind_bh->b_data; for (i = 0; i < 256; i++) diff -u --recursive --new-file v2.4.0-test7/linux/fs/msdos/namei.c linux/fs/msdos/namei.c --- v2.4.0-test7/linux/fs/msdos/namei.c Thu Jul 27 17:38:01 2000 +++ linux/fs/msdos/namei.c Tue Sep 5 14:07:29 2000 @@ -265,7 +265,7 @@ (*de)->starthi = 0; fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date); (*de)->size = 0; - fat_mark_buffer_dirty(sb, *bh, 1); + fat_mark_buffer_dirty(sb, *bh); return 0; } @@ -330,7 +330,7 @@ goto rmdir_done; de->name[0] = DELETED_FLAG; - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); fat_detach(inode); inode->i_nlink = 0; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; @@ -396,7 +396,7 @@ mark_inode_dirty(inode); mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); fat_brelse(sb, bh); fat_detach(inode); iput(inode); @@ -424,7 +424,7 @@ goto unlink_done; de->name[0] = DELETED_FLAG; - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); fat_detach(inode); fat_brelse(sb, bh); inode->i_nlink = 0; @@ -485,7 +485,7 @@ if (new_inode) fat_detach(new_inode); old_de->name[0] = DELETED_FLAG; - fat_mark_buffer_dirty(sb, old_bh, 1); + fat_mark_buffer_dirty(sb, old_bh); fat_detach(old_inode); fat_attach(old_inode, new_ino); if (is_hid) @@ -504,7 +504,7 @@ if (dotdot_bh) { dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart); dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16); - fat_mark_buffer_dirty(sb, dotdot_bh, 1); + fat_mark_buffer_dirty(sb, dotdot_bh); old_dir->i_nlink--; mark_inode_dirty(old_dir); if (new_inode) { diff -u --recursive --new-file v2.4.0-test7/linux/fs/ncpfs/ioctl.c linux/fs/ncpfs/ioctl.c --- v2.4.0-test7/linux/fs/ncpfs/ioctl.c Mon Jul 10 16:47:26 2000 +++ linux/fs/ncpfs/ioctl.c Tue Aug 29 14:09:15 2000 @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -25,6 +26,8 @@ #define NCP_OBJECT_NAME_MAX_LEN 4096 /* maximum limit for ncp_privatedata_ioctl */ #define NCP_PRIVATE_DATA_MAX_LEN 8192 +/* maximum negotiable packet size */ +#define NCP_PACKET_SIZE_INTERNAL 65536 int ncp_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -50,11 +53,11 @@ NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) { return -EINVAL; } - bouncebuffer = kmalloc(NCP_PACKET_SIZE, GFP_NFS); + bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL); if (!bouncebuffer) return -ENOMEM; if (copy_from_user(bouncebuffer, request.data, request.size)) { - kfree(bouncebuffer); + vfree(bouncebuffer); return -EFAULT; } ncp_lock_server(server); @@ -67,7 +70,7 @@ memcpy(server->packet, bouncebuffer, request.size); result = ncp_request2(server, request.function, - bouncebuffer, NCP_PACKET_SIZE); + bouncebuffer, NCP_PACKET_SIZE_INTERNAL); if (result < 0) result = -EIO; else @@ -78,7 +81,7 @@ if (result >= 0) if (copy_to_user(request.data, bouncebuffer, result)) result = -EFAULT; - kfree(bouncebuffer); + vfree(bouncebuffer); return result; case NCP_IOC_CONN_LOGGED_IN: @@ -287,7 +290,8 @@ return -EACCES; } /* get only low 8 bits... */ - get_user_ret(newstate, (unsigned char*)arg, -EFAULT); + if (get_user(newstate, (unsigned char *) arg)) + return -EFAULT; if (server->sign_active) { /* cannot turn signatures OFF when active */ if (!newstate) return -EINVAL; diff -u --recursive --new-file v2.4.0-test7/linux/fs/nfs/Makefile linux/fs/nfs/Makefile --- v2.4.0-test7/linux/fs/nfs/Makefile Tue Apr 11 15:09:22 2000 +++ linux/fs/nfs/Makefile Tue Sep 5 14:02:41 2000 @@ -9,7 +9,7 @@ O_TARGET := nfs.o O_OBJS := inode.o file.o read.o write.o dir.o symlink.o proc.o \ - nfs2xdr.o flushd.o + nfs2xdr.o flushd.o unlink.o ifdef CONFIG_ROOT_NFS O_OBJS += nfsroot.o mount_clnt.o diff -u --recursive --new-file v2.4.0-test7/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.4.0-test7/linux/fs/nfs/dir.c Wed Aug 23 18:36:38 2000 +++ linux/fs/nfs/dir.c Tue Sep 5 14:02:41 2000 @@ -606,16 +606,8 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) { if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { - struct dentry *dir = dentry->d_parent; - struct inode *dir_i = dir->d_inode; - int error; - lock_kernel(); - dir = dentry->d_parent; - dir_i = dir->d_inode; - nfs_zap_caches(dir_i); - NFS_CACHEINV(inode); - error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name); + nfs_complete_unlink(dentry); unlock_kernel(); } iput(inode); @@ -868,7 +860,7 @@ if (!error) { nfs_renew_times(dentry); d_move(dentry, sdentry); - dentry->d_flags |= DCACHE_NFSFS_RENAMED; + error = nfs_async_unlink(dentry); /* If we return 0 we don't unlink */ } dput(sdentry); diff -u --recursive --new-file v2.4.0-test7/linux/fs/nfs/nfs3proc.c linux/fs/nfs/nfs3proc.c --- v2.4.0-test7/linux/fs/nfs/nfs3proc.c Fri Jun 23 21:55:10 2000 +++ linux/fs/nfs/nfs3proc.c Tue Sep 5 14:02:41 2000 @@ -267,6 +267,34 @@ } static int +nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) +{ + struct nfs3_diropargs *arg; + struct nfs_fattr *res; + + arg = (struct nfs3_diropargs *)kmalloc(sizeof(*arg)+sizeof(*res), GFP_KERNEL); + if (!arg) + return -ENOMEM; + res = (struct nfs_fattr*)(arg + 1); + arg->fh = NFS_FH(dir); + arg->name = name->name; + arg->len = name->len; + msg->rpc_proc = NFS3PROC_REMOVE; + msg->rpc_argp = arg; + msg->rpc_resp = res; + return 0; +} + +static void +nfs3_proc_unlink_done(struct dentry *dir, struct rpc_message *msg) +{ + struct nfs_fattr *dir_attr = (struct nfs_fattr*)msg->rpc_resp; + + nfs_refresh_inode(dir->d_inode, dir_attr); + kfree(msg->rpc_argp); +} + +static int nfs3_proc_rename(struct dentry *old_dir, struct qstr *old_name, struct dentry *new_dir, struct qstr *new_name) { @@ -469,6 +497,8 @@ NULL, /* commit */ nfs3_proc_create, nfs3_proc_remove, + nfs3_proc_unlink_setup, + nfs3_proc_unlink_done, nfs3_proc_rename, nfs3_proc_link, nfs3_proc_symlink, diff -u --recursive --new-file v2.4.0-test7/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v2.4.0-test7/linux/fs/nfs/proc.c Wed Aug 23 18:36:38 2000 +++ linux/fs/nfs/proc.c Tue Sep 5 14:02:41 2000 @@ -233,6 +233,29 @@ } static int +nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) +{ + struct nfs_diropargs *arg; + + arg = (struct nfs_diropargs *)kmalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) + return -ENOMEM; + arg->fh = NFS_FH(dir); + arg->name = name->name; + arg->len = name->len; + msg->rpc_proc = NFSPROC_REMOVE; + msg->rpc_argp = arg; + return 0; +} + +static void +nfs_proc_unlink_done(struct dentry *dir, struct rpc_message *msg) +{ + NFS_CACHEINV(dir->d_inode); + kfree(msg->rpc_argp); +} + +static int nfs_proc_rename(struct dentry *old_dir, struct qstr *old_name, struct dentry *new_dir, struct qstr *new_name) { @@ -365,6 +388,8 @@ NULL, /* commit */ nfs_proc_create, nfs_proc_remove, + nfs_proc_unlink_setup, + nfs_proc_unlink_done, nfs_proc_rename, nfs_proc_link, nfs_proc_symlink, diff -u --recursive --new-file v2.4.0-test7/linux/fs/nfs/unlink.c linux/fs/nfs/unlink.c --- v2.4.0-test7/linux/fs/nfs/unlink.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nfs/unlink.c Tue Sep 5 14:02:41 2000 @@ -0,0 +1,212 @@ +/* + * linux/fs/nfs/unlink.c + * + * nfs sillydelete handling + * + * NOTE: we rely on holding the BKL for list manipulation protection. + */ + +#include +#include +#include +#include +#include +#include + + +struct nfs_unlinkdata { + struct nfs_unlinkdata *next; + struct dentry *dir, *dentry; + struct qstr name; + struct rpc_task task; + struct rpc_cred *cred; + unsigned int count; +}; + +static struct nfs_unlinkdata *nfs_deletes = NULL; +static struct rpc_wait_queue nfs_delete_queue = RPC_INIT_WAITQ("nfs_delete_queue"); + +/** + * nfs_detach_unlinkdata - Remove asynchronous unlink from global list + * @data: pointer to descriptor + */ +static inline void +nfs_detach_unlinkdata(struct nfs_unlinkdata *data) +{ + struct nfs_unlinkdata **q; + + for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) { + if (*q == data) { + *q = data->next; + break; + } + } +} + +/** + * nfs_put_unlinkdata - release data from a sillydelete operation. + * @data: pointer to unlink structure. + */ +static void +nfs_put_unlinkdata(struct nfs_unlinkdata *data) +{ + if (--data->count == 0) { + nfs_detach_unlinkdata(data); + if (data->name.name != NULL) + kfree(data->name.name); + kfree(data); + } +} + +#define NAME_ALLOC_LEN(len) ((len+16) & ~15) +/** + * nfs_copy_dname - copy dentry name to data structure + * @dentry: pointer to dentry + * @data: nfs_unlinkdata + */ +static inline void +nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data) +{ + char *str; + int len = dentry->d_name.len; + + str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL); + if (!str) + return; + memcpy(str, dentry->d_name.name, len); + if (!data->name.len) { + data->name.len = len; + data->name.name = str; + } else + kfree(str); +} + +/** + * nfs_async_unlink_init - Initialize the RPC info + * @task: rpc_task of the sillydelete + * + * We delay initializing RPC info until after the call to dentry_iput() + * in order to minimize races against rename(). + */ +static void +nfs_async_unlink_init(struct rpc_task *task) +{ + struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; + struct dentry *dir = data->dir; + struct rpc_message msg; + int status = -ENOENT; + + if (!data->name.len) + goto out_err; + + memset(&msg, 0, sizeof(msg)); + msg.rpc_cred = data->cred; + status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name); + if (status < 0) + goto out_err; + rpc_call_setup(task, &msg, 0); + return; + out_err: + rpc_exit(task, status); +} + +/** + * nfs_async_unlink_done - Sillydelete post-processing + * @task: rpc_task of the sillydelete + * + * Do the directory attribute update. + */ +static void +nfs_async_unlink_done(struct rpc_task *task) +{ + struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; + struct dentry *dir = data->dir; + struct inode *dir_i = dir->d_inode; + + nfs_zap_caches(dir_i); + NFS_PROTO(dir_i)->unlink_done(dir, &task->tk_msg); + rpcauth_releasecred(task->tk_auth, data->cred); + data->cred = NULL; + dput(dir); +} + +/** + * nfs_async_unlink_release - Release the sillydelete data. + * @task: rpc_task of the sillydelete + * + * We need to call nfs_put_unlinkdata as a 'tk_release' task since the + * rpc_task would be freed too. + */ +static void +nfs_async_unlink_release(struct rpc_task *task) +{ + struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; + nfs_put_unlinkdata(data); +} + +/** + * nfs_async_unlink - asynchronous unlinking of a file + * @dir: directory in which the file resides. + * @name: name of the file to unlink. + */ +int +nfs_async_unlink(struct dentry *dentry) +{ + struct dentry *dir = dentry->d_parent; + struct nfs_unlinkdata *data; + struct rpc_task *task; + struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); + int status = -ENOMEM; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + goto out; + memset(data, 0, sizeof(*data)); + + data->dir = dget(dir); + data->dentry = dentry; + + data->next = nfs_deletes; + nfs_deletes = data; + data->count = 1; + + task = &data->task; + rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC); + task->tk_calldata = data; + task->tk_action = nfs_async_unlink_init; + task->tk_release = nfs_async_unlink_release; + + dentry->d_flags |= DCACHE_NFSFS_RENAMED; + data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); + + rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL); + status = 0; + out: + return status; +} + +/** + * nfs_complete_remove - Initialize completion of the sillydelete + * @dentry: dentry to delete + * + * Since we're most likely to be called by dentry_iput(), we + * only use the dentry to find the sillydelete. We then copy the name + * into the qstr. + */ +void +nfs_complete_unlink(struct dentry *dentry) +{ + struct nfs_unlinkdata *data; + + for(data = nfs_deletes; data != NULL; data = data->next) { + if (dentry == data->dentry) + break; + } + if (!data) + return; + data->count++; + nfs_copy_dname(dentry, data); + if (data->task.tk_rpcwait == &nfs_delete_queue) + rpc_wake_up_task(&data->task); + nfs_put_unlinkdata(data); +} diff -u --recursive --new-file v2.4.0-test7/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c --- v2.4.0-test7/linux/fs/nfsd/nfsctl.c Thu Jul 27 17:38:01 2000 +++ linux/fs/nfsd/nfsctl.c Mon Aug 28 21:27:39 2000 @@ -312,7 +312,9 @@ EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Olaf Kirch "); -extern long (*do_nfsservctl)(int, void *, void *); +struct nfsd_linkage nfsd_linkage_s = { + do_nfsservctl: handle_sys_nfsservctl, +}; /* * Initialize the module @@ -321,7 +323,7 @@ init_module(void) { printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); - do_nfsservctl = handle_sys_nfsservctl; + nfsd_linkage = &nfsd_linkage_s; return 0; } @@ -331,7 +333,7 @@ void cleanup_module(void) { - do_nfsservctl = NULL; + nfsd_linkage = NULL; nfsd_export_shutdown(); nfsd_cache_shutdown(); remove_proc_entry("fs/nfs/exports", NULL); diff -u --recursive --new-file v2.4.0-test7/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.4.0-test7/linux/fs/nfsd/nfssvc.c Thu Jul 27 17:38:01 2000 +++ linux/fs/nfsd/nfssvc.c Fri Sep 1 14:33:04 2000 @@ -213,7 +213,7 @@ unsigned int signo; for (signo = 1; signo <= _NSIG; signo++) - if (sigismember(¤t->signal, signo) && + if (sigismember(¤t->pending.signal, signo) && !sigismember(¤t->blocked, signo)) break; printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo); diff -u --recursive --new-file v2.4.0-test7/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.4.0-test7/linux/fs/nfsd/vfs.c Thu Jul 27 17:38:01 2000 +++ linux/fs/nfsd/vfs.c Mon Aug 28 21:27:39 2000 @@ -142,6 +142,7 @@ } else dentry = dget(dparent->d_parent); } else { + fh_lock(fhp); dentry = lookup_one(name, dparent); err = PTR_ERR(dentry); if (IS_ERR(dentry)) diff -u --recursive --new-file v2.4.0-test7/linux/fs/ntfs/support.c linux/fs/ntfs/support.c --- v2.4.0-test7/linux/fs/ntfs/support.c Thu Jul 27 17:38:02 2000 +++ linux/fs/ntfs/support.c Tue Sep 5 14:07:30 2000 @@ -177,7 +177,7 @@ else { buf->fn_get(bh->b_data+start_offs,buf,to_copy); - mark_buffer_dirty(bh,1); + mark_buffer_dirty(bh); } unlock_buffer(bh); length-=to_copy; diff -u --recursive --new-file v2.4.0-test7/linux/fs/partitions/check.c linux/fs/partitions/check.c --- v2.4.0-test7/linux/fs/partitions/check.c Thu Jul 27 17:38:02 2000 +++ linux/fs/partitions/check.c Mon Aug 28 21:29:17 2000 @@ -228,24 +228,35 @@ } #ifdef CONFIG_PROC_FS -int get_partition_list(char * page) +int get_partition_list(char *page, char **start, off_t offset, int count) { - struct gendisk *p; - char buf[64]; - int n, len; + struct gendisk *dsk; + int len; len = sprintf(page, "major minor #blocks name\n\n"); - for (p = gendisk_head; p; p = p->next) { - for (n=0; n < (p->nr_real << p->minor_shift); n++) { - if (p->part[n].nr_sects && len < PAGE_SIZE - 80) { - len += sprintf(page+len, + for (dsk = gendisk_head; dsk; dsk = dsk->next) { + int n; + + for (n = 0; n < (dsk->nr_real << dsk->minor_shift); n++) + if (dsk->part[n].nr_sects) { + char buf[64]; + + len += sprintf(page + len, "%4d %4d %10d %s\n", - p->major, n, p->sizes[n], - disk_name(p, n, buf)); + dsk->major, n, dsk->sizes[n], + disk_name(dsk, n, buf)); + if (len < offset) + offset -= len, len = 0; + else if (len >= offset + count) + goto leave_loops; } - } } - return len; +leave_loops: + *start = page + offset; + len -= offset; + if (len < 0) + len = 0; + return len > count ? count : len; } #endif diff -u --recursive --new-file v2.4.0-test7/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.4.0-test7/linux/fs/proc/array.c Wed Aug 23 18:36:38 2000 +++ linux/fs/proc/array.c Fri Sep 1 14:32:17 2000 @@ -241,7 +241,7 @@ sigset_t ign, catch; buffer += sprintf(buffer, "SigPnd:\t"); - buffer = render_sigset_t(&p->signal, buffer); + buffer = render_sigset_t(&p->pending.signal, buffer); *buffer++ = '\n'; buffer += sprintf(buffer, "SigBlk:\t"); buffer = render_sigset_t(&p->blocked, buffer); @@ -382,7 +382,7 @@ * It must be decimal for Linux 2.0 compatibility. * Use /proc/#/status for real-time signals. */ - task->signal .sig[0] & 0x7fffffffUL, + task->pending.signal.sig[0] & 0x7fffffffUL, task->blocked.sig[0] & 0x7fffffffUL, sigign .sig[0] & 0x7fffffffUL, sigcatch .sig[0] & 0x7fffffffUL, diff -u --recursive --new-file v2.4.0-test7/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c --- v2.4.0-test7/linux/fs/proc/proc_misc.c Thu Jul 27 17:38:02 2000 +++ linux/fs/proc/proc_misc.c Mon Aug 28 21:29:17 2000 @@ -56,7 +56,7 @@ extern int get_ksyms_list(char *, char **, off_t, int); #endif extern int get_device_list(char *); -extern int get_partition_list(char *); +extern int get_partition_list(char *, char **, off_t, int); extern int get_filesystem_list(char *); extern int get_filesystem_info(char *); extern int get_exec_domain_list(char *); @@ -375,12 +375,8 @@ static int partitions_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { - int len = get_partition_list(page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; + int len = get_partition_list(page, start, off, count); + if (len < count) *eof = 1; return len; } diff -u --recursive --new-file v2.4.0-test7/linux/fs/qnx4/bitmap.c linux/fs/qnx4/bitmap.c --- v2.4.0-test7/linux/fs/qnx4/bitmap.c Fri Jun 23 21:55:10 2000 +++ linux/fs/qnx4/bitmap.c Tue Sep 5 14:07:30 2000 @@ -134,7 +134,7 @@ } else { (*g) |= (1 << (block % 8)); } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); return 0; diff -u --recursive --new-file v2.4.0-test7/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c --- v2.4.0-test7/linux/fs/qnx4/inode.c Thu Jul 27 17:38:02 2000 +++ linux/fs/qnx4/inode.c Tue Sep 5 14:07:30 2000 @@ -112,7 +112,7 @@ raw_inode->di_atime = cpu_to_le32(inode->i_atime); raw_inode->di_ctime = cpu_to_le32(inode->i_ctime); raw_inode->di_first_xtnt.xtnt_size = cpu_to_le32(inode->i_blocks); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); unlock_kernel(); } @@ -149,7 +149,7 @@ if (*flags & MS_RDONLY) { return 0; } - mark_buffer_dirty(qs->sb_buf, 1); + mark_buffer_dirty(qs->sb_buf); return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/fs/qnx4/namei.c linux/fs/qnx4/namei.c --- v2.4.0-test7/linux/fs/qnx4/namei.c Tue May 23 15:31:36 2000 +++ linux/fs/qnx4/namei.c Tue Sep 5 14:07:30 2000 @@ -178,7 +178,7 @@ de->di_status = 0; memset(de->di_fname, 0, sizeof de->di_fname); de->di_mode = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); inode->i_nlink = 0; mark_inode_dirty(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; @@ -221,7 +221,7 @@ de->di_status = 0; memset(de->di_fname, 0, sizeof de->di_fname); de->di_mode = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); inode->i_nlink--; diff -u --recursive --new-file v2.4.0-test7/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v2.4.0-test7/linux/fs/smbfs/inode.c Wed Aug 23 18:36:38 2000 +++ linux/fs/smbfs/inode.c Mon Aug 28 12:50:58 2000 @@ -445,7 +445,7 @@ memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, SMB_NLS_MAXNAMELEN); - strncpy(mnt->codepage.local_name, CONFIG_SMB_NLS_REMOTE, + strncpy(mnt->codepage.remote_name, CONFIG_SMB_NLS_REMOTE, SMB_NLS_MAXNAMELEN); if (ver == SMB_MOUNT_OLDVERSION) { diff -u --recursive --new-file v2.4.0-test7/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c --- v2.4.0-test7/linux/fs/smbfs/sock.c Wed Aug 23 18:36:38 2000 +++ linux/fs/smbfs/sock.c Sun Sep 3 11:46:40 2000 @@ -641,7 +641,7 @@ DEBUG1("len = %d cmd = 0x%X\n", len, buffer[8]); spin_lock_irqsave(¤t->sigmask_lock, flags); - sigpipe = sigismember(¤t->signal, SIGPIPE); + sigpipe = sigismember(¤t->pending.signal, SIGPIPE); old_set = current->blocked; siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); recalc_sigpending(current); @@ -659,7 +659,7 @@ /* read/write errors are handled by errno */ spin_lock_irqsave(¤t->sigmask_lock, flags); if (result == -EPIPE && !sigpipe) - sigdelset(¤t->signal, SIGPIPE); + sigdelset(¤t->pending.signal, SIGPIPE); current->blocked = old_set; recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); @@ -821,7 +821,7 @@ goto bad_conn; spin_lock_irqsave(¤t->sigmask_lock, flags); - sigpipe = sigismember(¤t->signal, SIGPIPE); + sigpipe = sigismember(¤t->pending.signal, SIGPIPE); old_set = current->blocked; siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); recalc_sigpending(current); @@ -841,7 +841,7 @@ /* read/write errors are handled by errno */ spin_lock_irqsave(¤t->sigmask_lock, flags); if (result == -EPIPE && !sigpipe) - sigdelset(¤t->signal, SIGPIPE); + sigdelset(¤t->pending.signal, SIGPIPE); current->blocked = old_set; recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); diff -u --recursive --new-file v2.4.0-test7/linux/fs/sysv/balloc.c linux/fs/sysv/balloc.c --- v2.4.0-test7/linux/fs/sysv/balloc.c Tue Jun 29 09:22:08 1999 +++ linux/fs/sysv/balloc.c Tue Sep 5 14:07:30 2000 @@ -83,7 +83,7 @@ } *flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */ memcpy(flc_blocks, sb->sv_sb_flc_blocks, *flc_count * sizeof(sysv_zone_t)); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); mark_buffer_uptodate(bh, 1); brelse(bh); *sb->sv_sb_flc_count = 0; @@ -100,7 +100,7 @@ } memset(bh->b_data, 0, sb->sv_block_size); /* this implies ((struct ..._freelist_chunk *) bh->b_data)->flc_count = 0; */ - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); mark_buffer_uptodate(bh, 1); brelse(bh); /* still *sb->sv_sb_flc_count = 0 */ @@ -119,8 +119,8 @@ to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) + 1); else *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks + 1; - mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */ - if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1); + mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */ + if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2); sb->s_dirt = 1; /* and needs time stamp */ unlock_super(sb); } @@ -207,7 +207,7 @@ return 0; } memset(bh->b_data, 0, sb->sv_block_size); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); mark_buffer_uptodate(bh, 1); brelse(bh); if (sb->sv_convert) @@ -215,8 +215,8 @@ to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) - 1); else *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks - 1; - mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */ - if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1); + mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */ + if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2); sb->s_dirt = 1; /* and needs time stamp */ unlock_super(sb); return block; @@ -311,7 +311,7 @@ printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count); if (!(sb->s_flags & MS_RDONLY)) { *sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count); - mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */ + mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ } } diff -u --recursive --new-file v2.4.0-test7/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c --- v2.4.0-test7/linux/fs/sysv/ialloc.c Mon Jul 10 16:47:26 2000 +++ linux/fs/sysv/ialloc.c Tue Sep 5 14:07:30 2000 @@ -74,11 +74,11 @@ if (*sb->sv_sb_fic_count < sb->sv_fic_size) *sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)++) = ino; (*sb->sv_sb_total_free_inodes)++; - mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */ - if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1); + mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */ + if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2); sb->s_dirt = 1; /* and needs time stamp */ memset(raw_inode, 0, sizeof(struct sysv_inode)); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); unlock_super(sb); brelse(bh); } @@ -128,8 +128,8 @@ } /* Now *sb->sv_sb_fic_count > 0. */ ino = *sv_sb_fic_inode(sb,--(*sb->sv_sb_fic_count)); - mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */ - if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1); + mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */ + if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2); sb->s_dirt = 1; /* and needs time stamp */ inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; @@ -147,7 +147,7 @@ mark_inode_dirty(inode); /* cleared by sysv_write_inode() */ /* That's it. */ (*sb->sv_sb_total_free_inodes)--; - mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified again */ + mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified again */ sb->s_dirt = 1; /* and needs time stamp again */ unlock_super(sb); return inode; @@ -185,7 +185,7 @@ printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count); if (!(sb->s_flags & MS_RDONLY)) { *sb->sv_sb_total_free_inodes = count; - mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */ + mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ } } diff -u --recursive --new-file v2.4.0-test7/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.4.0-test7/linux/fs/sysv/inode.c Thu Jul 27 17:38:02 2000 +++ linux/fs/sysv/inode.c Tue Sep 5 14:07:30 2000 @@ -532,7 +532,7 @@ if (sb->sv_convert) time = to_coh_ulong(time); *sb->sv_sb_time = time; - mark_buffer_dirty(sb->sv_bh2, 1); + mark_buffer_dirty(sb->sv_bh2); } sb->s_dirt = 0; } @@ -769,7 +769,7 @@ } memset(result->b_data, 0, sb->sv_block_size); mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result, 1); + mark_buffer_dirty(result); } else { *phys = tmp; *new = 1; @@ -780,7 +780,7 @@ goto repeat; } *p = (sb->sv_convert ? to_coh_ulong(block) : block); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); *err = 0; out: brelse(bh); @@ -894,7 +894,7 @@ if (buffer_new(&dummy)) { memset(bh->b_data, 0, inode->i_sb->sv_block_size); mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } return bh; } @@ -1126,7 +1126,7 @@ else for (block = 0; block < 10+1+1+1; block++) write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); return bh; } diff -u --recursive --new-file v2.4.0-test7/linux/fs/sysv/namei.c linux/fs/sysv/namei.c --- v2.4.0-test7/linux/fs/sysv/namei.c Fri Jun 23 21:55:11 2000 +++ linux/fs/sysv/namei.c Tue Sep 5 14:07:30 2000 @@ -179,7 +179,7 @@ mark_inode_dirty(dir); for (i = 0; i < SYSV_NAMELEN ; i++) de->name[i] = (i < namelen) ? name[i] : 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); *res_dir = de; break; } @@ -217,7 +217,7 @@ return error; } de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); d_instantiate(dentry, inode); return 0; @@ -251,7 +251,7 @@ return error; } de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); d_instantiate(dentry, inode); return 0; @@ -292,7 +292,7 @@ de->inode = dir->i_ino; strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */ inode->i_nlink = 2; - mark_buffer_dirty(dir_block, 1); + mark_buffer_dirty(dir_block); brelse(dir_block); inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) @@ -306,7 +306,7 @@ return error; } de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); dir->i_nlink++; mark_inode_dirty(dir); brelse(bh); @@ -392,7 +392,7 @@ if (inode->i_nlink != 2) printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink); de->inode = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); inode->i_nlink=0; dir->i_nlink--; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; @@ -422,7 +422,7 @@ inode->i_nlink=1; } de->inode = 0; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); inode->i_nlink--; @@ -463,7 +463,7 @@ if (err) goto out_no_entry; de->inode = inode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); d_instantiate(dentry, inode); out: @@ -502,7 +502,7 @@ return error; } de->inode = oldinode->i_ino; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); brelse(bh); oldinode->i_nlink++; oldinode->i_ctime = CURRENT_TIME; @@ -578,11 +578,11 @@ new_inode->i_ctime = CURRENT_TIME; mark_inode_dirty(new_inode); } - mark_buffer_dirty(old_bh, 1); - mark_buffer_dirty(new_bh, 1); + mark_buffer_dirty(old_bh); + mark_buffer_dirty(new_bh); if (dir_bh) { PARENT_INO(dir_bh->b_data) = new_dir->i_ino; - mark_buffer_dirty(dir_bh, 1); + mark_buffer_dirty(dir_bh); old_dir->i_nlink--; mark_inode_dirty(old_dir); if (new_inode) { diff -u --recursive --new-file v2.4.0-test7/linux/fs/sysv/truncate.c linux/fs/sysv/truncate.c --- v2.4.0-test7/linux/fs/sysv/truncate.c Tue Dec 7 09:32:48 1999 +++ linux/fs/sysv/truncate.c Tue Sep 5 14:07:30 2000 @@ -124,7 +124,7 @@ continue; } *ind = 0; - mark_buffer_dirty(indbh, 1); + mark_buffer_dirty(indbh); brelse(bh); sysv_free_block(sb,block); } @@ -183,7 +183,7 @@ continue; retry |= trunc_indirect(inode,offset+(i<sv_ind_per_block_bits),ind,sb->sv_convert,&dirty); if (dirty) - mark_buffer_dirty(indbh, 1); + mark_buffer_dirty(indbh); } for (i = 0; i < sb->sv_ind_per_block; i++) if (((sysv_zone_t *) indbh->b_data)[i]) @@ -240,7 +240,7 @@ continue; retry |= trunc_dindirect(inode,offset+(i<sv_ind_per_block_2_bits),ind,sb->sv_convert,&dirty); if (dirty) - mark_buffer_dirty(indbh, 1); + mark_buffer_dirty(indbh); } for (i = 0; i < sb->sv_ind_per_block; i++) if (((sysv_zone_t *) indbh->b_data)[i]) diff -u --recursive --new-file v2.4.0-test7/linux/fs/udf/balloc.c linux/fs/udf/balloc.c --- v2.4.0-test7/linux/fs/udf/balloc.c Mon Mar 27 08:08:30 2000 +++ linux/fs/udf/balloc.c Tue Sep 5 14:07:30 2000 @@ -268,7 +268,7 @@ } } } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (overflow) { block += count; @@ -278,7 +278,7 @@ error_return: sb->s_dirt = 1; if (UDF_SB_LVIDBH(sb)) - mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(sb)); unlock_super(sb); return; } @@ -334,7 +334,7 @@ bit ++; block ++; } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (block_count > 0) goto repeat; out: @@ -342,7 +342,7 @@ { UDF_SB_LVID(sb)->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count); - mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(sb)); } sb->s_dirt = 1; unlock_super(sb); @@ -478,13 +478,13 @@ goto repeat; } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (UDF_SB_LVIDBH(sb)) { UDF_SB_LVID(sb)->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1); - mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(sb)); } sb->s_dirt = 1; unlock_super(sb); diff -u --recursive --new-file v2.4.0-test7/linux/fs/udf/file.c linux/fs/udf/file.c --- v2.4.0-test7/linux/fs/udf/file.c Wed Aug 9 19:19:51 2000 +++ linux/fs/udf/file.c Tue Sep 5 14:07:30 2000 @@ -82,7 +82,7 @@ block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0); bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize); memcpy(bh->b_data + udf_ext0_offset(inode), kaddr, inode->i_size); - mark_buffer_dirty(bh, 0); + mark_buffer_dirty(bh); brelse(bh); SetPageUptodate(page); kunmap(page); @@ -107,7 +107,7 @@ bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize); memcpy(bh->b_data + udf_file_entry_alloc_offset(inode) + offset, kaddr + offset, to-offset); - mark_buffer_dirty(bh, 0); + mark_buffer_dirty(bh); brelse(bh); SetPageUptodate(page); kunmap(page); diff -u --recursive --new-file v2.4.0-test7/linux/fs/udf/ialloc.c linux/fs/udf/ialloc.c --- v2.4.0-test7/linux/fs/udf/ialloc.c Fri Jun 23 21:55:11 2000 +++ linux/fs/udf/ialloc.c Tue Sep 5 14:07:30 2000 @@ -62,7 +62,7 @@ UDF_SB_LVIDIU(sb)->numFiles = cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1); - mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(sb)); } unlock_super(sb); @@ -112,7 +112,7 @@ if (!(++uniqueID & 0x00000000FFFFFFFFUL)) uniqueID += 16; lvhd->uniqueID = cpu_to_le64(uniqueID); - mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(sb)); } inode->i_mode = mode; inode->i_sb = sb; diff -u --recursive --new-file v2.4.0-test7/linux/fs/udf/inode.c linux/fs/udf/inode.c --- v2.4.0-test7/linux/fs/udf/inode.c Wed Aug 9 19:19:51 2000 +++ linux/fs/udf/inode.c Tue Sep 5 14:07:30 2000 @@ -200,7 +200,7 @@ else UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG; inode->i_blocks = inode->i_sb->s_blocksize / 512; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); udf_release_data(bh); inode->i_data.a_ops->writepage(NULL, page); @@ -276,7 +276,7 @@ return NULL; } } - mark_buffer_dirty(dbh, 1); + mark_buffer_dirty(dbh); memset(sbh->b_data + udf_file_entry_alloc_offset(inode), 0, UDF_I_LENALLOC(inode)); @@ -295,7 +295,7 @@ /* UniqueID stuff */ inode->i_blocks = inode->i_sb->s_blocksize / 512; - mark_buffer_dirty(sbh, 1); + mark_buffer_dirty(sbh); udf_release_data(sbh); mark_inode_dirty(inode); inode->i_version ++; @@ -379,7 +379,7 @@ wait_on_buffer(bh); memset(bh->b_data, 0x00, inode->i_sb->s_blocksize); mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } return bh; } @@ -1294,7 +1294,7 @@ eid->identSuffix[1] = UDF_OS_ID_LINUX; dsea->majorDeviceIdent = kdev_t_to_nr(inode->i_rdev) >> 8; dsea->minorDeviceIdent = kdev_t_to_nr(inode->i_rdev) & 0xFF; - mark_buffer_dirty(tbh, 1); + mark_buffer_dirty(tbh); udf_release_data(tbh); } @@ -1387,7 +1387,7 @@ fe->descTag.tagChecksum += ((Uint8 *)&(fe->descTag))[i]; /* write the data blocks */ - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (do_sync) { ll_rw_block(WRITE, 1, &bh); @@ -1557,7 +1557,7 @@ } } udf_update_tag((*bh)->b_data, loffset); - mark_buffer_dirty(*bh, 1); + mark_buffer_dirty(*bh); udf_release_data(*bh); *bh = nbh; } @@ -1575,7 +1575,7 @@ aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize)); - mark_buffer_dirty(*bh, 1); + mark_buffer_dirty(*bh); } return ret; @@ -1634,7 +1634,7 @@ else mark_inode_dirty(inode); - mark_buffer_dirty(*bh, 1); + mark_buffer_dirty(*bh); if (inc) *extoffset += adsize; @@ -1932,7 +1932,7 @@ aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize)); udf_update_tag((obh)->b_data, oextoffset - (2*adsize)); - mark_buffer_dirty(obh, 1); + mark_buffer_dirty(obh); } } else @@ -1949,7 +1949,7 @@ aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize); udf_update_tag((obh)->b_data, oextoffset - adsize); - mark_buffer_dirty(obh, 1); + mark_buffer_dirty(obh); } } diff -u --recursive --new-file v2.4.0-test7/linux/fs/udf/namei.c linux/fs/udf/namei.c --- v2.4.0-test7/linux/fs/udf/namei.c Fri Jun 23 21:55:11 2000 +++ linux/fs/udf/namei.c Tue Sep 5 14:07:30 2000 @@ -133,8 +133,8 @@ } if (fibh->sbh != fibh->ebh) - mark_buffer_dirty(fibh->ebh, 1); - mark_buffer_dirty(fibh->sbh, 1); + mark_buffer_dirty(fibh->ebh); + mark_buffer_dirty(fibh->sbh); return 0; } @@ -1040,7 +1040,7 @@ if (!(++uniqueID & 0x00000000FFFFFFFFUL)) uniqueID += 16; lvhd->uniqueID = cpu_to_le64(uniqueID); - mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb)); } udf_write_fi(&cfi, fi, &fibh, NULL, NULL); if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) @@ -1093,7 +1093,7 @@ if (!(++uniqueID & 0x00000000FFFFFFFFUL)) uniqueID += 16; lvhd->uniqueID = cpu_to_le64(uniqueID); - mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb)); } udf_write_fi(&cfi, fi, &fibh, NULL, NULL); if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) @@ -1224,7 +1224,7 @@ old_inode->i_version = ++event; } else - mark_buffer_dirty(dir_bh, 1); + mark_buffer_dirty(dir_bh); old_dir->i_nlink --; mark_inode_dirty(old_dir); if (new_inode) diff -u --recursive --new-file v2.4.0-test7/linux/fs/udf/super.c linux/fs/udf/super.c --- v2.4.0-test7/linux/fs/udf/super.c Mon Jul 10 16:47:26 2000 +++ linux/fs/udf/super.c Tue Sep 5 14:07:30 2000 @@ -1219,7 +1219,7 @@ UDF_SB_LVID(sb)->descTag.tagChecksum += ((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i]; - mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(sb)); sb->s_dirt = 0; } } @@ -1254,7 +1254,7 @@ UDF_SB_LVID(sb)->descTag.tagChecksum += ((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i]; - mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + mark_buffer_dirty(UDF_SB_LVIDBH(sb)); } } diff -u --recursive --new-file v2.4.0-test7/linux/fs/udf/truncate.c linux/fs/udf/truncate.c --- v2.4.0-test7/linux/fs/udf/truncate.c Thu Mar 2 14:36:23 2000 +++ linux/fs/udf/truncate.c Tue Sep 5 14:07:30 2000 @@ -124,7 +124,7 @@ aed->lengthAllocDescs = cpu_to_le32(lenalloc); udf_update_tag(bh->b_data, lenalloc + sizeof(struct AllocExtDesc)); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } } @@ -166,7 +166,7 @@ aed->lengthAllocDescs = cpu_to_le32(lenalloc); udf_update_tag(bh->b_data, lenalloc + sizeof(struct AllocExtDesc)); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } } } diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/balloc.c linux/fs/ufs/balloc.c --- v2.4.0-test7/linux/fs/ufs/balloc.c Thu Nov 11 20:11:51 1999 +++ linux/fs/ufs/balloc.c Tue Sep 5 14:07:30 2000 @@ -110,8 +110,8 @@ INC_SWAB32(ubh_cg_blktot (ucpi, cylno)); } - ubh_mark_buffer_dirty (USPI_UBH, 1); - ubh_mark_buffer_dirty (UCPI_UBH, 1); + ubh_mark_buffer_dirty (USPI_UBH); + ubh_mark_buffer_dirty (UCPI_UBH); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); ubh_wait_on_buffer (UCPI_UBH); @@ -196,8 +196,8 @@ INC_SWAB32(ubh_cg_blktot(ucpi, cylno)); } - ubh_mark_buffer_dirty (USPI_UBH, 1); - ubh_mark_buffer_dirty (UCPI_UBH, 1); + ubh_mark_buffer_dirty (USPI_UBH); + ubh_mark_buffer_dirty (UCPI_UBH); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); ubh_wait_on_buffer (UCPI_UBH); @@ -227,7 +227,7 @@ bh = getblk (sb->s_dev, result + i, sb->s_blocksize); \ memset (bh->b_data, 0, sb->s_blocksize); \ mark_buffer_uptodate(bh, 1); \ - mark_buffer_dirty (bh, 1); \ + mark_buffer_dirty (bh); \ if (IS_SYNC(inode)) { \ ll_rw_block (WRITE, 1, &bh); \ wait_on_buffer (bh); \ @@ -364,7 +364,7 @@ { mark_buffer_clean (bh); bh->b_blocknr = result + i; - mark_buffer_dirty (bh, 0); + mark_buffer_dirty (bh); if (IS_SYNC(inode)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -458,8 +458,8 @@ SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count); SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count); - ubh_mark_buffer_dirty (USPI_UBH, 1); - ubh_mark_buffer_dirty (UCPI_UBH, 1); + ubh_mark_buffer_dirty (USPI_UBH); + ubh_mark_buffer_dirty (UCPI_UBH); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); ubh_wait_on_buffer (UCPI_UBH); @@ -582,8 +582,8 @@ INC_SWAB32(ucg->cg_frsum[allocsize - count]); succed: - ubh_mark_buffer_dirty (USPI_UBH, 1); - ubh_mark_buffer_dirty (UCPI_UBH, 1); + ubh_mark_buffer_dirty (USPI_UBH); + ubh_mark_buffer_dirty (UCPI_UBH); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); ubh_wait_on_buffer (UCPI_UBH); diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/cylinder.c linux/fs/ufs/cylinder.c --- v2.4.0-test7/linux/fs/ufs/cylinder.c Sun Jan 17 18:32:26 1999 +++ linux/fs/ufs/cylinder.c Tue Sep 5 14:07:30 2000 @@ -119,7 +119,7 @@ ucg->cg_rotor = SWAB32(ucpi->c_rotor); ucg->cg_frotor = SWAB32(ucpi->c_frotor); ucg->cg_irotor = SWAB32(ucpi->c_irotor); - ubh_mark_buffer_dirty (UCPI_UBH, 1); + ubh_mark_buffer_dirty (UCPI_UBH); for (i = 1; i < UCPI_UBH->count; i++) { brelse (UCPI_UBH->bh[i]); } diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/ialloc.c linux/fs/ufs/ialloc.c --- v2.4.0-test7/linux/fs/ufs/ialloc.c Mon Jul 10 16:47:26 2000 +++ linux/fs/ufs/ialloc.c Tue Sep 5 14:07:30 2000 @@ -121,8 +121,8 @@ DEC_SWAB32(sb->fs_cs(cg).cs_ndir); } } - ubh_mark_buffer_dirty (USPI_UBH, 1); - ubh_mark_buffer_dirty (UCPI_UBH, 1); + ubh_mark_buffer_dirty (USPI_UBH); + ubh_mark_buffer_dirty (UCPI_UBH); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi); ubh_wait_on_buffer (UCPI_UBH); @@ -252,8 +252,8 @@ INC_SWAB32(sb->fs_cs(cg).cs_ndir); } - ubh_mark_buffer_dirty (USPI_UBH, 1); - ubh_mark_buffer_dirty (UCPI_UBH, 1); + ubh_mark_buffer_dirty (USPI_UBH); + ubh_mark_buffer_dirty (UCPI_UBH); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi); ubh_wait_on_buffer (UCPI_UBH); diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/inode.c linux/fs/ufs/inode.c --- v2.4.0-test7/linux/fs/ufs/inode.c Thu Jul 27 17:38:02 2000 +++ linux/fs/ufs/inode.c Tue Sep 5 14:07:30 2000 @@ -360,7 +360,7 @@ *new = 1; } - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(inode)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -493,7 +493,7 @@ if (buffer_new(&dummy)) { memset(bh->b_data, 0, inode->i_sb->s_blocksize); mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); } return bh; } @@ -711,7 +711,7 @@ if (!inode->i_nlink) memset (ufs_inode, 0, sizeof(struct ufs_inode)); - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (do_sync) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/namei.c linux/fs/ufs/namei.c --- v2.4.0-test7/linux/fs/ufs/namei.c Fri Jun 23 21:55:11 2000 +++ linux/fs/ufs/namei.c Tue Sep 5 14:07:30 2000 @@ -321,7 +321,7 @@ dir->i_mtime = dir->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); *res_dir = de; *err = 0; @@ -428,7 +428,7 @@ de->d_ino = SWAB32(inode->i_ino); ufs_set_de_type (de, inode->i_mode); dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -467,7 +467,7 @@ de->d_ino = SWAB32(inode->i_ino); ufs_set_de_type (de, inode->i_mode); dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -530,7 +530,7 @@ ufs_set_de_namlen(de,2); strcpy (de->d_name, ".."); inode->i_nlink = 2; - mark_buffer_dirty(dir_block, 1); + mark_buffer_dirty(dir_block); brelse (dir_block); inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) @@ -542,7 +542,7 @@ de->d_ino = SWAB32(inode->i_ino); ufs_set_de_type (de, inode->i_mode); dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -657,7 +657,7 @@ dir->i_version = ++event; if (retval) goto end_rmdir; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -718,7 +718,7 @@ if (retval) goto end_unlink; dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -785,7 +785,7 @@ goto out_no_entry; de->d_ino = SWAB32(inode->i_ino); dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -825,7 +825,7 @@ de->d_ino = SWAB32(inode->i_ino); dir->i_version = ++event; - mark_buffer_dirty(bh, 1); + mark_buffer_dirty(bh); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -930,7 +930,7 @@ mark_inode_dirty(old_dir); if (dir_bh) { PARENT_INO(dir_bh->b_data) = SWAB32(new_dir->i_ino); - mark_buffer_dirty(dir_bh, 1); + mark_buffer_dirty(dir_bh); old_dir->i_nlink--; mark_inode_dirty(old_dir); if (new_inode) { @@ -941,13 +941,13 @@ mark_inode_dirty(new_dir); } } - mark_buffer_dirty(old_bh, 1); + mark_buffer_dirty(old_bh); if (IS_SYNC(old_dir)) { ll_rw_block (WRITE, 1, &old_bh); wait_on_buffer (old_bh); } - mark_buffer_dirty(new_bh, 1); + mark_buffer_dirty(new_bh); if (IS_SYNC(new_dir)) { ll_rw_block (WRITE, 1, &new_bh); wait_on_buffer (new_bh); diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/super.c linux/fs/ufs/super.c --- v2.4.0-test7/linux/fs/ufs/super.c Mon Jul 10 16:47:26 2000 +++ linux/fs/ufs/super.c Tue Sep 5 14:07:30 2000 @@ -192,7 +192,7 @@ if (!(sb->s_flags & MS_RDONLY)) { usb1->fs_clean = UFS_FSBAD; - ubh_mark_buffer_dirty(USPI_UBH, 1); + ubh_mark_buffer_dirty(USPI_UBH); sb->s_dirt = 1; sb->s_flags |= MS_RDONLY; } @@ -224,7 +224,7 @@ if (!(sb->s_flags & MS_RDONLY)) { usb1->fs_clean = UFS_FSBAD; - ubh_mark_buffer_dirty(USPI_UBH, 1); + ubh_mark_buffer_dirty(USPI_UBH); sb->s_dirt = 1; } va_start (args, fmt); @@ -422,7 +422,7 @@ ubh_memcpyubh (ubh, space, size); space += size; ubh_mark_buffer_uptodate (ubh, 1); - ubh_mark_buffer_dirty (ubh, 0); + ubh_mark_buffer_dirty (ubh); ubh_brelse (ubh); } for (i = 0; i < sb->u.ufs_sb.s_cg_loaded; i++) { @@ -845,7 +845,7 @@ if ((flags & UFS_ST_MASK) == UFS_ST_SUN || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(usb1, usb3, UFS_FSOK - SWAB32(usb1->fs_time)); - ubh_mark_buffer_dirty (USPI_UBH, 1); + ubh_mark_buffer_dirty (USPI_UBH); } sb->s_dirt = 0; UFSD(("EXIT\n")) @@ -915,7 +915,7 @@ if ((flags & UFS_ST_MASK) == UFS_ST_SUN || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(usb1, usb3, UFS_FSOK - SWAB32(usb1->fs_time)); - ubh_mark_buffer_dirty (USPI_UBH, 1); + ubh_mark_buffer_dirty (USPI_UBH); sb->s_dirt = 0; sb->s_flags |= MS_RDONLY; } diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/truncate.c linux/fs/ufs/truncate.c --- v2.4.0-test7/linux/fs/ufs/truncate.c Tue Dec 7 09:32:48 1999 +++ linux/fs/ufs/truncate.c Tue Sep 5 14:07:30 2000 @@ -248,7 +248,7 @@ bforget (bh); } *ind = SWAB32(0); - ubh_mark_buffer_dirty(ind_ubh, 1); + ubh_mark_buffer_dirty(ind_ubh); if (free_count == 0) { frag_to_free = tmp; free_count = uspi->s_fpb; @@ -334,7 +334,7 @@ if (!tmp) continue; retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); - ubh_mark_buffer_dirty(dind_bh, 1); + ubh_mark_buffer_dirty(dind_bh); } for (i = 0; i < uspi->s_apb; i++) @@ -400,7 +400,7 @@ tind = ubh_get_addr32 (tind_bh, i); retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); - ubh_mark_buffer_dirty(tind_bh, 1); + ubh_mark_buffer_dirty(tind_bh); } for (i = 0; i < uspi->s_apb; i++) if (SWAB32(*ubh_get_addr32 (tind_bh, i))) @@ -466,7 +466,7 @@ bh = ufs_bread (inode, inode->i_size >> uspi->s_fshift, 0, &err); if (bh) { memset (bh->b_data + offset, 0, uspi->s_fsize - offset); - mark_buffer_dirty (bh, 0); + mark_buffer_dirty (bh); brelse (bh); } } diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/util.c linux/fs/ufs/util.c --- v2.4.0-test7/linux/fs/ufs/util.c Tue Jun 29 09:22:08 1999 +++ linux/fs/ufs/util.c Tue Sep 5 14:07:30 2000 @@ -94,13 +94,13 @@ } } -void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh, int flag) +void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh) { unsigned i; if (!ubh) return; for ( i = 0; i < ubh->count; i++ ) - mark_buffer_dirty (ubh->bh[i], flag); + mark_buffer_dirty (ubh->bh[i]); } void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag) diff -u --recursive --new-file v2.4.0-test7/linux/fs/ufs/util.h linux/fs/ufs/util.h --- v2.4.0-test7/linux/fs/ufs/util.h Thu Nov 11 20:11:51 1999 +++ linux/fs/ufs/util.h Tue Sep 5 14:07:30 2000 @@ -212,7 +212,7 @@ extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned); extern void ubh_brelse (struct ufs_buffer_head *); extern void ubh_brelse_uspi (struct ufs_sb_private_info *); -extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *, int); +extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *); extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int); extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **); extern void ubh_wait_on_buffer (struct ufs_buffer_head *); diff -u --recursive --new-file v2.4.0-test7/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v2.4.0-test7/linux/fs/umsdos/dir.c Wed Aug 23 18:36:39 2000 +++ linux/fs/umsdos/dir.c Tue Sep 5 14:05:45 2000 @@ -68,7 +68,8 @@ const char *name, int len, off_t offset, - ino_t ino) + ino_t ino, + unsigned type) { int ret = -EINVAL; struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf; diff -u --recursive --new-file v2.4.0-test7/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c --- v2.4.0-test7/linux/fs/umsdos/emd.c Wed Aug 9 19:19:51 2000 +++ linux/fs/umsdos/emd.c Tue Sep 5 14:05:45 2000 @@ -142,7 +142,7 @@ recsize = umsdos_evalrecsize(p->name_len); if (offs + recsize > PAGE_CACHE_SIZE) { struct page *page2; - int part = (page_address(page) + PAGE_CACHE_SIZE) - p->spare; + int part = (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare; page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT), (filler_t*)mapping->a_ops->readpage, NULL); if (IS_ERR(page2)) { @@ -261,7 +261,7 @@ p->rdev = cpu_to_le16(entry->rdev); p->mode = cpu_to_le16(entry->mode); memcpy(p->name,entry->name, - (page_address(page) + PAGE_CACHE_SIZE) - p->spare); + (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare); memcpy(page_address(page2), entry->spare+PAGE_CACHE_SIZE-offs, offs+info->recsize-PAGE_CACHE_SIZE); @@ -505,7 +505,7 @@ struct dentry *demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); - if (IS_ERR(ret)) + if (IS_ERR(demd)) goto out; err = umsdos_find (demd, info); if (err && err == -ENOENT) { @@ -532,7 +532,7 @@ int ret; struct dentry *demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); - if (IS_ERR(ret)) + if (IS_ERR(demd)) goto out; umsdos_parse ("..LINK", 6, info); @@ -561,7 +561,7 @@ struct dentry *demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); - if (IS_ERR(ret)) + if (IS_ERR(demd)) goto out; ret = umsdos_find (demd, info); if (ret) @@ -642,7 +642,7 @@ struct dentry *demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); - if (IS_ERR(ret)) + if (IS_ERR(demd)) goto out; ret = umsdos_find (demd, info); if (ret) diff -u --recursive --new-file v2.4.0-test7/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c --- v2.4.0-test7/linux/fs/umsdos/ioctl.c Wed Aug 9 19:19:51 2000 +++ linux/fs/umsdos/ioctl.c Tue Sep 5 14:05:46 2000 @@ -29,7 +29,8 @@ const char *name, int name_len, off_t offset, - ino_t ino) + ino_t ino, + unsigned type) { int ret = -EINVAL; struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf; diff -u --recursive --new-file v2.4.0-test7/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.4.0-test7/linux/fs/vfat/namei.c Wed Aug 9 19:19:51 2000 +++ linux/fs/vfat/namei.c Tue Sep 5 14:07:29 2000 @@ -973,7 +973,7 @@ goto cleanup; } memcpy(*de, ps, sizeof(struct msdos_dir_slot)); - fat_mark_buffer_dirty(sb, *bh, 1); + fat_mark_buffer_dirty(sb, *bh); } dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; @@ -990,7 +990,7 @@ (*de)->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT; - fat_mark_buffer_dirty(sb, *bh, 1); + fat_mark_buffer_dirty(sb, *bh); /* slots can't be less than 1 */ sinfo_out->long_slots = slots - 1; @@ -1106,7 +1106,7 @@ dir->i_version = ++event; mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); /* remove the longname */ offset = sinfo->longname_offset; de = NULL; for (i = sinfo->long_slots; i > 0; --i) { @@ -1114,7 +1114,7 @@ continue; de->name[0] = DELETED_FLAG; de->attr = 0; - fat_mark_buffer_dirty(sb, bh, 1); + fat_mark_buffer_dirty(sb, bh); } if (bh) fat_brelse(sb, bh); } @@ -1276,7 +1276,7 @@ int start = MSDOS_I(new_dir)->i_logstart; dotdot_de->start = CT_LE_W(start); dotdot_de->starthi = CT_LE_W(start>>16); - fat_mark_buffer_dirty(sb, dotdot_bh, 1); + fat_mark_buffer_dirty(sb, dotdot_bh); old_dir->i_nlink--; if (new_inode) { new_inode->i_nlink--; diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h --- v2.4.0-test7/linux/include/asm-alpha/bitops.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-alpha/bitops.h Mon Aug 28 21:21:57 2000 @@ -175,13 +175,10 @@ extern inline unsigned long ffz(unsigned long word) { -#if 0 && defined(__alpha_cix__) - /* Swine architects -- a year after they publish v3 of the - handbook, in the 21264 data sheet they quietly change CIX - to FIX and remove the spiffy counting instructions. */ +#if defined(__alpha_cix__) && defined(__alpha_fix__) /* Whee. EV6 can calculate it directly. */ unsigned long result; - __asm__("ctlz %1,%0" : "=r"(result) : "r"(~word)); + __asm__("cttz %1,%0" : "=r"(result) : "r"(~word)); return result; #else unsigned long bits, qofs, bofs; @@ -214,10 +211,7 @@ * of bits set) of a N-bit word */ -#if 0 && defined(__alpha_cix__) -/* Swine architects -- a year after they publish v3 of the handbook, in - the 21264 data sheet they quietly change CIX to FIX and remove the - spiffy counting instructions. */ +#if defined(__alpha_cix__) && defined(__alpha_fix__) /* Whee. EV6 can calculate it directly. */ extern __inline__ unsigned long hweight64(unsigned long w) { diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-alpha/core_irongate.h linux/include/asm-alpha/core_irongate.h --- v2.4.0-test7/linux/include/asm-alpha/core_irongate.h Sun Mar 19 18:35:31 2000 +++ linux/include/asm-alpha/core_irongate.h Mon Aug 28 21:21:57 2000 @@ -83,247 +83,24 @@ igcsr32 agpmode; /* 0xB0 - AGP/GART mode control */ } Irongate0; -/* Bitfield and mask register definitions */ -/* Device, vendor IDs - offset 0x00 */ +typedef struct { -typedef union { - igcsr32 i; /* integer value of CSR */ - struct { - unsigned v : 16; - unsigned d : 16; - } r; /* structured interpretation */ -} ig_dev_vendor_t; - - -/* Status, command registers - offset 0x04 */ - -typedef union { - igcsr32 i; - struct { - unsigned command; - unsigned status; - } s; - struct { - /* command register fields */ - unsigned iospc : 1; /* always reads zero */ - unsigned memspc : 1; /* PCI memory space accesses? */ - unsigned iten : 1; /* always 1: can be bus initiator */ - unsigned scmon : 1; /* always 0 special cycles not chckd */ - unsigned mwic : 1; /* always 0 - no mem write & invalid */ - unsigned vgaps : 1; /* always 0 - palette rds not special */ - unsigned per : 1; /* parity error resp: always 0 */ - unsigned step : 1; /* address/data stepping : always 0 */ - unsigned serre : 1; /* 1 = sys err output driver enable */ - unsigned fbbce : 1; /* fast back-back cycle : always 0 */ - unsigned zero1 : 6; /* must be zero */ - - /* status register fields */ - unsigned zero2 : 4; /* must be zero */ - unsigned cl : 1; /* config space capa list: always 1 */ - unsigned pci66 : 1; /* 66 MHz PCI support - always 0 */ - unsigned udf : 1; /* user defined features - always 0 */ - unsigned fbbc : 1; /* back-back transactions - always 0 */ - unsigned ppe : 1; /* PCI parity error detected (0) */ - unsigned devsel : 2; /* DEVSEL timing (always 01) */ - unsigned sta : 1; /* signalled target abort (0) */ - unsigned rta : 1; /* recvd target abort */ - unsigned ria : 1; /* recvd initiator abort */ - unsigned serr : 1; /* SERR has been asserted */ - unsigned dpe : 1; /* DRAM parity error (0) */ - } r; -} ig_stat_cmd_t; - - -/* Revision ID, Programming interface, subclass, baseclass - offset 0x08 */ - -typedef union { - igcsr32 i; - struct { - /* revision ID */ - unsigned step : 4; /* stepping Revision ID */ - unsigned die : 4; /* die Revision ID */ - unsigned pif : 8; /* programming interface (0x00) */ - unsigned sub : 8; /* subclass code (0x00) */ - unsigned base: 8; /* baseclass code (0x06) */ - } r; -} ig_class_t; - - -/* Latency Timer, PCI Header type - offset 0x0C */ - -typedef union { - igcsr32 i; - struct { - unsigned zero1:8; /* reserved */ - unsigned lat : 8; /* latency in PCI bus clocks */ - unsigned hdr : 8; /* PCI header type */ - unsigned zero2:8; /* reserved */ - } r; -} ig_latency_t; - - -/* Base Address Register 0 - offset 0x10 */ - -typedef union { - igcsr32 i; - struct { - unsigned mem : 1; /* Reg pts to memory (always 0) */ - unsigned type: 2; /* 32 bit register = 0b00 */ - unsigned pref: 1; /* graphics mem prefetchable=1 */ - unsigned baddrl : 21; /* 32M = minimum alloc -> all zero */ - unsigned size : 6; /* size requirements for AGP */ - unsigned zero : 1; /* reserved=0 */ - } r; -} ig_bar0_t; - - -/* Base Address Register 1 - offset 0x14 */ - -typedef union { - igcsr32 i; - struct { - unsigned mem : 1; /* BAR0 maps to memory -> 0 */ - unsigned type : 2; /* BAR1 is 32-bit -> 0b00 */ - unsigned pref : 1; /* graphics mem prefetchable=1 */ - unsigned baddrl : 8; /* 4K alloc for AGP CSRs -> 0b00 */ - unsigned baddrh : 20; /* base addr of AGP CSRs A[30:11] */ - } r; -} ig_bar1_t; - - -/* Base Address Register 2 - offset 0x18 */ - -typedef union { - igcsr32 i; - struct { - unsigned io : 1; /* BAR2 maps to I/O space -> 1 */ - unsigned zero1: 1; /* reserved */ - unsigned addr : 22; /* BAR2[31:10] - PM2_BLK base */ - unsigned zero2: 8; /* reserved */ - } r; -} ig_bar2_t; - - -/* Capabilities Pointer - offset 0x34 */ - -typedef union { - igcsr32 i; - struct { - unsigned cap : 8; /* =0xA0, offset of AGP ctrl regs */ - unsigned zero: 24; /* reserved */ - } r; -} ig_capptr_t; - - -/* Base Address Chip Select Register 1,0 - offset 0x40 */ -/* Base Address Chip Select Register 3,2 - offset 0x44 */ -/* Base Address Chip Select Register 5,4 - offset 0x48 */ - -typedef union { - - igcsr32 i; - struct { - /* lower bank */ - unsigned en0 : 1; /* memory bank enabled */ - unsigned mask0 : 6; /* Address mask for A[28:23] */ - unsigned base0 : 9; /* Bank Base Address A[31:23] */ - - /* upper bank */ - unsigned en1 : 1; /* memory bank enabled */ - unsigned mask1 : 6; /* Address mask for A[28:23] */ - unsigned base1 : 9; /* Bank Base Address A[31:23] */ - } r; -} ig_bacsr_t, ig_bacsr10_t, ig_bacsr32_t, ig_bacsr54_t; - - -/* SDRAM Address Mapping Control Register - offset 0x50 */ - -typedef union { - igcsr32 i; - struct { - unsigned z1 : 1; /* reserved */ - unsigned bnks0: 1; /* 0->2 banks in chip select 0 */ - unsigned am0 : 1; /* row/column addressing */ - unsigned z2 : 1; /* reserved */ - - unsigned z3 : 1; /* reserved */ - unsigned bnks1: 1; /* 0->2 banks in chip select 1 */ - unsigned am1 : 1; /* row/column addressing */ - unsigned z4 : 1; /* reserved */ - - unsigned z5 : 1; /* reserved */ - unsigned bnks2: 1; /* 0->2 banks in chip select 2 */ - unsigned am2 : 1; /* row/column addressing */ - unsigned z6 : 1; /* reserved */ - - unsigned z7 : 1; /* reserved */ - unsigned bnks3: 1; /* 0->2 banks in chip select 3 */ - unsigned am3 : 1; /* row/column addressing */ - unsigned z8 : 1; /* reserved */ - - unsigned z9 : 1; /* reserved */ - unsigned bnks4: 1; /* 0->2 banks in chip select 4 */ - unsigned am4 : 1; /* row/column addressing */ - unsigned z10 : 1; /* reserved */ - - unsigned z11 : 1; /* reserved */ - unsigned bnks5: 1; /* 0->2 banks in chip select 5 */ - unsigned am5 : 1; /* row/column addressing */ - unsigned z12 : 1; /* reserved */ - - unsigned rsrvd: 8; /* reserved */ - } r; -} ig_drammap_t; - - -/* DRAM timing and driver strength register - offset 0x54 */ - -typedef union { - igcsr32 i; - struct { - /* DRAM timing parameters */ - unsigned trcd : 2; - unsigned tcl : 2; - unsigned tras: 3; - unsigned trp : 2; - unsigned trc : 3; - unsigned icl: 2; - unsigned ph : 2; - - /* Chipselect driver strength */ - unsigned adra : 1; - unsigned adrb : 1; - unsigned ctrl : 3; - unsigned dqm : 1; - unsigned cs : 1; - unsigned clk: 1; - unsigned rsrvd:8; - } r; -} ig_dramtm_t; - - -/* DRAM Mode / Status and ECC Register - offset 0x58 */ - -typedef union { - igcsr32 i; - struct { - unsigned chipsel : 6; /* failing ECC chip select */ - unsigned zero1 : 2; /* always reads zero */ - unsigned status : 2; /* ECC Detect logic status */ - unsigned zero2 : 6; /* always reads zero */ - - unsigned cycles : 2; /* cycles per refresh, see table */ - unsigned en : 1; /* ECC enable */ - unsigned r : 1; /* Large burst enable (=0) */ - unsigned bre : 1; /* Burst refresh enable */ - unsigned zero3 : 2; /* reserved = 0 */ - unsigned mwe : 1; /* Enable writes to DRAM mode reg */ - unsigned type : 1; /* SDRAM = 0, default */ - unsigned sdraminit : 1; /* SDRAM init - set params first! */ - unsigned zero4 : 6; /* reserved = 0 */ - } r; -} ig_dramms_t; + igcsr32 dev_vendor; /* 0x00 - Device and Vendor IDs */ + igcsr32 stat_cmd; /* 0x04 - Status and Command regs */ + igcsr32 class; /* 0x08 - subclass, baseclass etc */ + igcsr32 htype; /* 0x0C - header type (at 0x0E) */ + igcsr32 rsrvd0[2]; /* 0x10-0x17 reserved */ + igcsr32 busnos; /* 0x18 - Primary, secondary bus nos */ + igcsr32 io_baselim_regs; /* 0x1C - IO base, IO lim, AGP status */ + igcsr32 mem_baselim; /* 0x20 - memory base, memory lim */ + igcsr32 pfmem_baselim; /* 0x24 - prefetchable base, lim */ + igcsr32 rsrvd1[2]; /* 0x28-0x2F reserved */ + igcsr32 io_baselim; /* 0x30 - IO base, IO limit */ + igcsr32 rsrvd2[2]; /* 0x34-0x3B - reserved */ + igcsr32 interrupt; /* 0x3C - interrupt, PCI bridge ctrl */ + +} Irongate1; /* @@ -343,7 +120,21 @@ #define IRONGATE_IO (IDENT_ADDR | IRONGATE_BIAS | 0x1FC000000UL) #define IRONGATE_CONF (IDENT_ADDR | IRONGATE_BIAS | 0x1FE000000UL) -#define IRONGATE0 ((Irongate0 *) IRONGATE_CONF) +/* + * PCI Configuration space accesses are formed like so: + * + * 0x1FE << 24 | : 2 2 2 2 1 1 1 1 : 1 1 1 1 1 1 0 0 : 0 0 0 0 0 0 0 0 : + * : 3 2 1 0 9 8 7 6 : 5 4 3 2 1 0 9 8 : 7 6 5 4 3 2 1 0 : + * ---bus numer--- -device-- -fun- ---register---- + */ + +#define IGCSR(dev,fun,reg) ( IRONGATE_CONF | \ + ((dev)<<11) | \ + ((fun)<<8) | \ + (reg) ) + +#define IRONGATE0 ((Irongate0 *) IGCSR(0, 0, 0)) +#define IRONGATE1 ((Irongate1 *) IGCSR(1, 0, 0)) /* * Data structure for handling IRONGATE machine checks: diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h --- v2.4.0-test7/linux/include/asm-alpha/uaccess.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-alpha/uaccess.h Tue Aug 29 14:09:15 2000 @@ -79,24 +79,6 @@ __get_user_nocheck((x),(ptr),sizeof(*(ptr))) /* - * The "xxx_ret" versions return constant specified in third argument, if - * something bad happens. These macros can be optimized for the - * case of just returning from the function xxx_ret is used. - */ - -#define put_user_ret(x,ptr,ret) ({ \ -if (put_user(x,ptr)) return ret; }) - -#define get_user_ret(x,ptr,ret) ({ \ -if (get_user(x,ptr)) return ret; }) - -#define __put_user_ret(x,ptr,ret) ({ \ -if (__put_user(x,ptr)) return ret; }) - -#define __get_user_ret(x,ptr,ret) ({ \ -if (__get_user(x,ptr)) return ret; }) - -/* * The "lda %1, 2b-1b(%0)" bits are magic to get the assembler to * encode the bits we need for resolving the exception. See the * more extensive comments with fixup_inline_exception below for @@ -416,16 +398,6 @@ { return __copy_tofrom_user(to, from, n, from); } - -#define copy_to_user_ret(to,from,n,retval) ({ \ -if (copy_to_user(to,from,n)) \ - return retval; \ -}) - -#define copy_from_user_ret(to,from,n,retval) ({ \ -if (copy_from_user(to,from,n)) \ - return retval; \ -}) extern void __do_clear_user(void); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h --- v2.4.0-test7/linux/include/asm-arm/arch-arc/irq.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/arch-arc/irq.h Sun Sep 3 11:19:11 2000 @@ -168,5 +168,7 @@ } } + irq_mask[IRQ_KEYBOARDTX].noautoenable = 1; + init_FIQ(); } diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/arch-ebsa110/time.h linux/include/asm-arm/arch-ebsa110/time.h --- v2.4.0-test7/linux/include/asm-arm/arch-ebsa110/time.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-arm/arch-ebsa110/time.h Sun Sep 3 11:19:11 2000 @@ -46,6 +46,7 @@ #endif do_leds(); do_timer(regs); + do_profile(regs); } /* diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h --- v2.4.0-test7/linux/include/asm-arm/arch-ebsa285/hardware.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/arch-ebsa285/hardware.h Sun Sep 3 11:19:11 2000 @@ -15,20 +15,13 @@ /* Virtual Physical Size * 0xff800000 0x40000000 1MB X-Bus * 0xff000000 0x7c000000 1MB PCI I/O space - * * 0xfe000000 0x42000000 1MB CSR * 0xfd000000 0x78000000 1MB Outbound write flush (not supported) * 0xfc000000 0x79000000 1MB PCI IACK/special space - * * 0xfb000000 0x7a000000 16MB PCI Config type 1 * 0xfa000000 0x7b000000 16MB PCI Config type 0 - * * 0xf9000000 0x50000000 1MB Cache flush - * 0xf8000000 0x41000000 16MB Flash memory - * - * 0xe1000000 unmapped (to catch bad ISA/PCI) - * - * 0xe0000000 0x80000000 16MB ISA memory + * 0xf0000000 0x80000000 16MB ISA memory */ #define XBUS_SIZE 0x00100000 #define XBUS_BASE 0xff800000 @@ -54,9 +47,6 @@ #define FLUSH_SIZE 0x00100000 #define FLUSH_BASE 0xf9000000 -#define FLASH_SIZE 0x01000000 -#define FLASH_BASE 0xf8000000 - #define PCIMEM_SIZE 0x01000000 #define PCIMEM_BASE 0xf0000000 @@ -66,9 +56,6 @@ */ #define PCIMEM_SIZE 0x80000000 #define PCIMEM_BASE 0x80000000 - -#define FLASH_SIZE 0x01000000 -#define FLASH_BASE 0x7f000000 #define FLUSH_SIZE 0x00100000 #define FLUSH_BASE 0x7e000000 diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/arch-ebsa285/uncompress.h linux/include/asm-arm/arch-ebsa285/uncompress.h --- v2.4.0-test7/linux/include/asm-arm/arch-ebsa285/uncompress.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/arch-ebsa285/uncompress.h Sun Sep 3 11:19:11 2000 @@ -3,6 +3,7 @@ * * Copyright (C) 1996-1999 Russell King */ +#include /* * Note! This could cause problems on the NetWinder diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/arch-nexuspci/hardware.h linux/include/asm-arm/arch-nexuspci/hardware.h --- v2.4.0-test7/linux/include/asm-arm/arch-nexuspci/hardware.h Thu Mar 2 14:36:23 2000 +++ linux/include/asm-arm/arch-nexuspci/hardware.h Sun Sep 3 11:19:11 2000 @@ -63,4 +63,6 @@ #define INTCONT_LED 0x1a #define INTCONT_PCI_RESET 0x1c +#define UNCACHEABLE_ADDR STATUS_BASE + #endif diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/arch-nexuspci/time.h linux/include/asm-arm/arch-nexuspci/time.h --- v2.4.0-test7/linux/include/asm-arm/arch-nexuspci/time.h Thu Mar 2 14:36:23 2000 +++ linux/include/asm-arm/arch-nexuspci/time.h Sun Sep 3 11:19:11 2000 @@ -46,6 +46,7 @@ __raw_writeb(0x10, DUART_BASE + 0x14); timer_irq.handler = timer_interrupt; + timer_irq.flags = SA_SHIRQ; setup_arm_irq(IRQ_TIMER, &timer_irq); } diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/arch-nexuspci/uncompress.h linux/include/asm-arm/arch-nexuspci/uncompress.h --- v2.4.0-test7/linux/include/asm-arm/arch-nexuspci/uncompress.h Thu Mar 2 14:36:23 2000 +++ linux/include/asm-arm/arch-nexuspci/uncompress.h Sun Sep 3 11:19:11 2000 @@ -22,8 +22,11 @@ */ static void puts(const char *s) { - while (*s) + while (*s) { + if (*s == '\n') + _ll_write_char('\r'); _ll_write_char(*(s++)); + } } /* diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h --- v2.4.0-test7/linux/include/asm-arm/arch-rpc/irq.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/arch-rpc/irq.h Sun Sep 3 11:19:11 2000 @@ -152,21 +152,22 @@ irq_desc[irq].unmask = rpc_unmask_irq_b; break; - case 16 ... 22: + case 16 ... 21: irq_desc[irq].valid = 1; + irq_desc[irq].noautoenable = 1; irq_desc[irq].mask_ack = rpc_mask_irq_dma; irq_desc[irq].mask = rpc_mask_irq_dma; irq_desc[irq].unmask = rpc_unmask_irq_dma; break; - case 32 ... 40: + case 32 ... 39: irq_desc[irq].valid = 1; irq_desc[irq].mask_ack = ecard_disableirq; irq_desc[irq].mask = ecard_disableirq; irq_desc[irq].unmask = ecard_enableirq; break; - case 64 ... 72: + case 64 ... 71: irq_desc[irq].valid = 1; irq_desc[irq].mask_ack = rpc_mask_irq_fiq; irq_desc[irq].mask = rpc_mask_irq_fiq; @@ -174,6 +175,8 @@ break; } } + + irq_desc[IRQ_KEYBOARDTX].noautoenable = 1; init_FIQ(); } diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/current.h linux/include/asm-arm/current.h --- v2.4.0-test7/linux/include/asm-arm/current.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/current.h Sun Sep 3 11:19:11 2000 @@ -1,30 +1,16 @@ #ifndef _ASMARM_CURRENT_H #define _ASMARM_CURRENT_H -static inline unsigned long get_sp(void) -{ - unsigned long sp; - __asm__ ("mov %0,sp" : "=r" (sp)); - return sp; -} - /* Old compilers seem to generate bad code if we allow `current' to be non volatile. */ #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 90) static inline struct task_struct *get_current(void) __attribute__ (( __const__ )); -#define __VOLATILE_CURRENT -#else -#define __VOLATILE_CURRENT volatile #endif static inline struct task_struct *get_current(void) { - struct task_struct *ts; - __asm__ __VOLATILE_CURRENT ( - "bic %0, sp, #0x1f00 @ get_current - bic %0, %0, #0x00ff" - : "=r" (ts)); - return ts; + register unsigned long sp asm ("sp"); + return (struct task_struct *)(sp & ~0x1fff); } #define current (get_current()) diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h --- v2.4.0-test7/linux/include/asm-arm/dma.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/dma.h Sun Sep 3 11:19:11 2000 @@ -7,6 +7,7 @@ #include #include #include +#include #include /* diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/mach/arch.h linux/include/asm-arm/mach/arch.h --- v2.4.0-test7/linux/include/asm-arm/mach/arch.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/mach/arch.h Sun Sep 3 11:19:11 2000 @@ -0,0 +1,84 @@ +/* + * linux/include/asm-arm/mach/arch.h + * + * Copyright (C) 2000 Russell King + */ + +/* + * The size of struct machine_desc + * (for assembler code) + */ +#define SIZEOF_MACHINE_DESC 44 + +#ifndef __ASSEMBLY__ + +struct machine_desc { + /* + * Note! The first four elements are used + * by assembler code in head-armv.S + */ + unsigned int nr; /* architecture number */ + unsigned int phys_ram; /* start of physical ram */ + unsigned int phys_io; /* start of physical io */ + unsigned int virt_io; /* start of virtual io */ + + const char *name; /* architecture name */ + unsigned int param_offset; /* parameter page */ + + unsigned int video_start; /* start of video RAM */ + unsigned int video_end; /* end of video RAM */ + + unsigned int reserve_lp0 :1; /* never has lp0 */ + unsigned int reserve_lp1 :1; /* never has lp1 */ + unsigned int reserve_lp2 :1; /* never has lp2 */ + unsigned int broken_hlt :1; /* hlt is broken */ + unsigned int soft_reboot :1; /* soft reboot */ + void (*fixup)(struct machine_desc *, + struct param_struct *, char **, + struct meminfo *); + void (*map_io)(void);/* IO mapping function */ +}; + +/* + * Set of macros to define architecture features. This is built into + * a table by the linker. + */ +#define MACHINE_START(_type,_name) \ +const struct machine_desc __mach_desc_##_type \ + __attribute__((__section__(".arch.info"))) = { \ + nr: MACH_TYPE_##_type##, \ + name: _name, + +#define MAINTAINER(n) + +#define BOOT_MEM(_pram,_pio,_vio) \ + phys_ram: _pram, \ + phys_io: _pio, \ + virt_io: _vio, + +#define BOOT_PARAMS(_params) \ + param_offset: _params, + +#define VIDEO(_start,_end) \ + video_start: _start, \ + video_end: _end, + +#define DISABLE_PARPORT(_n) \ + reserve_lp##_n##: 1, + +#define BROKEN_HLT \ + broken_hlt: 1, + +#define SOFT_REBOOT \ + soft_reboot: 1, + +#define FIXUP(_func) \ + fixup: _func, + +#define MAPIO(_func) \ + map_io: _func, + +#define MACHINE_END \ +}; + +#endif diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/mach/dma.h linux/include/asm-arm/mach/dma.h --- v2.4.0-test7/linux/include/asm-arm/mach/dma.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/mach/dma.h Sun Sep 3 11:19:11 2000 @@ -0,0 +1,49 @@ +/* + * linux/arch/arm/kernel/dma.h + * + * Copyright (C) 1998-2000 Russell King + * + * This header file describes the interface between the generic DMA handler + * (dma.c) and the architecture-specific DMA backends (dma-*.c) + */ + +struct dma_struct; +typedef struct dma_struct dma_t; + +struct dma_ops { + int (*request)(dmach_t, dma_t *); /* optional */ + void (*free)(dmach_t, dma_t *); /* optional */ + void (*enable)(dmach_t, dma_t *); /* mandatory */ + void (*disable)(dmach_t, dma_t *); /* mandatory */ + int (*residue)(dmach_t, dma_t *); /* optional */ + int (*setspeed)(dmach_t, dma_t *, int); /* optional */ + char *type; +}; + +struct dma_struct { + struct scatterlist buf; /* single DMA */ + int sgcount; /* number of DMA SG */ + struct scatterlist *sg; /* DMA Scatter-Gather List */ + + unsigned int active:1; /* Transfer active */ + unsigned int invalid:1; /* Address/Count changed */ + unsigned int using_sg:1; /* using scatter list? */ + dmamode_t dma_mode; /* DMA mode */ + int speed; /* DMA speed */ + + unsigned int lock; /* Device is allocated */ + const char *device_id; /* Device name */ + + unsigned int dma_base; /* Controller base address */ + int dma_irq; /* Controller IRQ */ + int state; /* Controller state */ + struct scatterlist cur_sg; /* Current controller buffer */ + + struct dma_ops *d_ops; +}; + +/* Prototype: void arch_dma_init(dma) + * Purpose : Initialise architecture specific DMA + * Params : dma - pointer to array of DMA structures + */ +void arch_dma_init(dma_t *dma); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/mach/map.h linux/include/asm-arm/mach/map.h --- v2.4.0-test7/linux/include/asm-arm/mach/map.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/mach/map.h Sun Sep 3 11:19:11 2000 @@ -0,0 +1,28 @@ +/* + * linux/include/asm-arm/map.h + * + * Copyright (C) 1999-2000 Russell King + * + * Page table mapping constructs and function prototypes + */ +struct map_desc { + unsigned long virtual; + unsigned long physical; + unsigned long length; + int domain:4, + prot_read:1, + prot_write:1, + cacheable:1, + bufferable:1, + last:1; +}; + +#define LAST_DESC \ + { last: 1 } + +struct meminfo; + +extern void create_memmap_holes(struct meminfo *); +extern void memtable_init(struct meminfo *); +extern void iotable_init(struct map_desc *); +extern void setup_io_desc(void); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/mach/pci.h linux/include/asm-arm/mach/pci.h --- v2.4.0-test7/linux/include/asm-arm/mach/pci.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/mach/pci.h Sun Sep 3 11:19:11 2000 @@ -0,0 +1,36 @@ +/* + * linux/include/asm-arm/mach/pci.h + */ +#define MAX_NR_BUS 2 + +struct arm_bus_sysdata { + /* + * bitmask of features we can turn. + * See PCI command register for more info. + */ + u16 features; + /* + * Maximum devsel for this bus. + */ + u16 maxdevsel; + /* + * The maximum latency that devices on this + * bus can withstand. + */ + u8 max_lat; +}; + +struct arm_pci_sysdata { + struct arm_bus_sysdata bus[MAX_NR_BUS]; +}; + +struct hw_pci { + void (*init)(struct arm_pci_sysdata *); + u8 (*swizzle)(struct pci_dev *dev, u8 *pin); + int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); +}; + +extern u8 no_swizzle(struct pci_dev *dev, u8 *pin); + +void __init dc21285_init(struct arm_pci_sysdata *); +void __init plx90x0_init(struct arm_pci_sysdata *); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/mmu_context.h linux/include/asm-arm/mmu_context.h --- v2.4.0-test7/linux/include/asm-arm/mmu_context.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/mmu_context.h Sun Sep 3 11:19:11 2000 @@ -17,9 +17,19 @@ #define destroy_context(mm) do { } while(0) #define init_new_context(tsk,mm) 0 +/* + * This is called when "tsk" is about to enter lazy TLB mode. + * + * mm: describes the currently active mm context + * tsk: task which is entering lazy tlb + * cpu: cpu number which is entering lazy tlb + * + * tsk->mm will be NULL + */ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) { } + /* * This is the actual mm switch as far as the scheduler * is concerned. No registers are touched. diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h --- v2.4.0-test7/linux/include/asm-arm/pci.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-arm/pci.h Sun Sep 3 11:19:11 2000 @@ -93,8 +93,10 @@ { int i; - for (i = 0; i < nents; i++, sg++) + for (i = 0; i < nents; i++, sg++) { consistent_sync(sg->address, sg->length, direction); + sg->dma_address = virt_to_bus(sg->address); + } return nents; } @@ -136,7 +138,7 @@ int i; for (i = 0; i < nelems; i++, sg++) - consistent_sync(sg->address, sg->length, 3); + consistent_sync(sg->address, sg->length, direction); } /* Return whether the given PCI device DMA address mask can @@ -148,15 +150,6 @@ { return 1; } - -/* These macros should be used after a pci_map_sg call has been done - * to get bus addresses of each of the SG entries and their lengths. - * You should only work with the number of sg entries pci_map_sg - * returns, or alternatively stop on the first sg_dma_len(sg) which - * is 0. - */ -#define sg_dma_address(sg) (virt_to_bus((sg)->address)) -#define sg_dma_len(sg) ((sg)->length) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/pgalloc.h linux/include/asm-arm/pgalloc.h --- v2.4.0-test7/linux/include/asm-arm/pgalloc.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/pgalloc.h Sun Sep 3 11:19:11 2000 @@ -13,11 +13,10 @@ */ #include -extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ -} +/* + * ARM processors do not cache TLB tables in RAM. + */ +#define flush_tlb_pgtables(mm,start,end) do { } while (0) /* * Page table cache stuff diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/proc-armo/assembler.h linux/include/asm-arm/proc-armo/assembler.h --- v2.4.0-test7/linux/include/asm-arm/proc-armo/assembler.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/proc-armo/assembler.h Sun Sep 3 11:19:11 2000 @@ -78,3 +78,25 @@ .macro restore_irqs, oldcpsr @ This be restore_irqs .endm + +/* + * These two are used to save LR/restore PC over a user-based access. + * The old 26-bit architecture requires that we do. On 32-bit + * architecture, we can safely ignore this requirement. + */ + .macro save_lr + str lr, [sp, #-4]! + .endm + + .macro restore_pc + ldmfd sp!, {pc}^ + .endm + +#define USER(x...) \ +9999: x; \ + .section __ex_table,"a"; \ + .align 3; \ + .long 9999b,9001f; \ + .previous + + diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h --- v2.4.0-test7/linux/include/asm-arm/proc-armo/cache.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/proc-armo/cache.h Sun Sep 3 11:19:11 2000 @@ -1,14 +1,21 @@ /* - * Cache flushing... + * Cache handling for 26-bit ARM processors. */ #define flush_cache_all() do { } while (0) #define flush_cache_mm(mm) do { } while (0) #define flush_cache_range(mm,start,end) do { } while (0) #define flush_cache_page(vma,vmaddr) do { } while (0) #define flush_page_to_ram(page) do { } while (0) + +#define invalidate_dcache_range(start,end) do { } while (0) +#define clean_dcache_range(start,end) do { } while (0) +#define flush_dcache_range(start,end) do { } while (0) #define flush_dcache_page(page) do { } while (0) -#define flush_icache_page(vma,page) do { } while (0) +#define clean_dcache_entry(_s) do { } while (0) +#define clean_cache_entry(_start) do { } while (0) + #define flush_icache_range(start,end) do { } while (0) +#define flush_icache_page(vma,page) do { } while (0) /* DAG: ARM3 will flush cache on MEMC updates anyway? so don't bother */ #define clean_cache_area(_start,_size) do { } while (0) diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/proc-armo/locks.h linux/include/asm-arm/proc-armo/locks.h --- v2.4.0-test7/linux/include/asm-arm/proc-armo/locks.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/proc-armo/locks.h Sun Sep 3 11:19:11 2000 @@ -15,20 +15,20 @@ ({ \ __asm__ __volatile__ ( \ "@ atomic down operation\n" \ -" mov r0, pc\n" \ -" orr lr, r0, #0x08000000\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ " teqp lr, #0\n" \ " ldr lr, [%0]\n" \ -" and r0, r0, #0x0c000003\n" \ +" and ip, ip, #0x0c000003\n" \ " subs lr, lr, #1\n" \ " str lr, [%0]\n" \ -" orrmi r0, r0, #0x80000000 @ set N\n" \ -" teqp r0, #0\n" \ -" movmi r0, %0\n" \ +" orrmi ip, ip, #0x80000000 @ set N\n" \ +" teqp ip, #0\n" \ +" movmi ip, %0\n" \ " blmi " SYMBOL_NAME_STR(fail) \ : \ : "r" (ptr) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) #define __down_op_ret(ptr,fail) \ @@ -36,22 +36,22 @@ unsigned int result; \ __asm__ __volatile__ ( \ " @ down_op_ret\n" \ -" mov r0, pc\n" \ -" orr lr, r0, #0x08000000\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ " teqp lr, #0\n" \ " ldr lr, [%1]\n" \ -" and r0, r0, #0x0c000003\n" \ +" and ip, ip, #0x0c000003\n" \ " subs lr, lr, #1\n" \ " str lr, [%1]\n" \ -" orrmi r0, r0, #0x80000000 @ set N\n" \ -" teqp r0, #0\n" \ -" movmi r0, %1\n" \ -" movpl r0, #0\n" \ +" orrmi ip, ip, #0x80000000 @ set N\n" \ +" teqp ip, #0\n" \ +" movmi ip, %1\n" \ +" movpl ip, #0\n" \ " blmi " SYMBOL_NAME_STR(fail) "\n" \ -" mov %0, r0" \ +" mov %0, ip" \ : "=&r" (result) \ : "r" (ptr) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ result; \ }) @@ -59,20 +59,20 @@ ({ \ __asm__ __volatile__ ( \ "@ up_op\n" \ -" mov r0, pc\n" \ -" orr lr, r0, #0x08000000\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ " teqp lr, #0\n" \ " ldr lr, [%0]\n" \ -" and r0, r0, #0x0c000003\n" \ +" and ip, ip, #0x0c000003\n" \ " adds lr, lr, #1\n" \ " str lr, [%0]\n" \ -" orrle r0, r0, #0x80000000 @ set N - should this be mi ??? DAG ! \n" \ -" teqp r0, #0\n" \ -" movmi r0, %0\n" \ +" orrle ip, ip, #0x80000000 @ set N - should this be mi ??? DAG ! \n" \ +" teqp ip, #0\n" \ +" movmi ip, %0\n" \ " blmi " SYMBOL_NAME_STR(wake) \ : \ : "r" (ptr) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) /* @@ -89,22 +89,22 @@ ({ \ __asm__ __volatile__( \ "@ down_op_write\n" \ -" mov r0, pc\n" \ -" orr lr, r0, #0x08000000\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ " teqp lr, #0\n" \ -" and r0, r0, #0x0c000003\n" \ +" and ip, ip, #0x0c000003\n" \ \ " ldr lr, [%0]\n" \ " subs lr, lr, %1\n" \ " str lr, [%0]\n" \ \ -" orreq r0, r0, #0x40000000 @ set Z \n"\ -" teqp r0, #0\n" \ -" movne r0, %0\n" \ +" orreq ip, ip, #0x40000000 @ set Z \n"\ +" teqp ip, #0\n" \ +" movne ip, %0\n" \ " blne " SYMBOL_NAME_STR(fail) \ : \ : "r" (ptr), "I" (RW_LOCK_BIAS) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) /* Increments by RW_LOCK_BIAS, wakes if value >= 0 */ @@ -112,22 +112,22 @@ ({ \ __asm__ __volatile__( \ "@ up_op_read\n" \ -" mov r0, pc\n" \ -" orr lr, r0, #0x08000000\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ " teqp lr, #0\n" \ \ " ldr lr, [%0]\n" \ -" and r0, r0, #0x0c000003\n" \ +" and ip, ip, #0x0c000003\n" \ " adds lr, lr, %1\n" \ " str lr, [%0]\n" \ \ -" orrcs r0, r0, #0x20000000 @ set C\n" \ -" teqp r0, #0\n" \ -" movcs r0, %0\n" \ +" orrcs ip, ip, #0x20000000 @ set C\n" \ +" teqp ip, #0\n" \ +" movcs ip, %0\n" \ " blcs " SYMBOL_NAME_STR(wake) \ : \ : "r" (ptr), "I" (RW_LOCK_BIAS) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) #define __down_op_read(ptr,fail) \ @@ -137,22 +137,22 @@ ({ \ __asm__ __volatile__( \ "@ up_op_read\n" \ -" mov r0, pc\n" \ -" orr lr, r0, #0x08000000\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ " teqp lr, #0\n" \ \ " ldr lr, [%0]\n" \ -" and r0, r0, #0x0c000003\n" \ +" and ip, ip, #0x0c000003\n" \ " adds lr, lr, %1\n" \ " str lr, [%0]\n" \ \ -" orreq r0, r0, #0x40000000 @ Set Z \n" \ -" teqp r0, #0\n" \ -" moveq r0, %0\n" \ +" orreq ip, ip, #0x40000000 @ Set Z \n" \ +" teqp ip, #0\n" \ +" moveq ip, %0\n" \ " bleq " SYMBOL_NAME_STR(wake) \ : \ : "r" (ptr), "I" (1) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) #endif diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/proc-armv/assembler.h linux/include/asm-arm/proc-armv/assembler.h --- v2.4.0-test7/linux/include/asm-arm/proc-armv/assembler.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/proc-armv/assembler.h Sun Sep 3 11:19:11 2000 @@ -47,3 +47,24 @@ .macro restore_irqs, oldcpsr msr cpsr_c, \oldcpsr .endm + +/* + * These two are used to save LR/restore PC over a user-based access. + * The old 26-bit architecture requires that we do. On 32-bit + * architecture, we can safely ignore this requirement. + */ + .macro save_lr + .endm + + .macro restore_pc + mov pc, lr + .endm + +#define USER(x...) \ +9999: x; \ + .section __ex_table,"a"; \ + .align 3; \ + .long 9999b,9001f; \ + .previous + + diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/proc-armv/system.h linux/include/asm-arm/proc-armv/system.h --- v2.4.0-test7/linux/include/asm-arm/proc-armv/system.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/proc-armv/system.h Sun Sep 3 11:19:11 2000 @@ -109,6 +109,36 @@ }) /* + * Enable FIQs + */ +#define __stf() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ stf\n" \ +" bic %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory"); \ + }) + +/* + * Disable FIQs + */ +#define __clf() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ clf\n" \ +" orr %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory"); \ + }) + +/* * save current IRQ & FIQ state */ #define __save_flags(x) \ diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/ptrace.h linux/include/asm-arm/ptrace.h --- v2.4.0-test7/linux/include/asm-arm/ptrace.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-arm/ptrace.h Sun Sep 3 11:19:11 2000 @@ -3,11 +3,6 @@ #include -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 -#define PTRACE_GETFPREGS 14 -#define PTRACE_SETFPREGS 15 - #ifndef __ASSEMBLY__ #define pc_pointer(v) \ ((v) & ~PCMASK) @@ -16,6 +11,11 @@ (pc_pointer((regs)->ARM_pc)) #ifdef __KERNEL__ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 + extern void show_regs(struct pt_regs *); #define predicate(x) (x & 0xf0000000) diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/scatterlist.h linux/include/asm-arm/scatterlist.h --- v2.4.0-test7/linux/include/asm-arm/scatterlist.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/scatterlist.h Sun Sep 3 11:19:11 2000 @@ -1,12 +1,24 @@ #ifndef _ASMARM_SCATTERLIST_H #define _ASMARM_SCATTERLIST_H +#include + struct scatterlist { - char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ - unsigned int length; + char *address; /* virtual address */ + char *alt_address; /* indirect dma address, or NULL */ + dma_addr_t dma_address; /* dma address */ + unsigned int length; /* length */ }; + +/* + * These macros should be used after a pci_map_sg call has been done + * to get bus addresses of each of the SG entries and their lengths. + * You should only work with the number of sg entries pci_map_sg + * returns, or alternatively stop on the first sg_dma_len(sg) which + * is 0. + */ +#define sg_dma_address(sg) ((sg)->dma_address) +#define sg_dma_len(sg) ((sg)->length) #define ISA_DMA_THRESHOLD (0xffffffff) diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/shmparam.h linux/include/asm-arm/shmparam.h --- v2.4.0-test7/linux/include/asm-arm/shmparam.h Sun Nov 7 16:37:34 1999 +++ linux/include/asm-arm/shmparam.h Sun Sep 3 11:19:11 2000 @@ -3,6 +3,11 @@ #include +/* + * This should be the size of the virtually indexed cache/ways, + * or page size, whichever is greater since the cache aliases + * every size/ways bytes. + */ #define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ #endif /* _ASMARM_SHMPARAM_H */ diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h --- v2.4.0-test7/linux/include/asm-arm/uaccess.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-arm/uaccess.h Tue Aug 29 14:09:15 2000 @@ -59,9 +59,6 @@ * address space - it must have been done previously with a separate * "access_ok()" call. * - * The "xxx_ret" versions return constant specified in the third - * argument if something bad happens. - * * The "xxx_error" versions set the third argument to EFAULT if an * error occurs, and leave it unchanged on success. Note that these * versions are void (ie, don't return a value as such). @@ -69,14 +66,10 @@ #define get_user(x,p) __get_user_check((x),(p),sizeof(*(p))) #define __get_user(x,p) __get_user_nocheck((x),(p),sizeof(*(p))) #define __get_user_error(x,p,e) __get_user_nocheck_error((x),(p),sizeof(*(p)),(e)) -#define get_user_ret(x,p,r) ({ if (get_user(x,p)) return r; }) -#define __get_user_ret(x,p,r) ({ if (__get_user(x,p)) return r; }) #define put_user(x,p) __put_user_check((__typeof(*(p)))(x),(p),sizeof(*(p))) #define __put_user(x,p) __put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p))) #define __put_user_error(x,p,e) __put_user_nocheck_error((x),(p),sizeof(*(p)),(e)) -#define put_user_ret(x,p,r) ({ if (put_user(x,p)) return r; }) -#define __put_user_ret(x,p,r) ({ if (__put_user(x,p)) return r; }) static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n) { @@ -91,9 +84,6 @@ return n; } -#define copy_from_user_ret(t,f,n,r) \ - ({ if (copy_from_user(t,f,n)) return r; }) - static __inline__ unsigned long copy_to_user(void *to, const void *from, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) @@ -106,9 +96,6 @@ __do_copy_to_user(to, from, n); return n; } - -#define copy_to_user_ret(t,f,n,r) \ - ({ if (copy_to_user(t,f,n)) return r; }) static __inline__ unsigned long clear_user (void *to, unsigned long n) { diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.4.0-test7/linux/include/asm-i386/bugs.h Wed Aug 23 18:36:39 2000 +++ linux/include/asm-i386/bugs.h Wed Sep 6 15:03:21 2000 @@ -50,32 +50,22 @@ __setup("no387", no_387); -static char __initdata fpu_error = 0; - -static struct timer_list copro_timer __initdata = {{0, 0}, 0}; - -static void __init copro_timeout(unsigned long dummy) -{ - fpu_error = 1; - mod_timer(&copro_timer, jiffies+HZ); - printk(KERN_ERR "387 failed: trying to reset\n"); - send_sig(SIGFPE, current, 1); - outb_p(0,0xf1); - outb_p(0,0xf0); -} - static double __initdata x = 4195835.0; static double __initdata y = 3145727.0; -#ifdef CONFIG_X86_XMM -static float __initdata zero[4] = { 0.0, 0.0, 0.0, 0.0 }; -static float __initdata one[4] = { 1.0, 1.0, 1.0, 1.0 }; -#endif - +/* + * This used to check for exceptions.. + * However, it turns out that to support that, + * the XMM trap handlers basically had to + * be buggy. So let's have a correct XMM trap + * handler, and forget about printing out + * some status at boot. + * + * We should really only care about bugs here + * anyway. Not features. + */ static void __init check_fpu(void) { - unsigned short control_word; - if (!boot_cpu_data.hard_math) { #ifndef CONFIG_MATH_EMULATION printk(KERN_EMERG "No coprocessor found and no math emulation present.\n"); @@ -84,72 +74,8 @@ #endif return; } - if (mca_pentium_flag) { - /* The IBM Model 95 machines with pentiums lock up on - * fpu test, so we avoid it. All pentiums have inbuilt - * FPU and thus should use exception 16. We still do - * the FDIV test, although I doubt there where ever any - * MCA boxes built with non-FDIV-bug cpus. - */ - __asm__("fninit\n\t" - "fldl %1\n\t" - "fdivl %2\n\t" - "fmull %2\n\t" - "fldl %1\n\t" - "fsubp %%st,%%st(1)\n\t" - "fistpl %0\n\t" - "fwait\n\t" - "fninit" - : "=m" (*&boot_cpu_data.fdiv_bug) - : "m" (*&x), "m" (*&y)); - printk("mca-pentium specified, avoiding FPU coupling test... "); - if (!boot_cpu_data.fdiv_bug) - printk("??? No FDIV bug? Lucky you...\n"); - else - printk("detected FDIV bug though.\n"); - return; - } - /* - * check if exception 16 works correctly.. This is truly evil - * code: it disables the high 8 interrupts to make sure that - * the irq13 doesn't happen. But as this will lead to a lockup - * if no exception16 arrives, it depends on the fact that the - * high 8 interrupts will be re-enabled by the next timer tick. - * So the irq13 will happen eventually, but the exception 16 - * should get there first.. - */ - printk(KERN_INFO "Checking 386/387 coupling... "); - init_timer(&copro_timer); - copro_timer.function = copro_timeout; - mod_timer(&copro_timer, jiffies+HZ/2); - __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word)); - control_word &= 0xffc0; - __asm__("fldcw %0 ; fwait": :"m" (*&control_word)); - outb_p(inb_p(0x21) | (1 << 2), 0x21); - __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait"); - del_timer(&copro_timer); - if (fpu_error) - return; - if (!ignore_irq13) { - printk("OK, FPU using old IRQ 13 error reporting\n"); - return; - } - __asm__("fninit\n\t" - "fldl %1\n\t" - "fdivl %2\n\t" - "fmull %2\n\t" - "fldl %1\n\t" - "fsubp %%st,%%st(1)\n\t" - "fistpl %0\n\t" - "fwait\n\t" - "fninit" - : "=m" (*&boot_cpu_data.fdiv_bug) - : "m" (*&x), "m" (*&y)); - if (!boot_cpu_data.fdiv_bug) - printk("OK, FPU using exception 16 error reporting.\n"); - else - printk("Hmm, FPU using exception 16 error reporting with FDIV bug.\n"); +/* Enable FXSR and company _before_ testing for FP problems. */ #if defined(CONFIG_X86_FXSR) || defined(CONFIG_X86_RUNTIME_FXSR) /* * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. @@ -168,18 +94,24 @@ printk(KERN_INFO "Enabling unmasked SIMD FPU exception support... "); set_in_cr4(X86_CR4_OSXMMEXCPT); printk("done.\n"); - - /* Check if exception 19 works okay. */ - load_mxcsr(0x0000); - printk(KERN_INFO "Checking SIMD FPU exceptions... "); - __asm__("movups %0,%%xmm0\n\t" - "movups %1,%%xmm1\n\t" - "divps %%xmm0,%%xmm1\n\t" - : : "m" (*&zero), "m" (*&one)); - printk("OK, SIMD FPU using exception 19 error reporting.\n"); load_mxcsr(0x1f80); } #endif + + /* Test for the divl bug.. */ + __asm__("fninit\n\t" + "fldl %1\n\t" + "fdivl %2\n\t" + "fmull %2\n\t" + "fldl %1\n\t" + "fsubp %%st,%%st(1)\n\t" + "fistpl %0\n\t" + "fwait\n\t" + "fninit" + : "=m" (*&boot_cpu_data.fdiv_bug) + : "m" (*&x), "m" (*&y)); + if (boot_cpu_data.fdiv_bug) + printk("Hmm, FPU with FDIV bug.\n"); } static void __init check_hlt(void) diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-i386/page.h linux/include/asm-i386/page.h --- v2.4.0-test7/linux/include/asm-i386/page.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-i386/page.h Wed Sep 6 14:49:28 2000 @@ -75,7 +75,7 @@ * amount of physical memory you can use to about 950MB. * * If you want more physical memory than this then see the CONFIG_HIGHMEM4G - * amd CONFIG_HIGHMEM64G options in the kernel configuration. + * and CONFIG_HIGHMEM64G options in the kernel configuration. */ #define __PAGE_OFFSET (0xC0000000) diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.4.0-test7/linux/include/asm-i386/system.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-i386/system.h Wed Sep 6 14:49:29 2000 @@ -267,8 +267,15 @@ * I expect future Intel CPU's to have a weaker ordering, * but I'd also expect them to finally get their act together * and add some real memory barriers if so. + * + * The Pentium III does add a real memory barrier with the + * sfence instruction, so we use that where appropriate. */ +#ifndef CONFIG_X86_XMM #define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") +#else +#define mb() __asm__ __volatile__ ("sfence": : :"memory") +#endif #define rmb() mb() #define wmb() __asm__ __volatile__ ("": : :"memory") #define set_mb(var, value) do { xchg(&var, value); } while (0) diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h --- v2.4.0-test7/linux/include/asm-i386/uaccess.h Tue May 23 15:31:36 2000 +++ linux/include/asm-i386/uaccess.h Wed Sep 6 14:49:43 2000 @@ -232,20 +232,6 @@ : "=r"(err), ltype (x) \ : "m"(__m(addr)), "i"(-EFAULT), "0"(err)) -/* - * The "xxx_ret" versions return constant specified in third argument, if - * something bad happens. These macros can be optimized for the - * case of just returning from the function xxx_ret is used. - */ - -#define put_user_ret(x,ptr,ret) ({ if (put_user(x,ptr)) return ret; }) - -#define get_user_ret(x,ptr,ret) ({ if (get_user(x,ptr)) return ret; }) - -#define __put_user_ret(x,ptr,ret) ({ if (__put_user(x,ptr)) return ret; }) - -#define __get_user_ret(x,ptr,ret) ({ if (__get_user(x,ptr)) return ret; }) - /* * Copy To/From Userspace @@ -582,10 +568,6 @@ (__builtin_constant_p(n) ? \ __constant_copy_from_user((to),(from),(n)) : \ __generic_copy_from_user((to),(from),(n))) - -#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) - -#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) #define __copy_to_user(to,from,n) \ (__builtin_constant_p(n) ? \ diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-ia64/uaccess.h linux/include/asm-ia64/uaccess.h --- v2.4.0-test7/linux/include/asm-ia64/uaccess.h Wed Apr 26 16:34:09 2000 +++ linux/include/asm-ia64/uaccess.h Tue Aug 29 14:09:16 2000 @@ -86,16 +86,6 @@ #define __put_user(x,ptr) __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) -/* - * The "xxx_ret" versions return constant specified in third argument, if - * something bad happens. These macros can be optimized for the - * case of just returning from the function xxx_ret is used. - */ -#define put_user_ret(x,ptr,ret) ({ if (put_user(x,ptr)) return ret; }) -#define get_user_ret(x,ptr,ret) ({ if (get_user(x,ptr)) return ret; }) -#define __put_user_ret(x,ptr,ret) ({ if (__put_user(x,ptr)) return ret; }) -#define __get_user_ret(x,ptr,ret) ({ if (__get_user(x,ptr)) return ret; }) - extern void __get_user_unknown (void); #define __get_user_nocheck(x,ptr,size) \ @@ -278,18 +268,6 @@ __cu_len = __copy_user(__cu_to, __cu_from, __cu_len); \ } \ __cu_len; \ -}) - -#define copy_to_user_ret(to,from,n,retval) \ -({ \ - if (copy_to_user(to,from,n)) \ - return retval; \ -}) - -#define copy_from_user_ret(to,from,n,retval) \ -({ \ - if (copy_from_user(to,from,n)) \ - return retval; \ }) extern unsigned long __do_clear_user (void *, unsigned long); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-m68k/uaccess.h linux/include/asm-m68k/uaccess.h --- v2.4.0-test7/linux/include/asm-m68k/uaccess.h Fri Jan 28 15:09:09 2000 +++ linux/include/asm-m68k/uaccess.h Tue Aug 29 14:09:15 2000 @@ -759,10 +759,6 @@ #define __copy_from_user(to, from, n) copy_from_user(to, from, n) #define __copy_to_user(to, from, n) copy_to_user(to, from, n) -#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) - -#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) - /* * Copy a null terminated string from userspace. */ diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-mips/uaccess.h linux/include/asm-mips/uaccess.h --- v2.4.0-test7/linux/include/asm-mips/uaccess.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-mips/uaccess.h Tue Aug 29 14:09:15 2000 @@ -84,24 +84,6 @@ #define __get_user(x,ptr) \ __get_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) -/* - * The "xxx_ret" versions return constant specified in third argument, if - * something bad happens. These macros can be optimized for the - * case of just returning from the function xxx_ret is used. - */ - -#define put_user_ret(x,ptr,ret) ({ \ -if (put_user(x,ptr)) return ret; }) - -#define get_user_ret(x,ptr,ret) ({ \ -if (get_user(x,ptr)) return ret; }) - -#define __put_user_ret(x,ptr,ret) ({ \ -if (__put_user(x,ptr)) return ret; }) - -#define __get_user_ret(x,ptr,ret) ({ \ -if (__get_user(x,ptr)) return ret; }) - struct __large_struct { unsigned long buf[100]; }; #define __m(x) (*(struct __large_struct *)(x)) @@ -280,16 +262,6 @@ #define __MODULE_JAL(destination) \ "jal\t" #destination "\n\t" #endif - -#define copy_to_user_ret(to,from,n,retval) ({ \ -if (copy_to_user(to,from,n)) \ - return retval; \ -}) - -#define copy_from_user_ret(to,from,n,retval) ({ \ -if (copy_from_user(to,from,n)) \ - return retval; \ -}) extern size_t __copy_user(void *__to, const void *__from, size_t __n); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-mips64/uaccess.h linux/include/asm-mips64/uaccess.h --- v2.4.0-test7/linux/include/asm-mips64/uaccess.h Mon Jul 10 16:47:27 2000 +++ linux/include/asm-mips64/uaccess.h Tue Aug 29 14:09:16 2000 @@ -84,18 +84,6 @@ #define __get_user(x,ptr) \ __get_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) -/* - * The "xxx_ret" versions return constant specified in third argument, if - * something bad happens. These macros can be optimized for the - * case of just returning from the function xxx_ret is used. - */ - -#define put_user_ret(x,ptr,ret) ({ if (put_user(x,ptr)) return ret; }) -#define get_user_ret(x,ptr,ret) ({ if (get_user(x,ptr)) return ret; }) - -#define __put_user_ret(x,ptr,ret) ({ if (__put_user(x,ptr)) return ret; }) -#define __get_user_ret(x,ptr,ret) ({ if (__get_user(x,ptr)) return ret; }) - struct __large_struct { unsigned long buf[100]; }; #define __m(x) (*(struct __large_struct *)(x)) @@ -212,16 +200,6 @@ #define __MODULE_JAL(destination) \ "jal\t" #destination "\n\t" #endif - -#define copy_to_user_ret(to,from,n,retval) ({ \ -if (copy_to_user(to,from,n)) \ - return retval; \ -}) - -#define copy_from_user_ret(to,from,n,retval) ({ \ -if (copy_from_user(to,from,n)) \ - return retval; \ -}) extern size_t __copy_user(void *__to, const void *__from, size_t __n); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-ppc/uaccess.h linux/include/asm-ppc/uaccess.h --- v2.4.0-test7/linux/include/asm-ppc/uaccess.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-ppc/uaccess.h Tue Aug 29 14:09:15 2000 @@ -87,25 +87,6 @@ #define __put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) -/* - * The "xxx_ret" versions return constant specified in third argument, if - * something bad happens. These macros can be optimized for the - * case of just returning from the function xxx_ret is used. - */ - -#define put_user_ret(x,ptr,ret) ({ \ -if (put_user(x,ptr)) return ret; }) - -#define get_user_ret(x,ptr,ret) ({ \ -if (get_user(x,ptr)) return ret; }) - -#define __put_user_ret(x,ptr,ret) ({ \ -if (__put_user(x,ptr)) return ret; }) - -#define __get_user_ret(x,ptr,ret) ({ \ -if (__get_user(x,ptr)) return ret; }) - - extern long __put_user_bad(void); #define __put_user_nocheck(x,ptr,size) \ @@ -235,10 +216,6 @@ } return n; } - -#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) - -#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) #define __copy_from_user(to, from, size) \ __copy_tofrom_user((to), (from), (size)) diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h --- v2.4.0-test7/linux/include/asm-s390/uaccess.h Fri May 12 14:18:56 2000 +++ linux/include/asm-s390/uaccess.h Tue Aug 29 14:09:16 2000 @@ -407,10 +407,6 @@ err; \ }) -#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) - -#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) - /* * Copy a null terminated string from userspace. */ diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-sh/uaccess.h linux/include/asm-sh/uaccess.h --- v2.4.0-test7/linux/include/asm-sh/uaccess.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-sh/uaccess.h Tue Aug 29 14:09:16 2000 @@ -83,24 +83,6 @@ #define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr))) #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) -/* - * The "xxx_ret" versions return constant specified in third argument, if - * something bad happens. These macros can be optimized for the - * case of just returning from the function xxx_ret is used. - */ - -#define put_user_ret(x,ptr,ret) ({ \ -if (put_user(x,ptr)) return ret; }) - -#define get_user_ret(x,ptr,ret) ({ \ -if (get_user(x,ptr)) return ret; }) - -#define __put_user_ret(x,ptr,ret) ({ \ -if (__put_user(x,ptr)) return ret; }) - -#define __get_user_ret(x,ptr,ret) ({ \ -if (__get_user(x,ptr)) return ret; }) - struct __large_struct { unsigned long buf[100]; }; #define __m(x) (*(struct __large_struct *)(x)) @@ -256,20 +238,10 @@ } else __copy_res = __copy_size; \ __copy_res; }) -#define copy_to_user_ret(to,from,n,retval) ({ \ -if (copy_to_user(to,from,n)) \ - return retval; \ -}) - #define __copy_to_user(to,from,n) \ __copy_user((void *)(to), \ (void *)(from), n) -#define __copy_to_user_ret(to,from,n,retval) ({ \ -if (__copy_to_user(to,from,n)) \ - return retval; \ -}) - #define copy_from_user(to,from,n) ({ \ void *__copy_to = (void *) (to); \ void *__copy_from = (void *) (from); \ @@ -280,19 +252,9 @@ } else __copy_res = __copy_size; \ __copy_res; }) -#define copy_from_user_ret(to,from,n,retval) ({ \ -if (copy_from_user(to,from,n)) \ - return retval; \ -}) - #define __copy_from_user(to,from,n) \ __copy_user((void *)(to), \ (void *)(from), n) - -#define __copy_from_user_ret(to,from,n,retval) ({ \ -if (__copy_from_user(to,from,n)) \ - return retval; \ -}) /* XXX: Not sure it works well.. should be such that: 4byte clear and the rest. */ diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h --- v2.4.0-test7/linux/include/asm-sparc/hardirq.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sparc/hardirq.h Mon Aug 28 21:20:03 2000 @@ -1,7 +1,7 @@ /* hardirq.h: 32-bit Sparc hard IRQ support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com) */ #ifndef __SPARC_HARDIRQ_H @@ -9,77 +9,83 @@ #include #include +#include +#include /* entry.S is sensitive to the offsets of these fields */ typedef struct { unsigned int __softirq_active; unsigned int __softirq_mask; +#ifndef CONFIG_SMP unsigned int __local_irq_count; +#else + unsigned int __unused_on_SMP; /* DaveM says use brlock for SMP irq. KAO */ +#endif unsigned int __local_bh_count; unsigned int __syscall_count; } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ +/* Note that local_irq_count() is replaced by sparc64 specific version for SMP */ + +#ifndef CONFIG_SMP +#define irq_enter(cpu, irq) ((void)(irq), local_irq_count(cpu)++) +#define irq_exit(cpu, irq) ((void)(irq), local_irq_count(cpu)--) +#else +#undef local_irq_count +#define local_irq_count(cpu) (__brlock_array[cpu][BR_GLOBALIRQ_LOCK]) +#define irq_enter(cpu, irq) br_read_lock(BR_GLOBALIRQ_LOCK) +#define irq_exit(cpu, irq) br_read_unlock(BR_GLOBALIRQ_LOCK) +#endif /* * Are we in an interrupt context? Either doing bottom half * or hardware interrupt processing? */ -#define in_interrupt() ({ int __cpu = smp_processor_id(); \ - (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); }) +#define in_interrupt() ((local_irq_count(smp_processor_id()) + \ + local_bh_count(smp_processor_id())) != 0) -#define in_irq() ({ int __cpu = smp_processor_id(); \ - (local_irq_count(__cpu) != 0); }) +/* This tests only the local processors hw IRQ context disposition. */ +#define in_irq() (local_irq_count(smp_processor_id()) != 0) #ifndef CONFIG_SMP -#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) -#define hardirq_endlock(cpu) do { (void)(cpu); } while (0) - -#define hardirq_enter(cpu) (++local_irq_count(cpu)) -#define hardirq_exit(cpu) (--local_irq_count(cpu)) +#define hardirq_trylock(cpu) ((void)(cpu), local_irq_count(smp_processor_id()) == 0) +#define hardirq_endlock(cpu) do { (void)(cpu); } while(0) #define synchronize_irq() barrier() -#else +#else /* (CONFIG_SMP) */ -#include -#include -#include -#include +static __inline__ int irqs_running(void) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) + if (local_irq_count(cpu_logical_map(i))) + return 1; + return 0; +} extern unsigned char global_irq_holder; -extern spinlock_t global_irq_lock; -extern atomic_t global_irq_count; static inline void release_irqlock(int cpu) { - /* if we didn't own the irq lock, just ignore.. */ - if (global_irq_holder == (unsigned char) cpu) { + /* if we didn't own the irq lock, just ignore... */ + if(global_irq_holder == (unsigned char) cpu) { global_irq_holder = NO_PROC_ID; - spin_unlock(&global_irq_lock); + br_write_unlock(BR_GLOBALIRQ_LOCK); } } -static inline void hardirq_enter(int cpu) -{ - ++local_irq_count(cpu); - atomic_inc(&global_irq_count); -} - -static inline void hardirq_exit(int cpu) -{ - atomic_dec(&global_irq_count); - --local_irq_count(cpu); -} - static inline int hardirq_trylock(int cpu) { - return (! atomic_read(&global_irq_count) && - ! spin_is_locked (&global_irq_lock)); + spinlock_t *lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock; + + return (!local_irq_count(cpu) && !spin_is_locked(lock)); } -#define hardirq_endlock(cpu) do { } while (0) +#define hardirq_endlock(cpu) do { (void)(cpu); } while (0) extern void synchronize_irq(void); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h --- v2.4.0-test7/linux/include/asm-sparc/irq.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sparc/irq.h Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.h,v 1.31 2000/08/05 10:48:41 davem Exp $ +/* $Id: irq.h,v 1.32 2000/08/26 02:42:28 anton Exp $ * irq.h: IRQ registers on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -20,18 +20,6 @@ #define __irq_itoa(irq) BTFIXUP_CALL(__irq_itoa)(irq) #define NR_IRQS 15 - -/* IRQ handler dispatch entry and exit. */ -#ifdef CONFIG_SMP -#define irq_enter(cpu, irq) \ -do { hardirq_enter(cpu); \ - spin_unlock_wait(&global_irq_lock); \ - } while(0) -#define irq_exit(cpu, irq) hardirq_exit(cpu) -#else -#define irq_enter(cpu, irq) (++local_irq_count(cpu)) -#define irq_exit(cpu, irq) (--local_irq_count(cpu)) -#endif /* Dave Redman (djhr@tadpole.co.uk) * changed these to function pointers.. it saves cycles and will allow diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-sparc/oplib.h linux/include/asm-sparc/oplib.h --- v2.4.0-test7/linux/include/asm-sparc/oplib.h Sun Oct 4 10:22:44 1998 +++ linux/include/asm-sparc/oplib.h Mon Aug 28 21:20:03 2000 @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.20 1998/09/17 11:05:25 jj Exp $ +/* $Id: oplib.h,v 1.21 2000/08/26 02:38:04 anton Exp $ * oplib.h: Describes the interface and available routines in the * Linux Prom library. * @@ -9,6 +9,7 @@ #define __SPARC_OPLIB_H #include +#include /* The master romvec pointer... */ extern struct linux_romvec *romvec; @@ -311,6 +312,7 @@ /* Apply ranges of any prom node (and optionally parent node as well) to registers. */ extern void prom_apply_generic_ranges(int node, int parent, struct linux_prom_registers *sbusregs, int nregs); - + +extern spinlock_t prom_lock; #endif /* !(__SPARC_OPLIB_H) */ diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-sparc/uaccess.h linux/include/asm-sparc/uaccess.h --- v2.4.0-test7/linux/include/asm-sparc/uaccess.h Tue Jan 11 22:31:44 2000 +++ linux/include/asm-sparc/uaccess.h Tue Aug 29 14:09:16 2000 @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.21 2000/01/08 16:38:23 anton Exp $ +/* $Id: uaccess.h,v 1.22 2000/08/29 07:01:58 davem Exp $ * uaccess.h: User space memore access functions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -94,27 +94,17 @@ unsigned long __pu_addr = (unsigned long)(ptr); \ __put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); }) -#define put_user_ret(x,ptr,retval) ({ \ -unsigned long __pu_addr = (unsigned long)(ptr); \ -__put_user_check_ret((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr)),retval); }) - #define get_user(x,ptr) ({ \ unsigned long __gu_addr = (unsigned long)(ptr); \ __get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); }) -#define get_user_ret(x,ptr,retval) ({ \ -unsigned long __gu_addr = (unsigned long)(ptr); \ -__get_user_check_ret((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr)),retval); }) - /* * The "__xxx" versions do not do address space checking, useful when * doing multiple accesses to the same area (the user has to do the * checks by hand with "access_ok()") */ #define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr))) -#define __put_user_ret(x,ptr,retval) __put_user_nocheck_ret((x),(ptr),sizeof(*(ptr)),retval) #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr))) -#define __get_user_ret(x,ptr,retval) __get_user_nocheck_ret((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)),retval) struct __large_struct { unsigned long buf[100]; }; #define __m(x) ((struct __large_struct *)(x)) @@ -303,20 +293,10 @@ } else __copy_res = __copy_size; \ __copy_res; }) -#define copy_to_user_ret(to,from,n,retval) ({ \ -if (copy_to_user(to,from,n)) \ - return retval; \ -}) - #define __copy_to_user(to,from,n) \ __copy_user((void *)(to), \ (void *)(from), n) -#define __copy_to_user_ret(to,from,n,retval) ({ \ -if (__copy_to_user(to,from,n)) \ - return retval; \ -}) - #define copy_from_user(to,from,n) ({ \ void *__copy_to = (void *) (to); \ void *__copy_from = (void *) (from); \ @@ -327,20 +307,10 @@ } else __copy_res = __copy_size; \ __copy_res; }) -#define copy_from_user_ret(to,from,n,retval) ({ \ -if (copy_from_user(to,from,n)) \ - return retval; \ -}) - #define __copy_from_user(to,from,n) \ __copy_user((void *)(to), \ (void *)(from), n) -#define __copy_from_user_ret(to,from,n,retval) ({ \ -if (__copy_from_user(to,from,n)) \ - return retval; \ -}) - extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t size) { __kernel_size_t ret; @@ -367,11 +337,6 @@ __clear_res = __clear_user(__clear_addr, __clear_size); \ } else __clear_res = __clear_size; \ __clear_res; }) - -#define clear_user_ret(addr,size,retval) ({ \ -if (clear_user(addr,size)) \ - return retval; \ -}) extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count); diff -u --recursive --new-file v2.4.0-test7/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h --- v2.4.0-test7/linux/include/asm-sparc64/uaccess.h Wed Dec 29 13:13:21 1999 +++ linux/include/asm-sparc64/uaccess.h Tue Aug 29 14:09:16 2000 @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.32 1999/11/23 08:56:48 davem Exp $ */ +/* $Id: uaccess.h,v 1.33 2000/08/29 07:01:58 davem Exp $ */ #ifndef _ASM_UACCESS_H #define _ASM_UACCESS_H @@ -102,22 +102,12 @@ unsigned long __pu_addr = (unsigned long)(ptr); \ __put_user_nocheck((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); }) -#define put_user_ret(x,ptr,retval) ({ \ -unsigned long __pu_addr = (unsigned long)(ptr); \ -__put_user_nocheck_ret((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr)),retval); }) - #define get_user(x,ptr) ({ \ unsigned long __gu_addr = (unsigned long)(ptr); \ __get_user_nocheck((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); }) -#define get_user_ret(x,ptr,retval) ({ \ -unsigned long __gu_addr = (unsigned long)(ptr); \ -__get_user_nocheck_ret((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr)),retval); }) - #define __put_user(x,ptr) put_user(x,ptr) -#define __put_user_ret(x,ptr,retval) put_user_ret(x,ptr,retval) #define __get_user(x,ptr) get_user(x,ptr) -#define __get_user_ret(x,ptr,retval) get_user_ret(x,ptr,retval) struct __large_struct { unsigned long buf[100]; }; #define __m(x) ((struct __large_struct *)(x)) @@ -288,44 +278,14 @@ __copy_from_user((void *)(to), \ (void *)(from), (__kernel_size_t)(n)) -#define copy_from_user_ret(to,from,n,retval) ({ \ -if (copy_from_user(to,from,n)) \ - return retval; \ -}) - -#define __copy_from_user_ret(to,from,n,retval) ({ \ -if (__copy_from_user(to,from,n)) \ - return retval; \ -}) - #define copy_to_user(to,from,n) \ __copy_to_user((void *)(to), \ (void *) (from), (__kernel_size_t)(n)) -#define copy_to_user_ret(to,from,n,retval) ({ \ -if (copy_to_user(to,from,n)) \ - return retval; \ -}) - -#define __copy_to_user_ret(to,from,n,retval) ({ \ -if (__copy_to_user(to,from,n)) \ - return retval; \ -}) - #define copy_in_user(to,from,n) \ __copy_in_user((void *)(to), \ (void *) (from), (__kernel_size_t)(n)) -#define copy_in_user_ret(to,from,n,retval) ({ \ -if (copy_in_user(to,from,n)) \ - return retval; \ -}) - -#define __copy_in_user_ret(to,from,n,retval) ({ \ -if (__copy_in_user(to,from,n)) \ - return retval; \ -}) - extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t size) { extern __kernel_size_t __bzero_noasi(void *addr, __kernel_size_t size); @@ -335,11 +295,6 @@ #define clear_user(addr,n) \ __clear_user((void *)(addr), (__kernel_size_t)(n)) - -#define clear_user_ret(addr,size,retval) ({ \ -if (clear_user(addr,size)) \ - return retval; \ -}) extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count); diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/fat_cvf.h linux/include/linux/fat_cvf.h --- v2.4.0-test7/linux/include/linux/fat_cvf.h Mon Aug 9 11:43:49 1999 +++ linux/include/linux/fat_cvf.h Tue Sep 5 14:07:29 2000 @@ -14,8 +14,7 @@ struct buffer_head* (*cvf_getblk) (struct super_block*sb,int block); void (*cvf_brelse) (struct super_block *sb,struct buffer_head *bh); void (*cvf_mark_buffer_dirty) (struct super_block *sb, - struct buffer_head *bh, - int dirty_val); + struct buffer_head *bh); void (*cvf_set_uptodate) (struct super_block *sb, struct buffer_head *bh, int val); diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.4.0-test7/linux/include/linux/fs.h Wed Aug 23 18:36:39 2000 +++ linux/include/linux/fs.h Wed Sep 6 14:49:39 2000 @@ -361,7 +361,8 @@ unsigned long nrpages; /* number of pages */ struct address_space_operations *a_ops; /* methods */ void *host; /* owner: inode, block_device */ - struct vm_area_struct *i_mmap; /* list of mappings */ + struct vm_area_struct *i_mmap; /* list of private mappings */ + struct vm_area_struct *i_mmap_shared; /* list of shared mappings */ spinlock_t i_shared_lock; /* and spinlock protecting it */ }; @@ -984,8 +985,8 @@ __mark_buffer_protected(bh); } -extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh, int flag)); -extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh, int flag)); +extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh)); +extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh)); #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state) @@ -1049,9 +1050,20 @@ * This should be a per-architecture thing, to allow different * error and pointer decisions. */ -#define ERR_PTR(err) ((void *)((long)(err))) -#define PTR_ERR(ptr) ((long)(ptr)) -#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000)) +static inline void *ERR_PTR(long error) +{ + return (void *) error; +} + +static inline long PTR_ERR(const void *ptr) +{ + return (long) ptr; +} + +static inline long IS_ERR(const void *ptr) +{ + return (unsigned long)ptr > (unsigned long)-1000L; +} /* * The bitmask for a lookup event: @@ -1161,6 +1173,7 @@ int generic_block_bmap(struct address_space *, long, get_block_t *); int generic_commit_write(struct file *, struct page *, unsigned, unsigned); +int block_truncate_page(struct address_space *, loff_t, get_block_t *); extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/hfs_sysdep.h linux/include/linux/hfs_sysdep.h --- v2.4.0-test7/linux/include/linux/hfs_sysdep.h Thu Jul 27 17:38:02 2000 +++ linux/include/linux/hfs_sysdep.h Tue Sep 5 14:07:29 2000 @@ -150,7 +150,7 @@ } extern inline void hfs_buffer_dirty(hfs_buffer buffer) { - mark_buffer_dirty(buffer, 1); + mark_buffer_dirty(buffer); } extern inline void hfs_buffer_sync(hfs_buffer buffer) { diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.4.0-test7/linux/include/linux/mm.h Wed Aug 23 18:36:39 2000 +++ linux/include/linux/mm.h Wed Sep 6 14:49:43 2000 @@ -52,7 +52,8 @@ struct vm_area_struct * vm_avl_left; struct vm_area_struct * vm_avl_right; - /* For areas with inode, the list inode->i_mapping->i_mmap, + /* For areas with an address space and backing store, + * one of the address_space->i_mmap{,shared} lists, * for shm areas, the list of attaches, otherwise unused. */ struct vm_area_struct *vm_next_share; diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- v2.4.0-test7/linux/include/linux/nfs_fs.h Tue May 23 15:31:36 2000 +++ linux/include/linux/nfs_fs.h Wed Sep 6 14:50:19 2000 @@ -184,6 +184,12 @@ extern int nfs_lock(struct file *, int, struct file_lock *); /* + * linux/fs/nfs/unlink.c + */ +extern int nfs_async_unlink(struct dentry *); +extern void nfs_complete_unlink(struct dentry *); + +/* * linux/fs/nfs/write.c */ extern int nfs_writepage(struct file *file, struct page *); diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/nfs_xdr.h linux/include/linux/nfs_xdr.h --- v2.4.0-test7/linux/include/linux/nfs_xdr.h Tue May 23 15:31:36 2000 +++ linux/include/linux/nfs_xdr.h Tue Sep 5 14:02:41 2000 @@ -334,6 +334,9 @@ int (*create) (struct dentry *, struct qstr *, struct iattr *, int, struct nfs_fh *, struct nfs_fattr *); int (*remove) (struct dentry *, struct qstr *); + int (*unlink_setup) (struct rpc_message *, + struct dentry *, struct qstr *); + void (*unlink_done) (struct dentry *, struct rpc_message *); int (*rename) (struct dentry *, struct qstr *, struct dentry *, struct qstr *); int (*link) (struct dentry *, struct dentry *, struct qstr *); diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/nfsd/interface.h linux/include/linux/nfsd/interface.h --- v2.4.0-test7/linux/include/linux/nfsd/interface.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/nfsd/interface.h Tue Sep 5 12:56:51 2000 @@ -0,0 +1,23 @@ +/* + * include/linux/nfsd/interface.h + * + * defines interface between nfsd and other bits of + * the kernel. Particularly filesystems (eventually). + * + * Copyright (C) 2000 Neil Brown + */ + +#ifndef LINUX_NFSD_INTERFACE_H +#define LINUX_NFSD_INTERFACE_H + +#include + +#ifdef CONFIG_NFSD_MODULE + +extern struct nfsd_linkage { + long (*do_nfsservctl)(int cmd, void *argp, void *resp); +} * nfsd_linkage; + +#endif + +#endif /* LINUX_NFSD_INTERFACE_H */ diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/nfsd/nfsd.h linux/include/linux/nfsd/nfsd.h --- v2.4.0-test7/linux/include/linux/nfsd/nfsd.h Wed Aug 23 18:36:39 2000 +++ linux/include/linux/nfsd/nfsd.h Wed Sep 6 14:50:04 2000 @@ -21,7 +21,7 @@ #include #include #include - +#include /* * nfsd version */ diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/pagemap.h linux/include/linux/pagemap.h --- v2.4.0-test7/linux/include/linux/pagemap.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/pagemap.h Wed Sep 6 14:49:47 2000 @@ -62,7 +62,6 @@ #define s(x) ((x)+((x)>>PAGE_HASH_BITS)) return s(i+index) & (PAGE_HASH_SIZE-1); #undef i -#undef o #undef s } diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h --- v2.4.0-test7/linux/include/linux/pci_ids.h Wed Aug 23 18:36:39 2000 +++ linux/include/linux/pci_ids.h Mon Aug 28 21:25:25 2000 @@ -333,9 +333,11 @@ #define PCI_DEVICE_ID_SI_300 0x0300 #define PCI_DEVICE_ID_SI_530 0x0530 #define PCI_DEVICE_ID_SI_540 0x0540 +#define PCI_DEVICE_ID_SI_540_VGA 0x5300 #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 #define PCI_DEVICE_ID_SI_630 0x0630 +#define PCI_DEVICE_ID_SI_630_VGA 0x6300 #define PCI_DEVICE_ID_SI_5107 0x5107 #define PCI_DEVICE_ID_SI_5300 0x5300 #define PCI_DEVICE_ID_SI_5511 0x5511 diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.4.0-test7/linux/include/linux/sched.h Wed Aug 23 18:36:39 2000 +++ linux/include/linux/sched.h Wed Sep 6 14:49:42 2000 @@ -33,11 +33,14 @@ #define CLONE_VM 0x00000100 /* set if VM shared between processes */ #define CLONE_FS 0x00000200 /* set if fs info shared between processes */ #define CLONE_FILES 0x00000400 /* set if open files shared between processes */ -#define CLONE_SIGHAND 0x00000800 /* set if signal handlers shared */ +#define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */ #define CLONE_PID 0x00001000 /* set if pid shared */ #define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ #define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ +#define CLONE_THREAD 0x00010000 /* Same thread group? */ + +#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD) /* * These are the constant used to fake the fixed-point load-average @@ -311,6 +314,7 @@ pid_t pgrp; pid_t tty_old_pgrp; pid_t session; + pid_t tgid; /* boolean value for session group leader */ int leader; /* @@ -319,6 +323,7 @@ * p->p_pptr->pid) */ struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; + struct list_head thread_group; /* PID hash table linkage. */ struct task_struct *pidhash_next; @@ -363,8 +368,10 @@ /* signal handlers */ spinlock_t sigmask_lock; /* Protects signal and blocked */ struct signal_struct *sig; - sigset_t signal, blocked; - struct signal_queue *sigqueue, **sigqueue_tail; + + sigset_t blocked; + struct sigpending pending; + unsigned long sas_ss_sp; size_t sas_ss_size; int (*notifier)(void *priv); @@ -435,6 +442,7 @@ prev_task: &tsk, \ p_opptr: &tsk, \ p_pptr: &tsk, \ + thread_group: LIST_HEAD_INIT(tsk.thread_group), \ wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\ real_timer: { \ function: it_real_fn \ @@ -451,10 +459,8 @@ files: &init_files, \ sigmask_lock: SPIN_LOCK_UNLOCKED, \ sig: &init_signals, \ - signal: {{0}}, \ + pending: { NULL, &tsk.pending.head, {{0}}}, \ blocked: {{0}}, \ - sigqueue: NULL, \ - sigqueue_tail: &tsk.sigqueue, \ alloc_lock: SPIN_LOCK_UNLOCKED \ } @@ -556,8 +562,8 @@ extern int kill_pg_info(int, struct siginfo *, pid_t); extern int kill_sl_info(int, struct siginfo *, pid_t); extern int kill_proc_info(int, struct siginfo *, pid_t); -extern int kill_something_info(int, struct siginfo *, int); extern void notify_parent(struct task_struct *, int); +extern void do_notify_parent(struct task_struct *, int); extern void force_sig(int, struct task_struct *); extern int send_sig(int, struct task_struct *, int); extern int kill_pg(pid_t, int, int); @@ -571,11 +577,11 @@ return (p->sigpending != 0); } -/* Reevaluate whether the task has signals pending delivery. - This is required every time the blocked sigset_t changes. - All callers should have t->sigmask_lock. */ - -static inline void recalc_sigpending(struct task_struct *t) +/* + * Re-calculate pending state from the set of locally pending + * signals, globally pending signals, and blocked signals. + */ +static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked) { unsigned long ready; long i; @@ -583,23 +589,31 @@ switch (_NSIG_WORDS) { default: for (i = _NSIG_WORDS, ready = 0; --i >= 0 ;) - ready |= t->signal.sig[i] &~ t->blocked.sig[i]; + ready |= signal->sig[i] &~ blocked->sig[i]; break; - case 4: ready = t->signal.sig[3] &~ t->blocked.sig[3]; - ready |= t->signal.sig[2] &~ t->blocked.sig[2]; - ready |= t->signal.sig[1] &~ t->blocked.sig[1]; - ready |= t->signal.sig[0] &~ t->blocked.sig[0]; + case 4: ready = signal->sig[3] &~ blocked->sig[3]; + ready |= signal->sig[2] &~ blocked->sig[2]; + ready |= signal->sig[1] &~ blocked->sig[1]; + ready |= signal->sig[0] &~ blocked->sig[0]; break; - case 2: ready = t->signal.sig[1] &~ t->blocked.sig[1]; - ready |= t->signal.sig[0] &~ t->blocked.sig[0]; + case 2: ready = signal->sig[1] &~ blocked->sig[1]; + ready |= signal->sig[0] &~ blocked->sig[0]; break; - case 1: ready = t->signal.sig[0] &~ t->blocked.sig[0]; + case 1: ready = signal->sig[0] &~ blocked->sig[0]; } + return ready != 0; +} + +/* Reevaluate whether the task has signals pending delivery. + This is required every time the blocked sigset_t changes. + All callers should have t->sigmask_lock. */ - t->sigpending = (ready != 0); +static inline void recalc_sigpending(struct task_struct *t) +{ + t->sigpending = has_pending_signals(&t->pending.signal, &t->blocked); } /* True if we are on the alternate signal stack. */ @@ -704,7 +718,7 @@ extern int expand_fdset(struct files_struct *, int nr); extern void free_fdset(fd_set *, int); -extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); +extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); extern void flush_thread(void); extern void exit_thread(void); @@ -715,7 +729,7 @@ extern void daemonize(void); extern int do_execve(char *, char **, char **, struct pt_regs *); -extern int do_fork(unsigned long, unsigned long, struct pt_regs *); +extern int do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long); extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); @@ -798,6 +812,8 @@ #define for_each_task(p) \ for (p = &init_task ; (p = p->next_task) != &init_task ; ) +#define next_thread(p) \ + list_entry((p)->thread_group.next, struct task_struct, thread_group) static inline void del_from_runqueue(struct task_struct * p) { @@ -818,6 +834,7 @@ nr_threads--; unhash_pid(p); REMOVE_LINKS(p); + list_del(&p->thread_group); write_unlock_irq(&tasklist_lock); } diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/signal.h linux/include/linux/signal.h --- v2.4.0-test7/linux/include/linux/signal.h Wed Aug 18 16:43:29 1999 +++ linux/include/linux/signal.h Wed Sep 6 14:49:39 2000 @@ -9,12 +9,16 @@ * Real Time signals may be queued. */ -struct signal_queue -{ - struct signal_queue *next; +struct sigqueue { + struct sigqueue *next; siginfo_t info; }; +struct sigpending { + struct sigqueue *head, **tail; + sigset_t signal; +}; + /* * Define some primitives to manipulate sigset_t. */ @@ -206,6 +210,15 @@ } #endif /* __HAVE_ARCH_SIG_SETOPS */ + +static inline void init_sigpending(struct sigpending *sig) +{ + sigemptyset(&sig->signal); + sig->head = NULL; + sig->tail = &sig->head; +} + +extern long do_sigpending(void *, unsigned long); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test7/linux/include/linux/wait.h linux/include/linux/wait.h --- v2.4.0-test7/linux/include/linux/wait.h Fri Jul 14 12:12:16 2000 +++ linux/include/linux/wait.h Wed Sep 6 14:49:31 2000 @@ -4,8 +4,9 @@ #define WNOHANG 0x00000001 #define WUNTRACED 0x00000002 -#define __WALL 0x40000000 -#define __WCLONE 0x80000000 +#define __WNOTHREAD 0x20000000 /* Don't wait on children of other threads in this group */ +#define __WALL 0x40000000 /* Wait on all children, regardless of type */ +#define __WCLONE 0x80000000 /* Wait only on non-SIGCHLD children */ #ifdef __KERNEL__ @@ -184,7 +185,7 @@ if (!head->task_list.next || !head->task_list.prev) WQ_BUG(); #endif - list_add(&new->task_list, head->task_list.prev); + list_add_tail(&new->task_list, &head->task_list); } extern inline void __remove_wait_queue(wait_queue_head_t *head, diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/bulkmem.h linux/include/pcmcia/bulkmem.h --- v2.4.0-test7/linux/include/pcmcia/bulkmem.h Mon Dec 20 18:48:22 1999 +++ linux/include/pcmcia/bulkmem.h Sat Sep 2 00:13:49 2000 @@ -1,7 +1,7 @@ /* * Definitions for bulk memory services * - * bulkmem.h 1.11 1999/10/25 20:23:16 + * bulkmem.h 1.12 2000/06/12 21:55:41 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -14,7 +14,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/bus_ops.h linux/include/pcmcia/bus_ops.h --- v2.4.0-test7/linux/include/pcmcia/bus_ops.h Thu Nov 18 20:25:38 1999 +++ linux/include/pcmcia/bus_ops.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * bus_ops.h 1.8 1999/10/25 20:23:16 + * bus_ops.h 1.10 2000/06/12 21:55:41 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/ciscode.h linux/include/pcmcia/ciscode.h --- v2.4.0-test7/linux/include/pcmcia/ciscode.h Wed Feb 16 17:03:52 2000 +++ linux/include/pcmcia/ciscode.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * ciscode.h 1.40 2000/02/01 19:06:40 + * ciscode.h 1.45 2000/08/12 02:08:23 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the @@ -78,6 +78,9 @@ #define MANFID_NEW_MEDIA 0x0057 +#define MANFID_NOKIA 0x0124 +#define PRODID_NOKIA_CARDPHONE 0x0900 + #define MANFID_OLICOM 0x0121 #define PRODID_OLICOM_OC2231 0x3122 #define PRODID_OLICOM_OC2232 0x3222 @@ -94,6 +97,7 @@ #define MANFID_PIONEER 0x000b #define MANFID_PSION 0x016c +#define PRODID_PSION_NET100 0x0023 #define MANFID_QUATECH 0x0137 #define PRODID_QUATECH_SPP100 0x0003 @@ -106,11 +110,14 @@ #define MANFID_SOCKET 0x0104 #define PRODID_SOCKET_DUAL_RS232 0x0006 +#define PRODID_SOCKET_EIO 0x000a #define PRODID_SOCKET_LPE 0x000d #define MANFID_SUNDISK 0x0045 #define MANFID_TDK 0x0105 + +#define MANFID_TOSHIBA 0x0098 #define MANFID_XIRCOM 0x0105 diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/cisreg.h linux/include/pcmcia/cisreg.h --- v2.4.0-test7/linux/include/pcmcia/cisreg.h Fri Jan 21 18:19:17 2000 +++ linux/include/pcmcia/cisreg.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * cisreg.h 1.16 2000/01/16 19:19:14 + * cisreg.h 1.17 2000/06/12 21:55:41 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/cistpl.h linux/include/pcmcia/cistpl.h --- v2.4.0-test7/linux/include/pcmcia/cistpl.h Fri Jan 21 18:19:17 2000 +++ linux/include/pcmcia/cistpl.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * cistpl.h 1.32 2000/01/11 19:06:50 + * cistpl.h 1.34 2000/06/19 23:18:12 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the @@ -68,6 +68,7 @@ #define CISTPL_BYTEORDER 0x43 #define CISTPL_DATE 0x44 #define CISTPL_BATTERY 0x45 +#define CISTPL_FORMAT_A 0x47 /* Layer 3 tuples */ #define CISTPL_ORG 0x46 #define CISTPL_SPCL 0x90 @@ -530,6 +531,21 @@ #define CISTPL_ORG_APPSPEC 0x01 #define CISTPL_ORG_XIP 0x02 +typedef struct cistpl_format_t { + u_char type; + u_char edc; + u_int offset; + u_int length; +} cistpl_format_t; + +#define CISTPL_FORMAT_DISK 0x00 +#define CISTPL_FORMAT_MEM 0x01 + +#define CISTPL_EDC_NONE 0x00 +#define CISTPL_EDC_CKSUM 0x01 +#define CISTPL_EDC_CRC 0x02 +#define CISTPL_EDC_PCC 0x03 + typedef union cisparse_t { cistpl_device_t device; cistpl_checksum_t checksum; @@ -548,6 +564,7 @@ cistpl_device_geo_t device_geo; cistpl_vers_2_t vers_2; cistpl_org_t org; + cistpl_format_t format; } cisparse_t; typedef struct tuple_t { diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/cs.h linux/include/pcmcia/cs.h --- v2.4.0-test7/linux/include/pcmcia/cs.h Fri Jan 21 18:19:17 2000 +++ linux/include/pcmcia/cs.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * cs.h 1.69 1999/10/25 20:23:17 + * cs.h 1.71 2000/08/29 00:54:20 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the @@ -250,11 +250,6 @@ #define PRESENT_IOBASE_2 0x080 #define PRESENT_IOBASE_3 0x100 #define PRESENT_IOSIZE 0x200 - -/* Attributes for Request/GetConfiguration */ -#define CONF_ENABLE_IRQ 0x01 -#define EXCLUSIVE_USE 0x02 -#define VALID_CLIENT 0x04 /* For GetMemPage, MapMemPage */ typedef struct memreq_t { diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/cs_types.h linux/include/pcmcia/cs_types.h --- v2.4.0-test7/linux/include/pcmcia/cs_types.h Fri Jan 21 18:19:17 2000 +++ linux/include/pcmcia/cs_types.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * cs_types.h 1.17 2000/01/18 01:14:36 + * cs_types.h 1.18 2000/06/12 21:55:40 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/driver_ops.h linux/include/pcmcia/driver_ops.h --- v2.4.0-test7/linux/include/pcmcia/driver_ops.h Thu Nov 11 20:11:54 1999 +++ linux/include/pcmcia/driver_ops.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * driver_ops.h 1.14 1999/10/25 20:23:17 + * driver_ops.h 1.15 2000/06/12 21:55:40 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/ds.h linux/include/pcmcia/ds.h --- v2.4.0-test7/linux/include/pcmcia/ds.h Thu Nov 11 20:11:54 1999 +++ linux/include/pcmcia/ds.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * ds.h 1.55 1999/10/25 20:23:17 + * ds.h 1.56 2000/06/12 21:55:40 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/ftl.h linux/include/pcmcia/ftl.h --- v2.4.0-test7/linux/include/pcmcia/ftl.h Thu Nov 11 20:11:54 1999 +++ linux/include/pcmcia/ftl.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * ftl.h 1.7 1999/10/25 20:23:17 + * ftl.h 1.8 2000/06/12 21:55:40 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/mem_op.h linux/include/pcmcia/mem_op.h --- v2.4.0-test7/linux/include/pcmcia/mem_op.h Thu Nov 11 20:11:54 1999 +++ linux/include/pcmcia/mem_op.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * mem_op.h 1.12 1999/10/25 20:23:17 + * mem_op.h 1.13 2000/06/12 21:55:40 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/memory.h linux/include/pcmcia/memory.h --- v2.4.0-test7/linux/include/pcmcia/memory.h Thu Nov 11 20:11:54 1999 +++ linux/include/pcmcia/memory.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * memory.h 1.6 1999/10/25 20:23:17 + * memory.h 1.7 2000/06/12 21:55:40 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/ss.h linux/include/pcmcia/ss.h --- v2.4.0-test7/linux/include/pcmcia/ss.h Wed Feb 16 17:03:52 2000 +++ linux/include/pcmcia/ss.h Sat Sep 2 00:13:49 2000 @@ -1,5 +1,5 @@ /* - * ss.h 1.26 2000/02/04 20:35:21 + * ss.h 1.28 2000/06/12 21:55:40 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -12,7 +12,7 @@ * limitations under the License. * * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds + * . Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Alternatively, the contents of this file may be used under the @@ -61,6 +61,7 @@ #define SS_CAP_PAGE_REGS 0x0001 #define SS_CAP_VIRTUAL_BUS 0x0002 #define SS_CAP_MEM_ALIGN 0x0004 +#define SS_CAP_STATIC_MAP 0x0008 #define SS_CAP_PCCARD 0x4000 #define SS_CAP_CARDBUS 0x8000 diff -u --recursive --new-file v2.4.0-test7/linux/include/pcmcia/version.h linux/include/pcmcia/version.h --- v2.4.0-test7/linux/include/pcmcia/version.h Wed Feb 16 17:03:52 2000 +++ linux/include/pcmcia/version.h Sat Sep 2 00:13:49 2000 @@ -1,4 +1,4 @@ -/* version.h 1.83 2000/02/03 02:16:14 (David Hinds) */ +/* version.h 1.92 2000/07/21 18:26:56 (David Hinds) */ -#define CS_RELEASE "3.1.11" -#define CS_RELEASE_CODE 0x310b +#define CS_RELEASE "3.1.20" +#define CS_RELEASE_CODE 0x3115 diff -u --recursive --new-file v2.4.0-test7/linux/include/scsi/scsi.h linux/include/scsi/scsi.h --- v2.4.0-test7/linux/include/scsi/scsi.h Tue Dec 14 01:27:24 1999 +++ linux/include/scsi/scsi.h Tue Sep 5 14:08:55 2000 @@ -137,6 +137,7 @@ #define TYPE_MOD 0x07 /* Magneto-optical disk - * - treated as TYPE_DISK */ #define TYPE_MEDIUM_CHANGER 0x08 +#define TYPE_COMM 0x09 /* Communications device */ #define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ #define TYPE_NO_LUN 0x7f diff -u --recursive --new-file v2.4.0-test7/linux/init/main.c linux/init/main.c --- v2.4.0-test7/linux/init/main.c Wed Aug 23 18:36:39 2000 +++ linux/init/main.c Fri Sep 1 14:25:26 2000 @@ -584,7 +584,7 @@ * make syscalls (and thus be locked). */ smp_init(); - kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); unlock_kernel(); current->need_resched = 1; cpu_idle(); diff -u --recursive --new-file v2.4.0-test7/linux/kernel/exit.c linux/kernel/exit.c --- v2.4.0-test7/linux/kernel/exit.c Wed Aug 23 18:36:39 2000 +++ linux/kernel/exit.c Fri Sep 1 18:08:46 2000 @@ -144,17 +144,29 @@ return retval; } +/* + * When we die, we re-parent all our children. + * Try to give them to another thread in our process + * group, and if no such member exists, give it to + * the global child reaper process (ie "init") + */ static inline void forget_original_parent(struct task_struct * father) { - struct task_struct * p; + struct task_struct * p, *reaper; read_lock(&tasklist_lock); + + /* Next in our thread group */ + reaper = next_thread(father); + if (reaper == father) + reaper = child_reaper; + for_each_task(p) { if (p->p_opptr == father) { /* We dont want people slaying init */ p->exit_signal = SIGCHLD; p->self_exec_id++; - p->p_opptr = child_reaper; /* init */ + p->p_opptr = reaper; if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0); } } @@ -255,26 +267,6 @@ __exit_fs(tsk); } -static inline void __exit_sighand(struct task_struct *tsk) -{ - struct signal_struct * sig = tsk->sig; - - if (sig) { - spin_lock_irq(&tsk->sigmask_lock); - tsk->sig = NULL; - spin_unlock_irq(&tsk->sigmask_lock); - if (atomic_dec_and_test(&sig->count)) - kmem_cache_free(sigact_cachep, sig); - } - - flush_signals(tsk); -} - -void exit_sighand(struct task_struct *tsk) -{ - __exit_sighand(tsk); -} - /* * We can use these to temporarily drop into * "lazy TLB" mode and back. @@ -378,7 +370,6 @@ && !capable(CAP_KILL)) current->exit_signal = SIGCHLD; - notify_parent(current, current->exit_signal); /* * This loop does two things: @@ -390,6 +381,7 @@ */ write_lock_irq(&tasklist_lock); + do_notify_parent(current, current->exit_signal); while (current->p_cptr != NULL) { p = current->p_cptr; current->p_cptr = p->p_osptr; @@ -402,7 +394,7 @@ p->p_osptr->p_ysptr = p; p->p_pptr->p_cptr = p; if (p->state == TASK_ZOMBIE) - notify_parent(p, p->exit_signal); + do_notify_parent(p, p->exit_signal); /* * process group orphan check * Case ii: Our child is in a different pgrp @@ -449,7 +441,7 @@ __exit_mm(tsk); __exit_files(tsk); __exit_fs(tsk); - __exit_sighand(tsk); + exit_sighand(tsk); exit_thread(); tsk->state = TASK_ZOMBIE; tsk->exit_code = code; @@ -483,9 +475,9 @@ { int flag, retval; DECLARE_WAITQUEUE(wait, current); - struct task_struct *p; + struct task_struct *tsk; - if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL)) + if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL)) return -EINVAL; add_wait_queue(¤t->wait_chldexit,&wait); @@ -493,27 +485,30 @@ flag = 0; current->state = TASK_INTERRUPTIBLE; read_lock(&tasklist_lock); - for (p = current->p_cptr ; p ; p = p->p_osptr) { - if (pid>0) { - if (p->pid != pid) - continue; - } else if (!pid) { - if (p->pgrp != current->pgrp) - continue; - } else if (pid != -1) { - if (p->pgrp != -pid) + tsk = current; + do { + struct task_struct *p; + for (p = tsk->p_cptr ; p ; p = p->p_osptr) { + if (pid>0) { + if (p->pid != pid) + continue; + } else if (!pid) { + if (p->pgrp != current->pgrp) + continue; + } else if (pid != -1) { + if (p->pgrp != -pid) + continue; + } + /* Wait for all children (clone and not) if __WALL is set; + * otherwise, wait for clone children *only* if __WCLONE is + * set; otherwise, wait for non-clone children *only*. (Note: + * A "clone" child here is one that reports to its parent + * using a signal other than SIGCHLD.) */ + if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) + && !(options & __WALL)) continue; - } - /* Wait for all children (clone and not) if __WALL is set; - * otherwise, wait for clone children *only* if __WCLONE is - * set; otherwise, wait for non-clone children *only*. (Note: - * A "clone" child here is one that reports to its parent - * using a signal other than SIGCHLD.) */ - if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) - && !(options & __WALL)) - continue; - flag = 1; - switch (p->state) { + flag = 1; + switch (p->state) { case TASK_STOPPED: if (!p->exit_code) continue; @@ -543,15 +538,19 @@ REMOVE_LINKS(p); p->p_pptr = p->p_opptr; SET_LINKS(p); + do_notify_parent(p, SIGCHLD); write_unlock_irq(&tasklist_lock); - notify_parent(p, SIGCHLD); } else release(p); goto end_wait4; default: continue; + } } - } + if (options & __WNOTHREAD) + break; + tsk = next_thread(tsk); + } while (tsk != current); read_unlock(&tasklist_lock); if (flag) { retval = 0; diff -u --recursive --new-file v2.4.0-test7/linux/kernel/fork.c linux/kernel/fork.c --- v2.4.0-test7/linux/kernel/fork.c Wed Aug 23 18:36:39 2000 +++ linux/kernel/fork.c Tue Sep 5 14:48:59 2000 @@ -500,15 +500,18 @@ static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk) { + struct signal_struct *sig; + if (clone_flags & CLONE_SIGHAND) { atomic_inc(¤t->sig->count); return 0; } - tsk->sig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL); - if (!tsk->sig) + sig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL); + tsk->sig = sig; + if (!sig) return -1; - spin_lock_init(&tsk->sig->siglock); - atomic_set(&tsk->sig->count, 1); + spin_lock_init(&sig->siglock); + atomic_set(&sig->count, 1); memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action)); return 0; } @@ -528,10 +531,15 @@ /* * Ok, this is the main fork-routine. It copies the system process - * information (task[nr]) and sets up the necessary registers. It - * also copies the data segment in its entirety. + * information (task[nr]) and sets up the necessary registers. It also + * copies the data segment in its entirety. The "stack_start" and + * "stack_top" arguments are simply passed along to the platform + * specific copy_thread() routine. Most platforms ignore stack_top. + * For an example that's using stack_top, see + * arch/ia64/kernel/process.c. */ -int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) +int do_fork(unsigned long clone_flags, unsigned long stack_start, + struct pt_regs *regs, unsigned long stack_top) { int retval = -ENOMEM; struct task_struct *p; @@ -591,9 +599,7 @@ spin_lock_init(&p->alloc_lock); p->sigpending = 0; - sigemptyset(&p->signal); - p->sigqueue = NULL; - p->sigqueue_tail = &p->sigqueue; + init_sigpending(&p->pending); p->it_real_value = p->it_virt_value = p->it_prof_value = 0; p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0; @@ -628,7 +634,7 @@ goto bad_fork_cleanup_fs; if (copy_mm(clone_flags, p)) goto bad_fork_cleanup_sighand; - retval = copy_thread(0, clone_flags, usp, p, regs); + retval = copy_thread(0, clone_flags, stack_start, stack_top, p, regs); if (retval) goto bad_fork_cleanup_sighand; p->semundo = NULL; @@ -661,7 +667,13 @@ * Let it rip! */ retval = p->pid; + p->tgid = retval; + INIT_LIST_HEAD(&p->thread_group); write_lock_irq(&tasklist_lock); + if (clone_flags & CLONE_THREAD) { + p->tgid = current->tgid; + list_add(&p->thread_group, ¤t->thread_group); + } SET_LINKS(p); hash_pid(p); nr_threads++; diff -u --recursive --new-file v2.4.0-test7/linux/kernel/info.c linux/kernel/info.c --- v2.4.0-test7/linux/kernel/info.c Thu Aug 26 13:05:42 1999 +++ linux/kernel/info.c Tue Sep 5 13:57:57 2000 @@ -32,6 +32,42 @@ si_meminfo(&val); si_swapinfo(&val); + { + /* If the sum of all the available memory (i.e. ram + swap + + * highmem) is less then can be stored in a 32 bit unsigned long + * then we can be binary compatible with 2.2.x kernels. If not, + * well, who cares since in that case 2.2.x was broken anyways... + * + * -Erik Andersen */ + + unsigned long mem_total = val.totalram + val.totalswap; + if ( !(mem_total < val.totalram || mem_total < val.totalswap)) { + unsigned long mem_total2 = mem_total + val.totalhigh; + if (!(mem_total2 < mem_total || mem_total2 < val.totalhigh)) + { + /* If mem_total did not overflow. Divide all memory values by + * mem_unit and set mem_unit=1. This leaves things compatible with + * 2.2.x, and also retains compatibility with earlier 2.4.x + * kernels... */ + + int bitcount = 0; + while (val.mem_unit > 1) + { + bitcount++; + val.mem_unit >>= 1; + } + val.totalram <<= bitcount; + val.freeram <<= bitcount; + val.sharedram <<= bitcount; + val.bufferram <<= bitcount; + val.totalswap <<= bitcount; + val.freeswap <<= bitcount; + val.totalhigh <<= bitcount; + val.freehigh <<= bitcount; + } + } + } + if (copy_to_user(info, &val, sizeof(struct sysinfo))) return -EFAULT; return 0; diff -u --recursive --new-file v2.4.0-test7/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.4.0-test7/linux/kernel/ksyms.c Wed Aug 23 18:36:39 2000 +++ linux/kernel/ksyms.c Tue Sep 5 18:56:47 2000 @@ -55,9 +55,6 @@ extern int console_loglevel; extern void set_device_ro(kdev_t dev,int flag); -#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) -extern long (*do_nfsservctl)(int, void *, void *); -#endif extern void *sys_call_table; @@ -206,6 +203,7 @@ EXPORT_SYMBOL(block_sync_page); EXPORT_SYMBOL(cont_prepare_write); EXPORT_SYMBOL(generic_commit_write); +EXPORT_SYMBOL(block_truncate_page); EXPORT_SYMBOL(generic_block_bmap); EXPORT_SYMBOL(generic_file_read); EXPORT_SYMBOL(do_generic_file_read); @@ -264,10 +262,6 @@ EXPORT_SYMBOL(filemap_swapout); EXPORT_SYMBOL(filemap_sync); EXPORT_SYMBOL(lock_page); - -#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) -EXPORT_SYMBOL(do_nfsservctl); -#endif /* device registration */ EXPORT_SYMBOL(register_chrdev); diff -u --recursive --new-file v2.4.0-test7/linux/kernel/sched.c linux/kernel/sched.c --- v2.4.0-test7/linux/kernel/sched.c Wed Aug 23 18:36:39 2000 +++ linux/kernel/sched.c Fri Sep 1 14:05:25 2000 @@ -213,7 +213,9 @@ * This function must be inline as anything that saves and restores * flags has to do so within the same register window on sparc (Anton) */ -static inline void reschedule_idle(struct task_struct * p, unsigned long flags) +static FASTCALL(void reschedule_idle(struct task_struct * p)); + +static void reschedule_idle(struct task_struct * p) { #ifdef CONFIG_SMP int this_cpu = smp_processor_id(); @@ -284,7 +286,6 @@ goto preempt_now; } - spin_unlock_irqrestore(&runqueue_lock, flags); return; send_now_idle: @@ -296,12 +297,10 @@ if ((tsk->processor != current->processor) && !tsk->need_resched) smp_send_reschedule(tsk->processor); tsk->need_resched = 1; - spin_unlock_irqrestore(&runqueue_lock, flags); return; preempt_now: tsk->need_resched = 1; - spin_unlock_irqrestore(&runqueue_lock, flags); /* * the APIC stuff can go outside of the lock because * it uses no task information, only CPU#. @@ -316,7 +315,6 @@ tsk = cpu_curr(this_cpu); if (preemption_goodness(tsk, p, this_cpu) > 1) tsk->need_resched = 1; - spin_unlock_irqrestore(&runqueue_lock, flags); #endif } @@ -365,9 +363,7 @@ if (task_on_runqueue(p)) goto out; add_to_runqueue(p); - reschedule_idle(p, flags); // spin_unlocks runqueue - - return; + reschedule_idle(p); out: spin_unlock_irqrestore(&runqueue_lock, flags); } @@ -455,17 +451,34 @@ static inline void __schedule_tail(struct task_struct *prev) { #ifdef CONFIG_SMP - if ((prev->state == TASK_RUNNING) && - (prev != idle_task(smp_processor_id()))) { - unsigned long flags; - - spin_lock_irqsave(&runqueue_lock, flags); - prev->has_cpu = 0; - reschedule_idle(prev, flags); // spin_unlocks runqueue - } else { - wmb(); - prev->has_cpu = 0; - } + unsigned long flags; + + /* + * fast path falls through. We have to take the runqueue lock + * unconditionally to make sure that the test of prev->state + * and setting has_cpu is atomic wrt. interrupts. It's not + * a big problem in the common case because we recently took + * the runqueue lock so it's likely to be in this processor's + * cache. + */ + spin_lock_irqsave(&runqueue_lock, flags); + prev->has_cpu = 0; + if (prev->state == TASK_RUNNING) + goto running_again; +out_unlock: + spin_unlock_irqrestore(&runqueue_lock, flags); + return; + + /* + * Slow path - we 'push' the previous process and + * reschedule_idle() will attempt to find a new + * processor for it. (but it might preempt the + * current process as well.) + */ +running_again: + if (prev != idle_task(smp_processor_id())) + reschedule_idle(prev); + goto out_unlock; #endif /* CONFIG_SMP */ } @@ -638,6 +651,9 @@ same_process: reacquire_kernel_lock(current); + if (current->need_resched) + goto tq_scheduler_back; + return; recalculate: @@ -1124,13 +1140,13 @@ printk("\n"); { - struct signal_queue *q; + struct sigqueue *q; char s[sizeof(sigset_t)*2+1], b[sizeof(sigset_t)*2+1]; - render_sigset_t(&p->signal, s); + render_sigset_t(&p->pending.signal, s); render_sigset_t(&p->blocked, b); printk(" sig: %d %s %s :", signal_pending(p), s, b); - for (q = p->sigqueue; q ; q = q->next) + for (q = p->pending.head; q ; q = q->next) printk(" %d", q->info.si_signo); printk(" X\n"); } diff -u --recursive --new-file v2.4.0-test7/linux/kernel/signal.c linux/kernel/signal.c --- v2.4.0-test7/linux/kernel/signal.c Wed Aug 23 18:36:39 2000 +++ linux/kernel/signal.c Tue Sep 5 09:53:59 2000 @@ -28,32 +28,32 @@ #define SIG_SLAB_DEBUG 0 #endif -static kmem_cache_t *signal_queue_cachep; +static kmem_cache_t *sigqueue_cachep; atomic_t nr_queued_signals; int max_queued_signals = 1024; void __init signals_init(void) { - signal_queue_cachep = - kmem_cache_create("signal_queue", - sizeof(struct signal_queue), - __alignof__(struct signal_queue), + sigqueue_cachep = + kmem_cache_create("sigqueue", + sizeof(struct sigqueue), + __alignof__(struct sigqueue), SIG_SLAB_DEBUG, NULL, NULL); - if (!signal_queue_cachep) - panic("signals_init(): cannot create signal_queue SLAB cache"); + if (!sigqueue_cachep) + panic("signals_init(): cannot create sigueue SLAB cache"); } /* Given the mask, find the first available signal that should be serviced. */ static int -next_signal(sigset_t *signal, sigset_t *mask) +next_signal(struct task_struct *tsk, sigset_t *mask) { unsigned long i, *s, *m, x; int sig = 0; - s = signal->sig; + s = tsk->pending.signal.sig; m = mask->sig; switch (_NSIG_WORDS) { default: @@ -81,6 +81,23 @@ return sig; } +static void flush_sigqueue(struct sigpending *queue) +{ + struct sigqueue *q, *n; + + sigemptyset(&queue->signal); + q = queue->head; + queue->head = NULL; + queue->tail = &queue->head; + + while (q) { + n = q->next; + kmem_cache_free(sigqueue_cachep, q); + atomic_dec(&nr_queued_signals); + q = n; + } +} + /* * Flush all pending signals for a task. */ @@ -88,20 +105,23 @@ void flush_signals(struct task_struct *t) { - struct signal_queue *q, *n; - t->sigpending = 0; - sigemptyset(&t->signal); - q = t->sigqueue; - t->sigqueue = NULL; - t->sigqueue_tail = &t->sigqueue; + flush_sigqueue(&t->pending); +} - while (q) { - n = q->next; - kmem_cache_free(signal_queue_cachep, q); - atomic_dec(&nr_queued_signals); - q = n; - } +void exit_sighand(struct task_struct *tsk) +{ + struct signal_struct * sig = tsk->sig; + + spin_lock_irq(&tsk->sigmask_lock); + if (sig) { + tsk->sig = NULL; + if (atomic_dec_and_test(&sig->count)) + kmem_cache_free(sigact_cachep, sig); + } + tsk->sigpending = 0; + flush_sigqueue(&tsk->pending); + spin_unlock_irq(&tsk->sigmask_lock); } /* @@ -133,9 +153,13 @@ void block_all_signals(int (*notifier)(void *priv), void *priv, sigset_t *mask) { + unsigned long flags; + + spin_lock_irqsave(¤t->sigmask_lock, flags); current->notifier_mask = mask; current->notifier_data = priv; current->notifier = notifier; + spin_unlock_irqrestore(¤t->sigmask_lock, flags); } /* Notify the system that blocking has ended. */ @@ -143,9 +167,60 @@ void unblock_all_signals(void) { + unsigned long flags; + + spin_lock_irqsave(¤t->sigmask_lock, flags); current->notifier = NULL; current->notifier_data = NULL; recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); +} + +static int collect_signal(int sig, struct sigpending *list, siginfo_t *info) +{ + if (sigismember(&list->signal, sig)) { + /* Collect the siginfo appropriate to this signal. */ + struct sigqueue *q, **pp; + pp = &list->head; + while ((q = *pp) != NULL) { + if (q->info.si_signo == sig) + goto found_it; + pp = &q->next; + } + + /* Ok, it wasn't in the queue. We must have + been out of queue space. So zero out the + info. */ + info->si_signo = sig; + info->si_errno = 0; + info->si_code = 0; + info->si_pid = 0; + info->si_uid = 0; + return 1; + +found_it: + if ((*pp = q->next) == NULL) + list->tail = pp; + + /* Copy the sigqueue information and free the queue entry */ + copy_siginfo(info, &q->info); + kmem_cache_free(sigqueue_cachep,q); + atomic_dec(&nr_queued_signals); + + /* Non-RT signals can exist multiple times.. */ + if (sig >= SIGRTMIN) { + while ((q = *pp) != NULL) { + if (q->info.si_signo == sig) + goto found_another; + pp = &q->next; + } + } + + sigdelset(&list->signal, sig); +found_another: + return 1; + } + return 0; } /* @@ -165,82 +240,24 @@ signal_pending(current)); #endif - sig = next_signal(¤t->signal, mask); + sig = next_signal(current, mask); if (current->notifier) { - sigset_t merged; - int i; - int altsig; - - for (i = 0; i < _NSIG_WORDS; i++) - merged.sig[i] = mask->sig[i] - | current->notifier_mask->sig[i]; - altsig = next_signal(¤t->signal, &merged); - if (sig != altsig) { + if (sigismember(current->notifier_mask, sig)) { if (!(current->notifier)(current->notifier_data)) { current->sigpending = 0; return 0; - } + } } } if (sig) { - int reset = 1; - - /* Collect the siginfo appropriate to this signal. */ - struct signal_queue *q, **pp; - pp = ¤t->sigqueue; - q = current->sigqueue; - - /* Find the one we're interested in ... */ - for ( ; q ; pp = &q->next, q = q->next) - if (q->info.si_signo == sig) - break; - if (q) { - if ((*pp = q->next) == NULL) - current->sigqueue_tail = pp; - copy_siginfo(info, &q->info); - kmem_cache_free(signal_queue_cachep,q); - atomic_dec(&nr_queued_signals); - - /* Then see if this signal is still pending. - (Non rt signals may not be queued twice.) - */ - if (sig >= SIGRTMIN) - for (q = *pp; q; q = q->next) - if (q->info.si_signo == sig) { - reset = 0; - break; - } - - } else { - /* Ok, it wasn't in the queue. We must have - been out of queue space. So zero out the - info. */ - info->si_signo = sig; - info->si_errno = 0; - info->si_code = 0; - info->si_pid = 0; - info->si_uid = 0; - } - - if (reset) { - sigdelset(¤t->signal, sig); - recalc_sigpending(current); - } - + if (!collect_signal(sig, ¤t->pending, info)) + sig = 0; + /* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER, we need to xchg out the timer overrun values. */ - } else { - /* XXX: Once CLONE_PID is in to join those "threads" that are - part of the same "process", look for signals sent to the - "process" as well. */ - - /* Sanity check... */ - if (mask == ¤t->blocked && signal_pending(current)) { - printk(KERN_CRIT "SIG: sigpending lied\n"); - current->sigpending = 0; - } } + recalc_sigpending(current); #if DEBUG_SIG printk(" %d -> %d\n", signal_pending(current), sig); @@ -249,42 +266,92 @@ return sig; } +static int rm_from_queue(int sig, struct sigpending *s) +{ + struct sigqueue *q, **pp; + + if (!sigismember(&s->signal, sig)) + return 0; + + sigdelset(&s->signal, sig); + + pp = &s->head; + + while ((q = *pp) != NULL) { + if (q->info.si_signo == sig) { + if ((*pp = q->next) == NULL) + s->tail = pp; + kmem_cache_free(sigqueue_cachep,q); + atomic_dec(&nr_queued_signals); + continue; + } + pp = &q->next; + } + return 1; +} + /* - * Remove signal sig from queue and from t->signal. - * Returns 1 if sig was found in t->signal. + * Remove signal sig from t->pending. + * Returns 1 if sig was found. * * All callers must be holding t->sigmask_lock. */ static int rm_sig_from_queue(int sig, struct task_struct *t) { - struct signal_queue *q, **pp; + return rm_from_queue(sig, &t->pending); +} - if (sig >= SIGRTMIN) { - printk(KERN_CRIT "SIG: rm_sig_from_queue() doesn't support rt signals\n"); - return 0; - } +/* + * Bad permissions for sending the signal + */ +int bad_signal(int sig, struct siginfo *info, struct task_struct *t) +{ + return (!info || ((unsigned long)info != 1 && SI_FROMUSER(info))) + && ((sig != SIGCONT) || (current->session != t->session)) + && (current->euid ^ t->suid) && (current->euid ^ t->uid) + && (current->uid ^ t->suid) && (current->uid ^ t->uid) + && !capable(CAP_KILL); +} + +/* + * Signal type: + * < 0 : global action (kill - spread to all non-blocked threads) + * = 0 : ignored + * > 0 : wake up. + */ +static int signal_type(int sig, struct signal_struct *signals) +{ + unsigned long handler; - if (!sigismember(&t->signal, sig)) + if (!signals) return 0; + + handler = (unsigned long) signals->action[sig-1].sa.sa_handler; + if (handler > 1) + return 1; - sigdelset(&t->signal, sig); + /* "Ignore" handler.. Illogical, but that has an implicit handler for SIGCHLD */ + if (handler == 1) + return sig == SIGCHLD; - pp = &t->sigqueue; - q = t->sigqueue; + /* Default handler. Normally lethal, but.. */ + switch (sig) { - /* Find the one we're interested in ... - It may appear only once. */ - for ( ; q ; pp = &q->next, q = q->next) - if (q->info.si_signo == sig) - break; - if (q) { - if ((*pp = q->next) == NULL) - t->sigqueue_tail = pp; - kmem_cache_free(signal_queue_cachep,q); - atomic_dec(&nr_queued_signals); + /* Ignored */ + case SIGCONT: case SIGWINCH: + case SIGCHLD: case SIGURG: + return 0; + + /* Implicit behaviour */ + case SIGTSTP: case SIGTTIN: case SIGTTOU: + return 1; + + /* Implicit actions (kill or do special stuff) */ + default: + return -1; } - return 1; } + /* * Determine whether a signal should be posted or not. @@ -296,99 +363,44 @@ */ static int ignored_signal(int sig, struct task_struct *t) { - struct signal_struct *signals; - struct k_sigaction *ka; - /* Don't ignore traced or blocked signals */ if ((t->ptrace & PT_PTRACED) || sigismember(&t->blocked, sig)) return 0; - - signals = t->sig; - if (!signals) - return 1; - - ka = &signals->action[sig-1]; - switch ((unsigned long) ka->sa.sa_handler) { - case (unsigned long) SIG_DFL: - if (sig == SIGCONT || - sig == SIGWINCH || - sig == SIGCHLD || - sig == SIGURG) - break; - return 0; - case (unsigned long) SIG_IGN: - if (sig != SIGCHLD) - break; - /* fallthrough */ - default: - return 0; - } - return 1; + return signal_type(sig, t->sig) == 0; } -int -send_sig_info(int sig, struct siginfo *info, struct task_struct *t) +/* + * Handle TASK_STOPPED cases etc implicit behaviour + * of certain magical signals. + * + * SIGKILL gets spread out to every thread. + */ +static void handle_stop_signal(int sig, struct task_struct *t) { - unsigned long flags; - int ret; - struct signal_queue *q = 0; - - -#if DEBUG_SIG -printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); -#endif - - ret = -EINVAL; - if (sig < 0 || sig > _NSIG) - goto out_nolock; - /* The somewhat baroque permissions check... */ - ret = -EPERM; - if ((!info || ((unsigned long)info != 1 && SI_FROMUSER(info))) - && ((sig != SIGCONT) || (current->session != t->session)) - && (current->euid ^ t->suid) && (current->euid ^ t->uid) - && (current->uid ^ t->suid) && (current->uid ^ t->uid) - && !capable(CAP_KILL)) - goto out_nolock; - - /* The null signal is a permissions and process existance probe. - No signal is actually delivered. Same goes for zombies. */ - ret = 0; - if (!sig || !t->sig) - goto out_nolock; - - spin_lock_irqsave(&t->sigmask_lock, flags); switch (sig) { case SIGKILL: case SIGCONT: /* Wake up the process if stopped. */ if (t->state == TASK_STOPPED) wake_up_process(t); t->exit_code = 0; - if (rm_sig_from_queue(SIGSTOP, t) || rm_sig_from_queue(SIGTSTP, t) || - rm_sig_from_queue(SIGTTOU, t) || rm_sig_from_queue(SIGTTIN, t)) - recalc_sigpending(t); + rm_sig_from_queue(SIGSTOP, t); + rm_sig_from_queue(SIGTSTP, t); + rm_sig_from_queue(SIGTTOU, t); + rm_sig_from_queue(SIGTTIN, t); break; case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: /* If we're stopping again, cancel SIGCONT */ - if (rm_sig_from_queue(SIGCONT, t)) - recalc_sigpending(t); + rm_sig_from_queue(SIGCONT, t); break; } +} - /* Optimize away the signal, if it's a signal that can be - handled immediately (ie non-blocked and untraced) and - that is ignored (either explicitly or by default). */ - - if (ignored_signal(sig, t)) - goto out; - - /* Support queueing exactly one non-rt signal, so that we - can get more detailed information about the cause of - the signal. */ - if (sig < SIGRTMIN && sigismember(&t->signal, sig)) - goto out; +static int send_signal(int sig, struct siginfo *info, struct sigpending *signals) +{ + struct sigqueue * q = NULL; /* Real-time signals must be queued if sent by sigqueue, or some other real-time mechanism. It is implementation @@ -399,15 +411,14 @@ pass on the info struct. */ if (atomic_read(&nr_queued_signals) < max_queued_signals) { - q = (struct signal_queue *) - kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC); + q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC); } if (q) { atomic_inc(&nr_queued_signals); q->next = NULL; - *t->sigqueue_tail = q; - t->sigqueue_tail = &q->next; + *signals->tail = q; + signals->tail = &q->next; switch ((unsigned long) info) { case 0: q->info.si_signo = sig; @@ -433,38 +444,107 @@ * Queue overflow, abort. We may abort if the signal was rt * and sent by user using something other than kill(). */ - ret = -EAGAIN; - goto out; + return -EAGAIN; + } + + sigaddset(&signals->signal, sig); + return 0; +} + +/* + * Tell a process that it has a new active signal.. + * + * NOTE! we rely on the previous spin_lock to + * lock interrupts for us! We can only be called with + * "sigmask_lock" held, and the local interrupt must + * have been disabled when that got aquired! + * + * No need to set need_resched since signal event passing + * goes through ->blocked + */ +static inline void signal_wake_up(struct task_struct *t) +{ + t->sigpending = 1; + + if (t->state & TASK_INTERRUPTIBLE) { + wake_up_process(t); + return; } - sigaddset(&t->signal, sig); - if (!sigismember(&t->blocked, sig)) { - t->sigpending = 1; #ifdef CONFIG_SMP - /* - * If the task is running on a different CPU - * force a reschedule on the other CPU - note that - * the code below is a tad loose and might occasionally - * kick the wrong CPU if we catch the process in the - * process of changing - but no harm is done by that - * other than doing an extra (lightweight) IPI interrupt. - * - * note that we rely on the previous spin_lock to - * lock interrupts for us! No need to set need_resched - * since signal event passing goes through ->blocked. - */ - spin_lock(&runqueue_lock); - if (t->has_cpu && t->processor != smp_processor_id()) - smp_send_reschedule(t->processor); - spin_unlock(&runqueue_lock); + /* + * If the task is running on a different CPU + * force a reschedule on the other CPU to make + * it notice the new signal quickly. + * + * The code below is a tad loose and might occasionally + * kick the wrong CPU if we catch the process in the + * process of changing - but no harm is done by that + * other than doing an extra (lightweight) IPI interrupt. + */ + spin_lock(&runqueue_lock); + if (t->has_cpu && t->processor != smp_processor_id()) + smp_send_reschedule(t->processor); + spin_unlock(&runqueue_lock); #endif /* CONFIG_SMP */ - } +} + +static int deliver_signal(int sig, struct siginfo *info, struct task_struct *t) +{ + int retval = send_signal(sig, info, &t->pending); + + if (!retval && !sigismember(&t->blocked, sig)) + signal_wake_up(t); + + return retval; +} + +int +send_sig_info(int sig, struct siginfo *info, struct task_struct *t) +{ + unsigned long flags; + int ret; + + +#if DEBUG_SIG +printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); +#endif + + ret = -EINVAL; + if (sig < 0 || sig > _NSIG) + goto out_nolock; + /* The somewhat baroque permissions check... */ + ret = -EPERM; + if (bad_signal(sig, info, t)) + goto out_nolock; + + /* The null signal is a permissions and process existance probe. + No signal is actually delivered. Same goes for zombies. */ + ret = 0; + if (!sig || !t->sig) + goto out_nolock; + spin_lock_irqsave(&t->sigmask_lock, flags); + handle_stop_signal(sig, t); + + /* Optimize away the signal, if it's a signal that can be + handled immediately (ie non-blocked and untraced) and + that is ignored (either explicitly or by default). */ + + if (ignored_signal(sig, t)) + goto out; + + /* Support queueing exactly one non-rt signal, so that we + can get more detailed information about the cause of + the signal. */ + if (sig < SIGRTMIN && sigismember(&t->pending.signal, sig)) + goto out; + + ret = deliver_signal(sig, info, t); out: spin_unlock_irqrestore(&t->sigmask_lock, flags); - if ((t->state & TASK_INTERRUPTIBLE) && signal_pending(t)) - wake_up_process(t); - + if ((t->state & TASK_INTERRUPTIBLE) && signal_pending(t)) + wake_up_process(t); out_nolock: #if DEBUG_SIG printk(" %d -> %d\n", signal_pending(t), ret); @@ -509,22 +589,17 @@ int retval = -EINVAL; if (pgrp > 0) { struct task_struct *p; - int found = 0; retval = -ESRCH; read_lock(&tasklist_lock); for_each_task(p) { if (p->pgrp == pgrp) { int err = send_sig_info(sig, info, p); - if (err != 0) + if (retval) retval = err; - else - found++; } } read_unlock(&tasklist_lock); - if (found) - retval = 0; } return retval; } @@ -541,22 +616,17 @@ int retval = -EINVAL; if (sess > 0) { struct task_struct *p; - int found = 0; retval = -ESRCH; read_lock(&tasklist_lock); for_each_task(p) { if (p->leader && p->session == sess) { int err = send_sig_info(sig, info, p); - if (err) + if (retval) retval = err; - else - found++; } } read_unlock(&tasklist_lock); - if (found) - retval = 0; } return retval; } @@ -576,6 +646,7 @@ return error; } + /* * kill_something_info() interprets pid in interesting ways just like kill(2). * @@ -583,8 +654,7 @@ * is probably wrong. Should make it like BSD or SYSV. */ -int -kill_something_info(int sig, struct siginfo *info, int pid) +static int kill_something_info(int sig, struct siginfo *info, int pid) { if (!pid) { return kill_pg_info(sig, info, current->pgrp); @@ -645,11 +715,24 @@ } /* + * Joy. Or not. Pthread wants us to wake up every thread + * in our parent group. + */ +static void wake_up_parent(struct task_struct *parent) +{ + struct task_struct *tsk = parent; + + do { + wake_up_interruptible(&tsk->wait_chldexit); + tsk = next_thread(tsk); + } while (tsk != parent); +} + +/* * Let a parent know about a status change of a child. */ -void -notify_parent(struct task_struct *tsk, int sig) +void do_notify_parent(struct task_struct *tsk, int sig) { struct siginfo info; int why, status; @@ -693,7 +776,23 @@ info.si_status = status; send_sig_info(sig, &info, tsk->p_pptr); - wake_up_interruptible(&tsk->p_pptr->wait_chldexit); + wake_up_parent(tsk->p_pptr); +} + + +/* + * We need the tasklist lock because it's the only + * thing that protects out "parent" pointer. + * + * exit.c calls "do_notify_parent()" directly, because + * it already has the tasklist lock. + */ +void +notify_parent(struct task_struct *tsk, int sig) +{ + read_lock(&tasklist_lock); + do_notify_parent(tsk, sig); + read_unlock(&tasklist_lock); } EXPORT_SYMBOL(dequeue_signal); @@ -780,25 +879,29 @@ return error; } -asmlinkage long -sys_rt_sigpending(sigset_t *set, size_t sigsetsize) +long do_sigpending(void *set, unsigned long sigsetsize) { - int error = -EINVAL; + long error = -EINVAL; sigset_t pending; - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) + if (sigsetsize > sizeof(sigset_t)) goto out; spin_lock_irq(¤t->sigmask_lock); - sigandsets(&pending, ¤t->blocked, ¤t->signal); + sigandsets(&pending, ¤t->blocked, ¤t->pending.signal); spin_unlock_irq(¤t->sigmask_lock); error = -EFAULT; - if (!copy_to_user(set, &pending, sizeof(*set))) + if (!copy_to_user(set, &pending, sigsetsize)) error = 0; out: return error; +} + +asmlinkage long +sys_rt_sigpending(sigset_t *set, size_t sigsetsize) +{ + return do_sigpending(set, sigsetsize); } asmlinkage long @@ -914,10 +1017,12 @@ (act && (sig == SIGKILL || sig == SIGSTOP))) return -EINVAL; - spin_lock_irq(¤t->sigmask_lock); k = ¤t->sig->action[sig-1]; - if (oact) *oact = *k; + spin_lock(¤t->sig->siglock); + + if (oact) + *oact = *k; if (act) { *k = *act; @@ -945,33 +1050,14 @@ && (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH))) { - /* So dequeue any that might be pending. - XXX: process-wide signals? */ - if (sig >= SIGRTMIN && - sigismember(¤t->signal, sig)) { - struct signal_queue *q, **pp; - pp = ¤t->sigqueue; - q = current->sigqueue; - while (q) { - if (q->info.si_signo != sig) - pp = &q->next; - else { - if ((*pp = q->next) == NULL) - current->sigqueue_tail = pp; - kmem_cache_free(signal_queue_cachep, q); - atomic_dec(&nr_queued_signals); - } - q = *pp; - } - - } - sigdelset(¤t->signal, sig); - recalc_sigpending(current); + spin_lock_irq(¤t->sigmask_lock); + if (rm_sig_from_queue(sig, current)) + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); } } - spin_unlock_irq(¤t->sigmask_lock); - + spin_unlock(¤t->sig->siglock); return 0; } @@ -1039,6 +1125,12 @@ return error; } +asmlinkage long +sys_sigpending(old_sigset_t *set) +{ + return do_sigpending(set, sizeof(*set)); +} + #if !defined(__alpha__) /* Alpha has its own versions with special arguments. */ @@ -1088,22 +1180,6 @@ } error = 0; out: - return error; -} - -asmlinkage long -sys_sigpending(old_sigset_t *set) -{ - int error; - old_sigset_t pending; - - spin_lock_irq(¤t->sigmask_lock); - pending = current->blocked.sig[0] & current->signal.sig[0]; - spin_unlock_irq(¤t->sigmask_lock); - - error = -EFAULT; - if (!copy_to_user(set, &pending, sizeof(*set))) - error = 0; return error; } diff -u --recursive --new-file v2.4.0-test7/linux/kernel/timer.c linux/kernel/timer.c --- v2.4.0-test7/linux/kernel/timer.c Wed Aug 23 18:36:39 2000 +++ linux/kernel/timer.c Mon Aug 28 14:28:27 2000 @@ -724,7 +724,7 @@ asmlinkage long sys_getpid(void) { /* This is SMP safe - current->pid doesn't change */ - return current->pid; + return current->tgid; } /* diff -u --recursive --new-file v2.4.0-test7/linux/mm/bootmem.c linux/mm/bootmem.c --- v2.4.0-test7/linux/mm/bootmem.c Wed Aug 9 19:19:51 2000 +++ linux/mm/bootmem.c Mon Aug 28 13:58:35 2000 @@ -205,7 +205,7 @@ bdata->last_pos = start+areasize-1; bdata->last_offset = remaining_size; } - bdata->last_offset &= ~PAGE_MASK; + bdata->last_offset &= ~PAGE_MASK; } else { bdata->last_pos = start + areasize - 1; bdata->last_offset = size & ~PAGE_MASK; diff -u --recursive --new-file v2.4.0-test7/linux/mm/filemap.c linux/mm/filemap.c --- v2.4.0-test7/linux/mm/filemap.c Wed Aug 23 18:36:39 2000 +++ linux/mm/filemap.c Tue Aug 29 12:41:12 2000 @@ -895,7 +895,7 @@ * page only. */ if (PageLocked(page)) { - if (!filp->f_ralen || index >= raend || index + filp->f_ralen < raend) { + if (!filp->f_ralen || index >= raend || index + filp->f_rawin < raend) { raend = index; if (raend < end_index) max_ahead = filp->f_ramax; @@ -1072,7 +1072,15 @@ if (!Page_Uptodate(page)) goto page_not_up_to_date; + generic_file_readahead(reada_ok, filp, inode, page); page_ok: + /* If users can be writing to this page using arbitrary + * virtual addresses, take care about potential aliasing + * before reading the page on the kernel side. + */ + if (page->mapping->i_mmap_shared != NULL) + flush_dcache_page(page); + /* * Ok, we have the page, and it's up-to-date, so * now we can copy it to user space... diff -u --recursive --new-file v2.4.0-test7/linux/mm/memory.c linux/mm/memory.c --- v2.4.0-test7/linux/mm/memory.c Wed Aug 9 19:19:51 2000 +++ linux/mm/memory.c Fri Sep 1 13:51:10 2000 @@ -924,33 +924,9 @@ memclear_highpage_flush(page, offset, PAGE_SIZE - offset); } -/* - * Handle all mappings that got truncated by a "truncate()" - * system call. - * - * NOTE! We have to be ready to update the memory sharing - * between the file and the memory map for a potential last - * incomplete page. Ugly, but necessary. - */ -void vmtruncate(struct inode * inode, loff_t offset) +static void vmtruncate_list(struct vm_area_struct *mpnt, + unsigned long pgoff, unsigned long partial) { - unsigned long partial, pgoff; - struct vm_area_struct * mpnt; - struct address_space *mapping = inode->i_mapping; - unsigned long limit; - - if (inode->i_size < offset) - goto do_expand; - inode->i_size = offset; - truncate_inode_pages(mapping, offset); - spin_lock(&mapping->i_shared_lock); - if (!mapping->i_mmap) - goto out_unlock; - - pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - partial = (unsigned long)offset & (PAGE_CACHE_SIZE - 1); - - mpnt = mapping->i_mmap; do { struct mm_struct *mm = mpnt->vm_mm; unsigned long start = mpnt->vm_start; @@ -983,6 +959,39 @@ zap_page_range(mm, start, len); flush_tlb_range(mm, start, end); } while ((mpnt = mpnt->vm_next_share) != NULL); +} + + +/* + * Handle all mappings that got truncated by a "truncate()" + * system call. + * + * NOTE! We have to be ready to update the memory sharing + * between the file and the memory map for a potential last + * incomplete page. Ugly, but necessary. + */ +void vmtruncate(struct inode * inode, loff_t offset) +{ + unsigned long partial, pgoff; + struct address_space *mapping = inode->i_mapping; + unsigned long limit; + + if (inode->i_size < offset) + goto do_expand; + inode->i_size = offset; + truncate_inode_pages(mapping, offset); + spin_lock(&mapping->i_shared_lock); + if (!mapping->i_mmap && !mapping->i_mmap_shared) + goto out_unlock; + + pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + partial = (unsigned long)offset & (PAGE_CACHE_SIZE - 1); + + if (mapping->i_mmap != NULL) + vmtruncate_list(mapping->i_mmap, pgoff, partial); + if (mapping->i_mmap_shared != NULL) + vmtruncate_list(mapping->i_mmap_shared, pgoff, partial); + out_unlock: spin_unlock(&mapping->i_shared_lock); /* this should go into ->truncate */ @@ -1095,15 +1104,12 @@ */ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr) { - int high = 0; struct page *page = NULL; pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot)); if (write_access) { page = alloc_page(GFP_HIGHUSER); if (!page) return -1; - if (PageHighMem(page)) - high = 1; clear_user_highpage(page, addr); entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); mm->rss++; diff -u --recursive --new-file v2.4.0-test7/linux/mm/mmap.c linux/mm/mmap.c --- v2.4.0-test7/linux/mm/mmap.c Wed Aug 23 18:36:39 2000 +++ linux/mm/mmap.c Tue Aug 29 12:41:12 2000 @@ -906,15 +906,21 @@ if (file) { struct inode * inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; + struct vm_area_struct **head; + if (vmp->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); + + head = &mapping->i_mmap; + if (vmp->vm_flags & VM_SHARED) + head = &mapping->i_mmap_shared; /* insert vmp into inode's share list */ spin_lock(&mapping->i_shared_lock); - if((vmp->vm_next_share = mapping->i_mmap) != NULL) - mapping->i_mmap->vm_pprev_share = &vmp->vm_next_share; - mapping->i_mmap = vmp; - vmp->vm_pprev_share = &mapping->i_mmap; + if((vmp->vm_next_share = *head) != NULL) + (*head)->vm_pprev_share = &vmp->vm_next_share; + *head = vmp; + vmp->vm_pprev_share = head; spin_unlock(&mapping->i_shared_lock); } } diff -u --recursive --new-file v2.4.0-test7/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.4.0-test7/linux/mm/vmscan.c Wed Aug 9 19:19:51 2000 +++ linux/mm/vmscan.c Fri Sep 1 14:25:26 2000 @@ -646,7 +646,7 @@ { printk("Starting kswapd v1.7\n"); swap_setup(); - kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); return 0; } diff -u --recursive --new-file v2.4.0-test7/linux/net/atm/mpoa_proc.c linux/net/atm/mpoa_proc.c --- v2.4.0-test7/linux/net/atm/mpoa_proc.c Fri Jul 14 12:12:16 2000 +++ linux/net/atm/mpoa_proc.c Fri Sep 1 09:07:01 2000 @@ -155,7 +155,10 @@ if (*pos >= length) length = 0; else { if ((count + *pos) > length) count = length - *pos; - copy_to_user(buff, (char *)page , count); + if (copy_to_user(buff, (char *)page , count)) { + free_page(page); + return -EFAULT; + } *pos += count; } @@ -198,7 +201,7 @@ *ppos += incoming; page[incoming] = '\0'; - retval = parse_qos(buff, incoming); + retval = parse_qos(page, incoming); if (retval == 0) printk("mpoa: proc_mpc_write: could not parse '%s'\n", page); diff -u --recursive --new-file v2.4.0-test7/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.4.0-test7/linux/net/ax25/af_ax25.c Mon Jul 10 16:47:27 2000 +++ linux/net/ax25/af_ax25.c Sun Sep 3 14:54:18 2000 @@ -100,6 +100,7 @@ * with only 6 digipeaters and sockaddr_ax25 in ax25_bind(), * ax25_connect() and ax25_sendmsg() * Joerg(DL1BKE) Added support for SO_BINDTODEVICE + * Arnaldo C. Melo s/suser/capable(CAP_NET_ADMIN)/, some more cleanups */ #include @@ -817,10 +818,7 @@ if (put_user(length, optlen)) return -EFAULT; - if (copy_to_user(optval, valptr, length)) - return -EFAULT; - - return 0; + return copy_to_user(optval, valptr, length) ? -EFAULT : 0; } static int ax25_listen(struct socket *sock, int backlog) @@ -1070,7 +1068,7 @@ return -EINVAL; call = ax25_findbyuid(current->euid); - if (call == NULL && ax25_uid_policy && !suser()) + if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) return -EACCES; if (call == NULL) @@ -1584,9 +1582,7 @@ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; - if (put_user(amount, (int *)arg)) - return -EFAULT; - return 0; + return put_user(amount, (int *)arg); } case TIOCINQ: { @@ -1595,19 +1591,15 @@ /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->receive_queue)) != NULL) amount = skb->len; - if (put_user(amount, (int *)arg)) - return -EFAULT; - return 0; + return put_user(amount, (int *)arg); } case SIOCGSTAMP: if (sk != NULL) { if (sk->stamp.tv_sec == 0) return -ENOENT; - if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) - return -EFAULT; - return 0; - } + return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; + } return -EINVAL; case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ @@ -1621,7 +1613,7 @@ case SIOCAX25NOUID: { /* Set the default policy (default/bar) */ long amount; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (get_user(amount, (long *)arg)) return -EFAULT; @@ -1634,12 +1626,12 @@ case SIOCADDRT: case SIOCDELRT: case SIOCAX25OPTRT: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; return ax25_rt_ioctl(cmd, (void *)arg); case SIOCAX25CTLCON: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; return ax25_ctl_ioctl(cmd, (void *)arg); @@ -1688,7 +1680,7 @@ case SIOCAX25ADDFWD: case SIOCAX25DELFWD: { struct ax25_fwd_struct ax25_fwd; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) return -EFAULT; diff -u --recursive --new-file v2.4.0-test7/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v2.4.0-test7/linux/net/ax25/ax25_route.c Mon Jul 10 16:47:27 2000 +++ linux/net/ax25/ax25_route.c Mon Aug 28 21:16:05 2000 @@ -38,6 +38,7 @@ * Joerg(DL1BKE) Moved BPQ Ethernet driver to separate device. * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating. * Jonathan(G4KLX) Support for packet forwarding. + * Arnaldo C. Melo s/suser/capable/ */ #include @@ -363,7 +364,7 @@ return -EHOSTUNREACH; if ((call = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !suser()) + if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) return -EPERM; call = (ax25_address *)ax25->ax25_dev->dev->dev_addr; } diff -u --recursive --new-file v2.4.0-test7/linux/net/ax25/ax25_uid.c linux/net/ax25/ax25_uid.c --- v2.4.0-test7/linux/net/ax25/ax25_uid.c Tue Nov 23 22:42:21 1999 +++ linux/net/ax25/ax25_uid.c Mon Aug 28 21:16:05 2000 @@ -78,7 +78,7 @@ return -ENOENT; case SIOCAX25ADDUID: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (ax25_findbyuid(sax->sax25_uid)) return -EEXIST; @@ -95,7 +95,7 @@ return 0; case SIOCAX25DELUID: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) diff -u --recursive --new-file v2.4.0-test7/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c --- v2.4.0-test7/linux/net/decnet/af_decnet.c Fri Jun 23 21:55:24 2000 +++ linux/net/decnet/af_decnet.c Mon Aug 28 21:16:05 2000 @@ -32,6 +32,7 @@ * Patrick Caulfield: Fixes to delayed acceptance logic. * David S. Miller: New socket locking * Steve Whitehouse: Socket list hashing/locking + * Arnaldo C. Melo: use capable, not suser */ @@ -688,7 +689,7 @@ if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2)) return -EINVAL; - if (saddr->sdn_objnum && !suser()) + if (saddr->sdn_objnum && !capable(CAP_NET_BIND_SERVICE)) return -EPERM; if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL) @@ -698,7 +699,7 @@ return -EINVAL; if (saddr->sdn_flags & SDF_WILD) { - if (!suser()) + if (!capable(CAP_NET_BIND_SERVICE)) return -EPERM; } else { if (dn_ntohs(saddr->sdn_nodeaddrl)) { @@ -1101,7 +1102,7 @@ #if 0 case SIOCSIFADDR: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((err = copy_from_user(devname, ioarg->devname, 5)) != 0) break; @@ -1143,7 +1144,7 @@ #if 0 case SIOCSNETADDR: - if (!suser()) { + if (!capable(CAP_NET_ADMIN)) { err = -EPERM; break; } @@ -1174,7 +1175,7 @@ break; #endif case OSIOCSNETADDR: - if (!suser()) { + if (!capable(CAP_NET_ADMIN)) { err = -EPERM; break; } @@ -1189,8 +1190,7 @@ break; case OSIOCGNETADDR: - if ((err = put_user(decnet_address, (unsigned short *)arg)) != 0) - break; + err = put_user(decnet_address, (unsigned short *)arg); break; case SIOCGIFCONF: case SIOCGIFFLAGS: diff -u --recursive --new-file v2.4.0-test7/linux/net/econet/af_econet.c linux/net/econet/af_econet.c --- v2.4.0-test7/linux/net/econet/af_econet.c Thu Jul 27 17:38:02 2000 +++ linux/net/econet/af_econet.c Mon Aug 28 21:16:05 2000 @@ -641,17 +641,15 @@ static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - int err; int pid; switch(cmd) { case FIOSETOWN: case SIOCSPGRP: - err = get_user(pid, (int *) arg); - if (err) - return err; - if (current->pid != pid && current->pgrp != -pid && !suser()) + if (get_user(pid, (int *) arg)) + return -EFAULT; + if (current->pid != pid && current->pgrp != -pid && !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); @@ -661,10 +659,7 @@ case SIOCGSTAMP: if(sk->stamp.tv_sec==0) return -ENOENT; - err = -EFAULT; - if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) - err = 0; - return err; + return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; case SIOCGIFFLAGS: case SIOCSIFFLAGS: case SIOCGIFCONF: diff -u --recursive --new-file v2.4.0-test7/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c --- v2.4.0-test7/linux/net/ipv4/ip_gre.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/ip_gre.c Mon Aug 28 12:03:10 2000 @@ -632,6 +632,9 @@ #ifdef CONFIG_NETFILTER nf_conntrack_put(skb->nfct); skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif #endif ipgre_ecn_decapsulate(iph, skb); netif_rx(skb); @@ -858,6 +861,9 @@ #ifdef CONFIG_NETFILTER nf_conntrack_put(skb->nfct); skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif #endif IPTUNNEL_XMIT(); diff -u --recursive --new-file v2.4.0-test7/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.4.0-test7/linux/net/ipv4/ip_output.c Tue Apr 11 15:09:26 2000 +++ linux/net/ipv4/ip_output.c Mon Aug 28 12:03:10 2000 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.83 2000/03/25 01:52:08 davem Exp $ + * Version: $Id: ip_output.c,v 1.84 2000/08/25 02:15:47 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -327,6 +327,7 @@ kfree_skb(skb); return -EHOSTUNREACH; } + rt = (struct rtable *)skb->dst; } #endif diff -u --recursive --new-file v2.4.0-test7/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c --- v2.4.0-test7/linux/net/ipv4/ipip.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/ipip.c Mon Aug 28 12:03:10 2000 @@ -1,7 +1,7 @@ /* * Linux NET3: IP/IP protocol decoder. * - * Version: $Id: ipip.c,v 1.38 2000/08/02 06:03:59 davem Exp $ + * Version: $Id: ipip.c,v 1.39 2000/08/25 02:15:47 davem Exp $ * * Authors: * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 @@ -496,6 +496,9 @@ #ifdef CONFIG_NETFILTER nf_conntrack_put(skb->nfct); skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif #endif ipip_ecn_decapsulate(iph, skb); netif_rx(skb); @@ -639,6 +642,9 @@ #ifdef CONFIG_NETFILTER nf_conntrack_put(skb->nfct); skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif #endif IPTUNNEL_XMIT(); diff -u --recursive --new-file v2.4.0-test7/linux/net/ipv4/tcp_minisocks.c linux/net/ipv4/tcp_minisocks.c --- v2.4.0-test7/linux/net/ipv4/tcp_minisocks.c Wed Aug 23 18:36:39 2000 +++ linux/net/ipv4/tcp_minisocks.c Mon Aug 28 21:16:05 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_minisocks.c,v 1.1 2000/08/09 11:59:04 davem Exp $ + * Version: $Id: tcp_minisocks.c,v 1.2 2000/08/28 04:32:52 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -742,7 +742,7 @@ /* Back to base struct sock members. */ newsk->err = 0; newsk->priority = 0; - atomic_set(&newsk->refcnt, 1); + atomic_set(&newsk->refcnt, 2); #ifdef INET_REFCNT_DEBUG atomic_inc(&inet_sock_nr); #endif @@ -966,5 +966,6 @@ } bh_unlock_sock(child); + sock_put(child); return ret; } diff -u --recursive --new-file v2.4.0-test7/linux/net/ipv6/sit.c linux/net/ipv6/sit.c --- v2.4.0-test7/linux/net/ipv6/sit.c Wed Aug 9 19:19:52 2000 +++ linux/net/ipv6/sit.c Mon Aug 28 12:03:11 2000 @@ -6,7 +6,7 @@ * Pedro Roque * Alexey Kuznetsov * - * $Id: sit.c,v 1.42 2000/08/02 06:03:59 davem Exp $ + * $Id: sit.c,v 1.43 2000/08/25 02:15:47 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -401,6 +401,9 @@ #ifdef CONFIG_NETFILTER nf_conntrack_put(skb->nfct); skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif #endif ipip6_ecn_decapsulate(iph, skb); netif_rx(skb); @@ -567,6 +570,9 @@ #ifdef CONFIG_NETFILTER nf_conntrack_put(skb->nfct); skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif #endif IPTUNNEL_XMIT(); diff -u --recursive --new-file v2.4.0-test7/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.4.0-test7/linux/net/netrom/af_netrom.c Thu May 11 15:30:08 2000 +++ linux/net/netrom/af_netrom.c Mon Aug 28 21:16:05 2000 @@ -30,6 +30,7 @@ * Jonathan(G4KLX) Removed hdrincl. * NET/ROM 007 Jonathan(G4KLX) New timer architecture. * Impmented Idle timer. + * Arnaldo C. Melo s/suser/capable/, micro cleanups */ #include @@ -437,10 +438,7 @@ if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - - return 0; + return copy_to_user(optval, &val, len) ? -EFAULT : 0; } static int nr_listen(struct socket *sock, int backlog) @@ -616,7 +614,7 @@ * Only the super user can set an arbitrary user callsign. */ if (addr->fsa_ax25.sax25_ndigis == 1) { - if (!suser()) + if (!capable(CAP_NET_BIND_SERVICE)) return -EACCES; sk->protinfo.nr->user_addr = addr->fsa_digipeater[0]; sk->protinfo.nr->source_addr = addr->fsa_ax25.sax25_call; @@ -624,7 +622,7 @@ source = &addr->fsa_ax25.sax25_call; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !suser()) + if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) return -EPERM; user = source; } @@ -680,7 +678,7 @@ source = (ax25_address *)dev->dev_addr; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !suser()) + if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) return -EPERM; user = source; } @@ -1111,9 +1109,7 @@ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; - if (put_user(amount, (int *)arg)) - return -EFAULT; - return 0; + return put_user(amount, (int *)arg); } case TIOCINQ: { @@ -1122,18 +1118,14 @@ /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->receive_queue)) != NULL) amount = skb->len; - if (put_user(amount, (int *)arg)) - return -EFAULT; - return 0; + return put_user(amount, (int *)arg); } case SIOCGSTAMP: if (sk != NULL) { if (sk->stamp.tv_sec == 0) return -ENOENT; - if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; } return -EINVAL; @@ -1152,7 +1144,7 @@ case SIOCADDRT: case SIOCDELRT: case SIOCNRDECOBS: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return nr_rt_ioctl(cmd, (void *)arg); default: diff -u --recursive --new-file v2.4.0-test7/linux/net/packet/af_packet.c linux/net/packet/af_packet.c --- v2.4.0-test7/linux/net/packet/af_packet.c Wed Aug 23 18:36:39 2000 +++ linux/net/packet/af_packet.c Mon Aug 28 21:16:05 2000 @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.41 2000/08/10 01:21:14 davem Exp $ + * Version: $Id: af_packet.c,v 1.42 2000/08/29 03:44:56 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1585,7 +1585,7 @@ pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1); for (page = virt_to_page(pg_vec[i]); page <= pend; page++) - clear_bit(PG_reserved, &page->flags); + ClearPageReserved(page); free_pages(pg_vec[i], order); } } @@ -1640,7 +1640,7 @@ pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1); for (page = virt_to_page(pg_vec[i]); page <= pend; page++) - set_bit(PG_reserved, &page->flags); + SetPageReserved(page); } /* Page vector is allocated */ diff -u --recursive --new-file v2.4.0-test7/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.4.0-test7/linux/net/rose/af_rose.c Thu May 11 15:30:08 2000 +++ linux/net/rose/af_rose.c Mon Aug 28 21:16:05 2000 @@ -21,6 +21,7 @@ * Implemented idle timer. * Added use count to neighbour. * Tomi(OH2BNS) Fixed rose_getname(). + * Arnaldo C. Melo s/suser/capable/ + micro cleanups */ #include @@ -510,10 +511,7 @@ if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - - return 0; + return copy_to_user(optval, &val, len) ? -EFAULT : 0; } static int rose_listen(struct socket *sock, int backlog) @@ -695,7 +693,7 @@ source = &addr->srose_call; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !suser()) + if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) return -EACCES; user = source; } @@ -1236,9 +1234,7 @@ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; - if (put_user(amount, (unsigned int *)arg)) - return -EFAULT; - return 0; + return put_user(amount, (unsigned int *)arg); } case TIOCINQ: { @@ -1247,18 +1243,14 @@ /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->receive_queue)) != NULL) amount = skb->len; - if (put_user(amount, (unsigned int *)arg)) - return -EFAULT; - return 0; + return put_user(amount, (unsigned int *)arg); } case SIOCGSTAMP: if (sk != NULL) { if (sk->stamp.tv_sec == 0) return -ENOENT; - if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; } return -EINVAL; @@ -1284,9 +1276,7 @@ struct rose_cause_struct rose_cause; rose_cause.cause = sk->protinfo.rose->cause; rose_cause.diagnostic = sk->protinfo.rose->diagnostic; - if (copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0; } case SIOCRSSCAUSE: { @@ -1299,7 +1289,7 @@ } case SIOCRSSL2CALL: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) ax25_listen_release(&rose_callsign, NULL); if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address))) @@ -1309,9 +1299,7 @@ return 0; case SIOCRSGL2CALL: - if (copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0; case SIOCRSACCEPT: if (sk->protinfo.rose->state == ROSE_STATE_5) { diff -u --recursive --new-file v2.4.0-test7/linux/net/socket.c linux/net/socket.c --- v2.4.0-test7/linux/net/socket.c Wed Aug 23 18:36:39 2000 +++ linux/net/socket.c Mon Aug 28 12:04:42 2000 @@ -855,7 +855,7 @@ net_family_read_lock(); if (net_families[family] == NULL) { - i = -EINVAL; + i = -EAFNOSUPPORT; goto out; } @@ -1710,10 +1710,9 @@ * Initialize the protocols module. */ - proto_init(); - register_filesystem(&sock_fs_type); sock_mnt = kern_mount(&sock_fs_type); + proto_init(); /* * The netlink device handler may be needed early. diff -u --recursive --new-file v2.4.0-test7/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.4.0-test7/linux/net/x25/af_x25.c Wed Apr 26 16:34:10 2000 +++ linux/net/x25/af_x25.c Mon Aug 28 21:16:05 2000 @@ -20,6 +20,7 @@ * 2000-22-03 Daniela Squassoni Allowed disabling/enabling of * facilities negotiation and increased * the throughput upper limit. + * 2000-27-08 Arnaldo C. Melo s/suser/capable/ + micro cleanups */ #include @@ -402,10 +403,7 @@ if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - - return 0; + return copy_to_user(optval, &val, len) ? -EFAULT : 0; } static int x25_listen(struct socket *sock, int backlog) @@ -1067,9 +1065,7 @@ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; - if (put_user(amount, (unsigned int *)arg)) - return -EFAULT; - return 0; + return put_user(amount, (unsigned int *)arg); } case TIOCINQ: { @@ -1078,18 +1074,14 @@ /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->receive_queue)) != NULL) amount = skb->len; - if (put_user(amount, (unsigned int *)arg)) - return -EFAULT; - return 0; + return put_user(amount, (unsigned int *)arg); } case SIOCGSTAMP: if (sk != NULL) { if (sk->stamp.tv_sec == 0) return -ENOENT; - if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; } return -EINVAL; @@ -1114,15 +1106,13 @@ return x25_subscr_ioctl(cmd, (void *)arg); case SIOCX25SSUBSCRIP: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return x25_subscr_ioctl(cmd, (void *)arg); case SIOCX25GFACILITIES: { struct x25_facilities facilities; facilities = sk->protinfo.x25->facilities; - if (copy_to_user((void *)arg, &facilities, sizeof(facilities))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &facilities, sizeof(facilities)) ? -EFAULT : 0; } case SIOCX25SFACILITIES: { @@ -1148,9 +1138,7 @@ case SIOCX25GCALLUSERDATA: { struct x25_calluserdata calluserdata; calluserdata = sk->protinfo.x25->calluserdata; - if (copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata)) ? -EFAULT : 0; } case SIOCX25SCALLUSERDATA: { @@ -1166,9 +1154,7 @@ case SIOCX25GCAUSEDIAG: { struct x25_causediag causediag; causediag = sk->protinfo.x25->causediag; - if (copy_to_user((void *)arg, &causediag, sizeof(causediag))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &causediag, sizeof(causediag)) ? -EFAULT : 0; } default: