diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
commit | b9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch) | |
tree | 42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/sbus | |
parent | 7406b0a326f2d70ade2671c37d1beef62249db97 (diff) |
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/sbus')
-rw-r--r-- | drivers/sbus/char/jsflash.c | 363 | ||||
-rw-r--r-- | drivers/sbus/char/pcikbd.c | 215 | ||||
-rw-r--r-- | drivers/sbus/char/sab82532.c | 83 | ||||
-rw-r--r-- | drivers/sbus/char/su.c | 6 | ||||
-rw-r--r-- | drivers/sbus/char/sunkbd.c | 101 | ||||
-rw-r--r-- | drivers/sbus/char/sunmouse.c | 127 | ||||
-rw-r--r-- | drivers/sbus/char/zs.c | 8 |
7 files changed, 656 insertions, 247 deletions
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index af9f6c95f..44692c7e9 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -3,11 +3,15 @@ * * Copyright (C) 1991, 1992 Linus Torvalds (drivers/char/mem.c) * Copyright (C) 1997 Eddie C. Dost (drivers/sbus/char/flash.c) - * Copyright (C) 1999 Pete Zaitcev + * Copyright (C) 1997-2000 Pavel Machek <pavel@ucw.cz> (drivers/block/nbd.c) + * Copyright (C) 1999-2000 Pete Zaitcev * * This driver is used to program OS into a Flash SIMM on * Krups and Espresso platforms. * + * TODO: do not allow erase/programming if file systems are mounted. + * TODO: Erase/program both banks of a 8MB SIMM. + * * It is anticipated that programming an OS Flash will be a routine * procedure. In the same time it is exeedingly dangerous because * a user can program its OBP flash with OS image and effectively @@ -31,23 +35,25 @@ #include <linux/poll.h> #include <linux/init.h> #include <linux/string.h> -#if 0 /* P3 from mem.c */ -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/mman.h> -#include <linux/random.h> -#include <linux/raw.h> -#include <linux/capability.h> -#endif + +/* + * <linux/blk.h> is controlled from the outside with these definitions. + */ +#define MAJOR_NR JSFD_MAJOR + +#define DEVICE_NAME "jsfd" +#define DEVICE_REQUEST jsfd_do_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) +#define DEVICE_NO_RANDOM + +#include <linux/blk.h> + #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> -#if 0 /* P3 from mem.c */ -#include <asm/system.h> -#include <asm/sbus.h> -#include <asm/ebus.h> -#endif #include <asm/pcic.h> #include <asm/oplib.h> @@ -58,8 +64,23 @@ /* * Our device numbers have no business in system headers. * The only thing a user knows is the device name /dev/jsflash. + * + * Block devices are laid out like this: + * minor+0 - Bootstrap, for 8MB SIMM 0x20400000[0x800000] + * minor+1 - Filesystem to mount, normally 0x20400400[0x7ffc00] + * minor+2 - Whole flash area for any case... 0x20000000[0x01000000] + * Total 3 minors per flash device. + * + * It is easier to have static size vectors, so we define + * a total minor range JSF_MAX, which must cover all minors. */ -#define JSF_MINOR 178 +/* character device */ +#define JSF_MINOR 178 /* 178 is registered with hpa */ +/* block device */ +#define JSF_MAX 3 /* 3 minors wasted total so far. */ +#define JSF_NPART 3 /* 3 minors per flash device */ +#define JSF_PART_BITS 2 /* 2 bits of minors to cover JSF_NPART */ +#define JSF_PART_MASK 0x3 /* 2 bits mask */ /* * Access functions. @@ -86,11 +107,20 @@ static void jsf_outl(unsigned long addr, __u32 data) /* * soft carrier */ + +struct jsfd_part { + unsigned long dbase; + unsigned long dsize; + int refcnt; +}; + struct jsflash { unsigned long base; unsigned long size; unsigned long busy; /* In use? */ struct jsflash_ident_arg id; + /* int mbase; */ /* Minor base, typically zero */ + struct jsfd_part dv[JSF_NPART]; }; /* @@ -103,6 +133,12 @@ struct jsflash { #define JSF_BASE_JK 0x20400000 /* + */ +static int jsfd_blksizes[JSF_MAX]; +static int jsfd_sizes[JSF_MAX]; +static u64 jsfd_bytesizes[JSF_MAX]; + +/* * Let's pretend we may have several of these... */ static struct jsflash jsf0; @@ -112,7 +148,7 @@ static struct jsflash jsf0; * We use the Toggle bit DQ6 (0x40) because it does not * depend on the data value as /DATA bit DQ7 does. * - * XXX Do we need any timeout here? + * XXX Do we need any timeout here? So far it never hanged, beware broken hw. */ static void jsf_wait(unsigned long p) { unsigned int x1, x2; @@ -146,6 +182,73 @@ static void jsf_write4(unsigned long fa, u32 data) { } /* + */ +static void jsfd_read(char *buf, unsigned long p, size_t togo) { + union byte4 { + char s[4]; + unsigned int n; + } b; + + while (togo >= 4) { + togo -= 4; + b.n = jsf_inl(p); + memcpy(buf, b.s, 4); + p += 4; + buf += 4; + } +} + +static void jsfd_do_request(request_queue_t *q) +{ + struct request *req; + int dev; + struct jsfd_part *jdp; + unsigned long offset; + size_t len; + + for (;;) { + INIT_REQUEST; /* if (QUEUE_EMPTY) return; */ + req = CURRENT; + + dev = MINOR(req->rq_dev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + end_request(0); + continue; + } + jdp = &jsf0.dv[dev & JSF_PART_MASK]; + + offset = req->sector << 9; + len = req->current_nr_sectors << 9; + if ((offset + len) > jdp->dsize) { + end_request(0); + continue; + } + + if (req->cmd == WRITE) { + printk(KERN_ERR "jsfd: write\n"); + end_request(0); + continue; + } + if (req->cmd != READ) { + printk(KERN_ERR "jsfd: bad req->cmd %d\n", req->cmd); + end_request(0); + continue; + } + + if ((jdp->dbase & 0xff000000) != 0x20000000) { + printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); + end_request(0); + continue; + } + +/* printk("jsfd%d: read buf %p off %x len %x\n", dev, req->buffer, (int)offset, (int)len); */ /* P3 */ + jsfd_read(req->buffer, jdp->dbase + offset, len); + + end_request(1); + } +} + +/* * The memory devices use the full 32/64 bits of the offset, and so we cannot * check against negative addresses: they are ok. The return value is weird, * though, in that case (0). @@ -301,7 +404,7 @@ static int jsf_ioctl_program(unsigned long arg) if (verify_area(VERIFY_READ, uptr, togo)) return -EFAULT; while (togo != 0) { - --togo; + togo -= 4; copy_from_user(&b.s[0], uptr, 4); jsf_write4(p, b.n); p += 4; @@ -316,6 +419,8 @@ static int jsf_ioctl(struct inode *inode, struct file *f, unsigned int cmd, { int error = -ENOTTY; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; switch (cmd) { case JSFLASH_IDENT: if (verify_area(VERIFY_WRITE, (void *)arg, JSFIDSZ)) @@ -334,6 +439,34 @@ static int jsf_ioctl(struct inode *inode, struct file *f, unsigned int cmd, return error; } +static int jsfd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int dev; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!inode) + return -EINVAL; + if ((dev = MINOR(inode->i_rdev)) >= JSF_MAX) return -ENODEV; + + switch (cmd) { + case BLKGETSIZE: + return put_user(jsfd_bytesizes[dev] >> 9, (long *) arg); + +#if 0 + case BLKROSET: + case BLKROGET: + case BLKSSZGET: + return blk_ioctl(inode->i_rdev, cmd, arg); +#endif + + /* case BLKFLSBUF: */ /* Program, then read, what happens? Stale? */ + default: ; + } + return -ENOTTY; +} + static int jsf_mmap(struct file * file, struct vm_area_struct * vma) { return -ENXIO; @@ -350,6 +483,26 @@ static int jsf_open(struct inode * inode, struct file * filp) return 0; /* XXX What security? */ } +static int jsfd_open(struct inode *inode, struct file *file) +{ + struct jsfd_part *jdp; + int dev; + + if (!inode) + return -EINVAL; + dev = MINOR(inode->i_rdev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + printk(KERN_ALERT "jsfd_open: illegal minor %d\n", dev); + return -ENODEV; + } + + jdp = &jsf0.dv[dev]; + jdp->refcnt++; + + MOD_INC_USE_COUNT; + return 0; +} + static int jsf_release(struct inode *inode, struct file *file) { @@ -359,6 +512,30 @@ static int jsf_release(struct inode *inode, struct file *file) return 0; } +static int jsfd_release(struct inode *inode, struct file *file) +{ + struct jsfd_part *jdp; + int dev; + + if (!inode) + return -ENODEV; + dev = MINOR(inode->i_rdev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + printk(KERN_ALERT "jsfd_release: illegal minor %d\n", dev); + return -ENODEV; + } + + jdp = &jsf0.dv[dev]; + if (jdp->refcnt <= 0) { + printk(KERN_ALERT "jsfd_release: bad ref on minor %d\n", dev); + } else { + --jdp->refcnt; + } + /* N.B. Doesn't lo->file need an fput?? */ + MOD_DEC_USE_COUNT; + return 0; +} + static struct file_operations jsf_fops = { llseek: jsf_lseek, read: jsf_read, @@ -371,37 +548,90 @@ static struct file_operations jsf_fops = { static struct miscdevice jsf_dev = { JSF_MINOR, "jsflash", &jsf_fops }; +static struct block_device_operations jsfd_fops = { + open: jsfd_open, + release: jsfd_release, + ioctl: jsfd_ioctl, +}; + EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int __init jsflash_init(void) -#endif +int jsflash_init(void) { int rc; + struct jsflash *jsf; + int node; char banner[128]; + struct linux_prom_registers reg0; + + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "flash-memory"); + if (node != 0 && node != -1) { + if (prom_getproperty(node, "reg", + (char *)®0, sizeof(reg0)) == -1) { + printk("jsflash: no \"reg\" property\n"); + return -ENXIO; + } + if (reg0.which_io != 0) { + printk("jsflash: bus number nonzero: 0x%x:%x\n", + reg0.which_io, reg0.phys_addr); + return -ENXIO; + } + /* + * Flash may be somewhere else, for instance on Ebus. + * So, don't do the following check for IIep flash space. + */ +#if 0 + if ((reg0.phys_addr >> 24) != 0x20) { + printk("jsflash: suspicious address: 0x%x:%x\n", + reg0.which_io, reg0.phys_addr); + return -ENXIO; + } +#endif + if ((int)reg0.reg_size <= 0) { + printk("jsflash: bad size 0x%x\n", (int)reg0.reg_size); + return -ENXIO; + } + } else { + /* XXX Remove this code once PROLL ID12 got widespread */ + printk("jsflash: no /flash-memory node, use PROLL >= 12\n"); + prom_getproperty(prom_root_node, "banner-name", banner, 128); + if (strcmp (banner, "JavaStation-NC") != 0 && + strcmp (banner, "JavaStation-E") != 0) { + return -ENXIO; + } + reg0.which_io = 0; + reg0.phys_addr = 0x20400000; + reg0.reg_size = 0x00800000; + } - /* FIXME: Really autodetect things */ - prom_getproperty(prom_root_node, "banner-name", banner, 128); - if (strcmp (banner, "JavaStation-NC") && strcmp (banner, "JavaStation-E")) + /* Let us be really paranoid for modifications to probing code. */ + /* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */ + if (sparc_cpu_model != sun4m) { + /* We must be on sun4m because we use MMU Bypass ASI. */ return -ENXIO; + } - /* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */ - if (sparc_cpu_model == sun4m && jsf0.base == 0) { - /* XXX Autodetect */ - /* - * We do not want to use PROM properties; - * They are faked by PROLL anyways. - */ - jsf0.base = JSF_BASE_JK; - jsf0.size = 0x00800000; /* 8M */ + if (jsf0.base == 0) { + jsf = &jsf0; + + jsf->base = reg0.phys_addr; + jsf->size = reg0.reg_size; + + /* XXX Redo the userland interface. */ + jsf->id.off = JSF_BASE_ALL; + jsf->id.size = 0x01000000; /* 16M - all segments */ + strcpy(jsf->id.name, "Krups_all"); - jsf0.id.off = JSF_BASE_ALL; - jsf0.id.size = 0x01000000; /* 16M - all segments */ - strcpy(jsf0.id.name, "Krups_all"); + jsf->dv[0].dbase = jsf->base; + jsf->dv[0].dsize = jsf->size; + jsf->dv[1].dbase = jsf->base + 1024; + jsf->dv[1].dsize = jsf->size - 1024; + jsf->dv[2].dbase = JSF_BASE_ALL; + jsf->dv[2].dsize = 0x01000000; - printk("Espresso Flash @0x%lx\n", jsf0.base); + printk("Espresso Flash @0x%lx [%d MB]\n", jsf->base, + (int) (jsf->size / (1024*1024))); } if ((rc = misc_register(&jsf_dev)) != 0) { @@ -410,12 +640,63 @@ int __init jsflash_init(void) jsf0.base = 0; return rc; } + + return 0; +} + +int jsfd_init(void) { + struct jsflash *jsf; + struct jsfd_part *jdp; + int i; + + if (jsf0.base == 0) { + printk("jsfd_init: no flash\n"); /* P3 */ + return -EIO; + } + + if (register_blkdev(JSFD_MAJOR, "jsfd", &jsfd_fops)) { + printk("jsfd_init: unable to get major number %d\n", + JSFD_MAJOR); + return -EIO; + } + + printk("jsfd0: at major %d\n", MAJOR_NR); /* P3 */ + + blksize_size[JSFD_MAJOR] = jsfd_blksizes; + blk_size[JSFD_MAJOR] = jsfd_sizes; + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + /* blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); */ + for (i = 0; i < JSF_MAX; i++) { + if ((i & JSF_PART_MASK) >= JSF_NPART) continue; + jsf = &jsf0; /* actually, &jsfv[i >> JSF_PART_BITS] */ + jdp = &jsf->dv[i&JSF_PART_MASK]; + + jdp->refcnt = 0; + + jsfd_blksizes[i] = 1024; + jsfd_bytesizes[i] = jdp->dsize; + jsfd_sizes[i] = jsfd_bytesizes[i] >> 10; + register_disk(NULL, MKDEV(JSFD_MAJOR, i), 1, &jsfd_fops, + jsfd_bytesizes[i] >> 9); + set_device_ro(MKDEV(JSFD_MAJOR, i), 1); + } return 0; } #ifdef MODULE -void cleanup_module(void) -{ + +int init_module(void) { + int rc; + + if ((rc = jsflash_init()) == 0) { + jsfd_init(); + return 0; + } + return rc; +} + +void cleanup_module(void) { /* for (all probed units) { } */ if (jsf0.busy) @@ -424,5 +705,7 @@ void cleanup_module(void) jsf0.busy = 0; misc_deregister(&jsf_dev); + if (unregister_blkdev(JSFD_MAJOR, "jsfd") != 0) + printk("jsfd: cleanup_module failed\n"); } #endif diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c index 76b83eacb..d0e88d087 100644 --- a/drivers/sbus/char/pcikbd.c +++ b/drivers/sbus/char/pcikbd.c @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.44 2000/02/11 04:49:13 davem Exp $ +/* $Id: pcikbd.c,v 1.45 2000/04/24 06:10:19 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -23,6 +23,7 @@ #include <linux/kbd_ll.h> #include <linux/kbd_kern.h> #include <linux/delay.h> +#include <linux/spinlock.h> #include <linux/init.h> #include <asm/ebus.h> @@ -59,6 +60,8 @@ static volatile unsigned char reply_expected = 0; static volatile unsigned char acknowledge = 0; static volatile unsigned char resend = 0; +static spinlock_t pcikbd_lock = SPIN_LOCK_UNLOCKED; + unsigned char pckbd_read_mask = KBD_STAT_OBF; extern int pcikbd_init(void); @@ -71,26 +74,18 @@ extern unsigned char pci_getledstate(void); #define pcikbd_inb(x) inb(x) #define pcikbd_outb(v,x) outb(v,x) -#if 0 /* deadwood */ -static __inline__ unsigned char pcikbd_inb(unsigned long port) -{ - return inb(port); -} - -static __inline__ void pcikbd_outb(unsigned char val, unsigned long port) -{ - outb(val, port); -} -#endif - -static inline void kb_wait(void) +/* Wait for keyboard controller input buffer to drain. + * Must be invoked under the pcikbd_lock. + */ +static void kb_wait(void) { - unsigned long start = jiffies; + unsigned long timeout = 250; do { if(!(pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF)) return; - } while (jiffies - start < KBC_TIMEOUT); + mdelay(1); + } while (--timeout); } /* @@ -312,8 +307,11 @@ char pcikbd_unexpected_up(unsigned char keycode) static void pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; unsigned char status; + spin_lock_irqsave(&pcikbd_lock, flags); + kbd_pt_regs = regs; status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); do { @@ -327,27 +325,45 @@ pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while(status & KBD_STAT_OBF); tasklet_schedule(&keyboard_tasklet); + + spin_unlock_irqrestore(&pcikbd_lock, flags); } static int send_data(unsigned char data) { int retries = 3; - unsigned long start; + unsigned long flags; + + spin_lock_irqsave(&pcikbd_lock, flags); do { + unsigned long timeout = 1000; + kb_wait(); - acknowledge = resend = 0; + + acknowledge = 0; + resend = 0; reply_expected = 1; + pcikbd_outb(data, pcikbd_iobase + KBD_DATA_REG); - start = jiffies; do { - if(acknowledge) - return 1; - if(jiffies - start >= KBD_TIMEOUT) - return 0; - } while(!resend); - } while(retries-- > 0); + if (acknowledge) + goto out_ack; + if (resend) + break; + mdelay(1); + } while (--timeout); + if (timeout == 0) + goto out_timeout; + } while (retries-- > 0); + +out_timeout: + spin_unlock_irqrestore(&pcikbd_lock, flags); return 0; + +out_ack: + spin_unlock_irqrestore(&pcikbd_lock, flags); + return 1; } void pcikbd_leds(unsigned char leds) @@ -360,17 +376,23 @@ void pcikbd_leds(unsigned char leds) static int __init pcikbd_wait_for_input(void) { int status, data; - unsigned long start = jiffies; + unsigned long timeout = 1000; do { + mdelay(1); + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); - if(!(status & KBD_STAT_OBF)) + if (!(status & KBD_STAT_OBF)) continue; + data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); - if(status & (KBD_STAT_GTO | KBD_STAT_PERR)) + if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) continue; + return (data & 0xff); - } while(jiffies - start < KBD_INIT_TIMEOUT); + + } while (--timeout > 0); + return -1; } @@ -573,27 +595,12 @@ struct aux_queue { }; static struct aux_queue *queue; -static int aux_ready = 0; static int aux_count = 0; static int aux_present = 0; #define pcimouse_inb(x) inb(x) #define pcimouse_outb(v,x) outb(v,x) -#if 0 - -static __inline__ unsigned char pcimouse_inb(unsigned long port) -{ - return inb(port); -} - -static __inline__ void pcimouse_outb(unsigned char val, unsigned long port) -{ - outb(val, port); -} - -#endif - /* * Shared subroutines */ @@ -603,11 +610,11 @@ static unsigned int get_from_queue(void) unsigned int result; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&pcikbd_lock, flags); result = queue->buf[queue->tail]; queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - restore_flags(flags); + spin_unlock_irqrestore(&pcikbd_lock, flags); + return result; } @@ -645,17 +652,17 @@ static int aux_fasync(int fd, struct file *filp, int on) static int poll_aux_status(void) { - int retries=0; + int retries = 0; while ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) { if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((5*HZ + 99) / 100); + mdelay(5); retries++; } + return (retries < MAX_RETRIES); } @@ -699,51 +706,38 @@ static void aux_write_cmd(int val) } /* - * AUX handler critical section start and end. - * - * Only one process can be in the critical section and all keyboard sends are - * deferred as long as we're inside. This is necessary as we may sleep when - * waiting for the keyboard controller and other processes / BH's can - * preempt us. Please note that the input buffer must be flushed when - * aux_end_atomic() is called and the interrupt is no longer enabled as not - * doing so might cause the keyboard driver to ignore all incoming keystrokes. - */ - -static DECLARE_MUTEX(aux_sema4); - -static inline void aux_start_atomic(void) -{ - down(&aux_sema4); - tasklet_disable_nosync(&keyboard_tasklet); - tasklet_unlock_wait(&keyboard_tasklet); -} - -static inline void aux_end_atomic(void) -{ - tasklet_enable(&keyboard_tasklet); - up(&aux_sema4); -} - -/* * Interrupt from the auxiliary device: a character * is waiting in the keyboard/aux controller. */ void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int head = queue->head; - int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); + unsigned long flags; + int head, maxhead; + unsigned char val; + + spin_lock_irqsave(&pcikbd_lock, flags); - if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF) + head = queue->head; + maxhead = (queue->tail - 1) & (AUX_BUF_SIZE - 1); + + if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != + AUX_STAT_OBF) { + spin_unlock_irqrestore(&pcikbd_lock, flags); return; + } - add_mouse_randomness(queue->buf[head] = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG)); + val = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); + queue->buf[head] = val; + add_mouse_randomness(val); if (head != maxhead) { head++; - head &= AUX_BUF_SIZE-1; + head &= AUX_BUF_SIZE - 1; } queue->head = head; - aux_ready = 1; + + spin_unlock_irqrestore(&pcikbd_lock, flags); + if (queue->fasync) kill_fasync(queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); @@ -751,10 +745,13 @@ void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) static int aux_release(struct inode * inode, struct file * file) { + unsigned long flags; + aux_fasync(-1, file, 0); if (--aux_count) return 0; - aux_start_atomic(); + + spin_lock_irqsave(&pcikbd_lock, flags); /* Disable controller ints */ aux_write_cmd(AUX_INTS_OFF); @@ -763,7 +760,8 @@ static int aux_release(struct inode * inode, struct file * file) /* Disable Aux device */ pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - aux_end_atomic(); + + spin_unlock_irqrestore(&pcikbd_lock, flags); MOD_DEC_USE_COUNT; return 0; @@ -776,17 +774,19 @@ static int aux_release(struct inode * inode, struct file * file) static int aux_open(struct inode * inode, struct file * file) { + unsigned long flags; + if (!aux_present) return -ENODEV; - aux_start_atomic(); - if (aux_count++) { - aux_end_atomic(); + if (aux_count++) return 0; - } - if (!poll_aux_status()) { /* FIXME: Race condition */ + + spin_lock_irqsave(&pcikbd_lock, flags); + + if (!poll_aux_status()) { aux_count--; - aux_end_atomic(); + spin_unlock_irqrestore(&pcikbd_lock, flags); return -EBUSY; } queue->head = queue->tail = 0; /* Flush input queue */ @@ -798,9 +798,10 @@ static int aux_open(struct inode * inode, struct file * file) aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */ poll_aux_status(); - aux_end_atomic(); - aux_ready = 0; + spin_unlock_irqrestore(&pcikbd_lock, flags); + + return 0; } @@ -812,23 +813,35 @@ static ssize_t aux_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) { ssize_t retval = 0; + unsigned long flags; if (count) { ssize_t written = 0; - aux_start_atomic(); + spin_lock_irqsave(&pcikbd_lock, flags); + do { char c; + + spin_unlock_irqrestore(&pcikbd_lock, flags); + + get_user(c, buffer++); + + spin_lock_irqsave(&pcikbd_lock, flags); + if (!poll_aux_status()) break; - pcimouse_outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_WRITE_MOUSE, + pcimouse_iobase + KBD_CNTL_REG); if (!poll_aux_status()) break; - get_user(c, buffer++); + pcimouse_outb(c, pcimouse_iobase + KBD_DATA_REG); written++; } while (--count); - aux_end_atomic(); + + spin_unlock_irqrestore(&pcikbd_lock, flags); + retval = -EIO; if (written) { retval = written; @@ -872,7 +885,6 @@ repeat: put_user(c, buffer++); i--; } - aux_ready = !queue_empty(); if (count-i) { file->f_dentry->d_inode->i_atime = CURRENT_TIME; return count-i; @@ -885,7 +897,7 @@ repeat: static unsigned int aux_poll(struct file *file, poll_table * wait) { poll_wait(file, &queue->proc_list, wait); - if (aux_ready) + if (!queue_empty()) return POLLIN | POLLRDNORM; return 0; } @@ -972,7 +984,9 @@ found: pckbd_read_mask = AUX_STAT_OBF; misc_register(&psaux_mouse); - aux_start_atomic(); + + spin_lock_irq(&pcikbd_lock); + pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG); aux_write_ack(AUX_RESET); aux_write_ack(AUX_SET_SAMPLE); @@ -987,7 +1001,8 @@ found: poll_aux_status(); pcimouse_outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG); poll_aux_status(); - aux_end_atomic(); + + spin_unlock_irq(&pcikbd_lock); return 0; diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index b2fc1ffc3..28bcd6919 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.41 2000/03/13 03:54:17 davem Exp $ +/* $Id: sab82532.c,v 1.44 2000/04/26 09:36:32 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -176,12 +176,22 @@ static struct ebrg_struct ebrg_table[] = { #define NR_EBRG_VALUES (sizeof(ebrg_table)/sizeof(struct ebrg_struct)) -#define SAB82532_MAX_TEC_DELAY 2000 /* 2 ms */ +#define SAB82532_MAX_TEC_TIMEOUT 200000 /* 1 character time (at 50 baud) */ +#define SAB82532_MAX_CEC_TIMEOUT 50000 /* 2.5 TX CLKs (at 50 baud) */ static __inline__ void sab82532_tec_wait(struct sab82532 *info) { - int count = SAB82532_MAX_TEC_DELAY; - while ((readb(&info->regs->r.star) & SAB82532_STAR_TEC) && --count) + int timeout = info->tec_timeout; + + while ((readb(&info->regs->r.star) & SAB82532_STAR_TEC) && --timeout) + udelay(1); +} + +static __inline__ void sab82532_cec_wait(struct sab82532 *info) +{ + int timeout = info->cec_timeout; + + while ((readb(&info->regs->r.star) & SAB82532_STAR_CEC) && --timeout) udelay(1); } @@ -209,8 +219,7 @@ static __inline__ void sab82532_start_tx(struct sab82532 *info) } /* Issue a Transmit Frame command. */ - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr); out: @@ -277,8 +286,7 @@ static void batten_down_hatches(struct sab82532 *info) tmp = readb(&info->regs->rw.rfc); tmp &= ~(SAB82532_RFC_RFDF); writeb(tmp, &info->regs->rw.rfc); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); #ifndef __sparc_v9__ @@ -293,8 +301,7 @@ static void batten_down_hatches(struct sab82532 *info) * Reset FIFO to character + status mode. */ writeb(saved_rfc, &info->regs->w.rfc); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); } @@ -345,16 +352,19 @@ static inline void receive_chars(struct sab82532 *info, free_fifo++; } - if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { - count = readb(&info->regs->r.rbcl) & (info->recv_fifo_size - 1); - free_fifo++; - } - /* Issue a FIFO read command in case we where idle. */ if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_RFRD, &info->regs->w.cmdr); + /* Wait for command execution, to catch the TCD below. */ + sab82532_cec_wait(info); + } + + if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { + count = readb(&info->regs->r.rbcl) & (info->recv_fifo_size - 1); + if (count == 0) + count = info->recv_fifo_size; + free_fifo++; } if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { @@ -370,8 +380,7 @@ static inline void receive_chars(struct sab82532 *info, /* Issue Receive Message Complete command. */ if (free_fifo) { - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_RMC, &info->regs->w.cmdr); } @@ -451,8 +460,7 @@ static inline void transmit_chars(struct sab82532 *info, } /* Issue a Transmit Frame command. */ - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr); if (info->xmit_cnt < WAKEUP_CHARS) @@ -709,18 +717,14 @@ sab82532_init_line(struct sab82532 *info) /* * Wait for any commands or immediate characters */ - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); sab82532_tec_wait(info); /* * Clear the FIFO buffers. */ - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_XRES, &info->regs->w.cmdr); /* @@ -997,10 +1001,15 @@ static void change_speed(struct sab82532 *info) ebrg |= (ebrg_table[i].m << 6); info->baud = ebrg_table[i].baud; - if (info->baud) + if (info->baud) { info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud; - else + info->tec_timeout = (10 * 1000000) / info->baud; + info->cec_timeout = info->tec_timeout >> 2; + } else { info->timeout = 0; + info->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; + info->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; + } info->timeout += HZ / 50; /* Add .02 seconds of slop */ /* CTS flow control flags */ @@ -1037,8 +1046,7 @@ static void change_speed(struct sab82532 *info) SAB82532_ISR0_TIME; save_flags(flags); cli(); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); sab82532_tec_wait(info); writeb(dafo, &info->regs->w.dafo); writeb(ebrg & 0xff, &info->regs->w.bgr); @@ -2092,7 +2100,7 @@ int sab82532_read_proc(char *page, char **start, off_t off, int count, done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -2163,7 +2171,7 @@ static void __init sab82532_kgdb_hook(int line) static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.41 $"; + char *revision = "$Revision: 1.44 $"; char *version, *p; version = strchr(revision, ' '); @@ -2196,7 +2204,11 @@ int __init sab82532_init(void) memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; +#ifdef CONFIG_DEVFS_FS serial_driver.name = "tts/%d"; +#else + serial_driver.name = "ttyS"; +#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + su_num_ports; serial_driver.num = NR_PORTS; @@ -2267,6 +2279,8 @@ int __init sab82532_init(void) info->custom_divisor = 16; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; + info->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; + info->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; info->x_char = 0; info->event = 0; info->blocked_open = 0; @@ -2550,8 +2564,7 @@ sab82532_console_setup(struct console *con, char *options) info->flags |= ASYNC_CHECK_CD; save_flags(flags); cli(); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); sab82532_tec_wait(info); writeb(dafo, &info->regs->w.dafo); writeb(ebrg & 0xff, &info->regs->w.bgr); diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c index a691db430..6df7d9911 100644 --- a/drivers/sbus/char/su.c +++ b/drivers/sbus/char/su.c @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.37 2000/03/13 03:54:15 davem Exp $ +/* $Id: su.c,v 1.38 2000/04/22 00:45:16 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2204,7 +2204,7 @@ int su_read_proc(char *page, char **start, off_t off, int count, done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -2223,7 +2223,7 @@ done: */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.37 $"; + char *revision = "$Revision: 1.38 $"; char *version, *p; version = strchr(revision, ' '); diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index 91bf24a18..56bbe4035 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -24,6 +24,7 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/sysrq.h> +#include <linux/spinlock.h> #include <linux/devfs_fs_kernel.h> #include <asm/kbio.h> @@ -90,6 +91,8 @@ int keyboard_wait_for_keypress(struct console *co) return 0; } +static spinlock_t sunkbd_lock = SPIN_LOCK_UNLOCKED; + /* * global state includes the following, and various static variables * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. @@ -255,6 +258,7 @@ static unsigned char sunkbd_clickp; static void nop_kbd_put_char(unsigned char c) { } static void (*kbd_put_char)(unsigned char) = nop_kbd_put_char; +/* Must be invoked under sunkbd_lock. */ static inline void send_cmd(unsigned char c) { kbd_put_char(c); @@ -429,6 +433,7 @@ int sun_getkeycode(unsigned int scancode) e0_keys[scancode - 128]; } +static void __sunkbd_inchar(unsigned char ch, struct pt_regs *regs); void sunkbd_inchar(unsigned char ch, struct pt_regs *regs); static void keyboard_timer (unsigned long ignored); @@ -443,16 +448,17 @@ keyboard_timer (unsigned long ignored) { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&sunkbd_lock, flags); /* Auto repeat: send regs = 0 to indicate autorepeat */ - sunkbd_inchar (last_keycode, 0); + __sunkbd_inchar (last_keycode, 0); del_timer (&auto_repeat_timer); if (kbd_rate_ticks) { auto_repeat_timer.expires = jiffies + kbd_rate_ticks; add_timer (&auto_repeat_timer); } - restore_flags(flags); + + spin_unlock_irqrestore(&sunkbd_lock, flags); } #ifndef CONFIG_PCI @@ -460,8 +466,10 @@ DECLARE_TASKLET_DISABLED(keyboard_tasklet, sun_kbd_bh, 0); #endif /* #define SKBD_DEBUG */ -/* This is our keyboard 'interrupt' routine. */ -void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) +/* This is our keyboard 'interrupt' routine. + * Must run under sunkbd_lock. + */ +static void __sunkbd_inchar(unsigned char ch, struct pt_regs *regs) { unsigned char keycode; char up_flag; /* 0 or SUNKBD_UBIT */ @@ -612,6 +620,15 @@ out: tasklet_schedule(&keyboard_tasklet); } +void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) +{ + unsigned long flags; + + spin_lock_irqsave(&sunkbd_lock, flags); + __sunkbd_inchar(ch, regs); + spin_unlock_irqrestore(&sunkbd_lock, flags); +} + static void put_queue(int ch) { wake_up(&keypress_wait); @@ -1164,15 +1181,21 @@ static inline unsigned char getleds(void){ static unsigned char sunkbd_ledstate = 0xff; /* undefined */ void sun_kbd_bh(unsigned long dummy) { - unsigned char leds = getleds(); - unsigned char kbd_leds = vcleds_to_sunkbd(leds); + unsigned long flags; + unsigned char leds, kbd_leds; + + spin_lock_irqsave(&sunkbd_lock, flags); + leds = getleds(); + kbd_leds = vcleds_to_sunkbd(leds); if (kbd_leds != sunkbd_ledstate) { ledstate = leds; sunkbd_ledstate = kbd_leds; send_cmd(SKBDCMD_SETLED); send_cmd(kbd_leds); } + + spin_unlock_irqrestore(&sunkbd_lock, flags); } /* Support for keyboard "beeps". */ @@ -1180,7 +1203,11 @@ void sun_kbd_bh(unsigned long dummy) /* Timer routine to turn off the beep after the interval expires. */ static void sunkbd_kd_nosound(unsigned long __unused) { + unsigned long flags; + + spin_lock_irqsave(&sunkbd_lock, flags); send_cmd(SKBDCMD_BELLOFF); + spin_unlock_irqrestore(&sunkbd_lock, flags); } /* @@ -1195,8 +1222,7 @@ static void sunkbd_kd_mksound(unsigned int hz, unsigned int ticks) static struct timer_list sound_timer = { NULL, NULL, 0, 0, sunkbd_kd_nosound }; - save_flags(flags); - cli(); + spin_lock_irqsave(&sunkbd_lock, flags); del_timer(&sound_timer); @@ -1209,7 +1235,7 @@ static void sunkbd_kd_mksound(unsigned int hz, unsigned int ticks) } else send_cmd(SKBDCMD_BELLOFF); - restore_flags(flags); + spin_unlock_irqrestore(&sunkbd_lock, flags); } extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); @@ -1260,6 +1286,7 @@ int __init sun_kbd_init(void) #define KBD_QSIZE 32 static Firm_event kbd_queue [KBD_QSIZE]; static int kbd_head, kbd_tail; +static spinlock_t kbd_queue_lock = SPIN_LOCK_UNLOCKED; char kbd_opened; static int kbd_active = 0; static DECLARE_WAIT_QUEUE_HEAD(kbd_wait); @@ -1268,16 +1295,22 @@ static struct fasync_struct *kb_fasync; void push_kbd (int scan) { - int next = (kbd_head + 1) % KBD_QSIZE; + unsigned long flags; + int next; if (scan == KBD_IDLE) return; + + spin_lock_irqsave(&kbd_queue_lock, flags); + next = (kbd_head + 1) % KBD_QSIZE; if (next != kbd_tail){ kbd_queue [kbd_head].id = scan & KBD_KEYMASK; kbd_queue [kbd_head].value=scan & KBD_UP ? VKEY_UP : VKEY_DOWN; kbd_queue [kbd_head].time = xtime; kbd_head = next; } + spin_unlock_irqrestore(&kbd_queue_lock, flags); + if (kb_fasync) kill_fasync (kb_fasync, SIGIO, POLL_IN); wake_up_interruptible (&kbd_wait); @@ -1287,6 +1320,7 @@ static ssize_t kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); + unsigned long flags; char *end, *p; /* Return EWOULDBLOCK, because this is what the X server expects */ @@ -1294,9 +1328,11 @@ kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos) if (f->f_flags & O_NONBLOCK) return -EWOULDBLOCK; add_wait_queue (&kbd_wait, &wait); - while (kbd_head == kbd_tail && !signal_pending(current)) { - current->state = TASK_INTERRUPTIBLE; - schedule (); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (kbd_head == kbd_tail && !signal_pending(current)) { + schedule(); + goto repeat; } current->state = TASK_RUNNING; remove_wait_queue (&kbd_wait, &wait); @@ -1304,29 +1340,40 @@ kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos) /* There is data in the keyboard, fill the user buffer */ end = buffer+count; p = buffer; + spin_lock_irqsave(&kbd_queue_lock, flags); for (; p < end && kbd_head != kbd_tail;){ + Firm_event this_event = kbd_queue[kbd_tail]; + + kbd_tail = (kbd_tail + 1) % KBD_QSIZE; + + spin_unlock_irqrestore(&kbd_queue_lock, flags); + #ifdef CONFIG_SPARC32_COMPAT if (current->thread.flags & SPARC_FLAG_32BIT) { - copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], - sizeof(Firm_event)-sizeof(struct timeval), -EFAULT); + copy_to_user_ret((Firm_event *)p, &this_event, + sizeof(Firm_event)-sizeof(struct timeval), + -EFAULT); p += sizeof(Firm_event)-sizeof(struct timeval); - __put_user_ret(kbd_queue[kbd_tail].time.tv_sec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT); p += sizeof(u32); - __put_user_ret(kbd_queue[kbd_tail].time.tv_usec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT); p += sizeof(u32); } else #endif { - copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], + copy_to_user_ret((Firm_event *)p, &this_event, sizeof(Firm_event), -EFAULT); p += sizeof (Firm_event); } #ifdef KBD_DEBUG - printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN"); + printk ("[%s]", this_event.value == VKEY_UP ? "UP" : "DOWN"); #endif - kbd_tail++; - kbd_tail %= KBD_QSIZE; + + spin_lock_irqsave(&kbd_queue_lock, flags); } + + spin_unlock_irqrestore(&kbd_queue_lock, flags); + return p-buffer; } @@ -1387,7 +1434,9 @@ kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) switch (c) { case SKBDCMD_CLICK: case SKBDCMD_NOCLICK: + spin_lock_irq(&sunkbd_lock); send_cmd(c); + spin_unlock_irq(&sunkbd_lock); return 0; case SKBDCMD_BELLON: kd_mksound(1,0); @@ -1469,7 +1518,11 @@ kbd_open (struct inode *i, struct file *f) return 0; kbd_opened = fg_console + 1; + + spin_lock_irq(&kbd_queue_lock); kbd_head = kbd_tail = 0; + spin_unlock_irq(&kbd_queue_lock); + return 0; } @@ -1537,6 +1590,8 @@ void __init keyboard_zsinit(void (*put_char)(unsigned char)) if(sunkbd_type == SUNKBD_TYPE2) sunkbd_clickp = 0; + spin_lock_irq(&sunkbd_lock); + if(sunkbd_clickp) { send_cmd(SKBDCMD_CLICK); printk("with keyclick\n"); @@ -1549,6 +1604,8 @@ void __init keyboard_zsinit(void (*put_char)(unsigned char)) send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */ send_cmd(SKBDCMD_SETLED); send_cmd(0x0); /* All off */ + spin_unlock_irq(&sunkbd_lock); + /* Register the /dev/kbd interface */ devfs_register (NULL, "kbd", 0, DEVFS_FL_NONE, KBD_MAJOR, 0, diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c index f1641a33a..03869c52a 100644 --- a/drivers/sbus/char/sunmouse.c +++ b/drivers/sbus/char/sunmouse.c @@ -48,6 +48,7 @@ #include <linux/miscdevice.h> #include <linux/mm.h> #include <linux/poll.h> +#include <linux/spinlock.h> #include <linux/init.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -69,13 +70,13 @@ struct sun_mouse { unsigned char prev_state; /* Previous button state */ int delta_x; /* Current delta-x */ int delta_y; /* Current delta-y */ - int ready; /* set if there if data is available */ int active; /* set if device is open */ int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */ wait_queue_head_t proc_list; struct fasync_struct *fasync; /* The event/stream queue */ + spinlock_t lock; unsigned int head; unsigned int tail; union { @@ -96,14 +97,22 @@ extern void mouse_put_char(char ch); static int push_event (Firm_event *ev) { - int next = (sunmouse.head + 1) % EV_SIZE; + unsigned long flags; + int next, ret; - if (next != sunmouse.tail){ + spin_lock_irqsave(&sunmouse.lock, flags); + + next = (sunmouse.head + 1) % EV_SIZE; + ret = 0; + if (next != sunmouse.tail) { sunmouse.queue.ev [sunmouse.head] = *ev; sunmouse.head = next; - return 1; + ret = 1; } - return 0; + + spin_unlock_irqrestore(&sunmouse.lock, flags); + + return ret; } static int @@ -112,29 +121,32 @@ queue_empty (void) return sunmouse.head == sunmouse.tail; } -static Firm_event * -get_from_queue (void) +/* Must be invoked under the sunmouse.lock */ +static void get_from_queue (Firm_event *p) { - Firm_event *result; - - result = &sunmouse.queue.ev [sunmouse.tail]; + *p = sunmouse.queue.ev [sunmouse.tail]; sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE; - return result; } static void push_char (char c) { - int next = (sunmouse.head + 1) % STREAM_SIZE; + unsigned long flags; + int next; + + spin_lock_irqsave(&sunmouse.lock, flags); - if (next != sunmouse.tail){ + next = (sunmouse.head + 1) % STREAM_SIZE; + if (next != sunmouse.tail) { #ifdef SMOUSE_DEBUG printk("P<%02x>\n", (unsigned char)c); #endif sunmouse.queue.stream [sunmouse.head] = c; sunmouse.head = next; } - sunmouse.ready = 1; + + spin_unlock_irqrestore(&sunmouse.lock, flags); + if (sunmouse.fasync) kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible (&sunmouse.proc_list); @@ -325,24 +337,26 @@ sun_mouse_inbyte(unsigned char byte, int is_break) sunmouse.byte = 69; /* What could cause this? */ return; }; - if (!gen_events){ + + if (!gen_events) { push_char (~sunmouse.button_state & 0x87); push_char (sunmouse.delta_x); push_char (sunmouse.delta_y); return; } + d = bstate ^ pstate; pstate = bstate; - if (d){ - if (d & BUTTON_LEFT){ + if (d) { + if (d & BUTTON_LEFT) { ev.id = MS_LEFT; ev.value = bstate & BUTTON_LEFT; } - if (d & BUTTON_RIGHT){ + if (d & BUTTON_RIGHT) { ev.id = MS_RIGHT; ev.value = bstate & BUTTON_RIGHT; } - if (d & BUTTON_MIDDLE){ + if (d & BUTTON_MIDDLE) { ev.id = MS_MIDDLE; ev.value = bstate & BUTTON_MIDDLE; } @@ -350,25 +364,24 @@ sun_mouse_inbyte(unsigned char byte, int is_break) ev.value = ev.value ? VKEY_DOWN : VKEY_UP; pushed += push_event (&ev); } - if (sunmouse.delta_x){ + if (sunmouse.delta_x) { ev.id = LOC_X_DELTA; ev.time = xtime; ev.value = sunmouse.delta_x; pushed += push_event (&ev); sunmouse.delta_x = 0; } - if (sunmouse.delta_y){ + if (sunmouse.delta_y) { ev.id = LOC_Y_DELTA; ev.time = xtime; ev.value = sunmouse.delta_y; pushed += push_event (&ev); } - if(pushed != 0) { + if (pushed != 0) { /* We just completed a transaction, wake up whoever is awaiting * this event. */ - sunmouse.ready = 1; if (sunmouse.fasync) kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible(&sunmouse.proc_list); @@ -379,9 +392,9 @@ sun_mouse_inbyte(unsigned char byte, int is_break) static int sun_mouse_open(struct inode * inode, struct file * file) { - if(sunmouse.active++) + if (sunmouse.active++) return 0; - sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0; + sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; sunmouse.vuid_mode = VUID_NATIVE; return 0; @@ -401,9 +414,7 @@ static int sun_mouse_close(struct inode *inode, struct file *file) { sun_mouse_fasync (-1, file, 0); - if (--sunmouse.active) - return 0; - sunmouse.ready = 0; + sunmouse.active--; return 0; } @@ -419,49 +430,57 @@ sun_mouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); + unsigned long flags; - if (queue_empty ()){ + if (queue_empty ()) { if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; add_wait_queue (&sunmouse.proc_list, &wait); - while (queue_empty () && !signal_pending(current)) { - current->state = TASK_INTERRUPTIBLE; - schedule (); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; } current->state = TASK_RUNNING; remove_wait_queue (&sunmouse.proc_list, &wait); } - if (gen_events){ + if (gen_events) { char *p = buffer, *end = buffer+count; + spin_lock_irqsave(&sunmouse.lock, flags); while (p < end && !queue_empty ()){ + Firm_event this_event; + + get_from_queue(&this_event); + spin_unlock_irqrestore(&sunmouse.lock, flags); + #ifdef CONFIG_SPARC32_COMPAT if (current->thread.flags & SPARC_FLAG_32BIT) { - Firm_event *q = get_from_queue(); - if ((end - p) < ((sizeof(Firm_event) - sizeof(struct timeval) + (sizeof(u32) * 2)))) break; - copy_to_user_ret((Firm_event *)p, q, + copy_to_user_ret((Firm_event *)p, &this_event, sizeof(Firm_event)-sizeof(struct timeval), -EFAULT); p += sizeof(Firm_event)-sizeof(struct timeval); - __put_user_ret(q->time.tv_sec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT); p += sizeof(u32); - __put_user_ret(q->time.tv_usec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT); p += sizeof(u32); } else #endif { if ((end - p) < sizeof(Firm_event)) break; - copy_to_user_ret((Firm_event *)p, get_from_queue(), + copy_to_user_ret((Firm_event *)p, &this_event, sizeof(Firm_event), -EFAULT); p += sizeof (Firm_event); } + spin_lock_irqsave(&sunmouse.lock, flags); } - sunmouse.ready = !queue_empty (); + spin_unlock_irqrestore(&sunmouse.lock, flags); file->f_dentry->d_inode->i_atime = CURRENT_TIME; return p-buffer; } else { @@ -470,9 +489,24 @@ sun_mouse_read(struct file *file, char *buffer, if (count < limit) limit = count; for (c = 0; c < limit; c++) { - put_user(sunmouse.queue.stream[sunmouse.tail], buffer); + unsigned char val; + int empty = 0; + + spin_lock_irqsave(&sunmouse.lock, flags); + if (queue_empty()) { + empty = 1; + val = 0; + } else { + val = sunmouse.queue.stream[sunmouse.tail]; + sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; + } + spin_unlock_irqrestore(&sunmouse.lock, flags); + + if (empty) + break; + + put_user(val, buffer); buffer++; - sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; } while (c < count) { if (c >= 5) @@ -481,7 +515,6 @@ sun_mouse_read(struct file *file, char *buffer, buffer++; c++; } - sunmouse.ready = !queue_empty(); file->f_dentry->d_inode->i_atime = CURRENT_TIME; return c; } @@ -494,7 +527,7 @@ sun_mouse_read(struct file *file, char *buffer, static unsigned int sun_mouse_poll(struct file *file, poll_table *wait) { poll_wait(file, &sunmouse.proc_list, wait); - if(sunmouse.ready) + if(!queue_empty()) return POLLIN | POLLRDNORM; return 0; } @@ -516,8 +549,11 @@ sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsig int value; get_user_ret(value, (int *)arg, -EFAULT); + + spin_lock_irq(&sunmouse.lock); sunmouse.vuid_mode = value; sunmouse.head = sunmouse.tail = 0; + spin_unlock_irq(&sunmouse.lock); } else return -EINVAL; break; @@ -556,10 +592,11 @@ void sun_mouse_zsinit(void) { printk("Sun Mouse-Systems mouse driver version 1.00\n"); - sunmouse.ready = sunmouse.active = 0; + sunmouse.active = 0; misc_register (&sun_mouse_mouse); sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; init_waitqueue_head(&sunmouse.proc_list); + spin_lock_init(&sunmouse.lock); sunmouse.byte = 69; } diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index 868193747..fb687102c 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.56 2000/03/12 04:02:11 davem Exp $ +/* $Id: zs.c,v 1.57 2000/04/26 09:36:32 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1928,7 +1928,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) static void show_serial_version(void) { - char *revision = "$Revision: 1.56 $"; + char *revision = "$Revision: 1.57 $"; char *version, *p; version = strchr(revision, ' '); @@ -2415,7 +2415,11 @@ int __init zs_init(void) memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; +#ifdef CONFIG_DEVFS_FS serial_driver.name = "tts/%d"; +#else + serial_driver.name = "ttyS"; +#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = NUM_CHANNELS; |