diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 57c39a7..a54a4c2 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -15240,6 +15240,24 @@ CONFIG_INPUT_JOYDEV The module will be called joydev.o. If you want to compile it as a module, say M here and read . +Dummy keyboard driver +CONFIG_DUMMY_KEYB + What is this for? + + Not all systems have keyboards. Some don't even have a keyboard + port. However, some of those systems have video support and can + use the virtual terminal support for display. However, the virtual + terminal code expects a keyboard of some kind. This driver keeps + the virtual terminal code happy by providing it a "keyboard", albeit + a very quiet one. + + If you want to use the virtual terminal support but your system + does not support a keyboard, define CONFIG_DUMMY_KEYB along with + CONFIG_VT. + + This can also be selected lonesome without any VT support (i.e. no + monitor or keyboard attached) - just define CONFIG_DUMMY_KEYB. + Event interface support CONFIG_INPUT_EVDEV Say Y here if you want your USB or ADB HID device events be diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c index 92b4126..659e32f 100644 --- a/arch/i386/kernel/dmi_scan.c +++ b/arch/i386/kernel/dmi_scan.c @@ -411,7 +411,7 @@ typedef void (pm_kbd_func) (void); static __init int broken_ps2_resume(struct dmi_blacklist *d) { -#ifdef CONFIG_VT +#if defined(CONFIG_VT) && !defined(CONFIG_DUMMY_KEYB) if (pm_kbd_request_override == NULL) { pm_kbd_request_override = pckbd_pm_resume; diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 58f5222..bc90533 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -1194,7 +1194,7 @@ static int __init timer_irq_works(void) * might have cached one ExtINT interrupt. Finally, at * least one tick may be lost due to delays. */ - if (jiffies - t1 > 4) + if (jiffies - t1 > 4 && jiffies - t1 < 16) return 1; return 0; diff --git a/drivers/char/dummy_keyb.c b/drivers/char/dummy_keyb.c index f2b3582..a80d1a0 100644 --- a/drivers/char/dummy_keyb.c +++ b/drivers/char/dummy_keyb.c @@ -29,6 +29,7 @@ #include #include #include +#include void kbd_leds(unsigned char leds) { diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 3f6a0aa..6fc6f77 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -899,11 +899,13 @@ static ide_startstop_t ide_dma_timeout_r rq = HWGROUP(drive)->rq; HWGROUP(drive)->rq = NULL; - rq->errors = 0; - rq->sector = rq->bh->b_rsector; - rq->current_nr_sectors = rq->bh->b_size >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; - rq->buffer = rq->bh->b_data; + if (rq) { + rq->errors = 0; + rq->sector = rq->bh->b_rsector; + rq->current_nr_sectors = rq->bh->b_size >> 9; + rq->hard_cur_sectors = rq->current_nr_sectors; + rq->buffer = rq->bh->b_data; + } return ret; } diff --git a/drivers/input/Config.in b/drivers/input/Config.in index 5353414..56fd537 100644 --- a/drivers/input/Config.in +++ b/drivers/input/Config.in @@ -7,6 +7,11 @@ comment 'Input core support' tristate 'Input core support' CONFIG_INPUT dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT + +if [ "$CONFIG_INPUT_KEYBDEV" == "n" ]; then + bool ' Use dummy keyboard driver' CONFIG_DUMMY_KEYB $CONFIG_INPUT +fi + dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index f801a6d..c2746d0 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1613,15 +1613,20 @@ static int sis900_rx(struct net_device * long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; + int rx_work_limit; if (sis900_debug > 3) printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); + rx_work_limit = sis_priv->dirty_rx + NUM_RX_DESC - sis_priv->cur_rx; while (rx_status & OWN) { unsigned int rx_size; + if (--rx_work_limit < 0) + break; + rx_size = (rx_status & DSIZE) - CRC_SIZE; if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { @@ -1648,9 +1653,11 @@ static int sis900_rx(struct net_device * some unknow bugs, it is possible that we are working on NULL sk_buff :-( */ if (sis_priv->rx_skbuff[entry] == NULL) { - printk(KERN_INFO "%s: NULL pointer " - "encountered in Rx ring, skipping\n", - net_dev->name); + printk(KERN_WARNING "%s: NULL pointer " + "encountered in Rx ring\n" + "cur_rx:%4.4d, dirty_rx:%4.4d\n", + net_dev->name, sis_priv->cur_rx, + sis_priv->dirty_rx); break; } @@ -1688,6 +1695,7 @@ static int sis900_rx(struct net_device * sis_priv->rx_ring[entry].cmdsts = 0; sis_priv->rx_ring[entry].bufptr = 0; sis_priv->stats.rx_dropped++; + sis_priv->cur_rx++; break; } skb->dev = net_dev; @@ -1705,7 +1713,7 @@ static int sis900_rx(struct net_device * /* refill the Rx buffer, what if the rate of refilling is slower than consuming ?? */ - for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { + for (; sis_priv->cur_rx != sis_priv->dirty_rx; sis_priv->dirty_rx++) { struct sk_buff *skb; entry = sis_priv->dirty_rx % NUM_RX_DESC; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index d858dba..2862039 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -43,6 +43,8 @@ #include #include +#include "airo.h" + #ifdef CONFIG_PCI static struct pci_device_id card_ids[] = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, diff --git a/drivers/net/wireless/airo.h b/drivers/net/wireless/airo.h new file mode 100644 index 0000000..2533e2d --- /dev/null +++ b/drivers/net/wireless/airo.h @@ -0,0 +1,8 @@ +#ifndef _AIRO_H_ +#define _AIRO_H_ + +struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia); +void stop_airo_card(struct net_device *dev, int freeres); +int reset_airo_card(struct net_device *dev); + +#endif /* _AIRO_H_ */ diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index e4bc8b9..77714c6 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -45,6 +45,8 @@ #include #include +#include "airo.h" + /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not define PCMCIA_DEBUG at all, all the debug code will be @@ -91,10 +93,6 @@ MODULE_PARM(irq_list, "1-4i"); event handler. */ -struct net_device *init_airo_card( int, int, int ); -void stop_airo_card( struct net_device *, int ); -int reset_airo_card( struct net_device * ); - static void airo_config(dev_link_t *link); static void airo_release(u_long arg); static int airo_event(event_t event, int priority, diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index e7d783e..0ba81d0 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -807,7 +807,7 @@ static int adpt_hba_reset(adpt_hba* pHba static void adpt_i2o_sys_shutdown(void) { adpt_hba *pHba, *pNext; - struct adpt_i2o_post_wait_data *p1, *p2; + struct adpt_i2o_post_wait_data *p1, *old; printk(KERN_INFO"Shutting down Adaptec I2O controllers.\n"); printk(KERN_INFO" This could take a few minutes if there are many devices attached\n"); @@ -821,13 +821,14 @@ static void adpt_i2o_sys_shutdown(void) } /* Remove any timedout entries from the wait queue. */ - p2 = NULL; // spin_lock_irqsave(&adpt_post_wait_lock, flags); /* Nothing should be outstanding at this point so just * free them */ - for(p1 = adpt_post_wait_queue; p1; p2 = p1, p1 = p2->next) { - kfree(p1); + for(p1 = adpt_post_wait_queue; p1;) { + old = p1; + p1 = p1->next; + kfree(old); } // spin_unlock_irqrestore(&adpt_post_wait_lock, flags); adpt_post_wait_queue = 0; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 522b15b..c38f916 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -145,6 +145,7 @@ static struct dev_info device_list[] = {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-624X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"EMULEX", "MD21/S2 ESDI", "*", BLIST_SINGLELUN}, {"CANON", "IPUBJD", "*", BLIST_SPARSELUN}, {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN}, diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 59d65f5..287bcad 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -212,8 +212,13 @@ static struct { }; #define CMD_MAX (sizeof(sizes)/sizeof(sizes[0])-1) +#ifdef MODULE +long +handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp) +#else long asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp) +#endif { struct nfsctl_arg * argp = opaque_argp; union nfsctl_res * resp = opaque_resp; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 4aa9f60..00fa518 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -70,6 +70,7 @@ struct proc_dir_entry { atomic_t count; /* use count */ int deleted; /* delete flag */ kdev_t rdev; + void *set; }; #define PROC_INODE_PROPER(inode) ((inode)->i_ino & ~0xffff) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index e79bbac..23c7ae4 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -29,6 +29,7 @@ #include struct file; +struct completion; #define CTL_MAXNAME 10 @@ -829,6 +830,8 @@ struct ctl_table_header { ctl_table *ctl_table; struct list_head ctl_entry; + int used; + struct completion *unregistering; }; struct ctl_table_header * register_sysctl_table(ctl_table * table, diff --git a/kernel/panic.c b/kernel/panic.c index 7b38771..4c611d8 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -104,7 +104,7 @@ NORET_TYPE void panic(const char * fmt, #endif sti(); for(;;) { -#if defined(CONFIG_X86) && defined(CONFIG_VT) +#if defined(CONFIG_X86) && defined(CONFIG_VT) && !defined(CONFIG_DUMMY_KEYB) extern void panic_blink(void); panic_blink(); #endif diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 7a2fd02..3d54347 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -147,7 +147,7 @@ static struct inode_operations proc_sys_ extern struct proc_dir_entry *proc_sys_root; -static void register_proc_table(ctl_table *, struct proc_dir_entry *); +static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *); static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); #endif @@ -360,10 +360,51 @@ static ctl_table dev_table[] = { extern void init_irq_proc (void); +static spinlock_t sysctl_lock = SPIN_LOCK_UNLOCKED; + +/* called under sysctl_lock */ +static int use_table(struct ctl_table_header *p) +{ + if (unlikely(p->unregistering != NULL)) + return 0; + p->used++; + return 1; +} + +/* called under sysctl_lock */ +static void unuse_table(struct ctl_table_header *p) +{ + if (!--p->used) + if (unlikely(p->unregistering != NULL)) + complete(p->unregistering); +} + +/* called under sysctl_lock, will reacquire if has to wait */ +static void start_unregistering(struct ctl_table_header *p) +{ + /* + * if p->used is 0, nobody will ever touch that entry again; + * we'll eliminate all paths to it before dropping sysctl_lock + */ + if (unlikely(p->used)) { + struct completion wait; + init_completion(&wait); + p->unregistering = &wait; + spin_unlock(&sysctl_lock); + wait_for_completion(&wait); + spin_lock(&sysctl_lock); + } + /* + * do not remove from the list until nobody holds it; walking the + * list in do_sysctl() relies on that. + */ + list_del_init(&p->ctl_entry); +} + void __init sysctl_init(void) { #ifdef CONFIG_PROC_FS - register_proc_table(root_table, proc_sys_root); + register_proc_table(root_table, proc_sys_root, &root_table_header); init_irq_proc(); #endif } @@ -372,6 +413,7 @@ int do_sysctl(int *name, int nlen, void void *newval, size_t newlen) { struct list_head *tmp; + int error = -ENOTDIR; if (nlen <= 0 || nlen >= CTL_MAXNAME) return -ENOTDIR; @@ -383,21 +425,31 @@ int do_sysctl(int *name, int nlen, void if ((ssize_t)old_len < 0) return -EINVAL; } + spin_lock(&sysctl_lock); tmp = &root_table_header.ctl_entry; do { struct ctl_table_header *head = list_entry(tmp, struct ctl_table_header, ctl_entry); void *context = NULL; - int error = parse_table(name, nlen, oldval, oldlenp, + + if (!use_table(head)) + continue; + + spin_unlock(&sysctl_lock); + + error = parse_table(name, nlen, oldval, oldlenp, newval, newlen, head->ctl_table, &context); if (context) kfree(context); + + spin_lock(&sysctl_lock); + unuse_table(head); if (error != -ENOTDIR) - return error; - tmp = tmp->next; - } while (tmp != &root_table_header.ctl_entry); - return -ENOTDIR; + break; + } while ((tmp = tmp->next) != &root_table_header.ctl_entry); + spin_unlock(&sysctl_lock); + return error; } extern asmlinkage long sys_sysctl(struct __sysctl_args *args) @@ -604,12 +656,16 @@ struct ctl_table_header *register_sysctl return NULL; tmp->ctl_table = table; INIT_LIST_HEAD(&tmp->ctl_entry); + tmp->used = 0; + tmp->unregistering = NULL; + spin_lock(&sysctl_lock); if (insert_at_head) list_add(&tmp->ctl_entry, &root_table_header.ctl_entry); else list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); + spin_unlock(&sysctl_lock); #ifdef CONFIG_PROC_FS - register_proc_table(table, proc_sys_root); + register_proc_table(table, proc_sys_root, tmp); #endif return tmp; } @@ -623,10 +679,12 @@ struct ctl_table_header *register_sysctl */ void unregister_sysctl_table(struct ctl_table_header * header) { - list_del(&header->ctl_entry); + spin_lock(&sysctl_lock); + start_unregistering(header); #ifdef CONFIG_PROC_FS unregister_proc_table(header->ctl_table, proc_sys_root); #endif + spin_unlock(&sysctl_lock); kfree(header); } @@ -637,7 +695,7 @@ void unregister_sysctl_table(struct ctl_ #ifdef CONFIG_PROC_FS /* Scan the sysctl entries in table and add them all into /proc */ -static void register_proc_table(ctl_table * table, struct proc_dir_entry *root) +static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set) { struct proc_dir_entry *de; int len; @@ -673,6 +731,7 @@ static void register_proc_table(ctl_tabl de = create_proc_entry(table->procname, mode, root); if (!de) continue; + de->set = set; de->data = (void *) table; if (table->proc_handler) { de->proc_fops = &proc_sys_file_operations; @@ -681,7 +740,7 @@ static void register_proc_table(ctl_tabl } table->de = de; if (de->mode & S_IFDIR) - register_proc_table(table->child, de); + register_proc_table(table->child, de, set); } } @@ -706,6 +765,13 @@ static void unregister_proc_table(ctl_ta continue; } + /* + * In any case, mark the entry as goner; we'll keep it + * around if it's busy, but we'll know to do nothing with + * its fields. We are under sysctl_lock here. + */ + de->data = NULL; + /* Don't unregister proc entries that are still being used.. */ if (atomic_read(&de->count)) continue; @@ -719,31 +785,44 @@ static ssize_t do_rw_proc(int write, str size_t count, loff_t *ppos) { int op; - struct proc_dir_entry *de; + struct proc_dir_entry *de = + (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip; struct ctl_table *table; size_t res; - ssize_t error; - - de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip; - if (!de || !de->data) - return -ENOTDIR; - table = (struct ctl_table *) de->data; - if (!table || !table->proc_handler) - return -ENOTDIR; - op = (write ? 002 : 004); - if (ctl_perm(table, op)) - return -EPERM; - - res = count; + ssize_t error = -ENOTDIR; - /* - * FIXME: we need to pass on ppos to the handler. - */ + spin_lock(&sysctl_lock); + if (de && de->data && use_table(de->set)) { + /* + * at that point we know that sysctl was not unregistered + * and won't be until we finish + */ + spin_unlock(&sysctl_lock); + table = (struct ctl_table *) de->data; + if (!table || !table->proc_handler) + goto out; + error = -EPERM; + op = (write ? 002 : 004); + if (ctl_perm(table, op)) + goto out; + + /* careful: calling conventions are nasty here */ + res = count; - error = (*table->proc_handler) (table, write, file, buf, &res); - if (error) - return error; - return res; + /* + * FIXME: we need to pass on ppos to the handler. + */ + + error = (*table->proc_handler)(table, write, file, + buf, &res); + if (!error) + error = res; + out: + spin_lock(&sysctl_lock); + unuse_table(de->set); + } + spin_unlock(&sysctl_lock); + return error; } static ssize_t proc_readsys(struct file * file, char * buf,