diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /drivers/sbus/char | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff) |
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too
o Upgrade to 2.1.89.
Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'drivers/sbus/char')
-rw-r--r-- | drivers/sbus/char/.cvsignore | 1 | ||||
-rw-r--r-- | drivers/sbus/char/Config.in | 6 | ||||
-rw-r--r-- | drivers/sbus/char/Makefile | 34 | ||||
-rw-r--r-- | drivers/sbus/char/creator.c | 4 | ||||
-rw-r--r-- | drivers/sbus/char/flash.c | 232 | ||||
-rw-r--r-- | drivers/sbus/char/mach64.c | 149 | ||||
-rw-r--r-- | drivers/sbus/char/mach64.h | 8 | ||||
-rw-r--r-- | drivers/sbus/char/openprom.c | 3 | ||||
-rw-r--r-- | drivers/sbus/char/pcicons.c | 69 | ||||
-rw-r--r-- | drivers/sbus/char/pcikbd.c | 296 | ||||
-rw-r--r-- | drivers/sbus/char/pcikbd.h | 4 | ||||
-rw-r--r-- | drivers/sbus/char/rtc.c | 5 | ||||
-rw-r--r-- | drivers/sbus/char/sab82532.c | 522 | ||||
-rw-r--r-- | drivers/sbus/char/sbuscons.c | 25 | ||||
-rw-r--r-- | drivers/sbus/char/su.c | 26 | ||||
-rw-r--r-- | drivers/sbus/char/suncons.c | 15 | ||||
-rw-r--r-- | drivers/sbus/char/sunfb.c | 12 | ||||
-rw-r--r-- | drivers/sbus/char/sunkbd.c | 74 | ||||
-rw-r--r-- | drivers/sbus/char/sunkbd.h | 26 | ||||
-rw-r--r-- | drivers/sbus/char/sunkbdmap.c | 33 | ||||
-rw-r--r-- | drivers/sbus/char/sunmouse.c | 32 | ||||
-rw-r--r-- | drivers/sbus/char/sunserial.c | 326 | ||||
-rw-r--r-- | drivers/sbus/char/sunserial.h | 61 | ||||
-rw-r--r-- | drivers/sbus/char/vfc_dev.c | 3 | ||||
-rw-r--r-- | drivers/sbus/char/zs.c | 835 |
25 files changed, 1886 insertions, 915 deletions
diff --git a/drivers/sbus/char/.cvsignore b/drivers/sbus/char/.cvsignore index 4671378ae..857dd22e9 100644 --- a/drivers/sbus/char/.cvsignore +++ b/drivers/sbus/char/.cvsignore @@ -1 +1,2 @@ .depend +.*.flags diff --git a/drivers/sbus/char/Config.in b/drivers/sbus/char/Config.in index 90ecfc49a..4a8832678 100644 --- a/drivers/sbus/char/Config.in +++ b/drivers/sbus/char/Config.in @@ -19,6 +19,7 @@ if [ "$CONFIG_SUN_FB_DISPLAY" = "n" ]; then fbs=$fbs$SUN_FB_CGFOURTEEN fbs=$fbs$SUN_FB_LEO fbs=$fbs$TADPOLE_FB_WEITEK + fbs=$fbs$SUN_FB_CREATOR if [ "$fbs" = "nnnnnnnn" ]; then echo "Warning: You have excluded ALL FB Support" echo "Notice: Enabling Generic AutoResolution" @@ -41,7 +42,10 @@ fi comment 'Misc Linux/SPARC drivers' tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC -tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532 +if [ "$ARCH" = "sparc64" ]; then + tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532 + tristate 'OBP Flash Device support' CONFIG_OBP_FLASH +fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Bidirectional parallel port support (EXPERIMENTAL)' CONFIG_SUN_BPP diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index dfcc7afe3..5251d5090 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -51,13 +51,35 @@ endif O_TARGET := sunchar.o O_OBJ := ${FB_OBJS} suncons.o sbuscons.o pcicons.o sunfb.o -O_OBJS := ${O_OBJ} sunkbd.o sunkeymap.o sunmouse.o sunserial.o zs.o +O_OBJS := ${O_OBJ} sunkbd.o sunkbdmap.o sunmouse.o sunserial.o zs.o M_OBJS := ifeq ($(ARCH),sparc64) + +ifeq ($(CONFIG_PCI),y) + O_OBJS += su.o pcikbd.o + +ifeq ($(CONFIG_SAB82532),y) +O_OBJS += sab82532.o +else + ifeq ($(CONFIG_SAB82532),m) + M_OBJS += sab82532.o + endif endif +endif # eq($(CONFIG_PCI,y) + +ifeq ($(CONFIG_OBP_FLASH),y) +O_OBJS += flash.o +else + ifeq ($(CONFIG_OBP_FLASH),m) + M_OBJS += flash.o + endif +endif + +endif # eq($(ARCH),sparc64) + ifeq ($(CONFIG_SUN_OPENPROMIO),y) O_OBJS += openprom.o else @@ -90,14 +112,6 @@ else endif endif -ifeq ($(CONFIG_SAB82532),y) -O_OBJS += sab82532.o -else - ifeq ($(CONFIG_SAB82532),m) - M_OBJS += sab82532.o - endif -endif - # Add PCI console/fb drivers here. # ifeq ($(CONFIG_PCI),y) @@ -106,5 +120,7 @@ endif include $(TOPDIR)/Rules.make +sunkbdmap.o: sunkeymap.c + vfc.o: vfc_dev.o vfc_i2c.o $(LD) -r -o vfc.o vfc_dev.o vfc_i2c.o diff --git a/drivers/sbus/char/creator.c b/drivers/sbus/char/creator.c index 815e397e8..8b6ddf40f 100644 --- a/drivers/sbus/char/creator.c +++ b/drivers/sbus/char/creator.c @@ -1,4 +1,4 @@ -/* $Id: creator.c,v 1.12 1997/08/25 07:50:27 jj Exp $ +/* $Id: creator.c,v 1.13 1997/10/17 04:14:40 davem Exp $ * creator.c: Creator/Creator3D frame buffer driver * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -194,7 +194,7 @@ ffb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, unsigned long map_offset = 0; int i; int alignment; - struct vm_area_struct *vmm; + struct vm_area_struct *vmm = NULL; size = vma->vm_end - vma->vm_start; if (vma->vm_offset & ~PAGE_MASK) diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c new file mode 100644 index 000000000..ba67381a0 --- /dev/null +++ b/drivers/sbus/char/flash.c @@ -0,0 +1,232 @@ +/* $Id: flash.c,v 1.5 1997/11/01 10:22:13 ecd Exp $ + * flash.c: Allow mmap access to the OBP Flash, for OBP updates. + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/miscdevice.h> +#include <linux/malloc.h> +#include <linux/fcntl.h> +#include <linux/poll.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/sbus.h> +#include <asm/ebus.h> + +static struct { + unsigned long read_base; + unsigned long write_base; + unsigned long read_size; + unsigned long write_size; + unsigned long busy; +} flash; + +#define FLASH_MINOR 152 + +static int +flash_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long addr; + unsigned long size; + + if (vma->vm_offset & ~(PAGE_MASK)) + return -ENXIO; + + if (flash.read_base == flash.write_base) { + addr = __pa(flash.read_base); + size = flash.read_size; + } else { + if ((vma->vm_flags & VM_READ) && + (vma->vm_flags & VM_WRITE)) + return -EINVAL; + + if (vma->vm_flags & VM_READ) { + addr = __pa(flash.read_base); + size = flash.read_size; + } else if (vma->vm_flags & VM_WRITE) { + addr = __pa(flash.write_base); + size = flash.write_size; + } else + return -ENXIO; + } + + if (vma->vm_offset > size) + return -ENXIO; + addr += vma->vm_offset; + + if (vma->vm_end - (vma->vm_start + vma->vm_offset) > size) + size = vma->vm_end - (vma->vm_start + vma->vm_offset); + + pgprot_val(vma->vm_page_prot) &= ~(_PAGE_CACHE); + pgprot_val(vma->vm_page_prot) |= _PAGE_E; + vma->vm_flags |= (VM_SHM | VM_LOCKED); + + if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot)) + return -EAGAIN; + vma->vm_dentry = dget(file->f_dentry); + return 0; +} + +static long long +flash_llseek(struct file *file, long long offset, int origin) +{ + switch (origin) { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + if (file->f_pos > flash.read_size) + file->f_pos = flash.read_size; + break; + case 2: + file->f_pos = flash.read_size; + break; + default: + return -EINVAL; + } + return file->f_pos; +} + +static ssize_t +flash_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + unsigned long p = file->f_pos; + + if (count > flash.read_size - p) + count = flash.read_size - p; + + if (copy_to_user(buf, flash.read_base + p, count) < 0) + return -EFAULT; + + file->f_pos += count; + return count; +} + +static int +flash_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, (void *)&flash.busy) != 0) + return -EBUSY; + + MOD_INC_USE_COUNT; + return 0; +} + +static int +flash_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + flash.busy = 0; + return 0; +} + +static struct file_operations flash_fops = { + flash_llseek, + flash_read, + NULL, /* no write to the Flash, use mmap + * and play flash dependent tricks. + */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + flash_mmap, + flash_open, + flash_release +}; + +static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +__initfunc(int flash_init(void)) +#endif +{ + struct linux_sbus *sbus; + struct linux_sbus_device *sdev = 0; + struct linux_ebus *ebus; + struct linux_ebus_device *edev = 0; + struct linux_prom_registers regs[2]; + int len, err; + + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "flashprom")) { + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], + sdev->num_registers, sdev); + if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) { + flash.read_base = (unsigned long)sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + sdev->reg_addrs[0].reg_size, "flashprom", + sdev->reg_addrs[0].which_io, 0); + flash.read_size = sdev->reg_addrs[0].reg_size; + flash.write_base = flash.read_base; + flash.write_size = flash.read_size; + } else { + flash.read_base = (unsigned long)sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + sdev->reg_addrs[0].reg_size, "flashprom", + sdev->reg_addrs[0].which_io, 0); + flash.read_size = sdev->reg_addrs[0].reg_size; + flash.write_base = (unsigned long)sparc_alloc_io(sdev->reg_addrs[1].phys_addr, 0, + sdev->reg_addrs[1].reg_size, "flashprom", + sdev->reg_addrs[1].which_io, 0); + flash.write_size = sdev->reg_addrs[1].reg_size; + } + flash.busy = 0; + break; + } + } + if (!sdev) { +#ifdef CONFIG_PCI + for_all_ebusdev(edev, ebus) + if (!strcmp(edev->prom_name, "flashprom")) + break; + if (!edev) + return -ENODEV; + + len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs)); + if (len != sizeof(regs)) { + printk("flash: Strange reg property size %d\n", len); + return -ENODEV; + } + + flash.read_base = edev->base_address[0]; + flash.read_size = regs[0].reg_size; + flash.write_base = edev->base_address[1]; + flash.write_size = regs[1].reg_size; + flash.busy = 0; + +#else + return -ENODEV; +#endif + } + + printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n", + __pa(flash.read_base), flash.read_size, + __pa(flash.write_base), flash.write_size); + + err = misc_register(&flash_dev); + if (err) { + printk(KERN_ERR "flash: unable to get misc minor\n"); + return err; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + misc_deregister(&flash_dev); +} +#endif diff --git a/drivers/sbus/char/mach64.c b/drivers/sbus/char/mach64.c index c3c562306..05ed175d3 100644 --- a/drivers/sbus/char/mach64.c +++ b/drivers/sbus/char/mach64.c @@ -1,4 +1,4 @@ -/* $Id: mach64.c,v 1.8 1997/08/25 07:50:34 jj Exp $ +/* $Id: mach64.c,v 1.11 1997/10/17 04:13:35 davem Exp $ * mach64.c: Ultra/PCI Mach64 console driver. * * Just about all of this is from the PPC/mac driver, see that for @@ -8,6 +8,7 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include <linux/config.h> /* for CONFIG_CHIP_ID */ #include <linux/kernel.h> #include <linux/types.h> #include <linux/pci.h> @@ -22,13 +23,18 @@ #include <asm/pbm.h> #include <asm/fbio.h> #include <asm/sbus.h> +#include <asm/pgtable.h> #include "pcicons.h" #include "mach64.h" #include "fb.h" +static unsigned int mach64_pci_membase; +static unsigned int mach64_pci_iobase; + +#define MACH64_LE_FBOFF 0x000000 #define MACH64_REGOFF 0x7ffc00 -#define MACH64_FBOFF 0x800000 +#define MACH64_BE_FBOFF 0x800000 static inline void mach64_waitq(int entries) { @@ -69,7 +75,35 @@ static int mach64_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, fbinfo_t *fb) { - return -ENOSYS; + unsigned long addr, size; + + size = vma->vm_end - vma->vm_start; + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; + + if (vma->vm_offset == mach64_pci_iobase) { + addr = __pa(pcivga_iobase); + size = PAGE_SIZE; + } else if (vma->vm_offset >= (mach64_pci_membase + 0x800000)) { + addr = __pa(pcivga_membase) - mach64_pci_membase + + vma->vm_offset; + pgprot_val(vma->vm_page_prot) |= _PAGE_IE; + } else if (vma->vm_offset >= mach64_pci_membase) { + addr = __pa(pcivga_membase) - mach64_pci_membase + + vma->vm_offset; + } else { + return -EINVAL; + } + + pgprot_val(vma->vm_page_prot) &= ~(_PAGE_CACHE); + pgprot_val(vma->vm_page_prot) |= _PAGE_E; + vma->vm_flags |= (VM_SHM | VM_LOCKED); + + if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot)) + return -EAGAIN; + + vma->vm_dentry = dget(file->f_dentry); + return 0; } static void @@ -113,11 +147,29 @@ mach64_unblank(fbinfo_t *fb) static struct mach64_info mach64; +void mach64_test(fbinfo_t *fb) +{ + unsigned int x; + int i; + + for (i = 0; i < mach64.total_vram; i += 4) + writel(i, pcivga_membase + i); + + for (i = 0; i < mach64.total_vram; i += 4) + if ((x = readl(pcivga_membase + i)) != i) { + printk("vga mem read error @ %08x: exp %x, rd %x\n", + i, i, x); + i = (i & ~(0xffff)) + 0x10000; + } +} + int mach64_init(fbinfo_t *fb) { struct pci_dev *pdev; struct pcidev_cookie *cookie; + struct linux_pbm_info *pbm; unsigned long addr; + unsigned int tmp; memset(&mach64, 0, sizeof(mach64)); for(pdev = pci_devices; pdev; pdev = pdev->next) { @@ -148,49 +200,86 @@ int mach64_init(fbinfo_t *fb) prom_halt(); } + pcibios_read_config_dword(pdev->bus->number, pdev->devfn, + PCI_BASE_ADDRESS_0, &mach64_pci_membase); + mach64_pci_membase &= PCI_BASE_ADDRESS_MEM_MASK; + + pcibios_read_config_dword(pdev->bus->number, pdev->devfn, + PCI_BASE_ADDRESS_1, &mach64_pci_iobase); + mach64_pci_iobase &= PCI_BASE_ADDRESS_IO_MASK; + printk("mach64_init: IOBASE[%016lx] MEMBASE[%016lx]\n", pcivga_iobase, pcivga_membase); - cookie = (struct pcidev_cookie *)pdev->sysdata; + cookie = pdev->sysdata; + pbm = cookie->pbm; + fb->prom_node = cookie->prom_node; - fb->proc_entry.node = cookie->pbm->prom_node; + fb->proc_entry.node = pbm->prom_node; fb->type.fb_type = FBTYPE_PCI_MACH64; fb->type.fb_cmsize = 256; fb->info.private = (void *)&mach64; - fb->base = pcivga_membase + MACH64_FBOFF; - - switch(pcivga_readl(MACH64_REGOFF + MEM_CNTL) & MEM_SIZE_ALIAS) { - case MEM_SIZE_512K: - mach64.total_vram = 0x80000; - break; - case MEM_SIZE_1M: - mach64.total_vram = 0x100000; - break; - case MEM_SIZE_2M: - mach64.total_vram = 0x200000; - break; - case MEM_SIZE_4M: - mach64.total_vram = 0x400000; - break; - case MEM_SIZE_6M: - mach64.total_vram = 0x600000; - break; - case MEM_SIZE_8M: - mach64.total_vram = 0x800000; - break; - default: - mach64.total_vram = 0x80000; - break; - } + fb->base = pcivga_membase + MACH64_BE_FBOFF; if ((pcivga_readl(MACH64_REGOFF + CONFIG_CHIP_ID) & CFG_CHIP_TYPE) == MACH64_VT_ID) mach64.flags |= MACH64_MASK_VT; + /* + * Fix the PROM's idea of MEM_CNTL settings... + */ + tmp = pcivga_readl(MACH64_REGOFF + MEM_CNTL); + switch (tmp & 0xf) { + case 3: + tmp = (tmp & ~(0xf)) | 2; + break; + case 7: + tmp = (tmp & ~(0xf)) | 3; + break; + case 9: + tmp = (tmp & ~(0xf)) | 4; + break; + case 11: + tmp = (tmp & ~(0xf)) | 5; + break; + default: + break; + } + tmp &= ~(0x00f00000); + pcivga_writel(tmp, MACH64_REGOFF + MEM_CNTL); + + switch(tmp & MEM_SIZE_ALIAS) { + case MEM_SIZE_512K: + mach64.total_vram = 0x80000; + break; + case MEM_SIZE_1M: + mach64.total_vram = 0x100000; + break; + case MEM_SIZE_2M: + mach64.total_vram = 0x200000; + break; + case MEM_SIZE_4M: + mach64.total_vram = 0x400000; + break; + case MEM_SIZE_6M: + mach64.total_vram = 0x600000; + break; + case MEM_SIZE_8M: + mach64.total_vram = 0x800000; + break; + default: + mach64.total_vram = 0x80000; + break; + } + printk("mach64_init: total_vram[%08x] is_vt_chip[%d]\n", mach64.total_vram, mach64.flags & MACH64_MASK_VT ? 1 : 0); +#if 0 + mach64_test(fb); +#endif + fb->mmap = mach64_mmap; fb->loadcmap = mach64_loadcmap; fb->ioctl = 0; diff --git a/drivers/sbus/char/mach64.h b/drivers/sbus/char/mach64.h index 8bf6be478..02593fa7b 100644 --- a/drivers/sbus/char/mach64.h +++ b/drivers/sbus/char/mach64.h @@ -1,4 +1,4 @@ -/* $Id: mach64.h,v 1.3 1997/08/24 12:13:07 ecd Exp $ +/* $Id: mach64.h,v 1.4 1997/10/04 08:51:30 ecd Exp $ * mach64.h: Ultra/PCI mach64 driver constants etc. * * Copyright 1997 David S. Miller (davem@caip.rutgers.edu) @@ -42,6 +42,9 @@ struct mach64_info { #define CRTC_FIFO 0x001e #define CRTC_EXT_DISP 0x001f +#define SHARED_CNTL 0x0030 /* Dword offset 0C */ +#define SHARED_MEM_CONFIG 0x0034 /* Dword offset 0D */ + #define OVR_CLR 0x0040 /* Dword offset 10 */ #define OVR_WID_LEFT_RIGHT 0x0044 /* Dword offset 11 */ #define OVR_WID_TOP_BOTTOM 0x0048 /* Dword offset 12 */ @@ -60,6 +63,7 @@ struct mach64_info { #define BUS_CNTL 0x00A0 /* Dword offset 28 */ +#define EXT_MEM_CNTL 0x00AC /* Dword offset 2B */ #define MEM_CNTL 0x00B0 /* Dword offset 2C */ #define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 2D */ @@ -359,6 +363,8 @@ struct mach64_info { #define MEM_SIZE_6M 0x00000004 #define MEM_SIZE_8M 0x00000005 #define MEM_SIZE_ALIAS_GTB 0x0000000F +#define MEM_SIZE_512K_GTB 0x00000000 +#define MEM_SIZE_1M_GTB 0x00000001 #define MEM_SIZE_2M_GTB 0x00000003 #define MEM_SIZE_4M_GTB 0x00000007 #define MEM_SIZE_6M_GTB 0x00000009 diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 75b950071..6d09bfca4 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -526,8 +526,7 @@ static int openprom_ioctl(struct inode * inode, struct file * file, } } -static long long openprom_lseek(struct inode * inode, struct file * file, - long long offset, int origin) +static long long openprom_lseek(struct file * file, long long offset, int origin) { return -ESPIPE; } diff --git a/drivers/sbus/char/pcicons.c b/drivers/sbus/char/pcicons.c index 82c0df9aa..c20796e63 100644 --- a/drivers/sbus/char/pcicons.c +++ b/drivers/sbus/char/pcicons.c @@ -1,4 +1,4 @@ -/* $Id: pcicons.c,v 1.9 1997/08/28 02:23:24 ecd Exp $ +/* $Id: pcicons.c,v 1.10 1997/10/04 08:52:57 ecd Exp $ * pcicons.c: PCI specific probing and console operations layer. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -37,14 +37,9 @@ static int x_margin = 0; static int y_margin = 0; static int skip_bytes; -static void pci_cursor_blink(unsigned long); -static __u32 *cursor_screen_pos; -static __u32 cursor_bits; +static __u64 *cursor_screen_pos; +static __u64 cursor_bits[2]; static int cursor_pos = -1; -static int cursor_off = 1; -static struct timer_list pci_cursor_timer = { - NULL, NULL, 0, 0, pci_cursor_blink -}; extern int serial_console; @@ -219,52 +214,24 @@ static void pci_set_scrmem(int currcons, long offset) static void pci_invert_cursor(int cpos) { fbinfo_t *fb = &fbinfo[0]; - unsigned char color; - __u32 *screen, mask; - int i; - - del_timer(&pci_cursor_timer); + __u64 *screen; if (cpos == -1) { - if (cursor_off) - return; screen = cursor_screen_pos; - mask = cursor_bits; - } else { - screen = (__u32 *)(fb->base + fbuf_offset(cpos) - + 14 * fb->linebytes); - - color = CHARATTR_TO_SUNCOLOR( - vc_cons[fg_console].d->vc_color << 8); - - mask = (color ^ (color >> 4)) & 0x0f; - mask |= mask << 8; - mask |= mask << 16; - - cursor_screen_pos = screen; - cursor_bits = mask; - - pci_cursor_timer.expires = jiffies + (HZ >> 2); - add_timer(&pci_cursor_timer); - } - - for (i = 0; i < 2; i++) { - screen[0] ^= mask; - screen[1] ^= mask; - screen = (__u32 *)((unsigned long)screen + fb->linebytes); + *screen = cursor_bits[0]; + screen = (__u64 *)((unsigned long)screen + fb->linebytes); + *screen = cursor_bits[1]; + return; } -} -static void pci_cursor_blink(unsigned long ignored) -{ - unsigned long flags; + screen = (__u64 *)(fb->base + fbuf_offset(cpos) + 14 * fb->linebytes); + cursor_screen_pos = screen; - save_flags(flags); cli(); - if (cursor_pos != -1) { - pci_invert_cursor(cursor_pos); - cursor_off = 1 - cursor_off; - } - restore_flags(flags); + cursor_bits[0] = *screen; + *screen = 0x0000000000000000; + screen = (__u64 *)((unsigned long)screen + fb->linebytes); + cursor_bits[1] = *screen; + *screen = 0x0000000000000000; } static void pci_hide_cursor(void) @@ -275,11 +242,8 @@ static void pci_hide_cursor(void) return; save_flags(flags); cli(); - if (cursor_pos != -1) { + if (cursor_pos != -1) pci_invert_cursor(-1); - cursor_pos = -1; - } - cursor_off = 1; restore_flags(flags); } @@ -300,7 +264,6 @@ static void pci_set_cursor(int currcons) if (old_cursor != -1) pci_invert_cursor(-1); pci_invert_cursor(cursor_pos); - cursor_off = 0; } restore_flags(flags); } diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c index 8d90f85d6..31485aac8 100644 --- a/drivers/sbus/char/pcikbd.c +++ b/drivers/sbus/char/pcikbd.c @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.4 1997/09/05 22:59:53 ecd Exp $ +/* $Id: pcikbd.c,v 1.12 1997/12/27 16:28:27 jj Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -8,6 +8,7 @@ * to the original authors. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -19,6 +20,7 @@ #include <linux/random.h> #include <linux/miscdevice.h> #include <linux/kbd_ll.h> +#include <linux/delay.h> #include <linux/init.h> #include <asm/ebus.h> @@ -26,7 +28,6 @@ #include <asm/irq.h> #include <asm/io.h> #include <asm/uaccess.h> -#include <asm/keyboard.h> #include "pcikbd.h" #include "sunserial.h" @@ -35,6 +36,7 @@ static int kbd_node; static int beep_node; static unsigned long pcikbd_iobase = 0; +static unsigned long pcibeep_iobase = 0; static unsigned int pcikbd_irq; /* used only by send_data - set by keyboard_interrupt */ @@ -42,12 +44,31 @@ static volatile unsigned char reply_expected = 0; static volatile unsigned char acknowledge = 0; static volatile unsigned char resend = 0; +unsigned char pckbd_read_mask = KBD_STAT_OBF; + +extern int pcikbd_init(void); +extern void pci_compute_shiftstate(void); +extern int pci_setkeycode(unsigned int, unsigned int); +extern int pci_getkeycode(unsigned int); +extern void pci_setledstate(struct kbd_struct *, unsigned int); +extern unsigned char pci_getledstate(void); + +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); +} + static inline void kb_wait(void) { unsigned long start = jiffies; do { - if(!(inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF)) + if(!(pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF)) return; } while (jiffies - start < KBC_TIMEOUT); } @@ -167,6 +188,19 @@ static unsigned char e0_keys[128] = { 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ }; +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char pcikbd_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + static unsigned int prev_scancode = 0; int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode) @@ -268,25 +302,17 @@ pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned char status; - /* - * This IRQ might be shared with the 16550A serial chip, - * so we check dev_id to see if it was for us. - * (See also drivers/sbus/char/su.c). - */ - if (dev_id) - return; - - /* kbd_pt_regs = regs; */ - status = inb(pcikbd_iobase + KBD_STATUS_REG); + kbd_pt_regs = regs; + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); do { unsigned char scancode; - if(status & kbd_read_mask & KBD_STAT_MOUSE_OBF) + if(status & pckbd_read_mask & KBD_STAT_MOUSE_OBF) break; - scancode = inb(pcikbd_iobase + KBD_DATA_REG); + scancode = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); if((status & KBD_STAT_OBF) && do_acknowledge(scancode)) - /* handle_scancode(scancode) */; - status = inb(pcikbd_iobase + KBD_STATUS_REG); + handle_scancode(scancode); + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while(status & KBD_STAT_OBF); mark_bh(KEYBOARD_BH); } @@ -300,7 +326,7 @@ static int send_data(unsigned char data) kb_wait(); acknowledge = resend = 0; reply_expected = 1; - outb(data, pcikbd_iobase + KBD_DATA_REG); + pcikbd_outb(data, pcikbd_iobase + KBD_DATA_REG); start = jiffies; do { if(acknowledge) @@ -325,10 +351,10 @@ __initfunc(static int pcikbd_wait_for_input(void)) unsigned long start = jiffies; do { - status = inb(pcikbd_iobase + KBD_STATUS_REG); + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); if(!(status & KBD_STAT_OBF)) continue; - data = inb(pcikbd_iobase + KBD_DATA_REG); + data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); if(status & (KBD_STAT_GTO | KBD_STAT_PERR)) continue; return (data & 0xff); @@ -341,18 +367,55 @@ __initfunc(static void pcikbd_write(int address, int data)) int status; do { - status = inb(pcikbd_iobase + KBD_STATUS_REG); + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while (status & KBD_STAT_IBF); - outb(data, pcikbd_iobase + address); + pcikbd_outb(data, pcikbd_iobase + address); +} + +/* Timer routine to turn off the beep after the interval expires. */ +static void pcikbd_kd_nosound(unsigned long __unused) +{ + outl(0, pcibeep_iobase); } -__initfunc(static char *do_pcikbd_hwinit(void)) +/* + * Initiate a keyboard beep. If the frequency is zero, then we stop + * the beep. Any other frequency will start a monotone beep. The beep + * will be stopped by a timer after "ticks" jiffies. If ticks is 0, + * then we do not start a timer. + */ +static void pcikbd_kd_mksound(unsigned int hz, unsigned int ticks) +{ + unsigned long flags; + static struct timer_list sound_timer = { NULL, NULL, 0, 0, + pcikbd_kd_nosound }; + + save_flags(flags); cli(); + del_timer(&sound_timer); + if (hz) { + outl(1, pcibeep_iobase); + if (ticks) { + sound_timer.expires = jiffies + ticks; + add_timer(&sound_timer); + } + } else + outl(0, pcibeep_iobase); + restore_flags(flags); +} + +static void nop_kd_mksound(unsigned int hz, unsigned int ticks) +{ +} + +extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); + +__initfunc(static char *do_pcikbd_init_hw(void)) { while(pcikbd_wait_for_input() != -1) ; pcikbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); - if(pcikbd_wait_for_input() != 0xff) + if(pcikbd_wait_for_input() != 0x55) return "Keyboard failed self test"; pcikbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); @@ -388,23 +451,12 @@ __initfunc(static char *do_pcikbd_hwinit(void)) return NULL; /* success */ } -__initfunc(void pcikbd_hwinit(void)) -{ - char *msg; - - disable_irq(pcikbd_irq); - msg = do_pcikbd_hwinit(); - enable_irq(pcikbd_irq); - - if(msg) - printk("8042: keyboard init failure [%s]\n", msg); -} - -__initfunc(int pcikbd_probe(void)) +__initfunc(void pcikbd_init_hw(void)) { struct linux_ebus *ebus; struct linux_ebus_device *edev; struct linux_ebus_child *child; + char *msg; for_all_ebusdev(edev, ebus) { if(!strcmp(edev->prom_name, "8042")) { @@ -415,29 +467,57 @@ __initfunc(int pcikbd_probe(void)) } } printk("pcikbd_probe: no 8042 found\n"); - return -ENODEV; + return; found: pcikbd_iobase = child->base_address[0]; if (check_region(pcikbd_iobase, sizeof(unsigned long))) { printk("8042: can't get region %lx, %d\n", pcikbd_iobase, (int)sizeof(unsigned long)); - return -ENODEV; + return; } request_region(pcikbd_iobase, sizeof(unsigned long), "8042 controller"); pcikbd_irq = child->irqs[0]; if (request_irq(pcikbd_irq, &pcikbd_interrupt, - SA_SHIRQ, "keyboard", NULL)) { + SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) { printk("8042: cannot register IRQ %x\n", pcikbd_irq); - return -ENODEV; + return; } printk("8042(kbd): iobase[%016lx] irq[%x]\n", pcikbd_iobase, pcikbd_irq); - /* pcikbd_init(); */ - kbd_read_mask = KBD_STAT_OBF; - return 0; + kd_mksound = nop_kd_mksound; + for_all_ebusdev(edev, ebus) { + if(!strcmp(edev->prom_name, "beeper")) + break; + } + + /* + * XXX: my 3.1.3 PROM does not give me the beeper node for the audio + * auxio register, though I know it is there... (ecd) + */ + if (!edev) + pcibeep_iobase = (pcikbd_iobase & ~(0xffffff)) | 0x722000; + else + pcibeep_iobase = edev->base_address[0]; + + if (check_region(pcibeep_iobase, sizeof(unsigned int))) { + printk("8042: can't get region %lx, %d\n", + pcibeep_iobase, (int)sizeof(unsigned int)); + } else { + request_region(pcibeep_iobase, sizeof(unsigned int), "speaker"); + kd_mksound = pcikbd_kd_mksound; + printk("8042(speaker): iobase[%016lx]%s\n", pcibeep_iobase, + edev ? "" : " (forced)"); + } + + disable_irq(pcikbd_irq); + msg = do_pcikbd_init_hw(); + enable_irq(pcikbd_irq); + + if(msg) + printk("8042: keyboard init failure [%s]\n", msg); } @@ -451,8 +531,6 @@ static int ms_node; static unsigned long pcimouse_iobase = 0; static unsigned int pcimouse_irq; -#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */ - #define AUX_BUF_SIZE 2048 struct aux_queue { @@ -468,6 +546,16 @@ static int aux_ready = 0; static int aux_count = 0; static int aux_present = 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); +} + /* * Shared subroutines */ @@ -491,11 +579,11 @@ static inline int queue_empty(void) return queue->head == queue->tail; } -static int fasync_aux(struct inode *inode, struct file *filp, int on) +static int aux_fasync(struct file *filp, int on) { int retval; - retval = fasync_helper(inode, filp, on, &queue->fasync); + retval = fasync_helper(filp, on, &queue->fasync); if (retval < 0) return retval; return 0; @@ -521,11 +609,11 @@ static int poll_aux_status(void) { int retries=0; - while ((inb(pcimouse_iobase + KBD_STATUS_REG) & + while ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) { - if ((inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) + if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) - inb(pcimouse_iobase + KBD_DATA_REG); + pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + (5*HZ + 99) / 100; schedule(); @@ -541,9 +629,10 @@ static int poll_aux_status(void) static void aux_write_dev(int val) { poll_aux_status(); - outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG);/* Write magic cookie */ + pcimouse_outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG);/* Write magic cookie */ poll_aux_status(); - outb_p(val, pcimouse_iobase + KBD_DATA_REG); /* Write data */ + pcimouse_outb(val, pcimouse_iobase + KBD_DATA_REG); /* Write data */ + udelay(1); } /* @@ -555,8 +644,8 @@ __initfunc(static int aux_write_ack(int val)) aux_write_dev(val); poll_aux_status(); - if ((inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) - return (inb(pcimouse_iobase + KBD_DATA_REG)); + if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) + return (pcimouse_inb(pcimouse_iobase + KBD_DATA_REG)); return 0; } @@ -567,9 +656,9 @@ __initfunc(static int aux_write_ack(int val)) static void aux_write_cmd(int val) { poll_aux_status(); - outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - outb(val, pcimouse_iobase + KBD_DATA_REG); + pcimouse_outb(val, pcimouse_iobase + KBD_DATA_REG); } /* @@ -607,18 +696,10 @@ 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); - /* - * This IRQ might be shared with the 16550A serial chip, - * so we check dev_id to see if it was for us. - * (See also drivers/sbus/char/su.c). - */ - if (dev_id) - return; - - if ((inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF) + if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF) return; - add_mouse_randomness(queue->buf[head] = inb(pcimouse_iobase + KBD_DATA_REG)); + add_mouse_randomness(queue->buf[head] = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG)); if (head != maxhead) { head++; head &= AUX_BUF_SIZE-1; @@ -630,9 +711,9 @@ void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) wake_up_interruptible(&queue->proc_list); } -static int release_aux(struct inode * inode, struct file * file) +static int aux_release(struct inode * inode, struct file * file) { - fasync_aux(inode, file, 0); + aux_fasync(file, 0); if (--aux_count) return 0; aux_start_atomic(); @@ -642,7 +723,7 @@ static int release_aux(struct inode * inode, struct file * file) poll_aux_status(); /* Disable Aux device */ - outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); aux_end_atomic(); @@ -655,10 +736,11 @@ static int release_aux(struct inode * inode, struct file * file) * Enable auxiliary device. */ -static int open_aux(struct inode * inode, struct file * file) +static int aux_open(struct inode * inode, struct file * file) { if (!aux_present) return -ENODEV; + aux_start_atomic(); if (aux_count++) { aux_end_atomic(); @@ -674,7 +756,7 @@ static int open_aux(struct inode * inode, struct file * file) MOD_INC_USE_COUNT; poll_aux_status(); - outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase+KBD_CNTL_REG); /* Enable Aux */ + pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase+KBD_CNTL_REG); /* Enable Aux */ aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */ poll_aux_status(); @@ -688,31 +770,31 @@ static int open_aux(struct inode * inode, struct file * file) * Write to the aux device. */ -static long write_aux(struct inode * inode, struct file * file, - const char * buffer, unsigned long count) +static ssize_t aux_write(struct file * file, const char * buffer, + size_t count, loff_t *ppos) { - int retval = 0; + ssize_t retval = 0; if (count) { - int written = 0; + ssize_t written = 0; aux_start_atomic(); do { char c; if (!poll_aux_status()) break; - 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++); - outb(c, pcimouse_iobase + KBD_DATA_REG); + pcimouse_outb(c, pcimouse_iobase + KBD_DATA_REG); written++; } while (--count); aux_end_atomic(); retval = -EIO; if (written) { retval = written; - inode->i_mtime = CURRENT_TIME; + file->f_dentry->d_inode->i_mtime = CURRENT_TIME; } } @@ -727,11 +809,11 @@ static long write_aux(struct inode * inode, struct file * file, * Put bytes from input queue to buffer. */ -static long read_aux(struct inode * inode, struct file * file, - char * buffer, unsigned long count) +static ssize_t aux_read(struct file * file, char * buffer, + size_t count, loff_t *ppos) { struct wait_queue wait = { current, NULL }; - int i = count; + ssize_t i = count; unsigned char c; if (queue_empty()) { @@ -754,7 +836,7 @@ repeat: } aux_ready = !queue_empty(); if (count-i) { - inode->i_atime = CURRENT_TIME; + file->f_dentry->d_inode->i_atime = CURRENT_TIME; return count-i; } if (signal_pending(current)) @@ -764,7 +846,7 @@ repeat: static unsigned int aux_poll(struct file *file, poll_table * wait) { - poll_wait(&queue->proc_list, wait); + poll_wait(file, &queue->proc_list, wait); if (aux_ready) return POLLIN | POLLRDNORM; return 0; @@ -772,16 +854,16 @@ static unsigned int aux_poll(struct file *file, poll_table * wait) struct file_operations psaux_fops = { NULL, /* seek */ - read_aux, - write_aux, + aux_read, + aux_write, NULL, /* readdir */ aux_poll, NULL, /* ioctl */ NULL, /* mmap */ - open_aux, - release_aux, + aux_open, + aux_release, NULL, - fasync_aux, + aux_fasync, }; static struct miscdevice psaux_mouse = { @@ -816,7 +898,7 @@ found: pcimouse_irq = child->irqs[0]; if (request_irq(pcimouse_irq, &pcimouse_interrupt, - SA_SHIRQ, "mouse", NULL)) { + SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) { printk("8042: Cannot register IRQ %x\n", pcimouse_irq); return -ENODEV; } @@ -826,7 +908,7 @@ found: printk("8042: PS/2 auxiliary pointing device detected.\n"); aux_present = 1; - kbd_read_mask = AUX_STAT_OBF; + pckbd_read_mask = AUX_STAT_OBF; misc_register(&psaux_mouse); queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); @@ -834,18 +916,19 @@ found: queue->head = queue->tail = 0; queue->proc_list = NULL; aux_start_atomic(); - outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG); + aux_write_ack(AUX_RESET); aux_write_ack(AUX_SET_SAMPLE); aux_write_ack(100); aux_write_ack(AUX_SET_RES); aux_write_ack(3); aux_write_ack(AUX_SET_SCALE21); poll_aux_status(); - outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG); + pcimouse_outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG); poll_aux_status(); aux_end_atomic(); @@ -853,21 +936,6 @@ found: } -__initfunc(static int ps2_init(void)) -{ - int err; - - err = pcikbd_probe(); - if (err) - return err; - - err = pcimouse_init(); - if (err) - return err; - - return 0; -} - __initfunc(int ps2kbd_probe(unsigned long *memory_start)) { int pnode, enode, node, dnode; @@ -959,6 +1027,12 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start)) return -ENODEV; found: - sunserial_setinitfunc(memory_start, ps2_init); + sunkbd_setinitfunc(memory_start, pcimouse_init); + sunkbd_setinitfunc(memory_start, pcikbd_init); + kbd_ops.compute_shiftstate = pci_compute_shiftstate; + kbd_ops.setledstate = pci_setledstate; + kbd_ops.getledstate = pci_getledstate; + kbd_ops.setkeycode = pci_setkeycode; + kbd_ops.getkeycode = pci_getkeycode; return 0; } diff --git a/drivers/sbus/char/pcikbd.h b/drivers/sbus/char/pcikbd.h index 234a5e980..a9e38090c 100644 --- a/drivers/sbus/char/pcikbd.h +++ b/drivers/sbus/char/pcikbd.h @@ -1,4 +1,4 @@ -/* $Id: pcikbd.h,v 1.1 1997/08/24 02:53:25 davem Exp $ +/* $Id: pcikbd.h,v 1.2 1997/12/25 21:13:14 geert Exp $ * pcikbd.h: PCI/PC 8042 keyboard/mouse driver stuff. Mostly snarfed * from the existing driver by Martin Mares. * @@ -28,7 +28,7 @@ * Internal variables of the driver */ -extern unsigned char kbd_read_mask; +extern unsigned char pckbd_read_mask; extern unsigned char aux_device_present; extern unsigned long pcikbd_iobase; diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index e0fbf2569..ccc8dd2cd 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.10 1997/04/03 08:47:55 davem Exp $ +/* $Id: rtc.c,v 1.11 1997/09/20 20:47:26 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -70,8 +70,7 @@ void set_rtc_time(struct rtc_time *t) restore_flags(flags); } -static long long rtc_lseek(struct inode *inode, struct file *file, - long long offset, int origin) +static long long rtc_lseek(struct file *file, long long offset, int origin) { return -ESPIPE; } diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index 2134d3d75..9eed1d7f6 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.4 1997/09/03 17:04:21 ecd Exp $ +/* $Id: sab82532.c,v 1.13 1997/12/30 09:37:49 ecd Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -16,6 +16,7 @@ #include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/serial_reg.h> +#include <linux/console.h> #include <linux/major.h> #include <linux/string.h> #include <linux/fcntl.h> @@ -40,6 +41,9 @@ static int sab82532_refcount; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 +#define SERIAL_PARANOIA_CHECK +#define SERIAL_DO_RESTART + /* Set of debugging defines */ #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_INTR @@ -59,10 +63,23 @@ static struct tty_struct *sab82532_table[NR_PORTS]; static struct termios *sab82532_termios[NR_PORTS]; static struct termios *sab82532_termios_locked[NR_PORTS]; +#ifdef CONFIG_SERIAL_CONSOLE +extern int serial_console; +static struct console sab82532_console; +static int sab82532_console_init(void); +#endif + #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +static char *sab82532_version[16] = { + "V1.0", "V2.0", "V3.2", "V(0x03)", + "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)", + "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)", + "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)" +}; + /* * tmp_buf is used as a temporary buffer by sab82532_write. We need to * lock it in case the copy_from_user blocks while swapping in a page, @@ -178,8 +195,10 @@ static void sab82532_start(struct tty_struct *tty) restore_flags(flags); } -static void batten_down_hatches(void) +static void batten_down_hatches(struct sab82532 *info) { + unsigned char saved_rfc; + /* If we are doing kadb, we call the debugger * else we just drop into the boot monitor. * Note that we must flush the user windows @@ -187,6 +206,16 @@ static void batten_down_hatches(void) */ printk("\n"); flush_user_windows(); + + /* + * Set FIFO to single character mode. + */ + saved_rfc = info->regs->r.rfc; + info->regs->rw.rfc &= ~(SAB82532_RFC_RFDF); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + info->regs->w.cmdr = SAB82532_CMDR_RRES; + #ifndef __sparc_v9__ if ((((unsigned long)linux_dbvec) >= DEBUG_FIRSTVADDR) && (((unsigned long)linux_dbvec) <= DEBUG_LASTVADDR)) @@ -194,6 +223,14 @@ static void batten_down_hatches(void) else #endif prom_cmdline(); + + /* + * Reset FIFO to character + status mode. + */ + info->regs->w.rfc = saved_rfc; + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + info->regs->w.cmdr = SAB82532_CMDR_RRES; } /* @@ -242,16 +279,11 @@ static inline void receive_chars(struct sab82532 *info, count = info->recv_fifo_size; free_fifo++; } + if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { count = info->regs->r.rbcl & (info->recv_fifo_size - 1); free_fifo++; } - if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { -#if 1 - printk("sab82532: receive_chars: RFO"); -#endif - free_fifo++; - } /* Issue a FIFO read command in case we where idle. */ if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { @@ -260,8 +292,15 @@ static inline void receive_chars(struct sab82532 *info, info->regs->w.cmdr = SAB82532_CMDR_RFRD; } + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { +#if 1 + printk("sab82532: receive_chars: RFO"); +#endif + free_fifo++; + } + /* Read the FIFO. */ - for (i = 0; i < (count << 1); i++) + for (i = 0; i < count; i++) buf[i] = info->regs->r.rfifo[i]; /* Issue Receive Message Complete command. */ @@ -271,6 +310,11 @@ static inline void receive_chars(struct sab82532 *info, info->regs->w.cmdr = SAB82532_CMDR_RMC; } + if (info->is_console) + wake_up(&keypress_wait); + if (!tty) + return; + for (i = 0; i < count; ) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { #if 1 @@ -312,6 +356,12 @@ static inline void transmit_chars(struct sab82532 *info, { int i; + if (!info->tty) { + info->interrupt_mask1 |= SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) @@ -356,7 +406,7 @@ static inline void check_status(struct sab82532 *info, if (stat->sreg.isr1 & SAB82532_ISR1_BRK) { if (info->is_console) { - batten_down_hatches(); + batten_down_hatches(info); return; } if (tty->flip.count >= TTY_FLIPBUF_SIZE) { @@ -369,6 +419,9 @@ static inline void check_status(struct sab82532 *info, info->icount.brk++; } + if (!tty) + return; + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { info->icount.buf_overrun++; @@ -380,9 +433,6 @@ static inline void check_status(struct sab82532 *info, info->icount.overrun++; } - if (info->is_console) - return; - check_modem: if (stat->sreg.isr0 & SAB82532_ISR0_CDSC) { info->dcd = (info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : 1; @@ -581,38 +631,18 @@ static void do_serial_hangup(void *private_) tty_hangup(tty); } - -static int startup(struct sab82532 *info) +static void +sab82532_init_line(struct sab82532 *info) { - unsigned long flags; - unsigned long page; unsigned char stat; - page = get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - save_flags(flags); cli(); - - if (info->flags & ASYNC_INITIALIZED) { - free_page(page); - goto errout; - } - - if (!info->regs) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - free_page(page); - goto errout; - } - if (info->xmit_buf) - free_page(page); - else - info->xmit_buf = (unsigned char *)page; - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up serial port %d...", info->line); -#endif + /* + * Wait for any commands or immediate characters + */ + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); /* * Clear the FIFO buffers. @@ -662,7 +692,46 @@ static int startup(struct sab82532 *info) break; } info->regs->rw.ccr0 |= SAB82532_CCR0_PU; /* power-up */ - +} + +static int startup(struct sab82532 *info) +{ + unsigned long flags; + unsigned long page; + int retval = 0; + + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!info->regs) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + retval = -ENODEV; + goto errout; + } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *)page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up serial port %d...", info->line); +#endif + + /* + * Initialize the Hardware + */ + sab82532_init_line(info); + /* * Finally, enable interrupts */ @@ -689,7 +758,7 @@ static int startup(struct sab82532 *info) errout: restore_flags(flags); - return -ENODEV; + return retval; } /* @@ -720,6 +789,22 @@ static void shutdown(struct sab82532 *info) info->xmit_buf = 0; } + if (info->is_console) { + info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + info->regs->w.imr0 = info->interrupt_mask0; + info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); + return; + } + /* Disable Interrupts */ info->interrupt_mask0 = 0xff; info->regs->w.imr0 = info->interrupt_mask0; @@ -758,7 +843,7 @@ static void change_speed(struct sab82532 *info) unsigned int ebrg; tcflag_t cflag; unsigned char dafo; - int i; + int i, bits; if (!info->tty || !info->tty->termios) return; @@ -766,19 +851,23 @@ static void change_speed(struct sab82532 *info) /* Byte size and parity */ switch (cflag & CSIZE) { - case CS5: dafo = SAB82532_DAFO_CHL5; break; - case CS6: dafo = SAB82532_DAFO_CHL6; break; - case CS7: dafo = SAB82532_DAFO_CHL7; break; - case CS8: dafo = SAB82532_DAFO_CHL8; break; + case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; + case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; + case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; /* Never happens, but GCC is too dumb to figure it out */ - default: dafo = SAB82532_DAFO_CHL5; break; + default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; } - if (cflag & CSTOPB) + if (cflag & CSTOPB) { dafo |= SAB82532_DAFO_STOP; + bits++; + } - if (cflag & PARENB) + if (cflag & PARENB) { dafo |= SAB82532_DAFO_PARE; + bits++; + } if (cflag & PARODD) { #ifdef CMSPAR @@ -808,6 +897,12 @@ static void change_speed(struct sab82532 *info) ebrg = ebrg_table[i].n; ebrg |= (ebrg_table[i].m << 6); + if (ebrg_table[i].baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud; + else + info->timeout = 0; + info->timeout += HZ / 50; /* Add .02 seconds of slop */ + /* CTS flow control flags */ if (cflag & CRTSCTS) info->flags |= ASYNC_CTS_FLOW; @@ -842,6 +937,10 @@ static void change_speed(struct sab82532 *info) SAB82532_ISR0_TIME; save_flags(flags); cli(); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); info->regs->w.dafo = dafo; info->regs->w.bgr = ebrg & 0xff; info->regs->rw.ccr2 &= ~(0xc0); @@ -980,7 +1079,7 @@ static int sab82532_chars_in_buffer(struct tty_struct *tty) static void sab82532_flush_buffer(struct tty_struct *tty) { struct sab82532 *info = (struct sab82532 *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "sab82532_flush_buffer")) return; cli(); @@ -1003,7 +1102,7 @@ static void sab82532_send_xchar(struct tty_struct *tty, char ch) if (serial_paranoia_check(info, tty->device, "sab82532_send_xchar")) return; - if (info->regs->r.star & SAB82532_STAR_TEC) + while (info->regs->r.star & SAB82532_STAR_TEC) udelay(1); info->regs->w.tic = ch; } @@ -1114,7 +1213,7 @@ static int get_lsr_info(struct sab82532 * info, unsigned int *value) { unsigned int result; - result = info->all_sent ? TIOCSER_TEMT : 0; + result = (!info->xmit_buf && info->all_sent) ? TIOCSER_TEMT : 0; return put_user(result, value); } @@ -1496,7 +1595,9 @@ static void sab82532_close(struct tty_struct *tty, struct file * filp) */ info->interrupt_mask0 |= SAB82532_IMR0_TCD; info->regs->w.imr0 = info->interrupt_mask0; +#if 0 info->regs->rw.mode &= ~(SAB82532_MODE_RAC); +#endif if (info->flags & ASYNC_INITIALIZED) { /* * Before we drop DTR, make sure the UART transmitter @@ -1554,16 +1655,23 @@ static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout) char_time = 1; if (timeout) char_time = MIN(char_time, timeout); -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT printk("In sab82532_wait_until_sent(%d) check=%lu...", timeout, char_time); printk("jiff=%lu...", jiffies); #endif - - /* XXX: Implement this... */ - + while (info->xmit_cnt || !info->all_sent) { + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; + current->timeout = jiffies + char_time; + schedule(); + if (signal_pending(current)) + break; + if (timeout && (orig_jiffies + timeout) < jiffies) + break; + } current->state = TASK_RUNNING; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT + printk("xmit_cnt = %d, alls = %d (jiff=%lu)...done\n", info->xmit_cnt, info->all_sent, jiffies); #endif } @@ -1573,10 +1681,13 @@ static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout) static void sab82532_hangup(struct tty_struct *tty) { struct sab82532 * info = (struct sab82532 *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "sab82532_hangup")) return; + if (info->is_console) + return; + sab82532_flush_buffer(tty); shutdown(info); info->event = 0; @@ -1754,7 +1865,6 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) return -ENODEV; } - info->count++; if (serial_paranoia_check(info, tty->device, "sab82532_open")) return -ENODEV; @@ -1762,6 +1872,8 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) printk("sab82532_open %s%d, count = %d\n", tty->driver.name, info->line, info->count); #endif + + info->count++; tty->driver_data = info; info->tty = tty; @@ -1774,7 +1886,22 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) else tmp_buf = (unsigned char *) page; } - + + /* + * If the port is in the middle of closing, bail out now. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + /* * Start up serial port */ @@ -1801,6 +1928,14 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) change_speed(info); } +#ifdef CONFIG_SERIAL_CONSOLE + if (sab82532_console.cflag && sab82532_console.index == line) { + tty->termios->c_cflag = sab82532_console.cflag; + sab82532_console.cflag = 0; + change_speed(info); + } +#endif + info->session = current->session; info->pgrp = current->pgrp; @@ -1856,7 +1991,7 @@ int sab82532_read_proc(char *page, char **start, off_t off, int count, int i, len = 0; off_t begin = 0; - len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.4 $"); + len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.13 $"); for (i = 0; i < NR_PORTS && len < 4000; i++) { len += line_info(page + len, sab82532_table[i]); if (len+begin > off+count) @@ -1881,7 +2016,7 @@ done: * sab82532_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- */ -__initfunc(static int get_sab82532(void)) +__initfunc(static int get_sab82532(unsigned long *memory_start)) { struct linux_ebus *ebus; struct linux_ebus_device *edev; @@ -1895,23 +2030,29 @@ __initfunc(static int get_sab82532(void)) if (!edev) return -ENODEV; - printk("%s: SAB82532 at 0x%lx IRQ %x\n", __FUNCTION__, - edev->base_address[0], edev->irqs[0]); - regs = edev->base_address[0]; offset = sizeof(union sab82532_async_regs); for (i = 0; i < 2; i++) { - sab = (struct sab82532 *)kmalloc(sizeof(struct sab82532), - GFP_KERNEL); - if (!sab) { - printk("sab82532: can't alloc sab struct\n"); - break; + if (memory_start) { + *memory_start = (*memory_start + 7) & ~(7); + sab = (struct sab82532 *)*memory_start; + *memory_start += sizeof(struct sab82532); + } else { + sab = (struct sab82532 *)kmalloc(sizeof(struct sab82532), + GFP_KERNEL); + if (!sab) { + printk("sab82532: can't alloc sab struct\n"); + break; + } } memset(sab, 0, sizeof(struct sab82532)); sab->regs = (union sab82532_async_regs *)(regs + offset); sab->irq = edev->irqs[0]; + sab->line = 1 - i; + sab->xmit_fifo_size = 32; + sab->recv_fifo_size = 32; if (check_region((unsigned long)sab->regs, sizeof(union sab82532_async_regs))) { @@ -1932,20 +2073,8 @@ __initfunc(static int get_sab82532(void)) return 0; } -/* Hooks for running a serial console. con_init() calls this if the - * console is run over one of the ttya/ttyb serial ports. - * 'chip' should be zero, as for now we only have one chip on board. - * 'line' is decoded as 0=ttya, 1=ttyb. - */ -void -sab82532_cons_hook(int chip, int out, int line) -{ - prom_printf("sab82532: serial console is not implemented, yet\n"); - prom_halt(); -} - -void -sab82532_kgdb_hook(int line) +__initfunc(static void +sab82532_kgdb_hook(int line)) { prom_printf("sab82532: kgdb support is not implemented, yet\n"); prom_halt(); @@ -1953,7 +2082,7 @@ sab82532_kgdb_hook(int line) __initfunc(static inline void show_serial_version(void)) { - char *revision = "$Revision: 1.4 $"; + char *revision = "$Revision: 1.13 $"; char *version, *p; version = strchr(revision, ' '); @@ -1971,7 +2100,7 @@ __initfunc(int sab82532_init(void)) int i; if (!sab82532_chain) - get_sab82532(); + get_sab82532(0); if (!sab82532_chain) return -ENODEV; @@ -2035,9 +2164,6 @@ __initfunc(int sab82532_init(void)) for (info = sab82532_chain, i = 0; info; info = info->next, i++) { info->magic = SERIAL_MAGIC; - info->line = i; - info->tty = 0; - info->count = 0; info->type = info->regs->r.vstr & 0x0f; info->regs->w.pcr = ~((1 << 1) | (1 << 2) | (1 << 4)); @@ -2053,14 +2179,11 @@ __initfunc(int sab82532_init(void)) info->regs->rw.mode |= SAB82532_MODE_FRTS; info->regs->rw.mode |= SAB82532_MODE_RTS; - info->xmit_fifo_size = 32; - info->recv_fifo_size = 32; info->custom_divisor = 16; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; info->x_char = 0; info->event = 0; - info->count = 0; info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; @@ -2086,9 +2209,9 @@ __initfunc(int sab82532_init(void)) } } - printk(KERN_INFO "ttyS%02d at 0x%lx (irq = %x) is a %s\n", + printk(KERN_INFO "ttyS%02d at 0x%lx (irq = %x) is a SAB82532 %s\n", info->line, (unsigned long)info->regs, info->irq, - "SAB82532"); + sab82532_version[info->type]); } return 0; } @@ -2125,8 +2248,10 @@ __initfunc(int sab82532_probe(unsigned long *memory_start)) return -ENODEV; found: +#ifdef CONFIG_SERIAL_CONSOLE + sunserial_setinitfunc(memory_start, sab82532_console_init); +#endif sunserial_setinitfunc(memory_start, sab82532_init); - rs_ops.rs_cons_hook = sab82532_cons_hook; rs_ops.rs_kgdb_hook = sab82532_kgdb_hook; return 0; } @@ -2134,7 +2259,7 @@ found: #ifdef MODULE int init_module(void) { - if (get_sab82532()) + if (get_sab82532(0)) return -ENODEV; return sab82532_init(); @@ -2171,3 +2296,200 @@ void cleanup_module(void) } } #endif /* MODULE */ + +#ifdef CONFIG_SERIAL_CONSOLE + +static void +sab82532_console_putchar(struct sab82532 *info, char c) +{ + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); + info->regs->w.tic = c; +} + +static void +sab82532_console_write(struct console *con, const char *s, unsigned n) +{ + struct sab82532 *info; + int i; + + info = sab82532_chain + con->index; + + for (i = 0; i < n; i++) { + if (*s == '\n') + sab82532_console_putchar(info, '\r'); + sab82532_console_putchar(info, *s++); + } + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); +} + +static int +sab82532_console_wait_key(struct console *con) +{ + sleep_on(&keypress_wait); + return 0; +} + +static kdev_t +sab82532_console_device(struct console *con) +{ + return MKDEV(TTY_MAJOR, 64 + con->index); +} + +static int +sab82532_console_setup(struct console *con, char *options) +{ + struct sab82532 *info; + unsigned int ebrg; + tcflag_t cflag; + unsigned char dafo; + int i, bits; + unsigned long flags; + + info = sab82532_chain + con->index; + info->is_console = 1; + + /* + * Initialize the hardware + */ + sab82532_init_line(info); + + /* + * Finally, enable interrupts + */ + info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + info->regs->w.imr0 = info->interrupt_mask0; + info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + + printk("Console: ttyS%d (SAB82532)\n", info->line); + + sunserial_console_termios(con); + cflag = con->cflag; + + /* Byte size and parity */ + switch (cflag & CSIZE) { + case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; + case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; + case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + } + + if (cflag & CSTOPB) { + dafo |= SAB82532_DAFO_STOP; + bits++; + } + + if (cflag & PARENB) { + dafo |= SAB82532_DAFO_PARE; + bits++; + } + + if (cflag & PARODD) { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_MARK; + else +#endif + dafo |= SAB82532_DAFO_PAR_ODD; + } else { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_SPACE; + else +#endif + dafo |= SAB82532_DAFO_PAR_EVEN; + } + + /* Determine EBRG values based on baud rate */ + i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~(CBAUDEX); + if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES)) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + ebrg = ebrg_table[i].n; + ebrg |= (ebrg_table[i].m << 6); + + if (ebrg_table[i].baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud; + else + info->timeout = 0; + info->timeout += HZ / 50; /* Add .02 seconds of slop */ + + /* CTS flow control flags */ + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~(ASYNC_CTS_FLOW); + + if (cflag & CLOCAL) + info->flags &= ~(ASYNC_CHECK_CD); + else + info->flags |= ASYNC_CHECK_CD; + + save_flags(flags); cli(); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); + info->regs->w.dafo = dafo; + info->regs->w.bgr = ebrg & 0xff; + info->regs->rw.ccr2 &= ~(0xc0); + info->regs->rw.ccr2 |= (ebrg >> 2) & 0xc0; + if (info->flags & ASYNC_CTS_FLOW) { + info->regs->rw.mode &= ~(SAB82532_MODE_RTS); + info->regs->rw.mode |= SAB82532_MODE_FRTS; + info->regs->rw.mode &= ~(SAB82532_MODE_FCTS); + } else { + info->regs->rw.mode |= SAB82532_MODE_RTS; + info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); + info->regs->rw.mode |= SAB82532_MODE_FCTS; + } + info->regs->rw.mode |= SAB82532_MODE_RAC; + restore_flags(flags); + + return 0; +} + +static struct console sab82532_console = { + "ttyS", + sab82532_console_write, + NULL, + sab82532_console_device, + sab82532_console_wait_key, + NULL, + sab82532_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +__initfunc(int sab82532_console_init(void)) +{ + extern int con_is_present(void); + + if (con_is_present()) + return 0; + + if (!sab82532_chain) { + prom_printf("sab82532_console_setup: can't get SAB82532 chain"); + prom_halt(); + } + + sab82532_console.index = serial_console - 1; + register_console(&sab82532_console); + return 0; +} + +#endif /* CONFIG_SERIAL_CONSOLE */ diff --git a/drivers/sbus/char/sbuscons.c b/drivers/sbus/char/sbuscons.c index a0d47d79c..eda06fa76 100644 --- a/drivers/sbus/char/sbuscons.c +++ b/drivers/sbus/char/sbuscons.c @@ -1,4 +1,4 @@ -/* $Id: sbuscons.c,v 1.7 1997/08/28 09:30:07 davem Exp $ +/* $Id: sbuscons.c,v 1.10 1998/01/07 06:37:22 baccala Exp $ * sbuscons.c: Routines specific to SBUS frame buffer consoles. * * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su) @@ -1168,7 +1168,7 @@ static int sbus_blitc(uint charattr, unsigned long addr) const int cpl = chars_per_line; /* The register assignment is important here, do not modify without touching the assembly code as well */ register unsigned int x1 __asm__("g4"), x2 __asm__("g5"), x3 __asm__("g2"), x4 __asm__("g3"), flags __asm__("g7"); - register unsigned int *dst __asm__("g1"); + register unsigned int *dst; #else const int ipl = ints_per_line; unsigned int data2, data3, data4; @@ -1182,9 +1182,9 @@ static int sbus_blitc(uint charattr, unsigned long addr) if (j == ' ') /* space is quite common, so we optimize a bit */ { #ifdef ASM_BLITC #define BLITC_SPACE \ - "\n\t std %%g4, [%%g1]" \ - "\n\t std %%g4, [%%g1 + %0]" \ - "\n\t add %%g1, %1, %%g1" + "\n\t std %3, [%0]" \ + "\n\t std %3, [%0 + %1]" \ + "\n\t add %0, %2, %0" #define BLITC_SPC \ "\n\t std %0, [%1]" \ "\n\t std %0, [%1 + %2]" @@ -1195,7 +1195,7 @@ static int sbus_blitc(uint charattr, unsigned long addr) x3 = cpl << 1; __asm__ __volatile__ ( - "\n\t mov %2, %3" + "\n\t mov %3, %4" BLITC_SPACE BLITC_SPACE BLITC_SPACE @@ -1203,12 +1203,19 @@ static int sbus_blitc(uint charattr, unsigned long addr) BLITC_SPACE BLITC_SPACE BLITC_SPACE - : : "r" (cpl), "r" (x3), "r" (x1), "r" (x2)); + : "=r" (dst) + : "r" (cpl), "r" (x3), "r" (x1), "r" (x2)); __save_and_cli (flags); if (idx != cursor_pos) - __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (dst), "r" (cpl)); + __asm__ __volatile__ ( + BLITC_SPC + : /* no outputs */ + : "r" (x1), "r" (dst), "r" (cpl)); else - __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (under_cursor), "i" (8)); + __asm__ __volatile__ (BLITC_SPC + : /* no outputs */ + : "r" (x1), "r" (under_cursor), + "i" (8)); __restore_flags (flags); #else bgmask = attrib >> 4; diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c index 6cc5801cd..beba2e7e6 100644 --- a/drivers/sbus/char/su.c +++ b/drivers/sbus/char/su.c @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.3 1997/09/03 11:54:56 ecd Exp $ +/* $Id: su.c,v 1.4 1997/09/07 15:40:19 ecd Exp $ * su.c: Small serial driver for keyboard/mouse interface on Ultra/AX * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -150,16 +150,6 @@ su_interrupt(int irq, void *dev_id, struct pt_regs * regs) struct su_struct *info = (struct su_struct *)dev_id; unsigned char status; - /* - * We might share interrupts with ps2kbd/ms driver, - * in case we want to use the 16550A as general serial - * driver in the presence of ps2 devices, so do a - * sanity check here, needs to be done in ps2kbd/ms - * driver, too. - */ - if (!info || info->magic != SERIAL_MAGIC) - return; - #ifdef SERIAL_DEBUG_INTR printk("su_interrupt(%d)...", irq); #endif @@ -644,12 +634,12 @@ __initfunc(int su_probe (unsigned long *memory_start)) * Does it match? */ if (sunode == kbnode) { - info->kbd_node = kbnode; + info->kbd_node = sunode; ++info; ++devices; } if (sunode == msnode) { - info->ms_node = msnode; + info->ms_node = sunode; ++info; ++devices; } @@ -674,5 +664,15 @@ __initfunc(int su_probe (unsigned long *memory_start)) found: sunserial_setinitfunc(memory_start, su_init); rs_ops.rs_change_mouse_baud = su_change_mouse_baud; + sunkbd_setinitfunc(memory_start, sun_kbd_init); + kbd_ops.compute_shiftstate = sun_compute_shiftstate; + kbd_ops.setledstate = sun_setledstate; + kbd_ops.getledstate = sun_getledstate; + kbd_ops.setkeycode = sun_setkeycode; + kbd_ops.getkeycode = sun_getkeycode; + sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count, + sun_func_buf, sun_func_table, + sun_funcbufsize, sun_funcbufleft, + sun_accent_table, sun_accent_table_size); return 0; } diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c index 7e88b4688..586ac28c0 100644 --- a/drivers/sbus/char/suncons.c +++ b/drivers/sbus/char/suncons.c @@ -1,4 +1,4 @@ -/* $Id: suncons.c,v 1.73 1997/08/25 07:50:33 jj Exp $ +/* $Id: suncons.c,v 1.77 1997/12/19 07:32:59 ecd Exp $ * suncons.c: Sparc platform console generic layer. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -100,13 +100,11 @@ static void nop_console_restore_palette(void) static unsigned long nop_con_type_init(unsigned long mem_start, const char **display_desc) { - prom_printf("YIEEE: nop_con_type_init called!\n"); return mem_start; } static void nop_con_type_init_finish(void) { - prom_printf("YIEEE: nop_con_type_init_finish called!\n"); } static void nop_vesa_blank(void) @@ -323,12 +321,17 @@ __initfunc(static unsigned long finish_console_init(unsigned long memory_start)) extern void pci_console_inithook(void); #endif +__initfunc(int con_is_present(void)) +{ + return serial_console ? 0 : 1; +} + __initfunc(unsigned long sun_console_init(unsigned long memory_start)) { int i; /* Nothing to do in this case. */ - if(serial_console) + if (!con_is_present()) return memory_start; fbinfo = (fbinfo_t *)memory_start; @@ -358,7 +361,7 @@ extern int pci_console_probe(void); __initfunc(unsigned long pci_console_init(unsigned long memory_start)) { /* Nothing to do in this case. */ - if(serial_console) + if (!con_is_present()) return memory_start; if(pci_console_probe()) { @@ -369,8 +372,6 @@ __initfunc(unsigned long pci_console_init(unsigned long memory_start)) memory_start = finish_console_init(memory_start); con_type_init_finish(); - register_console(&vt_console_driver); - return memory_start; } #endif diff --git a/drivers/sbus/char/sunfb.c b/drivers/sbus/char/sunfb.c index 2ebd9cc5a..cae5bacbd 100644 --- a/drivers/sbus/char/sunfb.c +++ b/drivers/sbus/char/sunfb.c @@ -1,4 +1,4 @@ -/* $Id: sunfb.c,v 1.28 1997/08/22 15:55:23 jj Exp $ +/* $Id: sunfb.c,v 1.29 1997/09/20 20:47:26 davem Exp $ * sunfb.c: Sun generic frame buffer support. * * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -45,7 +45,7 @@ extern void set_other_palette (int); extern void set_cursor (int); #define FB_SETUP(err) \ - int minor = FB_DEV (inode->i_rdev); \ + int minor = FB_DEV (file->f_dentry->d_inode->i_rdev); \ \ if (minor >= fbinfos || \ fbinfo [minor].type.fb_type == FBTYPE_NOTYPE) \ @@ -229,7 +229,7 @@ fb_ioctl (struct inode *inode, struct file *file, uint cmd, unsigned long arg) } static int -fb_close (struct inode * inode, struct file *filp) +fb_close (struct inode * inode, struct file *file) { fbinfo_t *fb; struct fbcursor cursor; @@ -255,7 +255,7 @@ fb_close (struct inode * inode, struct file *filp) if (fb->open) fb->open = 0; - fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor); + fb_ioctl (inode, file, FBIOSCURPOS, (unsigned long) &cursor); set_other_palette (minor); if (!minor) { render_screen (); @@ -266,7 +266,7 @@ fb_close (struct inode * inode, struct file *filp) } static int -fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma) +fb_mmap (struct file *file, struct vm_area_struct *vma) { fbinfo_t *fb; FB_SETUP(ENXIO) @@ -276,7 +276,7 @@ fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma) if (fb->mmap){ int v; - v = (*fb->mmap)(inode, file, vma, fb->base, fb); + v = (*fb->mmap)(file->f_dentry->d_inode, file, vma, fb->base, fb); if (v) return v; vma->vm_flags |= VM_IO; diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index 1340e3f7c..d55fb5ba5 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -6,6 +6,7 @@ * compatibility - Miguel (miguel@nuclecu.unam.mx) * * Added PCI 8042 controller support -DaveM + * Added Magic SysRq support -MJ */ #include <linux/config.h> @@ -22,6 +23,7 @@ #include <linux/random.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/sysrq.h> #include <asm/kbio.h> #include <asm/vuid_event.h> @@ -77,10 +79,10 @@ extern void scrollback(int); extern void scrollfront(int); struct l1a_kbd_state l1a_state = { 0, 0 }; -unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ -unsigned char aux_device_present = 0x00; /* To make kernel/ksyms.c happy */ +#ifndef CONFIG_PCI struct wait_queue * keypress_wait = NULL; +#endif void keyboard_wait_for_keypress(void) { @@ -96,7 +98,6 @@ void keyboard_wait_for_keypress(void) /* shift state counters.. */ static unsigned char k_down[NR_SHIFT] = {0, }; /* keyboard key bitmap */ -#define BITS_PER_LONG (8*sizeof(unsigned long)) static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; void push_kbd (int scan); @@ -108,7 +109,9 @@ static int dead_key_next = 0; * the variable must be global, or a new procedure must be created to * return the value. I chose the former way. */ +#ifndef CONFIG_PCI /*static*/ int shift_state = 0; +#endif static int npadch = -1; /* -1 or number assembled on pad */ static unsigned char diacr = 0; static char rep = 0; /* flag telling character repeat */ @@ -120,7 +123,7 @@ static int compose_led_on = 0; static int kbd_delay_ticks = HZ / 5; static int kbd_rate_ticks = HZ / 20; -extern void compute_shiftstate(void); +void sun_compute_shiftstate(void); typedef void (*k_hand)(unsigned char value, char up_flag); typedef void (k_handfn)(unsigned char value, char up_flag); @@ -151,13 +154,16 @@ static void_fnp spec_fn_table[] = { }; /* maximum values each key_handler can handle */ +#ifndef CONFIG_PCI const int max_vals[] = { 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, NR_DEAD - 1, 255, 3, NR_SHIFT - 1, - 255, NR_ASCII - 1, NR_LOCK - 1, 255 + 255, NR_ASCII - 1, NR_LOCK - 1, 255, + NR_LOCK - 1 }; const int NR_TYPES = SIZE(max_vals); +#endif static void put_queue(int); static unsigned char handle_diacr(unsigned char); @@ -165,6 +171,18 @@ static unsigned char handle_diacr(unsigned char); /* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ static struct pt_regs * pt_regs; +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char sun_sysrq_xlate[128] = + "\0\0\0\0\0\201\202\212\203\213\204\214\205\0\206\0" /* 0x00 - 0x0f */ + "\207\210\211\0\0\0\0\0\0\0\0\0\0\03312" /* 0x10 - 0x1f */ + "34567890-=`\177\0=/*" /* 0x20 - 0x2f */ + "\0\0.\0\0\011qwertyuiop" /* 0x30 - 0x3f */ + "[]\177\000789-\0\0\0\0\0asd" /* 0x40 - 0x4f */ + "fghjkl;'\\\015\0154560\0" /* 0x50 - 0x5f */ + "\0\0\0\0zxcvbnm,./\0\012" /* 0x60 - 0x6f */ + "123\0\0\0\0\0\0 \0\0\0\0\0\0"; /* 0x70 - 0x7f */ +#endif + volatile unsigned char sunkbd_layout; volatile unsigned char sunkbd_type; #define SUNKBD_TYPE2 0x02 @@ -222,7 +240,7 @@ static unsigned char sunkbd_clickp; #define KEY_ALT 0x86 #define KEY_L1 0x87 -/* Do to kbd_init() being called before rs_init(), and kbd_init() doing: +/* Do to sun_kbd_init() being called before rs_init(), and sun_kbd_init() doing: * * init_bh(KEYBOARD_BH, kbd_bh); * mark_bh(KEYBOARD_BH); @@ -394,7 +412,7 @@ static unsigned char norepeat_keys[128] = { }; -int setkeycode(unsigned int scancode, unsigned int keycode) +int sun_setkeycode(unsigned int scancode, unsigned int keycode) { if (scancode < SC_LIM || scancode > 255 || keycode > 127) return -EINVAL; @@ -405,7 +423,7 @@ int setkeycode(unsigned int scancode, unsigned int keycode) return 0; } -int getkeycode(unsigned int scancode) +int sun_getkeycode(unsigned int scancode) { return (scancode < SC_LIM || scancode > 255) ? -EINVAL : @@ -468,7 +486,7 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) } else if(ch == SKBD_ALLUP) { del_timer (&auto_repeat_timer); memset(key_down, 0, sizeof(key_down)); - compute_shiftstate(); + sun_compute_shiftstate(); goto out; } #ifdef SKBD_DEBUG @@ -520,6 +538,14 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) rep = test_and_set_bit(keycode, key_down); } +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq hack */ + if (l1a_state.l1_down) { + if (!up_flag) + handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, kbd, tty); + goto out; + } +#endif + if(raw_mode) goto out; @@ -548,7 +574,7 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) u_char type; /* the XOR below used to be an OR */ - int shift_final = shift_state ^ kbd->lockstate; + int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate; ushort *key_map = key_maps[shift_final]; if (key_map != NULL) { @@ -572,7 +598,7 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) } else { /* maybe beep? */ /* we have at least to update shift_state */ - compute_shiftstate(); + sun_compute_shiftstate(); } } out: @@ -774,7 +800,7 @@ static void do_ignore(unsigned char value, char up_flag) static void do_null() { - compute_shiftstate(); + sun_compute_shiftstate(); } static void do_spec(unsigned char value, char up_flag) @@ -981,7 +1007,7 @@ static void do_shift(unsigned char value, char up_flag) /* called after returning from RAW mode or when changing consoles - recompute k_down[] and shift_state from key_down[] */ /* maybe called when keymap is undefined, so that shiftkey release is seen */ -void compute_shiftstate(void) +void sun_compute_shiftstate(void) { int i, j, k, sym, val; @@ -1055,11 +1081,11 @@ static unsigned char ledstate = 0xff; /* undefined */ static unsigned char sunkbd_ledstate = 0xff; /* undefined */ static unsigned char ledioctl; -unsigned char getledstate(void) { +unsigned char sun_getledstate(void) { return ledstate; } -void setledstate(struct kbd_struct *kbd, unsigned int led) { +void sun_setledstate(struct kbd_struct *kbd, unsigned int led) { if (!(led & ~7)) { ledioctl = led; kbd->ledmode = LED_SHOW_IOCTL; @@ -1181,7 +1207,7 @@ static void sunkbd_kd_mksound(unsigned int hz, unsigned int ticks) extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -__initfunc(int kbd_init(void)) +__initfunc(int sun_kbd_init(void)) { int i, opt_node; struct kbd_struct kbd0; @@ -1190,6 +1216,7 @@ __initfunc(int kbd_init(void)) kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; kbd0.ledmode = LED_SHOW_FLAGS; kbd0.lockstate = KBD_DEFLOCK; + kbd0.slockstate = 0; kbd0.modeflags = KBD_DEFMODE; kbd0.kbdmode = VC_XLATE; @@ -1245,8 +1272,8 @@ push_kbd (int scan) wake_up_interruptible (&kbd_wait); } -static long -kbd_read (struct inode *inode, struct file *f, char *buffer, unsigned long count) +static ssize_t +kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos) { struct wait_queue wait = { current, NULL }; char *end, *p; @@ -1278,12 +1305,11 @@ kbd_read (struct inode *inode, struct file *f, char *buffer, unsigned long count } /* Needed by X */ -static int -kbd_fasync (struct inode *inode, struct file *filp, int on) +static int kbd_fasync (struct file *filp, int on) { int retval; - retval = fasync_helper (inode, filp, on, &kb_fasync); + retval = fasync_helper (filp, on, &kb_fasync); if (retval < 0) return retval; return 0; @@ -1291,7 +1317,7 @@ kbd_fasync (struct inode *inode, struct file *filp, int on) static unsigned int kbd_poll (struct file *f, poll_table *wait) { - poll_wait(&kbd_wait, wait); + poll_wait(f, &kbd_wait, wait); if (kbd_head != kbd_tail) return POLLIN | POLLRDNORM; return 0; @@ -1353,7 +1379,7 @@ kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) if (c & LED_NLOCK) leds |= (1 << VC_NUMLOCK); if (c & LED_CLOCK) leds |= (1 << VC_CAPSLOCK); compose_led_on = !!(c & LED_CMPOSE); - setledstate(kbd_table + fg_console, leds); + sun_setledstate(kbd_table + fg_console, leds); break; case KIOCGLED: put_user_ret(vcleds_to_sunkbd(getleds()), (unsigned char *) arg, -EFAULT); @@ -1433,7 +1459,7 @@ kbd_close (struct inode *i, struct file *f) kbd_redirected = 0; kbd_opened = 0; - kbd_fasync (i, f, 0); + kbd_fasync (f, 0); return 0; } diff --git a/drivers/sbus/char/sunkbd.h b/drivers/sbus/char/sunkbd.h index 151c77457..a1bfeb85b 100644 --- a/drivers/sbus/char/sunkbd.h +++ b/drivers/sbus/char/sunkbd.h @@ -1,4 +1,4 @@ -/* $Id: sunkbd.h,v 1.1 1997/08/28 02:23:34 ecd Exp $ +/* $Id: sunkbd.h,v 1.3 1997/09/08 03:05:10 tdyas Exp $ * sunkbd.h: Defines needed by SUN Keyboard drivers * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -7,6 +7,8 @@ #ifndef _SPARC_SUNKBD_H #define _SPARC_SUNKBD_H 1 +#include <linux/config.h> + /* Keyboard defines for L1-A processing... */ #define SUNKBD_RESET 0xff #define SUNKBD_L1 0x01 @@ -24,4 +26,26 @@ extern void keyboard_zsinit(void (*kbd_put_char)(unsigned char)); extern void sunkbd_inchar(unsigned char, struct pt_regs *); extern void batten_down_hatches(void); +extern int sun_kbd_init(void); +extern void sun_compute_shiftstate(void); +extern void sun_setledstate(struct kbd_struct *, unsigned int); +extern unsigned char sun_getledstate(void); +extern int sun_setkeycode(unsigned int, unsigned int); +extern int sun_getkeycode(unsigned int); + +#ifdef CONFIG_PCI + +extern ushort *sun_key_maps[MAX_NR_KEYMAPS]; +extern unsigned int sun_keymap_count; + +extern char sun_func_buf[]; +extern char *sun_func_table[MAX_NR_FUNC]; +extern int sun_funcbufsize; +extern int sun_funcbufleft; + +extern struct kbdiacr sun_accent_table[MAX_DIACR]; +extern unsigned int sun_accent_table_size; + +#endif /* CONFIG_PCI */ + #endif /* !(_SPARC_SUNKBD_H) */ diff --git a/drivers/sbus/char/sunkbdmap.c b/drivers/sbus/char/sunkbdmap.c new file mode 100644 index 000000000..43afa0343 --- /dev/null +++ b/drivers/sbus/char/sunkbdmap.c @@ -0,0 +1,33 @@ + +/* $Id: sunkbdmap.c,v 1.1 1997/09/07 15:40:27 ecd Exp $ + * sunkbdmap.c: Wrapper around sunkeymap.c to change table names. + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + */ + +#include <linux/config.h> + +#ifdef CONFIG_PCI + +#define func_buf sun_func_buf +#define func_table sun_func_table +#define funcbufsize sun_funcbufsize +#define funcbufleft sun_funcbufleft +#define funcbufptr sun_funcbufptr +#define accent_table sun_accent_table +#define accent_table_size sun_accent_table_size + +#define key_maps sun_key_maps +#define keymap_count sun_keymap_count + +#define plain_map sun_plain_map +#define shift_map sun_shift_map +#define ctrl_map sun_ctrl_map +#define alt_map sun_alt_map +#define altgr_map sun_altgr_map +#define shift_ctrl_map sun_shift_ctrl_map +#define ctrl_alt_map sun_ctrl_alt_map + +#endif /* CONFIG_PCI */ + +#include "sunkeymap.c" diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c index 2f8f8b3c9..0de65c330 100644 --- a/drivers/sbus/char/sunmouse.c +++ b/drivers/sbus/char/sunmouse.c @@ -329,12 +329,11 @@ sun_mouse_open(struct inode * inode, struct file * file) return 0; } -static int -sun_mouse_fasync (struct inode *inode, struct file *filp, int on) +static int sun_mouse_fasync (struct file *filp, int on) { int retval; - retval = fasync_helper (inode, filp, on, &sunmouse.fasync); + retval = fasync_helper (filp, on, &sunmouse.fasync); if (retval < 0) return retval; return 0; @@ -343,23 +342,23 @@ sun_mouse_fasync (struct inode *inode, struct file *filp, int on) static int sun_mouse_close(struct inode *inode, struct file *file) { - sun_mouse_fasync (inode, file, 0); + sun_mouse_fasync (file, 0); if (--sunmouse.active) return 0; sunmouse.ready = 0; return 0; } -static long -sun_mouse_write(struct inode *inode, struct file *file, const char *buffer, - unsigned long count) +static ssize_t +sun_mouse_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) { return -EINVAL; /* foo on you */ } -static long -sun_mouse_read(struct inode *inode, struct file *file, char *buffer, - unsigned long count) +static ssize_t +sun_mouse_read(struct file *file, char *buffer, + size_t count, loff_t *ppos) { struct wait_queue wait = { current, NULL }; @@ -399,7 +398,7 @@ sun_mouse_read(struct inode *inode, struct file *file, char *buffer, } } sunmouse.ready = !queue_empty (); - inode->i_atime = CURRENT_TIME; + file->f_dentry->d_inode->i_atime = CURRENT_TIME; return p-buffer; } else { int c; @@ -410,7 +409,7 @@ sun_mouse_read(struct inode *inode, struct file *file, char *buffer, sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; } sunmouse.ready = !queue_empty(); - inode->i_atime = CURRENT_TIME; + file->f_dentry->d_inode->i_atime = CURRENT_TIME; return count-c; } /* Only called if nothing was sent */ @@ -421,7 +420,7 @@ sun_mouse_read(struct inode *inode, struct file *file, char *buffer, static unsigned int sun_mouse_poll(struct file *file, poll_table *wait) { - poll_wait(&sunmouse.proc_list, wait); + poll_wait(file, &sunmouse.proc_list, wait); if(sunmouse.ready) return POLLIN | POLLRDNORM; return 0; @@ -484,8 +483,11 @@ static struct miscdevice sun_mouse_mouse = { __initfunc(int sun_mouse_init(void)) { + if (!sunmouse.present) + return -ENODEV; + printk("Sun Mouse-Systems mouse driver version 1.00\n"); - sunmouse.present = 1; + sunmouse.ready = sunmouse.active = 0; misc_register (&sun_mouse_mouse); sunmouse.delta_x = sunmouse.delta_y = 0; @@ -498,5 +500,5 @@ __initfunc(int sun_mouse_init(void)) void sun_mouse_zsinit(void) { - sunmouse.ready = 1; + sunmouse.present = 1; } diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c index da90d5ade..8fb203207 100644 --- a/drivers/sbus/char/sunserial.c +++ b/drivers/sbus/char/sunserial.c @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.50 1997/09/03 11:54:59 ecd Exp $ +/* $Id: sunserial.c,v 1.56 1997/12/19 07:33:07 ecd Exp $ * serial.c: Serial port driver infrastructure for the Sparc. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -9,17 +9,19 @@ #include <linux/errno.h> #include <linux/tty.h> #include <linux/serial.h> +#include <linux/string.h> +#include <linux/kbd_diacr.h> +#include <linux/version.h> +#include <linux/init.h> #include <asm/oplib.h> #include "sunserial.h" -static void nop_rs_cons_hook(int chip, int out, int line) -{ - printk("Oops: %s called\n", __FUNCTION__); -} +int serial_console; -static void nop_rs_kgdb_hook(int channel) +__initfunc(static void +nop_rs_kgdb_hook(int channel)) { printk("Oops: %s called\n", __FUNCTION__); } @@ -36,10 +38,8 @@ static int nop_rs_read_proc(char *page, char **start, off_t off, int count, return 0; } - struct sunserial_operations rs_ops = { 0, - nop_rs_cons_hook, nop_rs_kgdb_hook, nop_rs_change_mouse_baud, nop_rs_read_proc @@ -47,25 +47,41 @@ struct sunserial_operations rs_ops = { int rs_init(void) { - struct rs_initfunc *init; + struct initfunc *init; int err = -ENODEV; init = rs_ops.rs_init; while (init) { - err = init->rs_init(); + err = init->init(); init = init->next; } return err; } -void rs_cons_hook(int chip, int out, int line) +__initfunc(void +rs_kgdb_hook(int channel)) { - rs_ops.rs_cons_hook(chip, out, line); + rs_ops.rs_kgdb_hook(channel); } -void rs_kgdb_hook(int channel) +__initfunc(static void sun_serial_finish_init(void)) { - rs_ops.rs_kgdb_hook(channel); + extern unsigned char *linux_serial_image; + extern int con_is_present(void); + char buffer[2048]; + + if (con_is_present()) + return; + + sprintf (buffer, linux_serial_image, UTS_RELEASE); + printk(buffer); +} + +__initfunc(long +serial_console_init(long kmem_start, long kmem_end)) +{ + sun_serial_finish_init(); + return kmem_start; } void rs_change_mouse_baud(int baud) @@ -88,45 +104,299 @@ void unregister_serial(int line) { } + +static void nop_compute_shiftstate (void) +{ + printk("Oops: %s called\n", __FUNCTION__); +} + +static void nop_setledstate (struct kbd_struct *kbd, unsigned int ledstate) +{ + printk("Oops: %s called\n", __FUNCTION__); +} + +static unsigned char nop_getledstate (void) +{ + printk("Oops: %s called\n", __FUNCTION__); + return 0; +} + +static int nop_setkeycode (unsigned int scancode, unsigned int keycode) +{ + printk("Oops: %s called\n", __FUNCTION__); + return -EINVAL; +} + +static int nop_getkeycode (unsigned int scancode) +{ + printk("Oops: %s called\n", __FUNCTION__); + return -EINVAL; +} + +struct sunkbd_operations kbd_ops = { + 0, + nop_compute_shiftstate, + nop_setledstate, + nop_getledstate, + nop_setkeycode, + nop_getkeycode +}; + +int kbd_init(void) +{ + struct initfunc *init; + int err = -ENODEV; + + init = kbd_ops.kbd_init; + while (init) { + err = init->init(); + init = init->next; + } + return err; +} + +void compute_shiftstate (void) +{ + kbd_ops.compute_shiftstate(); +} + +void setledstate (struct kbd_struct *kbd, unsigned int ledstate) +{ + kbd_ops.setledstate(kbd, ledstate); +} + +unsigned char getledstate (void) +{ + return kbd_ops.getledstate(); +} + +int setkeycode (unsigned int scancode, unsigned int keycode) +{ + return kbd_ops.setkeycode(scancode, keycode); +} + +int getkeycode (unsigned int scancode) +{ + return kbd_ops.getkeycode(scancode); +} + + void sunserial_setinitfunc(unsigned long *memory_start, int (*init) (void)) { - struct rs_initfunc *rs_init; + struct initfunc *rs_init; *memory_start = (*memory_start + 7) & ~(7); - rs_init = (struct rs_initfunc *) *memory_start; - *memory_start += sizeof(struct rs_initfunc); + rs_init = (struct initfunc *) *memory_start; + *memory_start += sizeof(struct initfunc); - rs_init->rs_init = init; + rs_init->init = init; rs_init->next = rs_ops.rs_init; rs_ops.rs_init = rs_init; } +void +sunserial_console_termios(struct console *con) +{ + char mode[16], buf[16], *s; + char *mode_prop = "ttyX-mode"; + char *cd_prop = "ttyX-ignore-cd"; + char *dtr_prop = "ttyX-rts-dtr-off"; + int baud, bits, stop, cflag; + char parity; + int carrier = 0; + int rtsdtr = 1; + int topnd, nd; + + if (!serial_console) + return; + + if (serial_console == 1) { + mode_prop[3] = 'a'; + cd_prop[3] = 'a'; + dtr_prop[3] = 'a'; + } else { + mode_prop[3] = 'b'; + cd_prop[3] = 'b'; + dtr_prop[3] = 'b'; + } + + topnd = prom_getchild(prom_root_node); + nd = prom_searchsiblings(topnd, "options"); + if (!nd) { + strcpy(mode, "9600,8,n,1,-"); + goto no_options; + } + + if (!prom_node_has_property(nd, mode_prop)) { + strcpy(mode, "9600,8,n,1,-"); + goto no_options; + } + + memset(mode, 0, sizeof(mode)); + prom_getstring(nd, mode_prop, mode, sizeof(mode)); + + if (prom_node_has_property(nd, cd_prop)) { + memset(buf, 0, sizeof(buf)); + prom_getstring(nd, cd_prop, buf, sizeof(buf)); + if (!strcmp(buf, "false")) + carrier = 1; + + /* XXX: this is unused below. */ + } + + if (prom_node_has_property(nd, cd_prop)) { + memset(buf, 0, sizeof(buf)); + prom_getstring(nd, cd_prop, buf, sizeof(buf)); + if (!strcmp(buf, "false")) + rtsdtr = 0; + + /* XXX: this is unused below. */ + } + +no_options: + cflag = CREAD | HUPCL | CLOCAL; + + s = mode; + baud = simple_strtoul(s, 0, 0); + s = strchr(s, ','); + bits = simple_strtoul(++s, 0, 0); + s = strchr(s, ','); + parity = *(++s); + s = strchr(s, ','); + stop = simple_strtoul(++s, 0, 0); + s = strchr(s, ','); + /* XXX handshake is not handled here. */ + + switch (baud) { + case 150: cflag |= B150; break; + case 300: cflag |= B300; break; + case 600: cflag |= B600; break; + case 1200: cflag |= B1200; break; + case 2400: cflag |= B2400; break; + case 4800: cflag |= B4800; break; + case 9600: cflag |= B9600; break; + case 19200: cflag |= B19200; break; + case 38400: cflag |= B38400; break; + default: cflag |= B9600; break; + } + + switch (bits) { + case 5: cflag |= CS5; break; + case 6: cflag |= CS6; break; + case 7: cflag |= CS7; break; + case 8: cflag |= CS8; break; + default: cflag |= CS8; break; + } + + switch (parity) { + case 'o': cflag |= (PARENB | PARODD); break; + case 'e': cflag |= PARENB; break; + case 'n': default: break; + } + + switch (stop) { + case 2: cflag |= CSTOPB; break; + case 1: default: break; + } + + con->cflag = cflag; +} + +void +sunkbd_setinitfunc(unsigned long *memory_start, int (*init) (void)) +{ + struct initfunc *kbd_init; + + *memory_start = (*memory_start + 7) & ~(7); + kbd_init = (struct initfunc *) *memory_start; + *memory_start += sizeof(struct initfunc); + + kbd_init->init = init; + kbd_init->next = kbd_ops.kbd_init; + kbd_ops.kbd_init = kbd_init; +} + +#ifdef CONFIG_PCI +void +sunkbd_install_keymaps(unsigned long *memory_start, + ushort **src_key_maps, unsigned int src_keymap_count, + char *src_func_buf, char **src_func_table, + int src_funcbufsize, int src_funcbufleft, + struct kbdiacr *src_accent_table, + unsigned int src_accent_table_size) +{ + extern unsigned int keymap_count; + int i, j; + + for (i = 0; i < MAX_NR_KEYMAPS; i++) { + if (src_key_maps[i]) { + if (!key_maps[i]) { + key_maps[i] = (ushort *)*memory_start; + *memory_start += NR_KEYS * sizeof(ushort); + } + for (j = 0; j < NR_KEYS; j++) + key_maps[i][j] = src_key_maps[i][j]; + } + key_maps[i] = src_key_maps[i]; + } + keymap_count = src_keymap_count; + + for (i = 0; i < MAX_NR_FUNC; i++) + func_table[i] = src_func_table[i]; + funcbufptr = src_func_buf; + funcbufsize = src_funcbufsize; + funcbufleft = src_funcbufleft; + + for (i = 0; i < MAX_DIACR; i++) + accent_table[i] = src_accent_table[i]; + accent_table_size = src_accent_table_size; +} +#endif + extern int zs_probe(unsigned long *); #ifdef CONFIG_SAB82532 extern int sab82532_probe(unsigned long *); #endif -#ifdef __sparc_v9__ +#ifdef CONFIG_PCI extern int ps2kbd_probe(unsigned long *); extern int su_probe(unsigned long *); #endif -unsigned long -sun_serial_setup(unsigned long memory_start) +__initfunc(unsigned long +sun_serial_setup(unsigned long memory_start)) { + int ret = -ENODEV; + /* Probe for controllers. */ - if (zs_probe(&memory_start) == 0) + ret = zs_probe(&memory_start); + if (!ret) return memory_start; #ifdef CONFIG_SAB82532 - sab82532_probe(&memory_start); + ret = sab82532_probe(&memory_start); #endif -#ifdef __sparc_v9__ - if (ps2kbd_probe(&memory_start) == 0) - return memory_start; - if (su_probe(&memory_start) == 0) - return memory_start; +#ifdef CONFIG_PCI + /* + * Keyboard serial devices. + * + * Well done, Sun, prom_devopen("/pci@1f,4000/ebus@1/su@14,3083f8") + * hangs the machine if no keyboard is connected to the device... + * All PCI PROMs seem to do this, I have seen this on the Ultra 450 + * with version 3.5 PROM, and on the Ultra/AX with 3.1.5 PROM. + * + * So be very careful not to probe for keyboards if we are on a + * serial console. + */ + if (!serial_console) { + if (ps2kbd_probe(&memory_start) == 0) + return memory_start; + if (su_probe(&memory_start) == 0) + return memory_start; + } #endif + if (!ret) + return memory_start; prom_printf("No serial devices found, bailing out.\n"); prom_halt(); diff --git a/drivers/sbus/char/sunserial.h b/drivers/sbus/char/sunserial.h index 8877d4b56..e0438051b 100644 --- a/drivers/sbus/char/sunserial.h +++ b/drivers/sbus/char/sunserial.h @@ -1,5 +1,5 @@ -/* $Id: sunserial.h,v 1.13 1997/09/03 11:55:00 ecd Exp $ - * sunserial.h: SUN serial driver infrastructure. +/* $Id: sunserial.h,v 1.17 1997/12/19 07:33:12 ecd Exp $ + * sunserial.h: SUN serial driver infrastructure (including keyboards). * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) */ @@ -7,42 +7,45 @@ #ifndef _SPARC_SUNSERIAL_H #define _SPARC_SUNSERIAL_H 1 +#include <linux/config.h> #include <linux/tty.h> +#include <linux/kd.h> +#include <linux/kbd_kern.h> +#include <linux/console.h> -struct rs_initfunc { - int (*rs_init) (void); - struct rs_initfunc *next; +struct initfunc { + int (*init) (void); + struct initfunc *next; }; struct sunserial_operations { - struct rs_initfunc *rs_init; - void (*rs_cons_hook) (int, int, int); - void (*rs_kgdb_hook) (int); - void (*rs_change_mouse_baud) (int); - int (*rs_read_proc) (char *, char **, off_t, int, int *, void *); + struct initfunc *rs_init; + void (*rs_kgdb_hook) (int); + void (*rs_change_mouse_baud) (int); + int (*rs_read_proc) (char *, char **, off_t, int, int *, void *); }; -/* - * XXX: Work in progress, don't worry this will go away in a few days. (ecd) - * - * To support multiple keyboards in one binary we have to take care - * about (at least) the following: - * - * int shift_state; - * - * char *func_buf; - * char *func_bufptr; - * int funcbufsize; - * int funcbufleft; - * char **func_table; - * - * XXX: keymaps need to be handled... - * - * struct kbd_struct *kbd_table; - * int (*kbd_init)(void); - */ +struct sunkbd_operations { + struct initfunc *kbd_init; + void (*compute_shiftstate) (void); + void (*setledstate) (struct kbd_struct *, unsigned int); + unsigned char (*getledstate) (void); + int (*setkeycode) (unsigned int, unsigned int); + int (*getkeycode) (unsigned int); +}; extern struct sunserial_operations rs_ops; +extern struct sunkbd_operations kbd_ops; + extern void sunserial_setinitfunc(unsigned long *, int (*) (void)); +extern void sunkbd_setinitfunc(unsigned long *, int (*) (void)); + +extern int serial_console; +extern void sunserial_console_termios(struct console *); + +#ifdef CONFIG_PCI +extern void sunkbd_install_keymaps(unsigned long *, ushort **, unsigned int, char *, + char **, int, int, struct kbdiacr *, unsigned int); +#endif #endif /* !(_SPARC_SUNSERIAL_H) */ diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index 007174a82..d144c7823 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -666,9 +666,6 @@ int init_module(void) int vfc_init(void) #endif { -#ifdef MODULE - register_symtab(0); -#endif return vfc_probe(); } diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index 8875f7dc7..6162ed4ad 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.3 1997/09/04 14:57:34 jj Exp $ +/* $Id: zs.c,v 1.15 1997/12/22 16:09:34 jj Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -22,8 +22,8 @@ #include <linux/keyboard.h> #include <linux/console.h> #include <linux/delay.h> -#include <linux/version.h> #include <linux/init.h> +#include <linux/sysrq.h> #include <asm/io.h> #include <asm/irq.h> @@ -36,6 +36,9 @@ #include <asm/sbus.h> #ifdef __sparc_v9__ #include <asm/fhc.h> +#ifdef CONFIG_PCI +#include <linux/bios32.h> +#endif #endif #include "sunserial.h" @@ -52,7 +55,6 @@ static int num_serial = 2; /* sun4/sun4c/sun4m - Two chips on board. */ struct sun_zslayout **zs_chips; struct sun_zschannel **zs_channels; -struct sun_zschannel *zs_conschan; struct sun_zschannel *zs_mousechan; struct sun_zschannel *zs_kbdchan; struct sun_zschannel *zs_kgdbchan; @@ -63,12 +65,12 @@ struct sun_serial *zs_chain; /* IRQ servicing chain */ int zilog_irq; struct tty_struct *zs_ttys; -/** struct tty_struct *zs_constty; **/ /* Console hooks... */ -static int zs_cons_chanout = 0; -static int zs_cons_chanin = 0; -struct sun_serial *zs_consinfo = 0; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console zs_console; +static int zs_console_init(void); +#endif static unsigned char kgdb_regs[16] = { 0, 0, 0, /* write 0, 1, 2 */ @@ -114,6 +116,8 @@ static int serial_refcount; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 +#define SERIAL_DO_RESTART + /* Debugging... DEBUG_INTR is bad to use when one of the zs * lines is your console ;( */ @@ -127,8 +131,7 @@ static int serial_refcount; #define _INLINE_ inline int zs_init(void); -void zs_cons_hook(int, int, int); -void zs_kgdb_hook(int); +static void zs_kgdb_hook(int); static void change_speed(struct sun_serial *info); @@ -443,20 +446,29 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs return; } if(info->is_cons) { +#ifdef CONFIG_MAGIC_SYSRQ + static int serial_sysrq; + + if (!ch) { + serial_sysrq = 1; + return; + } else if (serial_sysrq) { + if (ch == 'a' || ch == 'A') + /* whee, break-A received */ + batten_down_hatches(); + else + handle_sysrq(ch, regs, NULL, NULL); + serial_sysrq = 0; + return; + } +#else if(ch==0) { /* whee, break received */ batten_down_hatches(); /* Continue execution... */ return; -#if 0 - } else if (ch == 1) { - show_state(); - return; - } else if (ch == 2) { - show_buffers(); - return; -#endif } +#endif /* It is a 'keyboard interrupt' ;-) */ wake_up(&keypress_wait); } @@ -996,21 +1008,6 @@ void mouse_put_char(char ch) restore_flags(flags); } - -/* This is for console output over ttya/ttyb */ -static void zs_cons_put_char(char ch) -{ - struct sun_zschannel *chan = zs_conschan; - unsigned long flags; - - if(!chan) - return; - - save_flags(flags); cli(); - zs_put_char(chan, ch); - restore_flags(flags); -} - /* These are for receiving and sending characters under the kgdb * source level kernel debugger. */ @@ -1032,70 +1029,6 @@ char getDebugChar(void) return chan->data; } -/* - * Fair output driver allows a process to speak. - */ -static void zs_fair_output(void) -{ - int left; /* Output no more than that */ - unsigned long flags; - struct sun_serial *info = zs_consinfo; - char c; - - if (info == 0) return; - if (info->xmit_buf == 0) return; - - save_flags(flags); cli(); - left = info->xmit_cnt; - while (left != 0) { - c = info->xmit_buf[info->xmit_tail]; - info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - restore_flags(flags); - - zs_cons_put_char(c); - - cli(); - left = MIN(info->xmit_cnt, left-1); - } - - /* Last character is being transmitted now (hopefully). */ - zs_conschan->control = RES_Tx_P; - udelay(5); - - restore_flags(flags); - return; -} - -/* - * zs_console_print is registered for printk. - */ -static void zs_console_print(const char *s, unsigned count) -{ - int i; - - for (i = 0; i < count; i++, s++) { - if(*s == '\n') - zs_cons_put_char('\r'); - zs_cons_put_char(*s); - } - - /* Comment this if you want to have a strict interrupt-driven output */ - zs_fair_output(); -} - -static void zs_console_wait_key(void) -{ - sleep_on(&keypress_wait); -} - -static int zs_console_device(void) -{ - extern int serial_console; - - return MKDEV(TTYAUX_MAJOR, 64 + serial_console - 1); -} - static void zs_flush_chars(struct tty_struct *tty) { struct sun_serial *info = (struct sun_serial *)tty->driver_data; @@ -1190,7 +1123,7 @@ static int zs_write_room(struct tty_struct *tty) { struct sun_serial *info = (struct sun_serial *)tty->driver_data; int ret; - + if (serial_paranoia_check(info, tty->device, "zs_write_room")) return 0; ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; @@ -1202,7 +1135,7 @@ static int zs_write_room(struct tty_struct *tty) static int zs_chars_in_buffer(struct tty_struct *tty) { struct sun_serial *info = (struct sun_serial *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "zs_chars_in_buffer")) return 0; return info->xmit_cnt; @@ -1211,7 +1144,7 @@ static int zs_chars_in_buffer(struct tty_struct *tty) static void zs_flush_buffer(struct tty_struct *tty) { struct sun_serial *info = (struct sun_serial *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "zs_flush_buffer")) return; cli(); @@ -1641,10 +1574,13 @@ static void zs_close(struct tty_struct *tty, struct file * filp) void zs_hangup(struct tty_struct *tty) { struct sun_serial * info = (struct sun_serial *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "zs_hangup")) return; - + + if (info->is_cons) + return; + #ifdef SERIAL_DEBUG_OPEN printk("zs_hangup<%p: tty-%d, count = %d bye\n", __builtin_return_address(0), info->line, info->count); @@ -1862,6 +1798,14 @@ int zs_open(struct tty_struct *tty, struct file * filp) change_speed(info); } +#ifdef CONFIG_SERIAL_CONSOLE + if (zs_console.cflag && zs_console.index == line) { + tty->termios->c_cflag = zs_console.cflag; + zs_console.cflag = 0; + change_speed(info); + } +#endif + info->session = current->session; info->pgrp = current->pgrp; @@ -1875,7 +1819,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) static void show_serial_version(void) { - char *revision = "$Revision: 1.3 $"; + char *revision = "$Revision: 1.15 $"; char *version, *p; version = strchr(revision, ' '); @@ -1895,7 +1839,8 @@ static void show_serial_version(void) #ifdef __sparc_v9__ static struct devid_cookie zs_dcookie; static unsigned long zs_irq_flags; -static struct sun_zslayout *get_zs(int chip) +__initfunc(static struct sun_zslayout * +get_zs(int chip)) { unsigned int vaddr[2] = { 0, 0 }; int busnode, seen, zsnode, sun4u_ino; @@ -1968,13 +1913,16 @@ static struct sun_zslayout *get_zs(int chip) return (struct sun_zslayout *)(unsigned long) vaddr[0]; } #else /* !(__sparc_v9__) */ -static struct sun_zslayout *get_zs(int chip) +__initfunc(static struct sun_zslayout * +get_zs(int chip)) { struct linux_prom_irqs tmp_irq[2]; unsigned int paddr = 0; unsigned int vaddr[2] = { 0, 0 }; - int zsnode, tmpnode, iospace, slave, len, seen, sun4u_irq; + int zsnode, tmpnode, iospace, slave, len; + int cpunode = 0, bbnode = 0; static int irq = 0; + int chipid = chip; #if CONFIG_AP1000 printk("No zs chip\n"); @@ -2014,7 +1962,10 @@ static struct sun_zslayout *get_zs(int chip) if (board == (chip >> 1)) { node = prom_getchild(tmpnode); if (node && (node = prom_searchsiblings(node, "bootbus"))) { - zsnode = node; + cpunode = tmpnode; + bbnode = node; + zsnode = prom_getchild(node); + chipid = (chip & 1); break; } } @@ -2022,10 +1973,6 @@ static struct sun_zslayout *get_zs(int chip) } if (!tmpnode) panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1); - } else if (sparc_cpu_model == sun4u) { - tmpnode = prom_searchsiblings(zsnode, "sbus"); - if(tmpnode) - zsnode = prom_getchild(tmpnode); } else { tmpnode = prom_searchsiblings(zsnode, "obio"); if(tmpnode) @@ -2033,41 +1980,46 @@ static struct sun_zslayout *get_zs(int chip) } if(!zsnode) panic("get_zs no zs serial prom node"); - seen = 0; while(zsnode) { zsnode = prom_searchsiblings(zsnode, "zs"); slave = prom_getintdefault(zsnode, "slave", -1); - if((slave == chip) || - (sparc_cpu_model == sun4u && seen == chip)) { + if(slave == chipid) { /* The one we want */ - len = prom_getproperty(zsnode, "address", - (void *) vaddr, - sizeof(vaddr)); - if (len % sizeof(unsigned int)) { - prom_printf("WHOOPS: proplen for %s " - "was %d, need multiple of " - "%d\n", "address", len, - sizeof(unsigned int)); - panic("zilog: address property"); - } - zs_nodes[chip] = zsnode; - if(sparc_cpu_model == sun4u) { - len = prom_getproperty(zsnode, "interrupts", - (char *) &sun4u_irq, - sizeof(tmp_irq)); - tmp_irq[0].pri = sun4u_irq; - } else { - len = prom_getproperty(zsnode, "intr", - (char *) tmp_irq, - sizeof(tmp_irq)); - if (len % sizeof(struct linux_prom_irqs)) { - prom_printf( - "WHOOPS: proplen for %s " - "was %d, need multiple of " - "%d\n", "address", len, - sizeof(struct linux_prom_irqs)); + if (sparc_cpu_model != sun4d) { + len = prom_getproperty(zsnode, "address", + (void *) vaddr, + sizeof(vaddr)); + if (len % sizeof(unsigned int)) { + prom_printf("WHOOPS: proplen for %s " + "was %d, need multiple of " + "%d\n", "address", len, + sizeof(unsigned int)); panic("zilog: address property"); } + } else { + /* On sun4d don't have address property :( */ + struct linux_prom_registers zsreg[4]; + + if (prom_getproperty(zsnode, "reg", (char *)zsreg, sizeof(zsreg)) == -1) { + prom_printf ("Cannot map zs regs\n"); + prom_halt(); + } + prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1); + vaddr[0] = (unsigned long) + sparc_alloc_io(zsreg[0].phys_addr, 0, 8, + "Zilog Serial", zsreg[0].which_io, 0); + } + zs_nodes[chip] = zsnode; + len = prom_getproperty(zsnode, "intr", + (char *) tmp_irq, + sizeof(tmp_irq)); + if (len % sizeof(struct linux_prom_irqs)) { + prom_printf( + "WHOOPS: proplen for %s " + "was %d, need multiple of " + "%d\n", "address", len, + sizeof(struct linux_prom_irqs)); + panic("zilog: address property"); } if(!irq) { irq = zilog_irq = tmp_irq[0].pri; @@ -2078,7 +2030,6 @@ static struct sun_zslayout *get_zs(int chip) break; } zsnode = prom_getsibling(zsnode); - seen++; } if(!zsnode) panic("get_zs whee chip not found"); @@ -2089,242 +2040,6 @@ static struct sun_zslayout *get_zs(int chip) return (struct sun_zslayout *)(unsigned long) vaddr[0]; } #endif - -static inline void -init_zscons_termios(struct termios *termios) -{ - char mode[16], buf[16]; - char *mode_prop = "ttyX-mode"; - char *cd_prop = "ttyX-ignore-cd"; - char *dtr_prop = "ttyX-rts-dtr-off"; - char *s; - int baud, bits, cflag; - char parity; - int topnd, nd; - int channel, stop; - int carrier = 0; - int rtsdtr = 1; - extern int serial_console; - - if (!serial_console) - return; - - if (serial_console == 1) { - mode_prop[3] = 'a'; - cd_prop[3] = 'a'; - dtr_prop[3] = 'a'; - } else { - mode_prop[3] = 'b'; - cd_prop[3] = 'b'; - dtr_prop[3] = 'b'; - } - - topnd = prom_getchild(prom_root_node); - nd = prom_searchsiblings(topnd, "options"); - if (!nd) { - strcpy(mode, "9600,8,n,1,-"); - goto no_options; - } - - if (!prom_node_has_property(nd, mode_prop)) { - strcpy(mode, "9600,8,n,1,-"); - goto no_options; - } - - memset(mode, 0, sizeof(mode)); - prom_getstring(nd, mode_prop, mode, sizeof(mode)); - - if (prom_node_has_property(nd, cd_prop)) { - memset(buf, 0, sizeof(buf)); - prom_getstring(nd, cd_prop, buf, sizeof(buf)); - if (!strcmp(buf, "false")) - carrier = 1; - - /* XXX this is unused below. */ - } - - if (prom_node_has_property(nd, cd_prop)) { - memset(buf, 0, sizeof(buf)); - prom_getstring(nd, cd_prop, buf, sizeof(buf)); - if (!strcmp(buf, "false")) - rtsdtr = 0; - - /* XXX this is unused below. */ - } - -no_options: - cflag = CREAD | HUPCL | CLOCAL; - - s = mode; - baud = simple_strtoul(s, 0, 0); - s = strchr(s, ','); - bits = simple_strtoul(++s, 0, 0); - s = strchr(s, ','); - parity = *(++s); - s = strchr(s, ','); - stop = simple_strtoul(++s, 0, 0); - s = strchr(s, ','); - /* XXX handshake is not handled here. */ - - for (channel = 0; channel < NUM_CHANNELS; channel++) - if (zs_soft[channel].is_cons) - break; - - switch (baud) { - case 150: - cflag |= B150; - break; - case 300: - cflag |= B300; - break; - case 600: - cflag |= B600; - break; - case 1200: - cflag |= B1200; - break; - case 2400: - cflag |= B2400; - break; - case 4800: - cflag |= B4800; - break; - default: - baud = 9600; - case 9600: - cflag |= B9600; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - } - zs_soft[channel].zs_baud = baud; - - switch (bits) { - case 5: - zscons_regs[3] = Rx5 | RxENAB; - zscons_regs[5] = Tx5 | TxENAB; - zs_soft[channel].parity_mask = 0x1f; - cflag |= CS5; - break; - case 6: - zscons_regs[3] = Rx6 | RxENAB; - zscons_regs[5] = Tx6 | TxENAB; - zs_soft[channel].parity_mask = 0x3f; - cflag |= CS6; - break; - case 7: - zscons_regs[3] = Rx7 | RxENAB; - zscons_regs[5] = Tx7 | TxENAB; - zs_soft[channel].parity_mask = 0x7f; - cflag |= CS7; - break; - default: - case 8: - zscons_regs[3] = Rx8 | RxENAB; - zscons_regs[5] = Tx8 | TxENAB; - zs_soft[channel].parity_mask = 0xff; - cflag |= CS8; - break; - } - zscons_regs[5] |= DTR; - - switch (parity) { - case 'o': - zscons_regs[4] |= PAR_ENAB; - cflag |= (PARENB | PARODD); - break; - case 'e': - zscons_regs[4] |= (PAR_ENAB | PAR_EVEN); - cflag |= PARENB; - break; - default: - case 'n': - break; - } - - switch (stop) { - default: - case 1: - zscons_regs[4] |= SB1; - break; - case 2: - cflag |= CSTOPB; - zscons_regs[4] |= SB2; - break; - } - - termios->c_cflag = cflag; -} - -__initfunc(static void serial_finish_init(void (*printfunc)(const char *, unsigned))) -{ - extern unsigned char *linux_serial_image; - char buffer[2048]; - - sprintf (buffer, linux_serial_image, UTS_RELEASE); - (*printfunc)(buffer, strlen(buffer)); -} - -static inline void -zs_cons_check(struct sun_serial *ss, int channel) -{ - int i, o, io; - static int consout_registered = 0; - static int msg_printed = 0; - static struct console console = { - zs_console_print, 0, - zs_console_wait_key, zs_console_device }; - - i = o = io = 0; - - /* Is this one of the serial console lines? */ - if((zs_cons_chanout != channel) && - (zs_cons_chanin != channel)) - return; - zs_conschan = ss->zs_channel; - zs_consinfo = ss; - - /* Register the console output putchar, if necessary */ - if((zs_cons_chanout == channel)) { - o = 1; - /* double whee.. */ - if(!consout_registered) { - serial_finish_init (zs_console_print); - register_console(&console); - consout_registered = 1; - } - } - - /* If this is console input, we handle the break received - * status interrupt on this line to mean prom_halt(). - */ - if(zs_cons_chanin == channel) { - ss->break_abort = 1; - i = 1; - } - if(o && i) - io = 1; - - /* Set flag variable for this port so that it cannot be - * opened for other uses by accident. - */ - ss->is_cons = 1; - - if(io) { - if(!msg_printed) { - printk("zs%d: console I/O\n", ((channel>>1)&1)); - msg_printed = 1; - } - } else { - printk("zs%d: console %s\n", ((channel>>1)&1), - (i==1 ? "input" : (o==1 ? "output" : "WEIRD"))); - } -} - /* This is for the auto baud rate detection in the mouse driver. */ void zs_change_mouse_baud(int newbaud) { @@ -2347,10 +2062,11 @@ __initfunc(int zs_probe (unsigned long *memory_start)) if(sparc_cpu_model == sun4) goto no_probe; + NUM_SERIAL = 0; + node = prom_getchild(prom_root_node); if (sparc_cpu_model == sun4d) { node = prom_searchsiblings(node, "boards"); - NUM_SERIAL = 0; if (!node) panic ("Cannot find out count of boards"); else @@ -2360,22 +2076,38 @@ __initfunc(int zs_probe (unsigned long *memory_start)) node = prom_getsibling(node); } goto no_probe; - } else if (sparc_cpu_model == sun4u) { - node = prom_searchsiblings(node, "sbus"); - if(node) + } +#ifdef __sparc_v9__ + else if (sparc_cpu_model == sun4u) { + int central_node; + + /* Central bus zilogs must be checked for first, + * since Enterprise boxes have SBUS as well. + */ + central_node = prom_finddevice("/central"); + if(central_node != 0 && central_node != -1) + node = prom_searchsiblings(prom_getchild(central_node), "fhc"); + else + node = prom_searchsiblings(node, "sbus"); + if(node != 0 && node != -1) node = prom_getchild(node); - if(!node) + if(node == 0 || node == -1) return -ENODEV; - } else { + } +#endif /* __sparc_v9__ */ + else { node = prom_searchsiblings(node, "obio"); if(node) node = prom_getchild(node); + NUM_SERIAL = 2; goto no_probe; } node = prom_searchsiblings(node, "zs"); if (!node) return -ENODEV; + + NUM_SERIAL = 2; no_probe: p = (char *)((*memory_start + 7) & ~7); @@ -2399,17 +2131,85 @@ no_probe: *memory_start = (((unsigned long)p) + i + 7) & ~7; /* Fill in rs_ops struct... */ +#ifdef CONFIG_SERIAL_CONSOLE + sunserial_setinitfunc(memory_start, zs_console_init); +#endif sunserial_setinitfunc(memory_start, zs_init); - rs_ops.rs_cons_hook = zs_cons_hook; rs_ops.rs_kgdb_hook = zs_kgdb_hook; rs_ops.rs_change_mouse_baud = zs_change_mouse_baud; + sunkbd_setinitfunc(memory_start, sun_kbd_init); + kbd_ops.compute_shiftstate = sun_compute_shiftstate; + kbd_ops.setledstate = sun_setledstate; + kbd_ops.getledstate = sun_getledstate; + kbd_ops.setkeycode = sun_setkeycode; + kbd_ops.getkeycode = sun_getkeycode; +#ifdef CONFIG_PCI + sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count, + sun_func_buf, sun_func_table, + sun_funcbufsize, sun_funcbufleft, + sun_accent_table, sun_accent_table_size); +#endif return 0; } +static inline void zs_prepare(void) +{ + int channel, chip; + unsigned long flags; + + if (!NUM_SERIAL) return; + + save_and_cli(flags); + + /* Set up our interrupt linked list */ + zs_chain = &zs_soft[0]; + for(channel = 0; channel < NUM_CHANNELS - 1; channel++) { + zs_soft[channel].zs_next = &zs_soft[channel + 1]; + zs_soft[channel].line = channel; + } + zs_soft[channel].zs_next = 0; + + /* Initialize Softinfo */ + for(chip = 0; chip < NUM_SERIAL; chip++) { + /* If we are doing kgdb over one of the channels on + * chip zero, kgdb_channel will be set to 1 by the + * zs_kgdb_hook() routine below. + */ + if(!zs_chips[chip]) { + zs_chips[chip] = get_zs(chip); + /* Two channels per chip */ + zs_channels[(chip*2)] = &zs_chips[chip]->channelA; + zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; + zs_soft[(chip*2)].kgdb_channel = 0; + zs_soft[(chip*2)+1].kgdb_channel = 0; + } + + /* First, set up channel A on this chip. */ + channel = chip * 2; + zs_soft[channel].zs_channel = zs_channels[channel]; + zs_soft[channel].change_needed = 0; + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].cons_keyb = 0; + zs_soft[channel].cons_mouse = 0; + zs_soft[channel].channelA = 1; + + /* Now, channel B */ + channel++; + zs_soft[channel].zs_channel = zs_channels[channel]; + zs_soft[channel].change_needed = 0; + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].cons_keyb = 0; + zs_soft[channel].cons_mouse = 0; + zs_soft[channel].channelA = 0; + } + + restore_flags(flags); +} + __initfunc(int zs_init(void)) { - int chip, channel, brg, i; + int channel, brg, i; unsigned long flags; struct sun_serial *info; char dummy; @@ -2420,7 +2220,7 @@ __initfunc(int zs_init(void)) #endif #ifdef CONFIG_PCI - if (prom_searchsiblings(prom_getchild(prom_root_node), "pci")) + if (pcibios_present()) return 0; #endif @@ -2444,7 +2244,6 @@ __initfunc(int zs_init(void)) serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver.flags = TTY_DRIVER_REAL_RAW; @@ -2472,8 +2271,6 @@ __initfunc(int zs_init(void)) serial_driver.read_proc = 0; serial_driver.proc_entry = 0; - init_zscons_termios(&serial_driver.init_termios); - /* * The callout device is just like normal device except for * major number and the subtype code. @@ -2487,48 +2284,11 @@ __initfunc(int zs_init(void)) panic("Couldn't register serial driver\n"); if (tty_register_driver(&callout_driver)) panic("Couldn't register callout driver\n"); - - save_flags(flags); cli(); - /* Set up our interrupt linked list */ - zs_chain = &zs_soft[0]; - for(channel = 0; channel < NUM_CHANNELS - 1; channel++) - zs_soft[channel].zs_next = &zs_soft[channel + 1]; - zs_soft[channel + 1].zs_next = 0; + save_flags(flags); cli(); /* Initialize Softinfo */ - for(chip = 0; chip < NUM_SERIAL; chip++) { - /* If we are doing kgdb over one of the channels on - * chip zero, kgdb_channel will be set to 1 by the - * zs_kgdb_hook() routine below. - */ - if(!zs_chips[chip]) { - zs_chips[chip] = get_zs(chip); - /* Two channels per chip */ - zs_channels[(chip*2)] = &zs_chips[chip]->channelA; - zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; - zs_soft[(chip*2)].kgdb_channel = 0; - zs_soft[(chip*2)+1].kgdb_channel = 0; - } - - /* First, set up channel A on this chip. */ - channel = chip * 2; - zs_soft[channel].zs_channel = zs_channels[channel]; - zs_soft[channel].change_needed = 0; - zs_soft[channel].clk_divisor = 16; - zs_soft[channel].cons_keyb = 0; - zs_soft[channel].cons_mouse = 0; - zs_soft[channel].channelA = 1; - - /* Now, channel B */ - channel++; - zs_soft[channel].zs_channel = zs_channels[channel]; - zs_soft[channel].change_needed = 0; - zs_soft[channel].clk_divisor = 16; - zs_soft[channel].cons_keyb = 0; - zs_soft[channel].cons_mouse = 0; - zs_soft[channel].channelA = 0; - } + zs_prepare(); /* Initialize Hardware */ for(channel = 0; channel < NUM_CHANNELS; channel++) { @@ -2719,50 +2479,13 @@ __initfunc(int zs_init(void)) return 0; } -/* Hooks for running a serial console. con_init() calls this if the - * console is being run over one of the ttya/ttyb serial ports. - * 'chip' should be zero, as chip 1 drives the mouse/keyboard. - * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels - * are addressed backwards, channel B is first, then channel A. - */ -void -zs_cons_hook(int chip, int out, int line) -{ - int channel; - -#ifdef CONFIG_PCI - if (prom_searchsiblings(prom_getchild(prom_root_node), "pci")) - return; -#endif - - if(chip) - panic("zs_cons_hook called with chip not zero"); - if(line != 1 && line != 2) - panic("zs_cons_hook called with line not ttya or ttyb"); - channel = line - 1; - if(!zs_chips[chip]) { - zs_chips[chip] = get_zs(chip); - /* Two channels per chip */ - zs_channels[(chip*2)] = &zs_chips[chip]->channelA; - zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; - } - zs_soft[channel].zs_channel = zs_channels[channel]; - zs_soft[channel].change_needed = 0; - zs_soft[channel].clk_divisor = 16; - if(out) - zs_cons_chanout = ((chip * 2) + channel); - else - zs_cons_chanin = ((chip * 2) + channel); - zs_cons_check(&zs_soft[channel], channel); -} - /* This is called at boot time to prime the kgdb serial debugging * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1 * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */ -void -zs_kgdb_hook(int tty_num) +__initfunc(static void +zs_kgdb_hook(int tty_num)) { int chip = 0; @@ -2784,3 +2507,183 @@ zs_kgdb_hook(int tty_num) ZS_CLEARERR(zs_kgdbchan); ZS_CLEARFIFO(zs_kgdbchan); } + +#ifdef CONFIG_SERIAL_CONSOLE + +/* This is for console output over ttya/ttyb */ +static void +zs_console_putchar(struct sun_serial *info, char ch) +{ + unsigned long flags; + + if(!info->zs_channel) + return; + + save_flags(flags); cli(); + zs_put_char(info->zs_channel, ch); + restore_flags(flags); +} + +/* + * Fair output driver allows a process to speak. + */ +static void zs_fair_output(struct sun_serial *info) +{ + int left; /* Output no more than that */ + unsigned long flags; + char c; + + if (info == 0) return; + if (info->xmit_buf == 0) return; + + save_flags(flags); cli(); + left = info->xmit_cnt; + while (left != 0) { + c = info->xmit_buf[info->xmit_tail]; + info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + restore_flags(flags); + + zs_console_putchar(info, c); + + cli(); + left = MIN(info->xmit_cnt, left-1); + } + + /* Last character is being transmitted now (hopefully). */ + info->zs_channel->control = RES_Tx_P; + udelay(5); + + restore_flags(flags); + return; +} + +/* + * zs_console_write is registered for printk. + */ +static void +zs_console_write(struct console *con, const char *s, unsigned count) +{ + struct sun_serial *info; + int i; + + info = zs_soft + con->index; + + for (i = 0; i < count; i++, s++) { + if(*s == '\n') + zs_console_putchar(info, '\r'); + zs_console_putchar(info, *s); + } + + /* Comment this if you want to have a strict interrupt-driven output */ + zs_fair_output(info); +} + +static int +zs_console_wait_key(struct console *con) +{ + sleep_on(&keypress_wait); + return 0; +} + +static kdev_t zs_console_device(struct console *con) +{ + return MKDEV(TTY_MAJOR, 64 + con->index); +} + +__initfunc(static int +zs_console_setup(struct console *con, char *options)) +{ + struct sun_serial *info; + int i, brg, baud; + + info = zs_soft + con->index; + info->is_cons = 1; + + printk("Console: ttyS%d (Zilog8530)\n", info->line); + + sunserial_console_termios(con); + + i = con->cflag & CBAUD; + if (con->cflag & CBAUDEX) { + i &= ~CBAUDEX; + con->cflag &= ~CBAUDEX; + } + baud = baud_table[i]; + info->zs_baud = baud; + + switch (con->cflag & CSIZE) { + case CS5: + zscons_regs[3] = Rx5 | RxENAB; + zscons_regs[5] = Tx5 | TxENAB; + info->parity_mask = 0x1f; + break; + case CS6: + zscons_regs[3] = Rx6 | RxENAB; + zscons_regs[5] = Tx6 | TxENAB; + info->parity_mask = 0x3f; + break; + case CS7: + zscons_regs[3] = Rx7 | RxENAB; + zscons_regs[5] = Tx7 | TxENAB; + info->parity_mask = 0x7f; + break; + default: + case CS8: + zscons_regs[3] = Rx8 | RxENAB; + zscons_regs[5] = Tx8 | TxENAB; + info->parity_mask = 0xff; + break; + } + zscons_regs[5] |= DTR; + + if (con->cflag & PARENB) + zscons_regs[4] |= PAR_ENAB; + if (!(con->cflag & PARODD)) + zscons_regs[4] |= PAR_EVEN; + + if (con->cflag & CSTOPB) + zscons_regs[4] |= SB2; + else + zscons_regs[4] |= SB1; + + brg = BPS_TO_BRG(baud, ZS_CLOCK / info->clk_divisor); + zscons_regs[12] = brg & 0xff; + zscons_regs[13] = (brg >> 8) & 0xff; + + memcpy(info->curregs, zscons_regs, sizeof(zscons_regs)); + load_zsregs(info, zscons_regs); + + ZS_CLEARERR(info->zs_channel); + ZS_CLEARFIFO(info->zs_channel); + return 0; +} + +static struct console zs_console = { + "ttyS", + zs_console_write, + NULL, + zs_console_device, + zs_console_wait_key, + NULL, + zs_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +__initfunc(static int +zs_console_init(void)) +{ + extern int con_is_present(void); + + if (con_is_present()) + return 0; + + zs_console.index = serial_console - 1; + register_console(&zs_console); + return 0; +} + +#endif /* CONFIG_SERIAL_CONSOLE */ |