From 1a92894a2b89e2f11f2a2f53ee346a19df8ba49e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:14:55 -0500 Subject: [PATCH] - Revert TCP delayed ACK fix, and fix correctly. We should not send an ack if we don't have any pending (in which case the DACK timer will be set) (Dave Miller) --- Documentation/Changes | 2 +- Documentation/Configure.help | 16 +- Documentation/sysctl/vm.txt | 75 +- arch/i386/kernel/head.S | 1 - arch/i386/kernel/io_apic.c | 10 +- arch/i386/kernel/ioport.c | 16 +- arch/i386/kernel/irq.h | 6 +- arch/i386/kernel/process.c | 17 +- arch/i386/kernel/trampoline.S | 1 - arch/sparc/mm/init.c | 14 +- arch/sparc64/kernel/traps.c | 6 +- arch/sparc64/mm/init.c | 15 +- drivers/block/raid5.c | 2 +- drivers/char/Config.in | 5 - drivers/char/ftape/zftape/zftape-read.c | 1 - drivers/char/ftape/zftape/zftape-write.c | 1 - drivers/char/rtc.c | 56 +- drivers/net/ipddp.c | 71 +- drivers/net/ipddp.h | 1 - drivers/net/ppp.c | 2 +- drivers/scsi/scsi_error.c | 1 - drivers/scsi/scsi_obsolete.c | 1 - drivers/scsi/scsi_queue.c | 1 - drivers/sound/Config.in | 2 + drivers/sound/Makefile | 42 +- drivers/sound/ad1848.c | 113 +- drivers/sound/bin2hex.c | 19 +- drivers/sound/cs4232.c | 17 +- drivers/sound/dmabuf.c | 15 +- drivers/sound/dmabuf.c.old | 1599 ------------------- drivers/sound/gus_card.c | 11 +- drivers/sound/hex2hex.c | 17 +- drivers/sound/maui.c | 25 +- drivers/sound/mpu401.c | 1778 ++++++++++------------ drivers/sound/opl3.c | 78 +- drivers/sound/pas2_card.c | 4 +- drivers/sound/pss.c | 797 +++++----- drivers/sound/sb_audio.c | 16 +- drivers/sound/sb_card.c | 22 +- drivers/sound/sb_common.c | 32 +- drivers/sound/sound_calls.h | 5 +- drivers/sound/sound_timer.c | 8 + drivers/sound/soundcard.c | 21 +- drivers/sound/uart401.c | 337 ++-- drivers/sound/uart6850.c | 9 +- drivers/sound/v_midi.c | 11 +- fs/buffer.c | 6 +- fs/exec.c | 1 + fs/hfs/ChangeLog | 53 +- fs/hfs/Makefile | 2 +- fs/hfs/catalog.c | 403 ++--- fs/hfs/dir.c | 19 +- fs/hfs/dir_cap.c | 16 +- fs/hfs/dir_dbl.c | 19 +- fs/hfs/dir_nat.c | 10 +- fs/hfs/file.c | 16 +- fs/hfs/file_cap.c | 5 +- fs/hfs/file_hdr.c | 13 +- fs/hfs/hfs.h | 13 +- fs/hfs/inode.c | 45 +- fs/hfs/string.c | 11 +- fs/hfs/super.c | 15 +- fs/hfs/sysdep.c | 39 +- fs/hfs/version.c | 2 +- include/asm-i386/page.h | 2 + include/linux/hfs_fs.h | 7 +- include/linux/hfs_fs_i.h | 2 +- include/linux/hfs_sysdep.h | 4 + include/linux/swap.h | 6 +- include/linux/swapctl.h | 46 +- include/linux/sysctl.h | 3 +- include/net/sock.h | 15 +- include/net/tcp.h | 146 +- init/main.c | 4 - ipc/msg.c | 1 - kernel/fork.c | 6 +- kernel/sysctl.c | 4 +- mm/swap.c | 71 +- mm/vmscan.c | 24 +- net/802/sysctl_net_802.c | 1 - net/802/tr.c | 4 + net/appletalk/ddp.c | 57 +- net/ax25/af_ax25.c | 2 + net/core/iovec.c | 5 +- net/ipv4/proc.c | 56 +- net/ipv4/sysctl_net_ipv4.c | 10 +- net/ipv4/tcp.c | 38 +- net/ipv4/tcp_input.c | 397 +++-- net/ipv4/tcp_ipv4.c | 90 +- net/ipv4/tcp_output.c | 200 ++- net/ipv4/tcp_timer.c | 22 +- net/ipv4/timer.c | 40 +- net/ipv4/udp.c | 4 +- net/ipv6/proc.c | 59 +- net/ipv6/tcp_ipv6.c | 56 +- net/ipv6/udp.c | 2 +- net/netrom/af_netrom.c | 2 + net/netsyms.c | 7 +- net/packet/af_packet.c | 5 +- net/rose/af_rose.c | 2 + net/unix/af_unix.c | 4 +- 101 files changed, 2831 insertions(+), 4560 deletions(-) delete mode 100644 drivers/sound/dmabuf.c.old diff --git a/Documentation/Changes b/Documentation/Changes index 6f778a20f0e9..29dc474a224c 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -148,7 +148,7 @@ in some standard tools. Check in /proc/net/rt_local to verify their presence. To turn on IP forwarding, issue the following command: echo 1 > -/proc/sys/net/ipv4/ip_forwarding +/proc/sys/net/ipv4/ip_forward To run bootpd, you'll need to issue the following command: echo 1 >/proc/sys/net/ipv4/ip_boot_agent diff --git a/Documentation/Configure.help b/Documentation/Configure.help index efe2dc390bbd..edf25b0390a3 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -6571,12 +6571,6 @@ CONFIG_JOYSTICK be called joystick.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -ARC console time -CONFIG_RTC_ARC - If you boot your Alpha using the ARC firmware, say Y here. This option - adjusts the RTC clock to take into account the different starting epoch - used by ARC. - Sound card support CONFIG_SOUND If you have a Sound Card in your Computer, i.e. if it can say more @@ -6612,6 +6606,16 @@ CONFIG_SB an unknown card you may answer Y if the card claims to be SoundBlaster compatible. +Are you using the IBM Mwave "emulation" of SB ? +CONFIG_SB_MWAVE + The IBM Mwave can do whats loosely describable as emulation of an 8bit + soundblaster if you load the right firmware from DOS warm boot and pray + and your machine happens to like you. Say Y if you are doing this as the + IRQ test normally fails on the mwave emulation. If you'd like real MWAVE + support phone IBM (425-556-8822) and ask them why they still haven't + released any documentation. + [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html] + Generic OPL2/OPL3 FM synthesizer support CONFIG_ADLIB Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index a9f5d9058ffc..818d00f40643 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -16,6 +16,7 @@ usage. Currently, these files are in /proc/sys/vm: - bdflush +- buffermem - freepages - overcommit_memory - swapctl @@ -88,11 +89,27 @@ number of jiffies per second is 100, except on Alpha machines age_super is for filesystem metadata. ============================================================== +buffermem: + +The three values in this file correspond to the values in +the struct buffer_mem. It controls how much memory should +be used for buffer and cache memory. Note that memorymapped +files are also counted as cache memory... + +The values are: +min_percent -- this is the minumum percentage of memory + that should be spent on buffer + page cache +borrow_percent -- when Linux is short on memory, and buffer + and cache use more than this percentage of + memory, free pages are stolen from them +max_percent -- this is the maximum amount of memory that + can be used for buffer and cache memory +============================================================== freepages: -This file contains three values: min_free_pages, free_pages_low -and free_pages_high in order. +This file contains the values in the struct freepages. That +struct contains three members: min, low and high. These numbers are used by the VM subsystem to keep a reasonable number of pages on the free page list, so that programs can @@ -100,25 +117,23 @@ allocate new pages without having to wait for the system to free used pages first. The actual freeing of pages is done by kswapd, a kernel daemon. -min_free_pages -- when the number of free pages reaches this - level, only the kernel can allocate memory - for _critical_ tasks only -free_pages_low -- when the number of free pages drops below - this level, kswapd is woken up immediately -free_pages_high -- this is kswapd's target, when more than - free_pages_high pages are free, kswapd will - stop swapping. +min -- when the number of free pages reaches this + level, only the kernel can allocate memory + for _critical_ tasks only +low -- when the number of free pages drops below + this level, kswapd is woken up immediately +high -- this is kswapd's target, when more than + pages are free, kswapd will stop swapping. -When the number of free pages is between free_pages_low and -free_pages_high, and kswapd hasn't run for swapout_interval -jiffies, then kswapd is woken up too. See swapout_interval -for more info. +When the number of free pages is between low and high, +and kswapd hasn't run for swapout_interval jiffies, then +kswapd is woken up too. See swapout_interval for more info. When free memory is always low on your system, and kswapd has trouble keeping up with allocations, you might want to -increase these values, especially free_pages_high and perhaps -free_pages_low. I've found that a 1:2:4 relation for these -values tend to work rather well in a heavily loaded system. +increase these values, especially high and perhaps low. +I've found that a 1:2:4 relation for these values tend to work +rather well in a heavily loaded system. ============================================================== @@ -163,9 +178,7 @@ static inline int vm_enough_memory(long pages) swapctl: -This file contains no less than 16 variables, of which about -half is actually used :-) In the listing below, the unused -variables are marked as such. +This file contains no less than 8 variables. All of these values are used by kswapd, and the usage can be found in linux/mm/vmscan.c. @@ -177,18 +190,10 @@ typedef struct swap_control_v5 unsigned int sc_page_advance; unsigned int sc_page_decline; unsigned int sc_page_initial_age; - unsigned int sc_max_buff_age; /* unused */ - unsigned int sc_buff_advance; /* unused */ - unsigned int sc_buff_decline; /* unused */ - unsigned int sc_buff_initial_age; /* unused */ unsigned int sc_age_cluster_fract; unsigned int sc_age_cluster_min; unsigned int sc_pageout_weight; unsigned int sc_bufferout_weight; - unsigned int sc_buffer_grace; /* unused */ - unsigned int sc_nr_buffs_to_free; /* unused */ - unsigned int sc_nr_pages_to_free; /* unused */ - enum RCL_POLICY sc_policy; /* RCL_PERSIST hardcoded */ } swap_control_v5; -------------------------------------------------------------- @@ -207,9 +212,8 @@ is adjusted according to the following scheme: (default 1) And when a page reaches age 0, it's ready to be swapped out. -The variables sc_age_cluster_fract till sc_bufferout_weight -have to do with the amount of scanning kswapd is doing on -each call to try_to_swap_out(). +The next four variables can be used to control kswapd's +agressiveness in swapping out pages. sc_age_cluster_fract is used to calculate how many pages from a process are to be scanned by kswapd. The formula used is @@ -221,9 +225,12 @@ also scan small processes. The values of sc_pageout_weight and sc_bufferout_weight are used to control the how many tries kswapd will do in order -to swapout one page / buffer. As with sc_age_cluster_fract, -the actual value is calculated by several more or less complex -formulae and the default value is good for every purpose. +to swapout one page / buffer. These values can be used to +finetune the ratio between user pages and buffer/cache memory. +When you find that your Linux system is swapping out too much +process pages in order to satisfy buffer memory demands, you +might want to either increase sc_bufferout_weight, or decrease +the value of sc_pageout_weight. ============================================================== diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 8e9f4e17d94a..04892183862b 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -8,7 +8,6 @@ */ .text -#include #include #include #include diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 799561bd3ec2..219e7f853e05 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -513,7 +513,7 @@ void print_IO_APIC (void) return; } -void init_sym_mode (void) +static void init_sym_mode (void) { printk("enabling Symmetric IO mode ... "); outb (0x70, 0x22); @@ -521,6 +521,14 @@ void init_sym_mode (void) printk("...done.\n"); } +void init_pic_mode (void) +{ + printk("disabling Symmetric IO mode ... "); + outb (0x70, 0x22); + outb (0x00, 0x23); + printk("...done.\n"); +} + char ioapic_OEM_ID [16]; char ioapic_Product_ID [16]; diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c index 9bb150075c43..44fd26530d67 100644 --- a/arch/i386/kernel/ioport.c +++ b/arch/i386/kernel/ioport.c @@ -13,6 +13,7 @@ #include #include #include +#include /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) @@ -53,12 +54,25 @@ static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_ */ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) { + struct thread_struct * t = ¤t->tss; + if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; if (!suser()) return -EPERM; + /* + * If it's the first ioperm() call in this thread's lifetime, set the + * IO bitmap up. ioperm() is much less timing critical than clone(), + * this is why we delay this operation until now: + */ +#define IO_BITMAP_OFFSET offsetof(struct thread_struct,io_bitmap) + + if (t->bitmap != IO_BITMAP_OFFSET) { + t->bitmap = IO_BITMAP_OFFSET; + memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4); + } - set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on); + set_bitmap((unsigned long *)t->io_bitmap, from, num, !turn_on); return 0; } diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h index d77474e8756f..9824026dc727 100644 --- a/arch/i386/kernel/irq.h +++ b/arch/i386/kernel/irq.h @@ -1,10 +1,9 @@ #ifndef __irq_h #define __irq_h -#include - /* - * Various low-level irq details needed by irq.c and smp.c + * Various low-level irq details needed by irq.c, process.c, + * time.c, io_apic.c and smp.c * * Interrupt entry/exit code at both C and assembly level */ @@ -20,6 +19,7 @@ void init_IO_APIC_traps(void); int IO_APIC_get_PCI_irq_vector (int bus, int slot, int fn); void make_8259A_irq (unsigned int irq); void send_IPI (int dest, int vector); +void init_pic_mode (void); extern unsigned int io_apic_irqs; diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 27702c8190a6..e7aa2f46add8 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -44,6 +44,7 @@ #ifdef CONFIG_MATH_EMULATION #include #endif +#include "irq.h" #ifdef __SMP__ asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork"); @@ -280,6 +281,12 @@ static inline void kb_wait(void) void machine_restart(char * __unused) { +#if __SMP__ + /* + * turn off the IO-APIC, so we can do a clean reboot + */ + init_pic_mode(); +#endif if(!reboot_thru_bios) { /* rebooting needs to touch the page at absolute addr 0 */ @@ -510,9 +517,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512); else set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1); - p->tss.bitmap = offsetof(struct thread_struct,io_bitmap); - for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */ - p->tss.io_bitmap[i] = ~0; + /* + * a bitmap offset pointing outside of the TSS limit causes a nicely + * controllable SIGSEGV. The first sys_ioperm() call sets up the + * bitmap properly. + */ + p->tss.bitmap = sizeof(struct thread_struct); + if (last_task_used_math == current) __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387)); diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S index 9b322029fe6d..1f5303a9edcb 100644 --- a/arch/i386/kernel/trampoline.S +++ b/arch/i386/kernel/trampoline.S @@ -26,7 +26,6 @@ * entries except for the gdt one.. */ -#include #include #include #include diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 868fc2162d99..aa85666c68d6 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include #endif @@ -172,9 +173,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) struct cache_palias *sparc_aliases; -extern int min_free_pages; -extern int free_pages_low; -extern int free_pages_high; extern void srmmu_frob_mem_map(unsigned long); int physmem_mapped_contig = 1; @@ -265,11 +263,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) initpages << (PAGE_SHIFT-10), PAGE_OFFSET, end_mem); - min_free_pages = nr_free_pages >> 7; - if(min_free_pages < 16) - min_free_pages = 16; - free_pages_low = min_free_pages + (min_free_pages >> 1); - free_pages_high = min_free_pages + min_free_pages; + freepages.min = nr_free_pages >> 7; + if(freepages.min < 16) + freepages.min = 16; + freepages.low = freepages.min + (freepages.min >> 1); + freepages.high = freepages.min + freepages.min; } void free_initmem (void) diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index cde799d92cf7..6e1d30990620 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -26,8 +26,8 @@ #include #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif /* #define SYSCALL_TRACING */ @@ -327,7 +327,7 @@ void do_fpother(struct pt_regs *regs) case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ #ifdef CONFIG_MATHEMU_MODULE -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (!handle_mathemu) request_module("math-emu"); #endif diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 54dc8f265fb1..b564dc0dce98 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -864,10 +865,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) return device_scan (PAGE_ALIGN (start_mem)); } -extern int min_free_pages; -extern int free_pages_low; -extern int free_pages_high; - __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem)) { unsigned long addr, tmp2 = 0; @@ -946,11 +943,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) initpages << (PAGE_SHIFT-10), PAGE_OFFSET, end_mem); - min_free_pages = nr_free_pages >> 7; - if(min_free_pages < 16) - min_free_pages = 16; - free_pages_low = min_free_pages + (min_free_pages >> 1); - free_pages_high = min_free_pages + min_free_pages; + freepages.low = nr_free_pages >> 7; + if(freepages.low < 16) + freepages.low = 16; + freepages.low = freepages.low + (freepages.low >> 1); + freepages.high = freepages.low + freepages.low; } void free_initmem (void) diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c index bf0f2de0e231..2b0e97450c18 100644 --- a/drivers/block/raid5.c +++ b/drivers/block/raid5.c @@ -840,7 +840,7 @@ static void add_stripe_bh (struct stripe_head *sh, struct buffer_head *bh, int d if (sh->bh_new[dd_idx]) { printk("raid5: bug: stripe->bh_new[%d], sector %lu exists\n", dd_idx, sh->sector); printk("forcing oops.\n"); - *(int*)=0; + *(int*)0=0; } set_bit(BH_Lock, &bh->b_state); diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 89faab38cdab..de922c74869f 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -106,11 +106,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT fi bool 'Enhanced Real Time Clock Support' CONFIG_RTC -if [ "$CONFIG_RTC" = "y" ]; then - if [ "$ARCH" = "alpha" ]; then - bool ' ARC console time' CONFIG_RTC_ARC y - fi -fi if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi diff --git a/drivers/char/ftape/zftape/zftape-read.c b/drivers/char/ftape/zftape/zftape-read.c index d0e756e54b8a..91ed51423b3a 100644 --- a/drivers/char/ftape/zftape/zftape-read.c +++ b/drivers/char/ftape/zftape/zftape-read.c @@ -24,7 +24,6 @@ * for the QIC-117 floppy-tape driver for Linux. */ -#include #include #include diff --git a/drivers/char/ftape/zftape/zftape-write.c b/drivers/char/ftape/zftape/zftape-write.c index 05e5239ec266..03b126f49b63 100644 --- a/drivers/char/ftape/zftape/zftape-write.c +++ b/drivers/char/ftape/zftape/zftape-write.c @@ -24,7 +24,6 @@ * for the QIC-117 floppy-tape driver for Linux. */ -#include #include #include diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 26d15d18237a..846b858efb3c 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -63,13 +63,6 @@ #include #include -/* Adjust starting epoch if ARC console time is being used */ -#ifdef CONFIG_RTC_ARC -#define ARCFUDGE 20 -#else -#define ARCFUDGE 0 -#endif - /* * We sponge a minor off of the misc major. No need slurping * up another valuable major dev number for this. If you add @@ -126,12 +119,8 @@ unsigned char days_in_mo[] = * so that there is no possibility of conflicting with the * set_rtc_mmss() call that happens during some timer interrupts. * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) - * - * On Alpha we won't get any interrupts anyway, as they all end up - * in the system timer code. */ -#ifndef __alpha__ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* @@ -152,11 +141,9 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) add_timer(&rtc_irq_timer); } } -#endif /* * Now all the various file operations that we export. - * They are all useless on Alpha... *sigh*. */ static long long rtc_llseek(struct file *file, loff_t offset, int origin) @@ -167,9 +154,6 @@ static long long rtc_llseek(struct file *file, loff_t offset, int origin) static ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { -#ifdef __alpha__ - return -EIO; -#else struct wait_queue wait = { current, NULL }; unsigned long data; ssize_t retval; @@ -201,7 +185,6 @@ static ssize_t rtc_read(struct file *file, char *buf, remove_wait_queue(&rtc_wait, &wait); return retval; -#endif } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, @@ -212,7 +195,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, struct rtc_time wtime; switch (cmd) { -#ifndef __alpha__ case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ { mask_rtc_irq_bit(RTC_AIE); @@ -260,7 +242,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, set_rtc_irq_bit(RTC_UIE); return 0; } -#endif case RTC_ALM_READ: /* Read the present alarm time */ { /* @@ -335,7 +316,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, sizeof(struct rtc_time))) return -EFAULT; - yrs = rtc_tm.tm_year + 1900 + ARCFUDGE; + yrs = rtc_tm.tm_year + 1900; mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ day = rtc_tm.tm_mday; hrs = rtc_tm.tm_hour; @@ -400,7 +381,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, { return put_user(rtc_freq, (unsigned long *)arg); } -#ifndef __alpha__ case RTC_IRQP_SET: /* Set periodic IRQ rate. */ { int tmp = 0; @@ -437,7 +417,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, restore_flags(flags); return 0; } -#else /* __alpha__ */ +#ifdef __alpha__ case RTC_EPOCH_READ: /* Read the epoch. */ { return put_user (epoch, (unsigned long *)arg); @@ -467,18 +447,15 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * We enforce only one user at a time here with the open/close. * Also clear the previous interrupt data on an open, and clean * up things on a close. - * On Alpha we just open, for we don't mess with interrups anyway. */ static int rtc_open(struct inode *inode, struct file *file) { -#ifndef __alpha__ if(rtc_status & RTC_IS_OPEN) return -EBUSY; rtc_status |= RTC_IS_OPEN; rtc_irq_data = 0; -#endif return 0; } @@ -489,7 +466,6 @@ static int rtc_release(struct inode *inode, struct file *file) * in use, and clear the data. */ -#ifndef __alpha__ unsigned char tmp; unsigned long flags; @@ -510,11 +486,9 @@ static int rtc_release(struct inode *inode, struct file *file) rtc_irq_data = 0; rtc_status &= ~RTC_IS_OPEN; -#endif return 0; } -#ifndef __alpha__ static unsigned int rtc_poll(struct file *file, poll_table *wait) { poll_wait(file, &rtc_wait, wait); @@ -522,7 +496,6 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait) return POLLIN | POLLRDNORM; return 0; } -#endif /* * The various file operations we support. @@ -533,11 +506,7 @@ static struct file_operations rtc_fops = { rtc_read, NULL, /* No write */ NULL, /* No readdir */ -#ifdef __alpha__ - NULL, /* No select on Alpha */ -#else rtc_poll, -#endif rtc_ioctl, NULL, /* No mmap */ rtc_open, @@ -560,14 +529,12 @@ __initfunc(int rtc_init(void)) char *guess = NULL; #endif printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION); -#ifndef __alpha__ if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL)) { /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); return -EIO; } -#endif misc_register(&rtc_dev); /* Check region? Naaah! Just snarf it up. */ request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); @@ -599,8 +566,8 @@ __initfunc(int rtc_init(void)) guess = "Digital UNIX"; } if (guess) - printk("rtc: %s epoch (%ld) detected\n", guess, epoch); -#else + printk("rtc: %s epoch (%lu) detected\n", guess, epoch); +#endif init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; rtc_wait = NULL; @@ -610,7 +577,6 @@ __initfunc(int rtc_init(void)) CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); restore_flags(flags); rtc_freq = 1024; -#endif return 0; } @@ -626,7 +592,6 @@ __initfunc(int rtc_init(void)) * for something that requires a steady > 1KHz signal anyways.) */ -#ifndef __alpha__ void rtc_dropped_irq(unsigned long data) { unsigned long flags; @@ -643,7 +608,6 @@ void rtc_dropped_irq(unsigned long data) rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ restore_flags(flags); } -#endif /* * Info exported via "/proc/rtc". @@ -672,9 +636,10 @@ int get_rtc_status(char *buf) */ p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n", + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); get_rtc_alm_time(&tm); @@ -788,12 +753,9 @@ void get_rtc_time(struct rtc_time *rtc_tm) * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; */ - if ((rtc_tm->tm_year += epoch - 1900) <= 69) + if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) rtc_tm->tm_year += 100; - /* if ARCFUDGE == 0, the optimizer should do away with this */ - rtc_tm->tm_year -= ARCFUDGE; - rtc_tm->tm_mon--; } @@ -832,7 +794,6 @@ void get_rtc_alm_time(struct rtc_time *alm_tm) * meddles with the interrupt enable/disable bits. */ -#ifndef __alpha__ void mask_rtc_irq_bit(unsigned char bit) { unsigned char val; @@ -862,4 +823,3 @@ void set_rtc_irq_bit(unsigned char bit) rtc_irq_data = 0; restore_flags(flags); } -#endif diff --git a/drivers/net/ipddp.c b/drivers/net/ipddp.c index 1413495765e7..16e52bd98ff5 100644 --- a/drivers/net/ipddp.c +++ b/drivers/net/ipddp.c @@ -83,9 +83,6 @@ static unsigned int ipddp_debug = IPDDP_DEBUG; /* Index to functions, as function prototypes. */ static int ipddp_xmit(struct sk_buff *skb, struct device *dev); static struct net_device_stats *ipddp_get_stats(struct device *dev); -static int ipddp_rebuild_header(struct sk_buff *skb); -static int ipddp_hard_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); static int ipddp_create(struct ipddp_route *new_rt); static int ipddp_delete(struct ipddp_route *rt); static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); @@ -119,10 +116,10 @@ int ipddp_init(struct device *dev) /* Let the user now what mode we are in */ if(ipddp_mode == IPDDP_ENCAP) - printk("%s: Appletalk-IP Encapsulation mode by Bradford W. Johnson \n", + printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", dev->name); if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decapsulation mode by Jay Schulist \n", + printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", dev->name); /* Fill in the device structure with ethernet-generic values. */ @@ -140,8 +137,6 @@ int ipddp_init(struct device *dev) dev->stop = ipddp_close; dev->get_stats = ipddp_get_stats; dev->do_ioctl = ipddp_ioctl; - dev->hard_header = ipddp_hard_header; /* see ip_output.c */ - dev->rebuild_header = ipddp_rebuild_header; dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ dev->mtu = 585; @@ -157,24 +152,6 @@ int ipddp_init(struct device *dev) return 0; } -/* - * Transmit LLAP/ELAP frame using aarp_send_ddp. - */ -static int ipddp_xmit(struct sk_buff *skb, struct device *dev) -{ - /* Retrieve the saved address hint */ - struct at_addr *at = (struct at_addr *)skb->data; - skb_pull(skb,4); - - ((struct net_device_stats *) dev->priv)->tx_packets++; - ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; - - if(aarp_send_ddp(skb->dev, skb, at, NULL) < 0) - dev_kfree_skb(skb); - - return 0; -} - /* * Get the current statistics. This may be called with the card open or closed. */ @@ -184,19 +161,15 @@ static struct net_device_stats *ipddp_get_stats(struct device *dev) } /* - * Now the packet really wants to go out. On entry skb->data points to the - * ddpehdr we reserved earlier. skb->h.raw will be the higher level header. + * Transmit LLAP/ELAP frame using aarp_send_ddp. */ -static int ipddp_rebuild_header(struct sk_buff *skb) +static int ipddp_xmit(struct sk_buff *skb, struct device *dev) { u32 paddr = ((struct rtable*)skb->dst)->rt_gateway; struct ddpehdr *ddp; - struct at_addr at; struct ipddp_route *rt; struct at_addr *our_addr; - /* Wow! I'll eat my hat if this routine is really called. --ANK */ - /* * Find appropriate route to use, based only on IP number. */ @@ -205,25 +178,21 @@ static int ipddp_rebuild_header(struct sk_buff *skb) if(rt->ip == paddr) break; } - if(rt == NULL) - { - printk("%s: unreachable dst %s\n", cardname, in_ntoa(paddr)); - return -ENETUNREACH; - } + return 0; our_addr = atalk_find_dev_addr(rt->dev); if(ipddp_mode == IPDDP_DECAP) /* * Pull off the excess room that should not be there. - * This is the case for Localtalk, this may not hold - * true for Ethertalk, etc. + * This is due to a hard-header problem. This is the + * quick fix for now though, till it breaks. */ - skb_pull(skb, 31-(sizeof(struct ddpehdr)+1)); + skb_pull(skb, 35-(sizeof(struct ddpehdr)+1)); /* Create the Extended DDP header */ - ddp = (struct ddpehdr *) (skb->data+4); + ddp = (struct ddpehdr *)skb->data; ddp->deh_len = skb->len; ddp->deh_hops = 1; ddp->deh_pad = 0; @@ -231,7 +200,7 @@ static int ipddp_rebuild_header(struct sk_buff *skb) /* * For Localtalk we need aarp_send_ddp to strip the - * Ext DDP header and place a Shrt DDP header on it. + * long DDP header and place a shot DDP header on it. */ if(rt->dev->type == ARPHRD_LOCALTLK) { @@ -248,24 +217,16 @@ static int ipddp_rebuild_header(struct sk_buff *skb) ddp->deh_dport = 72; ddp->deh_sport = 72; - *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */ + *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ + *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */ - /* Hide it at the start of the buffer, we pull it out in ipddp_xmit */ - at = rt->at; - memcpy(skb->data,(void *)&at,sizeof(at)); - - skb->dev = rt->dev; /* set skb->dev to appropriate device */ skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ - return 0; -} + ((struct net_device_stats *) dev->priv)->tx_packets++; + ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; -static int ipddp_hard_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - /* Push down the header space and the type byte */ - skb_push(skb, sizeof(struct ddpehdr)+1+4); + if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) + dev_kfree_skb(skb); return 0; } diff --git a/drivers/net/ipddp.h b/drivers/net/ipddp.h index 31178934bfe9..076373b81eda 100644 --- a/drivers/net/ipddp.h +++ b/drivers/net/ipddp.h @@ -10,7 +10,6 @@ #define SIOCADDIPDDPRT (SIOCDEVPRIVATE) #define SIOCDELIPDDPRT (SIOCDEVPRIVATE+1) #define SIOCFINDIPDDPRT (SIOCDEVPRIVATE+2) -#define SIOCPRINTIPDDPRT (SIOCDEVPRIVATE+3) struct ipddp_route { diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 829f79df6855..de70cd00107a 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -51,7 +51,7 @@ /* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */ -#include /* for CONFIG_KERNELD */ +#include /* for CONFIG_KMOD */ #include #include #include diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index cc259fd67c2e..70adb0040708 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -8,7 +8,6 @@ * */ -#include #define __NO_VERSION__ #include diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c index a49bf3816e10..daede4a5682f 100644 --- a/drivers/scsi/scsi_obsolete.c +++ b/drivers/scsi/scsi_obsolete.c @@ -43,7 +43,6 @@ * driver uses the new code this *ENTIRE* file will be nuked. */ -#include /* for CONFIG_KERNELD */ #define __NO_VERSION__ #include diff --git a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c index 46d3ea73abd8..3c29353f9a79 100644 --- a/drivers/scsi/scsi_queue.c +++ b/drivers/scsi/scsi_queue.c @@ -10,7 +10,6 @@ * we attempt to remove commands from the queue and retry them. */ -#include #define __NO_VERSION__ #include diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index 7ef5f8dd4cdf..d4678da82554 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -6,6 +6,8 @@ fi dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND if [ "$CONFIG_SB" = "y" ]; then + bool 'Is the card a Soundman Games ?' CONFIG_SM_GAMES + bool 'Are you using the IBM Mwave "emulation" of SB ?' CONFIG_SB_MWAVE hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220 int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7 int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1 diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index e8ec0b12d229..6b09e336b5e5 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -117,22 +117,6 @@ else endif endif -ifeq ($(CONFIG_MPU401),y) -LX_OBJS += mpu401.o -else - ifeq ($(CONFIG_MPU401),m) - MX_OBJS += mpu401.o - else - ifeq ($(CONFIG_MPU_EMU),y) - LX_OBJS += mpu401.o - else - ifeq ($(CONFIG_MPU_EMU),m) - MX_OBJS += mpu401.o - endif - endif - endif -endif - ifeq ($(CONFIG_UART401),y) LX_OBJS += uart401.o else @@ -159,9 +143,31 @@ endif ifeq ($(CONFIG_SSCAPE),y) L_OBJS += sscape.o +LX_OBJS += ad1848.o +CONFIG_MPU401 = y else ifeq ($(CONFIG_SSCAPE),m) M_OBJS += sscape.o + MX_OBJS += ad1848.o + ifneq ($(CONFIG_MPU401),y) + CONFIG_MPU401 = m + endif + endif +endif + +ifeq ($(CONFIG_MPU401),y) +LX_OBJS += mpu401.o +else + ifeq ($(CONFIG_MPU401),m) + MX_OBJS += mpu401.o + else + ifeq ($(CONFIG_MPU_EMU),y) + LX_OBJS += mpu401.o + else + ifeq ($(CONFIG_MPU_EMU),m) + MX_OBJS += mpu401.o + endif + endif endif endif @@ -265,7 +271,7 @@ CONFIG_MAUI_BOOT_FILE := $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) maui.o: maui_boot.h maui_boot.h: $(CONFIG_MAUI_BOOT_FILE) bin2hex - bin2hex maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@ + bin2hex -i maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@ @ ( \ echo 'ifeq ($(strip $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_BOOT_FILE)))'; \ echo 'FILES_BOOT_UP_TO_DATE += $@'; \ @@ -297,7 +303,7 @@ CONFIG_TRIX_BOOT_FILE := $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE)) trix.o: trix_boot.h trix_boot.h: $(CONFIG_TRIX_BOOT_FILE) hex2hex - hex2hex trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@ + hex2hex -i trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@ @ ( \ echo 'ifeq ($(strip $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_BOOT_FILE)))'; \ echo 'FILES_BOOT_UP_TO_DATE += $@'; \ diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 6fdec35ec84d..d839ed208572 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -23,6 +23,12 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * general sleep/wakeup clean up. + * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free + * of irqs. Use dev_id. + * + * Status: + * Tested. Believed fully functional. */ #include @@ -144,9 +150,9 @@ static void ad1848_tmr_reprogram(int dev); static int ad_read(ad1848_info * devc, int reg) { - unsigned long flags; - int x; - int timeout = 900000; + unsigned long flags; + int x; + int timeout = 900000; while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; @@ -163,11 +169,10 @@ static int ad_read(ad1848_info * devc, int reg) static void ad_write(ad1848_info * devc, int reg, int data) { - unsigned long flags; - int timeout = 900000; + unsigned long flags; + int timeout = 900000; - while (timeout > 0 && - inb(devc->base) == 0x80) /*Are we initializing */ + while (timeout > 0 && inb(devc->base) == 0x80) /* Are we initializing */ timeout--; save_flags(flags); @@ -180,7 +185,7 @@ static void ad_write(ad1848_info * devc, int reg, int data) static void wait_for_calibration(ad1848_info * devc) { - int timeout = 0; + int timeout = 0; /* * Wait until the auto calibration process has finished. @@ -1751,7 +1756,11 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt else devc->audio_flags |= DMA_DUPLEX; } - + + portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL); + if(portc==NULL) + return -1; + if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, &ad1848_audio_driver, @@ -1762,12 +1771,11 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt dma_playback, dma_capture)) < 0) { + kfree(portc); + portc=NULL; return -1; } - portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(ad1848_port_info))); - sound_mem_sizes[sound_nblocks] = sizeof(ad1848_port_info); - if (sound_nblocks < 1024) - sound_nblocks++;; + audio_devs[my_dev]->portc = portc; memset((char *) portc, 0, sizeof(*portc)); @@ -1777,23 +1785,21 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt if (irq > 0) { - irq2dev[irq] = devc->dev_no = my_dev; - if (snd_set_irq_handler(devc->irq, adintr, - devc->name, - NULL) < 0) + devc->dev_no = my_dev; + if (request_irq(devc->irq, adintr, 0, devc->name, (void *)my_dev) < 0) { - printk(KERN_WARNING "ad1848: IRQ in use\n"); + printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n"); } if (devc->model != MD_1848 && devc->model != MD_C930) { - int x; - unsigned char tmp = ad_read(devc, 16); + int x; + unsigned char tmp = ad_read(devc, 16); devc->timer_ticks = 0; ad_write(devc, 21, 0x00); /* Timer MSB */ ad_write(devc, 20, 0x10); /* Timer LSB */ - +#ifndef __SMP__ ad_write(devc, 16, tmp | 0x40); /* Enable timer */ for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ @@ -1805,6 +1811,9 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt DDB(printk("Interrupt test OK\n")); devc->irq_ok = 1; } +#else + devc->irq_ok=1; +#endif } else devc->irq_ok = 1; /* Couldn't test. assume it's OK */ @@ -1840,7 +1849,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt void ad1848_control(int cmd, int arg) { - ad1848_info *devc; + ad1848_info *devc; if (nr_ad1848_devs < 1) return; @@ -1850,7 +1859,7 @@ void ad1848_control(int cmd, int arg) switch (cmd) { case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ - if (devc->model != MD_1845) + if (devc->model != MD_1845) return; ad_enter_MCE(devc); ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); @@ -1859,8 +1868,8 @@ void ad1848_control(int cmd, int arg) case AD1848_MIXER_REROUTE: { - int o = (arg >> 8) & 0xff; - int n = arg & 0xff; + int o = (arg >> 8) & 0xff; + int n = arg & 0xff; if (n == SOUND_MIXER_NONE) { /* Just hide this control */ @@ -1906,12 +1915,14 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int if (devc != NULL) { + if(audio_devs[dev]->portc!=NULL) + kfree(audio_devs[dev]->portc); release_region(devc->base, 4); if (!share_dma) { if (irq > 0) - snd_release_irq(devc->irq); + free_irq(devc->irq, NULL); sound_free_dma(audio_devs[dev]->dmap_out->dma); @@ -1926,35 +1937,15 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int void adintr(int irq, void *dev_id, struct pt_regs *dummy) { - unsigned char status; - ad1848_info *devc; - int dev; - int alt_stat = 0xff; - unsigned char c930_stat = 0; - int cnt = 0; - - if (irq < 0 || irq > 15) - { - dev = -1; - } - else - dev = irq2dev[irq]; - - if (dev < 0 || dev >= num_audiodevs) - { - for (irq = 0; irq < 17; irq++) - if (irq2dev[irq] != -1) - break; - - if (irq > 15) - { - /* printk("ad1848.c: Bogus interrupt %d\n", irq); */ - return; - } - dev = irq2dev[irq]; - devc = (ad1848_info *) audio_devs[dev]->devc; - } else - devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned char status; + ad1848_info *devc; + int dev; + int alt_stat = 0xff; + unsigned char c930_stat = 0; + int cnt = 0; + + dev = (int)dev_id; + devc = (ad1848_info *) audio_devs[dev]->devc; interrupt_again: /* Jump back here if int status doesn't reset */ @@ -2542,12 +2533,12 @@ EXPORT_SYMBOL(unload_ms_sound); #ifdef MODULE -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(dma, "i"); -MODULE_PARM(dma2, "i"); -MODULE_PARM(type, "i"); -MODULE_PARM(deskpro_xl, "i"); +MODULE_PARM(io, "i"); /* I/O for a raw AD1848 card */ +MODULE_PARM(irq, "i"); /* IRQ to use */ +MODULE_PARM(dma, "i"); /* First DMA channel */ +MODULE_PARM(dma2, "i"); /* Second DMA channel */ +MODULE_PARM(type, "i"); /* Card type */ +MODULE_PARM(deskpro_xl, "i"); /* Special magic for Deskpro XL boxen */ int io = -1; int irq = -1; diff --git a/drivers/sound/bin2hex.c b/drivers/sound/bin2hex.c index 351dd24e04dd..fc49c99d9fd1 100644 --- a/drivers/sound/bin2hex.c +++ b/drivers/sound/bin2hex.c @@ -2,12 +2,27 @@ int main( int argc, const char * argv [] ) { - const char * varname = argv[1]; + const char * varname; int i = 0; int c; + int id = 0; + if(argv[1] && strcmp(argv[1],"-i")==0) + { + argv++; + argc--; + id=1; + } + + if(argc==1) + { + fprintf(stderr, "bin2hex: [-i] firmware\n"); + exit(1); + } + + varname = argv[1]; printf( "/* automatically generated by bin2hex */\n" ); - printf( "static unsigned char %s [] =\n{\n", varname ); + printf( "static unsigned char %s [] %s =\n{\n", varname , id?"__initdata":""); while ( ( c = getchar( ) ) != EOF ) { diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index c8732dfe4f13..fdb5b738c30f 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -12,7 +12,14 @@ * CS4232 * CS4236 * CS4236B + * + * Note: You will need a PnP config setup to initialise some CS4232 boards + * anyway. + * + * Changes + * Alan Cox Modularisation, Basic cleanups. */ + /* * Copyright (C) by Hannu Savolainen 1993-1997 * @@ -20,6 +27,7 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ + #include #include @@ -99,6 +107,8 @@ int probe_cs4232(struct address_info *hw_config) * just one CS4232 compatible device can exist on the system. Also this * method conflicts with possible PnP support in the OS. For this reason * driver is just a temporary kludge. + * + * Also the Cirrus/Crystal method doesnt always work. Try ISAPnP first ;) */ /* @@ -106,8 +116,8 @@ int probe_cs4232(struct address_info *hw_config) * first time. */ - for (n = 0; n < 4; n++) { - + for (n = 0; n < 4; n++) + { /* * Wake up the card by sending a 32 byte Crystal key to the key port. */ @@ -298,8 +308,7 @@ struct address_info cfg; * loaded ready. */ -int -init_module(void) +int init_module(void) { if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) { diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index a9d4f4a04ff2..db6a02d05386 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -125,6 +125,7 @@ static void sound_free_dmap(struct dma_buffparms *dmap) free_pages((unsigned long) dmap->raw_buf, sz); dmap->raw_buf = NULL; + /* Remember the buffer is deleted so we dont Oops later */ dmap->fragment_size = 0; } @@ -832,12 +833,12 @@ int DMAbuf_move_wrpointer(int dev, int l) dmap->user_counter += l; dmap->flags |= DMA_DIRTY; - if (dmap->user_counter >= dmap->max_byte_counter) { + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Wrap the byte counters */ - long decr = dmap->user_counter; - dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->user_counter; - dmap->byte_counter -= decr; + long decr = dmap->byte_counter; + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); + decr -= dmap->byte_counter; + dmap->user_counter -= decr; } end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; @@ -928,7 +929,7 @@ static void do_outputintr(int dev, int dummy) dmap->byte_counter += dmap->bytes_in_use; if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); decr -= dmap->byte_counter; dmap->user_counter -= decr; } @@ -952,7 +953,7 @@ static void do_outputintr(int dev, int dummy) dmap->byte_counter += dmap->bytes_in_use; if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); decr -= dmap->byte_counter; dmap->user_counter -= decr; } diff --git a/drivers/sound/dmabuf.c.old b/drivers/sound/dmabuf.c.old deleted file mode 100644 index ebbd0ea84bf3..000000000000 --- a/drivers/sound/dmabuf.c.old +++ /dev/null @@ -1,1599 +0,0 @@ -/* - * sound/dmabuf.c - * - * The DMA buffer manager for digitized voice applications - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -#include - -#define BE_CONSERVATIVE - -#include "sound_config.h" - -#if defined(CONFIG_AUDIO) || defined(CONFIG_GUSHW) - -static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] = -{NULL}; -static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = -{ - {0}}; -static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = -{NULL}; -static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = -{ - {0}}; - -static int ndmaps = 0; - -#define MAX_DMAP (MAX_AUDIO_DEV*2) - -static struct dma_buffparms dmaps[MAX_DMAP] = -{ - {0}}; - -static void dma_reset_output (int dev); -static void dma_reset_input (int dev); -static int local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); - -static void -dma_init_buffers (int dev, struct dma_buffparms *dmap) -{ - - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->bytes_in_use = dmap->buffsize; - - dmap->dma_mode = DMODE_NONE; - dmap->mapping_flags = 0; - dmap->neutral_byte = 0x80; - dmap->data_rate = 8000; - dmap->cfrag = -1; - dmap->closing = 0; - dmap->nbufs = 1; - dmap->flags = DMA_BUSY; /* Other flags off */ -} - -static int -open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan) -{ - if (dmap->flags & DMA_BUSY) - return -EBUSY; - - { - int err; - - if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0) - return err; - } - - if (dmap->raw_buf == NULL) - { - printk ("Sound: DMA buffers not available\n"); - return -ENOSPC; /* Memory allocation failed during boot */ - } - - if (sound_open_dma (chan, audio_devs[dev]->name)) - { - printk ("Unable to grab(2) DMA%d for the audio driver\n", chan); - return -EBUSY; - } - - dma_init_buffers (dev, dmap); - dmap->open_mode = mode; - dmap->subdivision = dmap->underrun_count = 0; - dmap->fragment_size = 0; - dmap->max_fragments = 65536; /* Just a large value */ - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->applic_profile = APF_NORMAL; - dmap->needs_reorg = 1; - dmap->audio_callback = NULL; - dmap->callback_parm = 0; - - - if (dmap->dma_mode & DMODE_OUTPUT) - { - out_sleep_flag[dev].opts = WK_NONE; - } - else - { - in_sleep_flag[dev].opts = WK_NONE; - } - - return 0; -} - -static void -close_dmap (int dev, struct dma_buffparms *dmap, int chan) -{ - sound_close_dma (chan); - - if (dmap->flags & DMA_BUSY) - dmap->dma_mode = DMODE_NONE; - dmap->flags &= ~DMA_BUSY; - - disable_dma (dmap->dma); -} - - -static unsigned int -default_set_bits (int dev, unsigned int bits) -{ - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits); -} - -static int -default_set_speed (int dev, int speed) -{ - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) & speed); -} - -static short -default_set_channels (int dev, short channels) -{ - int c = channels; - - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c); -} - -static void -check_driver (struct audio_driver *d) -{ - if (d->set_speed == NULL) - d->set_speed = default_set_speed; - if (d->set_bits == NULL) - d->set_bits = default_set_bits; - if (d->set_channels == NULL) - d->set_channels = default_set_channels; -} - -int -DMAbuf_open (int dev, int mode) -{ - int retval; - struct dma_buffparms *dmap_in = NULL; - struct dma_buffparms *dmap_out = NULL; - - if (dev >= num_audiodevs) - { - return -ENXIO; - } - - if (!audio_devs[dev]) - { - return -ENXIO; - } - - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma; - } - - check_driver (audio_devs[dev]->d); - - if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0) - return retval; - - dmap_out = audio_devs[dev]->dmap_out; - dmap_in = audio_devs[dev]->dmap_in; - - if (dmap_in == dmap_out) - audio_devs[dev]->flags &= ~DMA_DUPLEX; - - if (mode & OPEN_WRITE) - { - if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0) - { - audio_devs[dev]->d->close (dev); - return retval; - } - } - - audio_devs[dev]->enable_bits = mode; - - if (mode == OPEN_READ || (mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - { - if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0) - { - audio_devs[dev]->d->close (dev); - - if (mode & OPEN_WRITE) - { - close_dmap (dev, dmap_out, audio_devs[dev]->dmap_out->dma); - } - - return retval; - } - } - - audio_devs[dev]->open_mode = mode; - audio_devs[dev]->go = 1; - - if (mode & OPEN_READ) - in_sleep_flag[dev].opts = WK_NONE; - - if (mode & OPEN_WRITE) - out_sleep_flag[dev].opts = WK_NONE; - - audio_devs[dev]->d->set_bits (dev, 8); - audio_devs[dev]->d->set_channels (dev, 1); - audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED); - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } - - return 0; -} - -void -DMAbuf_reset (int dev) -{ - if (audio_devs[dev]->open_mode & OPEN_WRITE) - dma_reset_output (dev); - - if (audio_devs[dev]->open_mode & OPEN_READ) - dma_reset_input (dev); -} - -static void -dma_reset_output (int dev) -{ - unsigned long flags; - int tmout; - - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - - if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ - return; - -/* - * First wait until the current fragment has been played completely - */ - save_flags (flags); - cli (); - - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - if (!signal_pending(current) - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - -/* - * Finally shut the device off - */ - - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_output) - audio_devs[dev]->d->halt_io (dev); - else - audio_devs[dev]->d->halt_output (dev); - audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; - restore_flags (flags); - - clear_dma_ff (dmap->dma); - disable_dma (dmap->dma); - dmap->byte_counter = 0; - reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0); - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; -} - -static void -dma_reset_input (int dev) -{ - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - save_flags (flags); - cli (); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_input) - audio_devs[dev]->d->halt_io (dev); - else - audio_devs[dev]->d->halt_input (dev); - audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; - restore_flags (flags); - - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1); -} - -void -DMAbuf_launch_output (int dev, struct dma_buffparms *dmap) -{ - if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) - return; /* Don't start DMA yet */ - - dmap->dma_mode = DMODE_OUTPUT; - - if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - if (!(dmap->flags & DMA_STARTED)) - { - reorganize_buffers (dev, dmap, 0); - - if (audio_devs[dev]->d->prepare_for_output (dev, - dmap->fragment_size, dmap->nbufs)) - return; - - if (!(dmap->flags & DMA_NODMA)) - { - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_WRITE); - } - dmap->flags |= DMA_STARTED; - } - if (dmap->counts[dmap->qhead] == 0) - dmap->counts[dmap->qhead] = dmap->fragment_size; - - dmap->dma_mode = DMODE_OUTPUT; - audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - dmap->flags |= DMA_ACTIVE; -} - -int -DMAbuf_sync (int dev) -{ - unsigned long flags; - int tmout, n = 0; - - if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - return 0; - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - save_flags (flags); - cli (); - - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - ; - if (dmap->qlen > 0) - if (!(dmap->flags & DMA_ACTIVE)) - DMAbuf_launch_output (dev, dmap); - ; - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - while (!signal_pending(current) - && n++ <= audio_devs[dev]->dmap_out->nbufs - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; - restore_flags (flags); - return audio_devs[dev]->dmap_out->qlen; - } - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - restore_flags (flags); - /* - * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait until the device has finished playing. - */ - - save_flags (flags); - cli (); - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - { - while (!signal_pending(current) - && audio_devs[dev]->d->local_qlen (dev)) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - } - restore_flags (flags); - } - audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; - return audio_devs[dev]->dmap_out->qlen; -} - -int -DMAbuf_release (int dev, int mode) -{ - unsigned long flags; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->closing = 1; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->closing = 1; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) - if (!signal_pending(current) - && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) - { - DMAbuf_sync (dev); - } - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } - - save_flags (flags); - cli (); - - DMAbuf_reset (dev); - audio_devs[dev]->d->close (dev); - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); - - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->open_mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); - audio_devs[dev]->open_mode = 0; - - restore_flags (flags); - - return 0; -} - -int -DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap) -{ - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) - return 0; - - if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ - { - DMAbuf_sync (dev); - DMAbuf_reset (dev); - dmap->dma_mode = DMODE_NONE; - } - - if (!dmap->dma_mode) - { - int err; - - reorganize_buffers (dev, dmap, 1); - if ((err = audio_devs[dev]->d->prepare_for_input (dev, - dmap->fragment_size, dmap->nbufs)) < 0) - { - return err; - } - dmap->dma_mode = DMODE_INPUT; - } - - if (!(dmap->flags & DMA_ACTIVE)) - { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0); - dmap->flags |= DMA_ACTIVE; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - return 0; -} - -int -DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) -{ - unsigned long flags; - int err = 0, n = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EIO; - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - - save_flags (flags); - cli (); - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't read from mmapped device (1)\n"); - restore_flags (flags); - return -EINVAL; - } - else - while (dmap->qlen <= 0 && n++ < 10) - { - int tmout; - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || - !audio_devs[dev]->go) - { - restore_flags (flags); - return -EAGAIN; - } - - if ((err = DMAbuf_activate_recording (dev, dmap)) < 0) - { - restore_flags (flags); - return err; - } - - /* Wait for the next block */ - - if (dontblock) - { - restore_flags (flags); - return -EAGAIN; - } - - if (!audio_devs[dev]->go) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - in_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&in_sleeper[dev]); - if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - in_sleep_flag[dev].opts |= WK_TIMEOUT; - } - in_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) - { - err = -EIO; - printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - dma_reset_input (dev); - ; - } - else - err = -EINTR; - } - restore_flags (flags); - - if (dmap->qlen <= 0) - { - if (err == 0) - err = -EINTR; - return err; - } - - *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; - *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - - return dmap->qhead; -} - -int -DMAbuf_rmchars (int dev, int buff_no, int c) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - int p = dmap->counts[dmap->qhead] + c; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't read from mmapped device (2)\n"); - return -EINVAL; - } - else if (dmap->qlen <= 0) - return -EIO; - else if (p >= dmap->fragment_size) - { /* This buffer is completely empty */ - dmap->counts[dmap->qhead] = 0; - dmap->qlen--; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - } - else - dmap->counts[dmap->qhead] = p; - - return 0; -} - -int -DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction) -{ -/* - * Try to approximate the active byte position of the DMA pointer within the - * buffer area as well as possible. - */ - int pos; - unsigned long flags; - - save_flags (flags); - cli (); - if (!(dmap->flags & DMA_ACTIVE)) - pos = 0; - else - { - int chan = dmap->dma; - - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = get_dma_residue (chan); - pos = dmap->bytes_in_use - pos; - - if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) - if (direction == DMODE_OUTPUT) - { - if (dmap->qhead == 0) - if (pos > dmap->fragment_size) - pos = 0; - } - else - { - if (dmap->qtail == 0) - if (pos > dmap->fragment_size) - pos = 0; - } - - if (pos < 0) - pos = 0; - if (pos >= dmap->bytes_in_use) - pos = 0; - enable_dma (dmap->dma); - } - restore_flags (flags); - /* printk( "%04x ", pos); */ - - return pos; -} - -/* - * DMAbuf_start_devices() is called by the /dev/music driver to start - * one or more audio devices at desired moment. - */ -static void -DMAbuf_start_device (int dev) -{ - if (audio_devs[dev]->open_mode != 0) - if (!audio_devs[dev]->go) - { - /* OK to start the device */ - audio_devs[dev]->go = 1; - - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } -} - -void -DMAbuf_start_devices (unsigned int devmask) -{ - int dev; - - for (dev = 0; dev < num_audiodevs; dev++) - if (devmask & (1 << dev)) - DMAbuf_start_device (dev); -} - -int -DMAbuf_space_in_queue (int dev) -{ - int len, max, tmp; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - int lim = dmap->nbufs; - - - if (lim < 2) - lim = 2; - - if (dmap->qlen >= lim) /* No space at all */ - return 0; - - /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ - - max = dmap->max_fragments; - if (max > lim) - max = lim; - len = dmap->qlen; - - if (audio_devs[dev]->d->local_qlen) - { - tmp = audio_devs[dev]->d->local_qlen (dev); - if (tmp && len) - tmp--; /* - * This buffer has been counted twice - */ - len += tmp; - } - if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ - len = len + 1; - - if (len >= max) - return 0; - return max - len; -} - -static int -output_sleep (int dev, int dontblock) -{ - int tmout; - int err = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dontblock) - { - return -EAGAIN; - } - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - { - return -EAGAIN; - } - - /* - * Wait for free space - */ - if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - - if (signal_pending(current)) - return -EIO; - - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - ; - dma_reset_output (dev); - } - else if (signal_pending(current)) - { - err = -EINTR; - } - - return err; -} - -static int -find_output_space (int dev, char **buf, int *size) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long flags; - unsigned long active_offs; - long len, offs; - int maxfrags; - int occupied_bytes = (dmap->user_counter % dmap->fragment_size); - - *buf = dmap->raw_buf; - - if (!(maxfrags = DMAbuf_space_in_queue (dev)) && !occupied_bytes) - { - return 0; - } - - save_flags (flags); - cli (); - -#ifdef BE_CONSERVATIVE - active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; -#else - active_offs = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); - /* Check for pointer wrapping situation */ - if (active_offs < 0 || active_offs >= dmap->bytes_in_use) - active_offs = 0; - active_offs += dmap->byte_counter; -#endif - - offs = (dmap->user_counter % dmap->bytes_in_use) & ~3; - if (offs < 0 || offs >= dmap->bytes_in_use) - { - printk ("OSS: Got unexpected offs %ld. Giving up.\n", offs); - printk ("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); - return 0; - } - *buf = dmap->raw_buf + offs; - - len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ - - if ((offs + len) > dmap->bytes_in_use) - { - len = dmap->bytes_in_use - offs; - } - - if (len < 0) - { - restore_flags (flags); - return 0; - } - - if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) - { - len = (maxfrags * dmap->fragment_size) - occupied_bytes; - } - - *size = len & ~3; - - restore_flags (flags); - return (len > 0); -} - -int -DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) -{ - unsigned long flags; - int err = -EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't write to mmapped device (3)\n"); - return -EINVAL; - } - - if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ - { - DMAbuf_reset (dev); - dmap->dma_mode = DMODE_NONE; - } - - dmap->dma_mode = DMODE_OUTPUT; - - save_flags (flags); - cli (); - - while (find_output_space (dev, buf, size) <= 0) - { - if ((err = output_sleep (dev, dontblock)) < 0) - { - restore_flags (flags); - return err; - } - } - - restore_flags (flags); - - return 0; -} - -int -DMAbuf_move_wrpointer (int dev, int l) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long ptr = (dmap->user_counter / dmap->fragment_size) - * dmap->fragment_size; - - unsigned long end_ptr, p; - int post = (dmap->flags & DMA_POST); - - ; - - dmap->flags &= ~DMA_POST; - - dmap->cfrag = -1; - - dmap->user_counter += l; - dmap->flags |= DMA_DIRTY; - - if (dmap->user_counter >= dmap->max_byte_counter) - { /* Wrap the byte counters */ - long decr = dmap->user_counter; - - dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->user_counter; - dmap->byte_counter -= decr; - } - - end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; - - p = (dmap->user_counter - 1) % dmap->bytes_in_use; - dmap->neutral_byte = dmap->raw_buf[p]; - - /* Update the fragment based bookkeeping too */ - while (ptr < end_ptr) - { - dmap->counts[dmap->qtail] = dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - ptr += dmap->fragment_size; - } - - dmap->counts[dmap->qtail] = dmap->user_counter - ptr; - -/* - * Let the low level driver to perform some postprocessing to - * the written data. - */ - if (audio_devs[dev]->d->postprocess_write) - audio_devs[dev]->d->postprocess_write (dev); - - if (!(dmap->flags & DMA_ACTIVE)) - if (dmap->qlen > 1 || - (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) - { - DMAbuf_launch_output (dev, dmap); - } - - ; - return 0; -} - -int -DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) -{ - int chan; - struct dma_buffparms *dmap; - - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk ("sound: DMA buffer(1) == NULL\n"); - printk ("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } - - if (chan < 0) - return 0; - - sound_start_dma (dev, dmap, chan, physaddr, count, dma_mode, 0); - - return count; -} - -static int -local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) -{ - int chan; - struct dma_buffparms *dmap; - - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk ("sound: DMA buffer(2) == NULL\n"); - printk ("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } - - if (dmap->flags & DMA_NODMA) - { - return 1; - } - - if (chan < 0) - return 0; - - sound_start_dma (dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); - dmap->flags |= DMA_STARTED; - - return count; -} - -static void -finish_output_interrupt (int dev, struct dma_buffparms *dmap) -{ - unsigned long flags; - - if (dmap->audio_callback != NULL) - dmap->audio_callback (dev, dmap->callback_parm); - - save_flags (flags); - cli (); - if ((out_sleep_flag[dev].opts & WK_SLEEP)) - { - { - out_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&out_sleeper[dev]); - }; - } - restore_flags (flags); -} - -static void -do_outputintr (int dev, int dummy) -{ - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - int this_fragment; - -#ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_out->dma >= 0) - sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); -#endif - - if (dmap->raw_buf == NULL) - { - printk ("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev); - return; - } - - if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ - { - /* mmapped access */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - - dmap->qlen++; /* Yes increment it (don't decrement) */ - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - dmap->counts[dmap->qhead] = dmap->fragment_size; - - DMAbuf_launch_output (dev, dmap); - finish_output_interrupt (dev, dmap); - return; - } - - save_flags (flags); - cli (); - - dmap->qlen--; - this_fragment = dmap->qhead; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - - while (dmap->qlen < 0) - { - dmap->underrun_count++; - - dmap->qlen++; - if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) - { - dmap->flags &= ~DMA_DIRTY; - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->buffsize); - } - dmap->user_counter += dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - - if (dmap->qlen > 0) - DMAbuf_launch_output (dev, dmap); - - restore_flags (flags); - finish_output_interrupt (dev, dmap); -} - -void -DMAbuf_outputintr (int dev, int notify_only) -{ - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - save_flags (flags); - cli (); - - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; - - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue (chan); - enable_dma (dmap->dma); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qhead != pos && n++ < dmap->nbufs) - { - do_outputintr (dev, notify_only); - } - } - else - do_outputintr (dev, notify_only); - restore_flags (flags); -} - -static void -do_inputintr (int dev) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; - -#ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_in->dma >= 0) - sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); -#endif - - if (dmap->raw_buf == NULL) - { - printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); - return; - } - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; - } - else if (dmap->qlen >= (dmap->nbufs - 1)) - { - printk ("Sound: Recording overrun\n"); - dmap->underrun_count++; - - /* Just throw away the oldest fragment but keep the engine running */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) - { - dmap->qlen++; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - } - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; - - save_flags (flags); - cli (); - if (dmap->qlen > 0) - if ((in_sleep_flag[dev].opts & WK_SLEEP)) - { - { - in_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&in_sleeper[dev]); - }; - } - restore_flags (flags); -} - -void -DMAbuf_inputintr (int dev) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; - - save_flags (flags); - cli (); - - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; - - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue (chan); - enable_dma (dmap->dma); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qtail != pos && ++n < dmap->nbufs) - { - do_inputintr (dev); - } - } - else - do_inputintr (dev); - restore_flags (flags); -} - -int -DMAbuf_open_dma (int dev) -{ -/* - * NOTE! This routine opens only the primary DMA channel (output). - */ - - int chan = audio_devs[dev]->dmap_out->dma; - int err; - - if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) - { - return -EBUSY; - } - dma_init_buffers (dev, audio_devs[dev]->dmap_out); - out_sleep_flag[dev].opts = WK_NONE; - audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; - - if (chan >= 0) - { - unsigned long flags; - - save_flags (flags); - cli (); - disable_dma (audio_devs[dev]->dmap_out->dma); - clear_dma_ff (chan); - restore_flags (flags); - } - - return 0; -} - -void -DMAbuf_close_dma (int dev) -{ - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); -} - -void -DMAbuf_init (int dev, int dma1, int dma2) -{ - /* - * NOTE! This routine could be called several times. - */ - - if (audio_devs[dev]->dmap_out == NULL) - { - if (audio_devs[dev]->d == NULL) - panic ("OSS: audio_devs[%d]->d == NULL\n", dev); - - if (audio_devs[dev]->parent_dev) - { /* Use DMA map of the parent dev */ - int parent = audio_devs[dev]->parent_dev - 1; - - audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; - audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; - } - else - { - audio_devs[dev]->dmap_out = - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_out->dma = dma1; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_in->dma = dma2; - } - } - } -} - -int -DMAbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) -{ - struct dma_buffparms *dmap; - unsigned long flags; - - switch (sel_type) - { - case SEL_IN: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - - dmap = audio_devs[dev]->dmap_in; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags (flags); - cli (); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&in_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - - if (dmap->dma_mode != DMODE_INPUT) - { - if (dmap->dma_mode == DMODE_NONE && - audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && - !dmap->qlen && - audio_devs[dev]->go) - { - unsigned long flags; - - save_flags (flags); - cli (); - DMAbuf_activate_recording (dev, dmap); - restore_flags (flags); - } - return 0; - } - - if (!dmap->qlen) - { - save_flags (flags); - cli (); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&in_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - return 1; - break; - - case SEL_OUT: - dmap = audio_devs[dev]->dmap_out; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags (flags); - cli (); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&out_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - - if (dmap->dma_mode == DMODE_INPUT) - { - return 0; - } - - if (dmap->dma_mode == DMODE_NONE) - { - return 1; - } - - if (!DMAbuf_space_in_queue (dev)) - { - save_flags (flags); - cli (); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&out_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - return 1; - break; - - case SEL_EX: - return 0; - } - - return 0; -} - - -#endif diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index 0f4f769ebf21..92e6dbab661b 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -30,7 +30,7 @@ int gus_pnp_flag = 0; void attach_gus_card(struct address_info *hw_config) { - snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp); + snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp, hw_config); gus_wave_init(hw_config); @@ -101,7 +101,7 @@ void unload_gus(struct address_info *hw_config) release_region(hw_config->io_base, 16); release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ - snd_release_irq(hw_config->irq); + snd_release_irq(hw_config->irq, hw_config); sound_free_dma(hw_config->dma); @@ -111,14 +111,15 @@ void unload_gus(struct address_info *hw_config) void gusintr(int irq, void *dev_id, struct pt_regs *dummy) { - unsigned char src; - extern int gus_timer_enabled; + unsigned char src; + extern int gus_timer_enabled; + struct address_info *hw_config=dev_id; sti(); #ifdef CONFIG_GUSMAX if (have_gus_max) - adintr(irq, NULL, NULL); + adintr(irq, (void *)hw_config->slots[3], NULL); #endif while (1) diff --git a/drivers/sound/hex2hex.c b/drivers/sound/hex2hex.c index 19753bfc2be6..4b182625b749 100644 --- a/drivers/sound/hex2hex.c +++ b/drivers/sound/hex2hex.c @@ -66,14 +66,27 @@ int loadhex(FILE *inf, unsigned char *buf) int main( int argc, const char * argv [] ) { - const char * varline = argv[1]; + const char * varline; int i,l; + int id=0; + if(argv[1] && strcmp(argv[1], "-i")==0) + { + argv++; + argc--; + id=1; + } + if(argv[1]==NULL) + { + fprintf(stderr,"hex2hex: [-i] filename\n"); + exit(1); + } + varline = argv[1; l = loadhex(stdin, buf); printf("/*\n *\t Computer generated file. Do not edit.\n */\n"); printf("static int %s_len = %d;\n", varline, l); - printf("static unsigned char %s[] = {\n", varline); + printf("static unsigned char %s[] %s = {\n", varline, id?"__initdata":""); for (i=0;i #include @@ -327,7 +335,7 @@ int probe_maui(struct address_info *hw_config) maui_base = hw_config->io_base; maui_osp = hw_config->osp; - if (snd_set_irq_handler(hw_config->irq, mauiintr, "Maui", maui_osp) < 0) + if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0) return 0; /* @@ -342,26 +350,26 @@ int probe_maui(struct address_info *hw_config) maui_read() == -1 || maui_read() == -1) if (!maui_init(hw_config->irq)) { - snd_release_irq(hw_config->irq); + free_irq(hw_config->irq, NULL); return 0; } } if (!maui_write(0xCF)) /* Report hardware version */ { printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); - snd_release_irq(hw_config->irq); + free_irq(hw_config->irq, NULL); return 0; } if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) { printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); - snd_release_irq(hw_config->irq); + free_irq(hw_config->irq, NULL); return 0; } if (tmp1 == 0xff || tmp2 == 0xff) { - snd_release_irq(hw_config->irq); - return 0; + free_irq(hw_config->irq, NULL); + return 0; } if (trace_init) printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2); @@ -439,7 +447,7 @@ void unload_maui(struct address_info *hw_config) if (irq < 0) irq = -irq; if (irq > 0) - snd_release_irq(irq); + free_irq(irq, NULL); } #ifdef MODULE @@ -452,8 +460,7 @@ static int fw_load = 0; struct address_info cfg; /* - * Install a CS4232 based card. Need to have ad1848 and mpu401 - * loaded ready. + * Install a Maui card. Needs mpu401 loaded already. */ int init_module(void) diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c index 9ae59740470b..ce92010fc70d 100644 --- a/drivers/sound/mpu401.c +++ b/drivers/sound/mpu401.c @@ -9,10 +9,12 @@ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * + * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) + * Alan Cox modularisation, use normal request_irq, use dev_id */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - */ + #include #include @@ -32,30 +34,30 @@ static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; #endif struct mpu_config - { - int base; /* +{ + int base; /* * I/O base */ - int irq; - int opened; /* - * Open mode - */ - int devno; - int synthno; - int uart_mode; - int initialized; - int mode; + int irq; + int opened; /* + * Open mode + */ + int devno; + int synthno; + int uart_mode; + int initialized; + int mode; #define MODE_MIDI 1 #define MODE_SYNTH 2 - unsigned char version, revision; - unsigned int capabilities; + unsigned char version, revision; + unsigned int capabilities; #define MPU_CAP_INTLG 0x10000000 #define MPU_CAP_SYNC 0x00000010 #define MPU_CAP_FSK 0x00000020 #define MPU_CAP_CLS 0x00000040 #define MPU_CAP_SMPTE 0x00000080 #define MPU_CAP_2PORT 0x00000001 - int timer_flag; + int timer_flag; #define MBUF_MAX 10 #define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \ @@ -75,28 +77,27 @@ struct mpu_config #define COMDPORT(base) (base+1) #define STATPORT(base) (base+1) -static int -mpu401_status(struct mpu_config *devc) +static int mpu401_status(struct mpu_config *devc) { return inb(STATPORT(devc->base)); } + #define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL)) #define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY)) -static void -write_command(struct mpu_config *devc, unsigned char cmd) + +static void write_command(struct mpu_config *devc, unsigned char cmd) { - outb((cmd), COMDPORT(devc->base)); + outb(cmd, COMDPORT(devc->base)); } -static int -read_data(struct mpu_config *devc) + +static int read_data(struct mpu_config *devc) { return inb(DATAPORT(devc->base)); } -static void -write_data(struct mpu_config *devc, unsigned char byte) +static void write_data(struct mpu_config *devc, unsigned char byte) { - outb((byte), DATAPORT(devc->base)); + outb(byte, DATAPORT(devc->base)); } #define OUTPUT_READY 0x40 @@ -107,22 +108,27 @@ write_data(struct mpu_config *devc, unsigned char byte) static struct mpu_config dev_conf[MAX_MIDI_DEV] = { - {0}}; + {0} +}; -static int n_mpu_devs = 0; -static volatile int irq2dev[17] = -{-1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static int n_mpu_devs = 0; -static int reset_mpu401(struct mpu_config *devc); -static void set_uart_mode(int dev, struct mpu_config *devc, int arg); +static int reset_mpu401(struct mpu_config *devc); +static void set_uart_mode(int dev, struct mpu_config *devc, int arg); -static int mpu_timer_init(int midi_dev); -static void mpu_timer_interrupt(void); -static void timer_ext_event(struct mpu_config *devc, int event, int parm); +static int mpu_timer_init(int midi_dev); +static void mpu_timer_interrupt(void); +static void timer_ext_event(struct mpu_config *devc, int event, int parm); -static struct synth_info mpu_synth_info_proto = -{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT}; +static struct synth_info mpu_synth_info_proto = { + "MPU-401 MIDI interface", + 0, + SYNTH_TYPE_MIDI, + MIDI_TYPE_MPU401, + 0, 128, + 0, 128, + SYNTH_CAP_INPUT +}; static struct synth_info mpu_synth_info[MAX_MIDI_DEV]; @@ -158,10 +164,10 @@ static unsigned char len_tab[] = /* # of data bytes following a status #else #define STORE(cmd) \ { \ - int len; \ - unsigned char obuf[8]; \ - cmd; \ - seq_input_event(obuf, len); \ + int len; \ + unsigned char obuf[8]; \ + cmd; \ + seq_input_event(obuf, len); \ } #endif @@ -169,242 +175,242 @@ static unsigned char len_tab[] = /* # of data bytes following a status #define _seqbufptr 0 #define _SEQ_ADVBUF(x) len=x -static int -mpu_input_scanner(struct mpu_config *devc, unsigned char midic) +static int mpu_input_scanner(struct mpu_config *devc, unsigned char midic) { switch (devc->m_state) - { - case ST_INIT: - switch (midic) - { - case 0xf8: - /* Timer overflow */ - break; - - case 0xfc: - printk(""); - break; - - case 0xfd: - if (devc->timer_flag) - mpu_timer_interrupt(); - break; - - case 0xfe: - return MPU_ACK; - break; - - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - printk("", midic & 0x0f); - break; - - case 0xf9: - printk(""); - break; - - case 0xff: - devc->m_state = ST_SYSMSG; - break; - - default: - if (midic <= 0xef) - { - /* printk( "mpu time: %d ", midic); */ - devc->m_state = ST_TIMED; - } else - printk(" ", midic); - } - break; - - case ST_TIMED: - { - int msg = ((int) (midic & 0xf0) >> 4); - - devc->m_state = ST_DATABYTE; - - if (msg < 8) /* Data byte */ - { - /* printk( "midi msg (running status) "); */ - msg = ((int) (devc->last_status & 0xf0) >> 4); - msg -= 8; - devc->m_left = len_tab[msg] - 1; - - devc->m_ptr = 2; - devc->m_buf[0] = devc->last_status; - devc->m_buf[1] = midic; - - if (devc->m_left <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - } else if (msg == 0xf) /* MPU MARK */ - { - devc->m_state = ST_INIT; - - switch (midic) - { - case 0xf8: - /* printk( "NOP "); */ - break; - - case 0xf9: - /* printk( "meas end "); */ - break; - - case 0xfc: - /* printk( "data end "); */ - break; - - default: - printk("Unknown MPU mark %02x\n", midic); - } - } else - { - devc->last_status = midic; - /* printk( "midi msg "); */ - msg -= 8; - devc->m_left = len_tab[msg]; - - devc->m_ptr = 1; - devc->m_buf[0] = midic; - - if (devc->m_left <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - } - } - break; - - case ST_SYSMSG: - switch (midic) - { - case 0xf0: - printk(""); - devc->m_state = ST_SYSEX; - break; - - case 0xf1: - devc->m_state = ST_MTC; - break; - - case 0xf2: - devc->m_state = ST_SONGPOS; - devc->m_ptr = 0; - break; - - case 0xf3: - devc->m_state = ST_SONGSEL; - break; - - case 0xf6: - /* printk( "tune_request\n"); */ - devc->m_state = ST_INIT; - - /* - * Real time messages - */ - case 0xf8: - /* midi clock */ - devc->m_state = ST_INIT; - timer_ext_event(devc, TMR_CLOCK, 0); - break; - - case 0xfA: - devc->m_state = ST_INIT; - timer_ext_event(devc, TMR_START, 0); - break; - - case 0xFB: - devc->m_state = ST_INIT; - timer_ext_event(devc, TMR_CONTINUE, 0); - break; - - case 0xFC: - devc->m_state = ST_INIT; - timer_ext_event(devc, TMR_STOP, 0); - break; - - case 0xFE: - /* active sensing */ - devc->m_state = ST_INIT; - break; - - case 0xff: - /* printk( "midi hard reset"); */ - devc->m_state = ST_INIT; - break; - - default: - printk("unknown MIDI sysmsg %0x\n", midic); - devc->m_state = ST_INIT; - } - break; - - case ST_MTC: - devc->m_state = ST_INIT; - printk("MTC frame %x02\n", midic); - break; - - case ST_SYSEX: - if (midic == 0xf7) - { - printk(""); - devc->m_state = ST_INIT; - } else - printk("%02x ", midic); - break; - - case ST_SONGPOS: - BUFTEST(devc); - devc->m_buf[devc->m_ptr++] = midic; - if (devc->m_ptr == 2) - { - devc->m_state = ST_INIT; - devc->m_ptr = 0; - timer_ext_event(devc, TMR_SPP, - ((devc->m_buf[1] & 0x7f) << 7) | - (devc->m_buf[0] & 0x7f)); - } - break; - - case ST_DATABYTE: - BUFTEST(devc); - devc->m_buf[devc->m_ptr++] = midic; - if ((--devc->m_left) <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - break; - - default: - printk("Bad state %d ", devc->m_state); - devc->m_state = ST_INIT; - } + { + case ST_INIT: + switch (midic) + { + case 0xf8: + /* Timer overflow */ + break; + + case 0xfc: + printk(""); + break; + + case 0xfd: + if (devc->timer_flag) + mpu_timer_interrupt(); + break; + + case 0xfe: + return MPU_ACK; + + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf3: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + printk("", midic & 0x0f); + break; + + case 0xf9: + printk(""); + break; + + case 0xff: + devc->m_state = ST_SYSMSG; + break; + + default: + if (midic <= 0xef) + { + /* printk( "mpu time: %d ", midic); */ + devc->m_state = ST_TIMED; + } + else + printk(" ", midic); + } + break; + + case ST_TIMED: + { + int msg = ((int) (midic & 0xf0) >> 4); + + devc->m_state = ST_DATABYTE; + + if (msg < 8) /* Data byte */ + { + /* printk( "midi msg (running status) "); */ + msg = ((int) (devc->last_status & 0xf0) >> 4); + msg -= 8; + devc->m_left = len_tab[msg] - 1; + + devc->m_ptr = 2; + devc->m_buf[0] = devc->last_status; + devc->m_buf[1] = midic; + + if (devc->m_left <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + } + else if (msg == 0xf) /* MPU MARK */ + { + devc->m_state = ST_INIT; + + switch (midic) + { + case 0xf8: + /* printk( "NOP "); */ + break; + + case 0xf9: + /* printk( "meas end "); */ + break; + + case 0xfc: + /* printk( "data end "); */ + break; + + default: + printk("Unknown MPU mark %02x\n", midic); + } + } + else + { + devc->last_status = midic; + /* printk( "midi msg "); */ + msg -= 8; + devc->m_left = len_tab[msg]; + + devc->m_ptr = 1; + devc->m_buf[0] = midic; + + if (devc->m_left <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + } + } + break; + + case ST_SYSMSG: + switch (midic) + { + case 0xf0: + printk(""); + devc->m_state = ST_SYSEX; + break; + + case 0xf1: + devc->m_state = ST_MTC; + break; + + case 0xf2: + devc->m_state = ST_SONGPOS; + devc->m_ptr = 0; + break; + + case 0xf3: + devc->m_state = ST_SONGSEL; + break; + + case 0xf6: + /* printk( "tune_request\n"); */ + devc->m_state = ST_INIT; + + /* + * Real time messages + */ + case 0xf8: + /* midi clock */ + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_CLOCK, 0); + break; + + case 0xfA: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_START, 0); + break; + + case 0xFB: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_CONTINUE, 0); + break; + + case 0xFC: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_STOP, 0); + break; + + case 0xFE: + /* active sensing */ + devc->m_state = ST_INIT; + break; + + case 0xff: + /* printk( "midi hard reset"); */ + devc->m_state = ST_INIT; + break; + + default: + printk("unknown MIDI sysmsg %0x\n", midic); + devc->m_state = ST_INIT; + } + break; + + case ST_MTC: + devc->m_state = ST_INIT; + printk("MTC frame %x02\n", midic); + break; + + case ST_SYSEX: + if (midic == 0xf7) + { + printk(""); + devc->m_state = ST_INIT; + } + else + printk("%02x ", midic); + break; + + case ST_SONGPOS: + BUFTEST(devc); + devc->m_buf[devc->m_ptr++] = midic; + if (devc->m_ptr == 2) + { + devc->m_state = ST_INIT; + devc->m_ptr = 0; + timer_ext_event(devc, TMR_SPP, + ((devc->m_buf[1] & 0x7f) << 7) | + (devc->m_buf[0] & 0x7f)); + } + break; + case ST_DATABYTE: + BUFTEST(devc); + devc->m_buf[devc->m_ptr++] = midic; + if ((--devc->m_left) <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + break; + + default: + printk("Bad state %d ", devc->m_state); + devc->m_state = ST_INIT; + } return 1; } -static void -mpu401_input_loop(struct mpu_config *devc) +static void mpu401_input_loop(struct mpu_config *devc) { - unsigned long flags; - int busy; - int n; + unsigned long flags; + int busy; + int n; save_flags(flags); cli(); @@ -418,72 +424,45 @@ mpu401_input_loop(struct mpu_config *devc) n = 50; while (input_avail(devc) && n-- > 0) - { - unsigned char c = read_data(devc); - - if (devc->mode == MODE_SYNTH) - { - mpu_input_scanner(devc, c); - } else if (devc->opened & OPEN_READ && devc->inputintr != NULL) - devc->inputintr(devc->devno, c); - } + { + unsigned char c = read_data(devc); + if (devc->mode == MODE_SYNTH) + { + mpu_input_scanner(devc, c); + } + else if (devc->opened & OPEN_READ && devc->inputintr != NULL) + devc->inputintr(devc->devno, c); + } devc->m_busy = 0; } -void -mpuintr(int irq, void *dev_id, struct pt_regs *dummy) +void mpuintr(int irq, void *dev_id, struct pt_regs *dummy) { struct mpu_config *devc; - int dev; + int dev = (int) dev_id; sti(); - -/* - * FreeBSD (and some others) pass unit number to the interrupt handler. - * In this case we have to scan the table for first handler. - */ - - if (irq < 1 || irq > 15) - { - dev = -1; - } else - dev = irq2dev[irq]; - - if (dev == -1) - { - int origirq = irq; - - for (irq = 0; irq <= 16; irq++) - if (irq2dev[irq] != -1) - break; - if (irq > 15) - { - printk("MPU-401: Bogus interrupt #%d?\n", origirq); - return; - } - dev = irq2dev[irq]; - devc = &dev_conf[dev]; - } else - devc = &dev_conf[dev]; + devc = &dev_conf[dev]; if (input_avail(devc)) + { if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) mpu401_input_loop(devc); else - { - /* Dummy read (just to acknowledge the interrupt) */ - read_data(devc); - } + { + /* Dummy read (just to acknowledge the interrupt) */ + read_data(devc); + } + } } -static int -mpu401_open(int dev, int mode, +static int mpu401_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev) ) { - int err; + int err; struct mpu_config *devc; if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) @@ -492,36 +471,34 @@ mpu401_open(int dev, int mode, devc = &dev_conf[dev]; if (devc->opened) - { - printk("MPU-401: Midi busy\n"); return -EBUSY; - } /* - * Verify that the device is really running. - * Some devices (such as Ensoniq SoundScape don't - * work before the on board processor (OBP) is initialized - * by downloading its microcode. + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloading its microcode. */ if (!devc->initialized) - { - if (mpu401_status(devc) == 0xff) /* Bus float */ - { - printk("MPU-401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401(devc); - } - irq2dev[devc->irq] = dev; + { + if (mpu401_status(devc) == 0xff) /* Bus float */ + { + printk(KERN_ERR "mpu401: Device not initialized properly\n"); + return -EIO; + } + reset_mpu401(devc); + } if (midi_devs[dev]->coproc) + { if ((err = midi_devs[dev]->coproc-> open(midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) - { - printk("MPU-401: Can't access coprocessor device\n"); - - return err; - } + { + printk("MPU-401: Can't access coprocessor device\n"); + return err; + } + } + set_uart_mode(dev, devc, 1); devc->mode = MODE_MIDI; devc->synthno = 0; @@ -534,19 +511,16 @@ mpu401_open(int dev, int mode, return 0; } -static void -mpu401_close(int dev) +static void mpu401_close(int dev) { struct mpu_config *devc; devc = &dev_conf[dev]; - if (devc->uart_mode) reset_mpu401(devc); /* * This disables the UART mode */ devc->mode = 0; - devc->inputintr = NULL; if (midi_devs[dev]->coproc) @@ -554,11 +528,10 @@ mpu401_close(int dev) devc->opened = 0; } -static int -mpu401_out(int dev, unsigned char midi_byte) +static int mpu401_out(int dev, unsigned char midi_byte) { - int timeout; - unsigned long flags; + int timeout; + unsigned long flags; struct mpu_config *devc; @@ -574,21 +547,20 @@ mpu401_out(int dev, unsigned char midi_byte) save_flags(flags); cli(); if (!output_ready(devc)) - { - printk("MPU-401: Send data timeout\n"); - restore_flags(flags); - return 0; - } + { + printk(KERN_WARNING "mpu401: Send data timeout\n"); + restore_flags(flags); + return 0; + } write_data(devc, midi_byte); restore_flags(flags); return 1; } -static int -mpu401_command(int dev, mpu_command_rec * cmd) +static int mpu401_command(int dev, mpu_command_rec * cmd) { - int i, timeout, ok; - int ret = 0; + int i, timeout, ok; + int ret = 0; unsigned long flags; struct mpu_config *devc; @@ -597,10 +569,10 @@ mpu401_command(int dev, mpu_command_rec * cmd) if (devc->uart_mode) /* * Not possible in UART mode */ - { - printk("MPU-401 commands not possible in the UART mode\n"); - return -EINVAL; - } + { + printk(KERN_WARNING "mpu401: commands not possible in the UART mode\n"); + return -EINVAL; + } /* * Test for input since pending input seems to block the output. */ @@ -613,83 +585,87 @@ mpu401_command(int dev, mpu_command_rec * cmd) */ timeout = 50000; - retry: +retry: if (timeout-- <= 0) - { - printk("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); - return -EIO; - } + { + printk(KERN_WARNING "mpu401: Command (0x%x) timeout\n", (int) cmd->cmd); + return -EIO; + } save_flags(flags); cli(); if (!output_ready(devc)) - { + { restore_flags(flags); goto retry; - } + } write_command(devc, cmd->cmd); ok = 0; for (timeout = 50000; timeout > 0 && !ok; timeout--) + { if (input_avail(devc)) - { - if (devc->opened && devc->mode == MODE_SYNTH) - { - if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK) - ok = 1; - } else - { /* Device is not currently open. Use simpler method */ - if (read_data(devc) == MPU_ACK) - ok = 1; - } - } + { + if (devc->opened && devc->mode == MODE_SYNTH) + { + if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK) + ok = 1; + } + else + { + /* Device is not currently open. Use simpler method */ + if (read_data(devc) == MPU_ACK) + ok = 1; + } + } + } if (!ok) - { - restore_flags(flags); - /* printk( "MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ - return -EIO; - } + { + restore_flags(flags); + return -EIO; + } if (cmd->nr_args) + { for (i = 0; i < cmd->nr_args; i++) - { - for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--); - - if (!mpu401_out(dev, cmd->data[i])) - { - restore_flags(flags); - printk("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); - return -EIO; - } - } + { + for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--); + + if (!mpu401_out(dev, cmd->data[i])) + { + restore_flags(flags); + printk(KERN_WARNING "mpu401: Command (0x%x), parm send failed.\n", (int) cmd->cmd); + return -EIO; + } + } + } ret = 0; cmd->data[0] = 0; if (cmd->nr_returns) + { for (i = 0; i < cmd->nr_returns; i++) - { - ok = 0; - for (timeout = 5000; timeout > 0 && !ok; timeout--) - if (input_avail(devc)) - { - cmd->data[i] = read_data(devc); - ok = 1; - } - if (!ok) - { - restore_flags(flags); - /* printk( "MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ - return -EIO; - } - } + { + ok = 0; + for (timeout = 5000; timeout > 0 && !ok; timeout--) + if (input_avail(devc)) + { + cmd->data[i] = read_data(devc); + ok = 1; + } + if (!ok) + { + restore_flags(flags); + return -EIO; + } + } + } restore_flags(flags); - return ret; } -static int -mpu_cmd(int dev, int cmd, int data) +static int mpu_cmd(int dev, int cmd, int data) { - int ret; + int ret; static mpu_command_rec rec; @@ -699,14 +675,11 @@ mpu_cmd(int dev, int cmd, int data) rec.data[0] = data & 0xff; if ((ret = mpu401_command(dev, &rec)) < 0) - { - return ret; - } + return ret; return (unsigned char) rec.data[0]; } -static int -mpu401_prefix_cmd(int dev, unsigned char status) +static int mpu401_prefix_cmd(int dev, unsigned char status) { struct mpu_config *devc = &dev_conf[dev]; @@ -714,37 +687,29 @@ mpu401_prefix_cmd(int dev, unsigned char status) return 1; if (status < 0xf0) - { - if (mpu_cmd(dev, 0xD0, 0) < 0) - { - return 0; - } - return 1; - } + { + if (mpu_cmd(dev, 0xD0, 0) < 0) + return 0; + return 1; + } switch (status) - { - case 0xF0: - if (mpu_cmd(dev, 0xDF, 0) < 0) - { - return 0; - } - return 1; - break; - - default: - return 0; - } + { + case 0xF0: + if (mpu_cmd(dev, 0xDF, 0) < 0) + return 0; + return 1; + default: + return 0; + } } -static int -mpu401_start_read(int dev) +static int mpu401_start_read(int dev) { return 0; } -static int -mpu401_end_read(int dev) +static int mpu401_end_read(int dev) { return 0; } @@ -756,49 +721,47 @@ static int mpu401_ioctl(int dev, unsigned cmd, caddr_t arg) int val, ret; devc = &dev_conf[dev]; - switch (cmd) { - case SNDCTL_MIDI_MPUMODE: - if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */ - printk("MPU-401: Intelligent mode not supported by the HW\n"); + switch (cmd) + { + case SNDCTL_MIDI_MPUMODE: + if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */ + printk(KERN_WARNING "mpu401: Intelligent mode not supported by the HW\n"); + return -EINVAL; + } + if (get_user(val, (int *)arg)) + return -EFAULT; + set_uart_mode(dev, devc, !val); + return 0; + + case SNDCTL_MIDI_MPUCMD: + if (copy_from_user(&rec, arg, sizeof(rec))) + return -EFAULT; + if ((ret = mpu401_command(dev, &rec)) < 0) + return ret; + if (copy_to_user(arg, &rec, sizeof(rec))) + return -EFAULT; + return 0; + + default: return -EINVAL; - } - if (__get_user(val, (int *)arg)) - return -EFAULT; - set_uart_mode(dev, devc, !val); - return 0; - - case SNDCTL_MIDI_MPUCMD: - if (__copy_from_user(&rec, arg, sizeof(rec))) - return -EFAULT; - if ((ret = mpu401_command(dev, &rec)) < 0) - return ret; - if (__copy_to_user(arg, &rec, sizeof(rec))) - return -EFAULT; - return 0; - - default: - return -EINVAL; } } -static void -mpu401_kick(int dev) +static void mpu401_kick(int dev) { } -static int -mpu401_buffer_status(int dev) +static int mpu401_buffer_status(int dev) { return 0; /* * No data in buffers */ } -static int -mpu_synth_ioctl(int dev, +static int mpu_synth_ioctl(int dev, unsigned int cmd, caddr_t arg) { - int midi_dev; + int midi_dev; struct mpu_config *devc; midi_dev = synth_devs[dev]->midi_dev; @@ -809,88 +772,77 @@ mpu_synth_ioctl(int dev, devc = &dev_conf[midi_dev]; switch (cmd) - { - - case SNDCTL_SYNTH_INFO: - memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info)); + { - return 0; - break; + case SNDCTL_SYNTH_INFO: + memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info)); + return 0; - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - break; + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; - default: - return -EINVAL; - } + default: + return -EINVAL; + } } -static int -mpu_synth_open(int dev, int mode) +static int mpu_synth_open(int dev, int mode) { - int midi_dev, err; + int midi_dev, err; struct mpu_config *devc; midi_dev = synth_devs[dev]->midi_dev; if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) - { - return -ENXIO; - } + return -ENXIO; + devc = &dev_conf[midi_dev]; /* - * Verify that the device is really running. - * Some devices (such as Ensoniq SoundScape don't - * work before the on board processor (OBP) is initialized - * by downloading its microcode. + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloading its microcode. */ if (!devc->initialized) - { - if (mpu401_status(devc) == 0xff) /* Bus float */ - { - printk("MPU-401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401(devc); - } + { + if (mpu401_status(devc) == 0xff) /* Bus float */ + { + printk(KERN_ERR "mpu401: Device not initialized properly\n"); + return -EIO; + } + reset_mpu401(devc); + } if (devc->opened) - { - printk("MPU-401: Midi busy\n"); - return -EBUSY; - } + return -EBUSY; devc->mode = MODE_SYNTH; devc->synthno = dev; devc->inputintr = NULL; - irq2dev[devc->irq] = midi_dev; if (midi_devs[midi_dev]->coproc) if ((err = midi_devs[midi_dev]->coproc-> open(midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) - { - printk("MPU-401: Can't access coprocessor device\n"); - - return err; - } + { + printk(KERN_WARNING "mpu401: Can't access coprocessor device\n"); + return err; + } devc->opened = mode; reset_mpu401(devc); if (mode & OPEN_READ) - { - mpu_cmd(midi_dev, 0x8B, 0); /* Enable data in stop mode */ - mpu_cmd(midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ - mpu_cmd(midi_dev, 0x87, 0); /* Enable pitch & controller */ - } + { + mpu_cmd(midi_dev, 0x8B, 0); /* Enable data in stop mode */ + mpu_cmd(midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ + mpu_cmd(midi_dev, 0x87, 0); /* Enable pitch & controller */ + } return 0; } -static void -mpu_synth_close(int dev) -{ - int midi_dev; +static void mpu_synth_close(int dev) +{ + int midi_dev; struct mpu_config *devc; midi_dev = synth_devs[dev]->midi_dev; @@ -958,55 +910,52 @@ static struct midi_operations mpu401_midi_proto = static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; -static void -mpu401_chk_version(int n, struct mpu_config *devc) +static void mpu401_chk_version(int n, struct mpu_config *devc) { - int tmp; - unsigned long flags; + int tmp; + unsigned long flags; devc->version = devc->revision = 0; save_flags(flags); cli(); if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0) - { - restore_flags(flags); - return; - } + { + restore_flags(flags); + return; + } if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ - { - restore_flags(flags); - return; - } + { + restore_flags(flags); + return; + } devc->version = tmp; if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) - { - devc->version = 0; - restore_flags(flags); - return; - } + { + devc->version = 0; + restore_flags(flags); + return; + } devc->revision = tmp; - restore_flags(flags); } -void -attach_mpu401(struct address_info *hw_config) +void attach_mpu401(struct address_info *hw_config) { - unsigned long flags; - char revision_char; + unsigned long flags; + char revision_char; - int m; + int m; struct mpu_config *devc; hw_config->slots[1] = -1; m = sound_alloc_mididev(); if (m == -1) - { - printk(KERN_WARNING "MPU-401: Too many midi devices detected\n"); - return; - } + { + printk(KERN_WARNING "MPU-401: Too many midi devices detected\n"); + return; + } devc = &dev_conf[m]; devc->base = hw_config->io_base; devc->osp = hw_config->osp; @@ -1024,35 +973,36 @@ attach_mpu401(struct address_info *hw_config) devc->irq = hw_config->irq; if (devc->irq < 0) - { - devc->irq *= -1; - devc->shared_irq = 1; - } - irq2dev[devc->irq] = m; + { + devc->irq *= -1; + devc->shared_irq = 1; + } if (!hw_config->always_detect) - { - /* Verify the hardware again */ - if (!reset_mpu401(devc)) - { - printk(KERN_WARNING "mpu401: Device didn't respond\n"); - sound_unload_mididev(m); - return; - } - if (!devc->shared_irq) - if (snd_set_irq_handler(devc->irq, mpuintr, "mpu401", devc->osp) < 0) - { - printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq); - sound_unload_mididev(m); - return; - } - save_flags(flags); - cli(); - mpu401_chk_version(m, devc); - if (devc->version == 0) - mpu401_chk_version(m, devc); - restore_flags(flags); - } + { + /* Verify the hardware again */ + if (!reset_mpu401(devc)) + { + printk(KERN_WARNING "mpu401: Device didn't respond\n"); + sound_unload_mididev(m); + return; + } + if (!devc->shared_irq) + { + if (request_irq(devc->irq, mpuintr, 0, "mpu401", (void *)m) < 0) + { + printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq); + sound_unload_mididev(m); + return; + } + } + save_flags(flags); + cli(); + mpu401_chk_version(m, devc); + if (devc->version == 0) + mpu401_chk_version(m, devc); + restore_flags(flags); + } request_region(hw_config->io_base, 2, "mpu401"); if (devc->version != 0) @@ -1061,36 +1011,32 @@ attach_mpu401(struct address_info *hw_config) devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ - mpu401_synth_operations[m] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; + mpu401_synth_operations[m] = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL); if (mpu401_synth_operations[m] == NULL) - { - sound_unload_mididev(m); - printk(KERN_ERR "mpu401: Can't allocate memory\n"); - return; - } + { + sound_unload_mididev(m); + printk(KERN_ERR "mpu401: Can't allocate memory\n"); + return; + } if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ - { - memcpy((char *) mpu401_synth_operations[m], - (char *) &std_midi_synth, + { + memcpy((char *) mpu401_synth_operations[m], + (char *) &std_midi_synth, sizeof(struct synth_operations)); - } else - { - memcpy((char *) mpu401_synth_operations[m], - (char *) &mpu401_synth_proto, + } + else + { + memcpy((char *) mpu401_synth_operations[m], + (char *) &mpu401_synth_proto, sizeof(struct synth_operations)); - } + } memcpy((char *) &mpu401_midi_operations[m], (char *) &mpu401_midi_proto, sizeof(struct midi_operations)); - mpu401_midi_operations[m].converter = - mpu401_synth_operations[m]; + mpu401_midi_operations[m].converter = mpu401_synth_operations[m]; memcpy((char *) &mpu_synth_info[m], (char *) &mpu_synth_info_proto, @@ -1099,37 +1045,36 @@ attach_mpu401(struct address_info *hw_config) n_mpu_devs++; if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */ - { - int ports = (devc->revision & 0x08) ? 32 : 16; - - devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | - MPU_CAP_CLS | MPU_CAP_2PORT; - - revision_char = (devc->revision == 0x7f) ? 'M' : ' '; - sprintf(mpu_synth_info[m].name, - "MQX-%d%c MIDI Interface #%d", - ports, - revision_char, - n_mpu_devs); - } else - { - - revision_char = devc->revision ? devc->revision + '@' : ' '; - if ((int) devc->revision > ('Z' - '@')) - revision_char = '+'; - - devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; - - if (hw_config->name) - sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name); - else - sprintf(mpu_synth_info[m].name, - "MPU-401 %d.%d%c Midi interface #%d", - (int) (devc->version & 0xf0) >> 4, - devc->version & 0x0f, - revision_char, - n_mpu_devs); - } + { + int ports = (devc->revision & 0x08) ? 32 : 16; + + devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | + MPU_CAP_CLS | MPU_CAP_2PORT; + + revision_char = (devc->revision == 0x7f) ? 'M' : ' '; + sprintf(mpu_synth_info[m].name, "MQX-%d%c MIDI Interface #%d", + ports, + revision_char, + n_mpu_devs); + } + else + { + revision_char = devc->revision ? devc->revision + '@' : ' '; + if ((int) devc->revision > ('Z' - '@')) + revision_char = '+'; + + devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; + + if (hw_config->name) + sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name); + else + sprintf(mpu_synth_info[m].name, + "MPU-401 %d.%d%c Midi interface #%d", + (int) (devc->version & 0xf0) >> 4, + devc->version & 0x0f, + revision_char, + n_mpu_devs); + } strcpy(mpu401_midi_operations[m].info.name, mpu_synth_info[m].name); @@ -1137,24 +1082,21 @@ attach_mpu401(struct address_info *hw_config) conf_printf(mpu_synth_info[m].name, hw_config); mpu401_synth_operations[m]->midi_dev = devc->devno = m; - mpu401_synth_operations[devc->devno]->info = - &mpu_synth_info[devc->devno]; + mpu401_synth_operations[devc->devno]->info = &mpu_synth_info[devc->devno]; if (devc->capabilities & MPU_CAP_INTLG) /* Intelligent mode */ hw_config->slots[2] = mpu_timer_init(m); - irq2dev[devc->irq] = m; midi_devs[m] = &mpu401_midi_operations[devc->devno]; hw_config->slots[1] = m; sequencer_init(); } -static int -reset_mpu401(struct mpu_config *devc) +static int reset_mpu401(struct mpu_config *devc) { - unsigned long flags; - int ok, timeout, n; - int timeout_limit; + unsigned long flags; + int ok, timeout, n; + int timeout_limit; /* * Send the RESET command. Try again if no success at the first time. @@ -1167,30 +1109,30 @@ reset_mpu401(struct mpu_config *devc) devc->initialized = 1; for (n = 0; n < 2 && !ok; n++) - { - for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) + { + for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) ok = output_ready(devc); - write_command(devc, MPU_RESET); /* + write_command(devc, MPU_RESET); /* * Send MPU-401 RESET Command */ - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ - for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) - { - save_flags(flags); - cli(); - if (input_avail(devc)) - if (read_data(devc) == MPU_ACK) - ok = 1; - restore_flags(flags); - } + for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) + { + save_flags(flags); + cli(); + if (input_avail(devc)) + if (read_data(devc) == MPU_ACK) + ok = 1; + restore_flags(flags); + } - } + } devc->m_state = ST_INIT; devc->m_ptr = 0; @@ -1201,43 +1143,37 @@ reset_mpu401(struct mpu_config *devc) return ok; } -static void -set_uart_mode(int dev, struct mpu_config *devc, int arg) +static void set_uart_mode(int dev, struct mpu_config *devc, int arg) { if (!arg && (devc->capabilities & MPU_CAP_INTLG)) - { - return; - } + return; if ((devc->uart_mode == 0) == (arg == 0)) - { - return; /* Already set */ - } + return; /* Already set */ reset_mpu401(devc); /* This exits the uart mode */ if (arg) - { - if (mpu_cmd(dev, UART_MODE_ON, 0) < 0) - { - printk("MPU%d: Can't enter UART mode\n", devc->devno); - devc->uart_mode = 0; - return; - } - } + { + if (mpu_cmd(dev, UART_MODE_ON, 0) < 0) + { + printk(KERN_ERR "mpu401: Can't enter UART mode\n"); + devc->uart_mode = 0; + return; + } + } devc->uart_mode = arg; } -int -probe_mpu401(struct address_info *hw_config) +int probe_mpu401(struct address_info *hw_config) { - int ok = 0; + int ok = 0; struct mpu_config tmp_devc; if (check_region(hw_config->io_base, 2)) - { - printk("\n\nmpu401.c: I/O port %x already in use\n\n", hw_config->io_base); - return 0; - } + { + printk(KERN_ERR "mpu401: I/O port %x already in use\n\n", hw_config->io_base); + return 0; + } tmp_devc.base = hw_config->io_base; tmp_devc.irq = hw_config->irq; tmp_devc.initialized = 0; @@ -1248,27 +1184,32 @@ probe_mpu401(struct address_info *hw_config) return 1; if (inb(hw_config->io_base + 1) == 0xff) - { - DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base)); - return 0; /* Just bus float? */ - } + { + DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base)); + return 0; /* Just bus float? */ + } ok = reset_mpu401(&tmp_devc); if (!ok) - { - DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base)); - } + { + DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base)); + } return ok; } -void -unload_mpu401(struct address_info *hw_config) +void unload_mpu401(struct address_info *hw_config) { + void *p; + int n=hw_config->slots[1]; + release_region(hw_config->io_base, 2); if (hw_config->always_detect == 0 && hw_config->irq > 0) - snd_release_irq(hw_config->irq); - sound_unload_mididev(hw_config->slots[1]); + free_irq(hw_config->irq, (void *)n); + p=mpu401_synth_operations[n]; + sound_unload_mididev(n); sound_unload_timerdev(hw_config->slots[2]); + if(p) + kfree(p); } /***************************************************** @@ -1285,23 +1226,20 @@ static volatile unsigned long curr_ticks, curr_clocks; static unsigned long prev_event_time; static int metronome_mode; -static unsigned long -clocks2ticks(unsigned long clocks) +static unsigned long clocks2ticks(unsigned long clocks) { /* - * The MPU-401 supports just a limited set of possible timebase values. - * Since the applications require more choices, the driver has to - * program the HW to do its best and to convert between the HW and - * actual timebases. + * The MPU-401 supports just a limited set of possible timebase values. + * Since the applications require more choices, the driver has to + * program the HW to do its best and to convert between the HW and + * actual timebases. */ - return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; } -static void -set_timebase(int midi_dev, int val) +static void set_timebase(int midi_dev, int val) { - int hw_val; + int hw_val; if (val < 48) val = 48; @@ -1314,19 +1252,18 @@ set_timebase(int midi_dev, int val) hw_val = max_timebase; if (mpu_cmd(midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0) - { - printk("MPU: Can't set HW timebase to %d\n", hw_val * 24); - return; - } + { + printk(KERN_WARNING "mpu401: Can't set HW timebase to %d\n", hw_val * 24); + return; + } hw_timebase = hw_val * 24; curr_timebase = val; } -static void -tmr_reset(void) +static void tmr_reset(void) { - unsigned long flags; + unsigned long flags; save_flags(flags); cli(); @@ -1336,8 +1273,7 @@ tmr_reset(void) restore_flags(flags); } -static void -set_timer_mode(int midi_dev) +static void set_timer_mode(int midi_dev) { if (timer_mode & TMR_MODE_CLS) mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ @@ -1345,31 +1281,31 @@ set_timer_mode(int midi_dev) mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ if (timer_mode & TMR_INTERNAL) - { + { mpu_cmd(midi_dev, 0x80, 0); /* Use MIDI sync */ - } else - { - if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) - { - mpu_cmd(midi_dev, 0x82, 0); /* Use MIDI sync */ - mpu_cmd(midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ - } else if (timer_mode & TMR_MODE_FSK) - mpu_cmd(midi_dev, 0x81, 0); /* Use FSK sync */ - } + } + else + { + if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) + { + mpu_cmd(midi_dev, 0x82, 0); /* Use MIDI sync */ + mpu_cmd(midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ + } + else if (timer_mode & TMR_MODE_FSK) + mpu_cmd(midi_dev, 0x81, 0); /* Use FSK sync */ + } } -static void -stop_metronome(int midi_dev) +static void stop_metronome(int midi_dev) { mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ } -static void -setup_metronome(int midi_dev) +static void setup_metronome(int midi_dev) { - int numerator, denominator; - int clks_per_click, num_32nds_per_beat; - int beats_per_measure; + int numerator, denominator; + int clks_per_click, num_32nds_per_beat; + int beats_per_measure; numerator = ((unsigned) metronome_mode >> 24) & 0xff; denominator = ((unsigned) metronome_mode >> 16) & 0xff; @@ -1380,15 +1316,14 @@ setup_metronome(int midi_dev) if (!metronome_mode) mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ else - { - mpu_cmd(midi_dev, 0xE4, clks_per_click); - mpu_cmd(midi_dev, 0xE6, beats_per_measure); - mpu_cmd(midi_dev, 0x83, 0); /* Enable metronome without accents */ - } + { + mpu_cmd(midi_dev, 0xE4, clks_per_click); + mpu_cmd(midi_dev, 0xE6, beats_per_measure); + mpu_cmd(midi_dev, 0x83, 0); /* Enable metronome without accents */ + } } -static int -mpu_start_timer(int midi_dev) +static int mpu_start_timer(int midi_dev) { tmr_reset(); set_timer_mode(midi_dev); @@ -1397,25 +1332,24 @@ mpu_start_timer(int midi_dev) return TIMER_NOT_ARMED; /* Already running */ if (timer_mode & TMR_INTERNAL) - { - mpu_cmd(midi_dev, 0x02, 0); /* Send MIDI start */ - tmr_running = 1; - return TIMER_NOT_ARMED; - } else - { - mpu_cmd(midi_dev, 0x35, 0); /* Enable mode messages to PC */ - mpu_cmd(midi_dev, 0x38, 0); /* Enable sys common messages to PC */ - mpu_cmd(midi_dev, 0x39, 0); /* Enable real time messages to PC */ - mpu_cmd(midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */ - } - + { + mpu_cmd(midi_dev, 0x02, 0); /* Send MIDI start */ + tmr_running = 1; + return TIMER_NOT_ARMED; + } + else + { + mpu_cmd(midi_dev, 0x35, 0); /* Enable mode messages to PC */ + mpu_cmd(midi_dev, 0x38, 0); /* Enable sys common messages to PC */ + mpu_cmd(midi_dev, 0x39, 0); /* Enable real time messages to PC */ + mpu_cmd(midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */ + } return TIMER_ARMED; } -static int -mpu_timer_open(int dev, int mode) +static int mpu_timer_open(int dev, int mode) { - int midi_dev = sound_timer_devs[dev]->devlink; + int midi_dev = sound_timer_devs[dev]->devlink; if (timer_open) return -EBUSY; @@ -1435,10 +1369,9 @@ mpu_timer_open(int dev, int mode) return 0; } -static void -mpu_timer_close(int dev) +static void mpu_timer_close(int dev) { - int midi_dev = sound_timer_devs[dev]->devlink; + int midi_dev = sound_timer_devs[dev]->devlink; timer_open = tmr_running = 0; mpu_cmd(midi_dev, 0x15, 0); /* Stop all */ @@ -1447,86 +1380,80 @@ mpu_timer_close(int dev) stop_metronome(midi_dev); } -static int -mpu_timer_event(int dev, unsigned char *event) +static int mpu_timer_event(int dev, unsigned char *event) { - unsigned char command = event[1]; - unsigned long parm = *(unsigned int *) &event[4]; - int midi_dev = sound_timer_devs[dev]->devlink; + unsigned char command = event[1]; + unsigned long parm = *(unsigned int *) &event[4]; + int midi_dev = sound_timer_devs[dev]->devlink; switch (command) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; - - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - if (tmr_running) - break; - return mpu_start_timer(midi_dev); - break; - - case TMR_STOP: - mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome(midi_dev); - tmr_running = 0; - break; - - case TMR_CONTINUE: - if (tmr_running) - break; - mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ - setup_metronome(midi_dev); - tmr_running = 1; - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 250) - parm = 250; - - if (mpu_cmd(midi_dev, 0xE0, parm) < 0) - printk("MPU: Can't set tempo to %d\n", (int) parm); - curr_tempo = parm; - } - break; - - case TMR_ECHO: - seq_copy_to_input(event, 8); - break; - - case TMR_TIMESIG: - if (metronome_mode) /* Metronome enabled */ - { - metronome_mode = parm; - setup_metronome(midi_dev); - } - break; - - default:; - } + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + if (tmr_running) + break; + return mpu_start_timer(midi_dev); + + case TMR_STOP: + mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ + stop_metronome(midi_dev); + tmr_running = 0; + break; + case TMR_CONTINUE: + if (tmr_running) + break; + mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ + setup_metronome(midi_dev); + tmr_running = 1; + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 250) + parm = 250; + if (mpu_cmd(midi_dev, 0xE0, parm) < 0) + printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) parm); + curr_tempo = parm; + } + break; + + case TMR_ECHO: + seq_copy_to_input(event, 8); + break; + + case TMR_TIMESIG: + if (metronome_mode) /* Metronome enabled */ + { + metronome_mode = parm; + setup_metronome(midi_dev); + } + break; + + default: + } return TIMER_NOT_ARMED; } -static unsigned long -mpu_timer_get_time(int dev) +static unsigned long mpu_timer_get_time(int dev) { if (!timer_open) return 0; @@ -1534,128 +1461,115 @@ mpu_timer_get_time(int dev) return curr_ticks; } -static int -mpu_timer_ioctl(int dev, - unsigned int command, caddr_t arg) +static int mpu_timer_ioctl(int dev, unsigned int command, caddr_t arg) { - int midi_dev = sound_timer_devs[dev]->devlink; + int midi_dev = sound_timer_devs[dev]->devlink; switch (command) - { - case SNDCTL_TMR_SOURCE: - { - int parm; - - parm = *(int *) arg; - parm &= timer_caps; - - if (parm != 0) - { - timer_mode = parm; - - if (timer_mode & TMR_MODE_CLS) - mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ - else if (timer_mode & TMR_MODE_SMPTE) - mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ - } - return (*(int *) arg = timer_mode); - } - break; - - case SNDCTL_TMR_START: - mpu_start_timer(midi_dev); - return 0; - break; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome(midi_dev); - return 0; - break; - - case SNDCTL_TMR_CONTINUE: - if (tmr_running) - return 0; - tmr_running = 1; - mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ - return 0; - break; - - case SNDCTL_TMR_TIMEBASE: - { - int val; - - val = *(int *) arg; - if (val) - set_timebase(midi_dev, val); - - return (*(int *) arg = curr_timebase); - } - break; - - case SNDCTL_TMR_TEMPO: - { - int val; - int ret; - - val = *(int *) arg; - - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0) - { - printk("MPU: Can't set tempo to %d\n", (int) val); - return ret; - } - curr_tempo = val; - } - return (*(int *) arg = curr_tempo); - } - break; - - case SNDCTL_SEQ_CTRLRATE: - { - int val; - - val = *(int *) arg; - if (val != 0) /* Can't change */ - return -EINVAL; - - return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); - } - break; - - case SNDCTL_SEQ_GETTIME: - return (*(int *) arg = curr_ticks); - break; - - case SNDCTL_TMR_METRONOME: - metronome_mode = *(int *) arg; - setup_metronome(midi_dev); - return 0; - break; - - default:; - } + { + case SNDCTL_TMR_SOURCE: + { + int parm; + + parm = *(int *) arg; + parm &= timer_caps; + if (parm != 0) + { + timer_mode = parm; + + if (timer_mode & TMR_MODE_CLS) + mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ + else if (timer_mode & TMR_MODE_SMPTE) + mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ + } + return (*(int *) arg = timer_mode); + } + break; + + case SNDCTL_TMR_START: + mpu_start_timer(midi_dev); + return 0; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ + stop_metronome(midi_dev); + return 0; + + case SNDCTL_TMR_CONTINUE: + if (tmr_running) + return 0; + tmr_running = 1; + mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ + return 0; + + case SNDCTL_TMR_TIMEBASE: + { + int val; + + val = *(int *) arg; + if (val) + set_timebase(midi_dev, val); + return (*(int *) arg = curr_timebase); + } + break; + + case SNDCTL_TMR_TEMPO: + { + int val; + int ret; + + val = *(int *) arg; + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0) + { + printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) val); + return ret; + } + curr_tempo = val; + } + return (*(int *) arg = curr_tempo); + } + break; + + case SNDCTL_SEQ_CTRLRATE: + { + int val; + + val = *(int *) arg; + if (val != 0) /* Can't change */ + return -EINVAL; + return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); + } + break; + + case SNDCTL_SEQ_GETTIME: + return (*(int *) arg = curr_ticks); + + case SNDCTL_TMR_METRONOME: + metronome_mode = *(int *) arg; + setup_metronome(midi_dev); + return 0; + + default: + } return -EINVAL; } -static void -mpu_timer_arm(int dev, long time) +static void mpu_timer_arm(int dev, long time) { if (time < 0) time = curr_ticks + 1; else if (time <= curr_ticks) /* It's the time */ return; - next_event_time = prev_event_time = time; - return; } @@ -1672,10 +1586,8 @@ static struct sound_timer_operations mpu_timer = mpu_timer_arm }; -static void -mpu_timer_interrupt(void) +static void mpu_timer_interrupt(void) { - if (!timer_open) return; @@ -1686,10 +1598,10 @@ mpu_timer_interrupt(void) curr_ticks = clocks2ticks(curr_clocks); if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer(0); - } + { + next_event_time = (unsigned long) -1; + sequencer_timer(0); + } } static void timer_ext_event(struct mpu_config *devc, int event, int parm) @@ -1706,8 +1618,9 @@ static void timer_ext_event(struct mpu_config *devc, int event, int parm) break; case TMR_START: - printk("Ext MIDI start\n"); + printk("Ext MIDI start\n"); if (!tmr_running) + { if (timer_mode & TMR_EXTERNAL) { tmr_running = 1; @@ -1715,6 +1628,7 @@ static void timer_ext_event(struct mpu_config *devc, int event, int parm) next_event_time = 0; STORE(SEQ_START_TIMER()); } + } break; case TMR_STOP: diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index 36734c2e7368..cd768801fa8a 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -2,25 +2,30 @@ * sound/opl3.c * * A low level driver for Yamaha YM3812 and OPL-3 -chips - */ -/* + * +* * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * + * Changes + * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) + * Alan Cox modularisation, fixed sound_mem allocs. + * + * Status + * Believed to work. Badly needs rewriting a bit to support multiple + * OPL3 devices. */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - */ + #include #include #include /* * Major improvements to the FM handling 30AUG92 by Rob Hooft, - */ -/* * hooft@chem.ruu.nl */ @@ -109,32 +114,32 @@ static int opl3_ioctl(int dev, unsigned int cmd, caddr_t arg) struct sbi_instrument ins; switch (cmd) { - case SNDCTL_FM_LOAD_INSTR: - printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); - if (__copy_from_user(&ins, arg, sizeof(ins))) - return -EFAULT; - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { - printk("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; - } - return store_instr(ins.channel, &ins); + case SNDCTL_FM_LOAD_INSTR: + printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); + if (copy_from_user(&ins, arg, sizeof(ins))) + return -EFAULT; + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { + printk(KERN_WARNING "FM Error: Invalid instrument number %d\n", ins.channel); + return -EINVAL; + } + return store_instr(ins.channel, &ins); - case SNDCTL_SYNTH_INFO: - devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; - if (__copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info))) - return -EFAULT; - return 0; + case SNDCTL_SYNTH_INFO: + devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; + if (copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info))) + return -EFAULT; + return 0; - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; - case SNDCTL_FM_4OP_ENABLE: - if (devc->model == 2) - enter_4op_mode(); - return 0; + case SNDCTL_FM_4OP_ENABLE: + if (devc->model == 2) + enter_4op_mode(); + return 0; - default: - return -EINVAL; + default: + return -EINVAL; } } @@ -151,8 +156,8 @@ int opl3_detect(int ioaddr, int *osp) * Note2! The chip is initialized if detected. */ - unsigned char stat1, signature; - int i; + unsigned char stat1, signature; + int i; if (devc != NULL) { @@ -160,10 +165,7 @@ int opl3_detect(int ioaddr, int *osp) return 0; } - devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(*devc))); - sound_mem_sizes[sound_nblocks] = sizeof(*devc); - if (sound_nblocks < 1024) - sound_nblocks++;; + devc = (struct opl_devinfo *)kmalloc(sizeof(*devc), GFP_KERNEL); if (devc == NULL) { @@ -333,7 +335,7 @@ static char fm_volume_table[128] = static void calc_vol(unsigned char *regbyte, int volume, int main_vol) { - int level = (~*regbyte & 0x3f); + int level = (~*regbyte & 0x3f); if (main_vol > 127) main_vol = 127; @@ -814,7 +816,8 @@ static int opl3_load_patch(int dev, int format, const char *addr, return -EINVAL; } - copy_from_user(&((char *) &ins)[offs], &(addr)[offs], sizeof(ins) - offs); + if(copy_from_user(&((char *) &ins)[offs], &(addr)[offs], sizeof(ins) - offs)) + return -EFAULT; if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { @@ -1199,6 +1202,7 @@ void cleanup_module(void) { if (devc) { + kfree(devc); devc = NULL; sound_unload_synthdev(me); } diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index 656034d54d2d..bf95b84d5763 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -164,7 +164,7 @@ static int config_pas_hw(struct address_info *hw_config) } else { - if (snd_set_irq_handler(pas_irq, pasintr, "PAS16", hw_config->osp) < 0) + if (request_irq(pas_irq, pasintr, "PAS16", 0, NULL) < 0) ok = 0; } } @@ -355,7 +355,7 @@ void unload_pas(struct address_info *hw_config) { sound_free_dma(hw_config->dma); - snd_release_irq(hw_config->irq); + free_irq(hw_config->irq, NULL); } #ifdef MODULE diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 9d62dd4852a0..7a0a2e66eda5 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -11,7 +11,8 @@ * for more info. */ /* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) + * Alan Cox modularisation, clean up. */ #include #include @@ -62,12 +63,12 @@ static int pss_synthLen = 0; #endif typedef struct pss_confdata - { - int base; - int irq; - int dma; - int *osp; - } +{ + int base; + int irq; + int dma; + int *osp; +} pss_confdata; @@ -77,12 +78,11 @@ static pss_confdata *devc = &pss_data; static int pss_initialized = 0; static int nonstandard_microcode = 0; -static void -pss_write(int data) +static void pss_write(int data) { - int i, limit; + int i, limit; - limit = jiffies + 10; /* The timeout is 0.1 seconds */ + limit = jiffies + HZ/10; /* The timeout is 0.1 seconds */ /* * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes * called while interrupts are disabled. This means that the timer is @@ -92,21 +92,20 @@ pss_write(int data) */ for (i = 0; i < 5000000 && jiffies < limit; i++) - { - if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) - { - outw(devc->base + PSS_DATA, data); - return; - } - } - printk("PSS: DSP Command (%04x) Timeout.\n", data); + { + if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) + { + outw(devc->base + PSS_DATA, data); + return; + } + } + printk(KERN_ERR "PSS: DSP Command (%04x) Timeout.\n", data); } -int -probe_pss(struct address_info *hw_config) +int probe_pss(struct address_info *hw_config) { - unsigned short id; - int irq, dma; + unsigned short id; + int irq, dma; devc->base = hw_config->io_base; irq = devc->irq = hw_config->irq; @@ -129,8 +128,7 @@ probe_pss(struct address_info *hw_config) return 1; } -static int -set_irq(pss_confdata * devc, int dev, int irq) +static int set_irq(pss_confdata * devc, int dev, int irq) { static unsigned short irq_bits[16] = { @@ -148,16 +146,15 @@ set_irq(pss_confdata * devc, int dev, int irq) tmp = inw(REG(dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ if ((bits = irq_bits[irq]) == 0 && irq != 0) - { - printk("PSS: Invalid IRQ %d\n", irq); - return 0; - } + { + printk(KERN_ERR "PSS: Invalid IRQ %d\n", irq); + return 0; + } outw(tmp | bits, REG(dev)); return 1; } -static int -set_io_base(pss_confdata * devc, int dev, int base) +static int set_io_base(pss_confdata * devc, int dev, int base) { unsigned short tmp = inw(REG(dev)) & 0x003f; unsigned short bits = (base & 0x0ffc) << 4; @@ -167,8 +164,7 @@ set_io_base(pss_confdata * devc, int dev, int base) return 1; } -static int -set_dma(pss_confdata * devc, int dev, int dma) +static int set_dma(pss_confdata * devc, int dev, int dma) { static unsigned short dma_bits[8] = { @@ -184,150 +180,139 @@ set_dma(pss_confdata * devc, int dev, int dma) tmp = inw(REG(dev)) & ~0x07; /* Load confreg, mask DMA bits out */ if ((bits = dma_bits[dma]) == 0 && dma != 4) - { - printk("PSS: Invalid DMA %d\n", dma); + { + printk(KERN_ERR "PSS: Invalid DMA %d\n", dma); return 0; - } + } outw(tmp | bits, REG(dev)); return 1; } -static int -pss_reset_dsp(pss_confdata * devc) +static int pss_reset_dsp(pss_confdata * devc) { - unsigned long i, limit = jiffies + 10; + unsigned long i, limit = jiffies + HZ/10; outw(0x2000, REG(PSS_CONTROL)); - - for (i = 0; i < 32768 && jiffies < limit; i++) + for (i = 0; i < 32768 && (limit-jiffies >= 0); i++) inw(REG(PSS_CONTROL)); - outw(0x0000, REG(PSS_CONTROL)); - return 1; } -static int -pss_put_dspword(pss_confdata * devc, unsigned short word) +static int pss_put_dspword(pss_confdata * devc, unsigned short word) { - int i, val; + int i, val; for (i = 0; i < 327680; i++) - { - val = inw(REG(PSS_STATUS)); - if (val & PSS_WRITE_EMPTY) - { - outw(word, REG(PSS_DATA)); - return 1; - } - } + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_WRITE_EMPTY) + { + outw(word, REG(PSS_DATA)); + return 1; + } + } return 0; } -static int -pss_get_dspword(pss_confdata * devc, unsigned short *word) +static int pss_get_dspword(pss_confdata * devc, unsigned short *word) { - int i, val; + int i, val; for (i = 0; i < 327680; i++) - { - val = inw(REG(PSS_STATUS)); - if (val & PSS_READ_FULL) - { - *word = inw(REG(PSS_DATA)); - return 1; - } - } - + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_READ_FULL) + { + *word = inw(REG(PSS_DATA)); + return 1; + } + } return 0; } -static int -pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags) +static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags) { - int i, limit, val, count; + int i, limit, val, count; if (flags & CPF_FIRST) - { + { /*_____ Warn DSP software that a boot is coming */ - outw(0x00fe, REG(PSS_DATA)); - - limit = jiffies + 10; + outw(0x00fe, REG(PSS_DATA)); - for (i = 0; i < 32768 && jiffies < limit; i++) - if (inw(REG(PSS_DATA)) == 0x5500) - break; - - outw(*block++, REG(PSS_DATA)); + limit = jiffies + HZ/10; + for (i = 0; i < 32768 && jiffies < limit; i++) + if (inw(REG(PSS_DATA)) == 0x5500) + break; - pss_reset_dsp(devc); - } + outw(*block++, REG(PSS_DATA)); + pss_reset_dsp(devc); + } count = 1; while (1) - { - int j; + { + int j; - for (j = 0; j < 327670; j++) - { + for (j = 0; j < 327670; j++) + { /*_____ Wait for BG to appear */ - if (inw(REG(PSS_STATUS)) & PSS_FLAG3) - break; - } - - if (j == 327670) - { - /* It's ok we timed out when the file was empty */ - if (count >= size && flags & CPF_LAST) - break; - else - { - printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size); - return 0; - } - } + if (inw(REG(PSS_STATUS)) & PSS_FLAG3) + break; + } + + if (j == 327670) + { + /* It's ok we timed out when the file was empty */ + if (count >= size && flags & CPF_LAST) + break; + else + { + printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size); + return 0; + } + } /*_____ Send the next byte */ - outw(*block++, REG(PSS_DATA)); - count++; - } + outw(*block++, REG(PSS_DATA)); + count++; + } if (flags & CPF_LAST) - { + { /*_____ Why */ - outw(0, REG(PSS_DATA)); - - limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - val = inw(REG(PSS_STATUS)); - - limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - { - val = inw(REG(PSS_STATUS)); - if (val & 0x4000) - break; - } - - /* now read the version */ - for (i = 0; i < 32000; i++) - { - val = inw(REG(PSS_STATUS)); - if (val & PSS_READ_FULL) - break; - } - if (i == 32000) - return 0; - - val = inw(REG(PSS_DATA)); - /* printk( "", val/16, val % 16); */ - } + outw(0, REG(PSS_DATA)); + + limit = jiffies + HZ/10; + for (i = 0; i < 32768 && (limit - jiffies >= 0); i++) + val = inw(REG(PSS_STATUS)); + + limit = jiffies + HZ/10; + for (i = 0; i < 32768 && (limit-jiffies >= 0); i++) + { + val = inw(REG(PSS_STATUS)); + if (val & 0x4000) + break; + } + + /* now read the version */ + for (i = 0; i < 32000; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_READ_FULL) + break; + } + if (i == 32000) + return 0; + + val = inw(REG(PSS_DATA)); + /* printk( "", val/16, val % 16); */ + } return 1; } -void -attach_pss(struct address_info *hw_config) +void attach_pss(struct address_info *hw_config) { unsigned short id; - char tmp[100]; + char tmp[100]; devc->base = hw_config->io_base; devc->irq = hw_config->irq; @@ -350,20 +335,20 @@ attach_pss(struct address_info *hw_config) #if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES if (sound_alloc_dma(hw_config->dma, "PSS")) - { - printk("pss.c: Can't allocate DMA channel\n"); - return; - } + { + printk("pss.c: Can't allocate DMA channel.\n"); + return; + } if (!set_irq(devc, CONF_PSS, devc->irq)) - { - printk("PSS: IRQ error\n"); - return; - } + { + printk("PSS: IRQ allocation error.\n"); + return; + } if (!set_dma(devc, CONF_PSS, devc->dma)) - { - printk("PSS: DRQ error\n"); - return; - } + { + printk(KERN_ERR "PSS: DMA allocation error\n"); + return; + } #endif pss_initialized = 1; @@ -371,8 +356,7 @@ attach_pss(struct address_info *hw_config) conf_printf(tmp, hw_config); } -static void -pss_init_speaker(void) +static void pss_init_speaker(void) { /* Don't ask what are these commands. I really don't know */ pss_write(0x0010); @@ -387,53 +371,52 @@ pss_init_speaker(void) pss_write(0x0800 | 0x00ce); /* Stereo switch? */ } -int -probe_pss_mpu(struct address_info *hw_config) +int probe_pss_mpu(struct address_info *hw_config) { - int timeout; + int timeout; if (!pss_initialized) return 0; if (check_region(hw_config->io_base, 2)) - { - printk("PSS: MPU I/O port conflict\n"); - return 0; - } + { + printk("PSS: MPU I/O port conflict\n"); + return 0; + } if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) - { - printk("PSS: MIDI base error.\n"); + { + printk("PSS: MIDI base could not be set.\n"); return 0; - } + } if (!set_irq(devc, CONF_MIDI, hw_config->irq)) - { - printk("PSS: MIDI IRQ error.\n"); + { + printk("PSS: MIDI IRQ allocation error.\n"); return 0; - } + } if (!pss_synthLen) - { - printk("PSS: Can't enable MPU. MIDI synth microcode not available.\n"); - return 0; - } + { + printk(KERN_ERR "PSS: Can't enable MPU. MIDI synth microcode not available.\n"); + return 0; + } if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return 0; - } + { + printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n"); + return 0; + } pss_init_speaker(); -/* - * Finally wait until the DSP algorithm has initialized itself and - * deactivates receive interrupt. - */ + /* + * Finally wait until the DSP algorithm has initialized itself and + * deactivates receive interrupt. + */ for (timeout = 900000; timeout > 0; timeout--) - { - if ((inb(hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ - inb(hw_config->io_base); /* Discard it */ - else - break; /* No more input */ - } + { + if ((inb(hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ + inb(hw_config->io_base); /* Discard it */ + else + break; /* No more input */ + } #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) return probe_mpu401(hw_config); @@ -442,62 +425,56 @@ probe_pss_mpu(struct address_info *hw_config) #endif } -static int -pss_coproc_open(void *dev_info, int sub_device) +static int pss_coproc_open(void *dev_info, int sub_device) { switch (sub_device) - { - case COPR_MIDI: - - if (pss_synthLen == 0) - { - printk("PSS: MIDI synth microcode not available.\n"); - return -EIO; - } - if (nonstandard_microcode) - if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return -EIO; - } - nonstandard_microcode = 0; - break; - - default:; - } + { + case COPR_MIDI: + if (pss_synthLen == 0) + { + printk(KERN_ERR "PSS: MIDI synth microcode not available.\n"); + return -EIO; + } + if (nonstandard_microcode) + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n"); + return -EIO; + } + nonstandard_microcode = 0; + break; + + default: + } return 0; } -static void -pss_coproc_close(void *dev_info, int sub_device) +static void pss_coproc_close(void *dev_info, int sub_device) { return; } -static void -pss_coproc_reset(void *dev_info) +static void pss_coproc_reset(void *dev_info) { if (pss_synthLen) if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); - } + { + printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n"); + } nonstandard_microcode = 0; } -static int -download_boot_block(void *dev_info, copr_buffer * buf) +static int download_boot_block(void *dev_info, copr_buffer * buf) { if (buf->len <= 0 || buf->len > sizeof(buf->data)) return -EINVAL; if (!pss_download_boot(devc, buf->data, buf->len, buf->flags)) - { - printk("PSS: Unable to load microcode block to DSP.\n"); - return -EIO; - } + { + printk(KERN_ERR "PSS: Unable to load microcode block to DSP.\n"); + return -EIO; + } nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ - return 0; } @@ -512,169 +489,170 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int l int i, err; /* printk( "PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - switch (cmd) { - case SNDCTL_COPR_RESET: - pss_coproc_reset(dev_info); - return 0; + switch (cmd) + { + case SNDCTL_COPR_RESET: + pss_coproc_reset(dev_info); + return 0; - case SNDCTL_COPR_LOAD: - buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); - if (buf == NULL) - return -ENOSPC; - if (__copy_from_user(buf, arg, sizeof(copr_buffer))) { + case SNDCTL_COPR_LOAD: + buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); + if (buf == NULL) + return -ENOSPC; + if (copy_from_user(buf, arg, sizeof(copr_buffer))) { + vfree(buf); + return -EFAULT; + } + err = download_boot_block(dev_info, buf); vfree(buf); - return -EFAULT; - } - err = download_boot_block(dev_info, buf); - vfree(buf); - return err; + return err; - case SNDCTL_COPR_SENDMSG: - mbuf = (copr_msg *)vmalloc(sizeof(copr_msg)); - if (mbuf == NULL) - return -ENOSPC; - if (__copy_from_user(mbuf, arg, sizeof(copr_msg))) { - vfree(mbuf); - return -EFAULT; - } - data = (unsigned short *)(mbuf->data); - save_flags(flags); - cli(); - for (i = 0; i < mbuf->len; i++) { - if (!pss_put_dspword(devc, *data++)) { - restore_flags(flags); - mbuf->len = i; /* feed back number of WORDs sent */ - err = __copy_to_user(arg, mbuf, sizeof(copr_msg)); + case SNDCTL_COPR_SENDMSG: + mbuf = (copr_msg *)vmalloc(sizeof(copr_msg)); + if (mbuf == NULL) + return -ENOSPC; + if (copy_from_user(mbuf, arg, sizeof(copr_msg))) { vfree(mbuf); - return err ? -EFAULT : -EIO; + return -EFAULT; } - } - restore_flags(flags); - vfree(mbuf); - return 0; - - case SNDCTL_COPR_RCVMSG: - err = 0; - mbuf = (copr_msg *)vmalloc(sizeof(copr_msg)); - if (mbuf == NULL) - return -ENOSPC; - data = (unsigned short *)mbuf->data; - save_flags(flags); - cli(); - for (i = 0; i < mbuf->len; i++) { - mbuf->len = i; /* feed back number of WORDs read */ - if (!pss_get_dspword(devc, data++)) { - if (i == 0) - err = -EIO; - break; + data = (unsigned short *)(mbuf->data); + save_flags(flags); + cli(); + for (i = 0; i < mbuf->len; i++) { + if (!pss_put_dspword(devc, *data++)) { + restore_flags(flags); + mbuf->len = i; /* feed back number of WORDs sent */ + err = copy_to_user(arg, mbuf, sizeof(copr_msg)); + vfree(mbuf); + return err ? -EFAULT : -EIO; + } } - } - restore_flags(flags); - if (__copy_to_user(arg, mbuf, sizeof(copr_msg))) - err = -EFAULT; - vfree(mbuf); - return err; - - case SNDCTL_COPR_RDATA: - if (__copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - save_flags(flags); - cli(); - if (!pss_put_dspword(devc, 0x00d0)) { - restore_flags(flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { restore_flags(flags); - return -EIO; - } - if (!pss_get_dspword(devc, &tmp)) { + vfree(mbuf); + return 0; + + case SNDCTL_COPR_RCVMSG: + err = 0; + mbuf = (copr_msg *)vmalloc(sizeof(copr_msg)); + if (mbuf == NULL) + return -ENOSPC; + data = (unsigned short *)mbuf->data; + save_flags(flags); + cli(); + for (i = 0; i < mbuf->len; i++) { + mbuf->len = i; /* feed back number of WORDs read */ + if (!pss_get_dspword(devc, data++)) { + if (i == 0) + err = -EIO; + break; + } + } restore_flags(flags); - return -EIO; - } - dbuf.parm1 = tmp; - restore_flags(flags); - if (__copy_to_user(arg, &dbuf, sizeof(dbuf))) - return -EFAULT; - return 0; + if (copy_to_user(arg, mbuf, sizeof(copr_msg))) + err = -EFAULT; + vfree(mbuf); + return err; - case SNDCTL_COPR_WDATA: - if (__copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - save_flags(flags); - cli(); - if (!pss_put_dspword(devc, 0x00d1)) { - restore_flags(flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) { - restore_flags(flags); - return -EIO; - } - tmp = (unsigned int)dbuf.parm2 & 0xffff; - if (!pss_put_dspword(devc, tmp)) { + case SNDCTL_COPR_RDATA: + if (copy_from_user(&dbuf, arg, sizeof(dbuf))) + return -EFAULT; + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d0)) { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { + restore_flags(flags); + return -EIO; + } + if (!pss_get_dspword(devc, &tmp)) { + restore_flags(flags); + return -EIO; + } + dbuf.parm1 = tmp; restore_flags(flags); - return -EIO; - } - restore_flags(flags); - return 0; + if (copy_to_user(arg, &dbuf, sizeof(dbuf))) + return -EFAULT; + return 0; - case SNDCTL_COPR_WCODE: - if (__copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - save_flags(flags); - cli(); - if (!pss_put_dspword(devc, 0x00d3)) { - restore_flags(flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - restore_flags(flags); - return -EIO; - } - tmp = (unsigned int)dbuf.parm2 & 0x00ff; - if (!pss_put_dspword(devc, tmp)) { - restore_flags(flags); - return -EIO; - } - tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff; - if (!pss_put_dspword(devc, tmp)) { + case SNDCTL_COPR_WDATA: + if (copy_from_user(&dbuf, arg, sizeof(dbuf))) + return -EFAULT; + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d1)) { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) { + restore_flags(flags); + return -EIO; + } + tmp = (unsigned int)dbuf.parm2 & 0xffff; + if (!pss_put_dspword(devc, tmp)) { + restore_flags(flags); + return -EIO; + } restore_flags(flags); - return -EIO; - } - restore_flags(flags); - return 0; + return 0; - case SNDCTL_COPR_RCODE: - if (__copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - save_flags(flags); - cli(); - if (!pss_put_dspword(devc, 0x00d2)) { - restore_flags(flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - restore_flags(flags); - return -EIO; - } - if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */ + case SNDCTL_COPR_WCODE: + if (copy_from_user(&dbuf, arg, sizeof(dbuf))) + return -EFAULT; + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d3)) { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { + restore_flags(flags); + return -EIO; + } + tmp = (unsigned int)dbuf.parm2 & 0x00ff; + if (!pss_put_dspword(devc, tmp)) { + restore_flags(flags); + return -EIO; + } + tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff; + if (!pss_put_dspword(devc, tmp)) { + restore_flags(flags); + return -EIO; + } restore_flags(flags); - return -EIO; - } - dbuf.parm1 = tmp << 8; - if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */ + return 0; + + case SNDCTL_COPR_RCODE: + if (copy_from_user(&dbuf, arg, sizeof(dbuf))) + return -EFAULT; + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d2)) { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { + restore_flags(flags); + return -EIO; + } + if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */ + restore_flags(flags); + return -EIO; + } + dbuf.parm1 = tmp << 8; + if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */ + restore_flags(flags); + return -EIO; + } + dbuf.parm1 |= tmp & 0x00ff; restore_flags(flags); - return -EIO; - } - dbuf.parm1 |= tmp & 0x00ff; - restore_flags(flags); - if (__copy_to_user(arg, &dbuf, sizeof(dbuf))) - return -EFAULT; - return 0; + if (copy_to_user(arg, &dbuf, sizeof(dbuf))) + return -EFAULT; + return 0; - default: - return -EINVAL; + default: + return -EINVAL; } return -EINVAL; } @@ -689,52 +667,47 @@ static coproc_operations pss_coproc_operations = &pss_data }; -void -attach_pss_mpu(struct address_info *hw_config) +void attach_pss_mpu(struct address_info *hw_config) { #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - { - attach_mpu401(hw_config); /* Slot 1 */ - - if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ - midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; - } + attach_mpu401(hw_config); /* Slot 1 */ + if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ + midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; #endif } -int -probe_pss_mss(struct address_info *hw_config) +int probe_pss_mss(struct address_info *hw_config) { - volatile int timeout; + volatile int timeout; if (!pss_initialized) return 0; if (check_region(hw_config->io_base, 8)) - { - printk("PSS: WSS I/O port conflict\n"); + { + printk(KERN_ERR "PSS: WSS I/O port conflicts.\n"); return 0; - } + } if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) - { - printk("PSS: WSS base error.\n"); - return 0; - } + { + printk("PSS: WSS base not settable.\n"); + return 0; + } if (!set_irq(devc, CONF_WSS, hw_config->irq)) - { - printk("PSS: WSS IRQ error.\n"); - return 0; - } + { + printk("PSS: WSS IRQ allocation error.\n"); + return 0; + } if (!set_dma(devc, CONF_WSS, hw_config->dma)) - { - printk("PSS: WSS DRQ error\n"); - return 0; - } + { + printk(KERN_ERR "PSS: WSS DMA allocation error\n"); + return 0; + } /* - * For some reason the card returns 0xff in the WSS status register - * immediately after boot. Probably MIDI+SB emulation algorithm - * downloaded to the ADSP2115 spends some time initializing the card. - * Let's try to wait until it finishes this task. + * For some reason the card returns 0xff in the WSS status register + * immediately after boot. Probably MIDI+SB emulation algorithm + * downloaded to the ADSP2115 spends some time initializing the card. + * Let's try to wait until it finishes this task. */ for (timeout = 0; timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04; @@ -748,8 +721,7 @@ probe_pss_mss(struct address_info *hw_config) return probe_ms_sound(hw_config); } -void -attach_pss_mss(struct address_info *hw_config) +void attach_pss_mss(struct address_info *hw_config) { attach_ms_sound(hw_config); /* Slot 0 */ @@ -757,34 +729,31 @@ attach_pss_mss(struct address_info *hw_config) audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations; } -void -unload_pss(struct address_info *hw_config) +void unload_pss(struct address_info *hw_config) { } -void -unload_pss_mpu(struct address_info *hw_config) +void unload_pss_mpu(struct address_info *hw_config) { #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401(hw_config); #endif } -void -unload_pss_mss(struct address_info *hw_config) +void unload_pss_mss(struct address_info *hw_config) { unload_ms_sound(hw_config); } #ifdef MODULE -int pss_io = 0x220; +int pss_io = -1; -int mss_io = 0x530; -int mss_irq = 11; -int mss_dma = 1; +int mss_io = -1; +int mss_irq = -1; +int mss_dma = -1; -int mpu_io = 0x330; +int mpu_io = -1; int mpu_irq = -1; struct address_info cfgpss = { 0 /* pss_io */, 0, -1, -1 }; @@ -798,22 +767,20 @@ MODULE_PARM(mss_dma, "i"); MODULE_PARM(mpu_io, "i"); MODULE_PARM(mpu_irq, "i"); -static int fw_load = 0; -static int pssmpu = 0, pssmss = 0; +static int fw_load = 0; +static int pssmpu = 0, pssmss = 0; /* * Load a PSS sound card module */ -int -init_module(void) +int init_module(void) { -#if 0 - if (pss_io == -1 || irq == -1 || dma == -1) { - printk("pss: dma, irq and io must be set.\n"); - return -EINVAL; + if (pss_io == -1 || mss_io == -1 || mss_irq == -1 || mss_dma == -1) { + printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n"); + return -EINVAL; } -#endif + cfgpss.io_base = pss_io; cfgmss.io_base = mss_io; @@ -823,7 +790,8 @@ init_module(void) cfgmpu.io_base = mpu_io; cfgmpu.irq = mpu_irq; - if (!pss_synth) { + if (!pss_synth) + { fw_load = 1; pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth); } @@ -845,8 +813,7 @@ init_module(void) return 0; } -void -cleanup_module(void) +void cleanup_module(void) { if (fw_load && pss_synth) kfree(pss_synth); diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c index 9a0fe3c79784..bf3a8dbef9f1 100644 --- a/drivers/sound/sb_audio.c +++ b/drivers/sound/sb_audio.c @@ -1151,14 +1151,14 @@ void sb_audio_init(sb_devc * devc, char *name) } if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - name, - driver, - sizeof(struct audio_driver), - audio_flags, - format_mask, - devc, - devc->dma8, - devc->dma8)) < 0) + name, + driver, + sizeof(struct audio_driver), + audio_flags, + format_mask, + devc, + devc->dma8, + devc->dma8)) < 0) { printk(KERN_ERR "sb: unable to install audio.\n"); return; diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index fddf74b7951a..941422c3f746 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -69,6 +69,7 @@ int trix = 0; /* Set trix=1 to load this as support for trix */ int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ int sm_games = 0; /* Mixer - see sb_mixer.c */ int acer = 0; /* Do acer notebook init */ +int mwave_bug = 0; /* Using the dreadful mwave sb emulation */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -80,10 +81,11 @@ MODULE_PARM(mad16, "i"); MODULE_PARM(trix, "i"); MODULE_PARM(pas2, "i"); MODULE_PARM(sm_games, "i"); +MODULE_PARM(mwave_bug, "i"); -static int sbmpu = 0; +static int sbmpu = 0; -void *smw_free = NULL; +void *smw_free = NULL; int init_module(void) { @@ -119,8 +121,7 @@ int init_module(void) return 0; } -void -cleanup_module(void) +void cleanup_module(void) { if (smw_free) kfree(smw_free); @@ -133,19 +134,20 @@ cleanup_module(void) #else -#ifdef SM_GAMES +#ifdef CONFIG_SM_GAMES int sm_games = 1; - #else int sm_games = 0; - #endif -#ifdef SB_ACER +#ifdef CONFIG_SB_ACER int acer = 1; - #else int acer = 0; - +#endif +#ifdef CONFIG_SB_MWAVE +int mwave_bug = 1; +#else +int mwave_bug = 0; #endif #endif #endif diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 0f3e1e6aa305..fcdcfcf2c9d5 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -28,7 +28,6 @@ static sb_devc *detected_devc = NULL; /* For communication from probe to init */ static sb_devc *last_devc = NULL; /* For MPU401 initialization */ -static sb_devc *irq2devc[16] = {NULL}; static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6 }; @@ -123,15 +122,9 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) int status; unsigned char src = 0xff; - sb_devc *devc = irq2devc[irq]; + sb_devc *devc = dev_id; - if (devc == NULL || devc->irq != irq) - { - DEB(printk("sbintr: Bogus interrupt IRQ%d\n", irq)); - return; - } devc->irq_ok = 1; - if (devc->model == MDL_SB16) { src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ @@ -710,6 +703,7 @@ void sb_dsp_init(struct address_info *hw_config) sb_devc *devc; char name[100]; extern int sb_be_quiet; + extern int mwave_bug; /* * Check if we had detected a SB device earlier @@ -743,21 +737,19 @@ void sb_dsp_init(struct address_info *hw_config) if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && hw_config->irq > 0) { /* IRQ setup */ - if (snd_set_irq_handler(hw_config->irq, sbintr, "soundblaster", devc->osp) < 0) + if (request_irq(hw_config->irq, sbintr, 0, "soundblaster", devc) < 0) { printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); sound_unload_audiodev(devc->dev); return; } - irq2devc[hw_config->irq] = devc; devc->irq_ok = 0; if (devc->major == 4) if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ { - snd_release_irq(devc->irq); + free_irq(devc->irq, devc); sound_unload_audiodev(devc->dev); - irq2devc[hw_config->irq] = NULL; return; } if ((devc->type == 0 || devc->type == MDL_ESS) && @@ -777,7 +769,7 @@ void sb_dsp_init(struct address_info *hw_config) /* Skip IRQ detection if SMP (doesn't work) */ devc->irq_ok = 1; #else - if (devc->major == 4 && devc->minor <= 11) /* Won't work */ + if ((devc->major == 4 && devc->minor <= 11 ) || mwave_bug ) /* Won't work */ devc->irq_ok = 1; else { @@ -883,6 +875,7 @@ void sb_dsp_init(struct address_info *hw_config) } } hw_config->card_subtype = devc->model; + hw_config->slots[0]=devc->dev; last_devc = devc; /* For SB MPU detection */ if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0) @@ -915,15 +908,8 @@ void sb_dsp_disable_recording(int io_base) void sb_dsp_unload(struct address_info *hw_config) { sb_devc *devc; - int irq = hw_config->irq; - if (irq < 0) - irq *= -1; - - if (irq > 2 && irq < 16) - devc = irq2devc[irq]; - else - devc = NULL; + devc = audio_devs[hw_config->slots[0]]->devc; if (devc && devc->base == hw_config->io_base) { @@ -937,12 +923,12 @@ void sb_dsp_unload(struct address_info *hw_config) } if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0) { - snd_release_irq(devc->irq); - irq2devc[devc->irq] = NULL; + free_irq(devc->irq, devc); sound_unload_mixerdev(devc->my_mixerdev); sound_unload_mididev(devc->my_mididev); sound_unload_audiodev(devc->my_dev); } + kfree(devc); } else release_region(hw_config->io_base, 16); diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h index 0ed168e1f319..416737f651b3 100644 --- a/drivers/sound/sound_calls.h +++ b/drivers/sound/sound_calls.h @@ -83,8 +83,9 @@ void MIDIbuf_init(void); /* From soundcard.c */ void request_sound_timer (int count); void sound_stop_timer(void); -int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp); -void snd_release_irq(int vect); +/* These two are about to die.. */ +int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp, void *dev_id); +void snd_release_irq(int vect, void *ptr); void sound_dma_malloc(int dev); void sound_dma_free(int dev); void conf_printf(char *name, struct address_info *hw_config); diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c index 8a519e7e209b..98666831692c 100644 --- a/drivers/sound/sound_timer.c +++ b/drivers/sound/sound_timer.c @@ -47,6 +47,14 @@ void reprogram_timer(void) { unsigned long usecs_per_tick; + /* + * The user is changing the timer rate before setting a timer + * slap, bad bad not allowed. + */ + + if(!tmr) + return; + usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); /* diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 2e4cce0d3b91..fe3622a737bd 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef __KERNEL__ #include #include @@ -438,7 +439,7 @@ static int sound_open(struct inode *inode, struct file *file) case SND_DEV_CTL: dev >>= 4; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) { char modname[20]; sprintf(modname, "mixer%d", dev); @@ -554,14 +555,14 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, caddr_t arg) { if (mixdev < 0 || mixdev >= MAX_MIXER_DEV) return -ENXIO; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD /* Try to load the mixer... */ if (mixer_devs[mixdev] == NULL) { char modname[20]; sprintf(modname, "mixer%d", mixdev); request_module(modname); } -#endif /* CONFIG_KERNELD */ +#endif /* CONFIG_KMOD */ if (mixdev >= num_mixers || !mixer_devs[mixdev]) return -ENXIO; if (cmd == SOUND_MIXER_INFO) @@ -800,7 +801,7 @@ free_all_irqs(void) if (irqs & (1ul << i)) { printk(KERN_WARNING "Sound warning: IRQ%d was left allocated - fixed.\n", i); - snd_release_irq(i); + snd_release_irq(i, NULL); } } irqs = 0; @@ -894,14 +895,14 @@ void cleanup_module(void) } #endif -int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp) +int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp, void *dev_id) { - int retcode; - unsigned long flags; + int retcode; + unsigned long flags; save_flags(flags); cli(); - retcode = request_irq(interrupt_level, iproc, 0, name, NULL); + retcode = request_irq(interrupt_level, iproc, 0, name, dev_id); if (retcode < 0) { @@ -914,13 +915,13 @@ int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct return retcode; } -void snd_release_irq(int vect) +void snd_release_irq(int vect, void *dev_id) { if (!(irqs & (1ul << vect))) return; irqs &= ~(1ul << vect); - free_irq(vect, NULL); + free_irq(vect, dev_id); } int sound_alloc_dma(int chn, char *deviceID) diff --git a/drivers/sound/uart401.c b/drivers/sound/uart401.c index 7293e9047396..2e7ed2a2783f 100644 --- a/drivers/sound/uart401.c +++ b/drivers/sound/uart401.c @@ -9,7 +9,15 @@ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * Changes: + * Alan Cox Reformatted, removed sound_mem usage, use normal Linux + * interrupt allocation. + * + * Status: + * Untested */ + #include #include @@ -19,45 +27,43 @@ #if (defined(CONFIG_UART401)||defined(CONFIG_MIDI)) || defined(MODULE) typedef struct uart401_devc - { - int base; - int irq; - int *osp; - void (*midi_input_intr) (int dev, unsigned char data); - int opened, disabled; - volatile unsigned char input_byte; - int my_dev; - int share_irq; - } +{ + int base; + int irq; + int *osp; + void (*midi_input_intr) (int dev, unsigned char data); + int opened, disabled; + volatile unsigned char input_byte; + int my_dev; + int share_irq; +} uart401_devc; static uart401_devc *detected_devc = NULL; -static uart401_devc *irq2devc[16] = -{NULL}; #define DATAPORT (devc->base) #define COMDPORT (devc->base+1) #define STATPORT (devc->base+1) -static int -uart401_status(uart401_devc * devc) +static int uart401_status(uart401_devc * devc) { return inb(STATPORT); } + #define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL)) #define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY)) -static void -uart401_cmd(uart401_devc * devc, unsigned char cmd) + +static void uart401_cmd(uart401_devc * devc, unsigned char cmd) { outb((cmd), COMDPORT); } -static int -uart401_read(uart401_devc * devc) + +static int uart401_read(uart401_devc * devc) { return inb(DATAPORT); } -static void -uart401_write(uart401_devc * devc, unsigned char byte) + +static void uart401_write(uart401_devc * devc, unsigned char byte) { outb((byte), DATAPORT); } @@ -71,30 +77,26 @@ uart401_write(uart401_devc * devc, unsigned char byte) static int reset_uart401(uart401_devc * devc); static void enter_uart_mode(uart401_devc * devc); -static void -uart401_input_loop(uart401_devc * devc) +static void uart401_input_loop(uart401_devc * devc) { while (input_avail(devc)) - { - unsigned char c = uart401_read(devc); - - if (c == MPU_ACK) - devc->input_byte = c; - else if (devc->opened & OPEN_READ && devc->midi_input_intr) - devc->midi_input_intr(devc->my_dev, c); - } + { + unsigned char c = uart401_read(devc); + + if (c == MPU_ACK) + devc->input_byte = c; + else if (devc->opened & OPEN_READ && devc->midi_input_intr) + devc->midi_input_intr(devc->my_dev, c); + } } -void -uart401intr(int irq, void *dev_id, struct pt_regs *dummy) +void uart401intr(int irq, void *dev_id, struct pt_regs *dummy) { - uart401_devc *devc; + uart401_devc *devc = dev_id; if (irq < 1 || irq > 15) return; - devc = irq2devc[irq]; - if (devc == NULL) return; @@ -108,12 +110,12 @@ uart401_open(int dev, int mode, void (*output) (int dev) ) { - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; if (devc->opened) - { - return -EBUSY; - } + { + return -EBUSY; + } while (input_avail(devc)) uart401_read(devc); @@ -125,21 +127,19 @@ uart401_open(int dev, int mode, return 0; } -static void -uart401_close(int dev) +static void uart401_close(int dev) { - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; reset_uart401(devc); devc->opened = 0; } -static int -uart401_out(int dev, unsigned char midi_byte) +static int uart401_out(int dev, unsigned char midi_byte) { - int timeout; - unsigned long flags; - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + int timeout; + unsigned long flags; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; if (devc->disabled) return 1; @@ -163,36 +163,32 @@ uart401_out(int dev, unsigned char midi_byte) for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); if (!output_ready(devc)) - { - printk("MPU-401: Timeout - Device not responding\n"); + { + printk(KERN_WARNING "uart401: Timeout - Device not responding\n"); devc->disabled = 1; reset_uart401(devc); enter_uart_mode(devc); return 1; - } + } uart401_write(devc, midi_byte); return 1; } -static int -uart401_start_read(int dev) +static int uart401_start_read(int dev) { return 0; } -static int -uart401_end_read(int dev) +static int uart401_end_read(int dev) { return 0; } -static void -uart401_kick(int dev) +static void uart401_kick(int dev) { } -static int -uart401_buffer_status(int dev) +static int uart401_buffer_status(int dev) { return 0; } @@ -203,7 +199,9 @@ uart401_buffer_status(int dev) static struct midi_operations uart401_operations = { - {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, + { + "MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401 + }, &std_midi_synth, {0}, uart401_open, @@ -218,11 +216,10 @@ static struct midi_operations uart401_operations = NULL }; -static void -enter_uart_mode(uart401_devc * devc) +static void enter_uart_mode(uart401_devc * devc) { - int ok, timeout; - unsigned long flags; + int ok, timeout; + unsigned long flags; save_flags(flags); cli(); @@ -242,11 +239,10 @@ enter_uart_mode(uart401_devc * devc) restore_flags(flags); } -void -attach_uart401(struct address_info *hw_config) +void attach_uart401(struct address_info *hw_config) { - uart401_devc *devc; - char *name = "MPU-401 (UART) MIDI"; + uart401_devc *devc; + char *name = "MPU-401 (UART) MIDI"; if (hw_config->name) name = hw_config->name; @@ -255,80 +251,75 @@ attach_uart401(struct address_info *hw_config) return; - devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(uart401_devc))); - sound_mem_sizes[sound_nblocks] = sizeof(uart401_devc); - if (sound_nblocks < 1024) - sound_nblocks++;; + devc = (uart401_devc *) kmalloc(sizeof(uart401_devc), GFP_KERNEL); if (devc == NULL) - { - printk(KERN_WARNING "uart401: Can't allocate memory\n"); - return; - } + { + printk(KERN_WARNING "uart401: Can't allocate memory\n"); + return; + } memcpy((char *) devc, (char *) detected_devc, sizeof(uart401_devc)); detected_devc = NULL; devc->irq = hw_config->irq; if (devc->irq < 0) - { - devc->share_irq = 1; - devc->irq *= -1; - } else + { + devc->share_irq = 1; + devc->irq *= -1; + } + else devc->share_irq = 0; if (devc->irq < 1 || devc->irq > 15) + { + kfree(devc); return; + } if (!devc->share_irq) - if (snd_set_irq_handler(devc->irq, uart401intr, "MPU-401 UART", devc->osp) < 0) - { - printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); - devc->share_irq = 1; - } - irq2devc[devc->irq] = devc; + { + if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) + { + printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); + devc->share_irq = 1; + } + } devc->my_dev = sound_alloc_mididev(); request_region(hw_config->io_base, 4, "MPU-401 UART"); enter_uart_mode(devc); if (devc->my_dev == -1) - { - printk(KERN_INFO "uart401: Too many midi devices detected\n"); - return; - } + { + printk(KERN_INFO "uart401: Too many midi devices detected\n"); + kfree(devc); + return; + } conf_printf(name, hw_config); std_midi_synth.midi_dev = devc->my_dev; - - - midi_devs[devc->my_dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations))); - sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; + midi_devs[devc->my_dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL); if (midi_devs[devc->my_dev] == NULL) - { - printk("uart401: Failed to allocate memory\n"); - sound_unload_mididev(devc->my_dev); - return; - } + { + printk(KERN_ERR "uart401: Failed to allocate memory\n"); + sound_unload_mididev(devc->my_dev); + kfree(devc); + devc=NULL; + return; + } memcpy((char *) midi_devs[devc->my_dev], (char *) &uart401_operations, sizeof(struct midi_operations)); midi_devs[devc->my_dev]->devc = devc; - - - midi_devs[devc->my_dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); - - if (sound_nblocks < 1024) - sound_nblocks++; - + midi_devs[devc->my_dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL); if (midi_devs[devc->my_dev]->converter == NULL) - { - printk(KERN_WARNING "uart401: Failed to allocate memory\n"); - sound_unload_mididev(devc->my_dev); - return; - } + { + printk(KERN_WARNING "uart401: Failed to allocate memory\n"); + sound_unload_mididev(devc->my_dev); + kfree(midi_devs[devc->my_dev]); + kfree(devc); + devc=NULL; + return; + } memcpy((char *) midi_devs[devc->my_dev]->converter, (char *) &std_midi_synth, sizeof(struct synth_operations)); @@ -339,10 +330,9 @@ attach_uart401(struct address_info *hw_config) devc->opened = 0; } -static int -reset_uart401(uart401_devc * devc) +static int reset_uart401(uart401_devc * devc) { - int ok, timeout, n; + int ok, timeout, n; /* * Send the RESET command. Try again if no success at the first time. @@ -351,31 +341,33 @@ reset_uart401(uart401_devc * devc) ok = 0; for (n = 0; n < 2 && !ok; n++) - { - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - - devc->input_byte = 0; - uart401_cmd(devc, MPU_RESET); - - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ - - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (devc->input_byte == MPU_ACK) /* Interrupt */ - ok = 1; - else if (input_avail(devc)) - if (uart401_read(devc) == MPU_ACK) - ok = 1; - - } + { + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); + devc->input_byte = 0; + uart401_cmd(devc, MPU_RESET); + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + + for (timeout = 50000; timeout > 0 && !ok; timeout--) + { + if (devc->input_byte == MPU_ACK) /* Interrupt */ + ok = 1; + else if (input_avail(devc)) + { + if (uart401_read(devc) == MPU_ACK) + ok = 1; + } + } + } if (ok) - { - DEB(printk("Reset UART401 OK\n")); - } else + { + DEB(printk("Reset UART401 OK\n")); + } + else DDB(printk("Reset UART401 failed - No hardware detected.\n")); if (ok) @@ -386,14 +378,12 @@ reset_uart401(uart401_devc * devc) return ok; } -int -probe_uart401(struct address_info *hw_config) +int probe_uart401(struct address_info *hw_config) { - int ok = 0; - unsigned long flags; - + int ok = 0; + unsigned long flags; static uart401_devc hw_info; - uart401_devc *devc = &hw_info; + uart401_devc *devc = &hw_info; DDB(printk("Entered probe_uart401()\n")); @@ -422,21 +412,10 @@ probe_uart401(struct address_info *hw_config) return ok; } -void -unload_uart401(struct address_info *hw_config) +void unload_uart401(struct address_info *hw_config) { - uart401_devc *devc; - - int irq = hw_config->irq; - - if (irq < 0) - { - irq *= -1; - } - if (irq < 1 || irq > 15) - return; - - devc = irq2devc[irq]; + uart401_devc *devc; + devc = midi_devs[hw_config->slots[4]]->devc; if (devc == NULL) return; @@ -444,47 +423,47 @@ unload_uart401(struct address_info *hw_config) release_region(hw_config->io_base, 4); if (!devc->share_irq) - snd_release_irq(devc->irq); - + free_irq(devc->irq, devc); + sound_unload_mididev(hw_config->slots[4]); if (devc) + { + kfree(midi_devs[devc->my_dev]->converter); + kfree(midi_devs[devc->my_dev]); + kfree(devc); devc = NULL; - sound_unload_mididev(hw_config->slots[4]); + } } #ifdef MODULE -int io = -1; -int irq = -1; +int io = -1; +int irq = -1; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); struct address_info hw; -int -init_module(void) +int init_module(void) { /* Can be loaded either for module use or to provide functions to others */ if (io != -1 && irq != -1) - { - printk("MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); - hw.irq = irq; - hw.io_base = io; - if (probe_uart401(&hw) == 0) - return -ENODEV; - attach_uart401(&hw); - } + { + printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); + hw.irq = irq; + hw.io_base = io; + if (probe_uart401(&hw) == 0) + return -ENODEV; + attach_uart401(&hw); + } SOUND_LOCK; return 0; } -void -cleanup_module(void) +void cleanup_module(void) { if (io != -1 && irq != -1) - { - unload_uart401(&hw); - } + unload_uart401(&hw); /* FREE SYMTAB */ SOUND_LOCK_END; } diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c index 932be1846a59..b26e75a89eb9 100644 --- a/drivers/sound/uart6850.c +++ b/drivers/sound/uart6850.c @@ -10,6 +10,11 @@ * Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver. * 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2. * + * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now + * uses native linux resources + * + * Status: Testing required + * */ #include #include @@ -297,7 +302,7 @@ int probe_uart6850(struct address_info *hw_config) uart6850_base = hw_config->io_base; uart6850_irq = hw_config->irq; - if (snd_set_irq_handler(uart6850_irq, m6850intr, "MIDI6850", uart6850_osp) < 0) + if (request_irq(uart6850_irq, m6850intr, 0, "MIDI6850", NULL) < 0) return 0; ok = reset_uart6850(); @@ -307,7 +312,7 @@ int probe_uart6850(struct address_info *hw_config) void unload_uart6850(struct address_info *hw_config) { - snd_release_irq(hw_config->irq); + free_irq(hw_config->irq, NULL); sound_unload_mididev(hw_config->slots[4]); } diff --git a/drivers/sound/v_midi.c b/drivers/sound/v_midi.c index 12c221a681ad..4820d5f36c7e 100644 --- a/drivers/sound/v_midi.c +++ b/drivers/sound/v_midi.c @@ -2,15 +2,22 @@ * sound/v_midi.c * * The low level driver for the Sound Blaster DS chips. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1996 * * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * ?? + * + * Changes + * Alan Cox Modularisation, changed memory allocations + * + * Status + * Untested */ + #include #include diff --git a/fs/buffer.c b/fs/buffer.c index 7e45b223e54e..ec844de9f490 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -731,7 +731,8 @@ static void refill_freelist(int size) /* We are going to try to locate this much memory. */ needed = bdf_prm.b_un.nrefill * size; - while ((nr_free_pages > min_free_pages*2) && + while ((nr_free_pages > freepages.min*2) && + BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) && grow_buffers(GFP_BUFFER, size)) { obtained += PAGE_SIZE; if (obtained >= needed) @@ -815,7 +816,8 @@ repeat: * are _any_ free buffers. */ while (obtained < (needed >> 1) && - nr_free_pages > min_free_pages + 5 && + nr_free_pages > freepages.min + 5 && + BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) && grow_buffers(GFP_BUFFER, size)) obtained += PAGE_SIZE; diff --git a/fs/exec.c b/fs/exec.c index 7d4b2f3b7b77..916e88fa9270 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -418,6 +418,7 @@ static int exec_mmap(void) retval = new_page_tables(current); if (retval) goto fail_restore; + up(&mm->mmap_sem); mmput(old_mm); return 0; diff --git a/fs/hfs/ChangeLog b/fs/hfs/ChangeLog index aa465a0a6801..c063e3f2d65d 100644 --- a/fs/hfs/ChangeLog +++ b/fs/hfs/ChangeLog @@ -1,12 +1,55 @@ -Wed Jan 7 19:33:33 1998 a sun +Wed Jan 21 14:04:26 1998 a sun + + * inode.c, sysdep.c + use d_iput to uncache dentry from catalog entry instead of relying + on put_inode. no more NULL pointer dereferences! + + * catalog.c + cleaned up hfs_cat_put a little. + + ISSUES (non-fatal): mv dir dir2 while creating files in dir screws + up directory counts. + + deletion using netatalk screws up directory + counts. + +Thu Jan 15 19:14:28 1998 a sun + + * catalog.c + make deletion happen when requested instead of waiting until + an hfs_cat_put as the dcache can hold onto entries for quite + some time. + +Wed Jan 14 14:43:16 1998 a sun + + * catalog.c + the current catalog allocation scheme allocates + PAGE_SIZE/sizeof(struct hfs_cat_entry) entries at a time and keeps + a pool of free entries up to this allocation unit * 8. * inode.c - don't hfs_cat_put in hfs_iget. that's a bad idea and results - in screwed up entry counts. + make sure to always hfs_cat_put if hfs_iget is going to return + NULL. + + * string.c, catalog.c + use linux' hashing method to generate hashes. the old hashing was + getting collisions. catalog.c also has a larger hash table to + prevent collisions. + +Tue Jan 13 13:06:01 1998 a sun + + * version.c + bumped to 0.95+asun3 * catalog.c - modified hfs_cat_put to undirty deleted entries without trying to - write them out. + re-wrote to dynamically allocate/delete catalog entries. on a 486, + entries fit into the size-256 slab. + +Wed Jan 7 19:33:33 1998 a sun + + * inode.c + don't hfs_cat_put gratuitously in hfs_iget. that's a bad + idea and results in screwed up entry counts. Tue Jan 6 14:38:24 1998 a sun diff --git a/fs/hfs/Makefile b/fs/hfs/Makefile index bab9a6e4b56c..7ea8e656005f 100644 --- a/fs/hfs/Makefile +++ b/fs/hfs/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the linux nfs-filesystem routines. +# Makefile for the linux hfs-filesystem routines. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 4055012f11c3..2435ceb319c2 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -10,6 +10,7 @@ * * Cache code shamelessly stolen from * linux/fs/inode.c Copyright (C) 1991, 1992 Linus Torvalds + * re-shamelessly stolen Copyright (C) 1997 Linus Torvalds * * In function preconditions the term "valid" applied to a pointer to * a structure means that the pointer is non-NULL and the structure it @@ -24,16 +25,15 @@ /*================ Variable-like macros ================*/ -#define NUM_FREE_ENTRIES 8 - /* Number of hash table slots */ -#define CCACHE_NR 128 - -/* Max number of entries in memory */ -#define CCACHE_MAX 1024 +#define C_HASHBITS 10 +#define C_HASHSIZE (1UL << C_HASHBITS) +#define C_HASHMASK (C_HASHSIZE - 1) -/* Number of entries to fit in a single page on an i386 */ -#define CCACHE_INC ((PAGE_SIZE - sizeof(void *))/sizeof(struct hfs_cat_entry)) +/* Number of entries to fit in a single page on an i386. + * Actually, now it's used to increment the free entry pool. */ +#define CCACHE_INC (PAGE_SIZE/sizeof(struct hfs_cat_entry)) +#define CCACHE_MAX (CCACHE_INC * 8) /*================ File-local data types ================*/ @@ -94,18 +94,11 @@ struct hfs_cat_rec { } u; }; - -struct allocation_unit { - struct allocation_unit *next; - struct hfs_cat_entry entries[CCACHE_INC]; -}; - /*================ File-local variables ================*/ static LIST_HEAD(entry_in_use); -static LIST_HEAD(entry_dirty); /* all the dirty entries */ static LIST_HEAD(entry_unused); -static struct list_head hash_table[CCACHE_NR]; +static struct list_head hash_table[C_HASHSIZE]; spinlock_t entry_lock = SPIN_LOCK_UNLOCKED; @@ -114,8 +107,6 @@ static struct { int nr_free_entries; } entries_stat; -static struct allocation_unit *allocation = NULL; - /*================ File-local functions ================*/ /* @@ -136,13 +127,16 @@ static inline hfs_u32 brec_to_id(struct hfs_brec *brec) * * hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer. */ -static inline unsigned int hashfn(const struct hfs_mdb *mdb, +static inline unsigned long hashfn(const struct hfs_mdb *mdb, const struct hfs_cat_key *key) { #define LSB(X) (((unsigned char *)(&X))[3]) - return ((unsigned int)LSB(mdb->create_date) ^ - (unsigned int)key->ParID[3] ^ - hfs_strhash(&key->CName)) % CCACHE_NR; + unsigned long hash; + + hash = (unsigned long) mdb | (unsigned long) key->ParID[3] | + hfs_strhash(&key->CName); + hash = hash ^ (hash >> C_HASHBITS) ^ (hash >> C_HASHBITS*2); + return hash & C_HASHMASK; #undef LSB } @@ -208,24 +202,7 @@ static void unlock_entry(struct hfs_cat_entry * entry) hfs_wake_up(&entry->wait); } -/* - * clear_entry() - * - * Zero all the fields of an entry and place it on the free list. - */ -static void clear_entry(struct hfs_cat_entry * entry) -{ - wait_on_entry(entry); - /* zero all but the wait queue */ - memset(&entry->wait, 0, - sizeof(*entry) - offsetof(struct hfs_cat_entry, wait)); - INIT_LIST_HEAD(&entry->hash); - INIT_LIST_HEAD(&entry->list); - INIT_LIST_HEAD(&entry->dirty); -} - -/* put entry on mdb dirty list. this only does it if it's on the hash - * list. we also add it to the global dirty list as well. */ +/* put entry on mdb dirty list. */ void hfs_cat_mark_dirty(struct hfs_cat_entry *entry) { struct hfs_mdb *mdb = entry->mdb; @@ -234,153 +211,74 @@ void hfs_cat_mark_dirty(struct hfs_cat_entry *entry) if (!(entry->state & HFS_DIRTY)) { entry->state |= HFS_DIRTY; - /* Only add valid (ie hashed) entries to the - * dirty list */ + /* Only add valid (ie hashed) entries to the dirty list. */ if (!list_empty(&entry->hash)) { list_del(&entry->list); list_add(&entry->list, &mdb->entry_dirty); - INIT_LIST_HEAD(&entry->dirty); - list_add(&entry->dirty, &entry_dirty); } } spin_unlock(&entry_lock); } -/* prune all entries */ -static void dispose_list(struct list_head *head) +/* delete an entry and remove it from the hash table. */ +static void delete_entry(struct hfs_cat_entry *entry) { - struct list_head *next; - int count = 0; - - next = head->next; - for (;;) { - struct list_head * tmp = next; - - next = next->next; - if (tmp == head) - break; - hfs_cat_prune(list_entry(tmp, struct hfs_cat_entry, list)); - count++; - } -} - -/* - * try_to_free_entries works by getting the underlying - * cache system to release entries. it gets called with the entry lock - * held. - * - * count can be up to 2 due to both a resource and data fork being - * listed. we can unuse dirty entries as well. - */ -#define CAN_UNUSE(tmp) (((tmp)->count < 3) && ((tmp)->state <= HFS_DIRTY)) -static int try_to_free_entries(const int goal) -{ - struct list_head *tmp, *head = &entry_in_use; - LIST_HEAD(freeable); - int found = 0, depth = goal << 1; - - /* try freeing from entry_in_use */ - while ((tmp = head->prev) != head && depth--) { - struct hfs_cat_entry *entry = - list_entry(tmp, struct hfs_cat_entry, list); - list_del(tmp); - if (CAN_UNUSE(entry)) { - list_del(&entry->hash); - INIT_LIST_HEAD(&entry->hash); - list_add(tmp, &freeable); - if (++found < goal) - continue; - break; + if (!(entry->state & HFS_DELETED)) { + entry->state |= HFS_DELETED; + list_del(&entry->hash); + INIT_LIST_HEAD(&entry->hash); + + if (entry->type == HFS_CDR_FIL) { + /* free all extents */ + entry->u.file.data_fork.lsize = 0; + hfs_extent_adj(&entry->u.file.data_fork); + entry->u.file.rsrc_fork.lsize = 0; + hfs_extent_adj(&entry->u.file.rsrc_fork); } - list_add(tmp, head); } +} - if (found < goal) { /* try freeing from global dirty list */ - head = &entry_dirty; - depth = goal << 1; - while ((tmp = head->prev) != head && depth--) { - struct hfs_cat_entry *entry = - list_entry(tmp, struct hfs_cat_entry, dirty); - list_del(tmp); - if (CAN_UNUSE(entry)) { - list_del(&entry->hash); - INIT_LIST_HEAD(&entry->hash); - list_del(&entry->list); - INIT_LIST_HEAD(&entry->list); - list_add(&entry->list, &freeable); - if (++found < goal) - continue; - break; - } - list_add(tmp, head); - } - } - - if (found) { - spin_unlock(&entry_lock); - dispose_list(&freeable); - spin_lock(&entry_lock); - } - return found; -} - -/* init_once */ -static inline void init_once(struct hfs_cat_entry *entry) +static inline void init_entry(struct hfs_cat_entry *entry) { - init_waitqueue(&entry->wait); + memset(entry, 0, sizeof(*entry)); + hfs_init_waitqueue(&entry->wait); INIT_LIST_HEAD(&entry->hash); INIT_LIST_HEAD(&entry->list); - INIT_LIST_HEAD(&entry->dirty); } /* - * grow_entries() + * hfs_cat_alloc() * - * Try to allocate more entries, adding them to the free list. this returns - * with the spinlock held if successful + * Try to allocate another entry. */ -static struct hfs_cat_entry *grow_entries(struct hfs_mdb *mdb) +static inline struct hfs_cat_entry *hfs_cat_alloc(void) { - struct allocation_unit *tmp; - struct hfs_cat_entry * entry; - int i; + struct hfs_cat_entry *entry; - spin_unlock(&entry_lock); - if ((entries_stat.nr_entries < CCACHE_MAX) && - HFS_NEW(tmp)) { - spin_lock(&entry_lock); - memset(tmp, 0, sizeof(*tmp)); - tmp->next = allocation; - allocation = tmp; - entry = tmp->entries; - for (i = 1; i < CCACHE_INC; i++) { - entry++; - init_once(entry); - list_add(&entry->list, &entry_unused); - } - init_once(tmp->entries); + if (!HFS_NEW(entry)) + return NULL; - entries_stat.nr_entries += CCACHE_INC; - entries_stat.nr_free_entries += CCACHE_INC - 1; - return tmp->entries; - } + init_entry(entry); + return entry; +} - /* allocation failed. do some pruning and try again */ - spin_lock(&entry_lock); - try_to_free_entries(entries_stat.nr_entries >> 2); - { - struct list_head *tmp = entry_unused.next; - if (tmp != &entry_unused) { - entries_stat.nr_free_entries--; - list_del(tmp); - entry = list_entry(tmp, struct hfs_cat_entry, list); - return entry; - } +/* this gets called with the spinlock held. */ +static int grow_entries(void) +{ + struct hfs_cat_entry *entry; + int i; + + for (i = 0; i < CCACHE_INC; i++) { + if (!(entry = hfs_cat_alloc())) + break; + list_add(&entry->list, &entry_unused); } - spin_unlock(&entry_lock); - return NULL; + entries_stat.nr_entries += i; + entries_stat.nr_free_entries += i; + + return i; } /* @@ -537,7 +435,8 @@ static void __write_entry(const struct hfs_cat_entry *entry, /* * write_entry() * - * Write a modified entry back to the catalog B-tree. + * Write a modified entry back to the catalog B-tree. this gets called + * with the entry locked. */ static void write_entry(struct hfs_cat_entry * entry) { @@ -577,6 +476,7 @@ static void write_entry(struct hfs_cat_entry * entry) } +/* this gets called with the spinlock held. */ static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb, const struct hfs_cat_key *key) { @@ -592,8 +492,9 @@ static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb, entry = list_entry(tmp, struct hfs_cat_entry, hash); if (entry->mdb != mdb) continue; - if (hfs_cat_compare(&entry->key, key)) + if (hfs_cat_compare(&entry->key, key)) { continue; + } entry->count++; break; } @@ -609,13 +510,14 @@ static struct hfs_cat_entry *get_new_entry(struct hfs_mdb *mdb, { struct hfs_cat_entry *entry; struct list_head *head = hash(mdb, key); - struct list_head *tmp = entry_unused.next; + struct list_head *tmp; - if (tmp != &entry_unused) { +add_new_entry: + tmp = entry_unused.next; + if ((tmp != &entry_unused) ) { list_del(tmp); entries_stat.nr_free_entries--; entry = list_entry(tmp, struct hfs_cat_entry, list); -add_new_entry: list_add(&entry->list, &entry_in_use); list_add(&entry->hash, head); entry->mdb = mdb; @@ -629,7 +531,8 @@ add_new_entry: if (hfs_bfind(&brec, mdb->cat_tree, HFS_BKEY(key), HFS_BFIND_READ_EQ)) { - /* uh oh. we failed to read the record */ + /* uh oh. we failed to read the record. + * the entry doesn't actually exist. */ entry->state |= HFS_DELETED; goto read_fail; } @@ -651,28 +554,18 @@ add_new_entry: return entry; } - /* - * Uhhuh.. We need to expand. Note that "grow_entries()" will - * release the spinlock, but will return with the lock held - * again if the allocation succeeded. - */ - entry = grow_entries(mdb); - if (entry) { - /* We released the lock, so.. */ - struct hfs_cat_entry * old = find_entry(mdb, key); - if (!old) - goto add_new_entry; - list_add(&entry->list, &entry_unused); - entries_stat.nr_free_entries++; - spin_unlock(&entry_lock); - wait_on_entry(old); - return old; - } - return entry; + /* try to allocate more entries. grow_entries() doesn't release + * the spinlock. */ + if (grow_entries()) + goto add_new_entry; + spin_unlock(&entry_lock); + return NULL; -read_fail: +read_fail: + /* spinlock unlocked already. we don't need to mark the entry + * dirty here because we know that it doesn't exist. */ remove_hash(entry); entry->state &= ~HFS_LOCK; hfs_wake_up(&entry->wait); @@ -694,11 +587,6 @@ static struct hfs_cat_entry *get_entry(struct hfs_mdb *mdb, struct hfs_cat_entry * entry; spin_lock(&entry_lock); - if (!entries_stat.nr_free_entries && - (entries_stat.nr_entries >= CCACHE_MAX)) - goto restock; - -search: entry = find_entry(mdb, key); if (!entry) { return get_new_entry(mdb, key, read); @@ -706,10 +594,6 @@ search: spin_unlock(&entry_lock); wait_on_entry(entry); return entry; - -restock: - try_to_free_entries(8); - goto search; } /* @@ -753,6 +637,9 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir, /* * Add a writer to dir, excluding readers. + * + * XXX: this is wrong. it allows a move to occur when a directory + * is being written to. */ static inline void start_write(struct hfs_cat_entry *dir) { @@ -880,7 +767,10 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key, goto done; bail1: + /* entry really didn't exist, so we don't need to really delete it. + * we do need to remove it from the hash, though. */ entry->state |= HFS_DELETED; + remove_hash(entry); unlock_entry(entry); bail2: hfs_cat_put(entry); @@ -900,13 +790,21 @@ done: * entry that the entry is in a consistent state, since another * process may get the entry while we sleep. That is why we * 'goto repeat' after each operation that might sleep. + * + * ADDITIONAL NOTE: the sys_entries will remove themselves from + * the sys_entry list on the final iput, so we don't need + * to worry about them here. + * + * nothing in hfs_cat_put goes to sleep now except + * on the initial entry. */ void hfs_cat_put(struct hfs_cat_entry * entry) { if (entry) { wait_on_entry(entry); - if (!entry->count) {/* just in case */ + /* just in case. this should never happen. */ + if (!entry->count) { hfs_warn("hfs_cat_put: trying to free free entry: %p\n", entry); return; @@ -914,52 +812,41 @@ void hfs_cat_put(struct hfs_cat_entry * entry) spin_lock(&entry_lock); if (!--entry->count) { -repeat: - if ((entry->state & HFS_DELETED)) { - if (entry->type == HFS_CDR_FIL) { - /* free all extents */ - entry->u.file.data_fork.lsize = 0; - hfs_extent_adj(&entry->u.file.data_fork); - entry->u.file.rsrc_fork.lsize = 0; - hfs_extent_adj(&entry->u.file.rsrc_fork); - } - entry->state = 0; - } else if (entry->type == HFS_CDR_FIL) { + if ((entry->state & HFS_DELETED)) + goto entry_deleted; + + if ((entry->type == HFS_CDR_FIL)) { /* clear out any cached extents */ if (entry->u.file.data_fork.first.next) { hfs_extent_free(&entry->u.file.data_fork); - spin_unlock(&entry_lock); - wait_on_entry(entry); - spin_lock(&entry_lock); - goto repeat; } if (entry->u.file.rsrc_fork.first.next) { hfs_extent_free(&entry->u.file.rsrc_fork); - spin_unlock(&entry_lock); - wait_on_entry(entry); - spin_lock(&entry_lock); - goto repeat; } } /* if we put a dirty entry, write it out. */ if ((entry->state & HFS_DIRTY)) { - list_del(&entry->dirty); - INIT_LIST_HEAD(&entry->dirty); - spin_unlock(&entry_lock); + entry->state ^= HFS_DIRTY | HFS_LOCK; write_entry(entry); - spin_lock(&entry_lock); - entry->state &= ~HFS_DIRTY; - goto repeat; + entry->state &= ~HFS_LOCK; } list_del(&entry->hash); +entry_deleted: /* deleted entries have already been removed + * from the hash list. */ list_del(&entry->list); - spin_unlock(&entry_lock); - clear_entry(entry); - spin_lock(&entry_lock); - list_add(&entry->list, &entry_unused); - entries_stat.nr_free_entries++; + if (entries_stat.nr_free_entries > CCACHE_MAX) { + HFS_DELETE(entry); + entries_stat.nr_entries--; + } else { + spin_unlock(&entry_lock); + wait_on_entry(entry); + init_entry(entry); + spin_lock(&entry_lock); + list_add(&entry->list, &entry_unused); + entries_stat.nr_free_entries++; + } } spin_unlock(&entry_lock); } @@ -995,20 +882,37 @@ static void invalidate_list(struct list_head *head, struct hfs_mdb *mdb, if (entry->mdb != mdb) { continue; } + if (!entry->count) { list_del(&entry->hash); INIT_LIST_HEAD(&entry->hash); - list_del(&entry->dirty); - INIT_LIST_HEAD(&entry->dirty); list_del(&entry->list); list_add(&entry->list, dispose); continue; } - hfs_warn("hfs_fs: entry %p(%u:%lu) busy on removed device %s.\n", - entry, entry->count, entry->state, + + hfs_warn("hfs_fs: entry %p(%u) busy on removed device %s.\n", + entry, entry->count, hfs_mdb_name(entry->mdb->sys_mdb)); } +} + +/* delete entries from a list */ +static void delete_list(struct list_head *head) +{ + struct list_head *next = head->next; + struct hfs_cat_entry *entry; + + for (;;) { + struct list_head * tmp = next; + next = next->next; + if (tmp == head) { + break; + } + entry = list_entry(tmp, struct hfs_cat_entry, list); + HFS_DELETE(entry); + } } /* @@ -1026,7 +930,7 @@ void hfs_cat_invalidate(struct hfs_mdb *mdb) invalidate_list(&mdb->entry_dirty, mdb, &throw_away); spin_unlock(&entry_lock); - dispose_list(&throw_away); + delete_list(&throw_away); } /* @@ -1052,9 +956,6 @@ void hfs_cat_commit(struct hfs_mdb *mdb) if (!entry->count) insert = entry_in_use.prev; - /* remove from global dirty list */ - list_del(&entry->dirty); - INIT_LIST_HEAD(&entry->dirty); /* add to in_use list */ list_del(&entry->list); @@ -1077,16 +978,13 @@ void hfs_cat_commit(struct hfs_mdb *mdb) * * Releases all the memory allocated in grow_entries(). * Must call hfs_cat_invalidate() on all MDBs before calling this. + * This only gets rid of the unused pool of entries. all the other + * entry references should have either been freed by cat_invalidate + * or moved onto the unused list. */ void hfs_cat_free(void) { - struct allocation_unit *tmp; - - while (allocation) { - tmp = allocation->next; - HFS_DELETE(allocation); - allocation = tmp; - } + delete_list(&entry_unused); } /* @@ -1272,6 +1170,9 @@ struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *entry) * Create a new file with the indicated name in the indicated directory. * The file will have the indicated flags, type and creator. * If successful an (struct hfs_cat_entry) is returned in '*result'. + * + * XXX: the presence of "record" probably means that the following two + * aren't currently SMP safe and need spinlocks. */ int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key, hfs_u8 flags, hfs_u32 type, hfs_u32 creator, @@ -1358,7 +1259,7 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, /* try to delete the file or directory */ if (!error) { - lock_entry(entry); + lock_entry(entry); if ((entry->state & HFS_DELETED)) { /* somebody beat us to it */ error = -ENOENT; @@ -1371,8 +1272,8 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, if (!error) { /* Mark the entry deleted and remove it from the cache */ - entry->state |= HFS_DELETED; - remove_hash(entry); + lock_entry(entry); + delete_entry(entry); /* try to delete the thread entry if it exists */ if (with_thread) { @@ -1380,6 +1281,7 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key)); } + unlock_entry(entry); update_dir(mdb, parent, is_dir, -1); } @@ -1430,10 +1332,12 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir, return -EINVAL; } + spin_lock(&entry_lock); while (mdb->rename_lock) { hfs_sleep_on(&mdb->rename_wait); } mdb->rename_lock = 1; + spin_unlock(&entry_lock); /* keep readers from getting confused by changing dir size */ start_write(new_dir); @@ -1501,7 +1405,7 @@ restart: &new_record, is_dir ? 2 + sizeof(DIR_REC) : 2 + sizeof(FIL_REC)); if (error == -EEXIST) { - dest->state |= HFS_DELETED; + delete_entry(dest); unlock_entry(dest); hfs_cat_put(dest); goto restart; @@ -1590,8 +1494,7 @@ have_distinct: /* Something went seriously wrong. The dir/file has been deleted. */ /* XXX try some recovery? */ - entry->state |= HFS_DELETED; - remove_hash(entry); + delete_entry(entry); goto bail1; } } @@ -1620,7 +1523,7 @@ have_distinct: /* delete any pre-existing or place-holder entry */ if (dest) { - dest->state |= HFS_DELETED; + delete_entry(dest); unlock_entry(dest); if (removed && dest->cnid) { *removed = dest; @@ -1639,7 +1542,7 @@ bail2: (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(new_key)); update_dir(mdb, new_dir, is_dir, -1); bail3: - dest->state |= HFS_DELETED; + delete_entry(dest); } unlock_entry(dest); hfs_cat_put(dest); @@ -1649,8 +1552,10 @@ done: end_write(old_dir); } end_write(new_dir); + spin_lock(&entry_lock); mdb->rename_lock = 0; hfs_wake_up(&mdb->rename_wait); + spin_unlock(&entry_lock); return error; } @@ -1663,7 +1568,7 @@ void hfs_cat_init(void) int i; struct list_head *head = hash_table; - i = CCACHE_NR; + i = C_HASHSIZE; do { INIT_LIST_HEAD(head); head++; diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 144d9d42d7b7..afd794155dc1 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -95,7 +95,7 @@ static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir) } /* - * update_dirs_plus() + * update_dirs_minus() * * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and * 'i_version' of the inodes associated with a directory that has @@ -138,10 +138,9 @@ static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, for (i = 0; i < 4; ++i) { if ((de = entry->sys_entry[i]) && (dentry != de)) { - entry->sys_entry[i] = NULL; - dget(de); - d_delete(de); - dput(de); + dget(de); + d_delete(de); + dput(de); } } } @@ -198,7 +197,7 @@ int hfs_create(struct inode * dir, struct dentry *dentry, int mode) error = -EIO; } else { if (HFS_I(dir)->d_drop_op) - HFS_I(dir)->d_drop_op(HFS_I(dir)->file_type, dentry); + HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type); d_instantiate(dentry, inode); } } @@ -285,7 +284,7 @@ int hfs_unlink(struct inode * dir, struct dentry *dentry) struct hfs_cat_key key; int error; - if (build_key(&key, dir, dentry->d_name.name, + if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) { error = -EPERM; } else if (!(victim = hfs_cat_get(entry->mdb, &key))) { @@ -386,15 +385,15 @@ int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, } else { /* no existing inodes. just drop negative dentries */ if (HFS_I(new_dir)->d_drop_op) - HFS_I(new_dir)->d_drop_op(HFS_I(new_dir)->file_type, - new_dentry); + HFS_I(new_dir)->d_drop_op(new_dentry, + HFS_I(new_dir)->file_type); update_dirs_plus(new_parent, is_dir); } /* update dcache */ d_move(old_dentry, new_dentry); } - + hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ return error; } diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c index d489c86cacb9..a7bb7f633aa3 100644 --- a/fs/hfs/dir_cap.c +++ b/fs/hfs/dir_cap.c @@ -1,5 +1,4 @@ -/* linux/fs/hfs/dir_cap.c - * +/* * Copyright (C) 1995-1997 Paul H. Hargrove * This file may be distributed under the terms of the GNU Public License. * @@ -154,11 +153,12 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry) struct hfs_cat_entry *entry; struct hfs_cat_key key; struct inode *inode = NULL; - + if (!dir || !S_ISDIR(dir->i_mode)) { - goto done; + return -ENOENT; } + dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; dtype = HFS_ITYPE(dir->i_ino); @@ -215,13 +215,13 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry) HFS_I(dir)->file_type, dentry); /* Don't return a resource fork for a directory */ - if (inode && (dtype == HFS_CAP_RDIR) && + if (inode && (dtype == HFS_CAP_RDIR) && (HFS_I(inode)->entry->type == HFS_CDR_DIR)) { + iput(inode); /* this does an hfs_cat_put */ inode = NULL; } done: - dentry->d_op = &hfs_dentry_operations; d_add(dentry, inode); return 0; } @@ -261,7 +261,7 @@ static int cap_readdir(struct file * filp, return -EBADF; } - entry = HFS_I(dir)->entry; + entry = HFS_I(dir)->entry; type = HFS_ITYPE(dir->i_ino); skip_dirs = (type == HFS_CAP_RDIR); @@ -368,7 +368,7 @@ static int cap_readdir(struct file * filp, * related calls (create, rename, and mknod). the directory calls * should be immune. the relevant calls in dir.c call drop_dentry * upon successful completion. */ -void hfs_cap_drop_dentry(const ino_t type, struct dentry *dentry) +void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type) { if (type == HFS_CAP_DATA) { /* given name */ hfs_drop_special(DOT_FINDERINFO, dentry->d_parent, dentry); diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c index c97247dc95d3..553fe8ef95bf 100644 --- a/fs/hfs/dir_dbl.c +++ b/fs/hfs/dir_dbl.c @@ -135,11 +135,12 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry) struct hfs_cat_entry *entry; struct hfs_cat_key key; struct inode *inode = NULL; - + if (!dir || !S_ISDIR(dir->i_mode)) { - goto done; + return -ENOENT; } + dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; /* Perform name-mangling */ @@ -175,12 +176,11 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry) hfs_nameout(dir, &cname, dentry->d_name.name+1, dentry->d_name.len-1); hfs_cat_build_key(entry->cnid, &cname, &key); - inode = hfs_iget(hfs_cat_get(entry->mdb, &key), + inode = hfs_iget(hfs_cat_get(entry->mdb, &key), HFS_DBL_HDR, dentry); } done: - dentry->d_op = &hfs_dentry_operations; d_add(dentry, inode); return 0; } @@ -219,7 +219,7 @@ static int dbl_readdir(struct file * filp, return -EBADF; } - entry = HFS_I(dir)->entry; + entry = HFS_I(dir)->entry; if (filp->f_pos == 0) { /* Entry 0 is for "." */ @@ -414,14 +414,14 @@ static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry, { int error; - if (is_hdr(new_dir, new_dentry->d_name.name, + if (is_hdr(new_dir, new_dentry->d_name.name, new_dentry->d_name.len)) { error = -EPERM; } else { error = hfs_rename(old_dir, old_dentry, new_dir, new_dentry); if ((error == -ENOENT) /*&& !must_be_dir*/ && - is_hdr(old_dir, old_dentry->d_name.name, + is_hdr(old_dir, old_dentry->d_name.name, old_dentry->d_name.len)) { error = -EPERM; } @@ -435,9 +435,8 @@ static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry, * as far as i can tell, the calls that need to do this are the file * related calls (create, rename, and mknod). the directory calls * should be immune. the relevant calls in dir.c call drop_dentry - * upon successful completion. this allocates an array for %name - * on the first attempt to access it. */ -void hfs_dbl_drop_dentry(const ino_t type, struct dentry *dentry) + * upon successful completion. */ +void hfs_dbl_drop_dentry(struct dentry *dentry, const ino_t type) { unsigned char tmp_name[HFS_NAMEMAX + 1]; struct dentry *de = NULL; diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c index 62c9ea2cb07a..b29bfdc17a2b 100644 --- a/fs/hfs/dir_nat.c +++ b/fs/hfs/dir_nat.c @@ -142,9 +142,10 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry) struct inode *inode = NULL; if (!dir || !S_ISDIR(dir->i_mode)) { - goto done; + return -ENOENT; } + dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; dtype = HFS_ITYPE(dir->i_ino); @@ -200,12 +201,11 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry) if (inode && (dtype == HFS_NAT_HDIR) && (HFS_I(inode)->entry != entry) && (HFS_I(inode)->entry->type == HFS_CDR_DIR)) { - iput(inode); + iput(inode); /* this does an hfs_cat_put */ inode = NULL; } done: - dentry->d_op = &hfs_dentry_operations; d_add(dentry, inode); return 0; } @@ -241,7 +241,7 @@ static int nat_readdir(struct file * filp, return -EBADF; } - entry = HFS_I(dir)->entry; + entry = HFS_I(dir)->entry; type = HFS_ITYPE(dir->i_ino); skip_dirs = (type == HFS_NAT_HDIR); @@ -329,7 +329,7 @@ static int nat_readdir(struct file * filp, * related calls (create, rename, and mknod). the directory calls * should be immune. the relevant calls in dir.c call drop_dentry * upon successful completion. */ -void hfs_nat_drop_dentry(const ino_t type, struct dentry *dentry) +void hfs_nat_drop_dentry(struct dentry *dentry, const ino_t type) { struct dentry *de; diff --git a/fs/hfs/file.c b/fs/hfs/file.c index 26f4983055db..e12792036cd6 100644 --- a/fs/hfs/file.c +++ b/fs/hfs/file.c @@ -98,11 +98,10 @@ struct buffer_head *hfs_getblk(struct hfs_fork *fork, int block, int create) to the file until we return, so it can't have moved. */ if (tmp) { - hfs_cat_mark_dirty(fork->entry); - return getblk(dev, tmp, HFS_SECTOR_SIZE); + hfs_cat_mark_dirty(fork->entry); + return getblk(dev, tmp, HFS_SECTOR_SIZE); } return NULL; - } else { /* If reading the block, then retry since the location on disk could have changed while @@ -236,6 +235,7 @@ static hfs_rwret_t hfs_file_write(struct file * filp, const char * buf, */ static void hfs_file_truncate(struct inode * inode) { + /*struct inode *inode = dentry->d_inode;*/ struct hfs_fork *fork = HFS_I(inode)->fork; fork->lsize = inode->i_size; @@ -268,7 +268,7 @@ static inline void xlate_to_user(char *buf, const char *data, int count) */ static inline void xlate_from_user(char *data, const char *buf, int count) { - copy_from_user(data, buf, count); + count -= copy_from_user(data, buf, count); while (count--) { if (*data == '\n') { *data = '\r'; @@ -398,16 +398,16 @@ hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, } else { chars = HFS_SECTOR_SIZE - offset; } - count -= chars; - read += chars; p = (*bhe)->b_data + offset; if (convert) { xlate_to_user(buf, p, chars); } else { - copy_to_user(buf, p, chars); + chars -= copy_to_user(buf, p, chars); } brelse(*bhe); + count -= chars; buf += chars; + read += chars; offset = 0; if (++bhe == &buflist[NBUF]) { bhe = buflist; @@ -479,7 +479,7 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, if (convert) { xlate_from_user(p, buf, c); } else { - copy_from_user(p, buf, c); + c -= copy_from_user(p, buf, c); } update_vm_cache(inode,pos,p,c); pos += c; diff --git a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c index 7c298264a5d3..10f39f751ad2 100644 --- a/fs/hfs/file_cap.c +++ b/fs/hfs/file_cap.c @@ -164,8 +164,7 @@ static hfs_rwret_t cap_info_read(struct file *filp, char *buf, memcount = left; } cap_build_meta(&meta, entry); - /* is copy_to_user guaranteed to write memcount? */ - copy_to_user(buf, ((char *)&meta) + pos, memcount); + memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount); left -= memcount; read += memcount; pos += memcount; @@ -291,6 +290,8 @@ static hfs_rwret_t cap_info_write(struct file *filp, const char *buf, */ static void cap_info_truncate(struct inode *inode) { + /*struct inode *inode = dentry->d_inode;*/ + if (inode->i_size > HFS_FORK_MAX) { inode->i_size = HFS_FORK_MAX; } diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c index 468a3f518d0c..049381dd03e5 100644 --- a/fs/hfs/file_hdr.c +++ b/fs/hfs/file_hdr.c @@ -288,12 +288,10 @@ static inline void adjust_forks(struct hfs_cat_entry *entry, (descr->length != entry->u.file.data_fork.lsize)) { entry->u.file.data_fork.lsize = descr->length; hfs_extent_adj(&entry->u.file.data_fork); - hfs_cat_mark_dirty(entry); } else if ((descr->id == HFS_HDR_RSRC) && (descr->length != entry->u.file.rsrc_fork.lsize)) { entry->u.file.rsrc_fork.lsize = descr->length; hfs_extent_adj(&entry->u.file.rsrc_fork); - hfs_cat_mark_dirty(entry); } } } @@ -414,7 +412,7 @@ static hfs_rwret_t hdr_read(struct file * filp, char * buf, } hdr_build_meta(&meta, layout, entry); - copy_to_user(buf, ((char *)&meta) + pos, left); + left -= copy_to_user(buf, ((char *)&meta) + pos, left); count -= left; read += left; pos += left; @@ -531,7 +529,7 @@ static hfs_rwret_t hdr_read(struct file * filp, char * buf, /* transfer the data */ if (p) { - copy_to_user(buf, p + offset, left); + left -= copy_to_user(buf, p + offset, left); } else if (fork) { left = hfs_do_read(inode, fork, offset, buf, left, filp->f_reada != 0); @@ -654,6 +652,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf, /* Handle possible size changes for the forks */ if (entry->type == HFS_CDR_FIL) { adjust_forks(entry, layout); + hfs_cat_mark_dirty(entry); } } @@ -887,6 +886,8 @@ done: */ static void hdr_truncate(struct inode *inode) { + /*struct inode *inode = dentry->d_inode;*/ + struct hfs_cat_entry *entry = HFS_I(inode)->entry; struct hfs_hdr_layout *layout; size_t size = inode->i_size; int lcv, last; @@ -907,14 +908,14 @@ static void hdr_truncate(struct inode *inode) } if (descr->id == HFS_HDR_RSRC) { - fork = &HFS_I(inode)->entry->u.file.rsrc_fork; + fork = &entry->u.file.rsrc_fork; #if 0 /* Can't yet truncate the data fork via a header file, since there is the * possibility to truncate via the data file, and the only locking is at * the inode level. */ } else if (descr->id == HFS_HDR_DATA) { - fork = &HFS_I(inode)->entry->u.file.data_fork; + fork = &entry->u.file.data_fork; #endif } else { continue; diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index ccc2f0cae525..9112a6db8fb5 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h @@ -11,10 +11,10 @@ #define _HFS_H #include -#include #define HFS_NEW(X) ((X) = hfs_malloc(sizeof(*(X)))) -#define HFS_DELETE(X) { hfs_free((X), sizeof(*(X))); (X) = NULL; } +#define HFS_DELETE(X) do { hfs_free((X), sizeof(*(X))); (X) = NULL; } \ + while (0) /* offsets to various blocks */ #define HFS_DD_BLK 0 /* Driver Descriptor block */ @@ -337,13 +337,12 @@ struct hfs_file { * This structure holds information about a * file or directory in an HFS filesystem. * - * 'wait' must remain 1st and 'next' 2nd since we do some pointer arithmetic. + * 'wait' must remain 1st and 'hash' 2nd since we do some pointer arithmetic. */ struct hfs_cat_entry { hfs_wait_queue wait; struct list_head hash; struct list_head list; - struct list_head dirty; struct hfs_mdb *mdb; hfs_sysentry sys_entry; struct hfs_cat_key key; @@ -366,7 +365,6 @@ struct hfs_cat_entry { #define HFS_KEYDIRTY 2 #define HFS_LOCK 4 #define HFS_DELETED 8 -#define HFS_SUPERBLK 16 /* * struct hfs_bnode_ref @@ -486,14 +484,11 @@ extern void hfs_mdb_put(struct hfs_mdb *, int); extern int hfs_part_find(hfs_sysmdb, int, int, hfs_s32 *, hfs_s32 *); /* string.c */ -extern unsigned int hfs_strhash(const struct hfs_name *); +extern unsigned long hfs_strhash(const struct hfs_name *); extern int hfs_strcmp(const struct hfs_name *, const struct hfs_name *); extern int hfs_streq(const struct hfs_name *, const struct hfs_name *); extern void hfs_tolower(unsigned char *, int); -/* sysdep.c */ -extern void hfs_cat_prune(struct hfs_cat_entry *); - extern __inline__ struct dentry *hfs_lookup_dentry(const char *name, const int len, struct dentry *base) diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index a0bf3d5769f8..340e9be7993e 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -73,17 +73,13 @@ static void init_file_inode(struct inode *inode, hfs_u8 fork) */ void hfs_put_inode(struct inode * inode) { - struct hfs_cat_entry *entry = HFS_I(inode)->entry; - - entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL; - hfs_cat_put(entry); - if (inode->i_count == 1) { - struct hfs_hdr_layout *tmp = HFS_I(inode)->layout; - if (tmp) { - HFS_I(inode)->layout = NULL; - HFS_DELETE(tmp); - } + struct hfs_hdr_layout *tmp = HFS_I(inode)->layout; + + if (tmp) { + HFS_I(inode)->layout = NULL; + HFS_DELETE(tmp); + } } } @@ -153,7 +149,7 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr) /* We must change all in-core inodes corresponding to this file. */ for (i = 0; i < 4; ++i) { if (de[i] && (de[i] != dentry)) { - inode_setattr(de[i]->d_inode, attr); + inode_setattr(de[i]->d_inode, attr); } } @@ -213,7 +209,7 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr) * benefit from a way to pass an additional (void *) through iget() to * the VFS read_inode() function. * - * hfs_iget no longer touches hfs_cat_entries. + * this will hfs_cat_put() the entry if it fails. */ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type, struct dentry *dentry) @@ -239,25 +235,15 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type, sb = entry->mdb->sys_mdb; sys_entry = &entry->sys_entry[HFS_ITYPE_TO_INT(type)]; - if (*sys_entry && (inode = (*sys_entry)->d_inode)) { - /* There is an existing inode for this file/dir. Use it. */ - ++inode->i_count; - return inode; - } - - if (!(inode = iget(sb, ntohl(entry->cnid) | type))) + if (!(inode = iget(sb, ntohl(entry->cnid) | type))) { + hfs_cat_put(entry); return NULL; + } if (inode->i_dev != sb->s_dev) { - iput(inode); + iput(inode); /* automatically does an hfs_cat_put */ inode = NULL; - } else if (inode->i_mode) { - /* The inode has been initialized by another process. - Note that if hfs_put_inode() is sleeping in hfs_cat_put() - then we still need to attach it to the entry. */ - if (!(*sys_entry)) - *sys_entry = dentry; /* cache dentry */ - } else { + } else if (!inode->i_mode) { /* Initialize the inode */ struct hfs_sb_info *hsb = HFS_SB(sb); @@ -281,10 +267,11 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type, if (!inode->i_mode) { clear_inode(inode); + hfs_cat_put(entry); inode = NULL; - } + } else + *sys_entry = dentry; /* cache dentry */ - *sys_entry = dentry; /* cache dentry */ } return inode; diff --git a/fs/hfs/string.c b/fs/hfs/string.c index cacc0a604f42..030850b82d4a 100644 --- a/fs/hfs/string.c +++ b/fs/hfs/string.c @@ -81,11 +81,14 @@ static unsigned char casefold[256] = { /* * Hash a string to an integer in a case-independent way */ -unsigned int hfs_strhash(const struct hfs_name *cname) +unsigned long hfs_strhash(const struct hfs_name *cname) { - /* Currently just sum of the 'order' of first and last characters */ - return ((unsigned int)caseorder[cname->Name[0]] + - (unsigned int)caseorder[cname->Name[cname->Len - 1]]); + unsigned long hash = init_name_hash(); + unsigned int i; + for (i = 0; i < cname->Len; i++) { + hash = partial_name_hash(caseorder[cname->Name[i]], hash); + } + return end_name_hash(hash); } /* diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 897130297918..9e278d383b94 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -163,8 +163,8 @@ static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len) tmp.f_blocks = mdb->alloc_blksz * mdb->fs_ablocks; tmp.f_bfree = mdb->alloc_blksz * mdb->free_ablocks; tmp.f_bavail = tmp.f_bfree; - tmp.f_files = mdb->fs_ablocks; /* According to the statfs manual page, -1 is the */ - tmp.f_ffree = mdb->free_ablocks; /* correct value when the meaning is undefined. */ + tmp.f_files = mdb->fs_ablocks; + tmp.f_ffree = mdb->free_ablocks; tmp.f_namelen = HFS_NAMELEN; return copy_to_user(buf, &tmp, len) ? -EFAULT : 0; @@ -459,16 +459,13 @@ struct super_block *hfs_read_super(struct super_block *s, void *data, if (!root_inode) goto bail_no_root; - /* cache the dentry in the inode */ - s->s_root = - HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] = - d_alloc_root(root_inode, NULL); + s->s_root = d_alloc_root(root_inode, NULL); if (!s->s_root) goto bail_no_root; - /* HFS_SUPERBLK prevents the root inode from being flushed - * inadvertantly. */ - HFS_I(root_inode)->entry->state = HFS_SUPERBLK; + /* fix up pointers. */ + HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] = + s->s_root; s->s_root->d_op = &hfs_dentry_operations; /* everything's okay */ diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c index fc7368a75e5a..659d0b2fc0f5 100644 --- a/fs/hfs/sysdep.c +++ b/fs/hfs/sysdep.c @@ -19,13 +19,16 @@ #include static int hfs_hash_dentry(struct dentry *, struct qstr *); -static int hfs_compare_dentry (struct dentry *, struct qstr *, struct qstr *); +static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); +static void hfs_dentry_iput(struct dentry *, struct inode *); struct dentry_operations hfs_dentry_operations = { NULL, /* d_validate(struct dentry *) */ hfs_hash_dentry, /* d_hash */ hfs_compare_dentry, /* d_compare */ - NULL /* d_delete(struct dentry *) */ + NULL, /* d_delete(struct dentry *) */ + NULL, /* d_release(struct dentry *) */ + hfs_dentry_iput /* d_iput(struct dentry *, struct inode *) */ }; /* @@ -55,19 +58,16 @@ hfs_buffer hfs_buffer_get(hfs_sysmdb sys_mdb, int block, int read) { /* dentry case-handling: just lowercase everything */ -/* should we use hfs_strhash? if so, it probably needs to be beefed - * up a little. */ +/* hfs_strhash now uses the same hashing function as the dcache. */ static int hfs_hash_dentry(struct dentry *dentry, struct qstr *this) { - unsigned char name[HFS_NAMELEN]; - int len = this->len; + struct hfs_name cname; - if (len > HFS_NAMELEN) + if ((cname.Len = this->len) > HFS_NAMELEN) return 0; - - strncpy(name, this->name, len); - hfs_tolower(name, len); - this->hash = full_name_hash(name, len); + + strncpy(cname.Name, this->name, this->len); + this->hash = hfs_strhash(&cname); return 0; } @@ -86,18 +86,11 @@ static int hfs_compare_dentry(struct dentry *dentry, struct qstr *a, return hfs_streq(&s1, &s2); } - -/* toss a catalog entry. this does it by dropping the dentry. */ -void hfs_cat_prune(struct hfs_cat_entry *entry) +static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode) { - int i; + struct hfs_cat_entry *entry = HFS_I(inode)->entry; - for (i = 0; i < 4; i++) { - struct dentry *de = entry->sys_entry[i]; - if (de) { - dget(de); - d_drop(de); - dput(de); - } - } + entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL; + hfs_cat_put(entry); + iput(inode); } diff --git a/fs/hfs/version.c b/fs/hfs/version.c index 8eb74084d4e8..8652c1ccae3e 100644 --- a/fs/hfs/version.c +++ b/fs/hfs/version.c @@ -7,4 +7,4 @@ * This file contains the version string for this release. */ -const char hfs_version[]="0.95+asun2"; +const char hfs_version[]="0.95+asun3"; diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index f5124c226c1e..5889ec88090f 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -1,6 +1,8 @@ #ifndef _I386_PAGE_H #define _I386_PAGE_H +#include + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) diff --git a/include/linux/hfs_fs.h b/include/linux/hfs_fs.h index de51db0b11a1..7eeb34a2c928 100644 --- a/include/linux/hfs_fs.h +++ b/include/linux/hfs_fs.h @@ -237,20 +237,20 @@ extern const struct hfs_name hfs_cap_reserved2[]; extern struct inode_operations hfs_cap_ndir_inode_operations; extern struct inode_operations hfs_cap_fdir_inode_operations; extern struct inode_operations hfs_cap_rdir_inode_operations; -extern void hfs_cap_drop_dentry(const ino_t, struct dentry *); +extern void hfs_cap_drop_dentry(struct dentry *, const ino_t); /* dir_dbl.c */ extern const struct hfs_name hfs_dbl_reserved1[]; extern const struct hfs_name hfs_dbl_reserved2[]; extern struct inode_operations hfs_dbl_dir_inode_operations; -extern void hfs_dbl_drop_dentry(const ino_t, struct dentry *); +extern void hfs_dbl_drop_dentry(struct dentry *, const ino_t); /* dir_nat.c */ extern const struct hfs_name hfs_nat_reserved1[]; extern const struct hfs_name hfs_nat_reserved2[]; extern struct inode_operations hfs_nat_ndir_inode_operations; extern struct inode_operations hfs_nat_hdir_inode_operations; -extern void hfs_nat_drop_dentry(const ino_t, struct dentry *); +extern void hfs_nat_drop_dentry(struct dentry *, const ino_t); /* dir_sngl.c */ extern const struct hfs_name hfs_sngl_reserved1[]; @@ -301,7 +301,6 @@ extern int hfs_mac2seven(char *, const struct hfs_name *); extern int hfs_mac2eight(char *, const struct hfs_name *); extern int hfs_mac2alpha(char *, const struct hfs_name *); extern int hfs_mac2triv(char *, const struct hfs_name *); -extern void hfs_tolower(unsigned char *, int); #define HFS_I(X) (&((X)->u.hfs_i)) #define HFS_SB(X) (&((X)->u.hfs_sb)) diff --git a/include/linux/hfs_fs_i.h b/include/linux/hfs_fs_i.h index cf9ed53e0958..453896882741 100644 --- a/include/linux/hfs_fs_i.h +++ b/include/linux/hfs_fs_i.h @@ -34,7 +34,7 @@ struct hfs_inode_info { struct hfs_hdr_layout *layout; /* for dentry cleanup */ - void (*d_drop_op)(const ino_t, struct dentry *); + void (*d_drop_op)(struct dentry *, const ino_t); }; #endif diff --git a/include/linux/hfs_sysdep.h b/include/linux/hfs_sysdep.h index 93de05aad8ed..22e2ac66b670 100644 --- a/include/linux/hfs_sysdep.h +++ b/include/linux/hfs_sysdep.h @@ -78,6 +78,10 @@ extern inline hfs_u32 hfs_time(void) { */ typedef struct wait_queue *hfs_wait_queue; +extern inline void hfs_init_waitqueue(hfs_wait_queue *queue) { + init_waitqueue(queue); +} + extern inline void hfs_sleep_on(hfs_wait_queue *queue) { sleep_on(queue); } diff --git a/include/linux/swap.h b/include/linux/swap.h index 4d291146e01d..494490c32eac 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -36,10 +36,10 @@ struct swap_info_struct { extern int nr_swap_pages; extern int nr_free_pages; extern atomic_t nr_async_pages; -extern int min_free_pages; -extern int free_pages_low; -extern int free_pages_high; extern struct inode swapper_inode; +extern unsigned long page_cache_size; +extern int buffermem; +#define BUFFER_MEM ((buffermem >> PAGE_SHIFT) + page_cache_size) /* Incomplete types for prototype declarations: */ struct task_struct; diff --git a/include/linux/swapctl.h b/include/linux/swapctl.h index e71dcd067a81..cc169d2dab85 100644 --- a/include/linux/swapctl.h +++ b/include/linux/swapctl.h @@ -6,29 +6,18 @@ /* Swap tuning control */ -/* First, enumerate the different reclaim policies */ -enum RCL_POLICY {RCL_ROUND_ROBIN, RCL_BUFF_FIRST, RCL_PERSIST}; - -typedef struct swap_control_v5 +typedef struct swap_control_v6 { unsigned int sc_max_page_age; unsigned int sc_page_advance; unsigned int sc_page_decline; unsigned int sc_page_initial_age; - unsigned int sc_max_buff_age; - unsigned int sc_buff_advance; - unsigned int sc_buff_decline; - unsigned int sc_buff_initial_age; unsigned int sc_age_cluster_fract; unsigned int sc_age_cluster_min; unsigned int sc_pageout_weight; unsigned int sc_bufferout_weight; - unsigned int sc_buffer_grace; - unsigned int sc_nr_buffs_to_free; - unsigned int sc_nr_pages_to_free; - enum RCL_POLICY sc_policy; -} swap_control_v5; -typedef struct swap_control_v5 swap_control_t; +} swap_control_v6; +typedef struct swap_control_v6 swap_control_t; extern swap_control_t swap_control; typedef struct swapstat_v1 @@ -42,7 +31,23 @@ typedef struct swapstat_v1 typedef swapstat_v1 swapstat_t; extern swapstat_t swapstats; -extern int min_free_pages, free_pages_low, free_pages_high; +typedef struct buffer_mem_v1 +{ + unsigned int min_percent; + unsigned int borrow_percent; + unsigned int max_percent; +} buffer_mem_v1; +typedef buffer_mem_v1 buffer_mem_t; +extern buffer_mem_t buffer_mem; + +typedef struct freepages_v1 +{ + unsigned int min; + unsigned int low; + unsigned int high; +} freepages_v1; +typedef freepages_v1 freepages_t; +extern freepages_t freepages; #define SC_VERSION 1 #define SC_MAX_VERSION 1 @@ -55,17 +60,11 @@ extern int min_free_pages, free_pages_low, free_pages_high; failure to free a resource at any priority */ #define RCL_FAILURE (RCL_MAXPRI + 1) -#define RCL_POLICY (swap_control.sc_policy) #define AGE_CLUSTER_FRACT (swap_control.sc_age_cluster_fract) #define AGE_CLUSTER_MIN (swap_control.sc_age_cluster_min) #define PAGEOUT_WEIGHT (swap_control.sc_pageout_weight) #define BUFFEROUT_WEIGHT (swap_control.sc_bufferout_weight) -#define NR_BUFFS_TO_FREE (swap_control.sc_nr_buffs_to_free) -#define NR_PAGES_TO_FREE (swap_control.sc_nr_pages_to_free) - -#define BUFFERMEM_GRACE (swap_control.sc_buffer_grace) - /* Page aging (see mm/swap.c) */ #define MAX_PAGE_AGE (swap_control.sc_max_page_age) @@ -73,11 +72,6 @@ extern int min_free_pages, free_pages_low, free_pages_high; #define PAGE_DECLINE (swap_control.sc_page_decline) #define PAGE_INITIAL_AGE (swap_control.sc_page_initial_age) -#define MAX_BUFF_AGE (swap_control.sc_max_buff_age) -#define BUFF_ADVANCE (swap_control.sc_buff_advance) -#define BUFF_DECLINE (swap_control.sc_buff_decline) -#define BUFF_INITIAL_AGE (swap_control.sc_buff_initial_age) - /* Given a resource of N units (pages or buffers etc), we only try to * age and reclaim AGE_CLUSTER_FRACT per 1024 resources each time we * scan the resource list. */ diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index dd1ed43e8000..7152aead4a88 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -84,6 +84,7 @@ enum VM_FREEPG, /* struct: Set free page thresholds */ VM_BDFLUSH, /* struct: Control buffer cache flushing */ VM_OVERCOMMIT_MEMORY, /* Turn off the virtual memory safety limit */ + VM_BUFFERMEM /* struct: Set cache memory thresholds */ }; @@ -148,8 +149,6 @@ enum NET_IPV4_FIB_HASH = 19, NET_IPV4_TCP_HOE_RETRANSMITS=32, - NET_IPV4_TCP_SACK, - NET_IPV4_TCP_TSACK, NET_IPV4_TCP_TIMESTAMPS, NET_IPV4_TCP_WINDOW_SCALING, NET_IPV4_TCP_VEGAS_CONG_AVOID, diff --git a/include/net/sock.h b/include/net/sock.h index 8ad6a22cc64c..589f58c7cc92 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -191,9 +191,6 @@ struct raw_opt { struct tcp_opt { - /* TCP bind bucket hash linkage. */ - struct sock *bind_next; - struct sock **bind_pprev; int tcp_header_len; /* Bytes of tcp header to send */ /* @@ -220,7 +217,7 @@ struct tcp_opt __u32 snd_wl2; /* Ack sequence for update */ __u32 snd_wnd; /* The window we expect to receive */ - __u16 max_window; + __u32 max_window; __u8 pending; /* pending events */ __u8 retransmits; __u32 last_ack_sent; /* last ack we sent */ @@ -262,8 +259,7 @@ struct tcp_opt * Options received (usually on last packet, some only on SYN packets). */ char tstamp_ok, /* TIMESTAMP seen on SYN packet */ - wscale_ok, /* Wscale seen on SYN packet */ - sack_ok; /* SACK_PERM seen on SYN packet */ + wscale_ok; /* Wscale seen on SYN packet */ char saw_tstamp; /* Saw TIMESTAMP on last packet */ __u16 in_mss; /* MSS option received from sender */ __u8 snd_wscale; /* Window scaling received from sender */ @@ -272,9 +268,6 @@ struct tcp_opt __u32 rcv_tsecr; /* Time stamp echo reply */ __u32 ts_recent; /* Time stamp to echo next */ __u32 ts_recent_stamp;/* Time we stored ts_recent (for aging) */ - int sacks; /* Number of SACK blocks if any */ - __u32 left_sack[4]; /* Left edges of blocks */ - __u32 right_sack[4]; /* Right edges of blocks */ struct timer_list probe_timer; /* Probes */ __u32 basertt; /* Vegas baseRTT */ @@ -347,6 +340,10 @@ struct sock struct sock *sklist_next; struct sock *sklist_prev; + /* Local port binding hash linkage. */ + struct sock *bind_next; + struct sock **bind_pprev; + /* Main hash linkage for various protocol lookup tables. */ struct sock *next; struct sock **pprev; diff --git a/include/net/tcp.h b/include/net/tcp.h index 2d64f215150b..3b04b7e4f4b3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -131,17 +131,53 @@ static __inline__ void tcp_sk_bindify(struct sock *sk) tb->flags = 0; } else { if((tb->flags & TCPB_FLAG_FASTREUSE) && - ((sk->reuse != 0) || (sk->state == TCP_LISTEN))) + ((sk->reuse == 0) || (sk->state == TCP_LISTEN))) tb->flags &= ~TCPB_FLAG_FASTREUSE; } - if((sk->tp_pinfo.af_tcp.bind_next = tb->owners) != NULL) - tb->owners->tp_pinfo.af_tcp.bind_pprev = - &sk->tp_pinfo.af_tcp.bind_next; + if((sk->bind_next = tb->owners) != NULL) + tb->owners->bind_pprev = &sk->bind_next; tb->owners = sk; - sk->tp_pinfo.af_tcp.bind_pprev = &tb->owners; + sk->bind_pprev = &tb->owners; sk->prev = (struct sock *) tb; } +/* This is a TIME_WAIT bucket. It works around the memory consumption + * problems of sockets in such a state on heavily loaded servers, but + * without violating the protocol specification. + */ +struct tcp_tw_bucket { + /* These _must_ match the beginning of struct sock precisely. + * XXX Yes I know this is gross, but I'd have to edit every single + * XXX networking file if I created a "struct sock_header". -DaveM + */ + struct sock *sklist_next; + struct sock *sklist_prev; + struct sock *bind_next; + struct sock **bind_pprev; + struct sock *next; + struct sock **pprev; + __u32 daddr; + __u32 rcv_saddr; + int bound_dev_if; + unsigned short num; + unsigned char state, + family; /* sk->zapped */ + __u16 source; /* sk->dummy_th.source */ + __u16 dest; /* sk->dummy_th.dest */ + + /* And these are ours. */ + __u32 rcv_nxt; + struct tcp_func *af_specific; + struct tcp_bind_bucket *tb; + struct timer_list timer; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct in6_addr v6_daddr; + struct in6_addr v6_rcv_saddr; +#endif +}; + +extern kmem_cache_t *tcp_timewait_cachep; + /* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6 * because the v6 tcp code to intialize a connection needs to interoperate * with the v4 code using the same variables. @@ -149,7 +185,6 @@ static __inline__ void tcp_sk_bindify(struct sock *sk) * address family independent and just leave one copy in the ipv4 section. * This would also clean up some code duplication. -- erics */ -extern int sysctl_tcp_sack; extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; @@ -244,9 +279,6 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk) #define TCPOPT_NOP 1 /* Padding */ #define TCPOPT_EOL 0 /* End of options */ #define TCPOPT_MSS 2 /* Segment size negotiating */ -/* - * We don't use these yet, but they are for PAWS and big windows - */ #define TCPOPT_WINDOW 3 /* Window scaling */ #define TCPOPT_SACK_PERM 4 /* SACK Permitted */ #define TCPOPT_SACK 5 /* SACK Block */ @@ -261,6 +293,10 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk) #define TCPOLEN_SACK_PERM 2 #define TCPOLEN_TIMESTAMP 10 +/* But this is what stacks really send out. */ +#define TCPOLEN_TSTAMP_ALIGNED 12 +#define TCPOLEN_WSCALE_ALIGNED 4 + /* * TCP option flags for parsed options. */ @@ -310,7 +346,6 @@ struct open_request { __u8 __pad; unsigned snd_wscale : 4, rcv_wscale : 4, - sack_ok : 1, tstamp_ok : 1, wscale_ok : 1; /* The following two fields can be easily recomputed I think -AK */ @@ -406,7 +441,7 @@ extern __inline int after(__u32 seq1, __u32 seq2) /* is s2<=s1<=s3 ? */ extern __inline int between(__u32 seq1, __u32 seq2, __u32 seq3) { - return (after(seq1+1, seq2) && before(seq1, seq3+1)); + return seq3 - seq2 >= seq1 - seq2; } @@ -441,6 +476,11 @@ extern int tcp_rcv_established(struct sock *sk, struct tcphdr *th, __u16 len); +extern int tcp_timewait_state_process(struct tcp_tw_bucket *tw, + struct sk_buff *skb, + struct tcphdr *th, + void *opt, __u16 len); + extern void tcp_close(struct sock *sk, unsigned long timeout); extern struct sock * tcp_accept(struct sock *sk, int flags); @@ -695,37 +735,44 @@ static __inline__ void tcp_set_state(struct sock *sk, int state) default: if (oldstate==TCP_ESTABLISHED) tcp_statistics.TcpCurrEstab--; - if (state == TCP_TIME_WAIT) - sk->prot->rehash(sk); } } static __inline__ void tcp_build_options(__u32 *ptr, struct tcp_opt *tp) { - /* FIXME: We will still need to do SACK here. */ if (tp->tstamp_ok) { - *ptr = ntohl((TCPOPT_NOP << 24) - | (TCPOPT_NOP << 16) - | (TCPOPT_TIMESTAMP << 8) - | TCPOLEN_TIMESTAMP); + *ptr = __constant_htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); /* rest filled in by tcp_update_options */ } } static __inline__ void tcp_update_options(__u32 *ptr, struct tcp_opt *tp) { - /* FIXME: We will still need to do SACK here. */ if (tp->tstamp_ok) { *++ptr = htonl(jiffies); *++ptr = htonl(tp->ts_recent); } } +static __inline__ void tcp_build_and_update_options(__u32 *ptr, struct tcp_opt *tp) +{ + if (tp->tstamp_ok) { + *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); + *ptr++ = htonl(jiffies); + *ptr = htonl(tp->ts_recent); + } +} + /* * This routines builds a generic TCP header. * They also build the RFC1323 Timestamp, but don't fill the * actual timestamp in (you need to call tcp_update_options for this). - * It can't (unfortunately) do SACK as well. * XXX: pass tp instead of sk here. */ @@ -750,9 +797,10 @@ static inline void tcp_build_header_data(struct tcphdr *th, struct sock *sk, int * It would be especially magical to compute the checksum for this * stuff on the fly here. */ -extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sack, int ts, int offer_wscale, int wscale) +extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int ts, int offer_wscale, int wscale) { - int count = 4 + (offer_wscale ? 4 : 0) + ((ts || sack) ? 4 : 0) + (ts ? 8 : 0); + int count = 4 + (offer_wscale ? TCPOLEN_WSCALE_ALIGNED : 0) + + ((ts) ? TCPOLEN_TSTAMP_ALIGNED : 0); unsigned char *optr = skb_put(skb,count); __u32 *ptr = (__u32 *)optr; @@ -761,20 +809,10 @@ extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sa */ *ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss); if (ts) { - if (sack) { - *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) - | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); - *ptr++ = htonl(jiffies); /* TSVAL */ - *ptr++ = htonl(0); /* TSECR */ - } else { - *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) - | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); - *ptr++ = htonl(jiffies); /* TSVAL */ - *ptr++ = htonl(0); /* TSECR */ - } - } else if (sack) { - *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) - | (TCPOPT_NOP << 8) | TCPOPT_NOP); + *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); + *ptr++ = htonl(jiffies); /* TSVAL */ + *ptr++ = __constant_htonl(0); /* TSECR */ } if (offer_wscale) *ptr++ = htonl((TCPOPT_WINDOW << 24) | (TCPOLEN_WINDOW << 16) | (wscale << 8)); @@ -823,33 +861,15 @@ extern __inline__ void tcp_select_initial_window(__u32 space, __u16 mss, (*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp); } -/* #define SYNQ_DEBUG 1 */ - extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, struct open_request *prev) { -#ifdef SYNQ_DEBUG - if (prev->dl_next != req) { - printk(KERN_DEBUG "synq_unlink: bad prev ptr: %p\n",prev); - return; - } -#endif - if(!req->dl_next) { -#ifdef SYNQ_DEBUG - if (tp->syn_wait_last != (void*) req) - printk(KERN_DEBUG "synq_unlink: bad last ptr %p,%p\n", - req,tp->syn_wait_last); -#endif + if(!req->dl_next) tp->syn_wait_last = (struct open_request **)prev; - } prev->dl_next = req->dl_next; } extern __inline__ void tcp_synq_queue(struct tcp_opt *tp, struct open_request *req) { -#ifdef SYNQ_DEBUG - if (*tp->syn_wait_last != NULL) - printk("synq_queue: last ptr doesn't point to last req.\n"); -#endif req->dl_next = NULL; *tp->syn_wait_last = req; tp->syn_wait_last = &req->dl_next; @@ -864,14 +884,11 @@ extern __inline__ void tcp_synq_init(struct tcp_opt *tp) extern __inline__ struct open_request *tcp_synq_unlink_tail(struct tcp_opt *tp) { struct open_request *head = tp->syn_wait_queue; -#ifdef SYNQ_DEBUG - if (!head) { - printk(KERN_DEBUG "tail drop on empty queue? - bug\n"); - return NULL; - } -#endif +#if 0 + /* Should be a net-ratelimit'd thing, not all the time. */ printk(KERN_DEBUG "synq tail drop with expire=%ld\n", head->expires-jiffies); +#endif if (head->dl_next == NULL) tp->syn_wait_last = &tp->syn_wait_queue; tp->syn_wait_queue = head->dl_next; @@ -902,10 +919,9 @@ extern __inline__ void tcp_dec_slow_timer(int timer) static __inline__ void tcp_sk_unbindify(struct sock *sk) { struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *) sk->prev; - if(sk->tp_pinfo.af_tcp.bind_next) - sk->tp_pinfo.af_tcp.bind_next->tp_pinfo.af_tcp.bind_pprev = - sk->tp_pinfo.af_tcp.bind_pprev; - *(sk->tp_pinfo.af_tcp.bind_pprev) = sk->tp_pinfo.af_tcp.bind_next; + if(sk->bind_next) + sk->bind_next->bind_pprev = sk->bind_pprev; + *sk->bind_pprev = sk->bind_next; if(tb->owners == NULL) tcp_inc_slow_timer(TCP_SLT_BUCKETGC); } diff --git a/init/main.c b/init/main.c index c309adfa3161..5bb9e7ff8868 100644 --- a/init/main.c +++ b/init/main.c @@ -78,8 +78,6 @@ extern void dquot_init(void); extern void smp_setup(char *str, int *ints); extern void ioapic_pirq_setup(char *str, int *ints); extern void no_scroll(char *str, int *ints); -extern void swap_setup(char *str, int *ints); -extern void buff_setup(char *str, int *ints); extern void panic_setup(char *str, int *ints); extern void bmouse_setup(char *str, int *ints); extern void msmouse_setup(char *str, int *ints); @@ -490,8 +488,6 @@ static struct kernel_param cooked_params[] __initdata = { #if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI) { "video=", video_setup }, #endif - { "swap=", swap_setup }, - { "buff=", buff_setup }, { "panic=", panic_setup }, { "console=", console_setup }, #ifdef CONFIG_VT diff --git a/ipc/msg.c b/ipc/msg.c index 1f1c4fd3c0d6..806f692dd580 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -3,7 +3,6 @@ * Copyright (C) 1992 Krishna Balasubramanian */ -#include #include #include #include diff --git a/kernel/fork.c b/kernel/fork.c index b4ddebc4cea2..a08aa2c6477e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -262,6 +262,9 @@ fail_nomem: /* * Allocate and initialize an mm_struct. + * + * NOTE! The mm mutex will be locked until the + * caller decides that all systems are go.. */ struct mm_struct * mm_alloc(void) { @@ -274,7 +277,7 @@ struct mm_struct * mm_alloc(void) mm->count = 1; mm->map_count = 0; mm->def_flags = 0; - mm->mmap_sem = MUTEX; + mm->mmap_sem = MUTEX_LOCKED; /* * Leave mm->pgd set to the parent's pgd * so that pgd_offset() is always valid. @@ -327,6 +330,7 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) retval = dup_mmap(mm); if (retval) goto free_pt; + up(&mm->mmap_sem); return 0; free_mm: diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 171a9dc74b37..e6864541f985 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -193,12 +193,14 @@ static ctl_table vm_table[] = { {VM_SWAPOUT, "swapout_interval", &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies}, {VM_FREEPG, "freepages", - &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec}, + &freepages, sizeof(freepages_t), 0600, NULL, &proc_dointvec}, {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &bdflush_min, &bdflush_max}, {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory, sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec}, + {VM_BUFFERMEM, "buffermem", + &buffer_mem, sizeof(buffer_mem_t), 0600, NULL, &proc_dointvec}, {0} }; diff --git a/mm/swap.c b/mm/swap.c index 80817ecf16c5..0ccf96dc84c7 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -5,10 +5,12 @@ */ /* - * This file should contain most things doing the swapping from/to disk. + * This file contains the default values for the opereation of the + * Linux VM subsystem. Finetuning documentation can be found in + * linux/Documentation/sysctl/vm.txt. * Started 18.12.91 - * * Swap aging added 23.2.95, Stephen Tweedie. + * Buffermem limits added 12.3.98, Rik van Riel. */ #include @@ -33,15 +35,18 @@ /* * We identify three levels of free memory. We never let free mem - * fall below the min_free_pages except for atomic allocations. We - * start background swapping if we fall below free_pages_high free - * pages, and we begin intensive swapping below free_pages_low. + * fall below the freepages.min except for atomic allocations. We + * start background swapping if we fall below freepages.high free + * pages, and we begin intensive swapping below freepages.low. * - * Keep these three variables contiguous for sysctl(2). + * These values are there to keep GCC from complaining. Actual + * initialization is done in mm/page_alloc.c or arch/sparc(64)/mm/init.c. */ -int min_free_pages = 48; -int free_pages_low = 72; -int free_pages_high = 96; +freepages_t freepages = { + 48, /* freepages.min */ + 72, /* freepages.low */ + 96 /* freepages.high */ +}; /* We track the number of pages currently being asynchronously swapped out, so that we don't try to swap TOO many pages out at once */ @@ -55,53 +60,15 @@ atomic_t nr_async_pages = ATOMIC_INIT(0); swap_control_t swap_control = { 20, 3, 1, 3, /* Page aging */ - 10, 2, 2, 4, /* Buffer aging */ 32, 4, /* Aging cluster */ 8192, 8192, /* Pageout and bufferout weights */ - -200, /* Buffer grace */ - 1, 1, /* Buffs/pages to free */ - RCL_ROUND_ROBIN /* Balancing policy */ }; swapstat_t swapstats = {0}; -/* General swap control */ - -/* Parse the kernel command line "swap=" option at load time: */ -__initfunc(void swap_setup(char *str, int *ints)) -{ - int * swap_vars[8] = { - &MAX_PAGE_AGE, - &PAGE_ADVANCE, - &PAGE_DECLINE, - &PAGE_INITIAL_AGE, - &AGE_CLUSTER_FRACT, - &AGE_CLUSTER_MIN, - &PAGEOUT_WEIGHT, - &BUFFEROUT_WEIGHT - }; - int i; - for (i=0; i < ints[0] && i < 8; i++) { - if (ints[i+1]) - *(swap_vars[i]) = ints[i+1]; - } -} - -/* Parse the kernel command line "buff=" option at load time: */ -__initfunc(void buff_setup(char *str, int *ints)) -{ - int * buff_vars[6] = { - &MAX_BUFF_AGE, - &BUFF_ADVANCE, - &BUFF_DECLINE, - &BUFF_INITIAL_AGE, - &BUFFEROUT_WEIGHT, - &BUFFERMEM_GRACE - }; - int i; - for (i=0; i < ints[0] && i < 6; i++) { - if (ints[i+1]) - *(buff_vars[i]) = ints[i+1]; - } -} +buffer_mem_t buffer_mem = { + 6, /* minimum percent buffer + cache memory */ + 20, /* borrow percent buffer + cache memory */ + 90 /* maximum percent buffer + cache memory */ +}; diff --git a/mm/vmscan.c b/mm/vmscan.c index bd97e393fbc4..5d4188ae559d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -6,7 +6,7 @@ * Swap reorganised 29.12.95, Stephen Tweedie. * kswapd added: 7.1.96 sct * Removed kswapd_ctl limits, and swap out as many pages as needed - * to bring the system back to free_pages_high: 2.4.97, Rik van Riel. + * to bring the system back to freepages.high: 2.4.97, Rik van Riel. * Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $ */ @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -454,11 +456,14 @@ static inline int do_try_to_free_page(int gfp_mask) stop = 3; if (gfp_mask & __GFP_WAIT) stop = 0; + if (BUFFER_MEM > buffer_mem.borrow_percent * num_physpages / 100) + state = 0; switch (state) { do { case 0: - if (shrink_mmap(i, gfp_mask)) + if (BUFFER_MEM > (buffer_mem.min_percent * num_physpages /100) && + shrink_mmap(i, gfp_mask)) return 1; state = 1; case 1: @@ -550,15 +555,15 @@ int kswapd(void *unused) swapstats.wakeups++; /* Do the background pageout: * When we've got loads of memory, we try - * (free_pages_high - nr_free_pages) times to + * (freepages.high - nr_free_pages) times to * free memory. As memory gets tighter, kswapd * gets more and more agressive. -- Rik. */ - tries = free_pages_high - nr_free_pages; - if (tries < min_free_pages) { - tries = min_free_pages; + tries = freepages.high - nr_free_pages; + if (tries < freepages.min) { + tries = freepages.min; } - else if (nr_free_pages < (free_pages_low + min_free_pages) / 2) + if (nr_free_pages < freepages.high + freepages.low) tries <<= 1; while (tries--) { int gfp_mask; @@ -590,9 +595,10 @@ void swap_tick(void) int want_wakeup = 0, memory_low = 0; int pages = nr_free_pages + atomic_read(&nr_async_pages); - if (pages < free_pages_low) + if (pages < freepages.low) memory_low = want_wakeup = 1; - else if (pages < free_pages_high && jiffies >= next_swap_jiffies) + else if ((pages < freepages.high || BUFFER_MEM > (num_physpages * buffer_mem.max_percent / 100)) + && jiffies >= next_swap_jiffies) want_wakeup = 1; if (want_wakeup) { diff --git a/net/802/sysctl_net_802.c b/net/802/sysctl_net_802.c index 0773d4c8eefe..19cd47af5172 100644 --- a/net/802/sysctl_net_802.c +++ b/net/802/sysctl_net_802.c @@ -24,6 +24,5 @@ ctl_table tr_table[] = { {NET_TR_RIF_TIMEOUT, "rif_timeout", &sysctl_tr_rif_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, {0} - {0} }; #endif diff --git a/net/802/tr.c b/net/802/tr.c index 0e044833556b..5f7dc656d526 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -511,12 +511,14 @@ int rif_get_info(char *buffer,char **start, off_t offset, int length, int dummy) * too much for this. */ +#ifdef CONFIG_PROC_FS static struct proc_dir_entry tr_rif_proc = { PROC_NET_TR_RIF, 6, "tr_rif", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, rif_get_info }; +#endif __initfunc(void rif_init(struct net_proto *unused)) { @@ -529,3 +531,5 @@ __initfunc(void rif_init(struct net_proto *unused)) #ifdef CONFIG_PROC_FS proc_net_register(&tr_rif_proc); #endif +} +} diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index a3e7659c6613..c56adc148b2c 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1404,6 +1404,31 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type return (0); } +#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE) + /* + * Check if IP-over-DDP + */ + if(skb->data[12] == 22) + { + struct device *dev; + + /* This needs to be able to handle ipddp"N" devices */ + if((dev = dev_get("ipddp0")) == NULL) + return (-ENODEV); + + skb->protocol = htons(ETH_P_IP); + skb_pull(skb, 13); + skb->dev = dev; + skb->h.raw = skb->data; + + ((struct net_device_stats *)dev->priv)->rx_packets++; + ((struct net_device_stats *)dev->priv)->rx_bytes += skb->len+13; + netif_rx(skb); /* Send the SKB up to a higher place. */ + + return (0); + } +#endif + /* * Which socket - atalk_search_socket() looks for a *full match* * of the tuple. @@ -1420,38 +1445,6 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type return (0); } -#ifdef CONFIG_IPDDP - /* - * Check if IP-over-DDP - */ - if(skb->data[12] == 22) - { - struct device *dev; - struct net_device_stats *estats; - - if((dev = dev_get("ipddp0")) == NULL) - return (-ENODEV); - - estats = (struct net_device_stats *) dev->priv; - skb->protocol = htons(ETH_P_IP); - skb_pull(skb, 13); - skb->dev = dev; - skb->h.raw = skb->data; - skb->nh.raw = skb->data; - - /* printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]); - * printk("tot_len %d, skb->len %d\n", - * ntohs(skb->h.iph->tot_len),skb->len); - */ - - estats->rx_packets++; - estats->rx_bytes += skb->len + 13; - netif_rx(skb); /* Send the SKB up to a higher place. */ - - return (0); - } -#endif /* CONFIG_IPDDP */ - /* * Queue packet (standard) */ diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 567169980596..107f481d639b 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1237,6 +1237,8 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) newsk = skb->sk; newsk->pair = NULL; + newsk->socket = newsock; + newsk->sleep = &newsock->wait; sti(); /* Now attach up the new socket */ diff --git a/net/core/iovec.c b/net/core/iovec.c index 843eed65724c..9e8873646909 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -86,14 +86,15 @@ out_free: int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) { - int err = -EFAULT; + int err; while(len>0) { if(iov->iov_len) { int copy = min(iov->iov_len, len); - if (copy_to_user(iov->iov_base, kdata, copy)) + err = copy_to_user(iov->iov_base, kdata, copy); + if (err) goto out; kdata+=copy; len-=copy; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 6b8bc48b2b28..0b197fe210db 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -7,7 +7,7 @@ * PROC file system. It is mainly used for debugging and * statistics. * - * Version: $Id: proc.c,v 1.25 1998/03/11 07:12:56 davem Exp $ + * Version: $Id: proc.c,v 1.26 1998/03/13 08:02:12 davem Exp $ * * Authors: Fred N. van Kempen, * Gerald J. Heim, @@ -77,11 +77,12 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format) unsigned long dest, src; unsigned short destp, srcp; int timer_active, timer_active1, timer_active2; + int tw_bucket = 0; unsigned long timer_expires; struct tcp_opt *tp = &sp->tp_pinfo.af_tcp; dest = sp->daddr; - src = sp->saddr; + src = sp->rcv_saddr; destp = sp->dummy_th.dest; srcp = sp->dummy_th.source; @@ -96,30 +97,47 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format) destp = ntohs(destp); srcp = ntohs(srcp); - timer_active1 = del_timer(&tp->retransmit_timer); - timer_active2 = del_timer(&sp->timer); - if (!timer_active1) tp->retransmit_timer.expires=0; - if (!timer_active2) sp->timer.expires=0; - timer_active=0; - timer_expires=jiffies; + if((format == 0) && (sp->state == TCP_TIME_WAIT)) { + struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp; + + tw_bucket = 1; + timer_active1 = timer_active2 = 0; + timer_active = 3; + timer_expires = tw->timer.expires; + } else { + timer_active1 = del_timer(&tp->retransmit_timer); + timer_active2 = del_timer(&sp->timer); + if (!timer_active1) tp->retransmit_timer.expires=0; + if (!timer_active2) sp->timer.expires=0; + timer_active = 0; + timer_expires = (unsigned) -1; + } if (timer_active1 && tp->retransmit_timer.expires < timer_expires) { - timer_active=1; - timer_expires=tp->retransmit_timer.expires; + timer_active = 1; + timer_expires = tp->retransmit_timer.expires; } if (timer_active2 && sp->timer.expires < timer_expires) { - timer_active=2; - timer_expires=sp->timer.expires; + timer_active = 2; + timer_expires = sp->timer.expires; } + if(timer_active == 0) + timer_expires = jiffies; sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", i, src, srcp, dest, destp, sp->state, - format==0?tp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc), - format==0?tp->rcv_nxt-tp->copied_seq:atomic_read(&sp->rmem_alloc), - timer_active, timer_expires-jiffies, - tp->retransmits, - sp->socket ? sp->socket->inode->i_uid:0, - timer_active?sp->timeout:0, - sp->socket ? sp->socket->inode->i_ino:0); + (tw_bucket ? + 0 : + (format == 0) ? + tp->write_seq-tp->snd_una : atomic_read(&sp->wmem_alloc)), + (tw_bucket ? + 0 : + (format == 0) ? + tp->rcv_nxt-tp->copied_seq: atomic_read(&sp->rmem_alloc)), + timer_active, timer_expires-jiffies, + (tw_bucket ? 0 : tp->retransmits), + (!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0, + (!tw_bucket && timer_active) ? sp->timeout : 0, + (!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0); if (timer_active1) add_timer(&tp->retransmit_timer); if (timer_active2) add_timer(&sp->timer); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index d453e55b0590..31c0a71eef7e 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.26 1998/03/08 05:56:35 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.27 1998/03/12 00:03:31 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -45,8 +45,6 @@ extern int sysctl_ip_masq_debug; extern int sysctl_tcp_cong_avoidance; extern int sysctl_tcp_hoe_retransmits; -extern int sysctl_tcp_sack; -extern int sysctl_tcp_tsack; extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; extern int sysctl_tcp_keepalive_time; @@ -99,12 +97,6 @@ ctl_table ipv4_table[] = { {NET_IPV4_TCP_HOE_RETRANSMITS, "tcp_hoe_retransmits", &sysctl_tcp_hoe_retransmits, sizeof(int), 0644, NULL, &proc_dointvec}, - {NET_IPV4_TCP_SACK, "tcp_sack", - &sysctl_tcp_sack, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_IPV4_TCP_TSACK, "tcp_tsack", - &sysctl_tcp_tsack, sizeof(int), 0644, NULL, - &proc_dointvec}, {NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps", &sysctl_tcp_timestamps, sizeof(int), 0644, NULL, &proc_dointvec}, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 2be0e7d287ce..133bda9d9069 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.89 1998/03/11 07:12:51 davem Exp $ + * Version: $Id: tcp.c,v 1.94 1998/03/13 14:15:52 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -426,6 +426,7 @@ struct tcp_mib tcp_statistics; kmem_cache_t *tcp_openreq_cachep; kmem_cache_t *tcp_bucket_cachep; +kmem_cache_t *tcp_timewait_cachep; /* * Find someone to 'accept'. Must be called with @@ -478,20 +479,6 @@ static void tcp_close_pending (struct sock *sk) tcp_synq_init(tp); } -/* - * Enter the time wait state. - */ - -void tcp_time_wait(struct sock *sk) -{ - tcp_set_state(sk,TCP_TIME_WAIT); - sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - sk->state_change(sk); - tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); -} - - /* * Walk down the receive queue counting readable data. * @@ -897,7 +884,6 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags) seglen -= copy; tcp_build_header_data(skb->h.th, sk, seglen || iovlen); - /* FIXME: still need to think about SACK options here. */ if (flags & MSG_OOB) { skb->h.th->urg = 1; @@ -1055,11 +1041,10 @@ static void cleanup_rbuf(struct sock *sk, int copied) SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk)); - /* We send a ACK if we can now advertise a non-zero window + /* We send an ACK if we can now advertise a non-zero window * which has been raised "significantly". */ - if(tcp_timer_is_set(sk, TIME_DACK) || - (copied >= tcp_receive_window(&sk->tp_pinfo.af_tcp))) + if(copied >= tcp_receive_window(&sk->tp_pinfo.af_tcp)) tcp_read_wakeup(sk); } @@ -1334,8 +1319,7 @@ static int tcp_close_state(struct sock *sk, int dead) * reset mistake. */ if(dead && ns==TCP_FIN_WAIT2) { - int timer_active=del_timer(&sk->timer); - if(timer_active) + if(sk->timer.prev && del_timer(&sk->timer)) add_timer(&sk->timer); else tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout); @@ -1418,7 +1402,7 @@ void tcp_close(struct sock *sk, unsigned long timeout) /* Timeout is not the same thing - however the code likes * to send both the same way (sigh). */ - if (tcp_close_state(sk,1)==1) + if (tcp_close_state(sk,1)) tcp_send_fin(sk); if (timeout) { @@ -1447,8 +1431,7 @@ void tcp_close(struct sock *sk, unsigned long timeout) * we may need to set up a timer. */ if (sk->state==TCP_FIN_WAIT2) { - int timer_active=del_timer(&sk->timer); - if(timer_active) + if(sk->timer.prev && del_timer(&sk->timer)) add_timer(&sk->timer); else tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout); @@ -1632,4 +1615,11 @@ __initfunc(void tcp_init(void)) NULL, NULL); if(!tcp_bucket_cachep) panic("tcp_init: Cannot alloc tcp_bind_bucket cache."); + + tcp_timewait_cachep = kmem_cache_create("tcp_tw_bucket", + sizeof(struct tcp_tw_bucket), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if(!tcp_timewait_cachep) + panic("tcp_init: Cannot alloc tcp_tw_bucket cache."); } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 424e7bce7b29..3263d2dac4af 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.76 1998/03/11 07:12:46 davem Exp $ + * Version: $Id: tcp_input.c,v 1.81 1998/03/14 06:09:54 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -67,12 +67,14 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack, extern int sysctl_tcp_fin_timeout; +/* These are on by default so the code paths get tested. + * For the final 2.2 this may be undone at our discretion. -DaveM + */ +int sysctl_tcp_timestamps = 1; +int sysctl_tcp_window_scaling = 1; + int sysctl_tcp_cong_avoidance; int sysctl_tcp_hoe_retransmits; -int sysctl_tcp_sack; -int sysctl_tcp_tsack; -int sysctl_tcp_timestamps; -int sysctl_tcp_window_scaling; int sysctl_tcp_syncookies = SYNC_INIT; int sysctl_tcp_stdurg; @@ -126,9 +128,9 @@ static void tcp_delack_estimator(struct tcp_opt *tp) static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt) { - long m; - /* - * The following amusing code comes from Jacobson's + long m = mrtt; /* RTT */ + + /* The following amusing code comes from Jacobson's * article in SIGCOMM '88. Note that rtt and mdev * are scaled versions of rtt and mean deviation. * This is designed to be as fast as possible @@ -137,12 +139,9 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt) * On a 1990 paper the rto value is changed to: * RTO = rtt + 4 * mdev */ - - m = mrtt; /* RTT */ - + if(m == 0) + m = 1; if (tp->srtt != 0) { - if(m<=0) - m=1; /* IS THIS RIGHT FOR <0 ??? */ m -= (tp->srtt >> 3); /* m is now error in rtt est */ tp->srtt += m; /* rtt = 7/8 rtt + 1/8 new */ if (m < 0) @@ -196,19 +195,17 @@ extern __inline__ void tcp_replace_ts_recent(struct tcp_opt *tp, __u32 end_seq) */ if (!before(end_seq,tp->last_ack_sent)) { tp->ts_recent = tp->rcv_tsval; - /* FIXME: need a corse timestamp. Days uptime - * would be good. - */ tp->ts_recent_stamp = jiffies; } } +#define PAWS_24DAYS (HZ * 60 * 60 * 24 * 24) + extern __inline__ int tcp_paws_discard(struct tcp_opt *tp) { - /* FIXME: must check that ts_recent is not - * more than 24 days old here. Yuck. - */ - return ((s32)(tp->rcv_tsval-tp->ts_recent) < 0); + /* ts_recent must be younger than 24 days */ + return (((jiffies - tp->ts_recent_stamp) >= PAWS_24DAYS) || + ((s32)(tp->rcv_tsval-tp->ts_recent) < 0)); } @@ -251,8 +248,6 @@ static void tcp_reset(struct sock *sk, struct sk_buff *skb) /* We want the right error as BSD sees it (and indeed as we do). */ switch (sk->state) { - case TCP_TIME_WAIT: - break; case TCP_SYN_SENT: sk->err = ECONNREFUSED; break; @@ -262,23 +257,8 @@ static void tcp_reset(struct sock *sk, struct sk_buff *skb) default: sk->err = ECONNRESET; }; -#ifdef CONFIG_TCP_RFC1337 - /* - * Time wait assassination protection [RFC1337] - * - * This is a good idea, but causes more sockets to take time to close. - * - * Ian Heavens has since shown this is an inadequate fix for the protocol - * bug in question. - */ - if(sk->state!=TCP_TIME_WAIT) { - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - } -#else tcp_set_state(sk,TCP_CLOSE); sk->shutdown = SHUTDOWN_MASK; -#endif if (!sk->dead) sk->state_change(sk); } @@ -296,7 +276,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy) int length=(th->doff*4)-sizeof(struct tcphdr); ptr = (unsigned char *)(th + 1); - tp->sacks = 0; tp->saw_tstamp = 0; while(length>0) { @@ -330,10 +309,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy) tp->snd_wscale = *(__u8 *)ptr; } break; - case TCPOPT_SACK_PERM: - if(opsize==TCPOLEN_SACK_PERM && th->syn) - if (sysctl_tcp_sack && !no_fancy) - tp->sack_ok = 1; case TCPOPT_TIMESTAMP: if(opsize==TCPOLEN_TIMESTAMP) { /* Cheaper to set again then to @@ -347,18 +322,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy) } } break; - case TCPOPT_SACK: - if (no_fancy || !sysctl_tcp_sack) - break; - tp->sacks = (opsize-2)>>3; - if (tp->sacks<<3 == opsize-2) { - int i; - for (i = 0; i < tp->sacks; i++) { - tp->left_sack[i] = ntohl(((__u32 *)ptr)[2*i]); - tp->right_sack[i] = ntohl(((__u32 *)ptr)[2*i+1]); - } - } else - tp->sacks = 0; } ptr+=opsize-2; length-=opsize; @@ -368,7 +331,7 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy) /* Fast parse options. This hopes to only see timestamps. * If it is wrong it falls back on tcp_parse_option(). - * This should probably get extended for timestamps + SACK as well. + * This should probably get extended for timestamps as well. * Assembly code anyone? -- erics */ static __inline__ int tcp_fast_parse_options(struct tcphdr *th, struct tcp_opt *tp) @@ -378,14 +341,12 @@ static __inline__ int tcp_fast_parse_options(struct tcphdr *th, struct tcp_opt * return 0; if (th->doff == sizeof(struct tcphdr)>>2) { tp->saw_tstamp = 0; - tp->sacks = 0; return 0; - } else if (th->doff == (sizeof(struct tcphdr)>>2)+3) { + } else if (th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) { __u32 *ptr = (__u32 *)(th + 1); - if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) - | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { + if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) + | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { tp->saw_tstamp = 1; - tp->sacks = 0; tp->rcv_tsval = ntohl(*++ptr); tp->rcv_tsecr = ntohl(*++ptr); return 1; @@ -557,7 +518,6 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack, expected = (tp->snd_nxt - tp->snd_una) * inv_basertt; - /* XXX sk->mss should move into tcp_opt as well -DaveM */ inv_basebd = sk->mss * inv_basertt; /* Slow Start */ @@ -802,7 +762,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, */ if (before(tp->snd_wl1, ack_seq) || (tp->snd_wl1 == ack_seq && !after(tp->snd_wl2, ack))) { - unsigned long nwin = ntohs(th->window) << tp->snd_wscale; + u32 nwin = ntohs(th->window) << tp->snd_wscale; if ((tp->snd_wl2 != ack) || (nwin > tp->snd_wnd)) { flag |= FLAG_WIN_UPDATE; @@ -882,6 +842,193 @@ uninteresting_ack: return 0; } +/* New-style handling of TIME_WAIT sockets. */ +static void tcp_timewait_kill(unsigned long __arg) +{ + struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)__arg; + + /* Zap the timer. */ + del_timer(&tw->timer); + + /* Unlink from various places. */ + if(tw->bind_next) + tw->bind_next->bind_pprev = tw->bind_pprev; + *(tw->bind_pprev) = tw->bind_next; + if(tw->tb->owners == NULL) + tcp_inc_slow_timer(TCP_SLT_BUCKETGC); + + if(tw->next) + tw->next->pprev = tw->pprev; + *tw->pprev = tw->next; + + /* We decremented the prot->inuse count when we entered TIME_WAIT + * and the sock from which this came was destroyed. + */ + tw->sklist_next->sklist_prev = tw->sklist_prev; + tw->sklist_prev->sklist_next = tw->sklist_next; + + /* Ok, now free it up. */ + kmem_cache_free(tcp_timewait_cachep, tw); +} + +/* We come here as a special case from the AF specific TCP input processing, + * and the SKB has no owner. Essentially handling this is very simple, + * we just keep silently eating rx'd packets until none show up for the + * entire timeout period. The only special cases are for BSD TIME_WAIT + * reconnects and SYN/RST bits being set in the TCP header. + */ +int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb, + struct tcphdr *th, void *opt, __u16 len) +{ + /* RFC 1122: + * "When a connection is [...] on TIME-WAIT state [...] + * [a TCP] MAY accept a new SYN from the remote TCP to + * reopen the connection directly, if it: + * + * (1) assigns its initial sequence number for the new + * connection to be larger than the largest sequence + * number it used on the previous connection incarnation, + * and + * + * (2) returns to TIME-WAIT state if the SYN turns out + * to be an old duplicate". + */ + if(th->syn && !th->rst && after(skb->seq, tw->rcv_nxt)) { + struct sock *sk; + struct tcp_func *af_specific = tw->af_specific; + __u32 isn; + + isn = tw->rcv_nxt + 128000; + if(isn == 0) + isn++; + tcp_timewait_kill((unsigned long)tw); + sk = af_specific->get_sock(skb, th); + if(sk == NULL || !ipsec_sk_policy(sk,skb)) + return 0; + skb_set_owner_r(skb, sk); + af_specific = sk->tp_pinfo.af_tcp.af_specific; + if(af_specific->conn_request(sk, skb, opt, isn) < 0) + return 1; /* Toss a reset back. */ + return 0; /* Discard the frame. */ + } + + /* Check RST or SYN */ + if(th->rst || th->syn) { + /* This is TIME_WAIT assasination, in two flavors. + * Oh well... nobody has a sufficient solution to this + * protocol bug yet. + */ + tcp_timewait_kill((unsigned long)tw); + + if(!th->rst) + return 1; /* toss a reset back */ + } else { + if(th->ack) { + /* In this case we must reset the TIMEWAIT timer. */ + del_timer(&tw->timer); + tw->timer.expires = jiffies + TCP_TIMEWAIT_LEN; + add_timer(&tw->timer); + } + } + return 0; /* Discard the frame. */ +} + +/* Enter the time wait state. This is always called from BH + * context. Essentially we whip up a timewait bucket, copy the + * relevant info into it from the SK, and mess with hash chains + * and list linkage. + */ +static __inline__ void tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw) +{ + struct sock **head, *sktw; + + /* Step 1: Remove SK from established hash. */ + if(sk->next) + sk->next->pprev = sk->pprev; + *sk->pprev = sk->next; + sk->pprev = NULL; + tcp_reg_zap(sk); + + /* Step 2: Put TW into bind hash where SK was. */ + tw->tb = (struct tcp_bind_bucket *)sk->prev; + if((tw->bind_next = sk->bind_next) != NULL) + sk->bind_next->bind_pprev = &tw->bind_next; + tw->bind_pprev = sk->bind_pprev; + *sk->bind_pprev = (struct sock *)tw; + + /* Step 3: Same for the protocol sklist. */ + (tw->sklist_next = sk->sklist_next)->sklist_prev = (struct sock *)tw; + (tw->sklist_prev = sk->sklist_prev)->sklist_next = (struct sock *)tw; + sk->sklist_next = NULL; + sk->prot->inuse--; + + /* Step 4: Hash TW into TIMEWAIT half of established hash table. */ + head = &tcp_established_hash[sk->hashent + (TCP_HTABLE_SIZE/2)]; + sktw = (struct sock *)tw; + if((sktw->next = *head) != NULL) + (*head)->pprev = &sktw->next; + *head = sktw; + sktw->pprev = head; +} + +void tcp_time_wait(struct sock *sk) +{ + struct tcp_tw_bucket *tw; + + tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC); + if(tw != NULL) { + /* Give us an identity. */ + tw->daddr = sk->daddr; + tw->rcv_saddr = sk->rcv_saddr; + tw->bound_dev_if= sk->bound_dev_if; + tw->num = sk->num; + tw->state = TCP_TIME_WAIT; + tw->family = sk->family; + tw->source = sk->dummy_th.source; + tw->dest = sk->dummy_th.dest; + tw->rcv_nxt = sk->tp_pinfo.af_tcp.rcv_nxt; + tw->af_specific = sk->tp_pinfo.af_tcp.af_specific; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if(tw->family == AF_INET6) { + memcpy(&tw->v6_daddr, + &sk->net_pinfo.af_inet6.daddr, + sizeof(struct in6_addr)); + memcpy(&tw->v6_rcv_saddr, + &sk->net_pinfo.af_inet6.rcv_saddr, + sizeof(struct in6_addr)); + } +#endif + /* Linkage updates. */ + tcp_tw_hashdance(sk, tw); + + /* Get the TIME_WAIT timeout firing. */ + init_timer(&tw->timer); + tw->timer.function = tcp_timewait_kill; + tw->timer.data = (unsigned long) tw; + tw->timer.expires = jiffies + TCP_TIMEWAIT_LEN; + add_timer(&tw->timer); + + /* CLOSE the SK. */ + if(sk->state == TCP_ESTABLISHED) + tcp_statistics.TcpCurrEstab--; + sk->state = TCP_CLOSE; + net_reset_timer(sk, TIME_DONE, + min(sk->tp_pinfo.af_tcp.srtt * 2, TCP_DONE_TIME)); + } else { + /* Sorry, we're out of memory, just CLOSE this + * socket up. We've got bigger problems than + * non-graceful socket closings. + */ + tcp_set_state(sk, TCP_CLOSE); + } + + /* Prevent rcvmsg/sndmsg calls, and wake people up. */ + sk->shutdown = SHUTDOWN_MASK; + if(!sk->dead) + sk->state_change(sk); +} + /* * Process the FIN bit. This now behaves as it is supposed to work * and the FIN takes effect when it is validly part of sequence @@ -897,13 +1044,8 @@ uninteresting_ack: * If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT. */ -static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) +static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) { - if(sk->state == TCP_SYN_SENT) { - /* RFC793 says to drop the segment and return. */ - return 1; - } - sk->tp_pinfo.af_tcp.fin_seq = skb->end_seq; tcp_send_ack(sk); @@ -931,12 +1073,6 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) case TCP_LAST_ACK: /* RFC793: Remain in the LAST-ACK state. */ break; - case TCP_TIME_WAIT: - /* Received a retransmission of the FIN, - * restart the TIME_WAIT timer. - */ - tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - break; case TCP_FIN_WAIT1: /* This case occurs when a simultaneous close @@ -953,21 +1089,15 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) break; case TCP_FIN_WAIT2: /* Received a FIN -- send ACK and enter TIME_WAIT. */ - tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - sk->shutdown |= SHUTDOWN_MASK; - tcp_set_state(sk,TCP_TIME_WAIT); - break; - case TCP_CLOSE: - /* Already in CLOSE. */ + tcp_time_wait(sk); break; default: - /* Only TCP_LISTEN is left, in that case we should never - * reach this piece of code. + /* Only TCP_LISTEN and TCP_CLOSE are left, in these + * cases we should never reach this piece of code. */ printk("tcp_fin: Impossible, sk->state=%d\n", sk->state); break; }; - return 0; } /* This one checks to see if we can put data from the @@ -994,6 +1124,8 @@ static void tcp_ofo_queue(struct sock *sk) skb_unlink(skb); skb_queue_tail(&sk->receive_queue, skb); tp->rcv_nxt = skb->end_seq; + if(skb->h.th->fin) + tcp_fin(skb, sk, skb->h.th); } } @@ -1012,6 +1144,10 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) dst_confirm(sk->dst_cache); skb_queue_tail(&sk->receive_queue, skb); tp->rcv_nxt = skb->end_seq; + if(skb->h.th->fin) + tcp_fin(skb, sk, skb->h.th); + else + tp->delayed_acks++; tcp_ofo_queue(sk); if (skb_queue_len(&tp->out_of_order_queue) == 0) tp->pred_flags = htonl((0x5010 << 16) | tp->snd_wnd); @@ -1022,7 +1158,6 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) if (!after(skb->end_seq, tp->rcv_nxt)) { /* A retransmit, 2nd most common case. Force an imediate ack. */ SOCK_DEBUG(sk, "retransmit received: seq %X\n", skb->seq); - tp->delayed_acks++; tcp_enter_quickack_mode(tp); kfree_skb(skb); return; @@ -1091,8 +1226,6 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len) if (skb->len == 0 && !th->fin) return(0); - /* FIXME: don't accept data after the received fin. */ - /* We no longer have anyone receiving data on this connection. */ tcp_data_queue(sk, skb); @@ -1101,9 +1234,9 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len) tp->rcv_nxt = tp->copied_seq; } - tp->delayed_acks++; - - /* Now tell the user we may have some data. */ + /* Above, tcp_data_queue() increments delayed_acks appropriately. + * Now tell the user we may have some data. + */ if (!sk->dead) { SOCK_DEBUG(sk, "Data wakeup.\n"); sk->data_ready(sk,0); @@ -1268,6 +1401,12 @@ static void prune_queue(struct sock *sk) /* Now continue with the receive queue if it wasn't enough */ while ((skb = skb_peek_tail(&sk->receive_queue))) { + /* Never toss anything when we've seen the FIN. + * It's just too complex to recover from it. + */ + if(skb->h.th->fin) + break; + /* Never remove packets that have been already acked */ if (before(skb->end_seq, tp->last_ack_sent+1)) { printk(KERN_DEBUG "prune_queue: hit acked data c=%x,%x,%x\n", @@ -1356,9 +1495,11 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, skb_queue_tail(&sk->receive_queue, skb); tp->rcv_nxt = skb->end_seq; + /* FIN bit check is not done since if FIN is set in + * this frame, the pred_flags won't match up. -DaveM + */ sk->data_ready(sk, 0); tcp_delack_estimator(tp); - tp->delayed_acks++; __tcp_ack_snd_check(sk); return 0; @@ -1398,10 +1539,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, /* step 7: process the segment text */ queued = tcp_data(skb, sk, len); - /* step 8: check the FIN bit */ - if (th->fin) - (void) tcp_fin(skb, sk, th); - tcp_data_snd_check(sk); /* If our receive queue has grown past its limits shrink it */ @@ -1569,14 +1706,15 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, tcp_set_state(sk, TCP_ESTABLISHED); tcp_parse_options(th,tp,0); - /* FIXME: need to make room for SACK still */ + if (tp->wscale_ok == 0) { tp->snd_wscale = tp->rcv_wscale = 0; tp->window_clamp = min(tp->window_clamp,65535); } if (tp->tstamp_ok) { - tp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: Define constant! */ - sk->dummy_th.doff += 3; /* reserve space of options */ + tp->tcp_header_len = + sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; + sk->dummy_th.doff += (TCPOLEN_TSTAMP_ALIGNED >> 2); } else tp->tcp_header_len = sizeof(struct tcphdr); if (tp->saw_tstamp) { @@ -1590,8 +1728,12 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (tp->in_mss) sk->mss = min(sk->mss, tp->in_mss); - /* Take out space for tcp options. */ - sk->mss -= tp->tcp_header_len - sizeof(struct tcphdr); + /* Check for the case where we tried to advertise + * a window including timestamp options, but did not + * end up using them for this connection. + */ + if((tp->tstamp_ok == 0) && sysctl_tcp_timestamps) + sk->mss += TCPOLEN_TSTAMP_ALIGNED; sk->dummy_th.dest = th->source; tp->copied_seq = tp->rcv_nxt; @@ -1629,52 +1771,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, } break; - - case TCP_TIME_WAIT: - /* RFC 1122: - * "When a connection is [...] on TIME-WAIT state [...] - * [a TCP] MAY accept a new SYN from the remote TCP to - * reopen the connection directly, if it: - * - * (1) assigns its initial sequence number for the new - * connection to be larger than the largest sequence - * number it used on the previous connection incarnation, - * and - * - * (2) returns to TIME-WAIT state if the SYN turns out - * to be an old duplicate". - */ - if (th->syn && !th->rst && after(skb->seq, tp->rcv_nxt)) { - __u32 isn; - - skb_orphan(skb); - sk->err = ECONNRESET; - tcp_set_state(sk, TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - - isn = tp->rcv_nxt + 128000; - if (isn == 0) - isn++; - - sk = tp->af_specific->get_sock(skb, th); - - if (sk == NULL || !ipsec_sk_policy(sk,skb)) - goto discard; - - skb_set_owner_r(skb, sk); - tp = &sk->tp_pinfo.af_tcp; - - if(tp->af_specific->conn_request(sk, skb, opt, isn) < 0) - return 1; - - goto discard; - } - - break; } /* Parse the tcp_options present on this header. - * By this point we really only expect timestamps and SACKs. + * By this point we really only expect timestamps. * Note that this really has to be here and not later for PAWS * (RFC1323) to work. */ @@ -1781,13 +1881,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, goto discard; } break; - - case TCP_TIME_WAIT: - /* Keep us in TIME_WAIT until we stop getting - * packets, reset the timeout. - */ - tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - break; } } else goto discard; @@ -1825,12 +1918,6 @@ step6: break; } - /* step 8: check the FIN bit */ - if (th->fin) { - if(tcp_fin(skb, sk, th) != 0) - goto discard; - } - tcp_data_snd_check(sk); tcp_ack_snd_check(sk); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3e1542ef2ae6..ced7f998be84 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.101 1998/03/11 07:12:54 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.106 1998/03/13 14:15:54 davem Exp $ * * IPv4 specific functions * @@ -60,8 +60,6 @@ #include -extern int sysctl_tcp_sack; -extern int sysctl_tcp_tsack; extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; extern int sysctl_tcp_syncookies; @@ -155,7 +153,8 @@ struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum) if(tb != NULL) { struct tcp_bind_bucket **head = &tcp_bound_hash[tcp_bhashfn(snum)]; - tb->port = (snum | 0x10000); + tb->port = snum; + tb->flags = TCPB_FLAG_LOCKED; tb->owners = NULL; if((tb->next = *head) != NULL) tb->next->pprev = &tb->next; @@ -188,7 +187,7 @@ static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum) int sk_reuse = sk->reuse; /* We must walk the whole port owner list in this case. -DaveM */ - for(sk2 = tb->owners; sk2; sk2 = sk2->tp_pinfo.af_tcp.bind_next) { + for(sk2 = tb->owners; sk2; sk2 = sk2->bind_next) { if(sk->bound_dev_if == sk2->bound_dev_if) { if(!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) { if(!sk2->rcv_saddr || @@ -246,7 +245,7 @@ static void tcp_v4_hash(struct sock *sk) struct sock **skp; SOCKHASH_LOCK(); - skp = &tcp_established_hash[tcp_sk_hashfn(sk)]; + skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))]; if((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; @@ -286,14 +285,10 @@ static void tcp_v4_rehash(struct sock *sk) if(state != TCP_CLOSE) { struct sock **skp; - if(state == TCP_LISTEN) { + if(state == TCP_LISTEN) skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)]; - } else { - int hash = tcp_sk_hashfn(sk); - if(state == TCP_TIME_WAIT) - hash += (TCP_HTABLE_SIZE/2); - skp = &tcp_established_hash[hash]; - } + else + skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))]; if((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; @@ -349,6 +344,7 @@ static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int d /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM + * It is assumed that this code only gets called from within NET_BH. */ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th, u32 saddr, u16 sport, @@ -375,8 +371,7 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th, goto hit; /* Optimize here for direct hit, only listening connections can - * have wildcards anyways. It is assumed that this code only - * gets called from within NET_BH. + * have wildcards anyways. */ hash = tcp_hashfn(daddr, hnum, saddr, sport); for(sk = tcp_established_hash[hash]; sk; sk = sk->next) { @@ -447,7 +442,7 @@ static struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr, s = tb->owners; } pass2: - for(; s; s = s->tp_pinfo.af_tcp.bind_next) { + for(; s; s = s->bind_next) { int score = 0; if(s->rcv_saddr) { if((s->num != hpnum || s->rcv_saddr != paddr) && @@ -591,7 +586,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) lock_sock(sk); /* Do this early, so there is less state to unwind on failure. */ - buff = sock_wmalloc(sk, MAX_SYN_SIZE, 0, GFP_KERNEL); + buff = sock_wmalloc(sk, (MAX_SYN_SIZE + sizeof(struct sk_buff)), + 0, GFP_KERNEL); if (buff == NULL) { release_sock(sk); ip_rt_put(rt); @@ -637,10 +633,18 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) /* No failure conditions can result past this point. */ + /* We'll fix this up when we get a response from the other end. + * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. + */ + tp->tcp_header_len = sizeof(struct tcphdr) + + (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); + th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr)); buff->h.th = th; memcpy(th,(void *)&(sk->dummy_th), sizeof(*th)); + /* th->doff gets fixed up below if we tack on options. */ + buff->seq = tp->write_seq++; th->seq = htonl(buff->seq); tp->snd_nxt = tp->write_seq; @@ -658,11 +662,9 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if(sk->mtu < 64) sk->mtu = 64; /* Sanity limit */ - if (sk->user_mss) - sk->mss = sk->user_mss; - else - sk->mss = (sk->mtu - sizeof(struct iphdr) - - sizeof(struct tcphdr)); + sk->mss = (sk->mtu - sizeof(struct iphdr) - tp->tcp_header_len); + if(sk->user_mss) + sk->mss = min(sk->mss, sk->user_mss); if (sk->mss < 1) { printk(KERN_DEBUG "intial sk->mss below 1\n"); @@ -677,9 +679,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) &tp->rcv_wscale); th->window = htons(tp->rcv_wnd); - tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack, - sysctl_tcp_timestamps, - sysctl_tcp_window_scaling,tp->rcv_wscale); + tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_timestamps, + sysctl_tcp_window_scaling, tp->rcv_wscale); buff->csum = 0; th->doff = (sizeof(*th)+ tmp)>>2; @@ -861,7 +862,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) th = (struct tcphdr*)(dp+(iph->ihl<<2)); sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex); - if (sk == NULL) { + if (sk == NULL || sk->state == TCP_TIME_WAIT) { icmp_statistics.IcmpInErrors++; return; } @@ -1018,7 +1019,8 @@ static void tcp_v4_send_reset(struct sk_buff *skb) skb1->csum = csum_partial((u8 *) th1, sizeof(*th1), 0); th1->check = tcp_v4_check(th1, sizeof(*th1), skb1->nh.iph->saddr, skb1->nh.iph->daddr, skb1->csum); - /* FIXME: should this carry an options packet? */ + + /* Do not place TCP options in a reset. */ ip_queue_xmit(skb1); tcp_statistics.TcpOutSegs++; tcp_statistics.TcpOutRsts++; @@ -1070,6 +1072,10 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req) mss = (skb->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr)); if (sk->user_mss) mss = min(mss, sk->user_mss); + + /* tcp_syn_build_options will do an skb_put() to obtain the TCP + * options bytes below. + */ skb->h.th = th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr)); /* Don't offer more than they did. @@ -1110,16 +1116,7 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req) req->rcv_wscale = rcv_wscale; } th->window = htons(req->rcv_wnd); - - /* XXX Partial csum of 4 byte quantity is itself! -DaveM - * Yes, but it's a bit harder to special case now. It's - * now computed inside the tcp_v4_send_check() to clean up - * updating the options fields in the mainline send code. - * If someone thinks this is really bad let me know and - * I'll try to do it a different way. -- erics - */ - - tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok, + tmp = tcp_syn_build_options(skb, req->mss, req->tstamp_ok, req->wscale_ok,req->rcv_wscale); skb->csum = 0; th->doff = (sizeof(*th) + tmp)>>2; @@ -1238,14 +1235,13 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */ req->rcv_isn = skb->seq; - tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0; + tp.tstamp_ok = tp.wscale_ok = tp.snd_wscale = 0; tp.in_mss = 536; tcp_parse_options(th,&tp,want_cookie); if (tp.saw_tstamp) req->ts_recent = tp.rcv_tsval; req->mss = tp.in_mss; req->tstamp_ok = tp.tstamp_ok; - req->sack_ok = tp.sack_ok; req->snd_wscale = tp.snd_wscale; req->wscale_ok = tp.wscale_ok; req->rmt_port = th->source; @@ -1374,7 +1370,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newtp->saw_tstamp = 0; newtp->in_mss = 536; - newtp->sacks = 0; init_timer(&newtp->probe_timer); newtp->probe_timer.function = &tcp_probe_timer; @@ -1448,7 +1443,6 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, if (newsk->mtu < 64) newsk->mtu = 64; - newtp->sack_ok = req->sack_ok; newtp->tstamp_ok = req->tstamp_ok; newtp->window_clamp = req->window_clamp; newtp->rcv_wnd = req->rcv_wnd; @@ -1463,8 +1457,8 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, if (newtp->tstamp_ok) { newtp->ts_recent = req->ts_recent; newtp->ts_recent_stamp = jiffies; - newtp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: define constant! */ - newsk->dummy_th.doff += 3; + newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; + newsk->dummy_th.doff += (TCPOLEN_TSTAMP_ALIGNED >> 2); } else { newtp->tcp_header_len = sizeof(struct tcphdr); } @@ -1653,6 +1647,8 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len) skb->used = 0; + if (sk->state == TCP_TIME_WAIT) + goto do_time_wait; if (!sk->sock_readers) return tcp_v4_do_rcv(sk, skb); @@ -1666,6 +1662,12 @@ discard_it: /* Discard frame. */ kfree_skb(skb); return 0; + +do_time_wait: + if(tcp_timewait_state_process((struct tcp_tw_bucket *)sk, + skb, th, &(IPCB(skb)->opt), skb->len)) + goto no_tcp_socket; + goto discard_it; } int tcp_v4_build_header(struct sock *sk, struct sk_buff *skb) @@ -1816,11 +1818,9 @@ static int tcp_v4_init_sock(struct sock *sk) /* FIXME: tie this to sk->rcvbuf? (May be unnecessary) */ /* tp->rcv_wnd = 8192; */ tp->tstamp_ok = 0; - tp->sack_ok = 0; tp->wscale_ok = 0; tp->in_mss = 536; tp->snd_wscale = 0; - tp->sacks = 0; tp->saw_tstamp = 0; tp->syn_backlog = 0; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2bdbb5d2347e..2d278aa73ab0 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.58 1998/03/11 07:12:49 davem Exp $ + * Version: $Id: tcp_output.c,v 1.63 1998/03/13 14:15:55 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -34,8 +34,6 @@ #include -extern int sysctl_tcp_sack; -extern int sysctl_tcp_tsack; extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; @@ -66,32 +64,19 @@ static __inline__ void update_send_head(struct sock *sk) void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue) { - struct tcphdr * th = skb->h.th; + struct tcphdr *th = skb->h.th; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); int size; /* Length of packet (not counting length of pre-tcp headers). */ size = skb->len - ((unsigned char *) th - skb->data); - /* Sanity check it.. */ - if (size < tp->tcp_header_len || size > skb->len) { - printk(KERN_DEBUG "tcp_send_skb: bad skb " - "(skb = %p, data = %p, th = %p, len = %u)\n", - skb, skb->data, th, skb->len); - kfree_skb(skb); - return; - } - - /* If we have queued a header size packet.. (these crash a few - * tcp stacks if ack is not set) - */ - if (size == tp->tcp_header_len) { - /* If it's got a syn or fin discard. */ - if(!th->syn && !th->fin) { - printk(KERN_DEBUG "tcp_send_skb: attempt to queue a bogon.\n"); - kfree_skb(skb); - return; - } + /* If there is a FIN or a SYN we add it onto the size. */ + if (th->fin || th->syn) { + if(th->syn) + size++; + if(th->fin) + size++; } /* Actual processing. */ @@ -107,7 +92,7 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue) tp->last_ack_sent = tp->rcv_nxt; th->ack_seq = htonl(tp->rcv_nxt); th->window = htons(tcp_select_window(sk)); - tcp_update_options((__u32 *)(th+1),tp); + tcp_update_options((__u32 *)(th + 1),tp); tp->af_specific->send_check(sk, th, size, skb); @@ -184,8 +169,6 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len) buff->h.th = nth; memcpy(nth, th, tp->tcp_header_len); - /* FIXME: Make sure this gets tcp options right. */ - /* Correct the new header. */ buff->seq = skb->seq + len; buff->end_seq = skb->end_seq; @@ -310,7 +293,7 @@ void tcp_write_xmit(struct sock *sk) tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt); th->window = rcv_wnd; - tcp_update_options((__u32 *)(th+1),tp); + tcp_update_options((__u32 *)(th + 1),tp); tp->af_specific->send_check(sk, th, size, skb); @@ -607,91 +590,98 @@ void tcp_do_retransmit(struct sock *sk, int all) } } -/* - * Send a fin. +/* Send a fin. The caller locks the socket for us. This cannot be + * allowed to fail queueing a FIN frame under any circumstances. */ - void tcp_send_fin(struct sock *sk) { - struct tcphdr *th =(struct tcphdr *)&sk->dummy_th; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct tcphdr *t1; - struct sk_buff *buff; - int tmp; - buff = sock_wmalloc(sk, BASE_ACK_SIZE + tp->tcp_header_len, 1, GFP_KERNEL); - if (buff == NULL) { - /* FIXME: This is a disaster if it occurs. */ - printk(KERN_INFO "tcp_send_fin: Impossible malloc failure"); - return; - } + /* Optimization, tack on the FIN if we have a queue of + * unsent frames. + */ + if(tp->send_head != NULL) { + struct sk_buff *tail = skb_peek_tail(&sk->write_queue); + struct tcphdr *th = tail->h.th; + int data_len; + + /* Unfortunately tcp_write_xmit won't check for going over + * the MSS due to the FIN sequence number, so we have to + * watch out for it here. + */ + data_len = (tail->tail - (((unsigned char *)th)+tp->tcp_header_len)); + if(data_len >= sk->mss) + goto build_new_frame; /* ho hum... */ - /* Administrivia. */ - buff->csum = 0; + /* tcp_write_xmit() will checksum the header etc. for us. */ + th->fin = 1; + tail->end_seq++; + } else { + struct sk_buff *buff; + struct tcphdr *th; - /* Put in the IP header and routing stuff. */ - tmp = tp->af_specific->build_net_header(sk, buff); - if (tmp < 0) { - int t; +build_new_frame: + buff = sock_wmalloc(sk, + (BASE_ACK_SIZE + tp->tcp_header_len + + sizeof(struct sk_buff)), + 1, GFP_KERNEL); + if (buff == NULL) { + /* We can only fail due to low memory situations, not + * due to going over our sndbuf limits (due to the + * force flag passed to sock_wmalloc). So just keep + * trying. We cannot allow this fail. The socket is + * still locked, so we need not check if the connection + * was reset in the meantime etc. + */ + goto build_new_frame; + } - /* FIXME: We must not throw this out. Eventually we must - * put a FIN into the queue, otherwise it never gets queued. - */ - kfree_skb(buff); - tp->write_seq++; - t = del_timer(&sk->timer); - if (t) - add_timer(&sk->timer); - else - tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - return; - } - - /* We ought to check if the end of the queue is a buffer and - * if so simply add the fin to that buffer, not send it ahead. - */ - t1 =(struct tcphdr *)skb_put(buff,tp->tcp_header_len); - buff->h.th = t1; - tcp_build_options((__u32 *)(t1+1),tp); + /* Administrivia. */ + buff->csum = 0; - memcpy(t1, th, sizeof(*t1)); - buff->seq = tp->write_seq; - tp->write_seq++; - buff->end_seq = tp->write_seq; - t1->seq = htonl(buff->seq); - t1->ack_seq = htonl(tp->rcv_nxt); - t1->window = htons(tcp_select_window(sk)); - t1->fin = 1; - - tp->af_specific->send_check(sk, t1, tp->tcp_header_len, buff); - - /* The fin can only be transmited after the data. */ - skb_queue_tail(&sk->write_queue, buff); - if (tp->send_head == NULL) { - /* FIXME: BUG! we need to check if the fin fits into the window - * here. If not we need to do window probing (sick, but true) + /* Put in the IP header and routing stuff. + * + * FIXME: + * We can fail if the interface for the route + * this socket takes goes down right before + * we get here. ANK is there a way to point + * this into a "black hole" route in such a + * case? Ideally, we should still be able to + * queue this and let the retransmit timer + * keep trying until the destination becomes + * reachable once more. -DaveM */ - struct sk_buff *skb1; - - tp->packets_out++; - tp->snd_nxt = tp->write_seq; - buff->when = jiffies; - - skb1 = skb_clone(buff, GFP_KERNEL); - if (skb1) { - skb_set_owner_w(skb1, sk); - tp->af_specific->queue_xmit(skb1); + if(tp->af_specific->build_net_header(sk, buff) < 0) { + kfree_skb(buff); + goto update_write_seq; } + th = (struct tcphdr *) skb_put(buff, tp->tcp_header_len); + buff->h.th = th; - if (!tcp_timer_is_set(sk, TIME_RETRANS)) - tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto); + memcpy(th, (void *) &(sk->dummy_th), sizeof(*th)); + th->seq = htonl(tp->write_seq); + th->fin = 1; + tcp_build_options((__u32 *)(th + 1), tp); + + /* This makes sure we do things like abide by the congestion + * window and other constraints which prevent us from sending. + */ + tcp_send_skb(sk, buff, 0); } +update_write_seq: + /* So that we recognize the ACK coming back for + * this FIN as being legitimate. + */ + tp->write_seq++; } /* WARNING: This routine must only be called when we have already sent * a SYN packet that crossed the incoming SYN that caused this routine * to get called. If this assumption fails then the initial rcv_wnd * and rcv_wscale values will not be correct. + * + * XXX When you have time Dave, redo this to use tcp_send_skb() just + * XXX like tcp_send_fin() above now does.... -DaveM */ int tcp_send_synack(struct sock *sk) { @@ -701,7 +691,7 @@ int tcp_send_synack(struct sock *sk) struct tcphdr *th; int tmp; - skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC); + skb = sock_wmalloc(sk, MAX_SYN_SIZE + sizeof(struct sk_buff), 1, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -733,8 +723,7 @@ int tcp_send_synack(struct sock *sk) tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt); tmp = tcp_syn_build_options(skb, sk->mss, - tp->sack_ok, tp->tstamp_ok, - tp->wscale_ok,tp->rcv_wscale); + tp->tstamp_ok, tp->wscale_ok, tp->rcv_wscale); skb->csum = 0; th->doff = (sizeof(*th) + tmp)>>2; @@ -774,7 +763,8 @@ void tcp_send_delayed_ack(struct tcp_opt *tp, int max_timeout) timeout += jiffies; /* Use new timeout only if there wasn't a older one earlier. */ - if (!del_timer(&tp->delack_timer) || timeout < tp->delack_timer.expires) + if ((!tp->delack_timer.prev || !del_timer(&tp->delack_timer)) || + (timeout < tp->delack_timer.expires)) tp->delack_timer.expires = timeout; add_timer(&tp->delack_timer); @@ -798,8 +788,6 @@ void tcp_send_ack(struct sock *sk) /* We need to grab some memory, and put together an ack, * and then put it into the queue to be sent. - * FIXME: is it better to waste memory here and use a - * constant sized ACK? */ buff = sock_wmalloc(sk, BASE_ACK_SIZE + tp->tcp_header_len, 1, GFP_ATOMIC); if (buff == NULL) { @@ -826,13 +814,13 @@ void tcp_send_ack(struct sock *sk) th = (struct tcphdr *)skb_put(buff,tp->tcp_header_len); memcpy(th, &sk->dummy_th, sizeof(struct tcphdr)); - tcp_build_options((__u32 *)(th+1),tp); /* Swap the send and the receive. */ th->window = ntohs(tcp_select_window(sk)); th->seq = ntohl(tp->snd_nxt); tp->last_ack_sent = tp->rcv_nxt; th->ack_seq = htonl(tp->rcv_nxt); + tcp_build_and_update_options((__u32 *)(th + 1), tp); /* Fill in the packet and send it. */ tp->af_specific->send_check(sk, th, tp->tcp_header_len, buff); @@ -881,6 +869,7 @@ void tcp_write_wakeup(struct sock *sk) } th = skb->h.th; + tcp_update_options((__u32 *)(th + 1), tp); tp->af_specific->send_check(sk, th, th->doff * 4 + win_size, skb); buff = skb_clone(skb, GFP_ATOMIC); if (buff == NULL) @@ -911,11 +900,8 @@ void tcp_write_wakeup(struct sock *sk) return; } - t1 = (struct tcphdr *) skb_put(buff, sizeof(struct tcphdr)); + t1 = (struct tcphdr *) skb_put(buff, tp->tcp_header_len); memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); - /* FIXME: should zero window probes have SACK and/or TIMESTAMP data? - * If so we have to tack them on here. - */ /* Use a previous sequence. * This should cause the other end to send an ack. @@ -924,11 +910,9 @@ void tcp_write_wakeup(struct sock *sk) t1->seq = htonl(tp->snd_nxt-1); t1->ack_seq = htonl(tp->rcv_nxt); t1->window = htons(tcp_select_window(sk)); + tcp_build_and_update_options((__u32 *)(t1 + 1), tp); - /* Value from dummy_th may be larger. */ - t1->doff = sizeof(struct tcphdr)/4; - - tp->af_specific->send_check(sk, t1, sizeof(*t1), buff); + tp->af_specific->send_check(sk, t1, tp->tcp_header_len, buff); } /* Send it. */ diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index d67e04da7409..330f8e992fe6 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.38 1998/03/10 05:11:17 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.39 1998/03/13 08:02:17 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -89,20 +89,24 @@ void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when) * The delayed ack timer can be set if we are changing the * retransmit timer when removing acked frames. */ - del_timer(&tp->probe_timer); - del_timer(&tp->retransmit_timer); + if(tp->probe_timer.prev) + del_timer(&tp->probe_timer); + if(tp->retransmit_timer.prev) + del_timer(&tp->retransmit_timer); tp->retransmit_timer.expires=jiffies+when; add_timer(&tp->retransmit_timer); break; case TIME_DACK: - del_timer(&tp->delack_timer); + if(tp->delack_timer.prev) + del_timer(&tp->delack_timer); tp->delack_timer.expires=jiffies+when; add_timer(&tp->delack_timer); break; case TIME_PROBE0: - del_timer(&tp->probe_timer); + if(tp->probe_timer.prev) + del_timer(&tp->probe_timer); tp->probe_timer.expires=jiffies+when; add_timer(&tp->probe_timer); break; @@ -137,8 +141,7 @@ static int tcp_write_err(struct sock *sk, int force) /* Time wait the socket. */ if (!force && ((1<state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING))) { - tcp_set_state(sk,TCP_TIME_WAIT); - tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + tcp_time_wait(sk); } else { /* Clean up time. */ tcp_set_state(sk, TCP_CLOSE); @@ -216,10 +219,9 @@ void tcp_probe_timer(unsigned long data) sk->err = ETIMEDOUT; sk->error_report(sk); - /* Time wait the socket. */ if ((1<state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) { - tcp_set_state(sk, TCP_TIME_WAIT); - tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + /* Time wait the socket. */ + tcp_time_wait(sk); } else { /* Clean up time. */ tcp_set_state(sk, TCP_CLOSE); diff --git a/net/ipv4/timer.c b/net/ipv4/timer.c index a719f59a41ee..6e97b5b3a841 100644 --- a/net/ipv4/timer.c +++ b/net/ipv4/timer.c @@ -5,7 +5,7 @@ * * TIMER - implementation of software timers for IP. * - * Version: $Id: timer.c,v 1.9 1998/03/11 07:12:44 davem Exp $ + * Version: $Id: timer.c,v 1.10 1998/03/13 08:02:18 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -52,38 +52,23 @@ void net_delete_timer (struct sock *t) { - unsigned long flags; - - save_flags (flags); - cli(); - - t->timeout = 0; if(t->timer.prev) del_timer (&t->timer); - - restore_flags (flags); + t->timeout = 0; } void net_reset_timer (struct sock *t, int timeout, unsigned long len) { net_delete_timer (t); t->timeout = timeout; -#if 1 - /* FIXME: ??? */ - if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */ - len = 3; /* happen (negative values ?) - don't ask me why ! -FB */ -#endif t->timer.expires = jiffies+len; add_timer (&t->timer); } - -/* - * Now we will only be called whenever we need to do - * something, but we must be sure to process all of the - * sockets that need it. +/* Now we will only be called whenever we need to do + * something, but we must be sure to process all of the + * sockets that need it. */ - void net_timer (unsigned long data) { struct sock *sk = (struct sock*)data; @@ -97,7 +82,7 @@ void net_timer (unsigned long data) } /* Always see if we need to send an ack. */ - if (sk->ack_backlog && !sk->zapped) { + if (sk->tp_pinfo.af_tcp.delayed_acks && !sk->zapped) { sk->prot->read_wakeup (sk); if (!sk->dead) sk->data_ready(sk,0); @@ -106,14 +91,13 @@ void net_timer (unsigned long data) /* Now we need to figure out why the socket was on the timer. */ switch (why) { case TIME_DONE: - /* If the socket hasn't been closed off, re-try a bit later */ + /* If the socket hasn't been closed off, re-try a bit later. */ if (!sk->dead) { net_reset_timer(sk, TIME_DONE, TCP_DONE_TIME); break; } - if (sk->state != TCP_CLOSE) - { + if (sk->state != TCP_CLOSE) { printk (KERN_DEBUG "non CLOSE socket in time_done\n"); break; } @@ -121,11 +105,9 @@ void net_timer (unsigned long data) break; case TIME_DESTROY: - /* - * We've waited for a while for all the memory associated with - * the socket to be freed. - */ - + /* We've waited for a while for all the memory associated with + * the socket to be freed. + */ destroy_sock(sk); break; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 39a98c5ec747..1b3893a7ab43 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.51 1998/03/08 05:56:40 davem Exp $ + * Version: $Id: udp.c,v 1.53 1998/03/12 03:20:00 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -828,7 +828,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) * of this packet since that is all * that will be read. */ - amount = skb->tail - skb->h.raw; + amount = skb->len - sizeof(struct udphdr); } return put_user(amount, (int *)arg); } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index b03b6ea2332c..b87d4696b575 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -7,7 +7,7 @@ * PROC file system. This is very similar to the IPv4 version, * except it reports the sockets in the INET6 address family. * - * Version: $Id: proc.c,v 1.5 1998/03/06 01:23:22 davem Exp $ + * Version: $Id: proc.c,v 1.6 1998/03/13 08:02:19 davem Exp $ * * Authors: David S. Miller (davem@caip.rutgers.edu) * @@ -21,6 +21,7 @@ #include #include #include +#include #include /* This is the main implementation workhorse of all these routines. */ @@ -52,21 +53,35 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta SOCKHASH_LOCK(); sp = pro->sklist_next; while(sp != (struct sock *)pro) { + struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp; + int tw_bucket = 0; + pos += 149; if(pos < offset) goto next; tp = &(sp->tp_pinfo.af_tcp); - dest = &sp->net_pinfo.af_inet6.daddr; - src = &sp->net_pinfo.af_inet6.rcv_saddr; + if((format == 0) && (sp->state == TCP_TIME_WAIT)) { + tw_bucket = 1; + dest = &tw->v6_daddr; + src = &tw->v6_rcv_saddr; + } else { + dest = &sp->net_pinfo.af_inet6.daddr; + src = &sp->net_pinfo.af_inet6.rcv_saddr; + } destp = ntohs(sp->dummy_th.dest); srcp = ntohs(sp->dummy_th.source); - - timer_active1 = del_timer(&tp->retransmit_timer); - timer_active2 = del_timer(&sp->timer); - if(!timer_active1) tp->retransmit_timer.expires = 0; - if(!timer_active2) sp->timer.expires = 0; - timer_active = 0; - timer_expires = (unsigned) -1; + if((format == 0) && (sp->state == TCP_TIME_WAIT)) { + timer_active1 = timer_active2 = 0; + timer_active = 3; + timer_expires = tw->timer.expires; + } else { + timer_active1 = del_timer(&tp->retransmit_timer); + timer_active2 = del_timer(&sp->timer); + if(!timer_active1) tp->retransmit_timer.expires = 0; + if(!timer_active2) sp->timer.expires = 0; + timer_active = 0; + timer_expires = (unsigned) -1; + } if(timer_active1 && tp->retransmit_timer.expires < timer_expires) { timer_active = timer_active1; timer_expires = tp->retransmit_timer.expires; @@ -75,6 +90,8 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta timer_active = timer_active2; timer_expires = sp->timer.expires; } + if(timer_active == 0) + timer_expires = jiffies; sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", i, @@ -83,13 +100,23 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, sp->state, - format==0?tp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc), - format==0?tp->rcv_nxt-tp->copied_seq:atomic_read(&sp->rmem_alloc), + (tw_bucket ? + 0 : + (format == 0) ? + tp->write_seq-tp->snd_una : + atomic_read(&sp->wmem_alloc)), + (tw_bucket ? + 0 : + (format == 0) ? + tp->rcv_nxt-tp->copied_seq : + atomic_read(&sp->rmem_alloc)), timer_active, timer_expires-jiffies, - tp->retransmits, - sp->socket ? sp->socket->inode->i_uid:0, - timer_active?sp->timeout:0, - sp->socket ? sp->socket->inode->i_ino:0); + (tw_bucket ? 0 : tp->retransmits), + ((!tw_bucket && sp->socket) ? + sp->socket->inode->i_uid : 0), + (!tw_bucket && timer_active) ? sp->timeout : 0, + ((!tw_bucket && sp->socket) ? + sp->socket->inode->i_ino : 0)); if(timer_active1) add_timer(&tp->retransmit_timer); if(timer_active2) add_timer(&sp->timer); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a9950b0ebe04..bfaaa93bfd14 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.56 1998/03/11 02:20:52 davem Exp $ + * $Id: tcp_ipv6.c,v 1.59 1998/03/13 08:02:20 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -44,7 +44,6 @@ #define ICMP_PARANOIA -extern int sysctl_tcp_sack; extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; @@ -113,7 +112,7 @@ static int tcp_v6_verify_bind(struct sock *sk, unsigned short snum) int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr); /* We must walk the whole port owner list in this case. -DaveM */ - for(sk2 = tb->owners; sk2; sk2 = sk2->tp_pinfo.af_tcp.bind_next) { + for(sk2 = tb->owners; sk2; sk2 = sk2->bind_next) { if(!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) { if(addr_type == IPV6_ADDR_ANY || !sk2->rcv_saddr || @@ -141,7 +140,7 @@ static void tcp_v6_hash(struct sock *sk) struct sock **skp; SOCKHASH_LOCK(); - skp = &tcp_established_hash[tcp_v6_sk_hashfn(sk)]; + skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))]; if((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; @@ -181,14 +180,10 @@ static void tcp_v6_rehash(struct sock *sk) if(state != TCP_CLOSE) { struct sock **skp; - if(state == TCP_LISTEN) { + if(state == TCP_LISTEN) skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)]; - } else { - int hash = tcp_v6_sk_hashfn(sk); - if(state == TCP_TIME_WAIT) - hash += (TCP_HTABLE_SIZE/2); - skp = &tcp_established_hash[hash]; - } + else + skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))]; if((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; @@ -224,6 +219,7 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM + * It is assumed that this code only gets called from within NET_BH. */ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th, struct in6_addr *saddr, u16 sport, @@ -250,8 +246,7 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th, goto hit; /* Optimize here for direct hit, only listening connections can - * have wildcards anyways. It is assumed that this code only - * gets called from within NET_BH. + * have wildcards anyways. */ hash = tcp_v6_hashfn(daddr, hnum, saddr, sport); for(sk = tcp_established_hash[hash]; sk; sk = sk->next) { @@ -270,10 +265,12 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th, for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next) if(sk->num == hnum && /* local port */ sk->family == AF_INET6 && /* address family */ - sk->dummy_th.dest == sport && /* remote port */ - !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.daddr, saddr) && - !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, daddr)) - goto hit; + sk->dummy_th.dest == sport) { /* remote port */ + struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk; + if(!ipv6_addr_cmp(&tw->v6_daddr, saddr) && + !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr)) + goto hit; + } #ifdef USE_QUICKSYNS listener_shortcut: #endif @@ -520,8 +517,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, * Put in the TCP options to say MTU. */ - tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack, - sysctl_tcp_timestamps, + tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_timestamps, sysctl_tcp_window_scaling,tp->rcv_wscale); th->doff = sizeof(*th)/4 + (tmp>>2); buff->csum = 0; @@ -623,7 +619,7 @@ void tcp_v6_err(int type, int code, unsigned char *header, __u32 info, sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source); - if (sk == NULL) { + if (sk == NULL || sk->state == TCP_TIME_WAIT) { /* XXX: Update ICMP error count */ return; } @@ -800,7 +796,7 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req) } th->window = htons(req->rcv_wnd); - tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok, + tmp = tcp_syn_build_options(skb, req->mss, req->tstamp_ok, req->wscale_ok,req->rcv_wscale); skb->csum = 0; th->doff = (sizeof(*th) + tmp)>>2; @@ -873,14 +869,13 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, req->rcv_isn = skb->seq; req->snt_isn = isn; - tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0; + tp.tstamp_ok = tp.wscale_ok = tp.snd_wscale = 0; tp.in_mss = 536; tcp_parse_options(skb->h.th,&tp,0); if (tp.saw_tstamp) req->ts_recent = tp.rcv_tsval; req->mss = tp.in_mss; req->tstamp_ok = tp.tstamp_ok; - req->sack_ok = tp.sack_ok; req->snd_wscale = tp.snd_wscale; req->wscale_ok = tp.wscale_ok; req->rmt_port = skb->h.th->source; @@ -984,7 +979,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ip6_dst_store(newsk, dst); - newtp->sack_ok = req->sack_ok; newtp->tstamp_ok = req->tstamp_ok; newtp->window_clamp = req->window_clamp; newtp->rcv_wnd = req->rcv_wnd; @@ -1186,12 +1180,14 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev, goto no_tcp_socket; } - skb->sk = sk; skb->seq = ntohl(th->seq); skb->end_seq = skb->seq + th->syn + th->fin + len - th->doff*4; skb->ack_seq = ntohl(th->ack_seq); - skb->used = 0; + if(sk->state == TCP_TIME_WAIT) + goto do_time_wait; + + skb->sk = sk; } /* @@ -1254,6 +1250,12 @@ discard_it: kfree_skb(skb); return 0; + +do_time_wait: + if(tcp_timewait_state_process((struct tcp_tw_bucket *)sk, + skb, th, &(IPCB(skb)->opt), skb->len)) + goto no_tcp_socket; + goto discard_it; } static int tcp_v6_rebuild_header(struct sock *sk, struct sk_buff *skb) @@ -1407,10 +1409,8 @@ static int tcp_v6_init_sock(struct sock *sk) tp->in_mss = 536; /* tp->rcv_wnd = 8192; */ tp->tstamp_ok = 0; - tp->sack_ok = 0; tp->wscale_ok = 0; tp->snd_wscale = 0; - tp->sacks = 0; tp->saw_tstamp = 0; tp->syn_backlog = 0; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5324fdc73822..40e9b02339d7 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.23 1998/03/08 05:56:59 davem Exp $ + * $Id: udp.c,v 1.24 1998/03/12 03:20:21 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index d800cf9d6b6e..9d8a206da99c 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -759,6 +759,8 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags) newsk = skb->sk; newsk->pair = NULL; + newsk->socket = newsock; + newsk->sleep = &newsock->wait; sti(); /* Now attach up the new socket */ diff --git a/net/netsyms.c b/net/netsyms.c index 8831de3f3b8f..ad51e9a3e2ef 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -244,7 +244,6 @@ EXPORT_SYMBOL(csum_partial_copy_fromiovecend); EXPORT_SYMBOL(__release_sock); EXPORT_SYMBOL(net_timer); /* UDP/TCP exported functions for TCPv6 */ -EXPORT_SYMBOL(sysctl_tcp_sack); EXPORT_SYMBOL(sysctl_tcp_timestamps); EXPORT_SYMBOL(sysctl_tcp_window_scaling); EXPORT_SYMBOL(sock_rspace); @@ -272,6 +271,7 @@ EXPORT_SYMBOL(tcp_slt_array); EXPORT_SYMBOL(__tcp_inc_slow_timer); EXPORT_SYMBOL(tcp_statistics); EXPORT_SYMBOL(tcp_rcv_state_process); +EXPORT_SYMBOL(tcp_timewait_state_process); EXPORT_SYMBOL(tcp_do_sendmsg); EXPORT_SYMBOL(tcp_v4_build_header); EXPORT_SYMBOL(tcp_v4_rebuild_header); @@ -293,6 +293,11 @@ EXPORT_SYMBOL(ipv4_specific); EXPORT_SYMBOL(tcp_simple_retransmit); EXPORT_SYMBOL(xrlim_allow); + +EXPORT_SYMBOL(tcp_write_xmit); +EXPORT_SYMBOL(dev_loopback_xmit); +EXPORT_SYMBOL(tcp_regs); + #endif #ifdef CONFIG_NETLINK diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f3893c9d461f..74fc7af82594 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -832,9 +832,10 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, int len, /* We can't use skb_copy_datagram here */ err = memcpy_toiovec(msg->msg_iov, skb->data, copied); - if (err) + if (err) { + err = -EFAULT; goto out_free; - + } sk->stamp=skb->stamp; if (msg->msg_name) diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 1056c7d73578..a575402c7feb 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -847,6 +847,8 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags) newsk = skb->sk; newsk->pair = NULL; + newsk->socket = newsock; + newsk->sleep = &newsock->wait; sti(); /* Now attach up the new socket */ diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index c74a1997c9f2..b04072d808a4 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1265,7 +1265,9 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size } chunk = min(skb->len, size); - /* N.B. This could fail with -EFAULT */ + /* N.B. This could fail with a non-zero value (which means -EFAULT + * and the non-zero value is the number of bytes not copied). + */ memcpy_toiovec(msg->msg_iov, skb->data, chunk); copied += chunk; size -= chunk; -- 2.39.5