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 Fri Aug 25 10:08:16 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 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/MAINTAINERS linux/MAINTAINERS --- v2.4.0-test7/linux/MAINTAINERS Wed Aug 23 18:36:36 2000 +++ linux/MAINTAINERS Sat Sep 2 00:13:49 2000 @@ -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 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/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/i387.c linux/arch/i386/kernel/i387.c --- v2.4.0-test7/linux/arch/i386/kernel/i387.c Fri Jun 23 21:55:07 2000 +++ linux/arch/i386/kernel/i387.c Fri Sep 1 17:16:26 2000 @@ -279,7 +279,6 @@ { struct task_struct *tsk = current; - unlazy_fpu( tsk ); tsk->thread.i387.fsave.status = tsk->thread.i387.fsave.swd; if ( __copy_to_user( buf, &tsk->thread.i387.fsave, sizeof(struct i387_fsave_struct) ) ) @@ -291,8 +290,6 @@ { struct task_struct *tsk = current; int err = 0; - - unlazy_fpu( tsk ); if ( convert_fxsr_to_user( buf, &tsk->thread.i387.fxsave ) ) return -1; 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<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/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/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/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/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 Tue Aug 29 14:09:15 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) @@ -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/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 Aug 29 14:09:15 2000 @@ -292,10 +292,10 @@ /* 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) + copy_from_user(&in, (type *) arg, sizeof in) #define IOCTL_OUT(arg, type, out) \ - copy_to_user_ret((type *) arg, &out, sizeof out, -EFAULT) + copy_to_user((type *) arg, &out, sizeof out) /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in a lot of places. This macro makes the code more clear. */ @@ -1463,7 +1463,8 @@ cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); if (!(cdo->capability & CDC_MULTI_SESSION)) return -ENOSYS; - IOCTL_IN(arg, struct cdrom_multisession, ms_info); + if (IOCTL_IN(arg, struct cdrom_multisession, ms_info)) + return -EFAULT; requested_format = ms_info.addr_format; if (!((requested_format == CDROM_MSF) || (requested_format == CDROM_LBA))) @@ -1473,7 +1474,8 @@ return ret; sanitize_format(&ms_info.addr, &ms_info.addr_format, requested_format); - IOCTL_OUT(arg, struct cdrom_multisession, ms_info); + if (IOCTL_OUT(arg, struct cdrom_multisession, ms_info)) + return -EFAULT; cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); return 0; } @@ -1632,7 +1634,8 @@ return -ENOSYS; if ((ret=cdo->get_mcn(cdi, &mcn))) return ret; - IOCTL_OUT(arg, struct cdrom_mcn, mcn); + if (IOCTL_OUT(arg, struct cdrom_mcn, mcn)) + return -EFAULT; cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); return 0; } @@ -1717,7 +1720,8 @@ if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ - IOCTL_IN(arg, struct cdrom_subchnl, q); + if (IOCTL_IN(arg, struct cdrom_subchnl, q)) + return -EFAULT; requested = q.cdsc_format; if (!((requested == CDROM_MSF) || (requested == CDROM_LBA))) @@ -1728,7 +1732,8 @@ back = q.cdsc_format; /* local copy */ sanitize_format(&q.cdsc_absaddr, &back, requested); sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); - IOCTL_OUT(arg, struct cdrom_subchnl, q); + if (IOCTL_OUT(arg, struct cdrom_subchnl, q)) + return -EFAULT; /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ return 0; } @@ -1737,10 +1742,12 @@ if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ - IOCTL_IN(arg, struct cdrom_tochdr, header); + if (IOCTL_IN(arg, struct cdrom_tochdr, header)) + return -EFAULT; if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) return ret; - IOCTL_OUT(arg, struct cdrom_tochdr, header); + if (IOCTL_OUT(arg, struct cdrom_tochdr, header)) + return -EFAULT; /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ return 0; } @@ -1750,7 +1757,8 @@ if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ - IOCTL_IN(arg, struct cdrom_tocentry, entry); + if (IOCTL_IN(arg, struct cdrom_tocentry, entry)) + return -EFAULT; requested_format = entry.cdte_format; if (!((requested_format == CDROM_MSF) || (requested_format == CDROM_LBA))) @@ -1761,7 +1769,8 @@ return ret; sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format); - IOCTL_OUT(arg, struct cdrom_tocentry, entry); + if (IOCTL_OUT(arg, struct cdrom_tocentry, entry)) + return -EFAULT; /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ return 0; } @@ -1770,7 +1779,8 @@ if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); - IOCTL_IN(arg, struct cdrom_msf, msf); + if (IOCTL_IN(arg, struct cdrom_msf, msf)) + return -EFAULT; return cdo->audio_ioctl(cdi, cmd, &msf); } case CDROMPLAYTRKIND: { @@ -1778,7 +1788,8 @@ if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); - IOCTL_IN(arg, struct cdrom_ti, ti); + if (IOCTL_IN(arg, struct cdrom_ti, ti)) + return -EFAULT; CHECKAUDIO; return cdo->audio_ioctl(cdi, cmd, &ti); } @@ -1787,7 +1798,8 @@ if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); - IOCTL_IN(arg, struct cdrom_volctrl, volume); + if (IOCTL_IN(arg, struct cdrom_volctrl, volume)) + return -EFAULT; return cdo->audio_ioctl(cdi, cmd, &volume); } case CDROMVOLREAD: { @@ -1797,7 +1809,8 @@ cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); if ((ret=cdo->audio_ioctl(cdi, cmd, &volume))) return ret; - IOCTL_OUT(arg, struct cdrom_volctrl, volume); + if (IOCTL_OUT(arg, struct cdrom_volctrl, volume)) + return -EFAULT; return 0; } case CDROMSTART: @@ -1894,7 +1907,8 @@ blocksize = CD_FRAMESIZE_RAW0; break; } - IOCTL_IN(arg, struct cdrom_msf, msf); + if (IOCTL_IN(arg, struct cdrom_msf, msf)) + return -EFAULT; lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0); /* FIXME: we need upper bound checking, too!! */ if (lba < 0) @@ -1933,7 +1947,8 @@ struct cdrom_read_audio ra; int lba, frames; - IOCTL_IN(arg, struct cdrom_read_audio, ra); + if (IOCTL_IN(arg, struct cdrom_read_audio, ra)) + return -EFAULT; if (ra.addr_format == CDROM_MSF) lba = msf_to_lba(ra.addr.msf.minute, @@ -1975,7 +1990,8 @@ case CDROMSUBCHNL: { struct cdrom_subchnl q; u_char requested, back; - IOCTL_IN(arg, struct cdrom_subchnl, q); + if (IOCTL_IN(arg, struct cdrom_subchnl, q)) + return -EFAULT; requested = q.cdsc_format; if (!((requested == CDROM_MSF) || (requested == CDROM_LBA))) @@ -1986,7 +2002,8 @@ back = q.cdsc_format; /* local copy */ sanitize_format(&q.cdsc_absaddr, &back, requested); sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); - IOCTL_OUT(arg, struct cdrom_subchnl, q); + if (IOCTL_OUT(arg, struct cdrom_subchnl, q)) + return -EFAULT; /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ return 0; } @@ -1994,7 +2011,8 @@ struct cdrom_ti ti; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); - IOCTL_IN(arg, struct cdrom_ti, ti); + if (IOCTL_IN(arg, struct cdrom_ti, ti)) + return -EFAULT; cgc.cmd[0] = GPCMD_PLAY_AUDIO_TI; cgc.cmd[4] = ti.cdti_trk0; @@ -2006,7 +2024,8 @@ case CDROMPLAYMSF: { struct cdrom_msf msf; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); - IOCTL_IN(arg, struct cdrom_msf, msf); + if (IOCTL_IN(arg, struct cdrom_msf, msf)) + return -EFAULT; cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; cgc.cmd[3] = msf.cdmsf_min0; cgc.cmd[4] = msf.cdmsf_sec0; @@ -2020,7 +2039,8 @@ case CDROMPLAYBLK: { struct cdrom_blk blk; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); - IOCTL_IN(arg, struct cdrom_blk, blk); + if (IOCTL_IN(arg, struct cdrom_blk, blk)) + return -EFAULT; cgc.cmd[0] = GPCMD_PLAY_AUDIO_10; cgc.cmd[2] = (blk.from >> 24) & 0xff; cgc.cmd[3] = (blk.from >> 16) & 0xff; @@ -2038,7 +2058,8 @@ unsigned short offset; cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); - IOCTL_IN(arg, struct cdrom_volctrl, volctrl); + if (IOCTL_IN(arg, struct cdrom_volctrl, volctrl)) + return -EFAULT; cgc.buffer = buffer; cgc.buflen = 24; @@ -2064,7 +2085,8 @@ volctrl.channel1 = buffer[offset+11]; volctrl.channel2 = buffer[offset+13]; volctrl.channel3 = buffer[offset+15]; - IOCTL_OUT(arg, struct cdrom_volctrl, volctrl); + if (IOCTL_OUT(arg, struct cdrom_volctrl, volctrl)) + return -EFAULT; return 0; } @@ -2130,10 +2152,12 @@ if (!CDROM_CAN(CDC_DVD)) return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); - IOCTL_IN(arg, dvd_authinfo, ai); + if (IOCTL_IN(arg, dvd_authinfo, ai)) + return -EFAULT; if ((ret = dvd_do_auth (cdi, &ai))) return ret; - IOCTL_OUT(arg, dvd_authinfo, ai); + if (IOCTL_OUT(arg, dvd_authinfo, ai)) + return -EFAULT; return 0; } @@ -2143,7 +2167,8 @@ if (!CDROM_CAN(CDC_GENERIC_PACKET)) return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); - IOCTL_IN(arg, struct cdrom_generic_command, cgc); + if (IOCTL_IN(arg, struct cdrom_generic_command, cgc)) + return -EFAULT; copy = !!cgc.buflen; userbuf = cgc.buffer; cgc.buffer = NULL; @@ -2190,7 +2215,8 @@ cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); if ((ret = cdrom_get_next_writable(dev, &next))) return ret; - IOCTL_OUT(arg, long, next); + if (IOCTL_OUT(arg, long, next)) + return -EFAULT; return 0; } case CDROM_LAST_WRITTEN: { @@ -2198,7 +2224,8 @@ cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); if ((ret = cdrom_get_last_written(dev, &last))) return ret; - IOCTL_OUT(arg, long, last); + if (IOCTL_OUT(arg, long, last)) + return -EFAULT; return 0; } } /* switch */ 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 Sat Sep 2 11:49:23 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 Aug 29 21:09:10 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, -EFAULT)) \ + 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/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/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 Jul 18 15:58:54 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/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/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 Sat Sep 2 11:47:51 2000 @@ -232,21 +232,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 +295,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 +352,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 Sat Sep 2 11:46:54 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/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 Sat Sep 2 11:47:33 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/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 Tue Aug 29 14:09:15 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 Aug 29 14:09:15 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) 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/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/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 Mon Aug 28 16:59:14 2000 @@ -0,0 +1,375 @@ +/* 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 +#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 Mon Aug 28 16:59:14 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: @@ -43,7 +43,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include "usb.h" #include "scsiglue.h" #include "transport.h" @@ -58,12 +57,16 @@ #ifdef CONFIG_USB_STORAGE_DPCM #include "dpcm.h" #endif +#ifdef CONFIG_USB_STORAGE_FREECOM +#include "freecom.h" +#endif #include #include #include #include #include +#include /* Some informational data */ MODULE_AUTHOR("Matthew Dharm "); @@ -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 }, + +#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, 0x0100, + { 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/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/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/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/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 Fri Sep 1 14:36:18 2000 @@ -2606,8 +2606,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 +2625,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/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 Fri Sep 1 14:25:26 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/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 Sat Sep 2 11:24:57 2000 @@ -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, 1); } 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 = 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 Sat Sep 2 11:24:57 2000 @@ -704,6 +704,285 @@ 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 1; + return 0; +} + +/** + * 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; + + 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); + + iblock = (inode->i_size + inode->i_sb->s_blocksize-1) + >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); + + 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, 1); + 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, 1); + 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 +1060,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,9 +1211,23 @@ 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)); @@ -966,7 +1251,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 Sat Sep 2 11:24:57 2000 @@ -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; @@ -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; 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/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/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/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/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/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/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/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 Sat Aug 26 10:51:39 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); 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/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/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 Sat Sep 2 11:45:44 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/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 Sat Sep 2 11:45:44 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 */ }; 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 Sat Sep 2 11:45:44 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/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 Mon Aug 28 21:27:39 2000 @@ -0,0 +1,21 @@ +/* + * 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 + +#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 Sat Sep 2 11:46:29 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 Sat Sep 2 11:45:49 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 Sat Sep 2 11:45:44 2000 @@ -33,12 +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_SIGNAL 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_SIGHAND CLONE_SIGNAL /* Old name */ + /* * These are the constant used to fake the fixed-point load-average * counting. Some notes: @@ -232,6 +234,7 @@ struct signal_struct { atomic_t count; struct k_sigaction action[_NSIG]; + struct sigpending pending; spinlock_t siglock; }; @@ -239,6 +242,7 @@ #define INIT_SIGNALS { \ ATOMIC_INIT(1), \ { {{0,}}, }, \ + { NULL, &init_signals.pending.head, }, \ SPIN_LOCK_UNLOCKED } /* @@ -311,6 +315,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 +324,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 +369,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 +443,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 +460,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 +563,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 +578,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 *p1, sigset_t *p2, sigset_t *blocked) { unsigned long ready; long i; @@ -583,23 +590,31 @@ switch (_NSIG_WORDS) { default: for (i = _NSIG_WORDS, ready = 0; --i >= 0 ;) - ready |= t->signal.sig[i] &~ t->blocked.sig[i]; + ready |= (p1->sig[i] | p2->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 = (p1->sig[3] | p2->sig[3]) &~ blocked->sig[3]; + ready |= (p1->sig[2] | p2->sig[2]) &~ blocked->sig[2]; + ready |= (p1->sig[1] | p2->sig[1]) &~ blocked->sig[1]; + ready |= (p1->sig[0] | p2->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 = (p1->sig[1] | p2->sig[1]) &~ blocked->sig[1]; + ready |= (p1->sig[0] | p2->sig[0]) &~ blocked->sig[0]; break; - case 1: ready = t->signal.sig[0] &~ t->blocked.sig[0]; + case 1: ready = (p1->sig[0] | p2->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->sig->pending.signal, &t->blocked); } /* True if we are on the alternate signal stack. */ @@ -798,6 +813,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 +835,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 Sat Sep 2 11:45:44 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,13 @@ } #endif /* __HAVE_ARCH_SIG_SETOPS */ + +static inline void init_sigpending(struct sigpending *sig) +{ + sigemptyset(&sig->signal); + sig->head = NULL; + sig->tail = &sig->head; +} #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 Sat Sep 2 11:45:44 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/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 Sat Sep 2 11:33:30 2000 @@ -500,15 +500,21 @@ static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk) { - if (clone_flags & CLONE_SIGHAND) { + struct signal_struct *sig; + + if (clone_flags & CLONE_SIGNAL) { 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); + + init_sigpending(&sig->pending); + memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action)); return 0; } @@ -591,9 +597,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; @@ -661,7 +665,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_SIGNAL) { + 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/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 Mon Aug 28 21:27:39 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; @@ -264,10 +261,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 Sat Sep 2 11:40:34 2000 @@ -28,52 +28,53 @@ #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; + unsigned long i, *s1, *s2, *m, x; int sig = 0; - s = signal->sig; + s1 = tsk->pending.signal.sig; + s2 = tsk->sig->pending.signal.sig; m = mask->sig; switch (_NSIG_WORDS) { default: - for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m) - if ((x = *s &~ *m) != 0) { + for (i = 0; i < _NSIG_WORDS; ++i, ++s1, ++s2, ++m) + if ((x = (*s1 | *s2) &~ *m) != 0) { sig = ffz(~x) + i*_NSIG_BPW + 1; break; } break; - case 2: if ((x = s[0] &~ m[0]) != 0) + case 2: if ((x = (s1[0] | s2[0]) &~ m[0]) != 0) sig = 1; - else if ((x = s[1] &~ m[1]) != 0) + else if ((x = (s1[1] | s2[1]) &~ m[1]) != 0) sig = _NSIG_BPW + 1; else break; sig += ffz(~x); break; - case 1: if ((x = *s &~ *m) != 0) + case 1: if ((x = (*s1 | *s2) &~ *m) != 0) sig = ffz(~x) + 1; break; } @@ -81,6 +82,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 +106,26 @@ 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); + 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)) { + flush_sigqueue(&sig->pending); + kmem_cache_free(sigact_cachep, sig); + } } + tsk->sigpending = 0; + flush_sigqueue(&tsk->pending); + spin_unlock_irq(&tsk->sigmask_lock); } /* @@ -148,6 +172,53 @@ recalc_sigpending(current); } +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; +} + /* * Dequeue a signal and return the element to the caller, which is * expected to free it. @@ -165,7 +236,7 @@ signal_pending(current)); #endif - sig = next_signal(¤t->signal, mask); + sig = next_signal(current, mask); if (current->notifier) { sigset_t merged; int i; @@ -174,73 +245,24 @@ for (i = 0; i < _NSIG_WORDS; i++) merged.sig[i] = mask->sig[i] | current->notifier_mask->sig[i]; - altsig = next_signal(¤t->signal, &merged); + altsig = next_signal(current, &merged); if (sig != altsig) { 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)) + if (!collect_signal(sig, ¤t->sig->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 +271,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) | rm_from_queue(sig, &t->sig->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 +368,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 +416,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 +449,170 @@ * 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 */ - } +} + +/* + * Send a thread-group-wide signal. + * + * Just add it to the shared signal queue. And + * make sure to inform everybody. + */ +static int send_tg_sig_info(int sig, struct siginfo *info, struct task_struct *p) +{ + int retval, type; + struct task_struct *tsk; + + if (sig < 0 || sig > _NSIG) + return -EINVAL; + + if (bad_signal(sig, info, p)) + return -EPERM; + + if (!sig || !p->sig) + return 0; + + /* Have we already delivered this non-queued signal? */ + if (sig < SIGRTMIN && sigismember(&p->sig->pending.signal, sig)) + return 0; + + /* Add the signal to the global queue */ + retval = send_signal(sig, info, &p->sig->pending); + if (retval < 0) + return retval; + + type = signal_type(sig, p->sig); + + /* Inform all threads about it.. */ + tsk = p; + do { + unsigned long flags; + + /* Zombie? Ignore */ + if (!tsk->sig) + continue; + + spin_lock_irqsave(&tsk->sigmask_lock, flags); + handle_stop_signal(sig, tsk); + + /* Blocked? */ + if (sigismember(&tsk->blocked, sig)) + goto next; + + /* Is the signal ignored by this thread? */ + switch (type) { + case 0: + goto next; + case -1: /* affects all threads? */ + sigaddset(&tsk->pending.signal, sig); + } + + /* Go, girl, go! */ + signal_wake_up(tsk); +next: + spin_unlock_irqrestore(&tsk->sigmask_lock, flags); + } while ((tsk = next_thread(tsk)) != p); + return 0; +} + +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 +657,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 +684,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 +714,35 @@ return error; } + +/* + * Send a signal to a thread group.. + * + * If the pid is the thread group ID, we consider this + * a "thread group" signal. Otherwise it degenerates into + * a thread-specific signal. + */ +static int kill_tg_info(int sig, struct siginfo *info, pid_t pid) +{ + int error; + struct task_struct *p; + + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + error = -ESRCH; + if (p) { + /* Is it the leader? Otherwise it degenerates into a per-thread thing */ + if (p->tgid == pid) { + spin_lock(&p->sig->siglock); + error = send_tg_sig_info(sig, info, p); + spin_unlock(&p->sig->siglock); + } else + error = send_sig_info(sig, info, p); + } + read_unlock(&tasklist_lock); + return error; +} + /* * kill_something_info() interprets pid in interesting ways just like kill(2). * @@ -583,8 +750,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); @@ -606,7 +772,7 @@ } else if (pid < 0) { return kill_pg_info(sig, info, -pid); } else { - return kill_proc_info(sig, info, pid); + return kill_tg_info(sig, info, pid); } } @@ -645,11 +811,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 +872,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); @@ -791,7 +986,8 @@ goto out; spin_lock_irq(¤t->sigmask_lock); - sigandsets(&pending, ¤t->blocked, ¤t->signal); + sigorsets(&pending, ¤t->pending.signal, ¤t->sig->pending.signal); + sigandsets(&pending, ¤t->blocked, &pending); spin_unlock_irq(¤t->sigmask_lock); error = -EFAULT; @@ -902,7 +1098,7 @@ info.si_signo = sig; /* POSIX.1b doesn't mention process groups. */ - return kill_proc_info(sig, &info, pid); + return kill_tg_info(sig, &info, pid); } int @@ -914,10 +1110,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 +1143,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; } @@ -1098,7 +1277,7 @@ old_sigset_t pending; spin_lock_irq(¤t->sigmask_lock); - pending = current->blocked.sig[0] & current->signal.sig[0]; + pending = current->blocked.sig[0] & (current->pending.signal.sig[0] | current->sig->pending.signal.sig[0]); spin_unlock_irq(¤t->sigmask_lock); error = -EFAULT; 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 Mon Aug 28 21:16:05 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,18 +1591,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; @@ -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: