From 6994774aa83f816dc72112cbdc43a5fb4b184b62 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:29:48 -0500 Subject: [PATCH] Import 2.3.36pre6 --- Documentation/Configure.help | 93 ++- arch/i386/kernel/pci-i386.c | 34 +- arch/sparc/kernel/ioport.c | 15 +- arch/sparc/kernel/irq.c | 3 +- arch/sparc/kernel/process.c | 3 +- arch/sparc/kernel/semaphore.c | 119 ++- arch/sparc/kernel/signal.c | 3 +- arch/sparc/kernel/smp.c | 1 + arch/sparc/kernel/sparc-stub.c | 3 +- arch/sparc/kernel/sun4d_irq.c | 3 +- arch/sparc/kernel/sun4d_smp.c | 1 + arch/sparc/kernel/sun4m_irq.c | 1 + arch/sparc/kernel/sun4m_smp.c | 1 + arch/sparc/kernel/sys_sunos.c | 4 +- arch/sparc/lib/Makefile | 86 +-- arch/sparc/lib/rwsem.S | 192 +++++ arch/sparc/mm/asyncd.c | 3 +- arch/sparc/mm/btfixup.c | 3 +- arch/sparc/mm/generic.c | 5 +- arch/sparc/mm/init.c | 34 +- arch/sparc/mm/io-unit.c | 3 +- arch/sparc/mm/iommu.c | 3 +- arch/sparc/mm/sun4c.c | 22 +- arch/sparc64/defconfig | 1 + arch/sparc64/kernel/pci.c | 7 +- arch/sparc64/kernel/semaphore.c | 174 ++++- arch/sparc64/lib/VISmemset.S | 29 +- drivers/pci/names.c | 1 - drivers/pci/pci.c | 74 +- drivers/pcmcia/Config.in | 1 - drivers/pcmcia/Makefile | 13 +- drivers/pcmcia/cardbus.c | 736 ++++++++---------- drivers/pcmcia/cs.c | 1 + drivers/pcmcia/cs_internal.h | 6 +- drivers/pcmcia/i82365.c | 1261 +------------------------------ drivers/pcmcia/pci_socket.c | 48 +- drivers/pcmcia/pci_socket.h | 2 - drivers/pcmcia/tcic.c | 9 - drivers/pcmcia/yenta.c | 205 +++-- drivers/usb/Config.in | 21 +- drivers/usb/Makefile | 127 ++-- drivers/usb/README.hid | 162 ++++ drivers/usb/README.kbd | 65 -- drivers/usb/README.ov511 | 70 ++ drivers/usb/evdev.c | 275 +++++++ drivers/usb/hid-debug.h | 233 ++++++ drivers/usb/hid.c | 1203 +++++++++++++++++++++++++++++ drivers/usb/hid.h | 345 +++++++++ drivers/usb/inits.h | 10 +- drivers/usb/input.c | 335 ++++++++ drivers/usb/joydev.c | 476 ++++++++++++ drivers/usb/keybdev.c | 139 ++++ drivers/usb/keyboard.c | 295 -------- drivers/usb/keymap-mac.c | 50 -- drivers/usb/keymap.c | 50 -- drivers/usb/maps/fixup.map | 30 - drivers/usb/maps/mac.map | 350 --------- drivers/usb/maps/serial.map | 370 --------- drivers/usb/maps/usb.map | 233 ------ drivers/usb/mkmap | 83 -- drivers/usb/mkmap.adb | 88 --- drivers/usb/mouse.c | 498 ------------ drivers/usb/mousedev.c | 457 +++++++++++ drivers/usb/ov511.c | 1241 ++++++++++++++++++++++++++++++ drivers/usb/ov511.h | 209 +++++ drivers/usb/usb-core.c | 24 +- drivers/usb/usb-serial.c | 973 +++++++++++------------- drivers/usb/usb.c | 48 +- drivers/usb/usb.h | 16 +- drivers/usb/usbkbd.c | 208 +++++ drivers/usb/usbmouse.c | 148 ++++ fs/cramfs/inflate/Makefile | 6 +- fs/cramfs/inflate/infblock.c | 19 - fs/cramfs/inflate/infcodes.c | 9 - fs/cramfs/inflate/inffast.c | 9 - fs/cramfs/inflate/inflate.c | 5 - fs/cramfs/inflate/zutil.h | 56 +- fs/filesystems.c | 4 + fs/openpromfs/inode.c | 4 +- fs/super.c | 2 - include/asm-sparc/dma.h | 3 +- include/asm-sparc/fcntl.h | 3 +- include/asm-sparc/pgalloc.h | 157 ++++ include/asm-sparc/pgtable.h | 174 +---- include/asm-sparc/sbus.h | 4 +- include/asm-sparc/scatterlist.h | 4 +- include/asm-sparc/semaphore.h | 188 +++++ include/asm-sparc/sfp-machine.h | 2 +- include/asm-sparc64/semaphore.h | 263 ++++++- include/asm-sparc64/string.h | 32 +- include/linux/input.h | 443 +++++++++++ include/linux/pci.h | 1 + include/pcmcia/ss.h | 2 - net/core/skbuff.c | 7 +- net/ipv6/tcp_ipv6.c | 7 +- net/netsyms.c | 1 + 96 files changed, 8412 insertions(+), 5028 deletions(-) create mode 100644 arch/sparc/lib/rwsem.S create mode 100644 drivers/usb/README.hid delete mode 100644 drivers/usb/README.kbd create mode 100644 drivers/usb/README.ov511 create mode 100644 drivers/usb/evdev.c create mode 100644 drivers/usb/hid-debug.h create mode 100644 drivers/usb/hid.c create mode 100644 drivers/usb/hid.h create mode 100644 drivers/usb/input.c create mode 100644 drivers/usb/joydev.c create mode 100644 drivers/usb/keybdev.c delete mode 100644 drivers/usb/keyboard.c delete mode 100644 drivers/usb/keymap-mac.c delete mode 100644 drivers/usb/keymap.c delete mode 100644 drivers/usb/maps/fixup.map delete mode 100644 drivers/usb/maps/mac.map delete mode 100644 drivers/usb/maps/serial.map delete mode 100644 drivers/usb/maps/usb.map delete mode 100644 drivers/usb/mkmap delete mode 100644 drivers/usb/mkmap.adb delete mode 100644 drivers/usb/mouse.c create mode 100644 drivers/usb/mousedev.c create mode 100644 drivers/usb/ov511.c create mode 100644 drivers/usb/ov511.h create mode 100644 drivers/usb/usbkbd.c create mode 100644 drivers/usb/usbmouse.c create mode 100644 include/asm-sparc/pgalloc.h create mode 100644 include/linux/input.h diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 27e30c5ded6c..848974d1e5c5 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -7906,15 +7906,62 @@ CONFIG_USB_OHCI_HCD The module will be called usb-ohci-hcd.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB mouse support +USB Human Interface Device (HID) support +CONFIG_USB_HID + Say Y here if you want to connect a keyboard, mouse, joystick, + graphic tablet, UPS or any other HID based devices to your computer + via USB. + +USB HIDBP Keyboard support +CONFIG_USB_KBD + Say Y here if you don't want to use the generic HID driver for your + USB keyboard and prefer to use the keyboard in its limited Boot + Protocol mode. This driver is much smaller than the HID one. + +USB HIDBP Mouse support CONFIG_USB_MOUSE - Say Y here if you want to connect a USB mouse to your computer's USB - port. + Say Y here if you don't want to use the generic HID driver for your + USB mouse and prefer to use the mouse in its limited Boot Protocol + mode. This driver is much smaller than the HID one. + +Keyboard support +CONFIG_INPUT_KEYBDEV + Say Y here if you want your USB HID keyboard to be able to serve as + a system keyboard. + +Mouse support +CONFIG_INPUT_MOUSEDEV + Say Y here if you want your USB HID mouse to be accessible as + misc devices 32+ under /dev/, as an emulated PS/2 mouse. + +Mix all mice into one device +CONFIG_INPUT_MOUSEDEV_MIX + Say Y here if you want input from all your USB HID mice to be mixed + into one misc device. If you say N, you'll have a separate + device for each your USB mouse. - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called mouse.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. +Joystick support +CONFIG_INPUT_JOYDEV + Say Y here if you want your USB HID joystick or gamepad to be + accessible as /dev/js device. You can't use a normal joystick + if you select this. + +Event interface support +CONFIG_INPUT_EVDEV + Say Y here if you want your USB HID device events be accessible + under /dev/inputX (misc 64+) in a generic way. + This is the future ... + +USB HID debug output +CONFIG_USB_HID_DEBUG + Say Y here if you want to see what the HID driver is doing, + perhaps it's doing something wrong with your device. + +USB HID lots of debug output +CONFIG_USB_HID_DEBUG_LOTS + Say Y here if you don't fear to read all the HID dumps the + HID driver will generate when you switch this on. Really LOTS + of debug output. USB scanner support CONFIG_USB_SCANNER @@ -7927,16 +7974,6 @@ CONFIG_USB_SCANNER The module will be called hp_scanner.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB keyboard support -CONFIG_USB_KBD - Say Y here if you want to connect a USB keyboard to your computer's - USB port. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called usb-keyboard.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. - USB audio parsing support CONFIG_USB_AUDIO Say Y here if you want to connect USB audio equipment such as @@ -7961,9 +7998,9 @@ CONFIG_USB_ACM USB serial converter support CONFIG_USB_SERIAL Say Y here if you want to connect a Connect Tech WhiteHEAT - multi-port USB to serial converter, or a Belkin, Peracom, or eTek - single port USB to serial converter. - + multi-port USB to serial converter; a Belkin, Peracom, or eTek + single port USB to serial converter; or a Handspring Visor. + This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called usb-serial.o. If you want to compile it @@ -7989,6 +8026,20 @@ CONFIG_USB_CPIA The module will be called cpia.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB OV511 Camera support +CONFIG_USB_OV511 + Say Y here if you want to connect this type of camera to your + computer's USB port. See drivers/usb/README.ov511 for more + information and for a list of supported cameras. + + NOTE: This code is experimental and you will not get video with it + yet. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ov511.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + USB Kodak DC-2xx Camera support CONFIG_USB_DC2XX Say Y here if you want to connect this type of still camera to @@ -13497,4 +13548,4 @@ CONFIG_I2C_CHARDEV # LocalWords: adbmouse DRI DRM dlabs GMX PLCs Applicom fieldbus applicom int # LocalWords: VWSND eg ESSSOLO CFU CFNR scribed eiconctrl eicon hylafax KFPU # LocalWords: EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator -# LocalWords: LOGIBUSMOUSE +# LocalWords: LOGIBUSMOUSE OV511 ov511 diff --git a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c index 2caba180732b..2197597c880c 100644 --- a/arch/i386/kernel/pci-i386.c +++ b/arch/i386/kernel/pci-i386.c @@ -256,25 +256,31 @@ static void __init pcibios_assign_resources(void) struct resource *r; for(dev=pci_devices; dev; dev=dev->next) { + int class = dev->class >> 8; + + /* Don't touch classless devices and host bridges */ + if (!class || class == PCI_CLASS_BRIDGE_HOST) + continue; + for(idx=0; idx<6; idx++) { r = &dev->resource[idx]; - if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) || - ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)) || - !dev->class || (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) - /* - * Don't touch IDE controllers and I/O ports of video cards! - * Also avoid classless devices and host bridges. - */ + + /* + * Don't touch IDE controllers and I/O ports of video cards! + */ + if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || + (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) continue; - if (!r->start && r->end) { - /* - * We shall assign a new address to this resource, either because - * the BIOS forgot to do so or because we have decided the old - * address was unusable for some reason. - */ + + /* + * We shall assign a new address to this resource, either because + * the BIOS forgot to do so or because we have decided the old + * address was unusable for some reason. + */ + if (!r->start && r->end) pci_assign_resource(dev, idx); - } } + if (pci_probe & PCI_ASSIGN_ROMS) { r = &dev->resource[PCI_ROM_RESOURCE]; r->end -= r->start; diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 3ecb4560de0a..e2b6b1ae4fdc 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.27 1999/11/14 06:23:04 zaitcev Exp $ +/* $Id: ioport.c,v 1.28 1999/12/27 06:08:28 anton Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -20,6 +20,7 @@ #include #include #include +#include #include struct resource *sparc_find_resource_bystart(struct resource *, unsigned long); @@ -228,7 +229,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) if (allocate_resource(&sparc_iomap, res, (offset + sz + PAGE_SIZE-1) & PAGE_MASK, - sparc_iomap.start, sparc_iomap.end, PAGE_SIZE) != 0) { + sparc_iomap.start, sparc_iomap.end, PAGE_SIZE, NULL, NULL) != 0) { /* Usually we cannot see printks in this case. */ prom_printf("alloc_io_res(%s): cannot occupy\n", (res->name != NULL)? res->name: "???"); @@ -320,7 +321,7 @@ void *sbus_alloc_consistant(struct sbus_dev *sdev, long len, u32 *dma_addrp) } if (allocate_resource(&sparc_dvma, res, len_total, - sparc_dvma.start, sparc_dvma.end, PAGE_SIZE) != 0) { + sparc_dvma.start, sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { printk("sbus_alloc_consistant: cannot occupy 0x%lx", len); free_pages(va, order); kfree(res); @@ -460,10 +461,16 @@ void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n) #endif } -void sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) { /* BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */ mmu_get_scsi_sgl(sg, n, sdev->bus); + + /* + * XXX sparc64 can return a partial length here. sun4c should do this + * but it currently panics if it can't fulfill the request - Anton + */ + return n; } void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 446927212f98..c89d04872ea8 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.98 1999/11/17 07:34:05 zaitcev Exp $ +/* $Id: irq.c,v 1.99 1999/12/27 06:08:29 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 615e8d17e53b..195f26df5502 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.141 1999/10/24 06:25:02 anton Exp $ +/* $Id: process.c,v 1.142 1999/12/27 06:08:31 anton Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/semaphore.c b/arch/sparc/kernel/semaphore.c index 2f2c8ecc7e36..1dcf35d4296a 100644 --- a/arch/sparc/kernel/semaphore.c +++ b/arch/sparc/kernel/semaphore.c @@ -1,5 +1,5 @@ -/* $Id: semaphore.c,v 1.1 1999/08/31 13:26:15 anton Exp $ - * Generic semaphore code. Buyer beware. Do your own +/* $Id: semaphore.c,v 1.2 1999/12/28 11:50:37 jj Exp $ + * Generic semaphore code. Buyer beware. Do your own * specific changes in */ @@ -62,8 +62,7 @@ void __up(struct semaphore *sem) #define DOWN_VAR \ struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); + DECLARE_WAITQUEUE(wait, tsk); #define DOWN_HEAD(task_state) \ \ @@ -127,3 +126,115 @@ int __down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); } + +/* rw mutexes + * Implemented by Jakub Jelinek (jakub@redhat.com) based on + * i386 implementation by Ben LaHaise (bcrl@redhat.com). + */ + +extern inline int ldstub(unsigned char *p) +{ + int ret; + asm volatile("ldstub %1, %0" : "=r" (ret) : "m" (*p) : "memory"); + return ret; +} + +void down_read_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (!ldstub(&sem->read_not_granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->read_not_granted) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void down_write_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (!ldstub(&sem->write_not_granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->write_not_granted) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (sem->count >= 0) + wake_up(&sem->wait); +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +void down_read_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->count >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +void down_write_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->count >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers) +{ + if (readers) { + /* Due to lame ldstub we don't do here + a BUG() consistency check */ + sem->read_not_granted = 0; + wake_up(&sem->wait); + } else { + sem->write_not_granted = 0; + wake_up(&sem->write_bias_wait); + } +} diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 0b2f35a9add8..ea0c7e1ffe39 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.98 1999/12/15 22:24:23 davem Exp $ +/* $Id: signal.c,v 1.99 1999/12/27 06:08:32 anton Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -22,6 +22,7 @@ #include #include #include +#include #include #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index dca81c77dfce..58f1be4e80e5 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c index 8cd0e8b6d3f4..c9bb60a866f0 100644 --- a/arch/sparc/kernel/sparc-stub.c +++ b/arch/sparc/kernel/sparc-stub.c @@ -1,4 +1,4 @@ -/* $Id: sparc-stub.c,v 1.25 1999/07/23 01:56:13 davem Exp $ +/* $Id: sparc-stub.c,v 1.26 1999/12/27 06:08:34 anton Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux @@ -107,6 +107,7 @@ #include #include #include +#include #include /* * diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 4b77bb3a6e18..dbbb4edca243 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -1,4 +1,4 @@ -/* $Id: sun4d_irq.c,v 1.23 1999/10/19 04:33:26 zaitcev Exp $ +/* $Id: sun4d_irq.c,v 1.24 1999/12/27 06:08:34 anton Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 93a6e77f8720..ec105ec18e7c 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 7c7df4a1e3e9..0f3cf9564aca 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 30a86d9d73e2..2d2d97810372 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 6be4cdb38551..247c673dff3c 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.106 1999/12/16 11:57:27 anton Exp $ +/* $Id: sys_sunos.c,v 1.107 1999/12/27 06:08:37 anton Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -198,7 +198,7 @@ asmlinkage int sunos_brk(unsigned long brk) freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT; freepages += atomic_read(&page_cache_size); freepages >>= 1; - freepages += nr_free_pages; + freepages += nr_free_pages(); freepages += nr_swap_pages; freepages -= num_physpages >> 4; freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index a4c28f6dcd3a..1a8c404e2982 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.30 1999/12/21 04:02:18 davem Exp $ +# $Id: Makefile,v 1.31 1999/12/28 11:50:39 jj Exp $ # Makefile for Sparc library files.. # @@ -6,7 +6,7 @@ OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \ - ashldi3.o + ashldi3.o rwsem.o ifdef CONFIG_SMP OBJS += irqlock.o @@ -16,85 +16,11 @@ lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) sync -checksum.o: checksum.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o checksum.o checksum.S +.S.s: + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 $< -o $*.s -memcpy.o: memcpy.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o memcpy.o memcpy.S - -memcmp.o: memcmp.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o memcmp.o memcmp.S - -memscan.o: memscan.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o memscan.o memscan.S - -strncmp.o: strncmp.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o strncmp.o strncmp.S - -strncpy_from_user.o: strncpy_from_user.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o strncpy_from_user.o strncpy_from_user.S - -strlen_user.o: strlen_user.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o strlen_user.o strlen_user.S - -copy_user.o: copy_user.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o copy_user.o copy_user.S - -blockops.o: blockops.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o blockops.o blockops.S - -memset.o: memset.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o memset.o memset.S - -locks.o: locks.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o locks.o locks.S - -atomic.o: atomic.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o atomic.o atomic.S - -bitops.o: bitops.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o bitops.o bitops.S - -ifdef CONFIG_SMP -irqlock.o: irqlock.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o irqlock.o irqlock.S -endif - -strlen.o: strlen.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o strlen.o strlen.S - -divdi3.o: divdi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o divdi3.o divdi3.S - -udivdi3.o: udivdi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o udivdi3.o udivdi3.S - -mul.o: mul.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o mul.o mul.S - -rem.o: rem.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -DST_DIV0=0x2 -c -o rem.o rem.S - -sdiv.o: sdiv.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -DST_DIV0=0x2 -c -o sdiv.o sdiv.S - -udiv.o: udiv.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -DST_DIV0=0x2 -c -o udiv.o udiv.S - -umul.o: umul.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o umul.o umul.S - -urem.o: urem.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -DST_DIV0=0x2 -c -o urem.o urem.S - -ashrdi3.o: ashrdi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o ashrdi3.o ashrdi3.S - -ashldi3.o: ashldi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o ashldi3.o ashldi3.S - -lshrdi3.o: lshrdi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o lshrdi3.o lshrdi3.S +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 -c $< -o $*.o dep: diff --git a/arch/sparc/lib/rwsem.S b/arch/sparc/lib/rwsem.S new file mode 100644 index 000000000000..4a6f2f4c0390 --- /dev/null +++ b/arch/sparc/lib/rwsem.S @@ -0,0 +1,192 @@ +/* $Id: rwsem.S,v 1.1 1999/12/28 11:50:39 jj Exp $ + * Assembly part of rw semaphores. + * + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) + */ + +#include +#include +#include + + .text + .align 4 + + .globl ___down_read +___down_read: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + nop + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + subcc %g7, 1, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + subcc %g7, 1, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bneg 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + bcs 4f + mov %g5, %l5 + call down_read_failed + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba ___down_read + restore %l5, %g0, %g5 +4: call down_read_failed_biased + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___down_write +___down_write: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + sethi %hi(0x01000000), %g2 + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + subcc %g7, %g2, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + subcc %g7, %g2, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bne 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + bcs 4f + mov %g5, %l5 + call down_write_failed + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba ___down_write + restore %l5, %g0, %g5 +4: call down_write_failed_biased + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___up_read +___up_read: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + nop + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + addcc %g7, 1, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + addcc %g7, 1, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + be 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 + clr %o1 + call __rwsem_wake + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___up_write +___up_write: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + sethi %hi(0x01000000), %g2 + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + addcc %g7, %g2, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + addcc %g7, %g2, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bcs 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 + mov %g7, %o1 + call __rwsem_wake + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 diff --git a/arch/sparc/mm/asyncd.c b/arch/sparc/mm/asyncd.c index d17979cd4426..6ed8a3c99288 100644 --- a/arch/sparc/mm/asyncd.c +++ b/arch/sparc/mm/asyncd.c @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.17 1999/08/14 03:51:44 anton Exp $ +/* $Id: asyncd.c,v 1.18 1999/12/27 06:30:02 anton Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -25,6 +25,7 @@ #include /* for cli()/sti() */ #include /* for memcpy_to/fromfs */ #include +#include #include #define DEBUG 0 diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c index 4ecf94360051..9b766f4eb603 100644 --- a/arch/sparc/mm/btfixup.c +++ b/arch/sparc/mm/btfixup.c @@ -1,4 +1,4 @@ -/* $Id: btfixup.c,v 1.8 1999/08/31 06:54:31 davem Exp $ +/* $Id: btfixup.c,v 1.9 1999/12/27 06:30:02 anton Exp $ * btfixup.c: Boot time code fixup and relocator, so that * we can get rid of most indirect calls to achieve single * image sun4c and srmmu kernel. @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c index 86786fb13b43..9e599fd9dac2 100644 --- a/arch/sparc/mm/generic.c +++ b/arch/sparc/mm/generic.c @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.8 1999/12/20 05:01:49 davem Exp $ +/* $Id: generic.c,v 1.9 1999/12/27 06:30:03 anton Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -27,7 +28,7 @@ static inline void forget_pte(pte_t page) free_page_and_swap_cache(mem_map+nr); return; } - swap_free(page); + swap_free(pte_to_swp_entry(page)); } /* Remap IO memory, the same way as remap_page_range(), but use diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 8849e47286a5..221496f98d7d 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.71 1999/12/16 12:58:33 anton Exp $ +/* $Id: init.c,v 1.72 1999/12/27 06:30:06 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -82,7 +82,7 @@ void show_mem(void) printk("Free swap: %6dkB\n", nr_swap_pages << (PAGE_SHIFT-10)); printk("%ld pages of RAM\n", totalram_pages); - printk("%d free pages\n", nr_free_pages); + printk("%d free pages\n", nr_free_pages()); printk("%ld pages in page table cache\n",pgtable_cache_size); #ifndef __SMP__ if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d) @@ -395,15 +395,17 @@ void __init mem_init(void) taint_real_pages(); + max_mapnr = last_valid_pfn; + high_memory = __va(last_valid_pfn << PAGE_SHIFT); + #ifdef DEBUG_BOOTMEM prom_printf("mem_init: Calling free_all_bootmem().\n"); #endif num_physpages = totalram_pages = free_all_bootmem(); +#if 0 free_unused_mem_map(); - - max_mapnr = last_valid_pfn; - high_memory = __va(last_valid_pfn << PAGE_SHIFT); +#endif codepages = (((unsigned long) &etext) - ((unsigned long)&_start)); codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT; @@ -413,7 +415,7 @@ void __init mem_init(void) initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT; printk("Memory: %dk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n", - nr_free_pages << (PAGE_SHIFT-10), + nr_free_pages() << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), @@ -423,7 +425,7 @@ void __init mem_init(void) * Please keep track of things and make sure this * always matches the code in mm/page_alloc.c -DaveM */ - i = nr_free_pages >> 7; + i = nr_free_pages() >> 7; if (i < 48) i = 48; if (i > 256) @@ -439,9 +441,17 @@ void free_initmem (void) addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - ClearPageReserved(mem_map + MAP_NR(addr)); - set_page_count(mem_map + MAP_NR(addr), 1); - free_page(addr); + unsigned long page; + struct page *p; + + page = (addr + + ((unsigned long) __va(phys_base)) - + PAGE_OFFSET); + p = mem_map + MAP_NR(page); + + ClearPageReserved(p); + set_page_count(p, 1); + __free_page(p); totalram_pages++; num_physpages++; } @@ -451,11 +461,11 @@ void si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages; + val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); val->totalhigh = 0; - val->freehigh = nr_free_highpages; + val->freehigh = 0; val->mem_unit = PAGE_SIZE; } diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index 5887532cd559..1a3476a161f3 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.17 1999/10/18 01:46:54 zaitcev Exp $ +/* $Id: io-unit.c,v 1.18 1999/12/28 04:28:55 anton Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 01a44806cfa0..041e00c6ac25 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -1,4 +1,4 @@ -/* $Id: iommu.c,v 1.15 1999/11/19 04:11:53 davem Exp $ +/* $Id: iommu.c,v 1.16 1999/12/28 04:28:54 anton Exp $ * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 676f0b6a3909..0530e635f1b0 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.181 1999/12/16 14:34:21 anton Exp $ +/* $Id: sun4c.c,v 1.182 1999/12/27 06:30:04 anton Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -1967,10 +1968,6 @@ static void sun4c_switch_mm_hw(struct mm_struct *old_mm, struct mm_struct *mm, s } else { /* Update the LRU ring of contexts. */ ctx = ctx_list_pool + mm->context; -#ifdef DEBUG_SUN4C_MM - if (!ctx->ctx_mm) - panic("context was not set up"); -#endif remove_from_ctx_list(ctx); add_to_used_ctxlist(ctx); } @@ -2027,10 +2024,6 @@ static void sun4c_switch_mm_sw(struct mm_struct *old_mm, struct mm_struct *mm, s } else { /* Update the LRU ring of contexts. */ ctx = ctx_list_pool + mm->context; -#ifdef DEBUG_SUN4C_MM - if (!ctx->ctx_mm) - panic("context was not set up"); -#endif remove_from_ctx_list(ctx); add_to_used_ctxlist(ctx); } @@ -2464,7 +2457,7 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr pgdp = sun4c_pgd_offset(vma->vm_mm, address); ptep = sun4c_pte_offset((pmd_t *) pgdp, address); *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); - pte = pte_val(*ptep); + pte = *ptep; } } } @@ -2586,7 +2579,14 @@ void __init sun4c_paging_init(void) swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg3); sun4c_init_ss2_cache_bug(); sparc_context_init(num_contexts); - free_area_init(end_pfn); + + { + unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + + zones_size[ZONE_DMA] = end_pfn; + free_area_init(zones_size); + } + cnt = 0; for (i = 0; i < num_segmaps; i++) if (mmu_entry_pool[i].locked) diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 8ca22aac9077..848984fef474 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -302,6 +302,7 @@ CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m CONFIG_EFS_FS=m +CONFIG_CRAMFS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index efb43f076446..11c29f971558 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.11 1999/12/20 05:02:07 davem Exp $ +/* $Id: pci.c,v 1.12 2000/01/01 03:32:50 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -229,6 +229,11 @@ void pcibios_align_resource(void *data, struct resource *res, unsigned long size { } +int pci_assign_resource(struct pci_dev *dev, int i) +{ + return -ENOSYS; /* :-)... actually implement this soon */ +} + char * __init pcibios_setup(char *str) { if (!strcmp(str, "onboardfirst")) { diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c index f72aeedd6bd0..88ab813f383d 100644 --- a/arch/sparc64/kernel/semaphore.c +++ b/arch/sparc64/kernel/semaphore.c @@ -1,4 +1,4 @@ -/* $Id: semaphore.c,v 1.1 1999/08/30 10:00:50 davem Exp $ +/* $Id: semaphore.c,v 1.2 1999/12/23 17:12:03 jj Exp $ * Generic semaphore code. Buyer beware. Do your own * specific changes in */ @@ -62,8 +62,7 @@ void __up(struct semaphore *sem) #define DOWN_VAR \ struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); + DECLARE_WAITQUEUE(wait, tsk); #define DOWN_HEAD(task_state) \ \ @@ -127,3 +126,172 @@ int __down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); } + +/* rw mutexes + * Implemented by Jakub Jelinek (jakub@redhat.com) based on + * i386 implementation by Ben LaHaise (bcrl@redhat.com). + */ + +asm(" + .text + .align 32 + .globl __down_read_failed +__down_read_failed: + save %sp, -160, %sp + membar #StoreStore + brz,pt %g5, 3f + mov %g7, %l0 +1: call down_read_failed + mov %l0, %o0 +2: lduw [%l0], %l1 + sub %l1, 1, %l2 + cas [%l0], %l1, %l2 + + cmp %l1, %l2 + bne,pn %icc, 2b + membar #StoreStore + subcc %l1, 1, %g0 + bpos,pt %icc, 4f + nop + bcc,pn %icc, 1b + nop + +3: call down_read_failed_biased + mov %l0, %o0 +4: ret + restore + .previous +"); + +asm(" + .text + .align 32 + .globl __down_write_failed +__down_write_failed: + save %sp, -160, %sp + membar #StoreStore + tst %g5 + bge,pt %icc, 3f + mov %g7, %l0 +1: call down_write_failed + mov %l0, %o0 +2: lduw [%l0], %l1 + sethi %hi (" RW_LOCK_BIAS_STR "), %l3 + sub %l1, %l3, %l2 + cas [%l0], %l1, %l2 + + cmp %l1, %l2 + bne,pn %icc, 2b + membar #StoreStore + subcc %l1, %l3, %g0 + be,pt %icc, 4f + nop + bcc,pn %icc, 1b + nop + +3: call down_write_failed_biased + mov %l0, %o0 +4: ret + restore + .previous +"); + +void down_read_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (clear_le_bit(0, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!test_le_bit(0, &sem->granted)) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void down_write_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (clear_le_bit(1, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!test_le_bit(1, &sem->granted)) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (sem->count >= 0) + wake_up(&sem->wait); +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +void down_read_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->count >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +void down_write_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->count >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers) +{ + if (readers) { + if (set_le_bit(0, &sem->granted)) + BUG(); + wake_up(&sem->wait); + } else { + if (set_le_bit(1, &sem->granted)) + BUG(); + wake_up(&sem->write_bias_wait); + } +} diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S index 7ccd7b8180ea..152723a49014 100644 --- a/arch/sparc64/lib/VISmemset.S +++ b/arch/sparc64/lib/VISmemset.S @@ -1,9 +1,9 @@ -/* $Id: VISmemset.S,v 1.9 1999/05/25 16:53:01 jj Exp $ +/* $Id: VISmemset.S,v 1.10 1999/12/23 17:02:16 jj Exp $ * VISmemset.S: High speed memset operations utilizing the UltraSparc * Visual Instruction Set. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996, 1997, 1999 Jakub Jelinek (jakub@redhat.com) */ #include "VIS.h" @@ -32,12 +32,7 @@ #endif #ifdef __KERNEL__ - #include - -#define RETL clr %o0 -#else -#define RETL mov %g3, %o0 #endif /* Well, memset is a lot easier to get right than bcopy... */ @@ -55,8 +50,8 @@ memset: #ifndef REGS_64BIT srl %o2, 0, %o2 #endif - mov %o0, %g3 #endif + mov %o0, %o4 cmp %o2, 7 bleu,pn %xcc, 17f andcc %o0, 3, %g5 @@ -188,19 +183,19 @@ memset: andcc %o2, 7, %o2 #ifdef __KERNEL__ 14: srl %g5, 1, %o3 - sethi %hi(13f), %o4 - sub %o4, %o3, %o4 - jmpl %o4 + %lo(13f), %g0 + sethi %hi(13f), %g3 + sub %g3, %o3, %g3 + jmpl %g3 + %lo(13f), %g0 add %o0, %g5, %o0 #else -14: rd %pc, %o4 +14: rd %pc, %g3 #ifdef REGS_64BIT srl %g5, 1, %o3 - sub %o4, %o3, %o4 + sub %g3, %o3, %g3 #else - sub %o4, %g5, %o4 + sub %g3, %g5, %g3 #endif - jmpl %o4 + (13f - 14b), %g0 + jmpl %g3 + (13f - 14b), %g0 add %o0, %g5, %o0 #endif 12: SET_BLOCKS(%o0, 0x68, %o1) @@ -220,14 +215,14 @@ memset: 1: bne,a,pn %xcc, 8f stb %o1, [%o0] 8: retl - RETL + mov %o4, %o0 17: brz,pn %o2, 0f 8: add %o0, 1, %o0 subcc %o2, 1, %o2 bne,pt %xcc, 8b stb %o1, [%o0 - 1] 0: retl - RETL + mov %o4, %o0 6: #ifdef REGS_64BIT stx %o1, [%o0] diff --git a/drivers/pci/names.c b/drivers/pci/names.c index 9018e8976630..a6114e789190 100644 --- a/drivers/pci/names.c +++ b/drivers/pci/names.c @@ -123,7 +123,6 @@ pci_class_name(u32 class) void __init pci_name_device(struct pci_dev *dev) { - sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device); } char * diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a1181a81fd4d..a3b741728e05 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -269,7 +269,7 @@ static inline unsigned int pci_resource_flags(unsigned int flags) return IORESOURCE_MEM; } -static void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) +static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { unsigned int pos, reg, next; u32 l, sz, tmp; @@ -447,6 +447,7 @@ static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pc */ static int __init pci_scan_cardbus(struct pci_bus *bus, struct pci_dev *dev, int busnr) { + int i; unsigned short cr; unsigned int buses; struct pci_bus *child; @@ -455,7 +456,14 @@ static int __init pci_scan_cardbus(struct pci_bus *bus, struct pci_dev *dev, int * Insert it into the tree of buses. */ child = pci_add_new_bus(bus, dev, ++busnr); - child->subordinate = busnr; + + for (i = 0; i < 4; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + + /* + * Maybe we'll have another bus behind this one? + */ + child->subordinate = ++busnr; sprintf(child->name, "PCI CardBus #%02x", child->number); /* @@ -566,7 +574,7 @@ static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int * Read interrupt line and base address registers. * The architecture-dependent code can tweak these, of course. */ -static void __init pci_read_irq(struct pci_dev *dev) +static void pci_read_irq(struct pci_dev *dev) { unsigned char irq; @@ -577,31 +585,15 @@ static void __init pci_read_irq(struct pci_dev *dev) } /* - * Read the config data for a PCI device, sanity-check it - * and fill in the dev structure... + * Fill in class and map information of a device */ -static struct pci_dev * __init pci_scan_device(struct pci_dev *temp) +int pci_setup_device(struct pci_dev * dev) { - struct pci_dev *dev; - u32 l, class; - - if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l)) - return NULL; - - /* some broken boards return 0 or ~0 if a slot is empty: */ - if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) - return NULL; - - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; + u32 class; - memcpy(dev, temp, sizeof(*dev)); - dev->vendor = l & 0xffff; - dev->device = (l >> 16) & 0xffff; sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - pci_name_device(dev); - + sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device); + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); class >>= 8; /* upper 3 bytes */ dev->class = class; @@ -635,8 +627,7 @@ static struct pci_dev * __init pci_scan_device(struct pci_dev *temp) default: /* unknown header */ printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n", dev->slot_name, dev->hdr_type); - kfree(dev); - return NULL; + return -1; bad: printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n", @@ -645,6 +636,36 @@ static struct pci_dev * __init pci_scan_device(struct pci_dev *temp) } /* We found a fine healthy device, go go go... */ + return 0; +} + +/* + * Read the config data for a PCI device, sanity-check it + * and fill in the dev structure... + */ +static struct pci_dev * __init pci_scan_device(struct pci_dev *temp) +{ + struct pci_dev *dev; + u32 l; + + if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l)) + return NULL; + + /* some broken boards return 0 or ~0 if a slot is empty: */ + if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) + return NULL; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + memcpy(dev, temp, sizeof(*dev)); + dev->vendor = l & 0xffff; + dev->device = (l >> 16) & 0xffff; + if (pci_setup_device(dev) < 0) { + kfree(dev); + dev = NULL; + } return dev; } @@ -667,6 +688,7 @@ struct pci_dev * __init pci_scan_slot(struct pci_dev *temp) dev = pci_scan_device(temp); if (!dev) continue; + pci_name_device(dev); if (!func) { is_multi = hdr_type & 0x80; first_dev = dev; diff --git a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in index 2d3af81d2c91..556ecf4c85e1 100644 --- a/drivers/pcmcia/Config.in +++ b/drivers/pcmcia/Config.in @@ -8,7 +8,6 @@ tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA if [ "$CONFIG_PCMCIA" != "n" ]; then if [ "$CONFIG_PCI" != "n" ]; then bool ' CardBus support' CONFIG_CARDBUS - dep_tristate ' Yenta Cardbus support' CONFIG_YENTA $CONFIG_CARDBUS fi bool ' i82365 compatible bridge support' CONFIG_I82365 bool ' Databook TCIC host bridge support' CONFIG_TCIC diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 37f1b1f5a38a..649e50a1454d 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -18,19 +18,16 @@ ifeq ($(CONFIG_PCMCIA),y) O_OBJS := cistpl.o rsrc_mgr.o bulkmem.o OX_OBJS := ds.o cs.o O_TARGET := pcmcia.o + ifeq ($(CONFIG_CARDBUS),y) + O_OBJS += cardbus.o + OX_OBJS += cb_enabler.o yenta.o pci_socket.o + endif ifeq ($(CONFIG_I82365),y) O_OBJS += i82365.o endif ifeq ($(CONFIG_TCIC),y) O_OBJS += tcic.o endif - ifeq ($(CONFIG_YENTA),y) - OX_OBJS += yenta.o pci_socket.o - endif - ifeq ($(CONFIG_CARDBUS),y) - O_OBJS += cardbus.o - OX_OBJS += cb_enabler.o - endif else ifeq ($(CONFIG_PCMCIA),m) M_OBJS := pcmcia_core.o @@ -45,7 +42,7 @@ else endif ifeq ($(CONFIG_CARDBUS),y) CORE_OBJS += cardbus.o - MX_OBJS += cb_enabler.o + MX_OBJS += cb_enabler.o yenta.o pci_socket.o endif endif endif diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 708f6dacd2c1..6b7dbf95e54c 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -33,9 +33,19 @@ well as setting up and shutting down Cardbus sockets. They are called from cs.c in response to Request/ReleaseConfiguration and Request/ReleaseIO calls. - + ======================================================================*/ +/* + * This file is going away. Cardbus handling has been re-written to be + * more of a PCI bridge thing, and the PCI code basically does all the + * resource handling. This has wrappers to make the rest of the PCMCIA + * subsystem not notice that it's not here any more. + * + * Linus, Jan 2000 + */ + + #define __NO_VERSION__ #include @@ -68,15 +78,12 @@ static int pc_debug = PCMCIA_DEBUG; #define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1))) -#define pci_readb pcibios_read_config_byte -#define pci_writeb pcibios_write_config_byte -#define pci_readw pcibios_read_config_word -#define pci_writew pcibios_write_config_word -#define pci_readl pcibios_read_config_dword -#define pci_writel pcibios_write_config_dword - -#define CB_BAR(n) (PCI_BASE_ADDRESS_0+(4*(n))) -#define CB_ROM_BASE 0x0030 +#define pci_readb pci_read_config_byte +#define pci_writeb pci_write_config_byte +#define pci_readw pci_read_config_word +#define pci_writew pci_write_config_word +#define pci_readl pci_read_config_dword +#define pci_writel pci_write_config_dword /* Offsets in the Expansion ROM Image Header */ #define ROM_SIGNATURE 0x0000 /* 2 bytes */ @@ -93,17 +100,9 @@ static int pc_debug = PCMCIA_DEBUG; #define PCDATA_INDICATOR 0x0015 typedef struct cb_config_t { - u_int size[7]; - struct pci_dev dev; + struct pci_dev dev; } cb_config_t; -#define BASE(dev,n) ((dev).resource[n].start) -#define ROM(dev) ((dev).resource[6].start) - -/* There are three classes of bridge maps: IO ports, - non-prefetchable memory, and prefetchable memory */ -typedef enum { B_IO, B_M1, B_M2 } bridge_type; - /*===================================================================== Expansion ROM's have a special layout, and pointers specify an @@ -114,45 +113,49 @@ typedef enum { B_IO, B_M1, B_M2 } bridge_type; =====================================================================*/ -static int check_rom(u_char *b, u_long len) +static int check_rom(u_char * b, u_long len) { - u_int img = 0, ofs = 0, sz; - u_short data; - DEBUG(0, "ROM image dump:\n"); - while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) { - data = readb(b+ROM_DATA_PTR) + - (readb(b+ROM_DATA_PTR+1) << 8); - sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) + - (readb(b+data+PCDATA_IMAGE_SZ+1) << 8)); - DEBUG(0, " image %d: 0x%06x-0x%06x, signature %c%c%c%c\n", - img, ofs, ofs+sz-1, - readb(b+data+PCDATA_SIGNATURE), - readb(b+data+PCDATA_SIGNATURE+1), - readb(b+data+PCDATA_SIGNATURE+2), - readb(b+data+PCDATA_SIGNATURE+3)); - ofs += sz; img++; - if ((readb(b+data+PCDATA_INDICATOR) & 0x80) || - (sz == 0) || (ofs >= len)) break; - b += sz; - } - return img; + u_int img = 0, ofs = 0, sz; + u_short data; + DEBUG(0, "ROM image dump:\n"); + while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { + data = readb(b + ROM_DATA_PTR) + + (readb(b + ROM_DATA_PTR + 1) << 8); + sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + + (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); + DEBUG(0, " image %d: 0x%06x-0x%06x, signature %c%c%c%c\n", + img, ofs, ofs + sz - 1, + readb(b + data + PCDATA_SIGNATURE), + readb(b + data + PCDATA_SIGNATURE + 1), + readb(b + data + PCDATA_SIGNATURE + 2), + readb(b + data + PCDATA_SIGNATURE + 3)); + ofs += sz; + img++; + if ((readb(b + data + PCDATA_INDICATOR) & 0x80) || + (sz == 0) || (ofs >= len)) + break; + b += sz; + } + return img; } -static u_int xlate_rom_addr(u_char *b, u_int addr) +static u_int xlate_rom_addr(u_char * b, u_int addr) { - u_int img = 0, ofs = 0, sz; - u_short data; - while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) { - if (img == (addr >> 28)) - return (addr & 0x0fffffff) + ofs; - data = readb(b+ROM_DATA_PTR) + (readb(b+ROM_DATA_PTR+1) << 8); - sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) + - (readb(b+data+PCDATA_IMAGE_SZ+1) << 8)); - if ((sz == 0) || (readb(b+data+PCDATA_INDICATOR) & 0x80)) - break; - b += sz; ofs += sz; img++; - } - return 0; + u_int img = 0, ofs = 0, sz; + u_short data; + while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { + if (img == (addr >> 28)) + return (addr & 0x0fffffff) + ofs; + data = readb(b + ROM_DATA_PTR) + (readb(b + ROM_DATA_PTR + 1) << 8); + sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + + (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); + if ((sz == 0) || (readb(b + data + PCDATA_INDICATOR) & 0x80)) + break; + b += sz; + ofs += sz; + img++; + } + return 0; } /*===================================================================== @@ -163,76 +166,36 @@ static u_int xlate_rom_addr(u_char *b, u_int addr) =====================================================================*/ -int cb_setup_cis_mem(socket_info_t *s, int space) +void cb_release_cis_mem(socket_info_t * s) { - cb_bridge_map *m = &s->cb_cis_map; - u_long base = 0; - u_int sz, br; - - if (space == s->cb_cis_space) - return CS_SUCCESS; - else if (s->cb_cis_space != 0) - cb_release_cis_mem(s); - DEBUG(1, "cs: cb_setup_cis_mem(space %d)\n", space); - /* If socket is configured, then use existing memory mapping */ - if (s->lock_count) { - s->cb_cis_virt = - ioremap(BASE(s->cb_config[0].dev, space-1), - s->cb_config[0].size[space-1] & ~3); - s->cb_cis_space = space; - return CS_SUCCESS; - } - - /* Not configured? Then set up temporary map */ - br = (space == 7) ? CB_ROM_BASE : CB_BAR(space-1); - pci_writel(s->cap.cb_dev->subordinate->number, 0, br, 0xffffffff); - pci_readl(s->cap.cb_dev->subordinate->number, 0, br, &sz); - sz &= PCI_BASE_ADDRESS_MEM_MASK; - sz = FIND_FIRST_BIT(sz); - if (sz < PAGE_SIZE) sz = PAGE_SIZE; - if (find_mem_region(&base, sz, sz, 0, "cb_enabler") != 0) { - printk(KERN_NOTICE "cs: could not allocate %dK memory for" - " CardBus socket %d\n", sz/1024, s->sock); - return CS_OUT_OF_RESOURCE; - } - s->cb_cis_space = space; - s->cb_cis_virt = ioremap(base, sz); - DEBUG(1, " phys 0x%08lx-0x%08lx, virt 0x%08lx\n", - base, base+sz-1, (u_long)s->cb_cis_virt); - pci_writel(s->cap.cb_dev->subordinate->number, 0, br, base | 1); - pci_writeb(s->cap.cb_dev->subordinate->number, 0, PCI_COMMAND, PCI_COMMAND_MEMORY); - m->map = 0; m->flags = MAP_ACTIVE; - m->start = base; m->stop = base+sz-1; - s->ss_entry->set_bridge(s->sock, m); - if ((space == 7) && (check_rom(s->cb_cis_virt, sz) == 0)) { - printk(KERN_NOTICE "cs: no valid ROM images found!\n"); - return CS_READ_FAILURE; - } - return CS_SUCCESS; + if (s->cb_cis_virt) { + DEBUG(1, "cs: cb_release_cis_mem()\n"); + iounmap(s->cb_cis_virt); + s->cb_cis_virt = NULL; + s->cb_cis_res = 0; + } } -void cb_release_cis_mem(socket_info_t *s) +static int cb_setup_cis_mem(socket_info_t * s, struct pci_dev *dev, struct resource *res) { - cb_bridge_map *m = &s->cb_cis_map; - u_int br; - if (s->cb_cis_virt) { - DEBUG(1, "cs: cb_release_cis_mem()\n"); - iounmap(s->cb_cis_virt); - s->cb_cis_virt = NULL; - s->cb_cis_space = 0; - } - if (m->start) { - /* This is overkill: we probably only need to release the - memory region, but the rest should be safe */ - br = (s->cb_cis_space == 7) ? - CB_ROM_BASE : CB_BAR(s->cb_cis_space-1); - m->map = 0; m->flags = 0; - s->ss_entry->set_bridge(s->sock, m); - pci_writeb(s->cap.cb_dev->subordinate->number, 0, PCI_COMMAND, 0); - pci_writel(s->cap.cb_dev->subordinate->number, 0, br, 0); - release_mem_region(m->start, m->stop - m->start + 1); - m->start = 0; - } + unsigned int start, size; + + if (res == s->cb_cis_res) + return 0; + + if (s->cb_cis_res) + cb_release_cis_mem(s); + + start = res->start; + size = res->end - start + 1; + s->cb_cis_virt = ioremap(start, size); + + if (!s->cb_cis_virt) + return -1; + + s->cb_cis_res = res; + + return 0; } /*===================================================================== @@ -242,30 +205,47 @@ void cb_release_cis_mem(socket_info_t *s) =====================================================================*/ -void read_cb_mem(socket_info_t *s, u_char fn, int space, +void read_cb_mem(socket_info_t * s, u_char fn, int space, u_int addr, u_int len, void *ptr) { - DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len); - if (space == 0) { - if (addr+len > 0x100) goto fail; - for (; len; addr++, ptr++, len--) - pci_readb(s->cap.cb_dev->subordinate->number, fn, addr, (u_char *)ptr); - } else { - if (cb_setup_cis_mem(s, space) != 0) goto fail; + struct pci_dev *dev; + struct resource *res; + + DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len); + + dev = &s->cb_config[fn].dev; + + /* Config space? */ + if (space == 0) { + if (addr + len > 0x100) + goto fail; + for (; len; addr++, ptr++, len--) + pci_readb(dev, addr, (u_char *) ptr); + return; + } + + res = dev->resource + space - 1; + if (!res->flags) + goto fail; + + if (cb_setup_cis_mem(s, dev, res) != 0) + goto fail; + if (space == 7) { - addr = xlate_rom_addr(s->cb_cis_virt, addr); - if (addr == 0) goto fail; + addr = xlate_rom_addr(s->cb_cis_virt, addr); + if (addr == 0) + goto fail; } - if (addr+len > s->cb_cis_map.stop - s->cb_cis_map.start) - goto fail; - if (s->cb_cis_virt != NULL) - for (; len; addr++, ptr++, len--) - *(u_char *)ptr = readb(s->cb_cis_virt+addr); - } - return; - fail: - memset(ptr, 0xff, len); - return; + + if (addr + len > res->end - res->start) + goto fail; + + memcpy_fromio(ptr, s->cb_cis_virt + addr, len); + return; + +fail: + memset(ptr, 0xff, len); + return; } /*===================================================================== @@ -276,93 +256,124 @@ void read_cb_mem(socket_info_t *s, u_char fn, int space, =====================================================================*/ -int cb_alloc(socket_info_t *s) +int cb_alloc(socket_info_t * s) { - struct pci_bus *bus; - struct pci_dev tmp; - u_short vend, v, dev; - u_char i, hdr, fn; - cb_config_t *c; - - bus = s->cap.cb_dev->subordinate; - memset(&tmp, 0, sizeof(tmp)); - tmp.bus = bus; tmp.devfn = 0; -printk("bus=%p, number=%d\n", bus, bus->number); - - pci_read_config_word(&tmp, PCI_VENDOR_ID, &vend); - pci_read_config_word(&tmp, PCI_DEVICE_ID, &dev); - printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, " - "device 0x%04x\n", bus->number, vend, dev); - - pci_read_config_byte(&tmp, PCI_HEADER_TYPE, &hdr); - fn = 1; - if (hdr & 0x80) { - do { - tmp.devfn = fn; - pci_read_config_word(&tmp, PCI_VENDOR_ID, &v); - if (v != vend) break; - fn++; - } while (fn < 8); - } - s->functions = fn; - - c = kmalloc(fn * sizeof(struct cb_config_t), GFP_ATOMIC); - if (!c) return CS_OUT_OF_RESOURCE; - memset(c, 0, fn * sizeof(struct cb_config_t)); + struct pci_bus *bus; + struct pci_dev tmp; + u_short vend, v, dev; + u_char i, hdr, fn; + cb_config_t *c; + + bus = s->cap.cb_dev->subordinate; + memset(&tmp, 0, sizeof(tmp)); + tmp.bus = bus; + tmp.devfn = 0; + printk("bus=%p, number=%d\n", bus, bus->number); + + pci_readw(&tmp, PCI_VENDOR_ID, &vend); + pci_readw(&tmp, PCI_DEVICE_ID, &dev); + printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, " + "device 0x%04x\n", bus->number, vend, dev); + + pci_readb(&tmp, PCI_HEADER_TYPE, &hdr); + fn = 1; + if (hdr & 0x80) { + do { + tmp.devfn = fn; + pci_readw(&tmp, PCI_VENDOR_ID, &v); + if (v != vend) + break; + fn++; + } while (fn < 8); + } + s->functions = fn; - for (i = 0; i < fn; i++) { - struct pci_dev *dev = &c[i].dev; + c = kmalloc(fn * sizeof(struct cb_config_t), GFP_ATOMIC); + if (!c) + return CS_OUT_OF_RESOURCE; + memset(c, 0, fn * sizeof(struct cb_config_t)); + + for (i = 0; i < fn; i++) { + struct pci_dev *dev = &c[i].dev; + int r; + + dev->bus = bus; + dev->devfn = i; + if (i < fn - 1) { + dev->sibling = dev->next = &c[i + 1].dev; + } + dev->vendor = vend; + pci_readw(dev, PCI_DEVICE_ID, &dev->device); + dev->hdr_type = hdr; + + pci_setup_device(dev); + for (r = 0; r < 7; r++) { + struct resource *res = dev->resource + r; + if (res->flags) { + /* Unset resource address, assign new one! */ + res->end -= res->start; + res->start = 0; + pci_assign_resource(dev, r); + } + printk("Resource %d at %08lx-%08lx (%04lx)\n", + r, + res->start, + res->end, + res->flags); + } + pci_enable_device(dev); - dev->bus = bus; - dev->devfn = i; - if (i < fn-1) { - dev->sibling = dev->next = &c[i+1].dev; - } - - dev->vendor = vend; - pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); - pci_read_config_dword(dev, PCI_CLASS_REVISION, &dev->class); - dev->class >>= 8; - dev->hdr_type = hdr; #ifdef CONFIG_PROC_FS - pci_proc_attach_device(dev); + pci_proc_attach_device(dev); #endif - } + } - /* Link into PCI device chain */ - bus->devices = &c[0].dev; - c[fn-1].dev.next = pci_devices; - pci_devices = &c[0].dev; - s->cb_config = c; - - return CS_SUCCESS; + /* Link into PCI device chain */ + bus->devices = &c[0].dev; + c[fn - 1].dev.next = pci_devices; + pci_devices = &c[0].dev; + s->cb_config = c; + + return CS_SUCCESS; +} + +static void free_resources(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < 7; i++) { + struct resource *res = dev->resource + i; + if (res->parent) + release_resource(res); + } } -void cb_free(socket_info_t *s) +void cb_free(socket_info_t * s) { - cb_config_t *c = s->cb_config; - struct pci_bus *bus = s->cap.cb_dev->subordinate; - - if (c) { - struct pci_dev **p; - /* Unlink from PCI device chain */ - p = &pci_devices; - while (*p) { - struct pci_dev * dev = *p; - if (dev->bus != bus) { - p = &dev->next; - continue; - } - *p = dev->next; + cb_config_t *c = s->cb_config; + struct pci_bus *bus = s->cap.cb_dev->subordinate; + + if (c) { + struct pci_dev **p; + /* Unlink from PCI device chain */ + p = &pci_devices; + while (*p) { + struct pci_dev *dev = *p; + if (dev->bus != bus) { + p = &dev->next; + continue; + } + *p = dev->next; + free_resources(dev); #ifdef CONFIG_PROC_FS - pci_proc_detach_device(dev); + pci_proc_detach_device(dev); #endif + } + bus->devices = NULL; + kfree(s->cb_config); + s->cb_config = NULL; + printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number); } - bus->devices = NULL; - kfree(s->cb_config); - s->cb_config = NULL; - printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number); - } } /*===================================================================== @@ -377,143 +388,59 @@ void cb_free(socket_info_t *s) ======================================================================*/ -int cb_config(socket_info_t *s) +int cb_config(socket_info_t * s) { - cb_config_t *c = s->cb_config; - u_char fn = s->functions; - u_char i, j, bus = s->cap.cb_dev->subordinate->number, *name; - u_int sz, align, m, mask[3], num[3], base[3]; - int irq, try, ret; - - printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cb_dev->subordinate->number); - - /* Determine IO and memory space needs */ - num[B_IO] = num[B_M1] = num[B_M2] = 0; - mask[B_IO] = mask[B_M1] = mask[B_M2] = 0; - for (i = 0; i < fn; i++) { - for (j = 0; j < 6; j++) { - pci_writel(bus, i, CB_BAR(j), 0xffffffff); - pci_readl(bus, i, CB_BAR(j), &sz); - if (sz == 0) continue; - if (sz & PCI_BASE_ADDRESS_SPACE) { - m = B_IO; - sz &= PCI_BASE_ADDRESS_IO_MASK; - } else { - m = (sz & PCI_BASE_ADDRESS_MEM_PREFETCH) ? B_M2 : B_M1; - sz &= PCI_BASE_ADDRESS_MEM_MASK; - } - sz = FIND_FIRST_BIT(sz); - c[i].size[j] = sz | m; - if (m && (sz < PAGE_SIZE)) sz = PAGE_SIZE; - num[m] += sz; mask[m] |= sz; - } - pci_writel(bus, i, CB_ROM_BASE, 0xffffffff); - pci_readl(bus, i, CB_ROM_BASE, &sz); - if (sz != 0) { - sz = FIND_FIRST_BIT(sz & ~0x00000001); - c[i].size[6] = sz | B_M1; - if (sz < PAGE_SIZE) sz = PAGE_SIZE; - num[B_M1] += sz; mask[B_M1] |= sz; - } - } - - /* Allocate system resources */ - name = "cb_enabler"; - s->io[0].NumPorts = num[B_IO]; - s->io[0].BasePort = 0; - if (num[B_IO]) { - if (find_io_region(&s->io[0].BasePort, num[B_IO], - num[B_IO], name) != 0) { - printk(KERN_NOTICE "cs: could not allocate %d IO ports for" - " CardBus socket %d\n", num[B_IO], s->sock); - goto failed; - } - base[B_IO] = s->io[0].BasePort + num[B_IO]; - } - s->win[0].size = num[B_M1]; - s->win[0].base = 0; - if (num[B_M1]) { - if (find_mem_region(&s->win[0].base, num[B_M1], num[B_M1], - 0, name) != 0) { - printk(KERN_NOTICE "cs: could not allocate %dK memory for" - " CardBus socket %d\n", num[B_M1]/1024, s->sock); - goto failed; - } - base[B_M1] = s->win[0].base + num[B_M1]; - } - s->win[1].size = num[B_M2]; - s->win[1].base = 0; - if (num[B_M2]) { - if (find_mem_region(&s->win[1].base, num[B_M2], num[B_M2], - 0, name) != 0) { - printk(KERN_NOTICE "cs: could not allocate %dK memory for" - " CardBus socket %d\n", num[B_M2]/1024, s->sock); - goto failed; - } - base[B_M2] = s->win[1].base + num[B_M2]; - } - - /* Set up base address registers */ - while (mask[B_IO] | mask[B_M1] | mask[B_M2]) { - num[B_IO] = FIND_FIRST_BIT(mask[B_IO]); mask[B_IO] -= num[B_IO]; - num[B_M1] = FIND_FIRST_BIT(mask[B_M1]); mask[B_M1] -= num[B_M1]; - num[B_M2] = FIND_FIRST_BIT(mask[B_M2]); mask[B_M2] -= num[B_M2]; + cb_config_t *c = s->cb_config; + u_char fn = s->functions; + u_char i, j; + int irq, try, ret; + + printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cb_dev->subordinate->number); + + /* Allocate interrupt if needed */ + s->irq.AssignedIRQ = irq = 0; + ret = -1; for (i = 0; i < fn; i++) { - for (j = 0; j < 7; j++) { - sz = c[i].size[j]; - m = sz & 3; sz &= ~3; - align = (m && (sz < PAGE_SIZE)) ? PAGE_SIZE : sz; - if (sz && (align == num[m])) { - base[m] -= align; - if (j < 6) - printk(KERN_INFO " fn %d bar %d: ", i, j+1); - else - printk(KERN_INFO " fn %d rom: ", i); - printk("%s 0x%x-0x%x\n", (m) ? "mem" : "io", - base[m], base[m]+sz-1); - BASE(c[i].dev, j) = base[m]; - } - } - } - } - - /* Allocate interrupt if needed */ - s->irq.AssignedIRQ = irq = 0; ret = -1; - for (i = 0; i < fn; i++) { - pci_readb(bus, i, PCI_INTERRUPT_PIN, &j); - if (j == 0) continue; - if (irq == 0) { - if (s->cap.irq_mask & (1 << s->cap.pci_irq)) { - irq = s->cap.pci_irq; - ret = 0; - } + struct pci_dev *dev = &c[i].dev; + pci_readb(dev, PCI_INTERRUPT_PIN, &j); + if (j == 0) + continue; + if (irq == 0) { + if (s->cap.irq_mask & (1 << s->cap.pci_irq)) { + irq = s->cap.pci_irq; + ret = 0; + } #ifdef CONFIG_ISA - else - for (try = 0; try < 2; try++) { - for (irq = 0; irq < 32; irq++) - if ((s->cap.irq_mask >> irq) & 1) { - ret = try_irq(IRQ_TYPE_EXCLUSIVE, irq, try); - if (ret == 0) break; + else + for (try = 0; try < 2; try++) { + for (irq = 0; irq < 32; irq++) + if ((s->cap.irq_mask >> irq) & 1) { + ret = try_irq(IRQ_TYPE_EXCLUSIVE, irq, try); + if (ret == 0) + break; + } + if (ret == 0) + break; + } + if (ret != 0) { + printk(KERN_NOTICE "cs: could not allocate interrupt" + " for CardBus socket %d\n", s->sock); + goto failed; } - if (ret == 0) break; - } - if (ret != 0) { - printk(KERN_NOTICE "cs: could not allocate interrupt" - " for CardBus socket %d\n", s->sock); - goto failed; - } #endif - s->irq.AssignedIRQ = irq; + s->irq.AssignedIRQ = irq; + } + } + for (i = 0; i < fn; i++) { + struct pci_dev *dev = &c[i].dev; + dev->irq = irq; } - } - for (i = 0; i < fn; i++) - c[i].dev.irq = irq; - - return CS_SUCCESS; -failed: - cb_release(s); - return CS_OUT_OF_RESOURCE; + return CS_SUCCESS; + + failed: + cb_release(s); + return CS_OUT_OF_RESOURCE; } /*====================================================================== @@ -526,22 +453,15 @@ failed: ======================================================================*/ -void cb_release(socket_info_t *s) +void cb_release(socket_info_t * s) { - cb_config_t *c = s->cb_config; - - DEBUG(0, "cs: cb_release(bus %d)\n", s->cap.cb_dev->subordinate->number); - - if (s->win[0].size > 0) - release_mem_region(s->win[0].base, s->win[0].size); - if (s->win[1].size > 0) - release_mem_region(s->win[1].base, s->win[1].size); - if (s->io[0].NumPorts > 0) - release_region(s->io[0].BasePort, s->io[0].NumPorts); - s->io[0].NumPorts = 0; + cb_config_t *c = s->cb_config; + + DEBUG(0, "cs: cb_release(bus %d)\n", s->cap.cb_dev->subordinate->number); + #ifdef CONFIG_ISA - if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq)) - undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq); + if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq)) + undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq); #endif } @@ -560,66 +480,32 @@ void cb_release(socket_info_t *s) ======================================================================*/ -void cb_enable(socket_info_t *s) +void cb_enable(socket_info_t * s) { - u_char i, j, bus = s->cap.cb_dev->subordinate->number; - cb_config_t *c = s->cb_config; - - DEBUG(0, "cs: cb_enable(bus %d)\n", bus); - - /* Configure bridge */ - if (s->cb_cis_map.start) + struct pci_dev *dev; + u_char i, bus = s->cap.cb_dev->subordinate->number; + + DEBUG(0, "cs: cb_enable(bus %d)\n", bus); + + /* Configure bridge */ cb_release_cis_mem(s); - for (i = 0; i < 3; i++) { - cb_bridge_map m; - switch (i) { - case B_IO: - m.map = 0; m.flags = MAP_IOSPACE | MAP_ACTIVE; - m.start = s->io[0].BasePort; - m.stop = m.start + s->io[0].NumPorts - 1; - break; - case B_M1: - m.map = 0; m.flags = MAP_ACTIVE; - m.start = s->win[0].base; - m.stop = m.start + s->win[0].size - 1; - break; - case B_M2: - m.map = 1; m.flags = MAP_PREFETCH | MAP_ACTIVE; - m.start = s->win[1].base; - m.stop = m.start + s->win[1].size - 1; - break; + + /* Set up PCI interrupt and command registers */ + for (i = 0; i < s->functions; i++) { + dev = &s->cb_config[i].dev; + pci_writeb(dev, PCI_COMMAND, PCI_COMMAND_MASTER | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_writeb(dev, PCI_CACHE_LINE_SIZE, 8); } - if (m.start == 0) continue; - DEBUG(0, " bridge %s map %d (flags 0x%x): 0x%x-0x%x\n", - (m.flags & MAP_IOSPACE) ? "io" : "mem", - m.map, m.flags, m.start, m.stop); - s->ss_entry->set_bridge(s->sock, &m); - } - - /* Set up base address registers */ - for (i = 0; i < s->functions; i++) { - for (j = 0; j < 6; j++) { - if (BASE(c[i].dev, j) != 0) - pci_writel(bus, i, CB_BAR(j), BASE(c[i].dev, j)); + + if (s->irq.AssignedIRQ) { + for (i = 0; i < s->functions; i++) { + dev = &s->cb_config[i].dev; + pci_writeb(dev, PCI_INTERRUPT_LINE, s->irq.AssignedIRQ); + } + s->socket.io_irq = s->irq.AssignedIRQ; + s->ss_entry->set_socket(s->sock, &s->socket); } - if (ROM(c[i].dev) != 0) - pci_writel(bus, i, CB_ROM_BASE, ROM(c[i].dev) | 1); - } - - /* Set up PCI interrupt and command registers */ - for (i = 0; i < s->functions; i++) { - pci_writeb(bus, i, PCI_COMMAND, PCI_COMMAND_MASTER | - PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_writeb(bus, i, PCI_CACHE_LINE_SIZE, 8); - } - - if (s->irq.AssignedIRQ) { - for (i = 0; i < s->functions; i++) - pci_writeb(bus, i, PCI_INTERRUPT_LINE, - s->irq.AssignedIRQ); - s->socket.io_irq = s->irq.AssignedIRQ; - s->ss_entry->set_socket(s->sock, &s->socket); - } } /*====================================================================== @@ -631,22 +517,10 @@ void cb_enable(socket_info_t *s) ======================================================================*/ -void cb_disable(socket_info_t *s) +void cb_disable(socket_info_t * s) { - u_char i; - cb_bridge_map m = { 0, 0, 0, 0xffff }; - - DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cb_dev->subordinate->number); - - /* Turn off bridge windows */ - if (s->cb_cis_map.start) + DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cb_dev->subordinate->number); + + /* Turn off bridge windows */ cb_release_cis_mem(s); - for (i = 0; i < 3; i++) { - switch (i) { - case B_IO: m.map = 0; m.flags = MAP_IOSPACE; break; - case B_M1: m.map = m.flags = 0; break; - case B_M2: m.map = 1; m.flags = 0; break; - } - s->ss_entry->set_bridge(s->sock, &m); - } } diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index a6bbd14abd34..7d883c87a59b 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -59,6 +59,7 @@ #include #include #include + #include "cs_internal.h" #include "rsrc_mgr.h" diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index e7470ea1fe25..cac2d350a92a 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -136,8 +136,7 @@ typedef struct socket_info_t { u_char *cis_virt; config_t *config; #ifdef CONFIG_CARDBUS - u_int cb_cis_space; - cb_bridge_map cb_cis_map; + struct resource * cb_cis_res; u_char *cb_cis_virt; struct cb_config_t *cb_config; #endif @@ -206,8 +205,7 @@ void cb_enable(socket_info_t *s); void cb_disable(socket_info_t *s); void read_cb_mem(socket_info_t *s, u_char fn, int space, u_int addr, u_int len, void *ptr); -int cb_setup_cis_mem(socket_info_t *s, int space); -void cb_release_cis_mem(socket_info_t *s); +void cb_release_cis_mem(socket_info_t * s); /* In cistpl.c */ void read_cis_mem(socket_info_t *s, int attr, diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 4369f5bf076a..8c96585c6221 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1,7 +1,6 @@ /*====================================================================== - Device driver for Intel 82365 and compatible PC Card controllers, - and Yenta-compatible PCI-to-CardBus controllers. + Device driver for Intel 82365 and compatible PC Card controllers. i82365.c 1.265 1999/11/10 18:36:21 @@ -156,54 +155,6 @@ MODULE_PARM(setup_time, "i"); MODULE_PARM(cmd_time, "i"); MODULE_PARM(recov_time, "i"); -#ifdef CONFIG_PCI -/* Scan PCI bus? */ -static int do_pci_probe = 1; -static int fast_pci = -1; -static int hold_time = -1; -/* Override BIOS interrupt routing mode? */ -static int irq_mode = -1; -static int has_clkrun = -1; -static int clkrun_sel = -1; -static int pci_latency = -1; -static int cb_latency = -1; -static int cb_bus_base = 0; -static int cb_bus_step = 2; -static int cb_write_post = -1; -MODULE_PARM(do_pci_probe, "i"); -MODULE_PARM(fast_pci, "i"); -MODULE_PARM(hold_time, "i"); -MODULE_PARM(irq_mode, "i"); -MODULE_PARM(has_clkrun, "i"); -MODULE_PARM(clkrun_sel, "i"); -MODULE_PARM(pci_latency, "i"); -MODULE_PARM(cb_latency, "i"); -MODULE_PARM(cb_bus_base, "i"); -MODULE_PARM(cb_bus_step, "i"); -MODULE_PARM(cb_write_post, "i"); -#endif - -#ifdef CONFIG_ISA -#ifdef CONFIG_PCI -/* PCI card status change interrupts? */ -static int pci_csc = 0; -/* PCI IO card functional interrupts? */ -static int pci_int = 0; -MODULE_PARM(pci_csc, "i"); -MODULE_PARM(pci_int, "i"); -#else /* no PCI */ -#define pci_csc 0 -#define pci_int 0 -#endif -#else /* no ISA */ -#ifdef CONFIG_PCI -#define pci_csc 0 -#define pci_int 1 -#else -#error "No bus architectures defined!" -#endif -#endif - /*====================================================================*/ typedef struct cirrus_state_t { @@ -244,25 +195,10 @@ typedef struct socket_info_t { void *info; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc; -#endif -#ifdef CONFIG_PCI - struct pci_dev *pdev; - u_char revision; - u_short bcr; - u_char pci_lat, cb_lat, sub_bus; - u_char cache; - u_int cb_phys; - char *cb_virt; #endif union { cirrus_state_t cirrus; vg46x_state_t vg46x; -#ifdef CONFIG_PCI - o2micro_state_t o2micro; - ti113x_state_t ti113x; - rl5c4xx_state_t rl5c4xx; - topic_state_t topic; -#endif } state; } socket_info_t; @@ -278,10 +214,8 @@ static socket_info_t socket[8] = { #ifdef CONFIG_ISA static int grab_irq; static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED; -#define ISA_LOCK(n, f) \ - if (!(socket[n].flags & IS_CARDBUS)) spin_lock_irqsave(&isa_lock, f) -#define ISA_UNLOCK(n, f) \ - if (!(socket[n].flags & IS_CARDBUS)) spin_unlock_irqrestore(&isa_lock, f) +#define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f) +#define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f) #else #define ISA_LOCK(n, f) do { } while (0) #define ISA_UNLOCK(n, f) do { } while (0) @@ -302,17 +236,6 @@ typedef enum pcic_id { IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469, IS_PD6710, IS_PD672X, IS_VT83C469, #endif -#ifdef CONFIG_PCI - IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730, - IS_I82092AA, IS_OM82C092G, - IS_PD6832, IS_OZ6832, IS_OZ6836, IS_OZ6812, - IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478, - IS_SMC34C90, - IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210, - IS_TI1251A, IS_TI1251B, IS_TI1450, IS_TI1225, IS_TI1211, IS_TI1420, - IS_TOPIC95_A, IS_TOPIC95_B, IS_TOPIC97, - IS_UNK_PCI, IS_UNK_CARDBUS -#endif } pcic_id; /* Flags for classifying groups of controllers */ @@ -327,15 +250,11 @@ typedef enum pcic_id { #define IS_VG_PWR 0x0800 #define IS_DF_PWR 0x1000 #define IS_PCI 0x2000 -#define IS_CARDBUS 0x4000 #define IS_ALIVE 0x8000 typedef struct pcic_t { char *name; u_short flags; -#ifdef CONFIG_PCI - u_short vendor, device; -#endif } pcic_t; static pcic_t pcic[] = { @@ -352,72 +271,6 @@ static pcic_t pcic[] = { { "Cirrus PD672x", IS_CIRRUS }, { "VIA VT83C469", IS_CIRRUS|IS_VIA }, #endif -#ifdef CONFIG_PCI - { "Cirrus PD6729", IS_CIRRUS|IS_PCI, - PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729 }, - { "Cirrus PD6730", IS_CIRRUS|IS_PCI, - PCI_VENDOR_ID_CIRRUS, 0xffff }, - { "O2Micro OZ6729", IS_O2MICRO|IS_PCI|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6729 }, - { "O2Micro OZ6730", IS_O2MICRO|IS_PCI|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6730 }, - { "Intel 82092AA", IS_PCI, - PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82092AA_0 }, - { "Omega Micro 82C092G", IS_PCI, - PCI_VENDOR_ID_OMEGA, PCI_DEVICE_ID_OMEGA_82C092G }, - { "Cirrus PD6832", IS_CIRRUS|IS_CARDBUS, - PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832 }, - { "O2Micro OZ6832/OZ6833", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 }, - { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 }, - { "O2Micro OZ6812", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6812 }, - { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 }, - { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466 }, - { "Ricoh RL5C475", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475 }, - { "Ricoh RL5C476", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476 }, - { "Ricoh RL5C478", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478 }, - { "SMC 34C90", IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_34C90 }, - { "TI 1130", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130 }, - { "TI 1131", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131 }, - { "TI 1250A", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250A }, - { "TI 1220", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220 }, - { "TI 1221", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221 }, - { "TI 1210", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210 }, - { "TI 1251A", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A }, - { "TI 1251B", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B }, - { "TI 1450", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450 }, - { "TI 1225", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225 }, - { "TI 1211", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211 }, - { "TI 1420", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420 }, - { "Toshiba ToPIC95-A", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, - PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_A }, - { "Toshiba ToPIC95-B", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, - PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_B }, - { "Toshiba ToPIC97", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, - PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97 }, - { "Unknown", IS_PCI|IS_UNKNOWN, 0, 0 }, - { "Unknown", IS_CARDBUS|IS_DF_PWR|IS_UNKNOWN, 0, 0 } -#endif }; #define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t)) @@ -438,18 +291,10 @@ static pcic_t pcic[] = { #define cb_writeb(s, r, v) writeb(v, socket[s].cb_virt + (r)) #define cb_writel(s, r, v) writel(v, socket[s].cb_virt + (r)) -static void cb_get_power(u_short sock, socket_state_t *state); -static void cb_set_power(u_short sock, socket_state_t *state); - /*====================================================================*/ static u_char i365_get(u_short sock, u_short reg) { -#ifdef CONFIG_PCI - if (socket[sock].cb_virt) - return cb_readb(sock, 0x0800 + reg); - else -#endif { ioaddr_t port = socket[sock].ioaddr; u_char val; @@ -461,11 +306,6 @@ static u_char i365_get(u_short sock, u_short reg) static void i365_set(u_short sock, u_short reg, u_char data) { -#ifdef CONFIG_PCI - if (socket[sock].cb_virt) - cb_writeb(sock, 0x0800 + reg, data); - else -#endif { ioaddr_t port = socket[sock].ioaddr; u_char val = I365_REG(socket[sock].psock, reg); @@ -551,14 +391,6 @@ static void cirrus_set_state(u_short s) i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]); } -#ifdef CONFIG_PCI -static int cirrus_set_irq_mode(u_short s, int pcsc, int pint) -{ - flip(socket[s].bcr, PD6832_BCR_MGMT_IRQ_ENA, !pcsc); - return 0; -} -#endif /* CONFIG_PCI */ - static u_int __init cirrus_set_opts(u_short s, char *buf) { socket_info_t *t = &socket[s]; @@ -574,7 +406,7 @@ static u_int __init cirrus_set_opts(u_short s, char *buf) strcat(buf, " [dyn mode]"); if (p->misc1 & PD67_MC1_INPACK_ENA) strcat(buf, " [inpack]"); - if (!(t->flags & (IS_PCI | IS_CARDBUS))) { + if (!(t->flags & IS_PCI)) { if (p->misc2 & PD67_MC2_IRQ15_RI) mask &= ~0x8000; if (has_led > 0) { @@ -588,13 +420,6 @@ static u_int __init cirrus_set_opts(u_short s, char *buf) if (p->misc2 & PD67_MC2_FREQ_BYPASS) strcat(buf, " [freq bypass]"); } -#ifdef CONFIG_PCI - } else { - p->misc1 &= ~PD67_MC1_MEDIA_ENA; - flip(p->misc2, PD67_MC2_FAST_PCI, fast_pci); - if (p->misc2 & PD67_MC2_IRQ15_RI) - mask &= (socket[s].type == IS_PD6730) ? ~0x0400 : ~0x8000; -#endif } if (!(t->flags & IS_VIA)) { if (setup_time >= 0) @@ -670,436 +495,6 @@ static u_int __init vg46x_set_opts(u_short s, char *buf) #endif -/*====================================================================== - - Code to save and restore global state information for TI 1130 and - TI 1131 controllers, and to set and report global configuration - options. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void ti113x_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - ti113x_state_t *p = &socket[s].state.ti113x; - config_readl(t, TI113X_SYSTEM_CONTROL, &p->sysctl); - config_readb(t, TI113X_CARD_CONTROL, &p->cardctl); - config_readb(t, TI113X_DEVICE_CONTROL, &p->devctl); - config_readb(t, TI1250_DIAGNOSTIC, &p->diag); -} - -static void ti113x_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - ti113x_state_t *p = &socket[s].state.ti113x; - config_writel(t, TI113X_SYSTEM_CONTROL, p->sysctl); - config_writeb(t, TI113X_CARD_CONTROL, p->cardctl); - config_writeb(t, TI113X_DEVICE_CONTROL, p->devctl); - config_writeb(t, TI1250_MULTIMEDIA_CTL, 0); - config_writeb(t, TI1250_DIAGNOSTIC, p->diag); - i365_set_pair(s, TI113X_IO_OFFSET(0), 0); - i365_set_pair(s, TI113X_IO_OFFSET(1), 0); -} - -static int ti113x_set_irq_mode(u_short s, int pcsc, int pint) -{ - socket_info_t *t = &socket[s]; - ti113x_state_t *p = &t->state.ti113x; - t->intr = (pcsc) ? I365_INTR_ENA : 0; - if (t->type <= IS_TI1131) { - p->cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA | - TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC); - if (pcsc) - p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC; - if (pint) - p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ; - } else if (t->type == IS_TI1250A) { - p->diag &= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ; - if (pcsc) - p->diag |= TI1250_DIAG_PCI_CSC; - if (pint) - p->diag |= TI1250_DIAG_PCI_IREQ; - } - return 0; -} - -static u_int __init ti113x_set_opts(u_short s, char *buf) -{ - socket_info_t *t = &socket[s]; - ti113x_state_t *p = &t->state.ti113x; - u_int mask = 0xffff; - int old = (t->type <= IS_TI1131); - - flip(p->sysctl, TI113X_SCR_CLKRUN_ENA, has_clkrun); - flip(p->sysctl, TI113X_SCR_CLKRUN_SEL, clkrun_sel); - flip(p->cardctl, TI113X_CCR_RIENB, has_ring); - p->cardctl &= ~TI113X_CCR_ZVENABLE; - switch (irq_mode) { - case 1: - p->devctl &= ~TI113X_DCR_IMODE_MASK; - p->devctl |= TI113X_DCR_IMODE_ISA; - break; - case 2: - p->devctl &= ~TI113X_DCR_IMODE_MASK; - p->devctl |= TI113X_DCR_IMODE_SERIAL; - break; - case 3: - p->devctl &= ~TI113X_DCR_IMODE_MASK; - p->devctl |= TI12XX_DCR_IMODE_ALL_SERIAL; - break; - default: - if ((p->devctl & TI113X_DCR_IMODE_MASK) == 0) - p->devctl |= TI113X_DCR_IMODE_ISA; - } - if (p->cardctl & TI113X_CCR_RIENB) { - strcat(buf, " [ring]"); - if (old) mask &= ~0x8000; - } - if (old && (p->sysctl & TI113X_SCR_CLKRUN_ENA)) { - if (p->sysctl & TI113X_SCR_CLKRUN_SEL) { - strcat(buf, " [clkrun irq 12]"); - mask &= ~0x1000; - } else { - strcat(buf, " [clkrun irq 10]"); - mask &= ~0x0400; - } - } - if (p->sysctl & TI113X_SCR_PWRSAVINGS) - strcat(buf, " [pwr save]"); - switch (p->devctl & TI113X_DCR_IMODE_MASK) { - case TI12XX_DCR_IMODE_PCI_ONLY: - strcat(buf, " [pci only]"); - mask = 0; - break; - case TI113X_DCR_IMODE_ISA: - strcat(buf, " [isa irq]"); - if (old) mask &= ~0x0018; - break; - case TI113X_DCR_IMODE_SERIAL: - strcat(buf, " [pci + serial irq]"); - mask = 0xffff; - break; - case TI12XX_DCR_IMODE_ALL_SERIAL: - strcat(buf, " [serial pci & irq]"); - mask = 0xffff; - break; - } - return mask; -} - -#endif - -/*====================================================================== - - Code to save and restore global state information for the Ricoh - RL5C4XX controllers, and to set and report global configuration - options. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void rl5c4xx_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; - config_readw(t, RL5C4XX_MISC, &p->misc); - config_readw(t, RL5C4XX_16BIT_CTL, &p->ctl); - config_readw(t, RL5C4XX_16BIT_IO_0, &p->io); - config_readw(t, RL5C4XX_16BIT_MEM_0, &p->mem); -} - -static void rl5c4xx_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; - config_writew(t, RL5C4XX_MISC, p->misc); - config_writew(t, RL5C4XX_16BIT_CTL, p->ctl); - config_writew(t, RL5C4XX_16BIT_IO_0, p->io); - config_writew(t, RL5C4XX_16BIT_MEM_0, p->mem); -} - -static u_int __init rl5c4xx_set_opts(u_short s, char *buf) -{ - rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; - u_int mask = 0xffff; - int old = (socket[s].type < IS_RL5C475); - - p->ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; - if (old) p->ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2; - - if (setup_time >= 0) { - p->io = (p->io & ~RL5C4XX_SETUP_MASK) + - ((setup_time+1) << RL5C4XX_SETUP_SHIFT); - p->mem = (p->mem & ~RL5C4XX_SETUP_MASK) + - (setup_time << RL5C4XX_SETUP_SHIFT); - } - if (cmd_time >= 0) { - p->io = (p->io & ~RL5C4XX_CMD_MASK) + - (cmd_time << RL5C4XX_CMD_SHIFT); - p->mem = (p->mem & ~RL5C4XX_CMD_MASK) + - (cmd_time << RL5C4XX_CMD_SHIFT); - } - if (hold_time >= 0) { - p->io = (p->io & ~RL5C4XX_HOLD_MASK) + - (hold_time << RL5C4XX_HOLD_SHIFT); - p->mem = (p->mem & ~RL5C4XX_HOLD_MASK) + - (hold_time << RL5C4XX_HOLD_SHIFT); - } - if (!old) { - switch (irq_mode) { - case 1: - p->misc &= ~RL5C47X_MISC_SRIRQ_ENA; break; - case 2: - p->misc |= RL5C47X_MISC_SRIRQ_ENA; break; - } - if (p->misc & RL5C47X_MISC_SRIRQ_ENA) - sprintf(buf, " [serial irq]"); - else - sprintf(buf, " [isa irq]"); - buf += strlen(buf); - } - sprintf(buf, " [io %d/%d/%d] [mem %d/%d/%d]", - (p->io & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT, - (p->io & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT, - (p->io & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT, - (p->mem & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT, - (p->mem & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT, - (p->mem & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT); - return mask; -} - -#endif - -/*====================================================================== - - Code to save and restore global state information for O2Micro - controllers, and to set and report global configuration options. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void o2micro_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - o2micro_state_t *p = &socket[s].state.o2micro; - if ((t->revision == 0x34) || (t->revision == 0x62) || - (t->type == IS_OZ6812)) { - p->mode_a = i365_get(s, O2_MODE_A_2); - p->mode_b = i365_get(s, O2_MODE_B_2); - } else { - p->mode_a = i365_get(s, O2_MODE_A); - p->mode_b = i365_get(s, O2_MODE_B); - } - p->mode_c = i365_get(s, O2_MODE_C); - p->mode_d = i365_get(s, O2_MODE_D); - if (t->flags & IS_CARDBUS) { - p->mhpg = i365_get(s, O2_MHPG_DMA); - p->fifo = i365_get(s, O2_FIFO_ENA); - p->mode_e = i365_get(s, O2_MODE_E); - } -} - -static void o2micro_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - o2micro_state_t *p = &socket[s].state.o2micro; - if ((t->revision == 0x34) || (t->revision == 0x62) || - (t->type == IS_OZ6812)) { - i365_set(s, O2_MODE_A_2, p->mode_a); - i365_set(s, O2_MODE_B_2, p->mode_b); - } else { - i365_set(s, O2_MODE_A, p->mode_a); - i365_set(s, O2_MODE_B, p->mode_b); - } - i365_set(s, O2_MODE_C, p->mode_c); - i365_set(s, O2_MODE_D, p->mode_d); - if (t->flags & IS_CARDBUS) { - i365_set(s, O2_MHPG_DMA, p->mhpg); - i365_set(s, O2_FIFO_ENA, p->fifo); - i365_set(s, O2_MODE_E, p->mode_e); - } -} - -static u_int __init o2micro_set_opts(u_short s, char *buf) -{ - socket_info_t *t = &socket[s]; - o2micro_state_t *p = &socket[s].state.o2micro; - u_int mask = 0xffff; - - p->mode_b = (p->mode_b & ~O2_MODE_B_IDENT) | O2_MODE_B_ID_CSTEP; - flip(p->mode_b, O2_MODE_B_IRQ15_RI, has_ring); - p->mode_c &= ~(O2_MODE_C_ZVIDEO | O2_MODE_C_DREQ_MASK); - if (t->flags & IS_CARDBUS) { - p->mode_d &= ~O2_MODE_D_W97_IRQ; - p->mode_e &= ~O2_MODE_E_MHPG_DMA; - p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA; - p->mhpg &= ~O2_MHPG_CHANNEL; - if (t->revision == 0x34) - p->mode_c = 0x20; - } else { - if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000; - } - sprintf(buf, " [a %02x] [b %02x] [c %02x] [d %02x]", - p->mode_a, p->mode_b, p->mode_c, p->mode_d); - if (t->flags & IS_CARDBUS) { - buf += strlen(buf); - sprintf(buf, " [mhpg %02x] [fifo %02x] [e %02x]", - p->mhpg, p->fifo, p->mode_e); - } - return mask; -} - -#endif - -/*====================================================================== - - Code to save and restore global state information for the Toshiba - ToPIC 95 and 97 controllers, and to set and report global - configuration options. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void topic_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - topic_state_t *p = &socket[s].state.topic; - config_readb(t, TOPIC_SLOT_CONTROL, &p->slot); - config_readb(t, TOPIC_CARD_CONTROL, &p->ccr); - config_readb(t, TOPIC_CARD_DETECT, &p->cdr); - config_readl(t, TOPIC_REGISTER_CONTROL, &p->rcr); -} - -static void topic_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - topic_state_t *p = &socket[s].state.topic; - config_writeb(t, TOPIC_SLOT_CONTROL, p->slot); - config_writeb(t, TOPIC_CARD_CONTROL, p->ccr); - config_writeb(t, TOPIC_CARD_DETECT, p->cdr); - config_writel(t, TOPIC_REGISTER_CONTROL, p->rcr); -} - -static int topic_set_irq_mode(u_short s, int pcsc, int pint) -{ - if (socket[s].type == IS_TOPIC97) { - topic_state_t *p = &socket[s].state.topic; - flip(p->ccr, TOPIC97_ICR_IRQSEL, pcsc); - return 0; - } else { - /* no ISA card status change irq */ - return !pcsc; - } -} - -static u_int __init topic_set_opts(u_short s, char *buf) -{ - topic_state_t *p = &socket[s].state.topic; - - p->slot |= TOPIC_SLOT_SLOTON|TOPIC_SLOT_SLOTEN|TOPIC_SLOT_ID_LOCK; - p->cdr |= TOPIC_CDR_MODE_PC32; - p->cdr &= ~(TOPIC_CDR_SW_DETECT); - sprintf(buf, " [slot 0x%02x] [ccr 0x%02x] [cdr 0x%02x] [rcr 0x%02x]", - p->slot, p->ccr, p->cdr, p->rcr); - return 0xffff; -} - -#endif - -/*====================================================================== - - Routines to handle common CardBus options - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void cb_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - - config_readb(t, PCI_CACHE_LINE_SIZE, &t->cache); - config_readb(t, PCI_LATENCY_TIMER, &t->pci_lat); - config_readb(t, CB_LATENCY_TIMER, &t->cb_lat); - config_readb(t, CB_CARDBUS_BUS, &t->cap.cardbus); - config_readb(t, CB_SUBORD_BUS, &t->sub_bus); - config_readw(t, CB_BRIDGE_CONTROL, &t->bcr); - t->cap.pci_irq = t->pdev->irq; -} - -static void cb_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - pci_set_power_state(t->pdev, 0); /* FIXME: Do we really need all of this? */ - config_writel(t, CB_LEGACY_MODE_BASE, 0); - config_writel(t, PCI_BASE_ADDRESS_0, t->cb_phys); - config_writew(t, PCI_COMMAND, CMD_DFLT); - config_writeb(t, PCI_CACHE_LINE_SIZE, t->cache); - config_writeb(t, PCI_LATENCY_TIMER, t->pci_lat); - config_writeb(t, CB_LATENCY_TIMER, t->cb_lat); - config_writeb(t, CB_CARDBUS_BUS, t->cap.cardbus); - config_writeb(t, CB_SUBORD_BUS, t->sub_bus); - config_writew(t, CB_BRIDGE_CONTROL, t->bcr); -} - -static int cb_get_irq_mode(u_short s) -{ - return (!(socket[s].bcr & CB_BCR_ISA_IRQ)); -} - -static int cb_set_irq_mode(u_short s, int pcsc, int pint) -{ - socket_info_t *t = &socket[s]; - flip(t->bcr, CB_BCR_ISA_IRQ, !(pint)); - if (t->flags & IS_CIRRUS) - return cirrus_set_irq_mode(s, pcsc, pint); - else if (t->flags & IS_TI) - return ti113x_set_irq_mode(s, pcsc, pint); - else if (t->flags & IS_TOPIC) - return topic_set_irq_mode(s, pcsc, pint); - return 0; -} - -static void __init pci_scan(u_short sock); - -static void __init cb_set_opts(u_short s, char *buf) -{ - socket_info_t *t = &socket[s]; - t->bcr |= CB_BCR_WRITE_POST; - /* some TI1130's seem to exhibit problems with write posting */ - if (((t->type == IS_TI1130) && (t->revision == 4) && - (cb_write_post < 0)) || (cb_write_post == 0)) - t->bcr &= ~CB_BCR_WRITE_POST; - if (t->cache == 0) t->cache = 8; - if (pci_latency >= 0) t->pci_lat = pci_latency; - if (t->pci_lat == 0) t->pci_lat = 0xa8; - if (cb_latency >= 0) t->cb_lat = cb_latency; - if (t->cb_lat == 0) t->cb_lat = 0xb0; - if ((t->cap.pci_irq == 0) && (pci_csc || pci_int) && do_scan) - pci_scan(s); - if (t->cap.pci_irq == 0) - strcat(buf, " [no pci irq]"); - else - sprintf(buf, " [pci irq %d]", t->cap.pci_irq); - buf += strlen(buf); - if ((cb_bus_base > 0) || (t->cap.cardbus == 0)) { - if (cb_bus_base <= 0) cb_bus_base = 0x20; - t->cap.cardbus = cb_bus_base; - t->sub_bus = cb_bus_base+cb_bus_step; - cb_bus_base += cb_bus_step+1; - } - if (!(t->flags & IS_TOPIC)) - t->cap.features |= SS_CAP_PAGE_REGS; - sprintf(buf, " [lat %d/%d] [bus %d/%d]", - t->pci_lat, t->cb_lat, t->cap.cardbus, t->sub_bus); -} - -#endif /*====================================================================== @@ -1116,27 +511,11 @@ static void get_bridge_state(u_short s) else if (t->flags & IS_VADEM) vg46x_get_state(s); #endif -#ifdef CONFIG_PCI - else if (t->flags & IS_O2MICRO) - o2micro_get_state(s); - else if (t->flags & IS_TI) - ti113x_get_state(s); - else if (t->flags & IS_RICOH) - rl5c4xx_get_state(s); - else if (t->flags & IS_TOPIC) - topic_get_state(s); - if (t->flags & IS_CARDBUS) - cb_get_state(s); -#endif } static void set_bridge_state(u_short s) { socket_info_t *t = &socket[s]; -#ifdef CONFIG_PCI - if (t->flags & IS_CARDBUS) - cb_set_state(s); -#endif if (t->flags & IS_CIRRUS) cirrus_set_state(s); else { @@ -1148,16 +527,6 @@ static void set_bridge_state(u_short s) if (t->flags & IS_VADEM) vg46x_set_state(s); #endif -#ifdef CONFIG_PCI - if (t->flags & IS_O2MICRO) - o2micro_set_state(s); - else if (t->flags & IS_TI) - ti113x_set_state(s); - else if (t->flags & IS_RICOH) - rl5c4xx_set_state(s); - else if (t->flags & IS_TOPIC) - topic_set_state(s); -#endif } static u_int __init set_bridge_opts(u_short s, u_short ns) @@ -1178,33 +547,11 @@ static u_int __init set_bridge_opts(u_short s, u_short ns) #ifdef CONFIG_ISA else if (socket[i].flags & IS_VADEM) m = vg46x_set_opts(i, buf); -#endif -#ifdef CONFIG_PCI - else if (socket[i].flags & IS_O2MICRO) - m = o2micro_set_opts(i, buf); - else if (socket[i].flags & IS_TI) - m = ti113x_set_opts(i, buf); - else if (socket[i].flags & IS_RICOH) - m = rl5c4xx_set_opts(i, buf); - else if (socket[i].flags & IS_TOPIC) - m = topic_set_opts(i, buf); - if (socket[i].flags & IS_CARDBUS) - cb_set_opts(i, buf+strlen(buf)); #endif set_bridge_state(i); printk(KERN_INFO " host opts [%d]:%s\n", i, (*buf) ? buf : " none"); } -#ifdef CONFIG_PCI - /* Mask out all PCI interrupts */ - for (i = 0; i < sockets; i++) - m &= ~(1<next) - m &= ~(1<irq); - } -#endif return m; } @@ -1219,11 +566,6 @@ static u_short irq_sock; static void irq_count(int irq, void *dev, struct pt_regs *regs) { -#ifdef CONFIG_PCI - if (socket[irq_sock].flags & IS_CARDBUS) { - cb_writel(irq_sock, CB_SOCKET_EVENT, -1); - } else -#endif i365_get(irq_sock, I365_CSC); irq_hits++; DEBUG(2, "-> hit on irq %d\n", irq); @@ -1246,23 +588,9 @@ static u_int __init test_irq(u_short sock, int irq, int pci) } /* Generate one interrupt */ -#ifdef CONFIG_PCI - if (socket[sock].flags & IS_CARDBUS) { - cb_writel(sock, CB_SOCKET_EVENT, -1); - i365_set(sock, I365_CSCINT, I365_CSC_STSCHG | (csc << 4)); - cb_writel(sock, CB_SOCKET_EVENT, -1); - cb_writel(sock, CB_SOCKET_MASK, CB_SM_CSTSCHG); - cb_writel(sock, CB_SOCKET_FORCE, CB_SE_CSTSCHG); - udelay(1000); - cb_writel(sock, CB_SOCKET_EVENT, -1); - cb_writel(sock, CB_SOCKET_MASK, 0); - } else -#endif - { - i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4)); - i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); - udelay(1000); - } + i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4)); + i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); + udelay(1000); free_irq(irq, NULL); @@ -1286,11 +614,6 @@ static u_int __init isa_scan(u_short sock, u_int mask0) mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8)); #endif -#ifdef CONFIG_PCI - /* Only scan if we can select ISA csc irq's */ - if (!(socket[sock].flags & IS_CARDBUS) || - (cb_set_irq_mode(sock, 0, 0) == 0)) -#endif if (do_scan) { set_bridge_state(sock); i365_set(sock, I365_CSCINT, 0); @@ -1326,26 +649,6 @@ static u_int __init isa_scan(u_short sock, u_int mask0) #endif /* CONFIG_ISA */ -#ifdef CONFIG_PCI - -static void __init pci_scan(u_short sock) -{ - u_int i; - - cb_set_irq_mode(sock, 1, 0); - set_bridge_state(sock); - i365_set(sock, I365_CSCINT, 0); - /* Only probe irq's 9..11, to be conservative */ - for (i = 9; i < 12; i++) { - if ((test_irq(sock, i, 1) == 0) && - (test_irq(sock, i, 1) == 0)) - break; - } - if (i < 12) socket[sock].cap.pci_irq = i; -} - -#endif /* CONFIG_PCI */ - /*====================================================================*/ /* Time conversion functions */ @@ -1476,16 +779,7 @@ static void __init add_pcic(int ns, int type) if (base == 0) printk("\n"); printk(KERN_INFO " %s", pcic[type].name); -#ifdef CONFIG_PCI - if (t->flags & IS_UNKNOWN) - printk(" [0x%04x 0x%04x]", t->pdev->vendor, t->pdev->device); - if (t->flags & IS_CARDBUS) - printk(" PCI-to-CardBus at %s, mem 0x%08x", t->pdev->slot_name, t->cb_phys); - else if (t->flags & IS_PCI) - printk(" PCI-to-PCMCIA at %s, port %#x", t->pdev->slot_name, t->ioaddr); - else -#endif - printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x", + printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x", t->ioaddr, t->psock*0x40); printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : "")); @@ -1504,19 +798,7 @@ static void __init add_pcic(int ns, int type) #else printk(KERN_INFO " PCI card interrupts,"); #endif - -#ifdef CONFIG_PCI - /* Can we use a PCI interrupt for card status changes? */ - if (pci_csc && t->cap.pci_irq) { - for (i = 0; i < ns; i++) - if (_check_irq(t[i].cap.pci_irq, SA_SHIRQ)) break; - if (i == ns) { - use_pci = 1; - printk(" PCI status changes\n"); - } - } -#endif - + #ifdef CONFIG_ISA /* Poll if only two interrupts available */ if (!use_pci && !poll_interval) { @@ -1554,116 +836,11 @@ static void __init add_pcic(int ns, int type) t[i].cap.features |= SS_CAP_PCCARD; t[i].cap.map_size = 0x1000; t[i].cap.irq_mask = mask; - if (pci_int && t[i].cap.pci_irq) - t[i].cap.irq_mask |= (1 << t[i].cap.pci_irq); t[i].cs_irq = isa_irq; -#ifdef CONFIG_PCI - if (t[i].flags & IS_CARDBUS) { - t[i].cap.features |= SS_CAP_CARDBUS; - cb_set_irq_mode(i, pci_csc && t[i].cap.pci_irq, - pci_int && t[i].cap.pci_irq); - } -#endif } } /* add_pcic */ -/*====================================================================*/ - -#ifdef CONFIG_PCI - -static void __init add_pci_bridge(int type, struct pci_dev *dev) -{ - socket_info_t *s = &socket[sockets]; - u_short i, ns; - u32 addr = dev->resource[0].start; - - if (type == PCIC_COUNT) type = IS_UNK_PCI; - pci_write_config_word(dev, PCI_COMMAND, CMD_DFLT); - for (i = ns = 0; i < ((type == IS_I82092AA) ? 4 : 2); i++) { - s->pdev = dev; - add_socket(addr, i, type); - ns++; s++; - } - add_pcic(ns, type); -} - -static void __init add_cb_bridge(int type, struct pci_dev *dev0) -{ - socket_info_t *s = &socket[sockets]; - u_short i, ns; - u_char a, b; - - if (type == PCIC_COUNT) - type = IS_UNK_CARDBUS; - - for (ns = 0; ns < 8; ns++, s++) { - struct pci_dev *dev; - - dev = pci_find_slot(dev0->bus->number, dev0->devfn + ns); - if (!dev) - break; - s->pdev = dev; - pci_read_config_byte(dev, PCI_CLASS_REVISION, &s->revision); - - /* Map CardBus registers if they are not already mapped */ - pci_write_config_dword(dev, CB_LEGACY_MODE_BASE, 0); - s->cb_phys = dev->resource[0].start; - if (!s->cb_phys || !(s->cb_virt = ioremap(s->cb_phys, 0x1000))) { - printk("\n"); - printk(KERN_ERR " No control registers found!\n"); - break; - } - request_mem_region(s->cb_phys, 0x1000, "i82365"); - s->cap.cb_dev = dev; - add_socket(0, 0, type); - } - if (ns == 0) return; - - s -= ns; - if (ns == 2) { - /* Nasty special check for bad bus mapping */ - config_readb(&s[0], CB_CARDBUS_BUS, &a); - config_readb(&s[1], CB_CARDBUS_BUS, &b); - if (a == b) { - config_writeb(&s[0], CB_CARDBUS_BUS, 0); - config_writeb(&s[1], CB_CARDBUS_BUS, 0); - } - } - add_pcic(ns, type); - - /* Re-do card voltage detection, if needed: this checks for - card presence with no voltage detect bits set */ - for (a = sockets-ns; a < sockets; a++) - if (!(cb_readl(a, CB_SOCKET_STATE) & 0x3c86)) - cb_writel(a, CB_SOCKET_FORCE, CB_SF_CVSTEST); - for (i = 0; i < 200; i++) { - for (a = sockets-ns; a < sockets; a++) - if (!(cb_readl(a, CB_SOCKET_STATE) & 0x3c86)) break; - if (a == sockets) break; - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/20); - } - if (i == 200) - printk(KERN_NOTICE "i82365: card voltage interrogation" - " timed out!\n"); -} - -static void __init pci_probe(u_int class, void (add_fn)(int, struct pci_dev *)) -{ - struct pci_dev *dev = NULL; - u_short i; - - while ((dev = pci_find_class(class << 8, dev))) { - pci_enable_device(dev); - if (PCI_FUNC(dev->devfn) != 0) continue; - for (i = 0; i < PCIC_COUNT; i++) - if ((pcic[i].vendor == dev->vendor) && (pcic[i].device == dev->device)) break; - add_fn(i, dev); - } -} - -#endif /* CONFIG_PCI */ /*====================================================================*/ @@ -1739,13 +916,6 @@ static void pcic_interrupt(int irq, void *dev, continue; ISA_LOCK(i, flags); csc = i365_get(i, I365_CSC); -#ifdef CONFIG_PCI - if ((socket[i].flags & IS_CARDBUS) && - (cb_readl(i,CB_SOCKET_EVENT) & (CB_SE_CCD1|CB_SE_CCD2))) { - cb_writel(i, CB_SOCKET_EVENT, CB_SE_CCD1|CB_SE_CCD2); - csc |= I365_CSC_DETECT; - } -#endif if ((csc == 0) || (!socket[i].handler) || (i365_get(i, I365_IDENT) & 0x70)) { ISA_UNLOCK(i, flags); @@ -1821,20 +991,6 @@ static int i365_get_status(u_short sock, u_int *value) *value |= (status & I365_CS_READY) ? SS_READY : 0; *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0; -#ifdef CONFIG_PCI - if (socket[sock].flags & IS_CARDBUS) { - status = cb_readl(sock, CB_SOCKET_STATE); -#ifndef CONFIG_CARDBUS - *value |= (status & CB_SS_32BIT) ? SS_CARDBUS : 0; -#endif - *value |= (status & CB_SS_3VCARD) ? SS_3VCARD : 0; - *value |= (status & CB_SS_XVCARD) ? SS_XVCARD : 0; - } else if (socket[sock].flags & IS_O2MICRO) { - status = i365_get(sock, O2_MODE_B); - *value |= (status & O2_MODE_B_VS1) ? 0 : SS_3VCARD; - *value |= (status & O2_MODE_B_VS2) ? 0 : SS_XVCARD; - } -#endif #ifdef CONFIG_ISA if (socket[sock].type == IS_VG469) { status = i365_get(sock, VG469_VSENSE); @@ -1864,11 +1020,6 @@ static int i365_get_socket(u_short sock, socket_state_t *state) state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; state->Vcc = state->Vpp = 0; -#ifdef CONFIG_PCI - if (t->flags & IS_CARDBUS) { - cb_get_power(sock, state); - } else -#endif if (t->flags & IS_CIRRUS) { if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) { if (reg & I365_VCC_5V) state->Vcc = 33; @@ -1904,12 +1055,7 @@ static int i365_get_socket(u_short sock, socket_state_t *state) reg = i365_get(sock, I365_INTCTL); state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD; -#ifdef CONFIG_PCI - if (cb_get_irq_mode(sock) != 0) - state->io_irq = t->cap.pci_irq; - else -#endif - state->io_irq = reg & I365_IRQ_MASK; + state->io_irq = reg & I365_IRQ_MASK; /* speaker control */ if (t->flags & IS_CIRRUS) { @@ -1946,12 +1092,6 @@ static int i365_set_socket(u_short sock, socket_state_t *state) state->Vcc, state->Vpp, state->io_irq, state->csc_mask); /* First set global controller options */ -#ifdef CONFIG_PCI - if ((t->flags & IS_CARDBUS) && t->cap.pci_irq) - cb_set_irq_mode(sock, pci_csc, - (t->cap.pci_irq == state->io_irq)); - t->bcr &= ~CB_BCR_CB_RESET; -#endif set_bridge_state(sock); /* IO card, RESET flag, IO interrupt */ @@ -1965,13 +1105,6 @@ static int i365_set_socket(u_short sock, socket_state_t *state) if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; -#ifdef CONFIG_PCI - if (t->flags & IS_CARDBUS) { - cb_set_power(sock, state); - reg |= i365_get(sock, I365_POWER) & - (I365_VCC_MASK|I365_VPP1_MASK); - } else -#endif if (t->flags & IS_CIRRUS) { if (state->Vpp != 0) { if (state->Vpp == 120) @@ -2053,13 +1186,6 @@ static int i365_set_socket(u_short sock, socket_state_t *state) } i365_set(sock, I365_CSCINT, reg); i365_get(sock, I365_CSC); -#ifdef CONFIG_PCI - if (t->flags & IS_CARDBUS) { - if (t->cs_irq || (pci_csc && t->cap.pci_irq)) - cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD); - cb_writel(sock, CB_SOCKET_EVENT, -1); - } -#endif return 0; } /* i365_set_socket */ @@ -2145,17 +1271,6 @@ static int i365_get_mem_map(u_short sock, struct pccard_mem_map *mem) mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0; mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start; mem->card_start &= 0x3ffffff; - -#ifdef CONFIG_PCI - /* Take care of high byte, for PCI controllers */ - if (socket[sock].type == IS_PD6729) { - i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); - addr = i365_get(sock, PD67_EXT_DATA) << 24; - } else if (socket[sock].flags & IS_CARDBUS) { - addr = i365_get(sock, CB_MEM_PAGE(map)) << 24; - mem->sys_stop += addr; mem->sys_start += addr; - } -#endif DEBUG(1, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5." "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed, @@ -2178,22 +1293,13 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem) if ((map > 4) || (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) return -EINVAL; - if (!(socket[sock].flags & (IS_PCI | IS_CARDBUS)) && + if (!(socket[sock].flags & IS_PCI) && ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff))) return -EINVAL; /* Turn off the window before changing anything */ if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map)) i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map)); - -#ifdef CONFIG_PCI - /* Take care of high byte, for PCI controllers */ - if (socket[sock].type == IS_PD6729) { - i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); - i365_set(sock, PD67_EXT_DATA, (mem->sys_start >> 24)); - } else if (socket[sock].flags & IS_CARDBUS) - i365_set(sock, CB_MEM_PAGE(map), mem->sys_start >> 24); -#endif base = I365_MEM(map); i = (mem->sys_start >> 12) & 0x0fff; @@ -2221,186 +1327,6 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem) return 0; } /* i365_set_mem_map */ -/*====================================================================== - - Power control for Cardbus controllers: used both for 16-bit and - Cardbus cards. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void cb_get_power(u_short sock, socket_state_t *state) -{ - u_int reg = cb_readl(sock, CB_SOCKET_CONTROL); - state->Vcc = state->Vpp = 0; - switch (reg & CB_SC_VCC_MASK) { - case CB_SC_VCC_3V: state->Vcc = 33; break; - case CB_SC_VCC_5V: state->Vcc = 50; break; - } - switch (reg & CB_SC_VPP_MASK) { - case CB_SC_VPP_3V: state->Vpp = 33; break; - case CB_SC_VPP_5V: state->Vpp = 50; break; - case CB_SC_VPP_12V: state->Vpp = 120; break; - } -} - -static void cb_set_power(u_short sock, socket_state_t *state) -{ - u_int reg = 0; - switch (state->Vcc) { - case 33: reg = CB_SC_VCC_3V; break; - case 50: reg = CB_SC_VCC_5V; break; - default: reg = 0; break; - } - switch (state->Vpp) { - case 33: reg |= CB_SC_VPP_3V; break; - case 50: reg |= CB_SC_VPP_5V; break; - case 120: reg |= CB_SC_VPP_12V; break; - } - if (reg != cb_readl(sock, CB_SOCKET_CONTROL)) - cb_writel(sock, CB_SOCKET_CONTROL, reg); -} - -#endif - -/*====================================================================== - - All the stuff that is strictly for Cardbus cards goes here. - -======================================================================*/ - -#ifdef CONFIG_CARDBUS - -static int cb_get_status(u_short sock, u_int *value) -{ - u_int s; - s = cb_readl(sock, CB_SOCKET_STATE); - *value = ((s & CB_SS_32BIT) ? SS_CARDBUS : 0); - *value |= ((s & CB_SS_CCD1) || (s & CB_SS_CCD2)) ? 0 : SS_DETECT; - *value |= (s & CB_SS_CSTSCHG) ? SS_STSCHG : 0; - *value |= (s & CB_SS_PWRCYCLE) ? (SS_POWERON|SS_READY) : 0; - *value |= (s & CB_SS_3VCARD) ? SS_3VCARD : 0; - *value |= (s & CB_SS_XVCARD) ? SS_XVCARD : 0; - DEBUG(1, "yenta: GetStatus(%d) = %#4.4x\n", sock, *value); - return 0; -} /* cb_get_status */ - -static int cb_get_socket(u_short sock, socket_state_t *state) -{ - socket_info_t *s = &socket[sock]; - u_short bcr; - - cb_get_power(sock, state); - config_readw(s, CB_BRIDGE_CONTROL, &bcr); - state->flags |= (bcr & CB_BCR_CB_RESET) ? SS_RESET : 0; - if (cb_get_irq_mode(sock) != 0) - state->io_irq = s->cap.pci_irq; - else - state->io_irq = i365_get(sock, I365_INTCTL) & I365_IRQ_MASK; - DEBUG(1, "yenta: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " - "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, - state->Vcc, state->Vpp, state->io_irq, state->csc_mask); - return 0; -} /* cb_get_socket */ - -static int cb_set_socket(u_short sock, socket_state_t *state) -{ - socket_info_t *s = &socket[sock]; - u_int reg; - - DEBUG(1, "yenta: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " - "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, - state->Vcc, state->Vpp, state->io_irq, state->csc_mask); - - /* First set global controller options */ - if (s->cap.pci_irq) - cb_set_irq_mode(sock, pci_csc, - (s->cap.pci_irq == state->io_irq)); - s->bcr &= ~CB_BCR_CB_RESET; - s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0; - set_bridge_state(sock); - - cb_set_power(sock, state); - - /* Handle IO interrupt using ISA routing */ - reg = s->intr; - if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq; - i365_set(sock, I365_INTCTL, reg); - - /* Handle CSC mask */ - reg = (socket[sock].cs_irq << 4); - if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; - i365_set(sock, I365_CSCINT, reg); - i365_get(sock, I365_CSC); - if (s->cs_irq || (pci_csc && s->cap.pci_irq)) - cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD); - cb_writel(sock, CB_SOCKET_EVENT, -1); - - return 0; -} /* cb_set_socket */ - -static int cb_get_bridge(u_short sock, struct cb_bridge_map *m) -{ - socket_info_t *s = &socket[sock]; - u_char map; - - map = m->map; - if (map > 1) return -EINVAL; - m->flags &= MAP_IOSPACE; - map += (m->flags & MAP_IOSPACE) ? 2 : 0; - config_readl(s, CB_MEM_BASE(map), &m->start); - config_readl(s, CB_MEM_LIMIT(map), &m->stop); - if (m->start || m->stop) { - m->flags |= MAP_ACTIVE; - m->stop |= (map > 1) ? 3 : 0x0fff; - } - if (map > 1) { - u_short bcr; - config_readw(s, CB_BRIDGE_CONTROL, &bcr); - m->flags |= (bcr & CB_BCR_PREFETCH(map)) ? MAP_PREFETCH : 0; - } - DEBUG(1, "yenta: GetBridge(%d, %d) = %#2.2x, %#4.4x-%#4.4x\n", - sock, map, m->flags, m->start, m->stop); - return 0; -} - -static int cb_set_bridge(u_short sock, struct cb_bridge_map *m) -{ - socket_info_t *s = &socket[sock]; - u_char map; - - DEBUG(1, "yenta: SetBridge(%d, %d, %#2.2x, %#4.4x-%#4.4x)\n", - sock, m->map, m->flags, m->start, m->stop); - map = m->map; - if (!(s->flags & IS_CARDBUS) || (map > 1) || (m->stop < m->start)) - return -EINVAL; - if (m->flags & MAP_IOSPACE) { - if ((m->stop > 0xffff) || (m->start & 3) || - ((m->stop & 3) != 3)) - return -EINVAL; - map += 2; - } else { - u_short bcr; - if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff)) - return -EINVAL; - config_readw(s, CB_BRIDGE_CONTROL, &bcr); - bcr &= ~CB_BCR_PREFETCH(map); - bcr |= (m->flags & MAP_PREFETCH) ? CB_BCR_PREFETCH(map) : 0; - config_writew(s, CB_BRIDGE_CONTROL, bcr); - } - if (m->flags & MAP_ACTIVE) { - config_writel(s, CB_MEM_BASE(map), m->start); - config_writel(s, CB_MEM_LIMIT(map), m->stop); - } else { - config_writel(s, CB_MEM_BASE(map), 0); - config_writel(s, CB_MEM_LIMIT(map), 0); - } - return 0; -} - -#endif /* CONFIG_CARDBUS */ - /*====================================================================== Routines for accessing socket information and register dumps via @@ -2417,13 +1343,6 @@ static int proc_read_info(char *buf, char **start, off_t pos, char *p = buf; p += sprintf(p, "type: %s\npsock: %d\n", pcic[s->type].name, s->psock); -#ifdef CONFIG_PCI - if (s->flags & (IS_PCI|IS_CARDBUS)) - p += sprintf(p, "bus: %02x\ndevfn: %02x.%1x\n", - s->pdev->bus->number, PCI_SLOT(s->pdev->devfn), PCI_FUNC(s->pdev->devfn)); - if (s->flags & IS_CARDBUS) - p += sprintf(p, "cardbus: %02x\n", s->cap.cardbus); -#endif return (p - buf); } @@ -2439,8 +1358,6 @@ static int proc_read_exca(char *buf, char **start, off_t pos, #endif ISA_LOCK(sock, flags); top = 0x40; - if (socket[sock].flags & IS_CARDBUS) - top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50; for (i = 0; i < top; i += 4) { if (i == 0x50) { p += sprintf(p, "\n"); @@ -2455,43 +1372,6 @@ static int proc_read_exca(char *buf, char **start, off_t pos, return (p - buf); } -#ifdef CONFIG_PCI -static int proc_read_pci(char *buf, char **start, off_t pos, - int count, int *eof, void *data) -{ - socket_info_t *s = data; - char *p = buf; - u_int a, b, c, d; - int i; - - for (i = 0; i < 0xc0; i += 0x10) { - config_readl(s, i, &a); - config_readl(s, i+4, &b); - config_readl(s, i+8, &c); - config_readl(s, i+12, &d); - p += sprintf(p, "%08x %08x %08x %08x\n", a, b, c, d); - } - return (p - buf); -} -#endif - -#ifdef CONFIG_CARDBUS -static int proc_read_cardbus(char *buf, char **start, off_t pos, - int count, int *eof, void *data) -{ - u_short sock = (socket_info_t *)data - socket; - char *p = buf; - int i, top; - - top = (socket[sock].flags & IS_O2MICRO) ? 0x30 : 0x20; - for (i = 0; i < top; i += 0x10) - p += sprintf(p, "%08x %08x %08x %08x\n", - cb_readl(sock,i+0x00), cb_readl(sock,i+0x04), - cb_readl(sock,i+0x08), cb_readl(sock,i+0x0c)); - return (p - buf); -} -#endif - static void pcic_proc_setup(unsigned int sock, struct proc_dir_entry *base) { #ifdef CONFIG_PROC_FS @@ -2502,14 +1382,6 @@ static void pcic_proc_setup(unsigned int sock, struct proc_dir_entry *base) create_proc_read_entry("info", 0, base, proc_read_info, s); create_proc_read_entry("exca", 0, base, proc_read_exca, s); -#ifdef CONFIG_PCI - if (s->flags & (IS_PCI|IS_CARDBUS)) - create_proc_read_entry("pci", 0, base, proc_read_pci, s); -#endif -#ifdef CONFIG_CARDBUS - if (s->flags & IS_CARDBUS) - create_proc_read_entry("cardbus", 0, base, proc_read_cardbus, s); -#endif s->proc = base; #endif } @@ -2520,37 +1392,12 @@ static void pcic_proc_remove(u_short sock) if (base == NULL) return; remove_proc_entry("info", base); remove_proc_entry("exca", base); -#ifdef CONFIG_PCI - if (socket[sock].flags & (IS_PCI|IS_CARDBUS)) - remove_proc_entry("pci", base); -#endif -#ifdef CONFIG_CARDBUS - if (socket[sock].flags & IS_CARDBUS) - remove_proc_entry("cardbus", base); -#endif } #endif /* CONFIG_PROC_FS */ /*====================================================================*/ -/* - * This looks like a lot of duplication, and it is. What we should REALLY - * have is separate functions for the separate cases, instead of having - * duplicate tests in them - and then have the test in the place that sets - * up the ss_entry function pointer table instead! - * - * For example, the IS_CARDBUS thing is something we know _statically_, - * and as such it is a waste of time and space to test it dynamically. - * - * Much of this goes away by splitting off the cases. One small step at a - * time.. - */ - -#ifdef CONFIG_CARDBUS -#define is_cardbus(sock) ((socket[(sock)].flags & IS_CARDBUS) && (cb_readl((sock), CB_SOCKET_STATE) & CB_SS_32BIT)) -#endif - /* * The locking is rather broken. Why do we only lock for ISA, not for * all other cases? If there are reasons to lock, we should lock. Not @@ -2561,15 +1408,12 @@ static void pcic_proc_remove(u_short sock) */ #ifdef CONFIG_ISA #define LOCKED(x) do { \ - if (socket[(sock)].flags & IS_CARDBUS) return x; \ - do { \ - int retval; \ - unsigned long flags; \ - spin_lock_irqsave(&isa_lock, flags); \ - retval = x; \ - spin_unlock_irqrestore(&isa_lock, flags); \ - return retval; \ - } while (0); \ + int retval; \ + unsigned long flags; \ + spin_lock_irqsave(&isa_lock, flags); \ + retval = x; \ + spin_unlock_irqrestore(&isa_lock, flags); \ + return retval; \ } while (0) #else #define LOCKED(x) return x @@ -2583,10 +1427,6 @@ static int pcic_get_status(unsigned int sock, u_int *value) return -EINVAL; } -#ifdef CONFIG_CARDBUS - if (is_cardbus(sock)) - return cb_get_status(sock, value); -#endif LOCKED(i365_get_status(sock, value)); } @@ -2595,10 +1435,6 @@ static int pcic_get_socket(unsigned int sock, socket_state_t *state) if (socket[sock].flags & IS_ALIVE) return -EINVAL; -#ifdef CONFIG_CARDBUS - if (is_cardbus(sock)) - return cb_get_socket(sock, state); -#endif LOCKED(i365_get_socket(sock, state)); } @@ -2607,10 +1443,6 @@ static int pcic_set_socket(unsigned int sock, socket_state_t *state) if (socket[sock].flags & IS_ALIVE) return -EINVAL; -#ifdef CONFIG_CARDBUS - if (is_cardbus(sock)) - return cb_set_socket(sock, state); -#endif LOCKED(i365_set_socket(sock, state)); } @@ -2646,24 +1478,6 @@ static int pcic_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) LOCKED(i365_set_mem_map(sock, mem)); } -static int pcic_get_bridge(unsigned int sock, struct cb_bridge_map *m) -{ -#ifdef CONFIG_CARDBUS - return cb_get_bridge(sock, m); -#else - return -EINVAL; -#endif -} - -static int pcic_set_bridge(unsigned int sock, struct cb_bridge_map *m) -{ -#ifdef CONFIG_CARDBUS - return cb_set_bridge(sock, m); -#else - return -EINVAL; -#endif -} - static int pcic_init(unsigned int s) { int i; @@ -2700,8 +1514,6 @@ static struct pccard_operations pcic_operations = { pcic_set_io_map, pcic_get_mem_map, pcic_set_mem_map, - pcic_get_bridge, - pcic_set_bridge, pcic_proc_setup }; @@ -2720,13 +1532,6 @@ static int __init init_i82365(void) printk(KERN_INFO "Intel PCIC probe: "); sockets = 0; -#ifdef CONFIG_PCI - if (do_pci_probe) { - pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge); - pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge); - } -#endif - #ifdef CONFIG_ISA isa_probe(); #endif @@ -2741,17 +1546,6 @@ static int __init init_i82365(void) if (grab_irq != 0) request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL); #endif -#ifdef CONFIG_PCI - if (pci_csc) { - u_int i, irq, mask = 0; - for (i = 0; i < sockets; i++) { - irq = socket[i].cap.pci_irq; - if (irq && !(mask & (1<op && socket->op->get_bridge) - return socket->op->get_bridge(socket, m); - return -EINVAL; -} - -static int pci_set_bridge(unsigned int sock, struct cb_bridge_map *m) -{ - pci_socket_t *socket = pci_socket_array + sock; - - if (socket->op && socket->op->set_bridge) - return socket->op->set_bridge(socket, m); - return -EINVAL; -} - static void pci_proc_setup(unsigned int sock, struct proc_dir_entry *base) { pci_socket_t *socket = pci_socket_array + sock; @@ -184,29 +159,32 @@ static struct pccard_operations pci_socket_operations = { pci_set_io_map, pci_get_mem_map, pci_set_mem_map, - pci_get_bridge, - pci_set_bridge, pci_proc_setup }; -static int __init pci_socket_probe(struct pci_dev *dev, int nr, const struct pci_simple_probe_entry * entry, void *data) +static int __init add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops) { pci_socket_t *socket = nr + pci_socket_array; - printk("Found controller %d: %s\n", nr, dev->name); socket->dev = dev; - socket->op = entry->dev_data; - socket->op->open(socket); - return 0; + socket->op = ops; + return socket->op->open(socket); } static int __init pci_socket_init(void) { - int sockets = pci_simple_probe(controller_list, MAX_SOCKETS, pci_socket_probe, NULL); + struct pci_dev *dev = NULL; + int nr = 0; + + while ((dev = pci_find_class(PCI_CLASS_BRIDGE_CARDBUS << 8, dev)) != NULL) { + printk("Adding cardbus controller %d: %s\n", nr, dev->name); + add_pci_socket(nr, dev, ¥ta_operations); + nr++; + } - if (sockets <= 0) + if (nr <= 0) return -1; - register_ss_entry(sockets, &pci_socket_operations); + register_ss_entry(nr, &pci_socket_operations); return 0; } diff --git a/drivers/pcmcia/pci_socket.h b/drivers/pcmcia/pci_socket.h index 5d0887a2354e..d4cec4241b5d 100644 --- a/drivers/pcmcia/pci_socket.h +++ b/drivers/pcmcia/pci_socket.h @@ -30,8 +30,6 @@ struct pci_socket_ops { int (*set_io_map)(struct pci_socket *, struct pccard_io_map *); int (*get_mem_map)(struct pci_socket *, struct pccard_mem_map *); int (*set_mem_map)(struct pci_socket *, struct pccard_mem_map *); - int (*get_bridge)(struct pci_socket *, struct cb_bridge_map *); - int (*set_bridge)(struct pci_socket *, struct cb_bridge_map *); void (*proc_setup)(struct pci_socket *, struct proc_dir_entry *base); }; diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 541b571f36b6..d5900c6f8c10 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -929,13 +929,6 @@ static int tcic_set_mem_map(unsigned int lsock, struct pccard_mem_map *mem) /*====================================================================*/ -static int tcic_get_bridge(unsigned int sock, struct cb_bridge_map *m) -{ - return -EINVAL; -} - -#define tcic_set_bridge tcic_get_bridge - static void tcic_proc_setup(unsigned int sock, struct proc_dir_entry *base) { } @@ -976,8 +969,6 @@ static struct pccard_operations tcic_operations = { tcic_set_io_map, tcic_get_mem_map, tcic_set_mem_map, - tcic_get_bridge, - tcic_set_bridge, tcic_proc_setup }; diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c index 3b5c1df7912d..330c657b2ebf 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta.c @@ -1,7 +1,7 @@ /* * Regular lowlevel cardbus driver ("yenta") * - * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999, 2000 Linus Torvalds */ #include #include @@ -185,44 +185,20 @@ static void yenta_set_power(pci_socket_t *socket, socket_state_t *state) cb_writel(socket, CB_SOCKET_CONTROL, reg); } -static void yenta_bridge_control(pci_socket_t *socket, u16 bridgectl) -{ - struct pci_dev *dev = socket->dev; - - /* MAGIC NUMBERS! Fixme */ - config_writew(socket, CB_BRIDGE_CONTROL, bridgectl); - config_writel(socket, CB_LEGACY_MODE_BASE, 0); - - config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); - config_writew(socket, PCI_COMMAND, - PCI_COMMAND_IO | - PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | - PCI_COMMAND_WAIT); - config_writeb(socket, PCI_CACHE_LINE_SIZE, 32); - config_writeb(socket, PCI_LATENCY_TIMER, 168); - config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176); - config_writeb(socket, PCI_PRIMARY_BUS, dev->bus->number); - config_writeb(socket, PCI_SECONDARY_BUS, dev->subordinate->number); - config_writeb(socket, PCI_SUBORDINATE_BUS, dev->subordinate->number); - config_writew(socket, CB_BRIDGE_CONTROL, bridgectl); -} - static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state) { u16 bridge; yenta_set_power(socket, state); - bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_CRST; - if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0; + bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN; /* ISA interrupt control? */ if (bridge & CB_BRIDGE_INTR) { u8 intr = exca_readb(socket, I365_INTCTL); - intr = (intr & ~0xf) | state->io_irq; + intr = (intr & ~0xf) ; // | state->io_irq; exca_writeb(socket, I365_INTCTL, intr); } } else { @@ -254,8 +230,7 @@ static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state) exca_writeb(socket, I365_CSCINT, reg); exca_readb(socket, I365_CSC); } - yenta_bridge_control(socket, bridge); - + config_writew(socket, CB_BRIDGE_CONTROL, bridge); /* Socket event mask: get card insert/remove events.. */ cb_writel(socket, CB_SOCKET_EVENT, -1); cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); @@ -406,69 +381,6 @@ static int yenta_set_mem_map(pci_socket_t *socket, struct pccard_mem_map *mem) return 0; } -static int yenta_get_bridge(pci_socket_t *socket, struct cb_bridge_map *m) -{ - unsigned map; - - map = m->map; - if (map > 1) - return -EINVAL; - - m->flags &= MAP_IOSPACE; - map += (m->flags & MAP_IOSPACE) ? 2 : 0; - m->start = config_readl(socket, CB_BRIDGE_BASE(map)); - m->stop = config_readl(socket, CB_BRIDGE_LIMIT(map)); - if (m->start || m->stop) { - m->flags |= MAP_ACTIVE; - m->stop |= (map > 1) ? 3 : 0x0fff; - } - - /* Get prefetch state for memory mappings */ - if (map < 2) { - u16 ctrl, prefetch_mask = CB_BRIDGE_PREFETCH0 << map; - - ctrl = config_readw(socket, CB_BRIDGE_CONTROL); - m->flags |= (ctrl & prefetch_mask) ? MAP_PREFETCH : 0; - } - return 0; -} - -static int yenta_set_bridge(pci_socket_t *socket, struct cb_bridge_map *m) -{ - unsigned map; - u32 start, end; - - map = m->map; - if (map > 1 || m->stop < m->start) - return -EINVAL; - - if (m->flags & MAP_IOSPACE) { - if ((m->stop > 0xffff) || (m->start & 3) || - ((m->stop & 3) != 3)) - return -EINVAL; - map += 2; - } else { - u16 ctrl, prefetch_mask = CB_BRIDGE_PREFETCH0 << map; - - if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff)) - return -EINVAL; - ctrl = config_readw(socket, CB_BRIDGE_CONTROL); - ctrl &= ~prefetch_mask; - ctrl |= (m->flags & MAP_PREFETCH) ? prefetch_mask : 0; - config_writew(socket, CB_BRIDGE_CONTROL, ctrl); - } - - start = 0; - end = 0; - if (m->flags & MAP_ACTIVE) { - start = m->start; - end = m->stop; - } - config_writel(socket, CB_BRIDGE_BASE(map), start); - config_writel(socket, CB_BRIDGE_LIMIT(map), end); - return 0; -} - static void yenta_proc_setup(pci_socket_t *socket, struct proc_dir_entry *base) { /* Not done yet */ @@ -533,22 +445,12 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket) return probe_irq_mask(val); } -/* Called at resume and initialization events */ -static int yenta_init(pci_socket_t *socket) +static void yenta_clear_maps(pci_socket_t *socket) { int i; pccard_io_map io = { 0, 0, 0, 0, 1 }; pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; - pci_set_power_state(socket->dev, 0); - - /* MAGIC NUMBERS! Fixme */ - config_writeb(socket, PCI_LATENCY_TIMER, 168); - config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176); - - exca_writeb(socket, I365_GBLCTL, 0x00); - exca_writeb(socket, I365_GENCTL, 0x00); - mem.sys_stop = 0x0fff; yenta_set_socket(socket, &dead_socket); for (i = 0; i < 2; i++) { @@ -559,6 +461,35 @@ static int yenta_init(pci_socket_t *socket) mem.map = i; yenta_set_mem_map(socket, &mem); } +} + +/* Called at resume and initialization events */ +static int yenta_init(pci_socket_t *socket) +{ + struct pci_dev *dev = socket->dev; + + pci_set_power_state(socket->dev, 0); + + config_writel(socket, CB_LEGACY_MODE_BASE, 0); + config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); + config_writew(socket, PCI_COMMAND, + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | + PCI_COMMAND_WAIT); + + /* MAGIC NUMBERS! Fixme */ + config_writeb(socket, PCI_CACHE_LINE_SIZE, 32); + config_writeb(socket, PCI_LATENCY_TIMER, 168); + config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176); + config_writeb(socket, PCI_PRIMARY_BUS, dev->bus->number); + config_writeb(socket, PCI_SECONDARY_BUS, dev->subordinate->number); + config_writeb(socket, PCI_SUBORDINATE_BUS, dev->subordinate->number); + + exca_writeb(socket, I365_GBLCTL, 0x00); + exca_writeb(socket, I365_GENCTL, 0x00); + + yenta_clear_maps(socket); return 0; } @@ -607,6 +538,63 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket) printk("Yenta IRQ list %04x\n", socket->cap.irq_mask); } +static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type) +{ + struct pci_bus *bus; + struct resource *root, *res; + u32 start, end; + u32 align, size, min, max; + unsigned offset; + + offset = 0x1c + 8*nr; + bus = socket->dev->subordinate; + res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; + printk("dev=%p, bus=%p, parent=%p\n", socket->dev, bus, socket->dev->bus); + printk("res = %p, bus->res = %p\n", res, bus->resource[nr]); + res->name = bus->name; + res->flags = type; + res->start = 0; + res->end = 0; + root = pci_find_parent_resource(socket->dev, res); + + if (!root) + return; + + start = config_readl(socket, offset); + end = config_readl(socket, offset+4) | 0xfff; + if (start && end > start) { + res->start = start; + res->end = end; + request_resource(root, res); + return; + } + + align = size = 4*1024*1024; + min = 0x10000000; max = ~0U; + if (type & IORESOURCE_IO) { + align = 1024; + size = 256; + min = 0x1000; + max = 0xffff; + } + + if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0) + return; + + config_writel(socket, offset, res->start); + config_writel(socket, offset+4, res->end); +} + +/* + * Allocate the bridge mappings for the device.. + */ +static void yenta_allocate_resources(pci_socket_t *socket) +{ + yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); + yenta_allocate_res(socket, 1, IORESOURCE_MEM); + yenta_allocate_res(socket, 2, IORESOURCE_IO); +} + /* * Initialize a cardbus controller. Make sure we have a usable * interrupt, and that we can map the cardbus area. Fill in the @@ -636,14 +624,17 @@ static int yenta_open(pci_socket_t *socket) if (!socket->base) return -1; + /* Disable all events */ + cb_writel(socket, CB_SOCKET_MASK, 0x0); + if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket)) socket->cb_irq = dev->irq; /* Figure out what the dang thing can do.. */ yenta_get_socket_capabilities(socket); - /* Disable all events */ - cb_writel(socket, CB_SOCKET_MASK, 0x0); + /* Set up the bridge regions.. */ + yenta_allocate_resources(socket); printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); return 0; @@ -676,8 +667,6 @@ struct pci_socket_ops yenta_operations = { yenta_set_io_map, yenta_get_mem_map, yenta_set_mem_map, - yenta_get_bridge, - yenta_set_bridge, yenta_proc_setup }; @@ -698,7 +687,5 @@ struct pci_socket_ops ricoh_operations = { yenta_set_io_map, yenta_get_mem_map, yenta_set_mem_map, - yenta_get_bridge, - yenta_set_bridge, yenta_proc_setup }; diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index c94c3f9b0ad1..b7292d9a2628 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -19,14 +19,31 @@ comment 'Miscellaneous USB options' fi comment 'USB Devices' - dep_tristate ' USB keyboard support' CONFIG_USB_KBD $CONFIG_USB - dep_tristate ' USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB + dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB + if [ "$CONFIG_USB_HID" != "y" ]; then + dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB + dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB + fi + if [ "$CONFIG_USB_HID" != "n" ]; then + dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB_HID + dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB_HID + if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then + bool ' Mix all mice into one device' CONFIG_INPUT_MOUSEDEV_MIX $CONFIG_USB_HID + fi + dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB_HID + dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB_HID + bool ' USB HID debug output' CONFIG_USB_HID_DEBUG + if [ "$CONFIG_USB_HID_DEBUG" != "n" ]; then + bool ' USB HID lots of debug output' CONFIG_USB_HID_DEBUG_LOTS + fi + fi dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB dep_tristate ' USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB + dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB dep_tristate ' USB SCSI (mass storage) support' CONFIG_USB_SCSI $CONFIG_USB if [ "$CONFIG_USB_SCSI" != "n" ]; then diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 03f3a56a655d..6d08917a047f 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -1,20 +1,12 @@ # -# Makefile for the kernel usb device drivers. +# Makefile for the kernel USB device drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now inherited from the -# parent makes.. SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) L_TARGET := usb.a -M_OBJS := -L_OBJS := MOD_LIST_NAME := USB_MODULES ifeq ($(CONFIG_USB),y) @@ -48,13 +40,6 @@ ifeq ($(CONFIG_USB_OHCI_HCD),m) MI_OBJS += ohci-hcd.o endif -ifeq ($(CONFIG_USB_MOUSE),y) - L_OBJS += mouse.o -endif -ifeq ($(CONFIG_USB_MOUSE),m) - M_OBJS += mouse.o -endif - ifeq ($(CONFIG_USB_SCANNER),y) L_OBJS += scanner.o endif @@ -85,21 +70,6 @@ ifeq ($(CONFIG_USB_SERIAL),m) M_OBJS += usb-serial.o endif -ifneq ($(CONFIG_ADB_KEYBOARD),y) -KEYMAP=keymap -else -KEYMAP=keymap-mac -endif - -ifeq ($(CONFIG_USB_KBD),y) - L_OBJS += keyboard.o $(KEYMAP).o -endif - -ifeq ($(CONFIG_USB_KBD),m) - M_OBJS += usb-keyboard.o - MI_OBJS += keyboard.o $(KEYMAP).o -endif - ifeq ($(CONFIG_USB_AUDIO),y) L_OBJS += audio.o endif @@ -116,6 +86,24 @@ ifeq ($(CONFIG_USB_CPIA),m) M_OBJS += cpia.o endif +ifeq ($(CONFIG_USB_OV511),y) + L_OBJS += ov511.o +endif + +ifeq ($(CONFIG_USB_OV511),m) + M_OBJS += ov511.o + MI_OBJS += ov511.o +endif + +ifeq ($(CONFIG_USB_OV511),y) + L_OBJS += ov511.o +endif + +ifeq ($(CONFIG_USB_OV511),m) + M_OBJS += ov511.o + MI_OBJS += ov511.o +endif + ifeq ($(CONFIG_USB_DC2XX),y) L_OBJS += dc2xx.o endif @@ -146,6 +134,71 @@ ifeq ($(CONFIG_USB_EZUSB),m) M_OBJS += ezusb.o endif +ifeq ($(CONFIG_USB_HID),y) + L_OBJS += hid.o + ILX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_HID),m) + M_OBJS += hid.o + IMX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_KBD),y) + L_OBJS += usbkbd.o + ILX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_KBD),m) + M_OBJS += usbkbd.o + IMX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_MOUSE),y) + L_OBJS += usbmouse.o + ILX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_MOUSE),m) + M_OBJS += usbmouse.o + IMX_OBJS := input.o +endif + +LX_OBJS += $(ILX_OBJS) +MX_OBJS += $(IMX_OBJS) + +ifeq ($(CONFIG_INPUT_KEYBDEV),y) + L_OBJS += keybdev.o +endif + +ifeq ($(CONFIG_INPUT_KEYBDEV),m) + M_OBJS += keybdev.o +endif + +ifeq ($(CONFIG_INPUT_MOUSEDEV),y) + L_OBJS += mousedev.o +endif + +ifeq ($(CONFIG_INPUT_MOUSEDEV),m) + M_OBJS += mousedev.o +endif + +ifeq ($(CONFIG_INPUT_JOYDEV),y) + L_OBJS += joydev.o +endif + +ifeq ($(CONFIG_INPUT_JOYDEV),m) + M_OBJS += joydev.o +endif + +ifeq ($(CONFIG_INPUT_EVDEV),y) + L_OBJS += evdev.o +endif + +ifeq ($(CONFIG_INPUT_EVDEV),m) + M_OBJS += evdev.o +endif + ifeq ($(CONFIG_USB_USS720),y) L_OBJS += uss720.o endif @@ -164,18 +217,6 @@ endif include $(TOPDIR)/Rules.make -keymap.o: keymap.c - -keymap.c: maps/serial.map maps/usb.map maps/fixup.map - ./mkmap > $@ - -keymap-mac.o: keymap-mac.c -keymap-mac.c: maps/mac.map maps/usb.map - ./mkmap.adb > $@ - -usb-keyboard.o: $(KEYMAP).o keyboard.o - $(LD) $(LD_RFLAG) -r -o $@ $(KEYMAP).o keyboard.o - ifeq ($(CONFIG_USB_SCSI_DEBUG),y) usb-scsi.o: usb_scsi.o usb_scsi_debug.o $(LD) $(LD_RFLAG) -r -o $@ usb_scsi.o usb_scsi_debug.o diff --git a/drivers/usb/README.hid b/drivers/usb/README.hid new file mode 100644 index 000000000000..3cd3373ff7c5 --- /dev/null +++ b/drivers/usb/README.hid @@ -0,0 +1,162 @@ + Linux HID driver v0.8 + (c) 1999 Vojtech Pavlik + (c) 1999 Andreas Gal + Sponsored by SuSE +---------------------------------------------------------------------------- + +0. Disclaimer +~~~~~~~~~~~~~ + This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + + This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + + You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., 59 +Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Should you need to contact me, the author, you can do so either by e-mail +- mail your message to , or by paper mail: Vojtech Pavlik, +Ucitelska 1576, Prague 8, 182 00 Czech Republic + + For your convenience, the GNU General Public License version 2 is included +in the package: See the file COPYING. + +1. Introduction +~~~~~~~~~~~~~~~ + This is a driver for USB devices conforming to the USB HID (Human Input +Device) standard. These devices include namely keyboards, mice and +joysticks. + + However many other devices (monitors, speakers, UPSs ...) also communicate +through the same protocol, which makes its specification somewhat bloated. +This isn't a problem, though, because the driver doesn't need to know about +all the possible devices it can control, and can just parse the protocol and +leave the rest of the job (for example understanding what the UPS wants to +say) to the userland. + + Because of this, the USB HID driver has two interfaces. One is via the +proc filesystem, allowing userland applications send and read arbitrary +reports to and from a connected USB device. The other is via a very simple +yet generic input device driver, which dispatches input events (keystrokes, +mouse or joystick movements) to specific, backward compatible userland +interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver +interface are emulated, and allow applications to immediately work with USB +mice, USB keyboards and USB joysticks without any changes. + + The input driver is aimed for a little more than USB device handling in +the future, though. It's generic enough so that it can be used for any +mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a +serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to +use this as well as the AT keyboard and Sun keyboard drivers. This will +hopefully allow conversion of all Linux keyboard and mouse and joystick +drivers to this scheme. + + This effort has it's home page at: + + http://www.suse.cz/development/input/ + +You'll find both the latest HID driver and the complete Input driver there. +There is also a mailing list for this: + + listproc@atrey.karlin.mff.cuni.cz + +Send "subscribe linux-joystick Your Name" to subscribe to it. + +2. Usage +~~~~~~~~ + Since the driver comes with recent 2.3 kernels, all that's needed to use +it is to enable it either as a module or compiled-in into the kernel. + + After that, after reboot (and possibly also inserting the USB and HID +modules) the following will happen: + +* If you selected keyboard support, all USB keystrokes will be also routed + to the Linux keyboard driver as if being input through the ordinary system + keyboard. + +* If you selected mouse support, there will be (one or more) simulated PS/2 + mouse devices on major 10, minor 32, 33 and more. These simulated mice can + in addition to a standard 3-button PS/2 mouse behave like MS Intellimice, + with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm + and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse + device can be open by any number of processes (unlike the /dev/psaux), and + for each of them the emulation is separate, each can use a different mode. + The mousedev driver, which emulates the mice, can also emulate a Genius + NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2 + mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X + can decode the 5 buttons yet, so this isn't very useful right now. + +* If you selected joystick support, the driver will take over major 15, the + joystick major number, and will emulate joysticks on it. This means the + normal joystick driver can't be used together with it (now, after the + normal joystick drivers are converted to the input scheme, all will work + nicely together). Also, you'll probably need to calibrate your joystick + manually ('man jscal') to be able to use it, because the USB + autocalibration is far from perfect yet. + +* If you selected event device support, there will be devices on major 10, + minors 64, 65 and more for each input device connected through this + driver. These devices output raw events the input driver dispatches. Each + has a timestamp. This hopefully will be THE way X will talk to keyboard + and mice, because it's hardware independent, and not limited by existing + de-facto standards. + +3. Verifying if it works +~~~~~~~~~~~~~~~~~~~~~~~~ + Typing a couple keys on the keyboard should be enough to check that a USB +keyboard works and is correctly connected to the kernel keyboard driver. + + Doing a cat /dev/hidmouse (c, 10, 32) will verify that a mouse is also +emulated, characters should appear if you move it. + + You can test the joystick emulation with the 'jstest' utility, available +in the joystick package (see Documentation/joystick.txt). + + You can test the event devics with the 'evtest' utitily available on the +input driver homepage (see the URL above). + +4. FAQ +~~~~~~ +Q: Why aren't any questions here yet? +A: Because none were frequent enough yet. + +5. Event interface +~~~~~~~~~~~~~~~~~~ + Should you want to add event device support into any application (X, gpm, +svgalib ...) I (vojtech@suse.cz) will be happy to provide you any help I +can. Here goes a description of the current state of things, which is going +to be extended, but not changed incompatibly as time goes: + + You can use blocking and nonblocking reads, also select() on the +/dev/inputX devices, and you'll always get a whole number of input events on +a read. Their layout is: + +struct input_event { + struct timeval time; + unsigned short type; + unsigned short code; + unsigned int value; +}; + + 'time' is the timestamp, it returns the time at which the event happened. +Type is for example EV_REL for relative momement, REL_KEY for a keypress or +release. More types are defined in include/linux/input.h. + + 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete +list is in include/linux/input.h. + + 'value' is the value the event carries. Either a relative change for +EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for +release, 1 for keypress and 2 for autorepeat. + +6. Proc interface +~~~~~~~~~~~~~~~~~ + For HID-specific devices there is also the /proc interface. It isn't +present in this release yet, though, so it's description will appear here +together with the code in the driver. diff --git a/drivers/usb/README.kbd b/drivers/usb/README.kbd deleted file mode 100644 index 84a77d90f044..000000000000 --- a/drivers/usb/README.kbd +++ /dev/null @@ -1,65 +0,0 @@ -This is a simple USB keyboard driver written from Linus' -USB driver (started with Greg's usb-0.03b.tar.gz source -tree) - -It works fine with my BTC keyboard but I'm still investigating -trouble with my MS keyboard (trouble starts with an inability -to set into boot protocol mode, though, this very well could -be all due to crappy hardware). - -Anyway, I would appreciate you taking a look if you have -any USB keyboards lying around. Oh also, I'm doing this on -UHCI so sorry if it breaks with OHCI. - --ham - - - -Keyboard patch --------------- - -Instead of using the multiple keyboard patch and then running into all -of the kernel version problems that the current Linux-USB project has -had, I'm just mapping the USB keycodes to the standard AT-101 keycodes -and sending them directly to "handle_scancode". - -This may or may not be considered a hack. Anyway it is effective, and -I think safe, and allows USB keyboards to coexist with a serial -keyboard (oh yeah, one side effect is that you can for example hold -down the control key on the serial keyboard and press "a" on the USB -keyboard and you get Control-a like with Windows USB) and works -fine for console and X. - -You do need to make a *tiny* patch the kernel source tree so that the -function "handle_scancode" is exported from keyboard.c though. - - $ cd /usr/src/linux - $ patch -p0 < kbd.patch - -And, of course, then, you need to rebuild and install the kernel. - -** [Vojtech]: Alternately, just 'insmod kbd-stub', if you don't want -to use the keyboard and are too lazy to patch the kernel. - -Keyboard map ------------- - -I'm including a stupid utility "mkmap" which generates the USB->serial -keymap. It takes in maps/serial.map (the current serial keymap, -generated by "dumpkeys"), maps/usb.map (the USB keymap), and -maps/fixup.map (fixes for e0 keys and misc.) and spits out keymap.c -Anyway, it is not beautiful but should serve its purpose for the -moment. - -Other changes -------------- -uhci.c: - * added a context value to the irq callback function - (this is exactly like the "dev_id" field to request_irq) - * played with uhci_reset_port to get better hot-plug results - (eg. do a wait_ms(200) before calling uhci_reset_port) -usb.c: - * disconnect all devices after uhci-control thread is killed - * skip over the HID descriptor - * disconnect the high-level driver in usb_disconnect - diff --git a/drivers/usb/README.ov511 b/drivers/usb/README.ov511 new file mode 100644 index 000000000000..14163ae87d83 --- /dev/null +++ b/drivers/usb/README.ov511 @@ -0,0 +1,70 @@ +------------------------------------------------------------------------------- +Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC +------------------------------------------------------------------------------- + +INTRODUCTION: + +This is a preliminary version of my OV511 Linux device driver. At the moment, +it does not do much more than detect the chip and initialize it. As trivial +as this sounds, it represents many hours of my work. Since OmniVision refused +to release the full specs to me, I had to write code to probe out the register +read/write commands. Some code is in place to allow a frame to be grabbed, but +it is nowhere near complete. + +SUPPORTED CAMERAS: +____________________________________________ +Manufacturer | Model | Custom ID +-----------------+--------------+----------- +D-Link | DSB-C300 | 3 +Creative Labs | WebCam 3 | 21 +-------------------------------------------- + +Any camera using the OV511 and the OV7610 CCD should work with this driver. The +driver only detects known cameras though, based on their custom id number. If +you have a currently unsupported camera, the ID number should be reported to you +in the kernel logs. If you have an unsupported camera, please send me the model, +manufacturer and ID number and I will add it to the detection code. In the +meantime, you can add to the code yourself in the function ov511_probe() + +WHAT YOU NEED: + +- If you want to help with the development, get the chip's specification docs at + http://www.ovt.com/omniusbp.html + +- A Video4Linux compatible frame grabber program (I recommend vidcat) + (see: http://www.exploits.org/v4l/ ) + +WHAT NEEDS TO BE DONE: + +In short, a lot. + +UPDATE: +Currently, the control messages are working fine ("vendor commands"; for +reading and writing the OV511 registers.) The I2C bus commands for reading and +writing the camera (OV7610) registers are implemented and working, with at least +one person's camera. The isochronous-in endpoint for video data is finally +producing data, but since ov511_parse_data() is not implemented you will not see +a picture yet. + +Support for specific CCD's will have to be implemented as well (such as the +OV7610.) + +The rest of the work will involve implementing support for all the different +resolutions, color depths, etc. Also, while support for the OV511's proprietary +lossy compression is apparently not necessary (the code currently disables it,) +it would be a nice addition as it improves performance quite a bit. OmniVision +wouldn't tell me how the algorithm works, so we can't really work on that yet. +Please kindly inform OmniVision that you would like them to release their +specifications to the Linux community. + +HOW TO CONTACT ME: + +You can email me at mmcclelland@delphi.com . Please prefix the subject line +with "OV511: " so that I am certain to notice your message. + +CREDITS: + +The code is based in no small part on the CPiA driver by Johannes Erdfelt, +Randy Dunlap, and others. Big thanks to them for their pioneering work on that +and the USB stack. Thanks to Bret Wallach for getting camera reg IO and ISOC +working. diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c new file mode 100644 index 000000000000..44d7cfec4530 --- /dev/null +++ b/drivers/usb/evdev.c @@ -0,0 +1,275 @@ +/* + * evdev.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Event char devices, giving access to raw input device events. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#define EVDEV_MINOR_BASE 64 +#define EVDEV_BUFFER_SIZE 64 + +#include +#include +#include +#include +#include +#include + +struct evdev { + char name[32]; + int used; + struct input_handle handle; + struct miscdevice misc; + wait_queue_head_t wait; + struct evdev_list *list; +}; + +struct evdev_list { + struct input_event buffer[EVDEV_BUFFER_SIZE]; + int head; + int tail; + struct fasync_struct *fasync; + struct evdev *evdev; + struct evdev_list *next; +}; + +static unsigned long evdev_miscbits = 0; +static struct evdev *evdev_base[BITS_PER_LONG]; + +static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct evdev *evdev = handle->private; + struct evdev_list *list = evdev->list; + + while (list) { + + get_fast_time(&list->buffer[list->head].time); + list->buffer[list->head].type = type; + list->buffer[list->head].code = code; + list->buffer[list->head].value = value; + list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); + + if (list->fasync) + kill_fasync(list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&evdev->wait); +} + +static int evdev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct evdev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int evdev_release(struct inode * inode, struct file * file) +{ + struct evdev_list *list = file->private_data; + struct evdev_list **listptr = &list->evdev->list; + + evdev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->evdev->used) { + clear_bit(list->evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits); + misc_deregister(&list->evdev->misc); + kfree(list->evdev); + } + + kfree(list); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int evdev_open(struct inode * inode, struct file * file) +{ + struct evdev_list *list; + int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE; + + if (i > BITS_PER_LONG || !test_bit(i, &evdev_miscbits)) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) + return -ENOMEM; + + memset(list, 0, sizeof(struct evdev_list)); + + list->evdev = evdev_base[i]; + list->next = evdev_base[i]->list; + evdev_base[i]->list = list; + + file->private_data = list; + + list->evdev->used++; + + MOD_INC_USE_COUNT; + return 0; +} + +static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct evdev_list *list = file->private_data; + int retval = 0; + + if (list->head == list->tail) { + + add_wait_queue(&list->evdev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (list->head == list->tail) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->evdev->wait, &wait); + } + + if (retval) + return retval; + + while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { + if (copy_to_user(buffer + retval, list->buffer + list->tail, + sizeof(struct input_event))) return -EFAULT; + list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); + retval += sizeof(struct input_event); + } + + return retval; +} + +static unsigned int evdev_poll(struct file *file, poll_table *wait) +{ + struct evdev_list *list = file->private_data; + poll_wait(file, &list->evdev->wait, wait); + if (list->head != list->tail) + return POLLIN | POLLRDNORM; + return 0; +} + +static struct file_operations evdev_fops = { + read: evdev_read, + write: evdev_write, + poll: evdev_poll, + open: evdev_open, + release: evdev_release, + fasync: evdev_fasync, +}; + +static int evdev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct evdev *evdev; + + if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL))) + return -1; + + memset(evdev, 0, sizeof(struct evdev)); + + init_waitqueue_head(&evdev->wait); + + evdev->misc.minor = ffz(evdev_miscbits); + set_bit(evdev->misc.minor, &evdev_miscbits); + evdev_base[evdev->misc.minor] = evdev; + + sprintf(evdev->name, "evdev%d", evdev->misc.minor); + evdev->misc.name = evdev->name; + evdev->misc.minor += EVDEV_MINOR_BASE; + evdev->misc.fops = &evdev_fops; + + evdev->handle.dev = dev; + evdev->handle.handler = handler; + evdev->handle.private = evdev; + + evdev->used = 1; + + misc_register(&evdev->misc); + input_open_device(&evdev->handle); + + printk("%s: Event device for input%d on misc%d - /dev/input%d\n", + evdev->name, dev->number, evdev->misc.minor, evdev->misc.minor - EVDEV_MINOR_BASE); + + return 0; +} + +static void evdev_disconnect(struct input_handle *handle) +{ + struct evdev *evdev = handle->private; + + input_close_device(handle); + + if (!--evdev->used) { + clear_bit(evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits); + misc_deregister(&evdev->misc); + kfree(evdev); + } +} + +static struct input_handler evdev_handler = { + event: evdev_event, + connect: evdev_connect, + disconnect: evdev_disconnect, +}; + +#ifdef MODULE +int init_module(void) +#else +int __init evdev_init(void) +#endif +{ + input_register_handler(&evdev_handler); + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + input_unregister_handler(&evdev_handler); +} +#endif diff --git a/drivers/usb/hid-debug.h b/drivers/usb/hid-debug.h new file mode 100644 index 000000000000..a31c2910f660 --- /dev/null +++ b/drivers/usb/hid-debug.h @@ -0,0 +1,233 @@ +/* + * driver/usb/hid-debug.h + * + * (c) 1999 Andreas Gal + * (c) 1999 Vojtech Pavlik + * + * Some debug stuff for the HID parser. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +struct hid_usage_entry { + unsigned page; + unsigned usage; + char *description; +}; + +static struct hid_usage_entry hid_usage_table[] = { + { 1, 0, "GenericDesktop" }, + {0, 0x01, "Pointer"}, + {0, 0x02, "Mouse"}, + {0, 0x04, "Joystick"}, + {0, 0x05, "GamePad"}, + {0, 0x06, "Keyboard"}, + {0, 0x07, "Keypad"}, + {0, 0x08, "MultiAxis"}, + {0, 0x30, "X"}, + {0, 0x31, "Y"}, + {0, 0x32, "Z"}, + {0, 0x33, "Rx"}, + {0, 0x34, "Ry"}, + {0, 0x35, "Rz"}, + {0, 0x36, "Slider"}, + {0, 0x37, "Dial"}, + {0, 0x38, "Wheel"}, + {0, 0x39, "HatSwitch"}, + {0, 0x3a, "CountedBuffer"}, + {0, 0x3b, "ByteCount"}, + {0, 0x3c, "MotionWakeup"}, + {0, 0x3d, "Start"}, + {0, 0x3e, "Select"}, + {0, 0x40, "Vx"}, + {0, 0x41, "Vy"}, + {0, 0x42, "Vz"}, + {0, 0x43, "Vbrx"}, + {0, 0x44, "Vbry"}, + {0, 0x45, "Vbrz"}, + {0, 0x46, "Vno"}, + {0, 0x80, "SystemControl"}, + {0, 0x81, "System PowerDown"}, + {0, 0x82, "System Sleep"}, + {0, 0x83, "System WakeUp"}, + {0, 0x84, "System ContextMenu"}, + {0, 0x85, "System MainMenu"}, + {0, 0x86, "System AppMenu"}, + {0, 0x87, "System MenuHelp"}, + {0, 0x88, "System MenuExit"}, + {0, 0x89, "System MenuSelect"}, + {0, 0x8a, "System MenuRight"}, + {0, 0x8b, "System MenuLeft"}, + {0, 0x8c, "System MenuUp"}, + {0, 0x8d, "System MenuDown"}, + {0, 0x90, "D-padUp"}, + {0, 0x91, "D-padDown"}, + {0, 0x92, "D-padRight"}, + {0, 0x93, "D-padLeft"}, + { 7, 0, "Keyboard" }, + { 8, 0, "LED" }, + { 9, 0, "Button" }, + { 13, 0, "Digitizers" }, + {0, 0x01, "Digitizer"}, + {0, 0x02, "Pen"}, + {0, 0x03, "LightPen"}, + {0, 0x04, "TouchScreen"}, + {0, 0x05, "TouchPad"}, + {0, 0x20, "Stylus"}, + {0, 0x21, "Puck"}, + {0, 0x22, "Finger"}, + {0, 0x30, "TipPressure"}, + {0, 0x31, "BarrelPressure"}, + {0, 0x32, "InRange"}, + {0, 0x33, "Touch"}, + {0, 0x34, "UnTouch"}, + {0, 0x35, "Tap"}, + {0, 0x39, "TabletFunctionKey"}, + {0, 0x3a, "ProgramChangeKey"}, + {0, 0x42, "TipSwitch"}, + {0, 0x43, "SecondaryTipSwitch"}, + {0, 0x44, "BarrelSwitch"}, + {0, 0x45, "Eraser"}, + {0, 0x46, "TabletPick"}, + { 15, 0, "PhysicalInterfaceDevice" }, + { 0, 0, NULL } +}; + +static void resolv_usage_page(unsigned page) { + struct hid_usage_entry *p; + + for (p = hid_usage_table; p->description; p++) + if (p->page == page) { + printk("%s", p->description); + return; + } + printk("%04x", page); +} + +static void resolv_usage(unsigned usage) { + struct hid_usage_entry *p; + + resolv_usage_page(usage >> 16); + printk("."); + for (p = hid_usage_table; p->description; p++) + if (p->page == (usage >> 16)) { + for(++p; p->description && p->page == 0; p++) + if (p->usage == (usage & 0xffff)) { + printk("%s", p->description); + return; + } + break; + } + printk("%04x", usage & 0xffff); +} + +__inline__ static void tab(int n) { + while (n--) printk(" "); +} + +static void hid_dump_field(struct hid_field *field, int n) { + int j; + + if (field->physical) { + tab(n); + printk("Physical("); + resolv_usage(field->physical); printk(")\n"); + } + if (field->logical) { + tab(n); + printk("Logical("); + resolv_usage(field->logical); printk(")\n"); + } + tab(n); printk("Usage(%d)\n", field->maxusage); + for (j = 0; j < field->maxusage; j++) { + tab(n+2);resolv_usage(field->usage[j].hid); printk("\n"); + } + if (field->logical_minimum != field->logical_maximum) { + tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); + tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); + } + if (field->physical_minimum != field->physical_maximum) { + tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); + tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); + } + if (field->unit_exponent) { + tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); + } + if (field->unit) { + tab(n); printk("Unit(%u)\n", field->unit); + } + tab(n); printk("Report Size(%u)\n", field->report_size); + tab(n); printk("Report Count(%u)\n", field->report_count); + tab(n); printk("Report Offset(%u)\n", field->report_offset); + + tab(n); printk("Flags( "); + j = field->flags; + printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); + printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); + printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); + printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); + printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); + printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); + printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); + printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); + printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); + printk(")\n"); +} + +void hid_dump_device(struct hid_device *device) { + struct hid_report_enum *report_enum; + struct hid_report *report; + struct list_head *list; + unsigned i,k; + static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; + + printk("Application("); + resolv_usage(device->application); + printk(")\n"); + + for (i = 0; i < HID_REPORT_TYPES; i++) { + report_enum = device->report_enum + i; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; + tab(2); + printk("%s", table[i]); + if (report->id) + printk("(%d)", report->id); + printk("[%s]", table[report->type]); + printk("\n"); + for (k = 0; k < report->maxfield; k++) { + tab(4); + printk("Field(%d)\n", k); + hid_dump_field(report->field[k], 6); + } + list = list->next; + } + } +} + +void hid_dump_input(struct hid_usage *usage, __s32 value) { + printk("hidd: input "); + resolv_usage(usage->hid); + printk(" = %d\n", value); +} diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c new file mode 100644 index 000000000000..861c4424ba6a --- /dev/null +++ b/drivers/usb/hid.c @@ -0,0 +1,1203 @@ +/* + * hid.c Version 0.8 + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 1999 Vojtech Pavlik + * + * USB HID support for the Linux input drivers + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb.h" +#include "hid.h" + +#ifdef CONFIG_USB_HID_DEBUG_LOTS +#include "hid-debug.h" +#else +#define hid_dump_input(a,b) do { } while (0) +#define hid_dump_device(c) do { } while (0) +#endif + +static unsigned char hid_keyboard[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43,192, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, + 120,121,122,123,192,138,192,192,128,129,131,137,133,135,136,113, + 115,114,192,192,192,192,192,124,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 29, 42, 56,125, 97, 54,100,126 +}; + +static struct { + __s32 x; + __s32 y; +} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +/* + * Register a new report for a device. + */ + +static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) +{ + struct hid_report_enum *report_enum = device->report_enum + type; + struct hid_report *report; + + if (report_enum->report_id_hash[id]) + return report_enum->report_id_hash[id]; + + if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL))) + return NULL; + memset(report, 0, sizeof(struct hid_report)); + + if (id != 0) report_enum->numbered = 1; + + report->id = id; + report->type = type; + report->size = 0; + report->device = device; + report_enum->report_id_hash[id] = report; + + list_add_tail(&report->list, &report_enum->report_list); + + return report; +} + +/* + * Register a new field for this report. + */ + +static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) +{ + if (report->maxfield < HID_MAX_FIELDS) { + struct hid_field *field; + + if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + + values * sizeof(unsigned), GFP_KERNEL))) + return NULL; + memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + + values * sizeof(unsigned)); + + report->field[report->maxfield++] = field; + field->usage = (struct hid_usage *)(field + 1); + field->value = (unsigned *)(field->usage + usages); + field->report = report; + + return field; + } + + hid_debug("too many fields in report"); + return NULL; +} + +/* + * Open a collection. The type/usage is pushed on the stack. + */ + +static int open_collection(struct hid_parser *parser, unsigned type) +{ + unsigned usage; + + usage = parser->local.usage[0]; + + if (type == HID_COLLECTION_APPLICATION) + parser->device->application = usage; + + if (parser->collection_stack_ptr < HID_COLLECTION_STACK_SIZE) { /* PUSH on stack */ + struct hid_collection *collection = parser->collection_stack + parser->collection_stack_ptr++; + collection->type = type; + collection->usage = usage; + return 0; + } + + hid_debug("collection stack overflow"); + return -1; +} + +/* + * Close a collection. + */ + +static int close_collection(struct hid_parser *parser) +{ + if (parser->collection_stack_ptr > 0) { /* POP from stack */ + parser->collection_stack_ptr--; + return 0; + } + hid_debug("collection stack underflow"); + return -1; +} + +/* + * Climb up the stack, search for the specified collection type + * and return the usage. + */ + +static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) +{ + unsigned n; + for (n = parser->collection_stack_ptr; n; n--) + if (parser->collection_stack[n].type == type) + return parser->collection_stack[n].usage; + return 0; /* we know nothing about this usage type */ +} + +/* + * Add a usage to the temporary parser table. + */ + +static int hid_add_usage(struct hid_parser *parser, unsigned usage) +{ + if (parser->local.usage_index >= MAX_USAGES) { + hid_debug("usage index exceeded"); + return -1; + } + parser->local.usage[parser->local.usage_index++] = usage; + return 0; +} + +/* + * Register a new field for this report. + */ + +static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) +{ + struct hid_report *report; + struct hid_field *field; + int usages; + unsigned offset; + int i; + + if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { + hid_debug("hid_register_report failed"); + return -1; + } + + if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */ + if (parser->global.logical_maximum <= parser->global.logical_minimum) { + hid_debug("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); + return -1; + } + usages = parser->local.usage_index; + /* Hint: we can assume usages < MAX_USAGE here */ + } else { /* VARIABLE */ + usages = parser->global.report_count; + } + offset = report->size; + report->size += parser->global.report_size * + parser->global.report_count; + if (usages == 0) + return 0; /* ignore padding fields */ + if ((field = hid_register_field(report, usages, + parser->global.report_count)) == NULL) + return 0; + field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); + field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); + for (i = 0; i < usages; i++) field->usage[i].hid = parser->local.usage[i]; + field->maxusage = usages; + field->flags = flags; + field->report_offset = offset; + field->report_type = report_type; + field->report_size = parser->global.report_size; + field->report_count = parser->global.report_count; + field->logical_minimum = parser->global.logical_minimum; + field->logical_maximum = parser->global.logical_maximum; + field->physical_minimum = parser->global.physical_minimum; + field->physical_maximum = parser->global.physical_maximum; + field->unit_exponent = parser->global.unit_exponent; + field->unit = parser->global.unit; + return 0; +} + +/* + * Read data value from item. + */ + +static __inline__ __u32 item_udata(struct hid_item *item) +{ + switch (item->size) { + case 1: return item->data.u8; + case 2: return item->data.u16; + case 4: return item->data.u32; + } + return 0; +} + +static __inline__ __s32 item_sdata(struct hid_item *item) +{ + switch (item->size) { + case 1: return item->data.s8; + case 2: return item->data.s16; + case 4: return item->data.s32; + } + return 0; +} + +/* + * Process a global item. + */ + +static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) +{ + switch (item->tag) { + + case HID_GLOBAL_ITEM_TAG_PUSH: + + if (parser->global_stack_ptr < HID_GLOBAL_STACK_SIZE) { + memcpy(parser->global_stack + parser->global_stack_ptr++, + &parser->global, sizeof(struct hid_parser)); + return 0; + } + hid_debug("global enviroment stack overflow"); + return -1; + + case HID_GLOBAL_ITEM_TAG_POP: + + if (parser->global_stack_ptr > 0) { + memcpy(&parser->global, parser->global_stack + parser->global_stack_ptr--, + sizeof(struct hid_parser)); + return 0; + } + hid_debug("global enviroment stack underflow"); + return -1; + + case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: + parser->global.usage_page = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: + parser->global.logical_minimum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: + parser->global.logical_maximum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: + parser->global.physical_minimum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: + parser->global.physical_maximum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: + parser->global.unit_exponent = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_UNIT: + parser->global.unit = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: + if ((parser->global.report_size = item_udata(item)) > 32) { + hid_debug("invalid report_size %d", parser->global.report_size); + return -1; + } + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: + if ((parser->global.report_count = item_udata(item)) > MAX_USAGES) { + hid_debug("invalid report_count %d", parser->global.report_count); + return -1; + } + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_ID: + if ((parser->global.report_id = item_udata(item)) == 0) { + hid_debug("report_id 0 is invalid"); + return -1; + } + return 0; + + default: + hid_debug("unknown global tag 0x%x", item->tag); + return -1; + } +} + +/* + * Process a local item. + */ + +static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) +{ + __u32 data; + + if (item->size == 0) { + hid_debug("item data expected for local item"); + return -1; + } + + data = item_udata(item); + + switch (item->tag) { + + case HID_LOCAL_ITEM_TAG_DELIMITER: + + if (data) { + /* + * We treat items before the first delimiter + * as global to all usage sets (branch 0). + * In the moment we process only these global + * items and the first delimiter set. + */ + if (parser->local.delimiter_depth != 0) { + hid_debug("nested delimiters"); + return -1; + } + parser->local.delimiter_depth++; + parser->local.delimiter_branch++; + } else { + if (parser->local.delimiter_depth < 1) { + hid_debug("bogus close delimiter"); + return -1; + } + parser->local.delimiter_depth--; + } + return 1; + + case HID_LOCAL_ITEM_TAG_USAGE: + + if (parser->local.delimiter_branch < 2) { + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + return hid_add_usage(parser, data); + } + hid_debug("alternative usage ignored"); + return 0; + + case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: + + if (parser->local.delimiter_branch < 2) { + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + parser->local.usage_minimum = data; + return 0; + } + hid_debug("alternative usage ignored"); + return 0; + + case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: + + if (parser->local.delimiter_branch < 2) { + unsigned n; + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + for (n = parser->local.usage_minimum; n <= data; n++) + if (hid_add_usage(parser, n)) { + hid_debug("hid_add_usage failed\n"); + return -1; + } + return 0; + } + hid_debug("alternative usage ignored"); + return 0; + + default: + + hid_debug("unknown local item tag 0x%x", item->tag); + return 0; + } +} + +/* + * Process a main item. + */ + +static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) +{ + __u32 data; + int ret; + + data = item_udata(item); + + switch (item->tag) { + case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: + ret = open_collection(parser, data & 3); + break; + case HID_MAIN_ITEM_TAG_END_COLLECTION: + ret = close_collection(parser); + break; + case HID_MAIN_ITEM_TAG_INPUT: + ret = hid_add_field(parser, HID_INPUT_REPORT, data); + break; + case HID_MAIN_ITEM_TAG_OUTPUT: + ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); + break; + case HID_MAIN_ITEM_TAG_FEATURE: + ret = hid_add_field(parser, HID_FEATURE_REPORT, data); + break; + default: + hid_debug("unknown main item tag 0x%x", item->tag); + ret = 0; + } + + memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ + + return ret; +} + +/* + * Process a reserved item. + */ + +static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) +{ + hid_debug("reserved item type, tag 0x%x", item->tag); + return 0; +} + +/* + * Free a report and all registered fields. The field->usage and + * field->value table's are allocated behind the field, so we need + * only to free(field) itself. + */ + +static void hid_free_report(struct hid_report *report) +{ + unsigned n; + + for (n = 0; n < report->maxfield; n++) + kfree(report->field[n]); + kfree(report); +} + +/* + * Free a device structure, all reports, and all fields. + */ + +static void hid_free_device(struct hid_device *device) +{ + unsigned i,j; + + for (i = 0; i < HID_REPORT_TYPES; i++) { + struct hid_report_enum *report_enum = device->report_enum + i; + + for (j = 0; j < 256; j++) { + struct hid_report *report = report_enum->report_id_hash[j]; + if (report) hid_free_report(report); + } + } + + if (device->rdesc) kfree(device->rdesc); +} + +/* + * Fetch a report description item from the data stream. We support long + * items, though they are not used yet. + */ + +static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) +{ + if ((end - start) > 0) { + + __u8 b = *start++; + item->type = (b >> 2) & 3; + item->tag = (b >> 4) & 15; + + if (item->tag == HID_ITEM_TAG_LONG) { + + item->format = HID_ITEM_FORMAT_LONG; + + if ((end - start) >= 2) { + + item->size = *start++; + item->tag = *start++; + + if ((end - start) >= item->size) { + item->data.longdata = start; + start += item->size; + return start; + } + } + } else { + + item->format = HID_ITEM_FORMAT_SHORT; + item->size = b & 3; + switch (item->size) { + + case 0: + return start; + + case 1: + if ((end - start) >= 1) { + item->data.u8 = *start++; + return start; + } + break; + + case 2: + if ((end - start) >= 2) { + item->data.u16 = le16_to_cpu( *((__u16*)start)++); + return start; + } + + case 3: + item->size++; + if ((end - start) >= 4) { + item->data.u32 = le32_to_cpu( *((__u32*)start)++); + return start; + } + } + } + } + return NULL; +} + +/* + * Parse a report description into a hid_device structure. Reports are + * enumerated, fields are attached to these reports. + */ + +static struct hid_device *hid_parse_report(__u8 *start, unsigned size) +{ + struct hid_device *device; + struct hid_parser *parser; + struct hid_item item; + __u8 *end; + unsigned i; + static int (*dispatch_type[])(struct hid_parser *parser, + struct hid_item *item) = { + hid_parser_main, + hid_parser_global, + hid_parser_local, + hid_parser_reserved + }; + + if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL))) + return NULL; + memset(device, 0, sizeof(struct hid_device)); + + for (i = 0; i < HID_REPORT_TYPES; i++) + INIT_LIST_HEAD(&device->report_enum[i].report_list); + + if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { + kfree(device); + return NULL; + } + memcpy(device->rdesc, start, size); + + if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) { + kfree(device->rdesc); + kfree(device); + return NULL; + } + memset(parser, 0, sizeof(struct hid_parser)); + parser->device = device; + + end = start + size; + while ((start = fetch_item(start, end, &item)) != 0) { + if (item.format != HID_ITEM_FORMAT_SHORT) { + hid_debug("unexpected long global item"); + hid_free_device(device); + kfree(parser); + return NULL; + } + if (dispatch_type[item.type](parser, &item)) { + hid_debug("item %u %u %u %u parsing failed\n", + item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); + hid_free_device(device); + kfree(parser); + return NULL; + } + + if (start == end) { + if (parser->collection_stack_ptr) { + hid_debug("unbalanced collection at end of report description"); + hid_free_device(device); + kfree(parser); + return NULL; + } + if (parser->local.delimiter_depth) { + hid_debug("unbalanced delimiter at end of report description"); + hid_free_device(device); + kfree(parser); + return NULL; + } + kfree(parser); + return device; + } + } + + hid_debug("item fetching failed at offset %d\n", (int)(end - start)); + hid_free_device(device); + kfree(parser); + return NULL; +} + +/* + * Convert a signed n-bit integer to signed 32-bit integer. Common + * cases are done through the compiler, the screwed things has to be + * done by hand. + */ + +static __inline__ __s32 snto32(__u32 value, unsigned n) +{ + switch (n) { + case 8: return ((__s8)value); + case 16: return ((__s16)value); + case 32: return ((__s32)value); + } + return value & (1 << (n - 1)) ? value | (-1 << n) : value; +} + +/* + * Convert a signed 32-bit integer to a signed n-bit integer. + */ + +static __inline__ __u32 s32ton(__s32 value, unsigned n) +{ + __s32 a = value >> (n - 1); + if (a && a != -1) return value > 0 ? 1 << (n - 1) : (1 << n) - 1; + return value & ((1 << n) - 1); +} + +/* + * Extract/implement a data field from/to a report. We use 64-bit unsigned, + * 32-bit aligned, so that we can possibly have alignment problems on some + * odd architectures. + */ + +static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) +{ + report += (offset >> 5) << 2; offset &= 31; + return (le64_to_cpu(*(__u64*)report) >> offset) & ((1 << n) - 1); +} + +static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) +{ + report += (offset >> 5) << 2; offset &= 31; + *(__u64*)report &= cpu_to_le64(~((1ULL << n) - 1) << offset); + *(__u64*)report |= cpu_to_le64((__u64)value << offset); +} + +static void hid_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage) +{ + struct input_dev *input = &device->input; + int max; + unsigned long *bit; + + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_KEYBOARD: + + if ((usage->hid & HID_USAGE) < 256) { + if (!(usage->code = hid_keyboard[usage->hid & HID_USAGE])) + return; + } else + usage->code = KEY_UNKNOWN; + + set_bit(EV_REP, input->evbit); + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; + break; + + case HID_UP_BUTTON: + + usage->code = ((usage->hid - 1) & 0xf) + 0x100; + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; + + switch (device->application) { + case HID_GD_GAMEPAD: usage->code += 0x10; + case HID_GD_JOYSTICK: usage->code += 0x10; + case HID_GD_MOUSE: usage->code += 0x10; + } + break; + + case HID_UP_GENDESK: + + usage->code = usage->hid & 0xf; + + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + usage->type = EV_REL; bit = input->relbit; max = REL_MAX; + break; + } + + usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; + + if (usage->hid == HID_GD_HATSWITCH) { + usage->code = ABS_HAT0X; + usage->hat = 1 + (field->logical_maximum == 4); + } + break; + + default: + + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + usage->code = REL_MISC; + usage->type = EV_REL; bit = input->relbit; max = REL_MAX; + break; + } + + if (field->logical_minimum == 0 && field->logical_maximum == 1) { + usage->code = BTN_MISC; + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; + break; + } + + usage->code = ABS_MISC; + usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; + break; + } + + set_bit(usage->type, input->evbit); + + while (usage->code <= max && test_and_set_bit(usage->code, bit)) { + usage->code = find_next_zero_bit(bit, max + 1, usage->code); + } + + if (usage->type == EV_ABS) { + int a = field->logical_minimum; + int b = field->logical_maximum; + + input->absmin[usage->code] = a; + input->absmax[usage->code] = b; + input->absfuzz[usage->code] = (b - a) >> 8; + input->absflat[usage->code] = (b - a) >> 4; + } + + if (usage->hat) { + int i; + for (i = usage->code; i < usage->code + 2; i++) { + input->absmax[i] = 1; + input->absmin[i] = -1; + input->absfuzz[i] = 0; + input->absflat[i] = 0; + } + set_bit(usage->code + 1, input->absbit); + } +} + +static void hid_process_event(struct input_dev *input, struct hid_usage *usage, __s32 value) +{ + hid_dump_input(usage, value); + + if (usage->hat) { + if (usage->hat == 2) value = value * 2 - 1; + input_event(input, usage->type, usage->code , hid_hat_to_axis[value].x); + input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y); + return; + } + + input_event(input, usage->type, usage->code, value); +} + +/* + * Search an array for a value. + */ + +static __inline__ int search(__s32 *array, __s32 value, unsigned n) +{ + while (n--) if (*array++ == value) return 0; + return -1; +} + +/* + * Analyse a received field, and fetch the data from it. The field + * content is stored for next report processing (we do differential + * reporting to the layer). + */ + +static void hid_input_field(struct hid_device *dev, struct hid_field *field, __u8 *data) +{ + unsigned n; + unsigned count = field->report_count; + unsigned offset = field->report_offset; + unsigned size = field->report_size; + __s32 min = field->logical_minimum; + __s32 max = field->logical_maximum; + __s32 value[count]; /* WARNING: gcc specific */ + + for (n = 0; n < count; n++) + value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : + extract(data, offset + n * size, size); + + for (n = 0; n < count; n++) { + + if (HID_MAIN_ITEM_VARIABLE & field->flags) { + + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + if (!value[n]) continue; + } else { + if (value[n] == field->value[n]) continue; + } + hid_process_event(&dev->input, &field->usage[n], value[n]); + + } else { + + if (field->value[n] >= min && field->value[n] <= max /* non-NULL value */ + && field->usage[field->value[n] - min].hid /* nonzero usage */ + && search(value, field->value[n], count)) + hid_process_event(&dev->input, &field->usage[field->value[n] - min], 0); + + if (value[n] >= min && value[n] <= max /* non-NULL value */ + && field->usage[value[n] - min].hid /* nonzero usage */ + && search(field->value, value[n], count)) + hid_process_event(&dev->input, &field->usage[value[n] - min], 1); + } + } + + memcpy(field->value, value, count * sizeof(__s32)); +} + +/* + * Interrupt input handler - analyse a received report. + */ + +static void hid_irq(struct urb *urb) +{ + struct hid_device *device = urb->context; + struct hid_report_enum *report_enum = device->report_enum + HID_INPUT_REPORT; + struct hid_report *report; + __u8 *data = urb->transfer_buffer; + int len = urb->actual_length; + int n; + + if (urb->status) { + hid_debug("nonzero status in irq %d", urb->status); + return; + } + + if (!len) { + hid_debug("empty report"); + return; + } + +#ifdef CONFIG_USB_HID_DEBUG_LOTS + printk(KERN_DEBUG "hid: report (size %u) (%snumbered) = ", len, report_enum->numbered ? "" : "un"); + for (n = 0; n < len; n++) + printk(" %02x", data[n]); + printk("\n"); +#endif + + n = 0; /* Normally report number is 0 */ + + if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ + n = *data++; + len--; + } + + if (!(report = report_enum->report_id_hash[n])) { + hid_debug("undefined report_id %d received", n); +#ifdef CONFIG_USB_HID_DEBUG + printk(KERN_DEBUG "hid: report (size %u) = ", len); + for (n = 0; n < len; n++) + printk(" %02x", data[n]); + printk("\n"); +#endif + + return; + } + + if (len < ((report->size - 1) >> 3) + 1) { + hid_debug("report %d is too short, (%d < %d)", report->id, len, ((report->size - 1) >> 3) + 1); + return; + } + + for (n = 0; n < report->maxfield; n++) + hid_input_field(device, report->field[n], data); + + return; +} + +/* + * Configure the input layer interface + * Read all reports and initalize the absoulte field values. + */ + +static void hid_init_input(struct hid_device *hid) +{ + struct hid_report_enum *report_enum = hid->report_enum + HID_INPUT_REPORT; + struct list_head *list; + int i, j; + + list = report_enum->report_list.next; + + while (list != &report_enum->report_list) { + + struct hid_report *report = (struct hid_report *) list; + int rlen = ((report->size - 1) >> 3) + 1 + report_enum->numbered; + int read; + + list = list->next; + + for (i = 0; i < report->maxfield; i++) + for (j = 0; j < report->field[i]->maxusage; j++) + hid_configure_usage(hid, report->field[i], report->field[i]->usage + j); + +#if 1 + { + char rdata[rlen]; + struct urb urb = { + transfer_buffer: rdata, + actual_length: rlen, + context: hid + }; + + memset(rdata, 0, rlen); + hid_debug("getting report type %d id %d len %d", report->type + 1, report->id, rlen); + + if ((read = usb_get_report(hid->dev, report->type + 1, report->id, hid->ifnum, rdata, rlen)) != rlen) { + hid_debug("reading report failed rlen %d read %d", rlen, read); +#ifdef CONFIG_USB_HID_DEBUG + printk(KERN_DEBUG "hid: report = "); + for (j = 0; j < rlen; j++) printk(" %02x", rdata[j]); + printk("\n"); +#endif + continue; + } + + hid_irq(&urb); + } +#endif + } +} + +/* + * Output the field into the report. + */ + +static void hid_output_field(struct hid_field *field, __u8 *data) +{ + unsigned count = field->report_count; + unsigned offset = field->report_offset; + unsigned size = field->report_size; + unsigned n; + + for (n = 0; n < count; n++) { + if (field->logical_minimum < 0) /* signed values */ + implement(data, offset + n * size, size, s32ton(field->value[n], size)); + else /* unsigned values */ + implement(data, offset + n * size, size, field->value[n]); + } +} + +/* + * Create a report. + */ + +void hid_output_report(struct hid_report *report, __u8 *data) +{ + unsigned n; + + /* skip the ID if we have a single report */ + if (report->device->report_enum[report->type].numbered) + *data++ = report->id; + + for (n = 0; n < report->maxfield; n++) + hid_output_field(report->field[n], data); +}; + +/* + * Set a field value. The report this field belongs to has to be + * created and transfered to the device, to set this value in the + * device. + */ + +int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) +{ + unsigned size = field->report_size; + + if (offset >= field->report_count) { + hid_debug("offset exceeds report_count"); + return -1; + } + if (field->logical_minimum < 0) { + if (value != snto32(s32ton(value, size), size)) { + hid_debug("value %d is out of range", value); + return -1; + } + } + if ( (value > field->logical_maximum) + || (value < field->logical_minimum)) { + hid_debug("value %d is invalid", value); + return -1; + } + field->value[offset] = value; + return 0; +} + +static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) +{ + struct usb_interface_descriptor *interface = &dev->actconfig->interface[ifnum].altsetting[0]; + struct usb_hid_descriptor *hdesc; + struct hid_device *hid; + unsigned rsize = 0; + int n; + + if (interface->bInterfaceClass != USB_INTERFACE_CLASS_HID) + return NULL; + + if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc) + && usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc)) { + hid_debug("class descriptor not present\n"); + return NULL; + } + + for (n = 0; n < hdesc->bNumDescriptors; n++) + if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT) + rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); + + if (!rsize || rsize > 1024) { + hid_debug("weird size of report descriptor (%u)", rsize); + return NULL; + } + + { + __u8 rdesc[rsize]; + + if ((n = usb_get_class_descriptor(dev, USB_DT_REPORT, 0, ifnum, rdesc, rsize)) < 0) { + hid_debug("reading report descriptor failed"); + return NULL; + } + +#ifdef CONFIG_USB_HID_DEBUG + printk(KERN_DEBUG "hid: report (size %u, read %d) = ", rsize, n); + for (n = 0; n < rsize; n++) + printk(" %02x", (unsigned) rdesc[n]); + printk("\n"); +#endif + + if (!(hid = hid_parse_report(rdesc, rsize))) { + hid_debug("parsing report descriptor failed"); + return NULL; + } + } + + for (n = 0; n < interface->bNumEndpoints; n++) { + + struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; + int pipe, maxp; + + if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ + continue; + + if (!(endpoint->bEndpointAddress & 0x80)) /* Not an input endpoint */ + continue; + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval); + + if (usb_submit_urb(&hid->urb)) { + hid_debug("submitting interrupt URB failed"); + continue; + } + + break; + } + + if (n == interface->bNumEndpoints) { + hid_debug("couldn't find an input interrupt endpoint"); + hid_free_device(hid); + return NULL; + } + + hid->version = hdesc->bcdHID; + hid->country = hdesc->bCountryCode; + hid->dev = dev; + hid->ifnum = ifnum; + + return hid; +} + +static void* hid_probe(struct usb_device *dev, unsigned int ifnum) +{ + char *hid_name[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", + "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; + struct hid_device *hid; + + hid_debug("HID probe called for ifnum %d", ifnum); + + if (!(hid = usb_hid_configure(dev, ifnum))) + return NULL; + + hid_dump_device(hid); + + hid_init_input(hid); + input_register_device(&hid->input); + + printk(KERN_INFO "input%d: USB HID v%d.%d %s\n", + hid->input.number, hid->version >> 8, hid->version & 0xff, + (hid->application & 0xffff) <= 8 ? hid_name[hid->application & 0xffff] : "device"); + + return hid; +} + +static void hid_disconnect(struct usb_device *dev, void *ptr) +{ + struct hid_device *hid = ptr; + + hid_debug("cleanup called"); + usb_unlink_urb(&hid->urb); + input_unregister_device(&hid->input); + hid_free_device(hid); +} + +static struct usb_driver hid_driver = { + name: "hid", + probe: hid_probe, + disconnect: hid_disconnect +}; + +#ifdef MODULE +int init_module(void) +#else +int hid_init(void) +#endif +{ + usb_register(&hid_driver); + return 0; +} + +#ifdef MODULE +void module_cleanup(void) +#else +void hid_cleanup(void) +#endif +{ + usb_deregister(&hid_driver); +} diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h new file mode 100644 index 000000000000..8ccdb67bd0dd --- /dev/null +++ b/drivers/usb/hid.h @@ -0,0 +1,345 @@ +#ifndef __HID_H +#define __HID_H + +/* + * drivers/usb/hid.h Version 0.8 + * + * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999 Andreas Gal + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include + +/* + * Enable/Disable debug information. + */ + +#ifdef CONFIG_USB_HID_DEBUG +#define hid_debug(fmt,arg...) printk(KERN_DEBUG "hid: " fmt "\n" , ##arg) +#else +#define hid_debug(fmt,arg...) do { } while (0) +#endif + +/* + * USB HID (Human Interface Device) interface class code + */ + +#define USB_INTERFACE_CLASS_HID 3 + +/* + * USB interface subclass codes. + */ + +#define USB_INTERFACE_SUBCLASS_NONE 0 +#define USB_INTERFACE_SUBCLASS_HID_BP 1 + +/* + * HID protocol codes (only for boot protocol) + */ + +#define HID_PROTOCOL_NONE 0 +#define HID_PROTOCOL_KBD 1 +#define HID_PROTOCOL_MOUSE 2 + +/* + * We parse each description item into this structure. Short items data + * values are expanded to 32-bit signed int, long items contain a pointer + * into the data area. + */ + +struct hid_item { + unsigned format; + __u8 size; + __u8 type; + __u8 tag; + union { + __u8 u8; + __s8 s8; + __u16 u16; + __s16 s16; + __u32 u32; + __s32 s32; + __u8 *longdata; + } data; +}; + +/* + * HID report item format + */ + +#define HID_ITEM_FORMAT_SHORT 0 +#define HID_ITEM_FORMAT_LONG 1 + +/* + * Special tag indicating long items + */ + +#define HID_ITEM_TAG_LONG 15 + +/* + * HID report descriptor item type (prefix bit 2,3) + */ + +#define HID_ITEM_TYPE_MAIN 0 +#define HID_ITEM_TYPE_GLOBAL 1 +#define HID_ITEM_TYPE_LOCAL 2 +#define HID_ITEM_TYPE_RESERVED 3 + +/* + * HID report descriptor main item tags + */ + +#define HID_MAIN_ITEM_TAG_INPUT 8 +#define HID_MAIN_ITEM_TAG_OUTPUT 9 +#define HID_MAIN_ITEM_TAG_FEATURE 11 +#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 +#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 + +/* + * HID report descriptor main item contents + * Warning: VOLATILE is not available for TAG_INPUT + */ + +#define HID_MAIN_ITEM_CONSTANT 0x001 +#define HID_MAIN_ITEM_VARIABLE 0x002 +#define HID_MAIN_ITEM_RELATIVE 0x004 +#define HID_MAIN_ITEM_WRAP 0x008 +#define HID_MAIN_ITEM_NONLINEAR 0x010 +#define HID_MAIN_ITEM_NO_PREFERRED 0x020 +#define HID_MAIN_ITEM_NULL_STATE 0x040 +#define HID_MAIN_ITEM_VOLATILE 0x080 +#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 + +/* + * HID report descriptor collection item types + */ + +#define HID_COLLECTION_PHYSICAL 0 +#define HID_COLLECTION_APPLICATION 1 +#define HID_COLLECTION_LOGICAL 2 + +/* + * HID report descriptor global item tags + */ + +#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 +#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 +#define HID_GLOBAL_ITEM_TAG_UNIT 6 +#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 +#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 +#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 +#define HID_GLOBAL_ITEM_TAG_PUSH 10 +#define HID_GLOBAL_ITEM_TAG_POP 11 + +/* + * HID report descriptor local item tags + */ + +#define HID_LOCAL_ITEM_TAG_USAGE 0 +#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 +#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 +#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 +#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 +#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 +#define HID_LOCAL_ITEM_TAG_DELIMITER 10 + +/* + * HID usage tables + */ + +#define HID_USAGE_PAGE 0xffff0000 + +#define HID_UP_GENDESK 0x00010000 +#define HID_UP_KEYBOARD 0x00070000 +#define HID_UP_LED 0x00080000 +#define HID_UP_BUTTON 0x00090000 +#define HID_UP_DIGITIZER 0x000d0000 +#define HID_UP_PID 0x000f0000 + +#define HID_USAGE 0x0000ffff + +#define HID_GD_MOUSE 0x00010002 +#define HID_GD_JOYSTICK 0x00010004 +#define HID_GD_GAMEPAD 0x00010005 +#define HID_GD_HATSWITCH 0x00010039 + +/* + * HID interface requests (this belongs here, the USB_REQ_xxx stuff should + * disapear). + */ + +#define HID_REQ_GET_REPORT 0x01 +#define HID_REQ_GET_IDLE 0x02 +#define HID_REQ_GET_PROTOCOL 0x03 +#define HID_REQ_SET_REPORT 0x09 +#define HID_REQ_SET_IDLE 0x0A +#define HID_REQ_SET_PROTOCOL 0x0B + +/* + * HID report types --- Ouch! HID spec says 1 2 3! + */ + +#define HID_INPUT_REPORT 0 +#define HID_OUTPUT_REPORT 1 +#define HID_FEATURE_REPORT 2 + +/* + * HID protocols + */ + +#define HID_PROTOCOL_BOOT 0 +#define HID_PROTOCOL_REPORT 1 + +/* + * This is the global enviroment of the parser. This information is + * persistent for main-items. The global enviroment can be saved and + * restored with PUSH/POP statements. + */ + +struct hid_global { + unsigned usage_page; + __s32 logical_minimum; + __s32 logical_maximum; + __s32 physical_minimum; + __s32 physical_maximum; + unsigned unit_exponent; + unsigned unit; + unsigned report_id; + unsigned report_size; + unsigned report_count; +}; + +/* + * This is the local enviroment. It is resistent up the the next main-item. + */ + +#define MAX_USAGES 256 + +struct hid_local { + unsigned usage[MAX_USAGES]; /* usage array */ + unsigned usage_index; + unsigned usage_minimum; + unsigned delimiter_depth; + unsigned delimiter_branch; +}; + +/* + * This is the collection stack. We climb up the stack to determine + * application and function of each field. + */ + +struct hid_collection { + unsigned type; + unsigned usage; +}; + +struct hid_usage { + unsigned hid; /* hid usage code */ + __u16 code; /* input driver code */ + __u8 type; /* input driver type */ + __u8 hat; /* hat switch fun */ +}; + +struct hid_field { + unsigned physical; /* physical usage for this field */ + unsigned logical; /* logical usage for this field */ + struct hid_usage *usage; /* usage table for this function */ + unsigned maxusage; /* maximum usage index */ + unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ + unsigned report_offset; /* bit offset in the report */ + unsigned report_size; /* size of this field in the report */ + unsigned report_count; /* number of this field in the report */ + unsigned report_type; /* (input,output,feature) */ + __s32 *value; /* last known value(s) */ + __s32 logical_minimum; + __s32 logical_maximum; + __s32 physical_minimum; + __s32 physical_maximum; + unsigned unit_exponent; + unsigned unit; + struct hid_report *report; /* associated report */ +}; + +#define HID_MAX_FIELDS 64 + +struct hid_report { + struct list_head list; + unsigned id; /* id of this report */ + unsigned type; /* report type */ + struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ + unsigned maxfield; /* maximum valid field index */ + unsigned size; /* size of the report (bits) */ + struct hid_device *device; /* associated device */ +}; + +struct hid_report_enum { + unsigned numbered; + struct list_head report_list; + struct hid_report *report_id_hash[256]; +}; + +#define HID_REPORT_TYPES 3 + +struct hid_device { /* device report descriptor */ + __u8 *rdesc; + unsigned rsize; + unsigned application; /* HID application, i.e. Digitizer */ + unsigned version; /* HID version */ + unsigned country; /* HID country */ + struct hid_report_enum report_enum[HID_REPORT_TYPES]; + + struct usb_device *dev; /* USB device */ + int ifnum; /* USB interface number */ + + char buffer[32]; /* Receive buffer */ + struct urb urb; /* USB URB structure */ + struct input_dev input; /* input device structure */ +}; + +#define HID_GLOBAL_STACK_SIZE 4 +#define HID_COLLECTION_STACK_SIZE 4 + +struct hid_parser { + struct hid_global global; + struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; + unsigned global_stack_ptr; + struct hid_local local; + struct hid_collection collection_stack[HID_COLLECTION_STACK_SIZE]; + unsigned collection_stack_ptr; + struct hid_device *device; +}; + +#endif + diff --git a/drivers/usb/inits.h b/drivers/usb/inits.h index 151ecf901a62..5e7eff546f67 100644 --- a/drivers/usb/inits.h +++ b/drivers/usb/inits.h @@ -3,16 +3,14 @@ void usb_acm_cleanup(void); int usb_audio_init(void); int usb_cpia_init(void); void usb_cpia_cleanup(void); +int usb_ov511_init(void); +void usb_ov511_cleanup(void); int usb_dc2xx_init(void); void usb_dc2xx_cleanup(void); int usb_hub_init(void); void usb_hub_cleanup(void); -int usb_kbd_init(void); -void usb_kbd_cleanup(void); void usb_major_init(void); void usb_major_cleanup(void); -int usb_mouse_init(void); -void usb_mouse_cleanup(void); int usb_scanner_init(void); void usb_scanner_cleanup(void); int usb_printer_init(void); @@ -22,3 +20,7 @@ int dabusb_init(void); void dabusb_cleanup(void); int proc_usb_init(void); void proc_usb_cleanup(void); +int hid_init(void); +int input_init(void); +int usb_mouse_init(void); +int usb_kbd_init(void); diff --git a/drivers/usb/input.c b/drivers/usb/input.c new file mode 100644 index 000000000000..fa370c9af8af --- /dev/null +++ b/drivers/usb/input.c @@ -0,0 +1,335 @@ +/* + * input.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * The input layer module itself + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); + +#ifndef MODULE +EXPORT_SYMBOL(input_register_device); +EXPORT_SYMBOL(input_unregister_device); +EXPORT_SYMBOL(input_register_handler); +EXPORT_SYMBOL(input_unregister_handler); +EXPORT_SYMBOL(input_open_device); +EXPORT_SYMBOL(input_close_device); +EXPORT_SYMBOL(input_event); +#endif + +static struct input_dev *input_dev = NULL; +static struct input_handler *input_handler = NULL; + +static int input_number = 0; + +void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct input_handle *handle = dev->handle; + +/* + * Filter non-events, and bad input values out. + */ + + if (type > EV_MAX || !test_bit(type, dev->evbit)) + return; + + switch (type) { + + case EV_KEY: + + if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value) + return; + + if (value == 2) break; + + change_bit(code, dev->key); + + if (test_bit(EV_REP, dev->evbit) && dev->timer.function) { + if (value) { + mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]); + dev->repeat_key = code; + break; + } + if (dev->repeat_key == code) + del_timer(&dev->timer); + } + + break; + + case EV_ABS: + + if (code > ABS_MAX || !test_bit(code, dev->absbit) || (value == dev->abs[code])) + return; + + dev->abs[code] = value; + + break; + + case EV_REL: + + if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0)) + return; + + break; + + case EV_LED: + + if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value) + return; + + change_bit(code, dev->led); + if (dev->event) dev->event(dev, type, code, value); + + break; + + case EV_SND: + + if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value) + return; + + change_bit(code, dev->snd); + if (dev->event) dev->event(dev, type, code, value); + + break; + + case EV_REP: + + if (code > REP_MAX || dev->rep[code] == value) return; + + dev->rep[code] = value; + if (dev->event) dev->event(dev, type, code, value); + + break; + } +/* + * Add randomness. + */ + +#if 0 /* BUG */ + add_input_randomness(((unsigned long) dev) ^ (type << 24) ^ (code << 16) ^ value); +#endif + +/* + * Distribute the event to handler modules. + */ + + while (handle) { + handle->handler->event(handle, type, code, value); + handle = handle->dnext; + } +} + +static void input_repeat_key(unsigned long data) +{ + struct input_dev *dev = (void *) data; + input_event(dev, EV_KEY, dev->repeat_key, 2); + mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]); +} + +void input_register_device(struct input_dev *dev) +{ + struct input_handler *handler = input_handler; + +/* + * Initialize repeat timer to default values. + */ + + init_timer(&dev->timer); + dev->timer.data = (long) dev; + dev->timer.function = input_repeat_key; + dev->rep[REP_DELAY] = HZ/4; + dev->rep[REP_PERIOD] = HZ/33; + +/* + * Add the device. + */ + + MOD_INC_USE_COUNT; + dev->number = input_number++; + dev->next = input_dev; + input_dev = dev; + +/* + * Notify handlers. + */ + + while (handler) { + handler->connect(handler, dev); + handler = handler->next; + } +} + +void input_unregister_device(struct input_dev *dev) +{ + struct input_handle *handle = dev->handle; + struct input_dev **devptr = &input_dev; + +/* + * Kill any pending repeat timers. + */ + + del_timer(&dev->timer); + +/* + * Notify handlers. + */ + + while (handle) { + handle->handler->disconnect(handle); + handle = handle->dnext; + } + +/* + * Remove the device. + */ + + while (*devptr && (*devptr != dev)) + devptr = &((*devptr)->next); + *devptr = (*devptr)->next; + + input_number--; + MOD_DEC_USE_COUNT; +} + +void input_register_handler(struct input_handler *handler) +{ + struct input_dev *dev = input_dev; + +/* + * Add the handler. + */ + + handler->next = input_handler; + input_handler = handler; + +/* + * Notify it about all existing devices. + */ + + while (dev) { + handler->connect(handler, dev); + dev = dev->next; + } +} + +void input_unregister_handler(struct input_handler *handler) +{ + struct input_handler **handlerptr = &input_handler; + struct input_handle *handle = handler->handle; + +/* + * Tell the handler to disconnect from all devices it keeps open. + */ + + while (handle) { + handler->disconnect(handle); + handle = handle->hnext; + } + +/* + * Remove it. + */ + + while (*handlerptr && (*handlerptr != handler)) + handlerptr = &((*handlerptr)->next); + + *handlerptr = (*handlerptr)->next; + +} + +void input_open_device(struct input_handle *handle) +{ + handle->dnext = handle->dev->handle; + handle->hnext = handle->handler->handle; + handle->dev->handle = handle; + handle->handler->handle = handle; + + if (handle->dev->open) + handle->dev->open(handle->dev); +} + +void input_close_device(struct input_handle *handle) +{ + struct input_handle **handleptr; + + if (handle->dev->close) + handle->dev->close(handle->dev); +/* + * Remove from device list of handles. + */ + + handleptr = &handle->dev->handle; + + while (*handleptr && (*handleptr != handle)) + handleptr = &((*handleptr)->dnext); + *handleptr = (*handleptr)->dnext; + +/* + * Remove from handler list of handles. + */ + + handleptr = &handle->handler->handle; + + while (*handleptr && (*handleptr != handle)) + handleptr = &((*handleptr)->hnext); + *handleptr = (*handleptr)->hnext; +} + + +#ifdef MODULE +int init_module(void) +#else +int __init input_init(void) +#endif +{ +#ifndef MODULE +#ifdef CONFIG_INPUT_KEYBDEV + keybdev_init(); +#endif +#ifdef CONFIG_INPUT_MOUSEDEV + mousedev_init(); +#endif +#ifdef CONFIG_INPUT_JOYDEV + joydev_init(); +#endif +#ifdef CONFIG_INPUT_EVDEV + evdev_init(); +#endif +#endif + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +} +#endif diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c new file mode 100644 index 000000000000..5ae17ea06f0c --- /dev/null +++ b/drivers/usb/joydev.c @@ -0,0 +1,476 @@ +/* + * joydev.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999 Colin Van Dyke + * + * Joystick device driver for the input driver suite. + * + * Sponsored by SuSE and Intel + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JOYDEV_MAJOR 15 +#define JOYDEV_BUFFER_SIZE 64 + +struct joydev { + char name[32]; + int used; + struct input_handle handle; + int minor; + wait_queue_head_t wait; + struct joydev *next; + struct joydev_list *list; + struct js_corr corr[ABS_MAX]; + struct JS_DATA_SAVE_TYPE glue; + int nabs; + int nkey; + __u16 keymap[KEY_MAX - BTN_0]; + __u16 keypam[KEY_MAX - BTN_0]; + __u8 absmap[ABS_MAX]; + __u8 abspam[ABS_MAX]; +}; + +struct joydev_list { + struct js_event buffer[JOYDEV_BUFFER_SIZE]; + int head; + int tail; + int startup; + struct fasync_struct *fasync; + struct joydev *joydev; + struct joydev_list *next; +}; + +static unsigned long joydev_minors = 0; +static struct joydev *joydev_base[BITS_PER_LONG]; + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_SUPPORTED_DEVICE("js"); + +static int js_correct(int value, struct js_corr *corr) +{ + switch (corr->type) { + case JS_CORR_NONE: + break; + case JS_CORR_BROKEN: + value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : + ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : + ((corr->coef[2] * (value - corr->coef[0])) >> 14); + break; + default: + return 0; + } + + if (value < -32767) return -32767; + if (value > 32767) return 32767; + + return value; +} + +static void js_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct joydev *joydev = handle->private; + struct joydev_list *list = joydev->list; + struct js_event event; + + switch (type) { + + case EV_KEY: + if (code < BTN_0 || value == 2) return; + event.type = JS_EVENT_BUTTON; + event.number = joydev->keymap[code - BTN_0]; + event.value = value; + break; + + case EV_ABS: + event.type = JS_EVENT_AXIS; + event.number = joydev->absmap[code]; + event.value = js_correct(value, &joydev->corr[event.number]); + break; + + default: + return; + } + + event.time = jiffies * (1000 / HZ); + + while (list) { + + memcpy(list->buffer + list->head, &event, sizeof(struct js_event)); + + if (list->startup == joydev->nabs + joydev->nkey) + if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) + list->startup = 0; + + if (list->fasync) + kill_fasync(list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&joydev->wait); +} + +static int joydev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct joydev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int joydev_release(struct inode * inode, struct file * file) +{ + struct joydev_list *list = file->private_data; + struct joydev_list **listptr = &list->joydev->list; + + joydev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->joydev->used) { + clear_bit(list->joydev->minor, &joydev_minors); + kfree(list->joydev); + } + + kfree(list); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int joydev_open(struct inode *inode, struct file *file) +{ + struct joydev_list *list; + int i = MINOR(inode->i_rdev); + + if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR) + return -EINVAL; + + if (i > BITS_PER_LONG || !test_bit(i, &joydev_minors)) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) + return -ENOMEM; + + memset(list, 0, sizeof(struct joydev_list)); + + list->joydev = joydev_base[i]; + list->next = joydev_base[i]->list; + joydev_base[i]->list = list; + + file->private_data = list; + + list->joydev->used++; + + MOD_INC_USE_COUNT; + return 0; +} + +static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; + struct input_dev *input = joydev->handle.dev; + int retval = 0; + + if (count < sizeof(struct js_event)) + return -EINVAL; + + if (count == sizeof(struct JS_DATA_TYPE)) { + + struct JS_DATA_TYPE data; + + data.buttons = (joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0 | + (joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0; + data.x = ((js_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x; + data.y = ((js_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y; + + if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) + return -EFAULT; + + list->startup = 0; + list->tail = list->head; + + return sizeof(struct JS_DATA_TYPE); + } + + if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) { + + add_wait_queue(&list->joydev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (list->head == list->tail) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->joydev->wait, &wait); + } + + if (retval) + return retval; + + while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { + + struct js_event event; + + event.time = jiffies * (1000/HZ); + + if (list->startup < joydev->nkey) { + event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; + event.value = !!test_bit(joydev->keypam[list->startup], input->key); + event.number = list->startup; + } else { + event.type = JS_EVENT_AXIS | JS_EVENT_INIT; + event.value = js_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]], + &joydev->corr[list->startup - joydev->nkey]); + event.number = list->startup - joydev->nkey; + } + + if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) + return -EFAULT; + + list->startup++; + retval += sizeof(struct js_event); + } + + while (list->head != list->tail && retval + sizeof(struct js_event) <= count) { + + if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event))) + return -EFAULT; + + list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); + retval += sizeof(struct js_event); + } + + return retval; +} + +static unsigned int joydev_poll(struct file *file, poll_table *wait) +{ + struct joydev_list *list = file->private_data; + poll_wait(file, &list->joydev->wait, wait); + if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) + return POLLIN | POLLRDNORM; + return 0; +} + +static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; + + switch (cmd) { + + case JS_SET_CAL: + return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg, + sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; + case JS_GET_CAL: + return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR, + sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; + case JS_SET_TIMEOUT: + return get_user(joydev->glue.JS_TIMEOUT, (int *) arg); + case JS_GET_TIMEOUT: + return put_user(joydev->glue.JS_TIMEOUT, (int *) arg); + case JS_SET_TIMELIMIT: + return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg); + case JS_GET_TIMELIMIT: + return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg); + case JS_SET_ALL: + return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg, + sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; + case JS_GET_ALL: + return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue, + sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; + + case JSIOCGVERSION: + return put_user(JS_VERSION, (__u32 *) arg); + case JSIOCGAXES: + return put_user(joydev->nabs, (__u8 *) arg); + case JSIOCGBUTTONS: + return put_user(joydev->nkey, (__u8 *) arg); + case JSIOCSCORR: + return copy_from_user(joydev->corr, (struct js_corr *) arg, + sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + case JSIOCGCORR: + return copy_to_user((struct js_corr *) arg, joydev->corr, + sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + default: + if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { + int len = strlen(joydev->name) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + if (copy_to_user((char *) arg, joydev->name, len)) return -EFAULT; + return len; + } + } + return -EINVAL; +} + +static struct file_operations joydev_fops = { + read: joydev_read, + write: joydev_write, + poll: joydev_poll, + open: joydev_open, + release: joydev_release, + ioctl: joydev_ioctl, + fasync: joydev_fasync, +}; + +static int joydev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct joydev *joydev; + int i, j; + + if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) && + test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) && + (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit) + || test_bit(BTN_1, dev->keybit)))) return -1; + + if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL))) + return -1; + + memset(joydev, 0, sizeof(struct joydev)); + + init_waitqueue_head(&joydev->wait); + + if (joydev_minors == -1) { + printk("Can't register new joystick - 32 devices already taken.\n"); + return -1; + } + + sprintf(joydev->name, "joydev%d", joydev->minor); + + joydev->handle.dev = dev; + joydev->handle.handler = handler; + joydev->handle.private = joydev; + + joydev->used = 1; + + for (i = 0; i < ABS_MAX; i++) + if (test_bit(i, dev->absbit)) { + joydev->absmap[i] = joydev->nabs; + joydev->abspam[joydev->nabs] = i; + joydev->nabs++; + } + + for (i = 0; i < KEY_MAX - BTN_0; i++) + if (test_bit(i + BTN_0, dev->keybit)) { + joydev->keymap[i] = joydev->nkey; + joydev->keypam[joydev->nkey] = i + BTN_0; + joydev->nkey++; + } + + joydev->minor = ffz(joydev_minors); + set_bit(joydev->minor, &joydev_minors); + joydev_base[joydev->minor] = joydev; + + for (i = 0; i < joydev->nabs; i++) { + j = joydev->abspam[i]; + joydev->corr[i].type = JS_CORR_BROKEN; + joydev->corr[i].prec = dev->absfuzz[j]; + joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; + joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; + joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); + joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); + } + + input_open_device(&joydev->handle); + + printk("%s: Joystick device for input%d on /dev/js%d\n", joydev->name, dev->number, joydev->minor); + + return 0; +} + +static void joydev_disconnect(struct input_handle *handle) +{ + struct joydev *joydev = handle->private; + + input_close_device(handle); + + if (!--joydev->used) { + clear_bit(joydev->minor, &joydev_minors); + kfree(joydev); + } +} + +static struct input_handler joydev_handler = { + event: js_event, + connect: joydev_connect, + disconnect: joydev_disconnect, +}; + +#ifdef MODULE +void cleanup_module(void) +{ + input_unregister_handler(&joydev_handler); + if (unregister_chrdev(JOYSTICK_MAJOR, "js")) + printk(KERN_ERR "js: can't unregister device\n"); +} + +int init_module(void) +#else +int __init joydev_init(void) +#endif +{ + if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) { + printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR); + return -EBUSY; + } + input_register_handler(&joydev_handler); + + return 0; +} diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c new file mode 100644 index 000000000000..a0749024d46f --- /dev/null +++ b/drivers/usb/keybdev.c @@ -0,0 +1,139 @@ +/* + * keybdev.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Input driver to keyboard driver binding. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_X86 + +static unsigned char keybdev_x86_e0s[] = + { 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48, + 0x49, 0x4b, 0x4d, 0x4f, 0x50, 0x51, 0x52, 0x53 }; + +#elif CONFIG_MAC_KEYBOARD + +static unsigned char keybdev_mac_codes[256] = + { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, + 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, + 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, + 11, 45, 46, 43, 47, 44,123, 67, 55, 49, 57,122,120, 99,118, 96, + 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, + 84, 85, 82, 65, 0, 0, 0,103,111, 0, 0, 0, 0, 0, 0, 0, + 76,125, 75, 0,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, + 0, 0, 0, 0,127, 81, 0,113 }; + +#endif + +void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) +{ + if (type != EV_KEY || code > 255) return; + +#ifdef CONFIG_X86 + + if (code >= 125) { + handle_scancode(0xe0, 1); + handle_scancode(code - 34, down); + } else if (code == 119) { + handle_scancode(0xe1, 1); + handle_scancode(0x1d, down); + handle_scancode(0x45, down); + } else if (code >= 96) { + handle_scancode(0xe0, 1); + handle_scancode(keybdev_x86_e0s[code - 96], down); + if (code == 99) { + handle_scancode(0xe0, 1); + handle_scancode(0x37, down); + } + } else handle_scancode(code, down); + +#elif CONFIG_MAC_KEYBOARD + + if (keycode < 128) + handle_scancode(keybdev_mac_codes[code], down); + +#else +#error "Cannot generate rawmode keyboard for your architecture yet." +#endif + +} + +static int keybdev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct input_handle *handle; + + if (!test_bit(EV_KEY, dev->evbit) || !test_bit(KEY_A, dev->keybit) || !test_bit(KEY_Z, dev->keybit)) + return -1; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return -1; + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + + input_open_device(handle); + + printk("keybdev.c: Adding keyboard: input%d\n", dev->number); + + return 0; +} + +static void keybdev_disconnect(struct input_handle *handle) +{ + printk("keybdev.c: Removing keyboard: input%d\n", handle->dev->number); + + input_close_device(handle); + + kfree(handle); +} + +struct input_handler keybdev_handler = { + event: keybdev_event, + connect: keybdev_connect, + disconnect: keybdev_disconnect, +}; + +#ifdef MODULE +void cleanup_module(void) +{ + input_unregister_handler(&keybdev_handler); +} +int init_module(void) +#else +int __init keybdev_init(void) +#endif +{ + input_register_handler(&keybdev_handler); + return 0; +} diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c deleted file mode 100644 index 28ab3e6934f9..000000000000 --- a/drivers/usb/keyboard.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - Fixes: - 1999/09/04 - Arnaldo Carvalho de Melo - Handle states in usb_kbd_irq - 1999/09/06 - Arnaldo Carvalho de Melo - rmmod usb-keyboard doesn't crash the system anymore: the irq - handlers are correctly released with usb_release_irq -*/ -#include -#include -#include -#include -#include -#include -#include - -#include -#include "usb.h" - -#define PCKBD_PRESSED 0x00 -#define PCKBD_RELEASED 0x80 -#define PCKBD_NEEDS_E0 0x80 - -#define USBKBD_MODIFIER_BASE 224 -#define USBKBD_KEYCODE_OFFSET 2 -#define USBKBD_KEYCODE_COUNT 6 - -#define USBKBD_VALID_KEYCODE(key) ((unsigned char)(key) > 3) -#define USBKBD_FIND_KEYCODE(down, key, count) \ - ((unsigned char*) memscan((down), (key), (count)) < ((down) + (count))) - -#define USBKBD_REPEAT_DELAY (HZ / 4) -#define USBKBD_REPEAT_RATE (HZ / 20) - -struct usb_keyboard { - struct usb_device *dev; - unsigned long down[2]; - unsigned char repeat_key; - struct timer_list repeat_timer; - struct list_head list; - unsigned int irqpipe; - void *irq_handler; /* host controller's IRQ transfer handle */ -}; - -extern unsigned char usb_kbd_map[]; - -static void *usb_kbd_probe(struct usb_device *dev, unsigned int i); -static void usb_kbd_disconnect(struct usb_device *dev, void *ptr); -static void usb_kbd_repeat(unsigned long dummy); - -static LIST_HEAD(usb_kbd_list); - -static struct usb_driver usb_kbd_driver = { - "keyboard", - usb_kbd_probe, - usb_kbd_disconnect, - {NULL, NULL} -}; - - -static void usb_kbd_handle_key(unsigned char key, int down) -{ - int scancode = (int) usb_kbd_map[key]; - if (scancode) { -#ifndef CONFIG_MAC_KEYBOARD - if (scancode & PCKBD_NEEDS_E0) { - handle_scancode(0xe0, 1); - } -#endif /* CONFIG_MAC_KEYBOARD */ - handle_scancode((scancode & ~PCKBD_NEEDS_E0), down); - } -} - -static void usb_kbd_repeat(unsigned long dev_id) -{ - struct usb_keyboard *kbd = (struct usb_keyboard *) dev_id; - - unsigned long flags; - save_flags(flags); - cli(); - - if (kbd->repeat_key) { - usb_kbd_handle_key(kbd->repeat_key, 1); - - /* reset repeat timer */ - kbd->repeat_timer.function = usb_kbd_repeat; - kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_RATE; - kbd->repeat_timer.data = (unsigned long) kbd; - kbd->repeat_timer.prev = NULL; - kbd->repeat_timer.next = NULL; - add_timer(&kbd->repeat_timer); - } - - restore_flags(flags); -} - -static int usb_kbd_irq(int state, void *buffer, int len, void *dev_id) -{ - struct usb_keyboard *kbd = (struct usb_keyboard *) dev_id; - unsigned long *down = (unsigned long *) buffer; - - /* - * USB_ST_NOERROR is the normal case. - * USB_ST_REMOVED occurs if keyboard disconnected - * On other states, ignore - */ - - switch (state) { - case USB_ST_REMOVED: - case USB_ST_INTERNALERROR: - printk(KERN_DEBUG "%s(%d): Suspending\n", __FILE__, - __LINE__); - return 0; /* disable */ - case USB_ST_NOERROR: - break; - default: - return 1; /* ignore */ - } - - if (kbd->down[0] != down[0] || kbd->down[1] != down[1]) { - unsigned char *olddown, *newdown; - unsigned char modsdelta, key; - int i; - - /* handle modifier change */ - modsdelta = - (*(unsigned char *) down ^ *(unsigned char *) kbd-> - down); - if (modsdelta) { - for (i = 0; i < 8; i++) { - if (modsdelta & 0x01) { - int pressed = - (*(unsigned char *) down >> i) - & 0x01; - usb_kbd_handle_key(i + - USBKBD_MODIFIER_BASE, - pressed); - } - modsdelta >>= 1; - } - } - - olddown = - (unsigned char *) kbd->down + USBKBD_KEYCODE_OFFSET; - newdown = (unsigned char *) down + USBKBD_KEYCODE_OFFSET; - - /* handle released keys */ - for (i = 0; i < USBKBD_KEYCODE_COUNT; i++) { - key = olddown[i]; - if (USBKBD_VALID_KEYCODE(key) - && !USBKBD_FIND_KEYCODE(newdown, key, - USBKBD_KEYCODE_COUNT)) - { - usb_kbd_handle_key(key, 0); - } - } - - /* handle pressed keys */ - kbd->repeat_key = 0; - for (i = 0; i < USBKBD_KEYCODE_COUNT; i++) { - key = newdown[i]; - if (USBKBD_VALID_KEYCODE(key) - && !USBKBD_FIND_KEYCODE(olddown, key, - USBKBD_KEYCODE_COUNT)) - { - usb_kbd_handle_key(key, 1); - kbd->repeat_key = key; - } - } - - /* set repeat timer if any keys were pressed */ - if (kbd->repeat_key) { - del_timer(&kbd->repeat_timer); - kbd->repeat_timer.function = usb_kbd_repeat; - kbd->repeat_timer.expires = - jiffies + USBKBD_REPEAT_DELAY; - kbd->repeat_timer.data = (unsigned long) kbd; - kbd->repeat_timer.prev = NULL; - kbd->repeat_timer.next = NULL; - add_timer(&kbd->repeat_timer); - } - - kbd->down[0] = down[0]; - kbd->down[1] = down[1]; - } - - return 1; -} - -static void *usb_kbd_probe(struct usb_device *dev, unsigned int i) -{ - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_keyboard *kbd; - int ret; - - interface = &dev->actconfig->interface[i].altsetting[0]; - endpoint = &interface->endpoint[0]; - - if (interface->bInterfaceClass != 3 - || interface->bInterfaceSubClass != 1 - || interface->bInterfaceProtocol != 1) { - return NULL; - } - - printk(KERN_INFO "USB HID boot protocol keyboard detected.\n"); - - kbd = kmalloc(sizeof(struct usb_keyboard), GFP_KERNEL); - if (kbd) { - memset(kbd, 0, sizeof(*kbd)); - kbd->dev = dev; - - usb_set_protocol(dev, 0); - usb_set_idle(dev, 0, 0); - - kbd->irqpipe = - usb_rcvintpipe(dev, endpoint->bEndpointAddress); - ret = - usb_request_irq(dev, kbd->irqpipe, usb_kbd_irq, - endpoint->bInterval, kbd, - &kbd->irq_handler); - if (ret) { - printk(KERN_INFO - "usb-keyboard failed usb_request_irq (0x%x)\n", - ret); - goto probe_err; - } - - list_add(&kbd->list, &usb_kbd_list); - - return kbd; - } - -probe_err: - if (kbd) - kfree(kbd); - return NULL; -} - -static void usb_kbd_disconnect(struct usb_device *dev, void *ptr) -{ - struct usb_keyboard *kbd = (struct usb_keyboard *) ptr; - if (kbd) { - usb_release_irq(dev, kbd->irq_handler, kbd->irqpipe); - list_del(&kbd->list); - del_timer(&kbd->repeat_timer); - kfree(kbd); - } - - printk(KERN_INFO "USB HID boot protocol keyboard removed.\n"); -} - -int usb_kbd_init(void) -{ - return usb_register(&usb_kbd_driver); -} - -void usb_kbd_cleanup(void) -{ - struct list_head *cur, *head = &usb_kbd_list; - - cur = head->next; - - while (cur != head) { - struct usb_keyboard *kbd = - list_entry(cur, struct usb_keyboard, list); - - cur = cur->next; - - list_del(&kbd->list); - INIT_LIST_HEAD(&kbd->list); - - if (kbd->irq_handler) { - usb_release_irq(kbd->dev, kbd->irq_handler, - kbd->irqpipe); - /* never keep a reference to a released IRQ! */ - kbd->irq_handler = NULL; - } - } - - usb_deregister(&usb_kbd_driver); -} - -#ifdef MODULE -int init_module(void) -{ - return usb_kbd_init(); -} - -void cleanup_module(void) -{ - usb_kbd_cleanup(); -} - -#endif diff --git a/drivers/usb/keymap-mac.c b/drivers/usb/keymap-mac.c deleted file mode 100644 index 48fc25e9b2aa..000000000000 --- a/drivers/usb/keymap-mac.c +++ /dev/null @@ -1,50 +0,0 @@ -unsigned char usb_kbd_map[256] = -{ - 0x00, 0x00, 0x00, 0x00, 0x80, 0x0b, 0x08, 0x02, - 0x0e, 0x03, 0x05, 0x04, 0x22, 0x26, 0x28, 0x25, - - 0x2e, 0x2d, 0x1f, 0x23, 0x0c, 0x0f, 0x01, 0x11, - 0x20, 0x09, 0x0d, 0x07, 0x10, 0x06, 0x12, 0x13, - - 0x14, 0x15, 0x17, 0x16, 0x1a, 0x1c, 0x19, 0x1d, - 0x24, 0x35, 0x33, 0x30, 0x31, 0x1b, 0x18, 0x21, - - 0x1e, 0x2a, 0x00, 0x29, 0x27, 0x32, 0x2b, 0x2f, - 0x2c, 0x39, 0x7a, 0x78, 0x63, 0x76, 0x60, 0x61, - - 0x62, 0x64, 0x65, 0x6d, 0x67, 0x6f, 0x69, 0x6b, - 0x71, 0x72, 0x73, 0x74, 0x75, 0x77, 0x79, 0x3c, - - 0x3b, 0x3d, 0x3e, 0x47, 0x4b, 0x43, 0x4e, 0x45, - 0x4c, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - - 0x5b, 0x5c, 0x52, 0x41, 0x00, 0x00, 0x00, 0x00, - 0x69, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x38, 0x3a, 0x37, 0x7d, 0x7b, 0x7c, 0x37, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff --git a/drivers/usb/keymap.c b/drivers/usb/keymap.c deleted file mode 100644 index 39f085cbdad1..000000000000 --- a/drivers/usb/keymap.c +++ /dev/null @@ -1,50 +0,0 @@ -unsigned char usb_kbd_map[256] = -{ - 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x2e, 0x20, - 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, - - 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, - 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, - - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, - - 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, - 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, - - 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, - 0x00, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, - - 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, - 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, - - 0x48, 0x49, 0x52, 0x53, 0x56, 0x6d, 0x00, 0x00, - 0xbd, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff --git a/drivers/usb/maps/fixup.map b/drivers/usb/maps/fixup.map deleted file mode 100644 index 6fbec256240d..000000000000 --- a/drivers/usb/maps/fixup.map +++ /dev/null @@ -1,30 +0,0 @@ -# misc fixes -keycode 0 = Pause -keycode 29 = Control -keycode 42 = Shift -keycode 54 = Shift_R -keycode 109 = Application - -# E0 keys (or'ed with 0x80) -keycode 156 = KP_Enter -keycode 157 = Control_R -keycode 181 = KP_Divide -keycode 183 = Print_Screen -keycode 184 = Alt_R -keycode 189 = F13 -keycode 190 = F14 -keycode 193 = F17 -keycode 198 = Break -keycode 199 = Home -keycode 200 = Up -keycode 201 = Prior -keycode 203 = Left -keycode 205 = Right -keycode 207 = End -keycode 208 = Down -keycode 209 = Next -keycode 210 = Insert -keycode 211 = Remove -keycode 219 = Window -keycode 220 = Window_R -keycode 221 = Menu diff --git a/drivers/usb/maps/mac.map b/drivers/usb/maps/mac.map deleted file mode 100644 index dd601f76d225..000000000000 --- a/drivers/usb/maps/mac.map +++ /dev/null @@ -1,350 +0,0 @@ -# Kernel keymap for Macintoshes. This uses 7 modifier combinations. -keymaps 0-2,4-5,8,12 -# -# Fixups: -keycode 0x69 = Print_Screen -keycode 0x6b = F14 -keycode 0x37 = Window_R -# -#keycode 0x00 = a -# hack! -keycode 0x80 = a - altgr keycode 0x00 = Hex_A -keycode 0x01 = s -keycode 0x02 = d - altgr keycode 0x02 = Hex_D -keycode 0x03 = f - altgr keycode 0x03 = Hex_F -keycode 0x04 = h -keycode 0x05 = g -keycode 0x06 = z -keycode 0x07 = x -keycode 0x08 = c - altgr keycode 0x08 = Hex_C -keycode 0x09 = v -keycode 0x0a = -keycode 0x0b = b - altgr keycode 0x0b = Hex_B -keycode 0x0c = q -keycode 0x0d = w -keycode 0x0e = e - altgr keycode 0x0e = Hex_E -keycode 0x0f = r -keycode 0x10 = y -keycode 0x11 = t -keycode 0x12 = one exclam - alt keycode 0x12 = Meta_one -keycode 0x13 = two at at - control keycode 0x13 = nul - shift control keycode 0x13 = nul - alt keycode 0x13 = Meta_two -keycode 0x14 = three numbersign - control keycode 0x14 = Escape - alt keycode 0x14 = Meta_three -keycode 0x15 = four dollar dollar - control keycode 0x15 = Control_backslash - alt keycode 0x15 = Meta_four -keycode 0x16 = six asciicircum - control keycode 0x16 = Control_asciicircum - alt keycode 0x16 = Meta_six -keycode 0x17 = five percent - control keycode 0x17 = Control_bracketright - alt keycode 0x17 = Meta_five -keycode 0x18 = equal plus - alt keycode 0x18 = Meta_equal -keycode 0x19 = nine parenleft bracketright - alt keycode 0x19 = Meta_nine -keycode 0x1a = seven ampersand braceleft - control keycode 0x1a = Control_underscore - alt keycode 0x1a = Meta_seven -keycode 0x1b = minus underscore backslash - control keycode 0x1b = Control_underscore - shift control keycode 0x1b = Control_underscore - alt keycode 0x1b = Meta_minus -keycode 0x1c = eight asterisk bracketleft - control keycode 0x1c = Delete - alt keycode 0x1c = Meta_eight -keycode 0x1d = zero parenright braceright - alt keycode 0x1d = Meta_zero -keycode 0x1e = bracketright braceright asciitilde - control keycode 0x1e = Control_bracketright - alt keycode 0x1e = Meta_bracketright -keycode 0x1f = o -keycode 0x20 = u -keycode 0x21 = bracketleft braceleft - control keycode 0x21 = Escape - alt keycode 0x21 = Meta_bracketleft -keycode 0x22 = i -keycode 0x23 = p -keycode 0x24 = Return - alt keycode 0x24 = Meta_Control_m -keycode 0x25 = l -keycode 0x26 = j -keycode 0x27 = apostrophe quotedbl - control keycode 0x27 = Control_g - alt keycode 0x27 = Meta_apostrophe -keycode 0x28 = k -keycode 0x29 = semicolon colon - alt keycode 0x29 = Meta_semicolon -keycode 0x2a = backslash bar - control keycode 0x2a = Control_backslash - alt keycode 0x2a = Meta_backslash -keycode 0x2b = comma less - alt keycode 0x2b = Meta_comma -keycode 0x2c = slash question - control keycode 0x2c = Delete - alt keycode 0x2c = Meta_slash -keycode 0x2d = n -keycode 0x2e = m -keycode 0x2f = period greater - control keycode 0x2f = Compose - alt keycode 0x2f = Meta_period -keycode 0x30 = Tab Tab - alt keycode 0x30 = Meta_Tab -keycode 0x31 = space space - control keycode 0x31 = nul - alt keycode 0x31 = Meta_space -keycode 0x32 = grave asciitilde - control keycode 0x32 = nul - alt keycode 0x32 = Meta_grave -keycode 0x33 = Delete Delete - control keycode 0x33 = BackSpace - alt keycode 0x33 = Meta_Delete -keycode 0x34 = -keycode 0x35 = Escape Escape - alt keycode 0x35 = Meta_Escape -keycode 0x36 = Control -keycode 0x37 = Window -keycode 0x38 = Shift -keycode 0x39 = Caps_Lock -keycode 0x3a = Alt -keycode 0x3b = Left - alt keycode 0x3b = Decr_Console -keycode 0x3c = Right - alt keycode 0x3c = Incr_Console -keycode 0x3d = Down -keycode 0x3e = Up -keycode 0x3f = -keycode 0x40 = -keycode 0x41 = KP_Period -keycode 0x42 = -keycode 0x43 = KP_Multiply -keycode 0x44 = -keycode 0x45 = KP_Add -keycode 0x46 = -keycode 0x47 = Num_Lock -# shift keycode 0x47 = Bare_Num_Lock -keycode 0x48 = -keycode 0x49 = -keycode 0x4a = -keycode 0x4b = KP_Divide -keycode 0x4c = KP_Enter -keycode 0x4d = -keycode 0x4e = KP_Subtract -keycode 0x4f = -keycode 0x50 = -keycode 0x51 = -#keycode 0x51 = KP_Equals -keycode 0x52 = KP_0 - alt keycode 0x52 = Ascii_0 - altgr keycode 0x52 = Hex_0 -keycode 0x53 = KP_1 - alt keycode 0x53 = Ascii_1 - altgr keycode 0x53 = Hex_1 -keycode 0x54 = KP_2 - alt keycode 0x54 = Ascii_2 - altgr keycode 0x54 = Hex_2 -keycode 0x55 = KP_3 - alt keycode 0x55 = Ascii_3 - altgr keycode 0x55 = Hex_3 -keycode 0x56 = KP_4 - alt keycode 0x56 = Ascii_4 - altgr keycode 0x56 = Hex_4 -keycode 0x57 = KP_5 - alt keycode 0x57 = Ascii_5 - altgr keycode 0x57 = Hex_5 -keycode 0x58 = KP_6 - alt keycode 0x58 = Ascii_6 - altgr keycode 0x58 = Hex_6 -keycode 0x59 = KP_7 - alt keycode 0x59 = Ascii_7 - altgr keycode 0x59 = Hex_7 -keycode 0x5b = KP_8 - alt keycode 0x5b = Ascii_8 - altgr keycode 0x5b = Hex_8 -keycode 0x5c = KP_9 - alt keycode 0x5c = Ascii_9 - altgr keycode 0x5c = Hex_9 -keycode 0x5d = -keycode 0x5e = -keycode 0x5f = -keycode 0x60 = F5 F15 Console_17 - control keycode 0x60 = F5 - alt keycode 0x60 = Console_5 - control alt keycode 0x60 = Console_5 -keycode 0x61 = F6 F16 Console_18 - control keycode 0x61 = F6 - alt keycode 0x61 = Console_6 - control alt keycode 0x61 = Console_6 -keycode 0x62 = F7 F17 Console_19 - control keycode 0x62 = F7 - alt keycode 0x62 = Console_7 - control alt keycode 0x62 = Console_7 -keycode 0x63 = F3 F13 Console_15 - control keycode 0x63 = F3 - alt keycode 0x63 = Console_3 - control alt keycode 0x63 = Console_3 -keycode 0x64 = F8 F18 Console_20 - control keycode 0x64 = F8 - alt keycode 0x64 = Console_8 - control alt keycode 0x64 = Console_8 -keycode 0x65 = F9 F19 Console_21 - control keycode 0x65 = F9 - alt keycode 0x65 = Console_9 - control alt keycode 0x65 = Console_9 -keycode 0x66 = -keycode 0x67 = F11 F11 Console_23 - control keycode 0x67 = F11 - alt keycode 0x67 = Console_11 - control alt keycode 0x67 = Console_11 -keycode 0x68 = -keycode 0x69 = F13 -keycode 0x6a = -keycode 0x6b = Scroll_Lock Show_Memory Show_Registers - control keycode 0x6b = Show_State - alt keycode 0x6b = Scroll_Lock -keycode 0x6c = -keycode 0x6d = F10 F20 Console_22 - control keycode 0x6d = F10 - alt keycode 0x6d = Console_10 - control alt keycode 0x6d = Console_10 -keycode 0x6e = -keycode 0x6f = F12 F12 Console_24 - control keycode 0x6f = F12 - alt keycode 0x6f = Console_12 - control alt keycode 0x6f = Console_12 -keycode 0x70 = -keycode 0x71 = Pause -keycode 0x72 = Insert -keycode 0x73 = Home -keycode 0x74 = Prior - shift keycode 0x74 = Scroll_Backward -keycode 0x75 = Remove -keycode 0x76 = F4 F14 Console_16 - control keycode 0x76 = F4 - alt keycode 0x76 = Console_4 - control alt keycode 0x76 = Console_4 -keycode 0x77 = End -keycode 0x78 = F2 F12 Console_14 - control keycode 0x78 = F2 - alt keycode 0x78 = Console_2 - control alt keycode 0x78 = Console_2 -keycode 0x79 = Next - shift keycode 0x79 = Scroll_Forward -keycode 0x7a = F1 F11 Console_13 - control keycode 0x7a = F1 - alt keycode 0x7a = Console_1 - control alt keycode 0x7a = Console_1 -keycode 0x7b = Shift_R -keycode 0x7c = Alt_R -keycode 0x7d = Control_R -keycode 0x7e = -keycode 0x7f = -#keycode 0x7f = Power - control shift keycode 0x7f = Boot -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff --git a/drivers/usb/maps/serial.map b/drivers/usb/maps/serial.map deleted file mode 100644 index e421a0d23814..000000000000 --- a/drivers/usb/maps/serial.map +++ /dev/null @@ -1,370 +0,0 @@ -keymaps 0-2,4-6,8-9,12 -keycode 1 = Escape - alt keycode 1 = Meta_Escape - shift alt keycode 1 = Meta_Escape - control alt keycode 1 = Meta_Escape -keycode 2 = one exclam - alt keycode 2 = Meta_one - shift alt keycode 2 = Meta_exclam -keycode 3 = two at at nul nul - alt keycode 3 = Meta_two - shift alt keycode 3 = Meta_at - control alt keycode 3 = Meta_nul -keycode 4 = three numbersign - control keycode 4 = Escape - alt keycode 4 = Meta_three - shift alt keycode 4 = Meta_numbersign -keycode 5 = four dollar dollar Control_backslash - alt keycode 5 = Meta_four - shift alt keycode 5 = Meta_dollar - control alt keycode 5 = Meta_Control_backslash -keycode 6 = five percent - control keycode 6 = Control_bracketright - alt keycode 6 = Meta_five - shift alt keycode 6 = Meta_percent -keycode 7 = six asciicircum - control keycode 7 = Control_asciicircum - alt keycode 7 = Meta_six - shift alt keycode 7 = Meta_asciicircum -keycode 8 = seven ampersand braceleft Control_underscore - alt keycode 8 = Meta_seven - shift alt keycode 8 = Meta_ampersand - control alt keycode 8 = Meta_Control_underscore -keycode 9 = eight asterisk bracketleft Delete - alt keycode 9 = Meta_eight - shift alt keycode 9 = Meta_asterisk - control alt keycode 9 = Meta_Delete -keycode 10 = nine parenleft bracketright - alt keycode 10 = Meta_nine - shift alt keycode 10 = Meta_parenleft -keycode 11 = zero parenright braceright - alt keycode 11 = Meta_zero - shift alt keycode 11 = Meta_parenright -keycode 12 = minus underscore backslash Control_underscore Control_underscore - alt keycode 12 = Meta_minus - shift alt keycode 12 = Meta_underscore - control alt keycode 12 = Meta_Control_underscore -keycode 13 = equal plus - alt keycode 13 = Meta_equal - shift alt keycode 13 = Meta_plus -keycode 14 = Delete - alt keycode 14 = Meta_Delete - shift alt keycode 14 = Meta_Delete - control alt keycode 14 = Meta_Delete -keycode 15 = Tab - alt keycode 15 = Meta_Tab - shift alt keycode 15 = Meta_Tab - control alt keycode 15 = Meta_Tab -keycode 16 = q -keycode 17 = w -keycode 18 = e -keycode 19 = r -keycode 20 = t -keycode 21 = y -keycode 22 = u -keycode 23 = i -keycode 24 = o -keycode 25 = p -keycode 26 = bracketleft braceleft - control keycode 26 = Escape - alt keycode 26 = Meta_bracketleft - shift alt keycode 26 = Meta_braceleft -keycode 27 = bracketright braceright asciitilde Control_bracketright - alt keycode 27 = Meta_bracketright - shift alt keycode 27 = Meta_braceright - control alt keycode 27 = Meta_Control_bracketright -keycode 28 = Return - alt keycode 28 = Meta_Control_m -keycode 29 = Control -keycode 30 = a -keycode 31 = s -keycode 32 = d -keycode 33 = f -keycode 34 = g -keycode 35 = h -keycode 36 = j -keycode 37 = k -keycode 38 = l -keycode 39 = semicolon colon - alt keycode 39 = Meta_semicolon - shift alt keycode 39 = Meta_colon -keycode 40 = apostrophe quotedbl - control keycode 40 = Control_g - alt keycode 40 = Meta_apostrophe - shift alt keycode 40 = Meta_quotedbl -keycode 41 = grave asciitilde - control keycode 41 = nul - alt keycode 41 = Meta_grave - shift alt keycode 41 = Meta_asciitilde -keycode 42 = Shift -keycode 43 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash - shift alt keycode 43 = Meta_bar -keycode 44 = z -keycode 45 = x -keycode 46 = c -keycode 47 = v -keycode 48 = b -keycode 49 = n -keycode 50 = m -keycode 51 = comma less - alt keycode 51 = Meta_comma - shift alt keycode 51 = Meta_less -keycode 52 = period greater - alt keycode 52 = Meta_period - shift alt keycode 52 = Meta_greater -keycode 53 = slash question - control keycode 53 = Delete - alt keycode 53 = Meta_slash - shift alt keycode 53 = Meta_question -keycode 54 = Shift -keycode 55 = KP_Multiply - altgr keycode 55 = Hex_C -keycode 56 = Alt -keycode 57 = space - control keycode 57 = nul - alt keycode 57 = Meta_space - shift alt keycode 57 = Meta_space - control alt keycode 57 = Meta_nul -keycode 58 = Caps_Lock -keycode 59 = F1 F13 Console_13 F25 - alt keycode 59 = Console_1 - control alt keycode 59 = Console_1 -keycode 60 = F2 F14 Console_14 F26 - alt keycode 60 = Console_2 - control alt keycode 60 = Console_2 -keycode 61 = F3 F15 Console_15 F27 - alt keycode 61 = Console_3 - control alt keycode 61 = Console_3 -keycode 62 = F4 F16 Console_16 F28 - alt keycode 62 = Console_4 - control alt keycode 62 = Console_4 -keycode 63 = F5 F17 Console_17 F29 - alt keycode 63 = Console_5 - control alt keycode 63 = Console_5 -keycode 64 = F6 F18 Console_18 F30 - alt keycode 64 = Console_6 - control alt keycode 64 = Console_6 -keycode 65 = F7 F19 Console_19 F31 - alt keycode 65 = Console_7 - control alt keycode 65 = Console_7 -keycode 66 = F8 F20 Console_20 F32 - alt keycode 66 = Console_8 - control alt keycode 66 = Console_8 -keycode 67 = F9 F21 Console_21 F33 - alt keycode 67 = Console_9 - control alt keycode 67 = Console_9 -keycode 68 = F10 F22 Console_22 F34 - alt keycode 68 = Console_10 - control alt keycode 68 = Console_10 -keycode 69 = Num_Lock - altgr keycode 69 = Hex_E -keycode 70 = Scroll_Lock Show_Memory Show_Registers Show_State - alt keycode 70 = Scroll_Lock -keycode 71 = KP_7 - altgr keycode 71 = Hex_7 - alt keycode 71 = Ascii_7 -keycode 72 = KP_8 - altgr keycode 72 = Hex_8 - alt keycode 72 = Ascii_8 -keycode 73 = KP_9 - altgr keycode 73 = Hex_9 - alt keycode 73 = Ascii_9 -keycode 74 = KP_Subtract -keycode 75 = KP_4 - altgr keycode 75 = Hex_4 - alt keycode 75 = Ascii_4 -keycode 76 = KP_5 - altgr keycode 76 = Hex_5 - alt keycode 76 = Ascii_5 -keycode 77 = KP_6 - altgr keycode 77 = Hex_6 - alt keycode 77 = Ascii_6 -keycode 78 = KP_Add -keycode 79 = KP_1 - altgr keycode 79 = Hex_1 - alt keycode 79 = Ascii_1 -keycode 80 = KP_2 - altgr keycode 80 = Hex_2 - alt keycode 80 = Ascii_2 -keycode 81 = KP_3 - altgr keycode 81 = Hex_3 - alt keycode 81 = Ascii_3 -keycode 82 = KP_0 - altgr keycode 82 = Hex_0 - alt keycode 82 = Ascii_0 -keycode 83 = KP_Period - altgr control keycode 83 = Boot - control alt keycode 83 = Boot -keycode 84 = Last_Console -keycode 85 = -keycode 86 = less greater bar - alt keycode 86 = Meta_less - shift alt keycode 86 = Meta_greater -keycode 87 = F11 F23 Console_23 F35 - alt keycode 87 = Console_11 - control alt keycode 87 = Console_11 -keycode 88 = F12 F24 Console_24 F36 - alt keycode 88 = Console_12 - control alt keycode 88 = Console_12 -keycode 89 = -keycode 90 = -keycode 91 = -keycode 92 = -keycode 93 = -keycode 94 = -keycode 95 = -keycode 96 = KP_Enter -keycode 97 = Control -keycode 98 = KP_Divide - altgr keycode 98 = Hex_B -keycode 99 = Control_backslash - alt keycode 99 = Meta_Control_backslash - shift alt keycode 99 = Meta_Control_backslash - control alt keycode 99 = Meta_Control_backslash -keycode 100 = AltGr -keycode 101 = Break -keycode 102 = Find -keycode 103 = Up - alt keycode 103 = KeyboardSignal -keycode 104 = Prior - shift keycode 104 = Scroll_Backward -keycode 105 = Left - alt keycode 105 = Decr_Console -keycode 106 = Right - alt keycode 106 = Incr_Console -keycode 107 = Select -keycode 108 = Down -keycode 109 = Next - shift keycode 109 = Scroll_Forward -keycode 110 = Insert -keycode 111 = Remove - altgr control keycode 111 = Boot - control alt keycode 111 = Boot -keycode 112 = Macro - altgr control keycode 112 = VoidSymbol - shift alt keycode 112 = VoidSymbol -keycode 113 = F13 - altgr control keycode 113 = VoidSymbol - shift alt keycode 113 = VoidSymbol -keycode 114 = F14 - altgr control keycode 114 = VoidSymbol - shift alt keycode 114 = VoidSymbol -keycode 115 = Help - altgr control keycode 115 = VoidSymbol - shift alt keycode 115 = VoidSymbol -keycode 116 = Do - altgr control keycode 116 = VoidSymbol - shift alt keycode 116 = VoidSymbol -keycode 117 = F17 - altgr control keycode 117 = VoidSymbol - shift alt keycode 117 = VoidSymbol -keycode 118 = KP_MinPlus - altgr control keycode 118 = VoidSymbol - shift alt keycode 118 = VoidSymbol -keycode 119 = Pause -keycode 120 = -keycode 121 = -keycode 122 = -keycode 123 = -keycode 124 = -keycode 125 = -keycode 126 = -keycode 127 = -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff --git a/drivers/usb/maps/usb.map b/drivers/usb/maps/usb.map deleted file mode 100644 index f4f40ffbfbb7..000000000000 --- a/drivers/usb/maps/usb.map +++ /dev/null @@ -1,233 +0,0 @@ -# USB kernel keymap. -keymaps 0-2,4-5,8,12 - -keycode 4 = a - altgr keycode 30 = Hex_A -keycode 5 = b - altgr keycode 48 = Hex_B -keycode 6 = c - altgr keycode 46 = Hex_C -keycode 7 = d - altgr keycode 32 = Hex_D -keycode 8 = e - altgr keycode 18 = Hex_E -keycode 9 = f - altgr keycode 33 = Hex_F -keycode 10 = g -keycode 11 = h -keycode 12 = i -keycode 13 = j -keycode 14 = k -keycode 15 = l -keycode 16 = m -keycode 17 = n -keycode 18 = o -keycode 19 = p -keycode 20 = q -keycode 21 = r -keycode 22 = s -keycode 23 = t -keycode 24 = u -keycode 25 = v -keycode 26 = w -keycode 27 = x -keycode 28 = y -keycode 29 = z -keycode 30 = one exclam - alt keycode 2 = Meta_one -keycode 31 = two at - control keycode 3 = nul - shift control keycode 3 = nul - alt keycode 3 = Meta_two -keycode 32 = three numbersign - control keycode 4 = Escape - alt keycode 4 = Meta_three -keycode 33 = four dollar - control keycode 5 = Control_backslash - alt keycode 5 = Meta_four -keycode 34 = five percent - control keycode 6 = Control_bracketright - alt keycode 6 = Meta_five -keycode 35 = six asciicircum - control keycode 7 = Control_asciicircum - alt keycode 7 = Meta_six -keycode 36 = seven ampersand - control keycode 8 = Control_underscore - alt keycode 8 = Meta_seven -keycode 37 = eight asterisk - control keycode 9 = Delete - alt keycode 9 = Meta_eight -keycode 38 = nine parenleft - alt keycode 10 = Meta_nine -keycode 39 = zero parenright - alt keycode 11 = Meta_zero -keycode 40 = Return - alt keycode 28 = Meta_Control_m -keycode 41 = Escape Escape - alt keycode 1 = Meta_Escape -keycode 42 = Delete Delete - control keycode 14 = BackSpace - alt keycode 14 = Meta_Delete -keycode 43 = Tab Tab - alt keycode 15 = Meta_Tab -keycode 44 = space space - control keycode 57 = nul - alt keycode 57 = Meta_space -keycode 45 = minus underscore backslash - control keycode 12 = Control_underscore - shift control keycode 12 = Control_underscore - alt keycode 12 = Meta_minus -keycode 46 = equal plus - alt keycode 13 = Meta_equal -keycode 47 = bracketleft braceleft - control keycode 26 = Escape - alt keycode 26 = Meta_bracketleft -keycode 48 = bracketright braceright asciitilde - control keycode 27 = Control_bracketright - alt keycode 27 = Meta_bracketright -keycode 49 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash -keycode 50 = -keycode 51 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 52 = apostrophe quotedbl - control keycode 40 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 53 = grave asciitilde - control keycode 41 = nul - alt keycode 41 = Meta_grave -keycode 54 = comma less - alt keycode 51 = Meta_comma -keycode 55 = period greater - control keycode 52 = Compose - alt keycode 52 = Meta_period -keycode 56 = slash question - control keycode 53 = Delete - alt keycode 53 = Meta_slash -keycode 57 = Caps_Lock -keycode 58 = F1 F11 Console_13 - control keycode 59 = F1 - alt keycode 59 = Console_1 - control alt keycode 59 = Console_1 -keycode 59 = F2 F12 Console_14 - control keycode 60 = F2 - alt keycode 60 = Console_2 - control alt keycode 60 = Console_2 -keycode 60 = F3 F13 Console_15 - control keycode 61 = F3 - alt keycode 61 = Console_3 - control alt keycode 61 = Console_3 -keycode 61 = F4 F14 Console_16 - control keycode 62 = F4 - alt keycode 62 = Console_4 - control alt keycode 62 = Console_4 -keycode 62 = F5 F15 Console_17 - control keycode 63 = F5 - alt keycode 63 = Console_5 - control alt keycode 63 = Console_5 -keycode 63 = F6 F16 Console_18 - control keycode 64 = F6 - alt keycode 64 = Console_6 - control alt keycode 64 = Console_6 -keycode 64 = F7 F17 Console_19 - control keycode 65 = F7 - alt keycode 65 = Console_7 - control alt keycode 65 = Console_7 -keycode 65 = F8 F18 Console_20 - control keycode 66 = F8 - alt keycode 66 = Console_8 - control alt keycode 66 = Console_8 -keycode 66 = F9 F19 Console_21 - control keycode 67 = F9 - alt keycode 67 = Console_9 - control alt keycode 67 = Console_9 -keycode 67 = F10 F20 Console_22 - control keycode 68 = F10 - alt keycode 68 = Console_10 - control alt keycode 68 = Console_10 -keycode 68 = F11 F11 Console_23 - control keycode 87 = F11 - alt keycode 87 = Console_11 - control alt keycode 87 = Console_11 -keycode 69 = F12 F12 Console_24 - control keycode 88 = F12 - alt keycode 88 = Console_12 - control alt keycode 88 = Console_12 -keycode 70 = Print_Screen -keycode 71 = Scroll_Lock Show_Memory Show_Registers - control keycode 70 = Show_State - alt keycode 70 = Scroll_Lock -keycode 72 = Pause -keycode 73 = Insert -keycode 74 = Home -keycode 75 = Prior - shift keycode 104 = Scroll_Backward -keycode 76 = Remove -# altgr control keycode 111 = Boot - control alt keycode 111 = Boot -keycode 77 = End -keycode 78 = Next - shift keycode 109 = Scroll_Forward -keycode 79 = Right - alt keycode 106 = Incr_Console -keycode 80 = Left - alt keycode 105 = Decr_Console -keycode 81 = Down -keycode 82 = Up -keycode 83 = Num_Lock - shift keycode 69 = Bare_Num_Lock -keycode 84 = KP_Divide -keycode 85 = KP_Multiply -keycode 86 = KP_Subtract -keycode 87 = KP_Add -keycode 88 = KP_Enter -keycode 89 = KP_1 - alt keycode 79 = Ascii_1 - altgr keycode 79 = Hex_1 -keycode 90 = KP_2 - alt keycode 80 = Ascii_2 - altgr keycode 80 = Hex_2 -keycode 91 = KP_3 - alt keycode 81 = Ascii_3 - altgr keycode 81 = Hex_3 -keycode 92 = KP_4 - alt keycode 75 = Ascii_4 - altgr keycode 75 = Hex_4 -keycode 93 = KP_5 - alt keycode 76 = Ascii_5 - altgr keycode 76 = Hex_5 -keycode 94 = KP_6 - alt keycode 77 = Ascii_6 - altgr keycode 77 = Hex_6 -keycode 95 = KP_7 - alt keycode 71 = Ascii_7 - altgr keycode 71 = Hex_7 -keycode 96 = KP_8 - alt keycode 72 = Ascii_8 - altgr keycode 72 = Hex_8 -keycode 97 = KP_9 - alt keycode 73 = Ascii_9 - altgr keycode 73 = Hex_9 -keycode 98 = KP_0 - alt keycode 82 = Ascii_0 - altgr keycode 82 = Hex_0 -keycode 99 = KP_Period -# altgr control keycode 83 = Boot - control alt keycode 83 = Boot -keycode 100 = -keycode 101 = Application -keycode 102 = -keycode 103 = -keycode 104 = F13 -keycode 105 = F14 - -# modifiers -keycode 224 = Control -keycode 225 = Shift -keycode 226 = Alt -keycode 227 = Window -keycode 228 = Control_R -keycode 229 = Shift_R -keycode 230 = Alt_R -keycode 231 = Window_R diff --git a/drivers/usb/mkmap b/drivers/usb/mkmap deleted file mode 100644 index 35808f227cca..000000000000 --- a/drivers/usb/mkmap +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl - -($ME = $0) =~ s|.*/||; - -$file = "maps/serial.map"; -$line = 1; -open(PC, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*(\S+)/) - { - my($idx) = int($1); - my($sym) = $2; - if(defined($map{uc($sym)})) - { - # print STDERR "$file:$line: warning: `$sym' redefined\n"; - } - $map{uc($sym)} = $idx; - } - $line++; -} -close(PC); - -$file = "maps/fixup.map"; -$line = 1; -open(FIXUP, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*/) - { - my($idx) = int($1); - for $sym (split(/\s+/, $')) - { - $map{uc($sym)} = $idx; - } - } - $line++; -} -close(FIXUP); - -$file = "maps/usb.map"; -$line = 1; -open(USB, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*/) - { - my($idx) = int($1); - for $sym (split(/\s+/, $')) - { - my($val) = $map{uc($sym)}; - $map[$idx] = $val; - if(!defined($val)) - { - print STDERR "$file:$line: warning: `$sym' undefined\n"; - } - else - { - last; - } - } - } - $line++; -} -close(USB); - -print "unsigned char usb_kbd_map[256] = \n{\n"; -for($x = 0; $x < 32; $x++) -{ - if($x && !($x % 2)) - { - print "\n"; - } - print " "; - for($y = 0; $y < 8; $y++) - { - my($idx) = $x * 8 + $y; - print sprintf(" 0x%02x,", - int(defined($map[$idx]) ? $map[$idx]:0)); - } - print "\n"; -} -print "};\n"; diff --git a/drivers/usb/mkmap.adb b/drivers/usb/mkmap.adb deleted file mode 100644 index 45020d5ccdfc..000000000000 --- a/drivers/usb/mkmap.adb +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/perl - -($ME = $0) =~ s|.*/||; - -$file = "maps/mac.map"; -$line = 1; -open(PC, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+|0x[0-9a-fA-F]+)\s*=\s*(\S+)/) - { - my($idx) = $1; - my($sym) = $2; - if ($idx =~ "0x.*") { - $idx = hex($idx); - } else { - $idx = int($idx); - } - if(defined($map{uc($sym)})) - { - # print STDERR "$file:$line: warning: `$sym' redefined\n"; - } - $map{uc($sym)} = $idx; - } - $line++; -} -close(PC); - -# $file = "maps/fixup.map"; -# $line = 1; -# open(FIXUP, $file) || die("$!"); -# while() -# { -# if(/^\s*keycode\s+(\d+)\s*=\s*/) -# { -# my($idx) = int($1); -# for $sym (split(/\s+/, $')) -# { -# $map{uc($sym)} = $idx; -# } -# } -# $line++; -# } -# close(FIXUP); - -$file = "maps/usb.map"; -$line = 1; -open(USB, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*/) - { - my($idx) = int($1); - for $sym (split(/\s+/, $')) - { - my($val) = $map{uc($sym)}; - $map[$idx] = $val; - if(!defined($val)) - { - print STDERR "$file:$line: warning: `$sym' undefined\n"; - } - else - { - last; - } - } - } - $line++; -} -close(USB); - -print "unsigned char usb_kbd_map[256] = \n{\n"; -for($x = 0; $x < 32; $x++) -{ - if($x && !($x % 2)) - { - print "\n"; - } - print " "; - for($y = 0; $y < 8; $y++) - { - my($idx) = $x * 8 + $y; - print sprintf(" 0x%02x,", - int(defined($map[$idx]) ? $map[$idx]:0)); - } - print "\n"; -} -print "};\n"; diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c deleted file mode 100644 index e1760b25ca35..000000000000 --- a/drivers/usb/mouse.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * USB HID boot protocol mouse support based on MS BusMouse driver, psaux - * driver, and Linus's skeleton USB mouse driver. Fixed up a lot by Linus. - * - * Brad Keryan 4/3/1999 - * - * version 0.? Georg Acher 1999/10/30 - * URBification for UHCI-Acher/Fliegl/Sailer - * - * version 0.30? Paul Ashton 1999/08/19 - Fixed behaviour on mouse - * disconnect and suspend/resume. Added module parameter "force=1" - * to allow opening of the mouse driver before mouse has been plugged - * in (enables consistent XF86Config settings). Fixed module use count. - * Documented missing blocking/non-blocking read handling (not fixed). - * - * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it - * correctly. Events are added together, not queued, to keep the rodent sober. - * - * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events. - * This is wrong: when an application (like X or gpm) reads the mouse device, - * it wants to find out the mouse's current position, not its recent history. - * The button thing turned out to be UHCI not flipping data toggle, so half the - * packets were thrown out. - * - * version 0.01: Switched over to busmouse protocol, and changed the minor - * number to 32 (same as uusbd's hidbp driver). Buttons work more sanely now, - * but it still doesn't generate button events unless you move the mouse. - * - * version 0.0: Driver emulates a PS/2 mouse, stealing /dev/psaux (sorry, I - * know that's not very nice). Moving in the X and Y axes works. Buttons don't - * work right yet: X sees a lot of MotionNotify/ButtonPress/ButtonRelease - * combos when you hold down a button and drag the mouse around. Probably has - * some additional bugs on an SMP machine. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include - -#include "usb.h" - -#define MODSTR "mouse.c: " - - -struct mouse_state { - unsigned char buttons; /* current button state */ - long dx; /* dx, dy, dz are change since last read */ - long dy; - long dz; - int present; /* this mouse is plugged in */ - int active; /* someone is has this mouse's device open */ - int ready; /* the mouse has changed state since the last read */ - int suspended; /* mouse disconnected */ - wait_queue_head_t wait; /* for polling */ - struct fasync_struct *fasync; - /* later, add a list here to support multiple mice */ - /* but we will also need a list of file pointers to identify it */ - - /* FIXME: move these to a per-mouse structure */ - struct usb_device *dev; /* host controller this mouse is on */ - void* irq_handle; /* host controller's IRQ transfer handle */ - char* buffer; - urb_t* urb; - __u8 bEndpointAddress; /* these are from the endpoint descriptor */ - __u8 bInterval; /* ... used when calling usb_request_irq */ -}; - -static struct mouse_state static_mouse_state; - -spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED; - -static int force=0; /* allow the USB mouse to be opened even if not there (yet) */ -MODULE_PARM(force,"i"); -int xxx=0; - -//static int mouse_irq(int state, void *__buffer, int len, void *dev_id) -static void mouse_irq(urb_t *urb) -{ - signed char *data = urb->transfer_buffer; - int state=urb->status; - int len=urb->actual_length; - /* finding the mouse is easy when there's only one */ - struct mouse_state *mouse = urb->context; - - if (state) - printk(KERN_DEBUG "%s(%d):state %d, bp %p, len %d\n", - __FILE__, __LINE__, state, data, len); - //printk("mouseirq: %i\n",xxx++); - /* - * USB_ST_NOERROR is the normal case. - * USB_ST_REMOVED occurs if mouse disconnected or suspend/resume - * USB_ST_INTERNALERROR occurs if system suspended then mouse removed - * followed by resume. On UHCI could then occur every second - * In both cases, suspend the mouse - * On other states, ignore - */ - switch (state) { - case USB_ST_REMOVED: - case USB_ST_INTERNALERROR: - printk(KERN_DEBUG "%s(%d): Suspending\n", - __FILE__, __LINE__); - mouse->suspended = 1; - // FIXME stop interrupt! - return; - case USB_ST_NOERROR: break; - default: - return; /* ignore */ - } - - /* if a mouse moves with no one listening, do we care? no */ - if(!mouse->active) - return; - - /* if the USB mouse sends an interrupt, then something noteworthy - must have happened */ - - mouse->buttons = data[0] & 0x0f; - mouse->dx += data[1]; /* data[] is signed, so this works */ - mouse->dy -= data[2]; /* y-axis is reversed */ - mouse->dz -= data[3]; - mouse->ready = 1; - - add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + - (mouse->dy << 8) + mouse->dx); - - wake_up_interruptible(&mouse->wait); - if (mouse->fasync) -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,20) - kill_fasync(mouse->fasync, SIGIO, POLL_IN); -#else - kill_fasync(mouse->fasync, SIGIO); -#endif - return; -} - -static int fasync_mouse(int fd, struct file *filp, int on) -{ - int retval; - struct mouse_state *mouse = &static_mouse_state; - - retval = fasync_helper(fd, filp, on, &mouse->fasync); - if (retval < 0) - return retval; - return 0; -} - -static int release_mouse(struct inode * inode, struct file * file) -{ - struct mouse_state *mouse = &static_mouse_state; - - fasync_mouse(-1, file, 0); - - printk(KERN_DEBUG "%s(%d): MOD_DEC\n", __FILE__, __LINE__); - MOD_DEC_USE_COUNT; - - if (--mouse->active == 0) { - mouse->suspended = 0; - /* stop polling the mouse while its not in use */ - usb_unlink_urb(mouse->urb); - } - - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - struct mouse_state *mouse = &static_mouse_state; - int ret; - unsigned int pipe; - - printk(KERN_DEBUG "%s(%d): open_mouse\n", __FILE__, __LINE__); - /* - * First open may fail since mouse_probe() may get called after this - * if module load is in response to the open - * mouse_probe() sets mouse->present. This open can be delayed by - * specifying force=1 in module load - * This helps if you want to insert the USB mouse after starting X - */ - if (!mouse->present) - { - if (force) /* always load the driver even if no mouse (yet) */ - { - printk(KERN_DEBUG "%s(%d): forced open\n", - __FILE__, __LINE__); - mouse->suspended = 1; - } - else - return -EINVAL; - } - - /* prevent the driver from being unloaded while its in use */ - printk(KERN_DEBUG "%s(%d): MOD_INC\n", __FILE__, __LINE__); - /* Increment use count even if already active */ - MOD_INC_USE_COUNT; - - if (mouse->active++) - return 0; - /* flush state */ - mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0; - - if (!mouse->present) /* only get here if force == 1 */ - return 0; - - /* start the usb controller's polling of the mouse */ - pipe = usb_rcvintpipe(mouse->dev, mouse->bEndpointAddress); - FILL_INT_URB(mouse->urb,mouse->dev,pipe, - mouse->buffer, - usb_maxpacket(mouse->urb->dev, pipe, usb_pipeout(pipe)), - mouse_irq,mouse,mouse->bInterval); - - ret=usb_submit_urb(mouse->urb); - - // ret = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), - // mouse_irq, mouse->bInterval, - // NULL, &mouse->irq_handle); - if (ret) { - printk (KERN_WARNING "usb-mouse: usb_submit_urb(INT) failed (0x%x)\n", ret); - MOD_DEC_USE_COUNT; - return ret; - } - return 0; -} - -static ssize_t write_mouse(struct file * file, - const char * buffer, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -/* - * Look like a PS/2 mouse, please.. - * In XFree86 (3.3.5 tested) you must select Protocol "NetMousePS/2", - * then use your wheel as Button 4 and 5 via ZAxisMapping 4 5. - * The PS/2 protocol is fairly strange, but - * oh, well, it's at least common.. - */ -static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - int retval = 0; - static int state = 0; - struct mouse_state *mouse = &static_mouse_state; - - if (!mouse->present) - return 0; - - if (!mouse->ready) { - if (file->f_flags & O_NONBLOCK) return -EAGAIN; - - add_wait_queue(&mouse->wait, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (!mouse->ready && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&mouse->wait, &wait); - } - if (signal_pending(current)) return -ERESTARTSYS; - - if (!mouse->present) - return 0; - if (count) { - mouse->ready = 0; - switch (state) { - case 0: { /* buttons and sign */ - int buttons = mouse->buttons; - mouse->buttons = 0; - if (mouse->dx < 0) - buttons |= 0x10; - if (mouse->dy < 0) - buttons |= 0x20; - put_user(buttons, buffer); - buffer++; - retval++; - state = 1; - if (!--count) - break; - } - case 1: { /* dx */ - int dx = mouse->dx; - mouse->dx = 0; - put_user(dx, buffer); - buffer++; - retval++; - state = 2; - if (!--count) - break; - } - case 2: { /* dy */ - int dy = mouse->dy; - mouse->dy = 0; - put_user(dy, buffer); - buffer++; - retval++; - state = 0; - if (!--count) - break; - } - - /* - * SUBTLE: - * - * The only way to get here is to do a read() of - * more than 3 bytes: if you read a byte at a time - * you will just ever see states 0-2, for backwards - * compatibility. - * - * So you can think of this as a packet interface, - * where you have arbitrary-sized packets, and you - * only ever see the first three bytes when you read - * them in small chunks. - */ - { /* fallthrough - dz */ - int dz = mouse->dz; - mouse->dz = 0; - put_user(dz, buffer); - buffer++; - retval++; - state = 0; - } - break; - } - } - return retval; -} - -static unsigned int mouse_poll(struct file *file, poll_table * wait) -{ - struct mouse_state *mouse = &static_mouse_state; - - poll_wait(file, &mouse->wait, wait); - if (mouse->ready) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations usb_mouse_fops = { - NULL, /* mouse_seek */ - read_mouse, - write_mouse, - NULL, /* mouse_readdir */ - mouse_poll, /* mouse_poll */ - NULL, /* mouse_ioctl */ - NULL, /* mouse_mmap */ - open_mouse, - NULL, /* flush */ - release_mouse, - NULL, - fasync_mouse, -}; - - void* mouse_probe(struct usb_device *dev,unsigned int ifnum) -{ - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - struct mouse_state *mouse = &static_mouse_state; - int ret; - unsigned int pipe; - - printk("mouse probe for if %i\n",ifnum); - /* Is it a mouse interface? */ - interface = &dev->actconfig->interface[ifnum].altsetting[0]; - if (interface->bInterfaceClass != 3) - return NULL; - if (interface->bInterfaceSubClass != 1) - return NULL; - if (interface->bInterfaceProtocol != 2) - return NULL; - - /* Multiple endpoints? What kind of mutant ninja-mouse is this? */ - if (interface->bNumEndpoints != 1) - return NULL; - - endpoint = &interface->endpoint[0]; - - /* Output endpoint? Curiousier and curiousier.. */ - if (!(endpoint->bEndpointAddress & 0x80)) - return NULL; - - /* If it's not an interrupt endpoint, we'd better punt! */ - if ((endpoint->bmAttributes & 3) != 3) - return NULL; - - printk("USB mouse found\n"); - - /* these are used to request the irq when the mouse is opened */ - mouse->dev = dev; - mouse->bEndpointAddress = endpoint->bEndpointAddress; - mouse->bInterval = endpoint->bInterval; - - mouse->present = 1; - - /* This appears to let USB mouse survive disconnection and */ - /* APM suspend/resume */ - if (mouse->suspended) - { - printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__); - /* restart the usb controller's polling of the mouse */ - - pipe = usb_rcvintpipe(mouse->dev, mouse->bEndpointAddress); - FILL_INT_URB(mouse->urb,mouse->dev,pipe, - mouse->buffer, - usb_maxpacket(mouse->urb->dev, pipe, usb_pipeout(pipe)), - mouse_irq,mouse,mouse->bInterval); - - ret=usb_submit_urb(mouse->urb); - if (ret) { - printk (KERN_WARNING "usb-mouse: usb_submit_urb(INT) failed (0x%x)\n", ret); - return NULL; - } - mouse->suspended = 0; - } - - printk("mouse probe2\n"); - return mouse; -} - -static void mouse_disconnect(struct usb_device *dev, void *priv) -{ - struct mouse_state *mouse = priv; - - /* stop the usb interrupt transfer */ - if (mouse->present) { - usb_unlink_urb(mouse->urb); - wake_up(&mouse->wait); - } - - /* this might need work */ - mouse->present = 0; - printk("Mouse disconnected\n"); -} - -static struct usb_driver mouse_driver = { - "mouse", - mouse_probe, - mouse_disconnect, - { NULL, NULL }, - &usb_mouse_fops, - 16 -}; - -int usb_mouse_init(void) -{ - struct mouse_state *mouse = &static_mouse_state; - - mouse->present = mouse->active = mouse->suspended = 0; - mouse->buffer=kmalloc(64,GFP_KERNEL); - - if (!mouse->buffer) - return -ENOMEM; - mouse->urb=usb_alloc_urb(0); - if (!mouse->urb) - printk(KERN_DEBUG MODSTR"URB allocation failed\n"); - - init_waitqueue_head(&mouse->wait); - mouse->fasync = NULL; - - if (usb_register(&mouse_driver)<0) - return -1; - - printk(KERN_INFO "USB HID boot protocol mouse driver registered.\n"); - return 0; -} - -void usb_mouse_cleanup(void) -{ - struct mouse_state *mouse = &static_mouse_state; - - /* stop the usb interrupt transfer */ - if (mouse->present) { - usb_unlink_urb(mouse->urb); - } - kfree(mouse->urb); - kfree(mouse->buffer); - /* this, too, probably needs work */ - usb_deregister(&mouse_driver); -} - -#ifdef MODULE -int init_module(void) -{ - return usb_mouse_init(); -} - -void cleanup_module(void) -{ - usb_mouse_cleanup(); -} -#endif diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c new file mode 100644 index 000000000000..c0ed6b8c3090 --- /dev/null +++ b/drivers/usb/mousedev.c @@ -0,0 +1,457 @@ +/* + * mousedev.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Input driver to PS/2 or ImPS/2 device driver module. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#define MOUSEDEV_MINOR_BASE 32 + +#include +#include +#include +#include +#include +#include +#include + +struct mousedev { + char name[32]; + int used; + struct input_handle handle; + struct miscdevice misc; + wait_queue_head_t wait; + struct mousedev_list *list; +}; + +struct mousedev_list { + struct fasync_struct *fasync; + struct mousedev *mousedev; + struct mousedev_list *next; + int dx, dy, dz; + unsigned char ps2[6]; + unsigned char buttons; + unsigned char ready, buffer, bufsiz; + unsigned char mode, genseq, impseq; +}; + +#define MOUSEDEV_GENIUS_LEN 5 +#define MOUSEDEV_IMPS_LEN 6 + +static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 }; +static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; + +#ifdef CONFIG_INPUT_MOUSEDEV_MIX +static struct mousedev mousedev_single; +#else +static unsigned long mousedev_miscbits = 0; +static struct mousedev *mousedev_base[BITS_PER_LONG]; +#endif + +static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct mousedev *mousedev = handle->private; + struct mousedev_list *list = mousedev->list; + int index; + + while (list) { + switch (type) { + case EV_REL: + switch (code) { + case REL_X: list->dx += value; break; + case REL_Y: list->dy -= value; break; + case REL_WHEEL: if (list->mode) list->dz += value; break; + } + break; + + case EV_KEY: + switch (code) { + case BTN_LEFT: index = 0; break; + case BTN_EXTRA: if (list->mode > 1) { index = 4; break; } + case BTN_RIGHT: index = 1; break; + case BTN_SIDE: if (list->mode > 1) { index = 3; break; } + case BTN_MIDDLE: index = 2; break; + default: index = 0; + } + switch (value) { + case 0: clear_bit(index, &list->buttons); break; + case 1: set_bit(index, &list->buttons); break; + case 2: return; + } + break; + } + + list->ready = 1; + + if (list->fasync) + kill_fasync(list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&mousedev->wait); +} + +static int mousedev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct mousedev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int mousedev_release(struct inode * inode, struct file * file) +{ + struct mousedev_list *list = file->private_data; + struct mousedev_list **listptr = &list->mousedev->list; + + mousedev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + +#ifndef CONFIG_INPUT_MOUSEDEV_MIX + if (!--list->mousedev->used) { + clear_bit(list->mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits); + misc_deregister(&list->mousedev->misc); + kfree(list->mousedev); + } +#endif + + kfree(list); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int mousedev_open(struct inode * inode, struct file * file) +{ + struct mousedev_list *list; + +#ifndef CONFIG_INPUT_MOUSEDEV_MIX + int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; + if (i > BITS_PER_LONG || !test_bit(i, &mousedev_miscbits)) + return -ENODEV; +#endif + + if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) + return -ENOMEM; + + memset(list, 0, sizeof(struct mousedev_list)); + + +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + list->mousedev = &mousedev_single; + list->next = mousedev_single.list; + mousedev_single.list = list; +#else + list->mousedev = mousedev_base[i]; + list->next = mousedev_base[i]->list; + mousedev_base[i]->list = list; + list->mousedev->used++; +#endif + + file->private_data = list; + + MOD_INC_USE_COUNT; + return 0; +} + +static void mousedev_packet(struct mousedev_list *list, unsigned char off) +{ + list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); + list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); + list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy)); + list->dx = list->dy = 0; + list->bufsiz = off + 3; + + if (list->mode > 1) + list->ps2[off] |= ((list->buttons & 0x30) << 2); + + if (list->mode) { + list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); + list->bufsiz++; + list->dz = 0; + } + list->ready = 0; + list->buffer = list->bufsiz; +} + + +static ssize_t mousedev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + struct mousedev_list *list = file->private_data; + unsigned char c; + int i; + + for (i = 0; i < count; i++) { + + c = buffer[i]; + +#ifdef MOUSEDEV_DEBUG + printk(KERN_DEBUG "mousedev: received char %#x\n", c); +#endif + + if (c == mousedev_genius_seq[list->genseq]) { + if (++list->genseq == MOUSEDEV_GENIUS_LEN) { + list->genseq = 0; + list->ready = 1; + list->mode = 2; + } + } else list->genseq = 0; + + if (c == mousedev_imps_seq[list->impseq]) { + if (++list->impseq == MOUSEDEV_IMPS_LEN) { + list->impseq = 0; + list->ready = 1; + list->mode = 1; + } + } else list->impseq = 0; + + list->ps2[0] = 0xfa; + list->bufsiz = 1; + + switch (c) { + + case 0xeb: /* Poll */ + mousedev_packet(list, 1); + break; + + case 0xf2: /* Get ID */ + list->ps2[1] = (list->mode == 1) ? 3 : 0; + list->bufsiz = 2; + break; + + case 0xe9: /* Get info */ + if (list->mode == 2) { + list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55; + } else { + list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; + } + list->bufsiz = 4; + break; + } + + list->buffer = list->bufsiz; + } + + if (list->fasync) + kill_fasync(list->fasync, SIGIO, POLL_IN); + + wake_up_interruptible(&list->mousedev->wait); + + return count; +} + +static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct mousedev_list *list = file->private_data; + int retval = 0; + + if (!list->ready && !list->buffer) { + + add_wait_queue(&list->mousedev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (!list->ready) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->mousedev->wait, &wait); + } + + if (retval) + return retval; + + if (!list->buffer) + mousedev_packet(list, 0); + + if (count > list->buffer) + count = list->buffer; + + if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer, count)) + return -EFAULT; + + list->buffer -= count; + + return count; +} + +static unsigned int mousedev_poll(struct file *file, poll_table *wait) +{ + struct mousedev_list *list = file->private_data; + poll_wait(file, &list->mousedev->wait, wait); + if (list->ready || list->buffer) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations mousedev_fops = { + read: mousedev_read, + write: mousedev_write, + poll: mousedev_poll, + open: mousedev_open, + release: mousedev_release, + fasync: mousedev_fasync, +}; + +static int mousedev_connect(struct input_handler *handler, struct input_dev *dev) +{ + + if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_REL, dev->evbit))) /* The device must have both rels and keys */ + return -1; + + if (!(test_bit(REL_X, dev->relbit) && test_bit(REL_Y, dev->relbit))) /* It must be a pointer device */ + return -1; + + if (!test_bit(BTN_LEFT, dev->keybit)) /* And have at least one mousebutton */ + return -1; + +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + { + struct input_handle *handle; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return -1; + + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + handle->private = &mousedev_single; + + input_open_device(handle); + + printk("mousedev.c: Adding mouse: input%d\n", dev->number); + } +#else + { + struct mousedev *mousedev; + + if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL))) + return -1; + + memset(mousedev, 0, sizeof(struct mousedev)); + + mousedev->misc.minor = ffz(mousedev_miscbits); + set_bit(mousedev->misc.minor, &mousedev_miscbits); + mousedev_base[mousedev->misc.minor] = mousedev; + + sprintf(mousedev->name, "mousedev%d", mousedev->misc.minor); + mousedev->misc.name = mousedev->name; + mousedev->misc.minor += MOUSEDEV_MINOR_BASE; + mousedev->misc.fops = &mousedev_fops; + + mousedev->handle.dev = dev; + mousedev->handle.handler = handler; + mousedev->handle.private = mousedev; + + init_waitqueue_head(&mousedev->wait); + + mousedev->used = 1; + + misc_register(&mousedev->misc); + input_open_device(&mousedev->handle); + + printk("%s: PS/2 mouse device for input%d on misc%d\n", + mousedev->name, dev->number, mousedev->misc.minor); + } +#endif + + return 0; +} + +static void mousedev_disconnect(struct input_handle *handle) +{ +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + printk("mousedev.c: Removing mouse: input%d\n", handle->dev->number); + input_close_device(handle); + kfree(handle); +#else + struct mousedev *mousedev = handle->private; + input_close_device(handle); + if (!--mousedev->used) { + clear_bit(mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits); + misc_deregister(&mousedev->misc); + kfree(mousedev); + } +#endif +} + +static struct input_handler mousedev_handler = { + event: mousedev_event, + connect: mousedev_connect, + disconnect: mousedev_disconnect, +}; + + +#ifdef MODULE +int init_module(void) +#else +int __init mousedev_init(void) +#endif +{ + input_register_handler(&mousedev_handler); + +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + memset(&mousedev_single, 0, sizeof(struct mousedev)); + + init_waitqueue_head(&mousedev_single.wait); + mousedev_single.misc.minor = MOUSEDEV_MINOR_BASE; + mousedev_single.misc.name = "mousedev"; + mousedev_single.misc.fops = &mousedev_fops; + + misc_register(&mousedev_single.misc); + + printk("mousedev: PS/2 mouse device on misc%d\n", mousedev_single.misc.minor); +#endif + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + misc_deregister(&mousedev_single.misc); +#endif + + input_unregister_handler(&mousedev_handler); +} +#endif diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c new file mode 100644 index 000000000000..e9ea434bd76a --- /dev/null +++ b/drivers/usb/ov511.c @@ -0,0 +1,1241 @@ +/* + * OmniVision OV511 Camera-to-USB Bridge Driver + * Copyright 1999 Mark W. McClelland + * + * Based on the Linux CPiA driver. + * + * Released under GPL v.2 license. + * + * Important keywords in comments: + * CAMERA SPECIFIC - Camera specific code; may not work with other cameras. + * DEBUG - Debugging code. + * FIXME - Something that is broken or needs improvement. + * + * Version History: + * Version 1.00 - Initial version + */ + + +#define __NO_VERSION__ + +/* Handle mangled (versioned) external symbols */ + +#include /* retrieve the CONFIG_* macros */ +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +# define MODVERSIONS /* force it on */ +#endif + +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb.h" +#include "ov511.h" + +/* Video Size 384 x 288 x 3 bytes for RGB */ +#define MAX_FRAME_SIZE (384 * 288 * 3) + +// FIXME - Force CIF to make some apps happy for the moment. Should find a +// better way to do this. +#define DEFAULT_WIDTH 384 +#define DEFAULT_HEIGHT 288 + +char kernel_version[] = UTS_RELEASE; + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +static struct usb_driver ov511_driver; + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if (pte_present(pte)) + ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1)); + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + unsigned long kva, ret; + + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; +} + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr, page; + + /* Round it off to PAGE_SIZE */ + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + mem = vmalloc(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_reserve(MAP_NR(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr, page; + + if (!mem) + return; + + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + adr=(unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_unreserve(MAP_NR(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + vfree(mem); +} + +int usb_ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +{ + int rc; + + rc = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 2 /* REG_IO */, + USB_TYPE_CLASS | USB_RECIP_DEVICE, + 0, (__u16)reg, &value, 1, HZ); + + PDEBUG("reg write: 0x%X:0x%X\n", reg, value); + + return rc; +} + +/* returns: negative is error, pos or zero is data */ +int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg) +{ + int rc; + unsigned char buffer[1]; + + rc = usb_control_msg(dev, + usb_rcvctrlpipe(dev, 0), + 2 /* REG_IO */, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, + 0, (__u16)reg, buffer, 1, HZ); + + PDEBUG("reg read: 0x%X:0x%X\n", reg, buffer[0]); + + if(rc < 0) + return rc; + else + return buffer[0]; +} + +int usb_ov511_cam_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +{ + int rc; + + // Three byte write cycle + + // Set slave ID (This might only need to be done once) + // (CAMERA SPECIFIC (OV7610/OV7110)) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, + OV7610_I2C_WRITE_ID); + if (rc < 0) return rc; + + // Select camera register (I2C sub-address) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); + if (rc < 0) return rc; + + // Write "value" to I2C data port of OV511 + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + if (rc < 0) return rc; + + // FIXME - should ensure bus is idle before continuing + + // Initiate 3-byte write cycle + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); + + return rc; +} + +/* returns: negative is error, pos or zero is data */ +int usb_ov511_cam_reg_read(struct usb_device *dev, unsigned char reg) +{ + int rc; + + // Two byte write cycle + + // Set slave ID (This might only need to be done once) + // (CAMERA SPECIFIC (OV7610/OV7110)) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, OV7610_I2C_WRITE_ID); + if (rc < 0) return rc; + + // Select camera register (I2C sub-address) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + if (rc < 0) return rc; + + // Initiate 2-byte write cycle + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); + if (rc < 0) return rc; + + // Two byte read cycle + + // Set slave ID (This might only need to be done once) + // (CAMERA SPECIFIC (OV7610/OV7110)) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, + OV7610_I2C_READ_ID); + if (rc < 0) return rc; + + // Initiate 2-byte read cycle + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + if (rc < 0) return rc; + + // FIXME - should check I2C bus status here before reading data! + + // Write "value" to I2C data port of OV511 + return usb_ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); +} + +int usb_ov511_reset(struct usb_device *dev, unsigned char reset_type) +{ + int rc; + + PDEBUG("Reset: type=0x%X\n", reset_type); + rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type); + if (rc < 0) + printk(KERN_ERR "ov511: reset: command failed\n"); + + rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0); + if (rc < 0) + printk(KERN_ERR "ov511: reset: command failed\n"); + + return rc; +} + +int usb_ov511_set_packet_size(struct usb_ov511 *ov511, int size) +{ + int alt, multiplier, err; + + PDEBUG("set packet size: %d\n", size); + + switch (size) { + case 992: + alt = 0; + multiplier = 31; + break; + case 993: + alt = 1; + multiplier = 32; + break; + case 768: + alt = 2; + multiplier = 24; + break; + case 769: + alt = 3; + multiplier = 25; + break; + case 512: + alt = 4; + multiplier = 16; + break; + case 513: + alt = 5; + multiplier = 17; + break; + case 257: + alt = 6; + multiplier = 9; + break; + case 0: + alt = 7; + multiplier = 1; // FIXME - is this correct? + break; + default: + printk(KERN_ERR "ov511_set_packet_size: invalid size (%d)\n", + size); + return -EINVAL; + } + + err = usb_ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, + multiplier); + if (err < 0) { + printk(KERN_ERR "ov511: Set packet size: Set FIFO size ret %d\n", + err); + return -ENOMEM; + } + + if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) { + printk(KERN_ERR "ov511: Set packet size: set interface error\n"); + return -EBUSY; + } + + // FIXME - Should we only reset the FIFO? + if (usb_ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0) + return -ENOMEM; + + return 0; +} + +/* How much data is left in the scratch buf? */ +#define scratch_left(x) (ov511->scratchlen - (int)((char *)x - (char *)ov511->scratch)) + +// FIXME - Useless stub +static void ov511_parse_data(struct usb_ov511 *ov511) +{ + PDEBUG("ov511_parse_data not implemented\n"); // TEMPORARY CODE +} + +static int ov511_compress_isochronous(struct usb_ov511 *ov511, urb_t *urb) +{ + unsigned char *cdata, *data; + int i, totlen = 0; + + data = ov511->scratch + ov511->scratchlen; + for (i = 0; i < urb->number_of_packets; i++) { + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (st) { + // Macro - must be in braces! + PDEBUG("data error: [%d] len=%d, status=%d\n", + i, n, st); + } + + if ((ov511->scratchlen + n) > SCRATCH_BUF_SIZE) { + PDEBUG("scratch buf overflow!scr_len: %d, n: %d\n", ov511->scratchlen, n ); + return totlen; + } + + if (n) { + memmove(data, cdata, n); + data += n; + totlen += n; + ov511->scratchlen += n; + } + } + + return totlen; +} + +static void ov511_isoc_irq(struct urb *urb) +{ + int len; + struct usb_ov511 *ov511 = urb->context; + struct ov511_sbuf *sbuf; + int i; + + PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length); + + if (!ov511->streaming) { + PDEBUG("hmmm... not streaming, but got interrupt\n"); + return; + } + + sbuf = &ov511->sbuf[ov511->cursbuf]; +// usb_kill_isoc(sbuf->isodesc); + + /* Copy the data received into our scratch buffer */ + len = ov511_compress_isochronous(ov511, urb); + + /* If we don't have a frame we're current working on, complain */ + if (ov511->scratchlen) { + if (ov511->curframe < 0) { + // Macro - must be in braces!! + PDEBUG("received data, but no frame available\n"); + } else + ov511_parse_data(ov511); + } + + for (i = 0; i < FRAMES_PER_DESC; i++) { + sbuf->urb->iso_frame_desc[i].status = 0; + sbuf->urb->iso_frame_desc[i].actual_length = 0; + } + + /* Move to the next sbuf */ + ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF; + + /* Reschedule this block of Isochronous desc */ +// usb_run_isoc(sbuf->isodesc, ov511->sbuf[ov511->cursbuf].isodesc); + + return; +} + +static int ov511_init_isoc(struct usb_ov511 *ov511) +{ + struct usb_device *dev = ov511->dev; + urb_t *urb; + int fx, err; + + ov511->compress = 0; + ov511->curframe = -1; + ov511->cursbuf = 0; + ov511->scratchlen = 0; + + // FIXME - is this the proper size? + usb_ov511_set_packet_size(ov511, 512); + + /* We double buffer the Iso lists */ + urb = usb_alloc_urb(FRAMES_PER_DESC); + + if (!urb) { + printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); + return -ENOMEM; + } + ov511->sbuf[0].urb = urb; + urb->dev = dev; + urb->context = ov511; + urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ov511->sbuf[0].data; + urb->complete = ov511_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + urb = usb_alloc_urb(FRAMES_PER_DESC); + if (!urb) { + printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); + return -ENOMEM; + } + ov511->sbuf[1].urb = urb; + urb->dev = dev; + urb->context = ov511; + urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ov511->sbuf[1].data; + urb->complete = ov511_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + ov511->sbuf[1].urb->next = ov511->sbuf[0].urb; + ov511->sbuf[0].urb->next = ov511->sbuf[1].urb; + + err = usb_submit_urb(ov511->sbuf[0].urb); + if (err) + printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(0) ret %d\n", + err); + err = usb_submit_urb(ov511->sbuf[1].urb); + if (err) + printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(1) ret %d\n", + err); + + ov511->streaming = 1; + + return 0; +} + + +static void ov511_stop_isoc(struct usb_ov511 *ov511) +{ + if (!ov511->streaming) + return; + +// FIXME - Figure out how to do this with the ov511 (Does the below do it?) +// /* Turn off continuous grab */ +// if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) { +// printk(KERN_ERR "cpia_set_grab_mode error\n"); +// return /* -EBUSY */; +// } + + usb_ov511_set_packet_size(ov511, 0); + + /* Unschedule all of the iso td's */ + usb_unlink_urb(ov511->sbuf[1].urb); + usb_unlink_urb(ov511->sbuf[0].urb); + + ov511->streaming = 0; + + /* Delete them all */ + usb_free_urb(ov511->sbuf[1].urb); + usb_free_urb(ov511->sbuf[0].urb); +} + +static int ov511_new_frame(struct usb_ov511 *ov511, int framenum) +{ + struct ov511_frame *frame; + int width, height; + + /* If we're not grabbing a frame right now and the other frame is */ + /* ready to be grabbed into, then use it instead */ + if (ov511->curframe == -1) { + if (ov511->frame[(framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES].grabstate == FRAME_READY) + framenum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; + } else + return 0; + + frame = &ov511->frame[framenum]; + width = frame->width; + height = frame->height; + + frame->grabstate = FRAME_GRABBING; + frame->scanstate = STATE_SCANNING; + frame->scanlength = 0; /* accumulated in ov511_parse_data() */ + + ov511->curframe = framenum; + + /* Make sure it's not too big */ + if (width > DEFAULT_WIDTH) + width = DEFAULT_WIDTH; + width = (width / 8) * 8; /* Multiple of 8 */ + + if (height > DEFAULT_HEIGHT) + height = DEFAULT_HEIGHT; + height = (height / 4) * 4; /* Multiple of 4 */ + +// FIXME - Don't know how to implement the equivalent of this for the ov511 +// /* Set the ROI they want */ +// if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0) +// return -EBUSY; + +// if (usb_cpia_set_compression(cpia->dev, cpia->compress ? +// COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) { +// printk(KERN_ERR "cpia_set_compression error\n"); +// return -EBUSY; +// } + + /* We want a fresh frame every 30 we get */ + ov511->compress = (ov511->compress + 1) % 30; + +// /* Grab the frame */ +// if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) { +// printk(KERN_ERR "cpia_upload_frame error\n"); +// return -EBUSY; +// } + + return 0; +} + + + +/* Video 4 Linux API */ +static int ov511_open(struct video_device *dev, int flags) +{ + int err = -EBUSY; + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + + PDEBUG("ov511_open\n"); + + down(&ov511->lock); + if (ov511->user) + goto out_unlock; + + ov511->frame[0].grabstate = FRAME_UNUSED; + ov511->frame[1].grabstate = FRAME_UNUSED; + + err = -ENOMEM; + + /* Allocate memory for the frame buffers */ + ov511->fbuf = rvmalloc(2 * MAX_FRAME_SIZE); + if (!ov511->fbuf) + goto open_err_ret; + + ov511->frame[0].data = ov511->fbuf; + ov511->frame[1].data = ov511->fbuf + MAX_FRAME_SIZE; + + PDEBUG("frame [0] @ %p\n", ov511->frame[0].data); + PDEBUG("frame [1] @ %p\n", ov511->frame[1].data); + + ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ov511->sbuf[0].data) + goto open_err_on0; + ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ov511->sbuf[1].data) + goto open_err_on1; + + PDEBUG("sbuf[0] @ %p\n", ov511->sbuf[0].data); + PDEBUG("sbuf[1] @ %p\n", ov511->sbuf[1].data); + + /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used + * (using read() instead). */ + ov511->frame[0].width = DEFAULT_WIDTH; + ov511->frame[0].height = DEFAULT_HEIGHT; + ov511->frame[0].bytes_read = 0; + ov511->frame[1].width = DEFAULT_WIDTH; + ov511->frame[1].height = DEFAULT_HEIGHT; + ov511->frame[1].bytes_read = 0; + + err = ov511_init_isoc(ov511); + if (err) + goto open_err_on2; + + ov511->user++; + up(&ov511->lock); + + MOD_INC_USE_COUNT; + + return 0; + +open_err_on2: + kfree (ov511->sbuf[1].data); +open_err_on1: + kfree (ov511->sbuf[0].data); +open_err_on0: + rvfree(ov511->fbuf, 2 * MAX_FRAME_SIZE); +open_err_ret: + return err; +out_unlock: + up(&ov511->lock); + return err; + +} + +static void ov511_close(struct video_device *dev) +{ + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + + PDEBUG("ov511_close\n"); + + down(&ov511->lock); + ov511->user--; + + MOD_DEC_USE_COUNT; + + ov511_stop_isoc(ov511); + + rvfree(ov511->fbuf, 2 * MAX_FRAME_SIZE); + + kfree(ov511->sbuf[1].data); + kfree(ov511->sbuf[0].data); + + up(&ov511->lock); +} + +static int ov511_init_done(struct video_device *dev) +{ + return 0; +} + +static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +// FIXME - Needs much work!!! +static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + + PDEBUG("IOCtl: 0x%X\n", cmd); + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + + strcpy(b.name, "OV511 USB Camera"); + b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = DEFAULT_WIDTH; + b.maxheight = DEFAULT_HEIGHT; + b.minwidth = 8; + b.minheight = 4; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.channel != 0) + return -EINVAL; + + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + strcpy(v.name, "Camera"); + + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCSCHAN: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v != 0) + return -EINVAL; + + return 0; + } + + case VIDIOCGPICT: + { + struct video_picture p; + + p.colour = 0x8000; /* Damn British people :) */ + p.hue = 0x8000; + p.brightness = 180 << 8; /* XXX */ + p.contrast = 192 << 8; /* XXX */ + p.whiteness = 105 << 8; /* XXX */ + p.depth = 24; + p.palette = VIDEO_PALETTE_RGB24; + + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) + return -EFAULT; + + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + + if (copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + if (vw.flags) + return -EINVAL; + if (vw.clipcount) + return -EINVAL; + if (vw.height != DEFAULT_HEIGHT) + return -EINVAL; + if (vw.width != DEFAULT_WIDTH) + return -EINVAL; + + ov511->compress = 0; + + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + + vw.x = 0; + vw.y = 0; + vw.width = DEFAULT_WIDTH; + vw.height = DEFAULT_HEIGHT; + vw.chromakey = 0; + vw.flags = 30; + + if (copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + + return 0; + } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + + memset(&vm, 0, sizeof(vm)); + vm.size = MAX_FRAME_SIZE * 2; + vm.frames = 2; + vm.offsets[0] = 0; + vm.offsets[1] = MAX_FRAME_SIZE; + + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + + return 0; + } + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) + return -EFAULT; + + PDEBUG("MCAPTURE\n"); + PDEBUG("frame: %d, size: %dx%d, format: %d\n", + vm.frame, vm.width, vm.height, vm.format); + + if (vm.format != VIDEO_PALETTE_RGB24) + return -EINVAL; + + if ((vm.frame != 0) && (vm.frame != 1)) + return -EINVAL; + + if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) + return -EBUSY; + + /* Don't compress if the size changed */ + if ((ov511->frame[vm.frame].width != vm.width) || + (ov511->frame[vm.frame].height != vm.height)) + ov511->compress = 0; + + ov511->frame[vm.frame].width = vm.width; + ov511->frame[vm.frame].height = vm.height; + + /* Mark it as ready */ + ov511->frame[vm.frame].grabstate = FRAME_READY; + + return ov511_new_frame(ov511, vm.frame); + } + case VIDIOCSYNC: + { + int frame; + + if (copy_from_user((void *)&frame, arg, sizeof(int))) + return -EFAULT; + + PDEBUG("syncing to frame %d\n", frame); + + switch (ov511->frame[frame].grabstate) { + case FRAME_UNUSED: + return -EINVAL; + case FRAME_READY: + case FRAME_GRABBING: + case FRAME_ERROR: +redo: + do { +#if 0 + init_waitqueue_head(&ov511->frame[frame].wq); +#endif + interruptible_sleep_on(&ov511->frame[frame].wq); + if (signal_pending(current)) + return -EINTR; + } while (ov511->frame[frame].grabstate == FRAME_GRABBING); + + if (ov511->frame[frame].grabstate == FRAME_ERROR) { + int ret; + + if ((ret = ov511_new_frame(ov511, frame)) < 0) + return ret; + goto redo; + } + case FRAME_DONE: + ov511->frame[frame].grabstate = FRAME_UNUSED; + break; + } + + ov511->frame[frame].grabstate = FRAME_UNUSED; + + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer vb; + + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; /* frame buffer not supported, not used */ + + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + return -EFAULT; + + return 0; + } + case VIDIOCKEY: + return 0; + case VIDIOCCAPTURE: + return -EINVAL; + case VIDIOCSFBUF: + return -EINVAL; + case VIDIOCGTUNER: + case VIDIOCSTUNER: + return -EINVAL; + case VIDIOCGFREQ: + case VIDIOCSFREQ: + return -EINVAL; + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock) +{ + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + int frmx = -1; + volatile struct ov511_frame *frame; + + PDEBUG("ov511_read: %ld bytes, noblock=%d\n", count, noblock); + + if (!dev || !buf) + return -EFAULT; + + /* See if a frame is completed, then use it. */ + if (ov511->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ + frmx = 0; + else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ + frmx = 1; + + if (noblock && (frmx == -1)) + return -EAGAIN; + + /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ + /* See if a frame is in process (grabbing), then use it. */ + if (frmx == -1) { + if (ov511->frame[0].grabstate == FRAME_GRABBING) + frmx = 0; + else if (ov511->frame[1].grabstate == FRAME_GRABBING) + frmx = 1; + } + + /* If no frame is active, start one. */ + if (frmx == -1) + ov511_new_frame(ov511, frmx = 0); + + frame = &ov511->frame[frmx]; + +restart: + while (frame->grabstate == FRAME_GRABBING) { + interruptible_sleep_on(&frame->wq); + if (signal_pending(current)) + return -EINTR; + } + + if (frame->grabstate == FRAME_ERROR) { + frame->bytes_read = 0; + printk(KERN_ERR "ov511_read: errored frame %d\n", ov511->curframe); + if (ov511_new_frame(ov511, frmx)) + printk(KERN_ERR "ov511_read: ov511_new_frame error\n"); + goto restart; + } + + PDEBUG("ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n", frmx, + frame->bytes_read, frame->scanlength); + + /* copy bytes to user space; we allow for partials reads */ + if ((count + frame->bytes_read) > frame->scanlength) + count = frame->scanlength - frame->bytes_read; + + if (copy_to_user(buf, frame->data + frame->bytes_read, count)) + return -EFAULT; + + frame->bytes_read += count; + PDEBUG("ov511_read: {copy} count used=%ld, new bytes_read=%ld\n", + count, frame->bytes_read); + + if (frame->bytes_read >= frame->scanlength) { /* All data has been read */ + frame->bytes_read = 0; + + /* Mark it as available to be used again. */ + ov511->frame[frmx].grabstate = FRAME_UNUSED; + if (ov511_new_frame(ov511, frmx ? 0 : 1)) + printk(KERN_ERR "ov511_read: ov511_new_frame returned error\n"); + } + + return count; +} + +static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + unsigned long start = (unsigned long)adr; + unsigned long page, pos; + + PDEBUG("mmap: %ld (%lX) bytes\n", size, size); + + if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) + return -EINVAL; + + pos = (unsigned long)ov511->fbuf; + while (size > 0) + { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return 0; +} + +// FIXME - needs V4L ID to be assigned +static struct video_device ov511_template = { + "OV511 USB Camera", + VID_TYPE_CAPTURE, + VID_HARDWARE_CPIA, /* FIXME */ + ov511_open, + ov511_close, + ov511_read, + ov511_write, + NULL, + ov511_ioctl, + ov511_mmap, + ov511_init_done, + NULL, + 0, + 0 +}; + +static int usb_ov511_configure(struct usb_ov511 *ov511) +{ + struct usb_device *dev = ov511->dev; + int temprc; // DEBUG CODE + + /* Set altsetting 0 */ + if (usb_set_interface(dev, ov511->iface, 0) < 0) { + printk(KERN_ERR "ov511: usb_set_interface error\n"); + return -EBUSY; + } + + memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); + + init_waitqueue_head(&ov511->frame[0].wq); + init_waitqueue_head(&ov511->frame[1].wq); + + if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) { + printk(KERN_ERR "ov511: video_register_device failed\n"); + return -EBUSY; + } + + // Disable compression + if (usb_ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) { + printk(KERN_ERR "ov511: disable compression: command failed\n"); + goto error; + } + + // Initialize system + // FIXME - This should be moved to a function + if (usb_ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) { + printk(KERN_ERR "ov511: enable system: command failed\n"); + goto error; + } + + if (usb_ov511_reset(dev, OV511_RESET_NOREGS) < 0) + goto error; + +// DEBUG - TEST CODE FOR CAMERA REG READ + temprc = usb_ov511_cam_reg_read(dev, 0x1D); + PDEBUG("Camera reg 0x1D: 0x%X\n", temprc); +// END DEBUG CODE + + ov511->compress = 0; + + return 0; + +error: + video_unregister_device(&ov511->vdev); + usb_driver_release_interface(&ov511_driver, + &dev->actconfig->interface[ov511->iface]); + + kfree(ov511); + + return -EBUSY; +} + +static void* ov511_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct usb_ov511 *ov511; + int rc; + + PDEBUG("probing for device...\n"); + + /* We don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) + return NULL; + + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + + /* Is it an OV511? */ + if (dev->descriptor.idVendor != 0x05a9) + return NULL; + if (dev->descriptor.idProduct != 0x0511) + return NULL; + + /* Checking vendor/product should be enough, but what the hell */ + if (interface->bInterfaceClass != 0xFF) + return NULL; + if (interface->bInterfaceSubClass != 0x00) + return NULL; + + /* We found one */ + printk(KERN_INFO "ov511: USB OV511-based camera found\n"); + + if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "ov511: couldn't kmalloc ov511 struct\n"); + return NULL; + } + + memset(ov511, 0, sizeof(*ov511)); + + ov511->dev = dev; + ov511->iface = interface->bInterfaceNumber; + + rc = usb_ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); + if (rc < 0) { + printk("ov511: Unable to read camera bridge registers\n"); + return NULL; + } else if (rc == 3) { // D-Link DSB-C300 + printk("ov511: Camera is a D-Link DSB-C300\n"); + ov511->customid = 3; + } else if (rc == 21) { // Creative Labs WebCam 3 + printk("ov511: Camera is a Creative Labs WebCam 3\n"); + ov511->customid = 21; + } else { + printk("ov511: Specific camera type (%d) not recognized\n", rc); + printk("ov511: Please contact mmcclelland@delphi.com to request\n"); + printk("ov511: support for your camera.\n"); + return NULL; + } + + // Reset in case driver was unloaded and reloaded without unplug + if (usb_ov511_reset(dev, OV511_RESET_ALL) < 0) + return NULL; + + if (!usb_ov511_configure(ov511)) { + ov511->user=0; + init_MUTEX(&ov511->lock); /* to 1 == available */ + return ov511; + } + else { + printk(KERN_ERR "ov511: Failed to configure camera\n"); + return NULL; + } + + return ov511; +} + +static void ov511_disconnect(struct usb_device *dev, void *ptr) +{ + + struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; + + video_unregister_device(&ov511->vdev); + + usb_driver_release_interface(&ov511_driver, + &ov511->dev->actconfig->interface[ov511->iface]); + + /* Free the memory */ + kfree(ov511); ov511 = NULL; +} + +static struct usb_driver ov511_driver = { + "ov511", + ov511_probe, + ov511_disconnect, + { NULL, NULL } +}; + +int usb_ov511_init(void) +{ + PDEBUG("usb_ov511_init()\n"); + + EXPORT_NO_SYMBOLS; + + return usb_register(&ov511_driver); +} + +void usb_ov511_cleanup(void) +{ + usb_deregister(&ov511_driver); +} + +#ifdef MODULE +int init_module(void) +{ + return usb_ov511_init(); +} + +void cleanup_module(void) +{ + usb_ov511_cleanup(); + + PDEBUG("Module unloaded\n"); +} +#endif + diff --git a/drivers/usb/ov511.h b/drivers/usb/ov511.h new file mode 100644 index 000000000000..0b85298027a4 --- /dev/null +++ b/drivers/usb/ov511.h @@ -0,0 +1,209 @@ +#ifndef __LINUX_OV511_H +#define __LINUX_OV511_H + +//#include + +#define OV511_DEBUG /* Turn on debug messages */ + +#ifdef OV511_DEBUG +# define PDEBUG(fmt, args...) printk("ov511: " fmt, ## args) +#else +# define PDEBUG(fmt, args...) /* Nothing */ +#endif + +/* Camera interface register numbers */ +#define OV511_REG_CAMERA_DELAY_MODE 0x10 +#define OV511_REG_CAMERA_EDGE_MODE 0x11 +#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM 0x12 +#define OV511_REG_CAMERA_CLAMPED_LINE_NUM 0x13 +#define OV511_REG_CAMERA_PIXEL_DIVISOR 0x14 +#define OV511_REG_CAMERA_LINE_DIVISOR 0x15 +#define OV511_REG_CAMERA_DATA_INPUT_SELECT 0x16 +#define OV511_REG_CAMERA_RESERVED_LINE_MODE 0x17 +#define OV511_REG_CAMERA_BITMASK 0x18 + +/* Snapshot mode camera interface register numbers */ +#define OV511_REG_SNAP_CAPTURED_FRAME 0x19 +#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM 0x1A +#define OV511_REG_SNAP_CLAMPED_LINE_NUM 0x1B +#define OV511_REG_SNAP_PIXEL_DIVISOR 0x1C +#define OV511_REG_SNAP_LINE_DIVISOR 0x1D +#define OV511_REG_SNAP_DATA_INPUT_SELECT 0x1E +#define OV511_REG_SNAP_BITMASK 0x1F + +/* DRAM register numbers */ +#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL 0x20 +#define OV511_REG_DRAM_READ_CYCLE_PREDICT 0x21 +#define OV511_REG_DRAM_MANUAL_READ_CYCLE 0x22 +#define OV511_REG_DRAM_REFRESH_COUNTER 0x23 + +/* ISO FIFO register numbers */ +#define OV511_REG_FIFO_PACKET_SIZE 0x30 +#define OV511_REG_FIFO_BITMASK 0x31 + +/* PIO register numbers */ +#define OV511_REG_PIO_BITMASK 0x38 +#define OV511_REG_PIO_DATA_PORT 0x39 +#define OV511_REG_PIO_BIST 0x3E + +/* I2C register numbers */ +#define OV511_REG_I2C_CONTROL 0x40 +#define OV511_REG_I2C_SLAVE_ID_WRITE 0x41 +#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE 0x42 +#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE 0x43 +#define OV511_REG_I2C_SLAVE_ID_READ 0x44 +#define OV511_REG_I2C_DATA_PORT 0x45 +#define OV511_REG_I2C_CLOCK_PRESCALER 0x46 +#define OV511_REG_I2C_TIME_OUT_COUNTER 0x47 + +/* I2C snapshot register numbers */ +#define OV511_REG_I2C_SNAP_SUB_ADDRESS 0x48 +#define OV511_REG_I2C_SNAP_DATA_PORT 0x49 + +/* System control register numbers */ +#define OV511_REG_SYSTEM_RESET 0x50 +#define OV511_RESET_UDC 0x01 +#define OV511_RESET_I2O 0x02 +#define OV511_RESET_FIFO 0x04 +#define OV511_RESET_OMNICE 0x08 +#define OV511_RESET_DRAM_INTF 0x10 +#define OV511_RESET_CAMERA_INTF 0x20 +#define OV511_RESET_OV511 0x40 +#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ +#define OV511_RESET_ALL 0x7F +#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51 +#define OV511_REG_SYSTEM_SNAPSHOT 0x52 +#define OV511_REG_SYSTEM_INIT 0x53 +#define OV511_REG_SYSTEM_USER_DEFINED 0x5E +#define OV511_REG_SYSTEM_CUSTOM_ID 0x5F + +/* OmniCE register numbers */ +#define OV511_OMNICE_PREDICATION_HORIZ_Y 0x70 +#define OV511_OMNICE_PREDICATION_HORIZ_UV 0x71 +#define OV511_OMNICE_PREDICATION_VERT_Y 0x72 +#define OV511_OMNICE_PREDICATION_VERT_UV 0x73 +#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74 +#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75 +#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76 +#define OV511_OMNICE_QUANTIZATION_VERT_UV 0x77 +#define OV511_OMNICE_ENABLE 0x78 +#define OV511_OMNICE_LUT_ENABLE 0x79 +#define OV511_OMNICE_Y_LUT_BEGIN 0x80 +#define OV511_OMNICE_Y_LUT_END 0x9F +#define OV511_OMNICE_UV_LUT_BEGIN 0xA0 +#define OV511_OMNICE_UV_LUT_END 0xBF + +/* Alternate numbers for various max packet sizes */ +#define OV511_ALTERNATE_SIZE_992 0 +#define OV511_ALTERNATE_SIZE_993 1 +#define OV511_ALTERNATE_SIZE_768 2 +#define OV511_ALTERNATE_SIZE_769 3 +#define OV511_ALTERNATE_SIZE_512 4 +#define OV511_ALTERNATE_SIZE_513 5 +#define OV511_ALTERNATE_SIZE_257 6 +#define OV511_ALTERNATE_SIZE_0 7 + + +#define STREAM_BUF_SIZE (PAGE_SIZE * 4) + +#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) + +#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ +#define FRAME_SIZE_PER_DESC 960 /* FIXME - Shouldn't be hardcoded */ + +// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)? +#define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */ + +// CAMERA SPECIFIC +// FIXME - these can vary between specific models +#define OV7610_I2C_WRITE_ID 0x42 +#define OV7610_I2C_READ_ID 0x43 + +/* Prototypes */ +int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg); +int usb_ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value); + + +enum { + STATE_SCANNING, /* Scanning for start */ + STATE_HEADER, /* Parsing header */ + STATE_LINES, /* Parsing lines */ +}; + +struct ov511_frame_header { + // FIXME - nothing here yet +}; + +struct usb_device; + +struct ov511_sbuf { + char *data; + urb_t *urb; +}; + +enum { + FRAME_UNUSED, /* Unused (no MCAPTURE) */ + FRAME_READY, /* Ready to start grabbing */ + FRAME_GRABBING, /* In the process of being grabbed into */ + FRAME_DONE, /* Finished grabbing, but not been synced yet */ + FRAME_ERROR, /* Something bad happened while processing */ +}; + +struct ov511_frame { + char *data; /* Frame buffer */ + + struct ov511_frame_header header; /* Header from stream */ + + int width; /* Width application is expecting */ + int height; /* Height */ + + int hdrwidth; /* Width the frame actually is */ + int hdrheight; /* Height */ + + volatile int grabstate; /* State of grabbing */ + int scanstate; /* State of scanning */ + + int curline; /* Line of frame we're working on */ + + long scanlength; /* uncompressed, raw data length of frame */ + long bytes_read; /* amount of scanlength that has been read from *data */ + + wait_queue_head_t wq; /* Processes waiting */ +}; + +#define OV511_NUMFRAMES 2 +#define OV511_NUMSBUF 2 + +struct usb_ov511 { + struct video_device vdev; + + /* Device structure */ + struct usb_device *dev; + + unsigned char customid; /* Type of camera */ + + unsigned char iface; + + struct semaphore lock; + int user; /* user count for exclusive use */ + + int streaming; /* Are we streaming Isochronous? */ + int grabbing; /* Are we grabbing? */ + + int compress; /* Should the next frame be compressed? */ + + char *fbuf; /* Videodev buffer area */ + + int curframe; /* Current receiving sbuf */ + struct ov511_frame frame[OV511_NUMFRAMES]; + + int cursbuf; /* Current receiving sbuf */ + struct ov511_sbuf sbuf[OV511_NUMSBUF]; + + /* Scratch space from the Isochronous pipe */ + unsigned char scratch[SCRATCH_BUF_SIZE]; + int scratchlen; +}; + +#endif + diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c index f6ab99776d6a..978085ff2734 100644 --- a/drivers/usb/usb-core.c +++ b/drivers/usb/usb-core.c @@ -40,15 +40,9 @@ int usb_init(void) # ifdef CONFIG_USB_OHCI_HCD ohci_hcd_init(); # endif -# ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -# endif # ifdef CONFIG_USB_SCANNER usb_scanner_init(); # endif -# ifdef CONFIG_USB_KBD - usb_kbd_init(); -# endif # ifdef CONFIG_USB_AUDIO usb_audio_init(); # endif @@ -64,6 +58,9 @@ int usb_init(void) # ifdef CONFIG_USB_CPIA usb_cpia_init(); # endif +# ifdef CONFIG_USB_OV511 + usb_ov511_init(); +# endif # ifdef CONFIG_USB_DC2XX usb_dc2xx_init(); # endif @@ -73,6 +70,18 @@ int usb_init(void) # ifdef CONFIG_USB_DABUSB dabusb_init(); # endif +# if defined(CONFIG_USB_HID) || defined(CONFIG_USB_MOUSE) || defined(CONFIG_USB_KBD) + input_init(); +# endif +# ifdef CONFIG_USB_HID + hid_init(); +# endif +# ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +# endif +# ifdef CONFIG_USB_KBD + usb_kbd_init(); +# endif #endif return 0; } @@ -107,6 +116,9 @@ void cleanup_drivers(void) # ifdef CONFIG_USB_CPIA usb_cpia_cleanup(); # endif +# ifdef CONFIG_USB_OV511 + usb_ov511_cleanup(); +# endif # ifdef CONFIG_USB_DC2XX usb_dc2xx_cleanup(); # endif diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c index 2ee72a057a77..47b98f472ac0 100644 --- a/drivers/usb/usb-serial.c +++ b/drivers/usb/usb-serial.c @@ -14,6 +14,17 @@ * * See README.serial for more information on using this driver. * + * version 0.3.1 (12/30/99) gkh + * Fixed problems with urb for bulk out. + * Added initial support for multiple sets of endpoints. This enables + * the Handspring Visor to be attached successfully. Only the first + * bulk in / bulk out endpoint pair is being used right now. + * + * version 0.3.0 (12/27/99) gkh + * Added initial support for the Handspring Visor based on a patch from + * Miles Lott (milos@sneety.insync.net) + * Cleaned up the code a bunch and converted over to using urbs only. + * * version 0.2.3 (12/21/99) gkh * Added initial support for the Connect Tech WhiteHEAT converter. * Incremented the number of ports in expectation of getting the @@ -71,12 +82,13 @@ /*#define SERIAL_DEBUG 1*/ #ifdef SERIAL_DEBUG - #define debug_info(message); printk(message); + #define debug_info(format,arg...) printk(KERN_DEBUG "USB Serial: " format "\n" , ##arg) #else - #define debug_info(message); + #define debug_info(format,arg...) do {} while (0) #endif + /* Module information */ MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"); MODULE_DESCRIPTION("USB Serial Driver"); @@ -96,7 +108,10 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); #define PERACOM_VENDOR_ID 0x0565 #define PERACOM_SERIAL_CONVERTER 0x0001 #define CONNECT_TECH_VENDOR_ID 0x0710 -#define CONNECT_TECH_WHITE_HEAT_ID 0x0001 +#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 +#define CONNECT_TECH_WHITE_HEAT_ID 0x8001 +#define HANDSPRING_VENDOR_ID 0x082d +#define HANDSPRING_VISOR_ID 0x0100 #define SERIAL_MAJOR 188 /* Nice legal number now */ @@ -114,6 +129,7 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr); #define HAS 0x02 #define HAS_NOT 0x01 +#define NUM_DONT_CARE (-1) /* local function prototypes */ static int serial_open (struct tty_struct *tty, struct file * filp); @@ -134,8 +150,14 @@ struct usb_serial_device_type { char needs_interrupt_in; char needs_bulk_in; char needs_bulk_out; - // add function calls + char num_interrupt_in; + char num_bulk_in; + char num_bulk_out; + /* function call to make before accepting driver */ + void (*startup) (void); + + /* serial function calls */ int (*open)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp); int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count); @@ -147,110 +169,150 @@ struct usb_serial_device_type { }; -/* function prototypes for the eTek type converters (this included Belkin and Peracom) */ +/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ +static int generic_serial_open (struct tty_struct *tty, struct file *filp); +static void generic_serial_close (struct tty_struct *tty, struct file *filp); +static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch); +static int generic_write_room (struct tty_struct *tty); +static int generic_chars_in_buffer (struct tty_struct *tty); + +/* All of the device info needed for the Generic Serial Converter */ +static struct usb_serial_device_type generic_device = { + name: "Generic", + idVendor: &vendor, /* use the user specified vendor id */ + idProduct: &product, /* use the user specified product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + open: generic_serial_open, + close: generic_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, +}; + + +/* function prototypes for the eTek type converters (this includes Belkin and Peracom) */ static int etek_serial_open (struct tty_struct *tty, struct file *filp); static void etek_serial_close (struct tty_struct *tty, struct file *filp); -static int etek_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void etek_serial_put_char (struct tty_struct *tty, unsigned char ch); -static int etek_write_room (struct tty_struct *tty); -static int etek_chars_in_buffer (struct tty_struct *tty); /* All of the device info needed for the Belkin Serial Converter */ static __u16 belkin_vendor_id = BELKIN_VENDOR_ID; static __u16 belkin_product_id = BELKIN_SERIAL_CONVERTER; static struct usb_serial_device_type belkin_device = { - "Belkin", - &belkin_vendor_id, /* the Belkin vendor id */ - &belkin_product_id, /* the Belkin serial converter product id */ - MUST_HAVE, /* this device must have an interrupt in endpoint */ - MUST_HAVE, /* this device must have a bulk in endpoint */ - MUST_HAVE, /* this device must have a bulk out endpoint */ - etek_serial_open, - etek_serial_close, - etek_serial_write, - etek_serial_put_char, - etek_write_room, - etek_chars_in_buffer, - NULL, - NULL + name: "Belkin", + idVendor: &belkin_vendor_id, /* the Belkin vendor id */ + idProduct: &belkin_product_id, /* the Belkin serial converter product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + open: etek_serial_open, + close: etek_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, }; /* All of the device info needed for the Peracom Serial Converter */ static __u16 peracom_vendor_id = PERACOM_VENDOR_ID; static __u16 peracom_product_id = PERACOM_SERIAL_CONVERTER; static struct usb_serial_device_type peracom_device = { - "Peracom", - &peracom_vendor_id, /* the Peracom vendor id */ - &peracom_product_id, /* the Peracom serial converter product id */ - MUST_HAVE, /* this device must have an interrupt in endpoint */ - MUST_HAVE, /* this device must have a bulk in endpoint */ - MUST_HAVE, /* this device must have a bulk out endpoint */ - etek_serial_open, - etek_serial_close, - etek_serial_write, - etek_serial_put_char, - etek_write_room, - etek_chars_in_buffer, - NULL, - NULL + name: "Peracom", + idVendor: &peracom_vendor_id, /* the Peracom vendor id */ + idProduct: &peracom_product_id, /* the Peracom serial converter product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + open: etek_serial_open, + close: etek_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, }; /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp); static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp); -static int whiteheat_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void whiteheat_serial_put_char (struct tty_struct *tty, unsigned char ch); -static int whiteheat_write_room (struct tty_struct *tty); -static int whiteheat_chars_in_buffer (struct tty_struct *tty); static void whiteheat_throttle (struct tty_struct *tty); static void whiteheat_unthrottle (struct tty_struct *tty); /* All of the device info needed for the Connect Tech WhiteHEAT */ static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID; +static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID; static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID; +static struct usb_serial_device_type whiteheat_fake_device = { + name: "Connect Tech - WhiteHEAT - (prerenumeration)", + idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ + idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, +}; static struct usb_serial_device_type whiteheat_device = { - "Connect Tech - WhiteHEAT", - &connecttech_vendor_id, /* the Connect Tech vendor id */ - &connecttech_whiteheat_product_id, /* the White Heat product id */ - DONT_CARE, /* don't have to have an interrupt in endpoint */ - DONT_CARE, /* don't have to have a bulk in endpoint */ - DONT_CARE, /* don't have to have a bulk out endpoint */ - whiteheat_serial_open, - whiteheat_serial_close, - whiteheat_serial_write, - whiteheat_serial_put_char, - whiteheat_write_room, - whiteheat_chars_in_buffer, - whiteheat_throttle, - whiteheat_unthrottle + name: "Connect Tech - WhiteHEAT", + idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ + idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + open: whiteheat_serial_open, + close: whiteheat_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, + throttle: whiteheat_throttle, + unthrottle: whiteheat_unthrottle }; -/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ -static int generic_serial_open (struct tty_struct *tty, struct file *filp); -static void generic_serial_close (struct tty_struct *tty, struct file *filp); -static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch); -static int generic_write_room (struct tty_struct *tty); -static int generic_chars_in_buffer (struct tty_struct *tty); - -/* All of the device info needed for the Generic Serial Converter */ -static struct usb_serial_device_type generic_device = { - "Generic", - &vendor, /* use the user specified vendor id */ - &product, /* use the user specified product id */ - DONT_CARE, /* don't have to have an interrupt in endpoint */ - DONT_CARE, /* don't have to have a bulk in endpoint */ - DONT_CARE, /* don't have to have a bulk out endpoint */ - generic_serial_open, - generic_serial_close, - generic_serial_write, - generic_serial_put_char, - generic_write_room, - generic_chars_in_buffer, - NULL, /* generic driver does not implement any flow control */ - NULL /* generic driver does not implement any flow control */ +/* function prototypes for a handspring visor */ +static int visor_serial_open (struct tty_struct *tty, struct file *filp); +static void visor_serial_close (struct tty_struct *tty, struct file *filp); +static void visor_throttle (struct tty_struct *tty); +static void visor_unthrottle (struct tty_struct *tty); + +/* All of the device info needed for the Handspring Visor */ +static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; +static __u16 handspring_product_id = HANDSPRING_VISOR_ID; +static struct usb_serial_device_type handspring_device = { + name: "Handspring Visor", + idVendor: &handspring_vendor_id, /* the Handspring vendor ID */ + idProduct: &handspring_product_id, /* the Handspring Visor product id */ + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 2, + num_bulk_out: 2, + open: visor_serial_open, + close: visor_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, + throttle: visor_throttle, + unthrottle: visor_unthrottle }; @@ -259,13 +321,16 @@ static struct usb_serial_device_type generic_device = { entry is NULL. */ static struct usb_serial_device_type *usb_serial_devices[] = { &generic_device, + &whiteheat_fake_device, &whiteheat_device, &belkin_device, &peracom_device, + &handspring_device, NULL }; +#define MAX_ENDPOINTS 8 struct usb_serial_state { struct usb_device * dev; @@ -277,32 +342,33 @@ struct usb_serial_state { char present; char active; - char has_interrupt_in; /* if this device has an interrupt in pipe or not */ + char num_interrupt_in; /* number of interrupt in endpoints we have */ char interrupt_in_inuse; /* if the interrupt in endpoint is in use */ - __u8 interrupt_in_endpoint; - __u8 interrupt_in_interval; - __u16 interrupt_in_size; /* the size of the interrupt in endpoint */ - unsigned int interrupt_in_pipe; - unsigned char * interrupt_in_buffer; - void * interrupt_in_transfer; - - char has_bulk_in; /* if thie device has a bulk in pipe or not */ - char bulk_in_inuse; /* if the bulk in endpoint is in use */ - __u8 bulk_in_endpoint; - __u8 bulk_in_interval; - __u16 bulk_in_size; /* the size of the bulk in endpoint */ - unsigned int bulk_in_pipe; - unsigned char * bulk_in_buffer; - void * bulk_in_transfer; - - char has_bulk_out; /* if this device has a bulk out pipe or not */ - char bulk_out_inuse; /* if the bulk out endpoint is in use */ - __u8 bulk_out_endpoint; - __u8 bulk_out_interval; - __u16 bulk_out_size; /* the size of the bulk out endpoint */ - unsigned int bulk_out_pipe; - unsigned char * bulk_out_buffer; - void * bulk_out_transfer; + __u8 interrupt_in_endpoint[MAX_ENDPOINTS]; + __u8 interrupt_in_interval[MAX_ENDPOINTS]; + __u16 interrupt_in_size[MAX_ENDPOINTS]; /* the size of the interrupt in endpoint */ + unsigned int interrupt_in_pipe[MAX_ENDPOINTS]; + unsigned char * interrupt_in_buffer[MAX_ENDPOINTS]; + void * interrupt_in_transfer[MAX_ENDPOINTS]; + struct urb control_urb; + + char num_bulk_in; /* number of bulk in endpoints we have */ + __u8 bulk_in_endpoint[MAX_ENDPOINTS]; + __u8 bulk_in_interval[MAX_ENDPOINTS]; + __u16 bulk_in_size[MAX_ENDPOINTS]; /* the size of the bulk in endpoint */ + unsigned int bulk_in_pipe[MAX_ENDPOINTS]; + unsigned char * bulk_in_buffer[MAX_ENDPOINTS]; + void * bulk_in_transfer[MAX_ENDPOINTS]; + struct urb read_urb; + + char num_bulk_out; /* number of bulk out endpoints we have */ + __u8 bulk_out_endpoint[MAX_ENDPOINTS]; + __u8 bulk_out_interval[MAX_ENDPOINTS]; + __u16 bulk_out_size[MAX_ENDPOINTS]; /* the size of the bulk out endpoint */ + unsigned int bulk_out_pipe[MAX_ENDPOINTS]; + unsigned char * bulk_out_buffer[MAX_ENDPOINTS]; + void * bulk_out_transfer[MAX_ENDPOINTS]; + struct urb write_urb; }; static struct usb_driver usb_serial_driver = { @@ -313,7 +379,6 @@ static struct usb_driver usb_serial_driver = { }; static int serial_refcount; -static struct tty_driver serial_tty_driver; static struct tty_struct * serial_tty[NUM_PORTS]; static struct termios * serial_termios[NUM_PORTS]; static struct termios * serial_termios_locked[NUM_PORTS]; @@ -321,76 +386,60 @@ static struct usb_serial_state serial_state_table[NUM_PORTS]; -static int serial_read_irq (int state, void *buffer, int count, void *dev_id) +static void serial_read_bulk (struct urb *urb) { - struct usb_serial_state *serial = (struct usb_serial_state *)dev_id; + struct usb_serial_state *serial = (struct usb_serial_state *)urb->context; struct tty_struct *tty = serial->tty; - unsigned char* data = buffer; + unsigned char *data = urb->transfer_buffer; int i; - debug_info("USB Serial: serial_read_irq\n"); + debug_info("serial_read_irq"); + + if (urb->status) { + debug_info("nonzero read bulk status received: %d", urb->status); + return; + } #ifdef SERIAL_DEBUG - if (count) { - printk("%d %s\n", count, data); + if (urb->actual_length) { + debug_info("%d %s\n", urb->actual_length, data); } #endif - if (count) { - for (i=0;iactual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); } tty_flip_buffer_push(tty); } - /* Continue transfer */ - /* return (1); */ + /* Continue trying to always read */ + if (usb_submit_urb(urb)) + debug_info("failed resubmitting read urb"); - /* No more transfer, let the irq schedule us again */ - serial->bulk_in_inuse = 0; - return (0); + return; } -static int serial_write_irq (int state, void *buffer, int count, void *dev_id) +static void serial_write_bulk (struct urb *urb) { - struct usb_serial_state *serial = (struct usb_serial_state *) dev_id; + struct usb_serial_state *serial = (struct usb_serial_state *) urb->context; struct tty_struct *tty = serial->tty; - debug_info("USB Serial: serial_write_irq\n"); - - if (!serial->bulk_out_inuse) { - debug_info("USB Serial: write irq for a finished pipe?\n"); - return (0); - } + debug_info("serial_write_irq"); - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; + if (urb->status) { + debug_info("nonzero write bulk status received: %d", urb->status); + return; + } if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); - return 0; -} - - -#if 0 -/* we will need this soon... removed for now to keep the compile warnings down */ -static int usb_serial_irq (int state, void *buffer, int len, void *dev_id) -{ - struct usb_serial_state *serial = (struct usb_serial_state *) dev_id; - - debug_info("USB Serial: usb_serial_irq\n"); - - /* ask for a bulk read */ -// serial->bulk_in_inuse = 1; -// serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); - - return (1); + return; } -#endif @@ -401,18 +450,18 @@ static int serial_open (struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial; - debug_info("USB Serial: serial_open\n"); + debug_info("serial_open"); /* assign a serial object to the tty pointer */ serial = &serial_state_table [MINOR(tty->device)-tty->driver.minor_start]; /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return (-ENODEV); } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return (-ENODEV); } @@ -432,23 +481,23 @@ static int serial_open (struct tty_struct *tty, struct file * filp) static void serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: serial_close\n"); + debug_info("serial_close"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return; } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return; } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return; } if (!serial->active) { - debug_info ("USB Serial: device already open\n"); + debug_info ("device already open"); return; } @@ -463,23 +512,23 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: serial_write\n"); + debug_info("serial_write"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return (-ENODEV); } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return (-ENODEV); } if (!serial->present) { - debug_info("USB Serial: device not registered\n"); + debug_info("device not registered"); return (-EINVAL); } if (!serial->active) { - debug_info ("USB Serial: device not opened\n"); + debug_info ("device not opened"); return (-EINVAL); } @@ -497,23 +546,23 @@ static void serial_put_char (struct tty_struct *tty, unsigned char ch) { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: serial_put_char\n"); + debug_info("serial_put_char"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return; } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return; } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return; } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return; } @@ -530,23 +579,23 @@ static int serial_write_room (struct tty_struct *tty) { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: serial_write_room\n"); + debug_info("serial_write_room"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return (-ENODEV); } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return (-ENODEV); } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return (-EINVAL); } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return (-EINVAL); } @@ -563,23 +612,23 @@ static int serial_chars_in_buffer (struct tty_struct *tty) { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: serial_chars_in_buffer\n"); + debug_info("serial_chars_in_buffer"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return (-ENODEV); } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return (-ENODEV); } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return (-EINVAL); } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return (-EINVAL); } @@ -596,23 +645,23 @@ static void serial_throttle (struct tty_struct * tty) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: serial_throttle\n"); + debug_info("serial_throttle"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return; } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return; } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return; } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return; } @@ -629,23 +678,23 @@ static void serial_unthrottle (struct tty_struct * tty) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: serial_unthrottle\n"); + debug_info("serial_unthrottle"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return; } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return; } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return; } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return; } @@ -666,22 +715,22 @@ static int etek_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: etek_serial_open\n"); + debug_info("etek_serial_open"); if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return -EINVAL; } if (serial->active) { - debug_info ("USB Serial: device already open\n"); + debug_info ("device already open"); return -EINVAL; } serial->active = 1; /*Start reading from the device*/ - serial->bulk_in_inuse = 1; - serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); + if (usb_submit_urb(&serial->read_urb)) + debug_info("usb_submit_urb(read bulk) failed"); /* Need to do device specific setup here (control lines, baud rate, etc.) */ /* FIXME!!! */ @@ -693,104 +742,18 @@ static int etek_serial_open (struct tty_struct *tty, struct file *filp) static void etek_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: etek_serial_close\n"); + debug_info("etek_serial_close"); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ - if (serial->bulk_out_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; - } - if (serial->bulk_in_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_in_transfer); - serial->bulk_in_inuse = 0; - } - - /* release the irq? */ - + usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->read_urb); serial->active = 0; } -static int etek_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) -{ - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - int written; - - debug_info("USB Serial: etek_serial_write\n"); - - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return (0); - } - - written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count; - - if (from_user) { - copy_from_user(serial->bulk_out_buffer, buf, written); - } - else { - memcpy (serial->bulk_out_buffer, buf, written); - } - - /* send the data out the bulk port */ - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial); - - return (written); -} - - -static void etek_serial_put_char (struct tty_struct *tty, unsigned char ch) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - debug_info("USB Serial: etek_serial_put_char\n"); - - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return; - } - - /* send the single character out the bulk port */ - serial->bulk_out_buffer[0] = ch; - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial); - - return; -} - - -static int etek_write_room (struct tty_struct *tty) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - debug_info("USB Serial: etek_write_room\n"); - - if (serial->bulk_out_inuse) { - return (0); - } - - return (serial->bulk_out_size); -} - - -static int etek_chars_in_buffer (struct tty_struct *tty) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - debug_info("USB Serial: etek_chars_in_buffer\n"); - - if (serial->bulk_out_inuse) { - return (serial->bulk_out_size); - } - - return (0); -} - - /***************************************************************************** * Connect Tech's White Heat specific driver functions *****************************************************************************/ @@ -798,22 +761,22 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: whiteheat_serial_open\n"); + debug_info("whiteheat_serial_open"); if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return -EINVAL; } if (serial->active) { - debug_info ("USB Serial: device already open\n"); + debug_info ("device already open"); return -EINVAL; } serial->active = 1; /*Start reading from the device*/ - serial->bulk_in_inuse = 1; - serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); + if (usb_submit_urb(&serial->read_urb)) + debug_info("usb_submit_urb(read bulk) failed"); /* Need to do device specific setup here (control lines, baud rate, etc.) */ /* FIXME!!! */ @@ -825,119 +788,98 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp) static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: whiteheat_serial_close\n"); + debug_info("whiteheat_serial_close"); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ - if (serial->bulk_out_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; - } - if (serial->bulk_in_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_in_transfer); - serial->bulk_in_inuse = 0; - } - - /* release the irq? */ - + usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->read_urb); serial->active = 0; } -static int whiteheat_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) +static void whiteheat_throttle (struct tty_struct * tty) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - int written; + debug_info("whiteheat_throttle"); - debug_info("USB Serial: whiteheat_serial_write\n"); - - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return (0); - } - - written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count; - - if (from_user) { - copy_from_user(serial->bulk_out_buffer, buf, written); - } - else { - memcpy (serial->bulk_out_buffer, buf, written); - } - - /* send the data out the bulk port */ - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial); + /* Change the control signals */ + /* FIXME!!! */ - return (written); -} + return; +} -static void whiteheat_serial_put_char (struct tty_struct *tty, unsigned char ch) +static void whiteheat_unthrottle (struct tty_struct * tty) { - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + debug_info("whiteheat_unthrottle"); - debug_info("USB Serial: whiteheat_serial_put_char\n"); - - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return; - } - - /* send the single character out the bulk port */ - serial->bulk_out_buffer[0] = ch; - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial); + /* Change the control signals */ + /* FIXME!!! */ return; } -static int whiteheat_write_room (struct tty_struct *tty) +/****************************************************************************** + * Handspring Visor specific driver functions + ******************************************************************************/ +static int visor_serial_open (struct tty_struct *tty, struct file *filp) { - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + debug_info("visor_serial_open"); - debug_info("USB Serial: whiteheat_write_room\n"); - - if (serial->bulk_out_inuse) { - return (0); + if (!serial->present) { + debug_info("no device registered"); + return -EINVAL; } - return (serial->bulk_out_size); -} - + if (serial->active) { + debug_info ("device already open"); + return -EINVAL; + } -static int whiteheat_chars_in_buffer (struct tty_struct *tty) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + serial->active = 1; - debug_info("USB Serial: whiteheat_chars_in_buffer\n"); - - if (serial->bulk_out_inuse) { - return (serial->bulk_out_size); - } + /*Start reading from the device*/ + if (usb_submit_urb(&serial->read_urb)) + debug_info("usb_submit_urb(read bulk) failed"); return (0); } - -static void whiteheat_throttle (struct tty_struct * tty) +static void visor_serial_close(struct tty_struct *tty, struct file * filp) { - debug_info("USB Serial: whiteheat_throttle\n"); + struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + debug_info("USB: visor_serial_close"); + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->read_urb); + serial->active = 0; +} + + +static void visor_throttle (struct tty_struct * tty) +{ +/* struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; */ + + debug_info("visor_throttle"); + /* Change the control signals */ /* FIXME!!! */ return; } - -static void whiteheat_unthrottle (struct tty_struct * tty) +static void visor_unthrottle (struct tty_struct * tty) { - debug_info("USB Serial: whiteheat_unthrottle\n"); - +/* struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; */ + + debug_info("visor_unthrottle"); + /* Change the control signals */ /* FIXME!!! */ @@ -952,24 +894,24 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: generic_serial_open\n"); + debug_info("generic_serial_open"); if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return -EINVAL; } if (serial->active) { - debug_info ("USB Serial: device already open\n"); + debug_info ("device already open"); return -EINVAL; } serial->active = 1; /* if we have a bulk interrupt, start reading from it */ - if (serial->has_bulk_in) { + if (serial->num_bulk_in) { /*Start reading from the device*/ - serial->bulk_in_inuse = 1; - serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); + if (usb_submit_urb(&serial->read_urb)) + debug_info("usb_submit_urb(read bulk) failed"); } return (0); @@ -979,16 +921,14 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp) static void generic_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: generic_serial_close\n"); + debug_info("generic_serial_close"); /* shutdown any bulk reads that might be going on */ - if (serial->bulk_out_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; + if (serial->num_bulk_out) { + usb_unlink_urb (&serial->write_urb); } - if (serial->bulk_in_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_in_transfer); - serial->bulk_in_inuse = 0; + if (serial->num_bulk_in) { + usb_unlink_urb (&serial->read_urb); } serial->active = 0; @@ -998,31 +938,37 @@ static void generic_serial_close(struct tty_struct *tty, struct file * filp) static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - int written; - debug_info("USB Serial: generic_serial_write\n"); + debug_info("generic_serial_write"); + + if (count == 0) { + debug_info("write request of 0 bytes"); + return (0); + } /* only do something if we have a bulk out endpoint */ - if (serial->has_bulk_out) { - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); + if (serial->num_bulk_out) { + if (serial->write_urb.status == -EINPROGRESS) { + debug_info ("already writing"); return (0); } - written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count; - + count = (count > serial->bulk_out_size[0]) ? serial->bulk_out_size[0] : count; + if (from_user) { - copy_from_user(serial->bulk_out_buffer, buf, written); + copy_from_user(serial->write_urb.transfer_buffer, buf, count); } else { - memcpy (serial->bulk_out_buffer, buf, written); + memcpy (serial->write_urb.transfer_buffer, buf, count); } /* send the data out the bulk port */ - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial); + serial->write_urb.transfer_buffer_length = count; - return (written); + if (usb_submit_urb(&serial->write_urb)) + debug_info("usb_submit_urb(write bulk) failed"); + + return (count); } /* no bulk out, so return 0 bytes written */ @@ -1034,19 +980,17 @@ static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch) { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: generic_serial_put_char\n"); + debug_info("generic_serial_put_char"); /* if we have a bulk out endpoint, then shove a character out it */ - if (serial->has_bulk_out) { - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return; - } - + if (serial->num_bulk_out) { /* send the single character out the bulk port */ - serial->bulk_out_buffer[0] = ch; - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial); + memcpy (serial->write_urb.transfer_buffer, &ch, 1); + serial->write_urb.transfer_buffer_length = 1; + + if (usb_submit_urb(&serial->write_urb)) + debug_info("usb_submit_urb(write bulk) failed"); + } return; @@ -1056,14 +1000,17 @@ static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch) static int generic_write_room (struct tty_struct *tty) { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + int room; - debug_info("USB Serial: generic_write_room\n"); + debug_info("generic_write_room"); - if (serial->has_bulk_out) { - if (serial->bulk_out_inuse) { - return (0); - } - return (serial->bulk_out_size); + if (serial->num_bulk_out) { + if (serial->write_urb.status == -EINPROGRESS) + room = 0; + else + room = serial->bulk_out_size[0]; + debug_info("generic_write_room returns %d", room); + return (room); } return (0); @@ -1074,11 +1021,11 @@ static int generic_chars_in_buffer (struct tty_struct *tty) { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: generic_chars_in_buffer\n"); + debug_info("generic_chars_in_buffer"); - if (serial->has_bulk_out) { - if (serial->bulk_out_inuse) { - return (serial->bulk_out_size); + if (serial->num_bulk_out) { + if (serial->write_urb.status == -EINPROGRESS) { + return (serial->bulk_out_size[0]); } } @@ -1103,9 +1050,9 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) struct usb_serial_state *serial = NULL; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *interrupt_in_endpoint = NULL; - struct usb_endpoint_descriptor *bulk_in_endpoint = NULL; - struct usb_endpoint_descriptor *bulk_out_endpoint = NULL; + struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_ENDPOINTS]; + struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_ENDPOINTS]; + struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_ENDPOINTS]; struct usb_serial_device_type *type; int device_num; int serial_num; @@ -1113,20 +1060,21 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) char interrupt_pipe; char bulk_in_pipe; char bulk_out_pipe; + int num_interrupt_in = 0; + int num_bulk_in = 0; + int num_bulk_out = 0; /* loop through our list of known serial converters, and see if this device matches */ device_num = 0; while (usb_serial_devices[device_num] != NULL) { type = usb_serial_devices[device_num]; - #ifdef SERIAL_DEBUG - printk ("USB Serial: Looking at %s Vendor id=%.4x Product id=%.4x\n", type->name, *(type->idVendor), *(type->idProduct)); - #endif + debug_info ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct)); /* look at the device descriptor */ if ((dev->descriptor.idVendor == *(type->idVendor)) && (dev->descriptor.idProduct == *(type->idProduct))) { - debug_info("USB Serial: descriptor matches...looking at the endpoints\n") + debug_info("descriptor matches...looking at the endpoints"); /* descriptor matches, let's try to find the endpoints needed */ interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT; @@ -1139,37 +1087,28 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk in endpoint */ - debug_info("USB Serial: found bulk in\n"); - if (bulk_in_pipe == HAS) { - printk("USB Serial: can't have more than one bulk in endpoint\n"); - goto probe_error; - } + debug_info("found bulk in"); bulk_in_pipe = HAS; - bulk_in_endpoint = endpoint; + bulk_in_endpoint[num_bulk_in] = endpoint; + ++num_bulk_in; } if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk out endpoint */ - debug_info("USB Serial: found bulk out\n"); - if (bulk_out_pipe == HAS) { - printk("USB Serial: can't have more than one bulk out endpoint\n"); - goto probe_error; - } + debug_info("found bulk out"); bulk_out_pipe = HAS; - bulk_out_endpoint = endpoint; + bulk_out_endpoint[num_bulk_out] = endpoint; + ++num_bulk_out; } if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x03)) { /* we found a interrupt in endpoint */ - debug_info("USB Serial: found interrupt in\n"); - if (interrupt_pipe == HAS) { - printk("USB Serial: can't have more than one interrupt in endpoint\n"); - goto probe_error; - } + debug_info("found interrupt in"); interrupt_pipe = HAS; - interrupt_in_endpoint = endpoint; + interrupt_in_endpoint[num_interrupt_in] = endpoint; + ++num_interrupt_in; } } @@ -1182,7 +1121,7 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) printk (KERN_INFO "USB Serial: %s converter detected.\n", type->name); if (0>(serial_num = Get_Free_Serial())) { - debug_info("USB Serial: Too many devices connected\n"); + debug_info("Too many devices connected"); return NULL; } @@ -1192,45 +1131,49 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) serial->dev = dev; serial->type = type; serial->number = serial_num; + serial->num_bulk_in = num_bulk_in; + serial->num_bulk_out = num_bulk_out; + serial->num_interrupt_in = num_interrupt_in; /* set up the endpoint information */ - if (bulk_in_endpoint) { - serial->has_bulk_in = 1; - serial->bulk_in_inuse = 0; - serial->bulk_in_endpoint = bulk_in_endpoint->bEndpointAddress; - serial->bulk_in_size = bulk_in_endpoint->wMaxPacketSize; - serial->bulk_in_interval = bulk_in_endpoint->bInterval; - serial->bulk_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); - serial->bulk_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL); - if (!serial->bulk_in_buffer) { + for (i = 0; i < num_bulk_in; ++i) { + serial->bulk_in_endpoint[i] = bulk_in_endpoint[i]->bEndpointAddress; + serial->bulk_in_size[i] = bulk_in_endpoint[i]->wMaxPacketSize; + serial->bulk_in_interval[i] = bulk_in_endpoint[i]->bInterval; + serial->bulk_in_pipe[i] = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint[i]); + serial->bulk_in_buffer[i] = kmalloc (serial->bulk_in_size[i], GFP_KERNEL); + if (!serial->bulk_in_buffer[i]) { printk("USB Serial: Couldn't allocate bulk_in_buffer\n"); goto probe_error; } } - - if (bulk_out_endpoint) { - serial->has_bulk_out = 1; - serial->bulk_out_inuse = 0; - serial->bulk_out_endpoint = bulk_out_endpoint->bEndpointAddress; - serial->bulk_out_size = bulk_out_endpoint->wMaxPacketSize; - serial->bulk_out_interval = bulk_out_endpoint->bInterval; - serial->bulk_out_pipe = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint); - serial->bulk_out_buffer = kmalloc (serial->bulk_out_size, GFP_KERNEL); - if (!serial->bulk_out_buffer) { + if (num_bulk_in) + FILL_BULK_URB(&serial->read_urb, dev, usb_rcvbulkpipe (dev, serial->bulk_in_endpoint[0]), + serial->bulk_in_buffer[0], serial->bulk_in_size[0], serial_read_bulk, serial); + + for (i = 0; i < num_bulk_out; ++i) { + serial->bulk_out_endpoint[i] = bulk_out_endpoint[i]->bEndpointAddress; + serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize; + serial->bulk_out_interval[i] = bulk_out_endpoint[i]->bInterval; + serial->bulk_out_pipe[i] = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint[i]); + serial->bulk_out_buffer[i] = kmalloc (serial->bulk_out_size[i], GFP_KERNEL); + if (!serial->bulk_out_buffer[i]) { printk("USB Serial: Couldn't allocate bulk_out_buffer\n"); goto probe_error; } } + if (num_bulk_out) + FILL_BULK_URB(&serial->write_urb, dev, usb_sndbulkpipe (dev, serial->bulk_in_endpoint[0]), + serial->bulk_in_buffer[0], serial->bulk_in_size[0], serial_write_bulk, serial); - if (interrupt_in_endpoint) { - serial->has_interrupt_in = 1; + for (i = 0; i < num_interrupt_in; ++i) { serial->interrupt_in_inuse = 0; - serial->interrupt_in_endpoint = interrupt_in_endpoint->bEndpointAddress; - serial->interrupt_in_size = interrupt_in_endpoint->wMaxPacketSize; - serial->interrupt_in_interval = interrupt_in_endpoint->bInterval; + serial->interrupt_in_endpoint[i] = interrupt_in_endpoint[i]->bEndpointAddress; + serial->interrupt_in_size[i] = interrupt_in_endpoint[i]->wMaxPacketSize; + serial->interrupt_in_interval[i] = interrupt_in_endpoint[i]->bInterval; /* serial->interrupt_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); */ - serial->interrupt_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL); - if (!serial->interrupt_in_buffer) { + serial->interrupt_in_buffer[i] = kmalloc (serial->bulk_in_size[i], GFP_KERNEL); + if (!serial->interrupt_in_buffer[i]) { printk("USB Serial: Couldn't allocate interrupt_in_buffer\n"); goto probe_error; } @@ -1266,12 +1209,15 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) probe_error: if (serial) { - if (serial->bulk_in_buffer) - kfree (serial->bulk_in_buffer); - if (serial->bulk_out_buffer) - kfree (serial->bulk_out_buffer); - if (serial->interrupt_in_buffer) - kfree (serial->interrupt_in_buffer); + for (i = 0; i < num_bulk_in; ++i) + if (serial->bulk_in_buffer[i]) + kfree (serial->bulk_in_buffer[i]); + for (i = 0; i < num_bulk_out; ++i) + if (serial->bulk_out_buffer[i]) + kfree (serial->bulk_out_buffer[i]); + for (i = 0; i < num_interrupt_in; ++i) + if (serial->interrupt_in_buffer[i]) + kfree (serial->interrupt_in_buffer[i]); } return NULL; } @@ -1280,30 +1226,29 @@ probe_error: static void usb_serial_disconnect(struct usb_device *dev, void *ptr) { struct usb_serial_state *serial = (struct usb_serial_state *) ptr; + int i; if (serial) { if (!serial->present) { /* something strange is going on */ - debug_info("USB Serial: disconnect but not present?\n") + debug_info("disconnect but not present?"); return; } /* need to stop any transfers...*/ - if (serial->bulk_in_inuse) { - usb_terminate_bulk (serial->dev, serial->bulk_in_transfer); - serial->bulk_in_inuse = 0; - } - if (serial->bulk_out_inuse) { - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; - } - // usb_release_irq (serial->dev, serial->irq_handle, serial->bulk_in_pipe); - if (serial->bulk_in_buffer) - kfree (serial->bulk_in_buffer); - if (serial->bulk_out_buffer) - kfree (serial->bulk_out_buffer); - if (serial->interrupt_in_buffer) - kfree (serial->interrupt_in_buffer); + usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->read_urb); + + /* free up any memory that we allocated */ + for (i = 0; i < serial->num_bulk_in; ++i) + if (serial->bulk_in_buffer[i]) + kfree (serial->bulk_in_buffer[i]); + for (i = 0; i < serial->num_bulk_out; ++i) + if (serial->bulk_out_buffer[i]) + kfree (serial->bulk_out_buffer[i]); + for (i = 0; i < serial->num_interrupt_in; ++i) + if (serial->interrupt_in_buffer[i]) + kfree (serial->interrupt_in_buffer[i]); serial->present = 0; serial->active = 0; @@ -1319,6 +1264,45 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) } +static struct tty_driver serial_tty_driver = { + magic: TTY_DRIVER_MAGIC, + driver_name: "usb", + name: "ttyUSB", + major: SERIAL_MAJOR, + minor_start: 0, + num: NUM_PORTS, + type: TTY_DRIVER_TYPE_SERIAL, + subtype: SERIAL_TYPE_NORMAL, + flags: TTY_DRIVER_REAL_RAW, + refcount: &serial_refcount, + table: serial_tty, + proc_entry: NULL, + other: NULL, + termios: serial_termios, + termios_locked: serial_termios_locked, + + open: serial_open, + close: serial_close, + write: serial_write, + put_char: serial_put_char, + flush_chars: NULL, + write_room: serial_write_room, + ioctl: NULL, + set_termios: NULL, + set_ldisc: NULL, + throttle: serial_throttle, + unthrottle: serial_unthrottle, + stop: NULL, + start: NULL, + hangup: NULL, + break_ctl: NULL, + wait_until_sent: NULL, + send_xchar: NULL, + read_proc: NULL, + chars_in_buffer: serial_chars_in_buffer, + flush_buffer: NULL +}; + int usb_serial_init(void) { @@ -1330,45 +1314,8 @@ int usb_serial_init(void) } /* register the tty driver */ - memset (&serial_tty_driver, 0, sizeof(struct tty_driver)); - serial_tty_driver.magic = TTY_DRIVER_MAGIC; - serial_tty_driver.driver_name = "usb"; - serial_tty_driver.name = "ttyUSB"; - serial_tty_driver.major = SERIAL_MAJOR; - serial_tty_driver.minor_start = 0; - serial_tty_driver.num = NUM_PORTS; - serial_tty_driver.type = TTY_DRIVER_TYPE_SERIAL; - serial_tty_driver.subtype = SERIAL_TYPE_NORMAL; serial_tty_driver.init_termios = tty_std_termios; serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_tty_driver.flags = TTY_DRIVER_REAL_RAW; - serial_tty_driver.refcount = &serial_refcount; - serial_tty_driver.table = serial_tty; - serial_tty_driver.proc_entry = NULL; - serial_tty_driver.other = NULL; - serial_tty_driver.termios = serial_termios; - serial_tty_driver.termios_locked = serial_termios_locked; - - serial_tty_driver.open = serial_open; - serial_tty_driver.close = serial_close; - serial_tty_driver.write = serial_write; - serial_tty_driver.put_char = serial_put_char; - serial_tty_driver.flush_chars = NULL; //serial_flush_chars; - serial_tty_driver.write_room = serial_write_room; - serial_tty_driver.ioctl = NULL; //serial_ioctl; - serial_tty_driver.set_termios = NULL; //serial_set_termios; - serial_tty_driver.set_ldisc = NULL; - serial_tty_driver.throttle = serial_throttle; - serial_tty_driver.unthrottle = serial_unthrottle; - serial_tty_driver.stop = NULL; //serial_stop; - serial_tty_driver.start = NULL; //serial_start; - serial_tty_driver.hangup = NULL; //serial_hangup; - serial_tty_driver.break_ctl = NULL; //serial_break; - serial_tty_driver.wait_until_sent = NULL; //serial_wait_until_sent; - serial_tty_driver.send_xchar = NULL; //serial_send_xchar; - serial_tty_driver.read_proc = NULL; //serial_read_proc; - serial_tty_driver.chars_in_buffer = serial_chars_in_buffer; - serial_tty_driver.flush_buffer = NULL; //serial_flush_buffer; if (tty_register_driver (&serial_tty_driver)) { printk( "USB Serial: failed to register tty driver\n" ); return -EPERM; diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index fae15aa479dc..b9610f91f3d2 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -1178,6 +1178,34 @@ void usb_init_root_hub(struct usb_device *dev) dev->actconfig = NULL; } +/* + * __usb_get_extra_descriptor() finds a descriptor of specific type in the + * extra field of the interface and endpoint descriptor structs. + */ + +int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr) +{ + struct usb_descriptor_header *header; + + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + if (header->bDescriptorType == type) { + *ptr = header; + return 0; + } + + buffer += header->bLength; + size -= header->bLength; + } + return -1; +} + /* * Something got disconnected. Get rid of it, and all of its children. */ @@ -1268,6 +1296,14 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char return result; } +int usb_get_class_descriptor(struct usb_device *dev, unsigned char type, + unsigned char id, unsigned char index, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_RT_INTERFACE | USB_DIR_IN, + (type << 8) + id, index, buf, size, HZ * GET_TIMEOUT); +} + int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) { return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), @@ -1313,8 +1349,6 @@ int usb_set_protocol(struct usb_device *dev, int protocol) USB_REQ_SET_PROTOCOL, USB_RT_HIDD, protocol, 1, NULL, 0, HZ * SET_TIMEOUT); } -/* keyboards want a nonzero duration according to HID spec, but - mice should use infinity (0) -keryan */ int usb_set_idle(struct usb_device *dev, int duration, int report_id) { return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_IDLE, @@ -1446,6 +1480,13 @@ int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, (type << 8) + id, index, buf, size, HZ * GET_TIMEOUT); } +int usb_set_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_SET_REPORT, USB_RT_HIDD, + (type << 8) + id, index, buf, size, HZ); +} + int usb_get_configuration(struct usb_device *dev) { int result; @@ -1737,11 +1778,14 @@ EXPORT_SYMBOL(usb_release_bandwidth); EXPORT_SYMBOL(usb_set_address); EXPORT_SYMBOL(usb_get_descriptor); +EXPORT_SYMBOL(usb_get_class_descriptor); +EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_get_string); EXPORT_SYMBOL(usb_string); EXPORT_SYMBOL(usb_get_protocol); EXPORT_SYMBOL(usb_set_protocol); EXPORT_SYMBOL(usb_get_report); +EXPORT_SYMBOL(usb_set_report); EXPORT_SYMBOL(usb_set_idle); EXPORT_SYMBOL(usb_clear_halt); EXPORT_SYMBOL(usb_set_interface); diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h index 5b4d46f6e0cb..3e7c44dccd8e 100644 --- a/drivers/usb/usb.h +++ b/drivers/usb/usb.h @@ -44,6 +44,7 @@ #define USB_DT_ENDPOINT_SIZE 7 #define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ #define USB_DT_HUB_NONVAR_SIZE 7 +#define USB_DT_HID_SIZE 9 /* * USB Request Type and Endpoint Directions @@ -742,19 +743,28 @@ static inline unsigned int __default_pipe(struct usb_device *dev) */ int usb_new_device(struct usb_device *dev); int usb_set_address(struct usb_device *dev); -int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned -char descindex, void *buf, int size); +int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, + unsigned char descindex, void *buf, int size); +int usb_get_class_descriptor(struct usb_device *dev, unsigned char desctype, + unsigned char descindex, unsigned char ifnum, void *buf, int size); int usb_get_device_descriptor(struct usb_device *dev); +int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr); int usb_get_status (struct usb_device *dev, int type, int target, void *data); int usb_get_protocol(struct usb_device *dev); int usb_set_protocol(struct usb_device *dev, int protocol); int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_idle(struct usb_device *dev, int duration, int report_id); int usb_set_configuration(struct usb_device *dev, int configuration); -int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size); +int usb_get_report(struct usb_device *dev, unsigned char type, + unsigned char id, unsigned char index, void *buf, int size); +int usb_set_report(struct usb_device *dev, unsigned char type, + unsigned char id, unsigned char index, void *buf, int size); char *usb_string(struct usb_device *dev, int index); int usb_clear_halt(struct usb_device *dev, int endp); +#define usb_get_extra_descriptor(ifpoint,type,ptr)\ + __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,type,(void**)ptr) + /* * Some USB bandwidth allocation constants. */ diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c new file mode 100644 index 000000000000..461294bbae46 --- /dev/null +++ b/drivers/usb/usbkbd.c @@ -0,0 +1,208 @@ +/* + * usbkbd.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * USB HIDBP Keyboard support + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include "usb.h" + +MODULE_AUTHOR("Vojtech Pavlik "); + +static unsigned char usb_kbd_keycode[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 0, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, + 120,121,122,123, 0,138, 0, 0,128,129,131,137,133,135,136,113, + 115,114, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56,125, 97, 54,100,126 +}; + +struct usb_kbd { + struct input_dev dev; + unsigned char new[8]; + unsigned char old[8]; + struct urb irq, led; + devrequest dr; + unsigned char leds; +}; + +static void usb_kbd_irq(struct urb *urb) +{ + struct usb_kbd *kbd = urb->context; + int i; + + if (urb->status) return; + + for (i = 0; i < 8; i++) + input_report_key(&kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); + + for (i = 2; i < 8; i++) { + + if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { + if (usb_kbd_keycode[kbd->old[i]]) + input_report_key(&kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); + else + printk(KERN_DEBUG "usbkbd.c: Unknown key (scancode %#x) released.\n", kbd->old[i]); + } + + if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { + if (usb_kbd_keycode[kbd->new[i]]) + input_report_key(&kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); + else + printk(KERN_DEBUG "usbkbd.c: Unknown key (scancode %#x) pressed.\n", kbd->new[i]); + } + } + + memcpy(kbd->old, kbd->new, 8); +} + +int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct usb_kbd *kbd = dev->private; + + if (type != EV_LED) return -1; + + kbd->leds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | + (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | + (!!test_bit(LED_NUML, dev->led)); + + usb_submit_urb(&kbd->led); + + return -1; +} + +static void usb_kbd_led(struct urb *urb) +{ + if (urb->status) + printk(KERN_DEBUG "nonzero control status received: %d\n", urb->status); +} + +static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_kbd *kbd; + int i; + + if (dev->descriptor.bNumConfigurations != 1) return NULL; + interface = dev->config[0].interface[ifnum].altsetting + 0; + + if (interface->bInterfaceClass != 3) return NULL; + if (interface->bInterfaceSubClass != 1) return NULL; + if (interface->bInterfaceProtocol != 1) return NULL; + if (interface->bNumEndpoints != 1) return NULL; + + endpoint = interface->endpoint + 0; + if (!(endpoint->bEndpointAddress & 0x80)) return NULL; + if ((endpoint->bmAttributes & 3) != 3) return NULL; + + usb_set_protocol(dev, 0); + + if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL; + memset(kbd, 0, sizeof(struct usb_kbd)); + + kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); + + for (i = 0; i < 255; i++) + set_bit(usb_kbd_keycode[i], kbd->dev.keybit); + clear_bit(0, kbd->dev.keybit); + + kbd->dev.private = kbd; + kbd->dev.event = usb_kbd_event; + + kbd->dr.requesttype = USB_RT_HIDD; + kbd->dr.request = USB_REQ_SET_REPORT; + kbd->dr.value = 0x200; + kbd->dr.index = 1; + kbd->dr.length = 1; + + { + int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + int maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, + usb_kbd_irq, kbd, endpoint->bInterval); + } + + FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, endpoint->bEndpointAddress), + (void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd); + + if (usb_submit_urb(&kbd->irq)) { + kfree(kbd); + return NULL; + } + + input_register_device(&kbd->dev); + + printk(KERN_INFO "input%d: USB HIDBP keyboard\n", kbd->dev.number); + + + return kbd; +} + +static void usb_kbd_disconnect(struct usb_device *dev, void *ptr) +{ + struct usb_kbd *kbd = ptr; + usb_unlink_urb(&kbd->irq); + input_unregister_device(&kbd->dev); + kfree(kbd); +} + +static struct usb_driver usb_kbd_driver = { + name: "keyboard", + probe: usb_kbd_probe, + disconnect: usb_kbd_disconnect +}; + +#ifdef MODULE +void cleanup_module(void) +{ + usb_deregister(&usb_kbd_driver); +} + +int init_module(void) +#else +int usb_kbd_init(void) +#endif +{ + usb_register(&usb_kbd_driver); + return 0; +} diff --git a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c new file mode 100644 index 000000000000..e4145d0956f7 --- /dev/null +++ b/drivers/usb/usbmouse.c @@ -0,0 +1,148 @@ +/* + * usbmouse.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * USB HIDBP Mouse support + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include "usb.h" + +MODULE_AUTHOR("Vojtech Pavlik "); + +#define USBMOUSE_EXTRA + +struct usb_mouse { + signed char data[8]; + struct input_dev dev; + struct urb irq; +}; + +static void usb_mouse_irq(struct urb *urb) +{ + struct usb_mouse *mouse = urb->context; + signed char *data = mouse->data; + struct input_dev *dev = &mouse->dev; + + if (urb->status) return; + + input_report_key(dev, BTN_LEFT, !!(data[0] & 0x01)); + input_report_key(dev, BTN_RIGHT, !!(data[0] & 0x02)); + input_report_key(dev, BTN_MIDDLE, !!(data[0] & 0x04)); + input_report_rel(dev, REL_X, data[1]); + input_report_rel(dev, REL_Y, data[2]); +#ifdef USBMOUSE_EXTRA + input_report_key(dev, BTN_SIDE, !!(data[0] & 0x08)); + input_report_key(dev, BTN_EXTRA, !!(data[0] & 0x10)); + input_report_rel(dev, REL_WHEEL, data[3]); +#endif +} + +static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_mouse *mouse; + + if (dev->descriptor.bNumConfigurations != 1) return NULL; + interface = dev->config[0].interface[ifnum].altsetting + 0; + + if (interface->bInterfaceClass != 3) return NULL; + if (interface->bInterfaceSubClass != 1) return NULL; + if (interface->bInterfaceProtocol != 2) return NULL; + if (interface->bNumEndpoints != 1) return NULL; + + endpoint = interface->endpoint + 0; + if (!(endpoint->bEndpointAddress & 0x80)) return NULL; + if ((endpoint->bmAttributes & 3) != 3) return NULL; + +#ifndef USBMOUSE_EXTRA + usb_set_protocol(dev, 0); +#endif + + if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL; + memset(mouse, 0, sizeof(struct usb_mouse)); + + mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); +#ifdef USBMOUSE_EXTRA + mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); + mouse->dev.relbit[0] |= BIT(REL_WHEEL); +#endif + + { + int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + int maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp, + usb_mouse_irq, mouse, endpoint->bInterval); + } + + if (usb_submit_urb(&mouse->irq)) { + kfree(mouse); + return NULL; + } + + input_register_device(&mouse->dev); + + printk(KERN_INFO "input%d: USB HIDBP mouse\n", mouse->dev.number); + + return mouse; +} + +static void usb_mouse_disconnect(struct usb_device *dev, void *ptr) +{ + struct usb_mouse *mouse = ptr; + usb_unlink_urb(&mouse->irq); + input_unregister_device(&mouse->dev); + kfree(mouse); +} + +static struct usb_driver usb_mouse_driver = { + name: "usb_mouse", + probe: usb_mouse_probe, + disconnect: usb_mouse_disconnect, +}; + +#ifdef MODULE +void cleanup_module(void) +{ + usb_deregister(&usb_mouse_driver); +} + +int init_module(void) +#else +int usb_mouse_init(void) +#endif +{ + usb_register(&usb_mouse_driver); + return 0; +} + diff --git a/fs/cramfs/inflate/Makefile b/fs/cramfs/inflate/Makefile index 294c36ced254..92feb8325b45 100644 --- a/fs/cramfs/inflate/Makefile +++ b/fs/cramfs/inflate/Makefile @@ -26,9 +26,9 @@ # uncompression can be done without blocking on allocation). # -OBJECTFILES=adler32.o infblock.o infcodes.o inffast.o inflate.o inftrees.o infutil.o uncompr.o +O_TARGET := zlib.o -zlib.o: $(OBJECTFILES) - ld -r -o zlib.o $(OBJECTFILES) +O_OBJS := adler32.o infblock.o infcodes.o inffast.o inflate.o \ + inftrees.o infutil.o uncompr.o include $(TOPDIR)/Rules.make diff --git a/fs/cramfs/inflate/infblock.c b/fs/cramfs/inflate/infblock.c index 1266f90ce82d..b6cc1fc86465 100644 --- a/fs/cramfs/inflate/infblock.c +++ b/fs/cramfs/inflate/infblock.c @@ -80,7 +80,6 @@ uLongf *c; s->read = s->write = s->window; if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); - Tracev((stderr, "inflate: blocks reset\n")); } @@ -100,7 +99,6 @@ uInt w; s->end = s->window + w; s->checkfn = c; s->mode = TYPE; - Tracev((stderr, "inflate: blocks allocated\n")); inflate_blocks_reset(s, z, Z_NULL); return s; } @@ -132,16 +130,12 @@ int r; switch (t >> 1) { case 0: /* stored */ - Tracev((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); DUMPBITS(3) t = k & 7; /* go to byte boundary */ DUMPBITS(t) s->mode = LENS; /* get length of stored block */ break; case 1: /* fixed */ - Tracev((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); { uInt bl, bd; inflate_huft *tl, *td; @@ -158,8 +152,6 @@ int r; s->mode = CODES; break; case 2: /* dynamic */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); DUMPBITS(3) s->mode = TABLE; break; @@ -182,7 +174,6 @@ int r; } s->sub.left = (uInt)b & 0xffff; b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); break; case STORED: @@ -197,9 +188,6 @@ int r; q += t; m -= t; if ((s->sub.left -= t) != 0) break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); s->mode = s->last ? DRY : TYPE; break; case TABLE: @@ -220,7 +208,6 @@ int r; } DUMPBITS(14) s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); s->mode = BTREE; case BTREE: while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) @@ -242,7 +229,6 @@ int r; LEAVE } s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); s->mode = DTREE; case DTREE: while (t = s->sub.trees.table, @@ -305,7 +291,6 @@ int r; r = t; LEAVE } - Tracev((stderr, "inflate: trees ok\n")); if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) { r = Z_MEM_ERROR; @@ -321,9 +306,6 @@ int r; r = Z_OK; inflate_codes_free(s->sub.decode.codes, z); LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); if (!s->last) { s->mode = TYPE; @@ -353,7 +335,6 @@ inflate_blocks_statef *s; z_streamp z; { inflate_blocks_reset(s, z, Z_NULL); - Tracev((stderr, "inflate: blocks freed\n")); return Z_OK; } diff --git a/fs/cramfs/inflate/infcodes.c b/fs/cramfs/inflate/infcodes.c index c6aea522e79f..ea7f6aba8e53 100644 --- a/fs/cramfs/inflate/infcodes.c +++ b/fs/cramfs/inflate/infcodes.c @@ -72,7 +72,6 @@ z_streamp z; c->dbits = (Byte)bd; c->ltree = tl; c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); } return c; } @@ -127,9 +126,6 @@ int r; if (e == 0) /* literal */ { c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); c->mode = LIT; break; } @@ -148,7 +144,6 @@ int r; } if (e & 32) /* end of block */ { - Tracevv((stderr, "inflate: end of block\n")); c->mode = WASH; break; } @@ -163,7 +158,6 @@ int r; DUMPBITS(j) c->sub.code.need = c->dbits; c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); c->mode = DIST; case DIST: /* i: get distance next */ j = c->sub.code.need; @@ -193,7 +187,6 @@ int r; NEEDBITS(j) c->sub.copy.dist += (uInt)b & inflate_mask[j]; DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); c->mode = COPY; case COPY: /* o: copying bytes in window, waiting for space */ #ifndef __TURBOC__ /* Turbo C bug for following expression */ @@ -223,7 +216,6 @@ int r; case WASH: /* o: got eob, possibly more output */ if (k > 7) /* return unused byte, if any */ { - Assert(k < 16, "inflate_codes grabbed too many bytes") k -= 8; n++; p--; /* can always return one */ @@ -252,5 +244,4 @@ void inflate_codes_free(c, z) inflate_codes_statef *c; z_streamp z; { - Tracev((stderr, "inflate: codes free\n")); } diff --git a/fs/cramfs/inflate/inffast.c b/fs/cramfs/inflate/inffast.c index 61a78ee933fc..5da2cd0a993c 100644 --- a/fs/cramfs/inflate/inffast.c +++ b/fs/cramfs/inflate/inffast.c @@ -60,9 +60,6 @@ z_streamp z; if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) { DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; continue; @@ -75,7 +72,6 @@ z_streamp z; e &= 15; c = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); /* decode distance base of block to copy */ GRABBITS(15); /* max bits for distance code */ @@ -89,7 +85,6 @@ z_streamp z; GRABBITS(e) /* get extra bits (up to 13) */ d = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); /* do the copy */ m -= c; @@ -138,9 +133,6 @@ z_streamp z; if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) { DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; break; @@ -148,7 +140,6 @@ z_streamp z; } else if (e & 32) { - Tracevv((stderr, "inflate: * end of block\n")); UNGRAB UPDATE return Z_STREAM_END; diff --git a/fs/cramfs/inflate/inflate.c b/fs/cramfs/inflate/inflate.c index 2a160855e391..c5b7a0c44982 100644 --- a/fs/cramfs/inflate/inflate.c +++ b/fs/cramfs/inflate/inflate.c @@ -59,7 +59,6 @@ z_streamp z; z->msg = Z_NULL; z->state->mode = z->state->nowrap ? BLOCKS : METHOD; inflate_blocks_reset(z->state->blocks, z, Z_NULL); - Tracev((stderr, "inflate: reset\n")); return Z_OK; } @@ -72,7 +71,6 @@ z_streamp z; if (z->state->blocks != Z_NULL) inflate_blocks_free(z->state->blocks, z); z->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); return Z_OK; } @@ -120,7 +118,6 @@ int stream_size; inflateEnd(z); return Z_MEM_ERROR; } - Tracev((stderr, "inflate: allocated\n")); /* reset state */ inflateReset(z); @@ -180,7 +177,6 @@ int f; z->state->sub.marker = 5; /* can't try inflateSync */ break; } - Tracev((stderr, "inflate: zlib header ok\n")); if (!(b & PRESET_DICT)) { z->state->mode = BLOCKS; @@ -253,7 +249,6 @@ int f; z->state->sub.marker = 5; /* can't try inflateSync */ break; } - Tracev((stderr, "inflate: zlib check ok\n")); z->state->mode = DONE; case DONE: return Z_STREAM_END; diff --git a/fs/cramfs/inflate/zutil.h b/fs/cramfs/inflate/zutil.h index 4816d01683e5..b3aa1991b5a7 100644 --- a/fs/cramfs/inflate/zutil.h +++ b/fs/cramfs/inflate/zutil.h @@ -8,23 +8,15 @@ subject to change. Applications should only use zlib.h. */ -/* @(#) $Id$ */ +/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */ #ifndef _Z_UTIL_H #define _Z_UTIL_H #include "zlib.h" -# include -# include - -#ifdef __KERNEL__ -# include -# include -#else -# include -# include -#endif +#include +#include #ifndef local # define local static @@ -37,15 +29,6 @@ typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; -extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - /* common constants */ #ifndef DEF_WBITS @@ -77,44 +60,11 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ #ifndef OS_CODE # define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, uInt len)); -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) ({ \ - printf("alloc %d %d at %s:%d\n", items, size, __FILE__, __LINE__); \ - calloc((items), (size)); }) -#define ZFREE(strm, addr) free(addr) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} #endif /* _Z_UTIL_H */ diff --git a/fs/filesystems.c b/fs/filesystems.c index 42056c7b96f5..bae48e19a865 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -52,6 +52,10 @@ extern int init_coda(void); extern int init_devpts_fs(void); #endif +#ifdef CONFIG_SUN_OPENPROMFS +extern int init_openprom_fs(void); +#endif + void __init filesystem_setup(void) { #ifdef CONFIG_MINIX_FS diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 08405bff0e8d..f677594deac2 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -1,4 +1,4 @@ -/* $Id: inode.c,v 1.1 1999/12/20 12:23:44 jj Exp $ +/* $Id: inode.c,v 1.2 1999/12/27 07:13:38 anton Exp $ * openpromfs.c: /proc/openprom handling routines * * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) @@ -1107,7 +1107,7 @@ static struct file_system_type openprom_fs_type = { NULL }; -static int init_openprom_fs(void) +int init_openprom_fs(void) { nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0); if (!nodes) { diff --git a/fs/super.c b/fs/super.c index 9f901236be09..bea64227410c 100644 --- a/fs/super.c +++ b/fs/super.c @@ -181,7 +181,6 @@ int register_filesystem(struct file_system_type * fs) return 0; } -#ifdef CONFIG_MODULES int unregister_filesystem(struct file_system_type * fs) { struct file_system_type ** tmp; @@ -197,7 +196,6 @@ int unregister_filesystem(struct file_system_type * fs) } return -EINVAL; } -#endif static int fs_index(const char * __name) { diff --git a/include/asm-sparc/dma.h b/include/asm-sparc/dma.h index 0c36c64c4dce..32607e9da381 100644 --- a/include/asm-sparc/dma.h +++ b/include/asm-sparc/dma.h @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.34 1999/10/24 16:01:21 zaitcev Exp $ +/* $Id: dma.h,v 1.35 1999/12/27 06:37:09 anton Exp $ * include/asm-sparc/dma.h * * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) @@ -16,6 +16,7 @@ #include #include #include +#include #include extern spinlock_t dma_spin_lock; diff --git a/include/asm-sparc/fcntl.h b/include/asm-sparc/fcntl.h index 84367de40675..b2e490145371 100644 --- a/include/asm-sparc/fcntl.h +++ b/include/asm-sparc/fcntl.h @@ -1,4 +1,4 @@ -/* $Id: fcntl.h,v 1.11 1998/10/26 20:03:10 davem Exp $ */ +/* $Id: fcntl.h,v 1.12 1999/12/27 06:37:11 anton Exp $ */ #ifndef _SPARC_FCNTL_H #define _SPARC_FCNTL_H @@ -19,6 +19,7 @@ #define O_NOCTTY 0x8000 /* not fcntl */ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ +#define O_LARGEFILE 0x40000 #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff --git a/include/asm-sparc/pgalloc.h b/include/asm-sparc/pgalloc.h new file mode 100644 index 000000000000..c8e5d10628b8 --- /dev/null +++ b/include/asm-sparc/pgalloc.h @@ -0,0 +1,157 @@ +/* $Id: pgalloc.h,v 1.1 1999/12/28 04:13:35 anton Exp $ */ +#ifndef _SPARC_PGALLOC_H +#define _SPARC_PGALLOC_H + +#include +#include + +#include +#include + +/* Fine grained cache/tlb flushing. */ +#ifdef __SMP__ +BTFIXUPDEF_CALL(void, local_flush_cache_all, void) +BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *) +BTFIXUPDEF_CALL(void, local_flush_cache_range, struct mm_struct *, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, local_flush_cache_page, struct vm_area_struct *, unsigned long) + +#define local_flush_cache_all() BTFIXUP_CALL(local_flush_cache_all)() +#define local_flush_cache_mm(mm) BTFIXUP_CALL(local_flush_cache_mm)(mm) +#define local_flush_cache_range(mm,start,end) BTFIXUP_CALL(local_flush_cache_range)(mm,start,end) +#define local_flush_cache_page(vma,addr) BTFIXUP_CALL(local_flush_cache_page)(vma,addr) + +BTFIXUPDEF_CALL(void, local_flush_tlb_all, void) +BTFIXUPDEF_CALL(void, local_flush_tlb_mm, struct mm_struct *) +BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct mm_struct *, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, local_flush_tlb_page, struct vm_area_struct *, unsigned long) + +#define local_flush_tlb_all() BTFIXUP_CALL(local_flush_tlb_all)() +#define local_flush_tlb_mm(mm) BTFIXUP_CALL(local_flush_tlb_mm)(mm) +#define local_flush_tlb_range(mm,start,end) BTFIXUP_CALL(local_flush_tlb_range)(mm,start,end) +#define local_flush_tlb_page(vma,addr) BTFIXUP_CALL(local_flush_tlb_page)(vma,addr) + +BTFIXUPDEF_CALL(void, local_flush_page_to_ram, struct page *) +BTFIXUPDEF_CALL(void, local_flush_sig_insns, struct mm_struct *, unsigned long) + +#define local_flush_page_to_ram(page) BTFIXUP_CALL(local_flush_page_to_ram)(page) +#define local_flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(local_flush_sig_insns)(mm,insn_addr) + +extern void smp_flush_cache_all(void); +extern void smp_flush_cache_mm(struct mm_struct *mm); +extern void smp_flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end); +extern void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page); + +extern void smp_flush_tlb_all(void); +extern void smp_flush_tlb_mm(struct mm_struct *mm); +extern void smp_flush_tlb_range(struct mm_struct *mm, + unsigned long start, + unsigned long end); +extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page); +extern void smp_flush_page_to_ram(struct page *page); +extern void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); +#endif + +BTFIXUPDEF_CALL(void, flush_cache_all, void) +BTFIXUPDEF_CALL(void, flush_cache_mm, struct mm_struct *) +BTFIXUPDEF_CALL(void, flush_cache_range, struct mm_struct *, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long) + +#define flush_cache_all() BTFIXUP_CALL(flush_cache_all)() +#define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm) +#define flush_cache_range(mm,start,end) BTFIXUP_CALL(flush_cache_range)(mm,start,end) +#define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr) +#define flush_icache_range(start, end) do { } while (0) + +BTFIXUPDEF_CALL(void, flush_tlb_all, void) +BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *) +BTFIXUPDEF_CALL(void, flush_tlb_range, struct mm_struct *, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, flush_tlb_page, struct vm_area_struct *, unsigned long) + +#define flush_tlb_all() BTFIXUP_CALL(flush_tlb_all)() +#define flush_tlb_mm(mm) BTFIXUP_CALL(flush_tlb_mm)(mm) +#define flush_tlb_range(mm,start,end) BTFIXUP_CALL(flush_tlb_range)(mm,start,end) +#define flush_tlb_page(vma,addr) BTFIXUP_CALL(flush_tlb_page)(vma,addr) + +BTFIXUPDEF_CALL(void, flush_page_to_ram, struct page *) +BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long) + +#define flush_page_to_ram(page) BTFIXUP_CALL(flush_page_to_ram)(page) +#define flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(flush_sig_insns)(mm,insn_addr) + +extern struct pgtable_cache_struct { + unsigned long *pgd_cache; + unsigned long *pte_cache; + unsigned long pgtable_cache_sz; + unsigned long pgd_cache_sz; + spinlock_t pgd_spinlock; + spinlock_t pte_spinlock; +} pgt_quicklists; +#define pgd_quicklist (pgt_quicklists.pgd_cache) +#define pmd_quicklist ((unsigned long *)0) +#define pte_quicklist (pgt_quicklists.pte_cache) +#define pgd_spinlock (pgt_quicklists.pgd_spinlock) +#define pte_spinlock (pgt_quicklists.pte_spinlock) +#define pgtable_cache_size (pgt_quicklists.pgtable_cache_sz) +#define pgd_cache_size (pgt_quicklists.pgd_cache_sz) + +BTFIXUPDEF_CALL(pte_t *, get_pte_fast, void) +BTFIXUPDEF_CALL(pgd_t *, get_pgd_fast, void) +BTFIXUPDEF_CALL(void, free_pte_slow, pte_t *) +BTFIXUPDEF_CALL(void, free_pgd_slow, pgd_t *) +BTFIXUPDEF_CALL(int, do_check_pgt_cache, int, int) + +#define get_pte_fast() BTFIXUP_CALL(get_pte_fast)() +extern __inline__ pmd_t *get_pmd_fast(void) +{ + return (pmd_t *)0; +} +#define get_pgd_fast() BTFIXUP_CALL(get_pgd_fast)() +#define free_pte_slow(pte) BTFIXUP_CALL(free_pte_slow)(pte) +extern __inline__ void free_pmd_slow(pmd_t *pmd) +{ +} +#define free_pgd_slow(pgd) BTFIXUP_CALL(free_pgd_slow)(pgd) +#define do_check_pgt_cache(low,high) BTFIXUP_CALL(do_check_pgt_cache)(low,high) + +/* + * Allocate and free page tables. The xxx_kernel() versions are + * used to allocate a kernel page table - this turns on ASN bits + * if any, and marks the page tables reserved. + */ +BTFIXUPDEF_CALL(void, pte_free_kernel, pte_t *) +BTFIXUPDEF_CALL(pte_t *, pte_alloc_kernel, pmd_t *, unsigned long) + +#define pte_free_kernel(pte) BTFIXUP_CALL(pte_free_kernel)(pte) +#define pte_alloc_kernel(pmd,addr) BTFIXUP_CALL(pte_alloc_kernel)(pmd,addr) + +BTFIXUPDEF_CALL(void, pmd_free_kernel, pmd_t *) +BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_kernel, pgd_t *, unsigned long) + +#define pmd_free_kernel(pmd) BTFIXUP_CALL(pmd_free_kernel)(pmd) +#define pmd_alloc_kernel(pgd,addr) BTFIXUP_CALL(pmd_alloc_kernel)(pgd,addr) + +BTFIXUPDEF_CALL(void, pte_free, pte_t *) +BTFIXUPDEF_CALL(pte_t *, pte_alloc, pmd_t *, unsigned long) + +#define pte_free(pte) BTFIXUP_CALL(pte_free)(pte) +#define pte_alloc(pmd,addr) BTFIXUP_CALL(pte_alloc)(pmd,addr) + +BTFIXUPDEF_CALL(void, pmd_free, pmd_t *) +BTFIXUPDEF_CALL(pmd_t *, pmd_alloc, pgd_t *, unsigned long) + +#define pmd_free(pmd) BTFIXUP_CALL(pmd_free)(pmd) +#define pmd_alloc(pgd,addr) BTFIXUP_CALL(pmd_alloc)(pgd,addr) + +BTFIXUPDEF_CALL(void, pgd_free, pgd_t *) +BTFIXUPDEF_CALL(pgd_t *, pgd_alloc, void) + +#define pgd_free(pgd) BTFIXUP_CALL(pgd_free)(pgd) +#define pgd_alloc() BTFIXUP_CALL(pgd_alloc)() + +BTFIXUPDEF_CALL(void, set_pgdir, unsigned long, pgd_t) + +#define set_pgdir(address,entry) BTFIXUP_CALL(set_pgdir)(address,entry) + +#endif /* _SPARC64_PGALLOC_H */ diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h index 692fd0a64b5e..931e67169fc7 100644 --- a/include/asm-sparc/pgtable.h +++ b/include/asm-sparc/pgtable.h @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.86 1999/12/16 14:41:19 anton Exp $ */ +/* $Id: pgtable.h,v 1.87 1999/12/27 06:37:14 anton Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H @@ -9,7 +9,6 @@ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include #include #include #include @@ -23,10 +22,11 @@ #include #include #include +#include + +#ifndef __ASSEMBLY__ extern void load_mmu(void); -extern int io_remap_page_range(unsigned long from, unsigned long to, - unsigned long size, pgprot_t prot, int space); BTFIXUPDEF_CALL(void, quick_kernel_fault, unsigned long) @@ -120,10 +120,6 @@ BTFIXUPDEF_INT(page_kernel) #define PAGE_READONLY __pgprot(BTFIXUP_INT(page_readonly)) #define PAGE_KERNEL __pgprot(BTFIXUP_INT(page_kernel)) -BTFIXUPDEF_CALL(void, set_pgdir, unsigned long, pgd_t) - -#define set_pgdir(address,entry) BTFIXUP_CALL(set_pgdir)(address,entry) - /* Top-level page directory */ extern pgd_t swapper_pg_dir[1024]; @@ -297,7 +293,7 @@ BTFIXUPDEF_CALL_CONST(pte_t, pte_mkyoung, pte_t) #define page_pte(page) page_pte_prot(page, __pgprot(0)) /* Permanent address of a page. */ -#define page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT)) +#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; }) #define pte_page(x) (mem_map+pte_pagenr(x)) /* @@ -342,149 +338,6 @@ BTFIXUPDEF_CALL(pte_t *, pte_offset, pmd_t *, unsigned long) /* Find an entry in the third-level page table.. */ #define pte_offset(dir,addr) BTFIXUP_CALL(pte_offset)(dir,addr) -extern struct pgtable_cache_struct { - unsigned long *pgd_cache; - unsigned long *pte_cache; - unsigned long pgtable_cache_sz; - unsigned long pgd_cache_sz; - spinlock_t pgd_spinlock; - spinlock_t pte_spinlock; -} pgt_quicklists; -#define pgd_quicklist (pgt_quicklists.pgd_cache) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist (pgt_quicklists.pte_cache) -#define pgd_spinlock (pgt_quicklists.pgd_spinlock) -#define pte_spinlock (pgt_quicklists.pte_spinlock) -#define pgtable_cache_size (pgt_quicklists.pgtable_cache_sz) -#define pgd_cache_size (pgt_quicklists.pgd_cache_sz) - -BTFIXUPDEF_CALL(pte_t *, get_pte_fast, void) -BTFIXUPDEF_CALL(pgd_t *, get_pgd_fast, void) -BTFIXUPDEF_CALL(void, free_pte_slow, pte_t *) -BTFIXUPDEF_CALL(void, free_pgd_slow, pgd_t *) -BTFIXUPDEF_CALL(int, do_check_pgt_cache, int, int) - -#define get_pte_fast() BTFIXUP_CALL(get_pte_fast)() -extern __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} -#define get_pgd_fast() BTFIXUP_CALL(get_pgd_fast)() -#define free_pte_slow(pte) BTFIXUP_CALL(free_pte_slow)(pte) -extern __inline__ void free_pmd_slow(pmd_t *pmd) -{ -} -#define free_pgd_slow(pgd) BTFIXUP_CALL(free_pgd_slow)(pgd) -#define do_check_pgt_cache(low,high) BTFIXUP_CALL(do_check_pgt_cache)(low,high) - -/* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any, and marks the page tables reserved. - */ -BTFIXUPDEF_CALL(void, pte_free_kernel, pte_t *) -BTFIXUPDEF_CALL(pte_t *, pte_alloc_kernel, pmd_t *, unsigned long) - -#define pte_free_kernel(pte) BTFIXUP_CALL(pte_free_kernel)(pte) -#define pte_alloc_kernel(pmd,addr) BTFIXUP_CALL(pte_alloc_kernel)(pmd,addr) - -BTFIXUPDEF_CALL(void, pmd_free_kernel, pmd_t *) -BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_kernel, pgd_t *, unsigned long) - -#define pmd_free_kernel(pmd) BTFIXUP_CALL(pmd_free_kernel)(pmd) -#define pmd_alloc_kernel(pgd,addr) BTFIXUP_CALL(pmd_alloc_kernel)(pgd,addr) - -BTFIXUPDEF_CALL(void, pte_free, pte_t *) -BTFIXUPDEF_CALL(pte_t *, pte_alloc, pmd_t *, unsigned long) - -#define pte_free(pte) BTFIXUP_CALL(pte_free)(pte) -#define pte_alloc(pmd,addr) BTFIXUP_CALL(pte_alloc)(pmd,addr) - -BTFIXUPDEF_CALL(void, pmd_free, pmd_t *) -BTFIXUPDEF_CALL(pmd_t *, pmd_alloc, pgd_t *, unsigned long) - -#define pmd_free(pmd) BTFIXUP_CALL(pmd_free)(pmd) -#define pmd_alloc(pgd,addr) BTFIXUP_CALL(pmd_alloc)(pgd,addr) - -BTFIXUPDEF_CALL(void, pgd_free, pgd_t *) -BTFIXUPDEF_CALL(pgd_t *, pgd_alloc, void) - -#define pgd_free(pgd) BTFIXUP_CALL(pgd_free)(pgd) -#define pgd_alloc() BTFIXUP_CALL(pgd_alloc)() - -/* Fine grained cache/tlb flushing. */ - -#ifdef __SMP__ -BTFIXUPDEF_CALL(void, local_flush_cache_all, void) -BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *) -BTFIXUPDEF_CALL(void, local_flush_cache_range, struct mm_struct *, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, local_flush_cache_page, struct vm_area_struct *, unsigned long) - -#define local_flush_cache_all() BTFIXUP_CALL(local_flush_cache_all)() -#define local_flush_cache_mm(mm) BTFIXUP_CALL(local_flush_cache_mm)(mm) -#define local_flush_cache_range(mm,start,end) BTFIXUP_CALL(local_flush_cache_range)(mm,start,end) -#define local_flush_cache_page(vma,addr) BTFIXUP_CALL(local_flush_cache_page)(vma,addr) - -BTFIXUPDEF_CALL(void, local_flush_tlb_all, void) -BTFIXUPDEF_CALL(void, local_flush_tlb_mm, struct mm_struct *) -BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct mm_struct *, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, local_flush_tlb_page, struct vm_area_struct *, unsigned long) - -#define local_flush_tlb_all() BTFIXUP_CALL(local_flush_tlb_all)() -#define local_flush_tlb_mm(mm) BTFIXUP_CALL(local_flush_tlb_mm)(mm) -#define local_flush_tlb_range(mm,start,end) BTFIXUP_CALL(local_flush_tlb_range)(mm,start,end) -#define local_flush_tlb_page(vma,addr) BTFIXUP_CALL(local_flush_tlb_page)(vma,addr) - -BTFIXUPDEF_CALL(void, local_flush_page_to_ram, struct page *) -BTFIXUPDEF_CALL(void, local_flush_sig_insns, struct mm_struct *, unsigned long) - -#define local_flush_page_to_ram(page) BTFIXUP_CALL(local_flush_page_to_ram)(page) -#define local_flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(local_flush_sig_insns)(mm,insn_addr) - -extern void smp_flush_cache_all(void); -extern void smp_flush_cache_mm(struct mm_struct *mm); -extern void smp_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end); -extern void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page); - -extern void smp_flush_tlb_all(void); -extern void smp_flush_tlb_mm(struct mm_struct *mm); -extern void smp_flush_tlb_range(struct mm_struct *mm, - unsigned long start, - unsigned long end); -extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page); -extern void smp_flush_page_to_ram(struct page *page); -extern void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); -#endif - -BTFIXUPDEF_CALL(void, flush_cache_all, void) -BTFIXUPDEF_CALL(void, flush_cache_mm, struct mm_struct *) -BTFIXUPDEF_CALL(void, flush_cache_range, struct mm_struct *, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long) - -#define flush_cache_all() BTFIXUP_CALL(flush_cache_all)() -#define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm) -#define flush_cache_range(mm,start,end) BTFIXUP_CALL(flush_cache_range)(mm,start,end) -#define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr) -#define flush_icache_range(start, end) do { } while (0) - -BTFIXUPDEF_CALL(void, flush_tlb_all, void) -BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *) -BTFIXUPDEF_CALL(void, flush_tlb_range, struct mm_struct *, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, flush_tlb_page, struct vm_area_struct *, unsigned long) - -#define flush_tlb_all() BTFIXUP_CALL(flush_tlb_all)() -#define flush_tlb_mm(mm) BTFIXUP_CALL(flush_tlb_mm)(mm) -#define flush_tlb_range(mm,start,end) BTFIXUP_CALL(flush_tlb_range)(mm,start,end) -#define flush_tlb_page(vma,addr) BTFIXUP_CALL(flush_tlb_page)(vma,addr) - -BTFIXUPDEF_CALL(void, flush_page_to_ram, struct page *) -BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long) - -#define flush_page_to_ram(page) BTFIXUP_CALL(flush_page_to_ram)(page) -#define flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(flush_sig_insns)(mm,insn_addr) - /* The permissions for pgprot_val to make a page mapped on the obio space */ extern unsigned int pg_iobits; @@ -512,9 +365,12 @@ BTFIXUPDEF_CALL(void, update_mmu_cache, struct vm_area_struct *, unsigned long, extern int invalid_segment; -#define SWP_TYPE(entry) (((entry) >> 2) & 0x7f) -#define SWP_OFFSET(entry) (((entry) >> 9) & 0x3ffff) -#define SWP_ENTRY(type,offset) ((((type) & 0x7f) << 2) | (((offset) & 0x3ffff) << 9)) +/* Encode and de-code a swap entry */ +#define SWP_TYPE(x) (((x).val >> 2) & 0x7f) +#define SWP_OFFSET(x) (((x).val >> 9) & 0x3ffff) +#define SWP_ENTRY(type,offset) ((swp_entry_t) { (((type) & 0x7f) << 2) | (((offset) & 0x3ffff) << 9) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) struct ctx_list { struct ctx_list *next; @@ -579,6 +435,12 @@ __get_iospace (unsigned long addr) extern unsigned long *sparc_valid_addr_bitmap; /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ -#define kern_addr_valid(addr) (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap)) +#define kern_addr_valid(addr) \ + (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap)) + +extern int io_remap_page_range(unsigned long from, unsigned long to, + unsigned long size, pgprot_t prot, int space); + +#endif /* !(__ASSEMBLY__) */ #endif /* !(_SPARC_PGTABLE_H) */ diff --git a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h index 5af2d7d1a484..ecfc3037f460 100644 --- a/include/asm-sparc/sbus.h +++ b/include/asm-sparc/sbus.h @@ -1,4 +1,4 @@ -/* $Id: sbus.h,v 1.19 1999/10/25 06:17:56 zaitcev Exp $ +/* $Id: sbus.h,v 1.20 1999/12/27 06:37:17 anton Exp $ * sbus.h: Defines for the Sun SBus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -108,7 +108,7 @@ extern void sbus_free_consistant(struct sbus_dev *, long, void *, u32); /* All the rest use streaming mode mappings. */ extern u32 sbus_map_single(struct sbus_dev *, void *, long); extern void sbus_unmap_single(struct sbus_dev *, u32, long); -extern void sbus_map_sg(struct sbus_dev *, struct scatterlist *, int); +extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int); extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int); /* Finally, allow explicit synchronization of streamable mappings. */ diff --git a/include/asm-sparc/scatterlist.h b/include/asm-sparc/scatterlist.h index 6f26d6478ee1..e5776df9b61f 100644 --- a/include/asm-sparc/scatterlist.h +++ b/include/asm-sparc/scatterlist.h @@ -1,7 +1,9 @@ -/* $Id: scatterlist.h,v 1.3 1999/10/18 01:47:13 zaitcev Exp $ */ +/* $Id: scatterlist.h,v 1.4 1999/12/27 06:37:20 anton Exp $ */ #ifndef _SPARC_SCATTERLIST_H #define _SPARC_SCATTERLIST_H +#include + struct scatterlist { char * address; /* Location data is to be transferred to */ char * alt_address; /* Location of actual if address is a diff --git a/include/asm-sparc/semaphore.h b/include/asm-sparc/semaphore.h index 9c647a571d06..68c2dc3596ee 100644 --- a/include/asm-sparc/semaphore.h +++ b/include/asm-sparc/semaphore.h @@ -208,6 +208,194 @@ extern inline void up(struct semaphore * sem) : "g3", "g4", "g7", "memory", "cc"); } +/* rw mutexes (should that be mutices? =) -- throw rw + * spinlocks and semaphores together, and this is what we + * end up with... + * + * The lock is initialized to BIAS. This way, a writer + * subtracts BIAS ands gets 0 for the case of an uncontended + * lock. Readers decrement by 1 and see a positive value + * when uncontended, negative if there are writers waiting + * (in which case it goes to sleep). + * + * The value 0x01000000 supports up to 128 processors and + * lots of processes. BIAS must be chosen such that subtracting + * BIAS once per CPU will result in the int remaining + * negative. + * In terms of fairness, this should result in the lock + * flopping back and forth between readers and writers + * under heavy use. + * + * -ben + */ +#define RW_LOCK_BIAS 0x01000000 + +struct rw_semaphore { + int count; + unsigned char lock; + unsigned char read_not_granted; + unsigned char write_not_granted; + wait_queue_head_t wait; + wait_queue_head_t write_bias_wait; +#if WAITQUEUE_DEBUG + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +#if WAITQUEUE_DEBUG +#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif + +#define __RWSEM_INITIALIZER(name) \ +{ RW_LOCK_BIAS, 0, 0xff, 0xff, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ + __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } + +extern inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RW_LOCK_BIAS; + sem->lock = 0; + sem->read_not_granted = 0xff; + sem->write_not_granted = 0xff; + init_waitqueue_head(&sem->wait); + init_waitqueue_head(&sem->write_bias_wait); +#if WAITQUEUE_DEBUG + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +extern void ___down_read(/* Special calling convention */ void); +extern void ___down_write(/* Special calling convention */ void); +extern void ___up_read(/* Special calling convention */ void); +extern void ___up_write(/* Special calling convention */ void); + +extern inline void down_read(struct rw_semaphore *sem) +{ + register atomic_t *ptr asm("g1"); + +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + ptr = (atomic_t *) __atomic_fool_gcc(sem); + + __asm__ __volatile__(" + mov %%o7, %%g4 + call %1 + add %%o7, 8, %%o7 + " + :: "r" (ptr), "i" (___down_read) + : "g2", "g3", "g4", "g7", "memory", "cc"); +#if WAITQUEUE_DEBUG + if (!sem->write_not_granted) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_inc(&sem->readers); +#endif +} + +extern inline void down_write(struct rw_semaphore *sem) +{ + register atomic_t *ptr asm("g1"); + +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + ptr = (atomic_t *) __atomic_fool_gcc(sem); + + __asm__ __volatile__(" + mov %%o7, %%g4 + call %1 + add %%o7, 8, %%o7 + " + :: "r" (ptr), "i" (___down_write) + : "g2", "g3", "g4", "g7", "memory", "cc"); +#if WAITQUEUE_DEBUG + if (atomic_read(&sem->writers)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (!sem->read_not_granted) + BUG(); + if (!sem->write_not_granted) + BUG(); + atomic_inc(&sem->writers); +#endif +} + +/* When a reader does a release, the only significant + * case is when there was a writer waiting, and we've + * bumped the count to 0: we must wake the writer up. + */ +extern inline void __up_read(struct rw_semaphore *sem) +{ + register atomic_t *ptr asm("g1"); + + ptr = (atomic_t *) __atomic_fool_gcc(sem); + + __asm__ __volatile__(" + mov %%o7, %%g4 + call %1 + add %%o7, 8, %%o7 + " + :: "r" (ptr), "i" (___up_read) + : "g2", "g3", "g4", "g7", "memory", "cc"); +} + +/* releasing the writer is easy -- just release it and + * wake up any sleepers. + */ +extern inline void __up_write(struct rw_semaphore *sem) +{ + register atomic_t *ptr asm("g1"); + + ptr = (atomic_t *) __atomic_fool_gcc(sem); + + __asm__ __volatile__(" + mov %%o7, %%g4 + call %1 + add %%o7, 8, %%o7 + " + :: "r" (ptr), "i" (___up_write) + : "g2", "g3", "g4", "g7", "memory", "cc"); +} + +extern inline void up_read(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (!sem->write_not_granted) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_dec(&sem->readers); +#endif + __up_read(sem); +} + +extern inline void up_write(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (!sem->read_not_granted) + BUG(); + if (!sem->write_not_granted) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (atomic_read(&sem->writers) != 1) + BUG(); + atomic_dec(&sem->writers); +#endif + __up_write(sem); +} + #endif /* __KERNEL__ */ #endif /* !(_SPARC_SEMAPHORE_H) */ diff --git a/include/asm-sparc/sfp-machine.h b/include/asm-sparc/sfp-machine.h index 9ac17ed0afb5..c3f12332dee5 100644 --- a/include/asm-sparc/sfp-machine.h +++ b/include/asm-sparc/sfp-machine.h @@ -35,7 +35,7 @@ #define _FP_MUL_MEAT_D(R,X,Y) \ _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) #define _FP_MUL_MEAT_Q(R,X,Y) \ - _FP_MUL_MEAT_5_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) + _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) diff --git a/include/asm-sparc64/semaphore.h b/include/asm-sparc64/semaphore.h index e119514c4cb9..717f6a533a04 100644 --- a/include/asm-sparc64/semaphore.h +++ b/include/asm-sparc64/semaphore.h @@ -66,7 +66,7 @@ extern __inline__ void down(struct semaphore * sem) #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - __asm__ __volatile__(" + __asm__ __volatile__(" 1: lduw [%0], %%g5 sub %%g5, 1, %%g7 cas [%0], %%g5, %%g7 @@ -100,7 +100,7 @@ extern __inline__ int down_interruptible(struct semaphore *sem) #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - __asm__ __volatile__(" + __asm__ __volatile__(" 1: lduw [%2], %%g5 sub %%g5, 1, %%g7 cas [%2], %%g5, %%g7 @@ -136,7 +136,7 @@ extern inline int down_trylock(struct semaphore *sem) #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - __asm__ __volatile__(" + __asm__ __volatile__(" 1: lduw [%2], %%g5 sub %%g5, 1, %%g7 cas [%2], %%g5, %%g7 @@ -197,7 +197,262 @@ extern __inline__ void up(struct semaphore * sem) .previous\n" : : "r" (__atomic_fool_gcc(sem)), "i" (__up) : "g5", "g7", "memory", "cc"); -} +} + +/* rw mutexes (should that be mutices? =) -- throw rw + * spinlocks and semaphores together, and this is what we + * end up with... + * + * The lock is initialized to BIAS. This way, a writer + * subtracts BIAS ands gets 0 for the case of an uncontended + * lock. Readers decrement by 1 and see a positive value + * when uncontended, negative if there are writers waiting + * (in which case it goes to sleep). + * + * The value 0x01000000 supports up to 128 processors and + * lots of processes. BIAS must be chosen such that subtracting + * BIAS once per CPU will result in the int remaining + * negative. + * In terms of fairness, this should result in the lock + * flopping back and forth between readers and writers + * under heavy use. + * + * -ben + * + * Once we start supporting machines with more than 128 CPUs, + * we should go for using a 64bit atomic type instead of 32bit + * as counter. We shall probably go for bias 0x80000000 then, + * so that single sethi can set it. + * + * -jj + */ +#define RW_LOCK_BIAS 0x01000000 +#define RW_LOCK_BIAS_STR "0x01000000" + +struct rw_semaphore { + int count; + /* So that this does not have to be 64bit type, + * we'll use le bitops on it which use casa instead of casx. + * bit 0 means read bias granted + * bit 1 means write bias granted + */ + unsigned granted; + wait_queue_head_t wait; + wait_queue_head_t write_bias_wait; +#if WAITQUEUE_DEBUG + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +#if WAITQUEUE_DEBUG +#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif + +#define __RWSEM_INITIALIZER(name) \ +{ RW_LOCK_BIAS, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ + __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } + +extern inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RW_LOCK_BIAS; + sem->granted = 0; + init_waitqueue_head(&sem->wait); + init_waitqueue_head(&sem->write_bias_wait); +#if WAITQUEUE_DEBUG + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +extern void __down_read_failed(/* Special calling convention */ void); +extern void __down_write_failed(/* Special calling convention */ void); +extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers); + +extern inline void down_read(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + __asm__ __volatile__(" + 1: lduw [%0], %%g5 + subcc %%g5, 1, %%g7 + cas [%0], %%g5, %%g7 + bneg,pn %%icc, 3f + cmp %%g5, %%g7 + bne,pn %%icc, 1b + membar #StoreStore + 2: + .subsection 2 + 3: bne,pn %%icc, 1b + mov %0, %%g7 + save %%sp, -160, %%sp + mov %%g1, %%l1 + mov %%g2, %%l2 + call %1 + mov %%g3, %%l3 + mov %%l1, %%g1 + mov %%l2, %%g2 + ba,pt %%xcc, 2b + restore %%l3, %%g0, %%g3 + .previous\n" + : : "r" (__atomic_fool_gcc(sem)), "i" (__down_read_failed) + : "g5", "g7", "memory", "cc"); +#if WAITQUEUE_DEBUG + if (test_le_bit(1, &sem->granted)) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_inc(&sem->readers); +#endif +} + +extern inline void down_write(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + __asm__ __volatile__(" + 1: lduw [%0], %%g5 + sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 + subcc %%g5, %%g7, %%g7 + cas [%0], %%g5, %%g7 + bne,pn %%icc, 3f + cmp %%g5, %%g7 + bne,pn %%icc, 1b + membar #StoreStore + 2: + .subsection 2 + 3: bne,pn %%icc, 1b + mov %0, %%g7 + save %%sp, -160, %%sp + mov %%g1, %%l1 + mov %%g2, %%l2 + call %1 + mov %%g3, %%l3 + mov %%l1, %%g1 + mov %%l2, %%g2 + ba,pt %%xcc, 2b + restore %%l3, %%g0, %%g3 + .previous\n" + : : "r" (__atomic_fool_gcc(sem)), "i" (__down_write_failed) + : "g5", "g7", "memory", "cc"); +#if WAITQUEUE_DEBUG + if (atomic_read(&sem->writers)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (test_le_bit(0, &sem->granted)) + BUG(); + if (test_le_bit(1, &sem->granted)) + BUG(); + atomic_inc(&sem->writers); +#endif +} + +/* When a reader does a release, the only significant + * case is when there was a writer waiting, and we've + * bumped the count to 0: we must wake the writer up. + */ +extern inline void __up_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__(" + membar #StoreLoad | #LoadLoad + 1: lduw [%0], %%g5 + addcc %%g5, 1, %%g7 + cas [%0], %%g5, %%g7 + be,pn %%icc, 3f + cmp %%g5, %%g7 + bne,pn %%icc, 1b + nop + 2: + .subsection 2 + 3: bne,pn %%icc, 1b + mov %0, %%g7 + save %%sp, -160, %%sp + mov %%g1, %%l1 + mov %%g2, %%l2 + clr %%o1 + mov %%g7, %%o0 + call %1 + mov %%g3, %%l3 + mov %%l1, %%g1 + mov %%l2, %%g2 + ba,pt %%xcc, 2b + restore %%l3, %%g0, %%g3 + .previous\n" + : : "r" (__atomic_fool_gcc(sem)), "i" (__rwsem_wake) + : "g5", "g7", "memory", "cc"); +} + +/* releasing the writer is easy -- just release it and + * wake up any sleepers. + */ +extern inline void __up_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__(" + membar #StoreLoad | #LoadLoad + 1: lduw [%0], %%g5 + sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 + add %%g5, %%g7, %%g7 + cas [%0], %%g5, %%g7 + cmp %%g5, %%g7 + bne,pn %%icc, 1b + sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 + addcc %%g5, %%g7, %%g5 + bcs,pn %%icc, 3f + nop + 2: + .subsection 2 + 3: mov %0, %%g7 + save %%sp, -160, %%sp + mov %%g1, %%l1 + mov %%g2, %%l2 + srl %%g5, 0, %%o1 + mov %%g7, %%o0 + call %1 + mov %%g3, %%l3 + mov %%l1, %%g1 + mov %%l2, %%g2 + ba,pt %%xcc, 2b + restore %%l3, %%g0, %%g3 + .previous\n" + : : "r" (__atomic_fool_gcc(sem)), "i" (__rwsem_wake) + : "g5", "g7", "memory", "cc"); +} + +extern inline void up_read(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (test_le_bit(1, &sem->granted)) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_dec(&sem->readers); +#endif + __up_read(sem); +} + +extern inline void up_write(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (test_le_bit(0, &sem->granted)) + BUG(); + if (test_le_bit(1, &sem->granted)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (atomic_read(&sem->writers) != 1) + BUG(); + atomic_dec(&sem->writers); +#endif + __up_write(sem); +} #endif /* __KERNEL__ */ diff --git a/include/asm-sparc64/string.h b/include/asm-sparc64/string.h index c1a67071f467..f6b69aa53cfd 100644 --- a/include/asm-sparc64/string.h +++ b/include/asm-sparc64/string.h @@ -1,9 +1,9 @@ -/* $Id: string.h,v 1.14 1998/10/20 03:09:18 jj Exp $ +/* $Id: string.h,v 1.15 1999/12/23 17:02:20 jj Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997,1999 Jakub Jelinek (jakub@redhat.com) */ #ifndef __SPARC64_STRING_H__ @@ -21,7 +21,9 @@ extern __kernel_size_t __memcpy_short(void *,const void *,__kernel_size_t,long,l extern __kernel_size_t __memcpy_entry(void *,const void *,__kernel_size_t,long,long); extern __kernel_size_t __memcpy_16plus(void *,const void *,__kernel_size_t,long,long); extern __kernel_size_t __memcpy_384plus(void *,const void *,__kernel_size_t,long,long); -extern __kernel_size_t __memset(void *,int,__kernel_size_t); +extern void *__memset(void *,int,__kernel_size_t); +extern void *__builtin_memcpy(void *,const void *,__kernel_size_t); +extern void *__builtin_memset(void *,int,__kernel_size_t); #ifndef EXPORT_SYMTAB_STROPS @@ -65,28 +67,24 @@ extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_si #define __HAVE_ARCH_MEMSET -extern inline void *__constant_memset(void *s, char c, __kernel_size_t count) +extern inline void *__constant_memset(void *s, int c, __kernel_size_t count) { extern __kernel_size_t __bzero(void *, __kernel_size_t); - if(!c) + if(!c) { __bzero(s, count); - else - __memset(s, c, count); - return s; -} - -extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count) -{ - __memset(s, c, count); - return s; + return s; + } else + return __memset(s, c, count); } #undef memset #define memset(s, c, count) \ -(__builtin_constant_p(c) ? \ - __constant_memset((s), (c), (count)) : \ - __nonconstant_memset((s), (c), (count))) +((__builtin_constant_p(count) && (count) <= 32) ? \ + __builtin_memset((s), (c), (count)) : \ + (__builtin_constant_p(c) ? \ + __constant_memset((s), (c), (count)) : \ + __memset((s), (c), (count)))) #define __HAVE_ARCH_MEMSCAN diff --git a/include/linux/input.h b/include/linux/input.h new file mode 100644 index 000000000000..82714d31e11e --- /dev/null +++ b/include/linux/input.h @@ -0,0 +1,443 @@ +#ifndef _INPUT_H +#define _INPUT_H + +/* + * input.h Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +/* + * The event structure itself + */ + +struct input_event { + struct timeval time; + unsigned short type; + unsigned short code; + unsigned int value; +}; + +/* + * Event types + */ + +#define EV_RST 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_MAX 0x1f + +/* + * Keys and buttons + */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 + +#define KEY_F13 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_F14 89 +#define KEY_F15 90 +#define KEY_F16 91 +#define KEY_F17 92 +#define KEY_F18 93 +#define KEY_F19 94 +#define KEY_F20 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_F21 120 +#define KEY_F22 121 +#define KEY_F23 122 +#define KEY_F24 123 +#define KEY_JPN 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 +#define KEY_AGAIN 129 +#define KEY_PROPS 130 +#define KEY_UNDO 131 +#define KEY_FRONT 132 +#define KEY_COPY 133 +#define KEY_OPEN 134 +#define KEY_PASTE 135 +#define KEY_FIND 136 +#define KEY_CUT 137 +#define KEY_HELP 138 +#define KEY_MENU 139 +#define KEY_CALC 140 +#define KEY_SETUP 141 +#define KEY_SLEEP 142 + +#define KEY_WAKEUP 143 +#define KEY_FILE 144 +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 +#define KEY_DIRECTION 153 +#define KEY_CYCLEWINDOWS 154 + +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 + +#define KEY_UNKNOWN 192 + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_BASE 0x125 +#define BTN_BASE2 0x126 +#define BTN_BASE3 0x127 +#define BTN_BASE4 0x128 +#define BTN_BASE5 0x129 + +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c + +#define KEY_MAX 0x1ff + +/* + * Relative axes + */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f + +/* + * Absolute axes + */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_MISC 0x18 +#define ABS_MAX 0x1f + +/* + * LEDs + */ + +#define LED_SCROLLL 0x00 +#define LED_NUML 0x01 +#define LED_CAPSL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_MAX 0x0f + +/* + * Autorepeat values + */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 + +/* + * Sounds + */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_MAX 0x07 + +#ifdef __KERNEL__ + +/* + * In-kernel definitions. + */ + +#include + +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define BIT(x) (1<<((x)%BITS_PER_LONG)) +#define LONG(x) ((x)/BITS_PER_LONG) + +struct input_dev { + + void *private; + + int number; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + + unsigned char *keycode; + unsigned int repeat_key; + struct timer_list timer; + + int abs[ABS_MAX + 1]; + int rep[REP_MAX + 1]; + + unsigned long key[NBITS(KEY_MAX)]; + unsigned long led[NBITS(LED_MAX)]; + unsigned long snd[NBITS(SND_MAX)]; + + int absmax[ABS_MAX + 1]; + int absmin[ABS_MAX + 1]; + int absfuzz[ABS_MAX + 1]; + int absflat[ABS_MAX + 1]; + + int (*open)(struct input_dev *dev); + void (*close)(struct input_dev *dev); + int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); + + struct input_handle *handle; + struct input_dev *next; +}; + +struct input_handler { + + void *private; + + void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); + int (*connect)(struct input_handler *handler, struct input_dev *dev); + void (*disconnect)(struct input_handle *handle); + + struct input_handle *handle; + + struct input_handler *next; +}; + +struct input_handle { + + void *private; + + struct input_dev *dev; + struct input_handler *handler; + + struct input_handle *dnext; + struct input_handle *hnext; +}; + +int keybdev_init(void); +int mousedev_init(void); +int joydev_init(void); +int evdev_init(void); + +void input_register_device(struct input_dev *); +void input_unregister_device(struct input_dev *); + +void input_register_handler(struct input_handler *); +void input_unregister_handler(struct input_handler *); + +void input_open_device(struct input_handle *); +void input_close_device(struct input_handle *); + +void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); + +#define input_report_key(a,b,c) input_event(a, EV_KEY, b, c) +#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) +#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) + +#endif +#endif diff --git a/include/linux/pci.h b/include/linux/pci.h index bc3fe4e3dbda..64184285d454 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -478,6 +478,7 @@ int pci_write_config_byte(struct pci_dev *dev, int where, u8 val); int pci_write_config_word(struct pci_dev *dev, int where, u16 val); int pci_write_config_dword(struct pci_dev *dev, int where, u32 val); +int pci_setup_device(struct pci_dev * dev); int pci_enable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); int pci_set_power_state(struct pci_dev *dev, int state); diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 1e9f9fc42ec7..fb3819ba81a1 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -130,8 +130,6 @@ struct pccard_operations { int (*set_io_map)(unsigned int sock, struct pccard_io_map *io); int (*get_mem_map)(unsigned int sock, struct pccard_mem_map *mem); int (*set_mem_map)(unsigned int sock, struct pccard_mem_map *mem); - int (*get_bridge)(unsigned int sock, struct cb_bridge_map *m); - int (*set_bridge)(unsigned int sock, struct cb_bridge_map *m); void (*proc_setup)(unsigned int sock, struct proc_dir_entry *base); }; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a7f689938fb8..12a8f8d72f4a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4,7 +4,7 @@ * Authors: Alan Cox * Florian La Roche * - * Version: $Id: skbuff.c,v 1.62 1999/12/23 02:13:42 davem Exp $ + * Version: $Id: skbuff.c,v 1.63 2000/01/02 09:15:17 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -358,8 +358,9 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, /* Set the tail pointer and length */ skb_put(n,skb->len); - /* Copy the bytes: data pointers must point to same data. */ - memcpy(n->data - skb_headroom(skb), skb->head, skb->end-skb->head); + + /* Copy the data only. */ + memcpy(n->data, skb->data, skb->len); copy_skb_header(n, skb); return n; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 21864c894787..9ae22d8181b2 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.113 1999/12/15 22:39:58 davem Exp $ + * $Id: tcp_ipv6.c,v 1.114 2000/01/03 17:19:17 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -273,8 +273,8 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor } } } - if (sk) - sock_hold(sk); + if (result) + sock_hold(result); read_unlock(&tcp_lhash_lock); return result; } @@ -730,7 +730,6 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr, if (dst == NULL) { struct flowi fl; - struct dst_entry *dst; /* BUGGG_FUTURE: Again, it is not clear how to handle rthdr case. Ignore this complexity diff --git a/net/netsyms.c b/net/netsyms.c index 97c2f57980ee..88cd2a03bb10 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -580,6 +580,7 @@ EXPORT_SYMBOL(nf_reinject); EXPORT_SYMBOL(nf_register_interest); EXPORT_SYMBOL(nf_unregister_interest); EXPORT_SYMBOL(nf_hook_slow); +EXPORT_SYMBOL(nf_hooks); #endif EXPORT_SYMBOL(register_gifconf); -- 2.39.5