@@ -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
@@ -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).
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 <high>
+ 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.
==============================================================
*/
.text
-#include <linux/config.h>
#include <linux/tasks.h>
#include <linux/linkage.h>
#include <asm/segment.h>
@@ -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];
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/stddef.h>
/* 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;
}
#ifndef __irq_h
#define __irq_h
-#include <linux/config.h>
-
/*
- * 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;
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
#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));
* entries except for the gdt one..
*/
-#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
+#include <linux/swapctl.h>
#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/blk.h>
#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)
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
#include <asm/lsu.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#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
#include <linux/init.h>
#include <linux/blk.h>
#include <linux/swap.h>
+#include <linux/swapctl.h>
#include <asm/head.h>
#include <asm/system.h>
@@ -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)
@@ -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);
@@ -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
* for the QIC-117 floppy-tape driver for Linux.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/mm.h>
* for the QIC-117 floppy-tape driver for Linux.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/system.h>
-/* 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
@@ -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 <johns393@maroon.tc.umn.edu>\n",
+ printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n",
dev->name);
if(ipddp_mode == IPDDP_DECAP)
- printk("%s: Appletalk-IP Decapsulation mode by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n",
+ printk("%s: Appletalk-IP Decap. mode by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\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;
@@ -158,24+153,6 @@ int ipddp_init(struct device *dev) }
/*
- * 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.
*/
static struct net_device_stats *ipddp_get_stats(struct device *dev)
@@ -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;
}
#define SIOCADDIPDDPRT (SIOCDEVPRIVATE)
#define SIOCDELIPDDPRT (SIOCDEVPRIVATE+1)
#define SIOCFINDIPDDPRT (SIOCDEVPRIVATE+2)
-#define SIOCPRINTIPDDPRT (SIOCDEVPRIVATE+3)
struct ipddp_route
{
/* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */
-#include <linux/config.h> /* for CONFIG_KERNELD */
+#include <linux/config.h> /* for CONFIG_KMOD */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
*
*/
-#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
* driver uses the new code this *ENTIRE* file will be nuked.
*/
-#include <linux/config.h> /* for CONFIG_KERNELD */
#define __NO_VERSION__
#include <linux/module.h>
* we attempt to remove commands from the queue and retry them.
*/
-#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
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
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
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 += $@'; \
*/
/*
* 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 <linux/config.h>
@@ -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;
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 )
{
* 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
*
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
+
#include <linux/config.h>
#include <linux/module.h>
@@ -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)
{
@@ -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;
}
+++ /dev/null
-/*
- * 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 <linux/config.h>
-
-#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
@@ -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)
@@ -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\x1d;
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<l;i++)
{
* 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 General clean up, use kernel IRQ
+ * system
+ *
+ * Status:
+ * Untested
*/
+
#include <linux/config.h>
#include <linux/module.h>
@@ -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)
* 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 <linux/config.h>
#include <linux/module.h>
@@ -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("<all end>");
- 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("<Trk data rq #%d>", midic & 0x0f);
- break;
-
- case 0xf9:
- printk("<conductor rq>");
- 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("<MPU: Unknown event %02x> ", 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("<SYX>");
- 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("<EOX>");
- 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("<all end>");
+ 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("<Trk data rq #%d>", midic & 0x0f);
+ break;
+
+ case 0xf9:
+ printk("<conductor rq>");
+ 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("<MPU: Unknown event %02x> ", 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("<SYX>");
+ 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("<EOX>");
+ 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:
* 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 <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
/*
* 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);
}
@@ -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;
}
}
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
* 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 <linux/config.h>
#include <linux/module.h>
@@ -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( "<PSS: microcode version %d.%d loaded>", 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( "<PSS: microcode version %d.%d loaded>", 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);
@@ -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;
@@ -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
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);
@@ -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);
@@ -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);
/*
#include <linux/fcntl.h>
#include <linux/ctype.h>
#include <linux/stddef.h>
+#include <linux/kmod.h>
#ifdef __KERNEL__
#include <asm/io.h>
#include <asm/segment.h>
@@ -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)
* 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 <linux/config.h>
#include <linux/module.h>
#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;
}
* 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 <linux/config.h>
#include <linux/module.h>
@@ -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]);
}
* 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 <linux/config.h>
#include <linux/module.h>
@@ -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;
@@ -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;
-Wed Jan 7 19:33:33 1998 a sun <asun@zoology.washington.edu>
+Wed Jan 21 14:04:26 1998 a sun <asun@zoology.washington.edu>
+
+ * 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 <asun@zoology.washington.edu>
+
+ * 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 <asun@zoology.washington.edu>
+
+ * 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 <asun@zoology.washington.edu>
+
+ * 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 <asun@zoology.washington.edu>
+
+ * 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 <asun@zoology.washington.edu>
#
-# 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
*
* 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
/*================ 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);
* 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;
(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);
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++;
@@ -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;
}
-/* 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);
@@ -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;
@@ -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;
@@ -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;
@@ -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;
}
@@ -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);
}
}
*/
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;
#define _HFS_H
#include <linux/hfs_sysdep.h>
-#include <linux/hfs_fs.h>
#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)
@@ -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;
@@ -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);
}
/*
@@ -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 */
#include <linux/hfs_fs.h>
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);
}
* This file contains the version string for this release.
*/
-const char hfs_version[]="0.95+asun2";
+const char hfs_version[]="0.95+asun3";
#ifndef _I386_PAGE_H
#define _I386_PAGE_H
+#include <linux/config.h>
+
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
@@ -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))
@@ -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
@@ -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);
}
@@ -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;
/* 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. */
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 */
};
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,
@@ -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;
@@ -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);
}
@@ -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
* Copyright (C) 1992 Krishna Balasubramanian
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/msg.h>
@@ -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:
@@ -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}
};
*/
/*
- * 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 <linux/mm.h>
/*
* 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 */
+};
* 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 $
*/
#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
@@ -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) {
@@ -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
@@ -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
+}
+}
@@ -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 <net,node,port> 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)
*/
@@ -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 */
@@ -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;
* 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, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -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);
/*
* 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},
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -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
@@ -479,20+480,6 @@ static void tcp_close_pending (struct sock *sk) }
/*
- * 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.
*
* Must be called with the socket lock held.
@@ -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.");
}
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -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;
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);
*
* 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
*
#include <linux/inet.h>
-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;
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
#include <net/tcp.h>
-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. */
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -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<<sk->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<<sk->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);
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
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;
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -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);
}
* 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)
*
#include <linux/net.h>
#include <linux/in6.h>
#include <net/sock.h>
+#include <net/tcp.h>
#include <net/transp_v6.h>
/* 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);
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $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
#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;
*
* 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
@@ -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 */
@@ -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
@@ -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)
@@ -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 */
@@ -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;