E: xavyer@ix.netcom.com
D: USB Serial Empeg Empeg-car Mark I/II Driver
+N: Matthias Bruestle
+E: m@mbsks.franken.de
+D: REINER SCT cyberJack pinpad/e-com USB chipcard reader driver
+S: Germany
+
N: Ray Burr
E: ryb@nightmare.com
D: Original author of Amiga FFS filesystem
S: USA
N: Benjamin Herrenschmidt
-E: bh40@calva.net
+E: benh@kernel.crashing.org
E: benh@mipsys.com
-D: PowerMac booter (BootX)
-D: Additional PowerBook support
-D: Apple "Core99" machines support (ibook,g4,...)
-S: 22, rue des Marguettes
-S: 75012 Paris
+D: Various parts of PPC & PowerMac
+S: 122, boulevard Baille
+S: 13005 Marseille
S: France
N: Sebastian Hetze
N: Paul Mackerras
E: paulus@samba.org
+D: PPP driver
+D: Linux for PowerPC
D: Linux port for PCI Power Macintosh
N: Pat Mackinlay
S: 1098 VA Amsterdam
S: The Netherlands
+N: Jeroen Vreeken
+E: pe1rxq@amsat.org
+W: http://www.chello.nl/~j.vreeken/
+D: SE401 usb webcam driver
+S: Maastrichterweg 63
+S: 5554 GG Valkenswaard
+S: The Netherlands
+
N: Peter Shaobo Wang
E: pwang@mmdcorp.com
W: http://www.mmdcorp.com/pw/linux
PPP
---
-o <ftp://ftp.samba.org/ppp/ppp-2.4.0.tar.gz>
+o <ftp://ftp.samba.org/pub/ppp/ppp-2.4.0.tar.gz>
Isdn4k-utils
------------
The module will be called mct_u232.o. If you want to compile it as
a module, say M here and read Documentation/modules.txt.
+USB Prolific 2303 Single Port Serial Driver
+CONFIG_USB_SERIAL_PL2303
+ Say Y here if you want to use the PL2303 USB Serial single port
+ adapter from Prolific.
+
+ 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 pl2303.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt.
+
+USB REINER SCT cyberJack pinpad/e-com chipcard reader
+CONFIG_USB_SERIAL_CYBERJACK
+ Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
+ reader. This is an interface to ISO 7816 compatible contactbased
+ chipcards, e.g. GSM SIMs.
+
+ 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 cyberjack.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt.
+
+ If unsure, say N.
+
USB Edgeport Serial Driver
CONFIG_USB_SERIAL_EDGEPORT
Say Y here if you want to use any of the following devices from
module, say M here and read Documentation/modules.txt.
+USB SE401 Camera support
+CONFIG_USB_SE401
+ Say Y here if you want to connect this type of camera to your
+ computer's USB port. See Documentation/usb/se401.txt for more
+ information and for a list of supported cameras.
+
+ This driver uses the Video For Linux API. You must say Y or M to
+ "Video For Linux" (under Multimedia Devices) to use this driver.
+ Information on this API and pointers to "v4l" programs may be found
+ on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml .
+
+ 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 se401.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
USB ADMtek Pegasus-based ethernet device support
CONFIG_USB_PEGASUS
Say Y if you want to use your USB ethernet device. Supported
- Java(tm) Binary Kernel Support for Linux v1.02
+ Java(tm) Binary Kernel Support for Linux v1.03
----------------------------------------------
Linux beats them ALL! While all other OS's are TALKING about direct
(you should really have read binfmt_misc.txt now):
support for Java applications:
':Java:M::\xca\xfe\xba\xbe::/usr/local/bin/javawrapper:'
+ support for executable Jar files:
+ ':ExecutableJAR:E::jar::/usr/local/bin/jarwrapper:'
support for Java Applets:
':Applet:E::html::/usr/bin/appletviewer:'
or the following, if you want to be more selective:
====================== Cut here ===================
-Now simply chmod +x the .class and/or .html files you want to execute.
+====================== Cut here ===================
+#!/bin/bash
+# /usr/local/java/bin/jarwrapper - the wrapper for binfmt_misc/jar
+
+java -jar $1
+====================== Cut here ===================
+
+
+Now simply chmod +x the .class, .jar and/or .html files you want to execute.
To add a Java program to your path best put a symbolic link to the main
.class file into /usr/bin (or another place you like) omitting the .class
extension. The directory containing the original .class file will be
./HelloWorld.class
+To execute Java Jar files, simple chmod the *.jar files to include
+the execution bit, then just do
+ ./Application.jar
+
+
To execute Java Applets, simple chmod the *.html files to include
the execution bit, then just do
./Applet.html
originally by Brian A. Lantz, brian@lantz.com
heavily edited for binfmt_misc by Richard Günther
-new scripts by Colin J. Watson <cjw44@cam.ac.uk>.
+new scripts by Colin J. Watson <cjw44@cam.ac.uk>
+added executable Jar file support by Kurt Huwig <kurt@iku-netz.de>
--- /dev/null
+Linux driver for SE401 based USB cameras
+
+Copyright, 2001, Jeroen Vreeken
+
+
+INTRODUCTION:
+
+The SE401 chip is the used in low-cost usb webcams.
+It is produced by Endpoints Inc. (www.endpoints.com).
+It interfaces directly to a cmos image sensor and USB. The only other major
+part in a se401 based camera is a dram chip.
+
+The following cameras are known to work with this driver:
+
+Aox se401 (non-branded) cameras
+Philips PVCV665 USB VGA webcam 'Vesta Fun'
+Kensington VideoCAM PC Camera Model 67014
+Kensington VideoCAM PC Camera Model 67015
+Kensington VideoCAM PC Camera Model 67016
+Kensington VideoCAM PC Camera Model 67017
+
+
+WHAT YOU NEED:
+
+- USB support
+- VIDEO4LINUX support
+
+More information about USB support for linux can be found at:
+http://www.linux-usb.org
+
+
+MODULE OPTIONS:
+
+When the driver is compiled as a module you can also use the 'flickerless'
+option. With it exposure is limited to values that do not interfere with the
+net frequency. Valid options for this option are 0, 50 and 60. (0=disable,
+50=50hz, 60=60hz)
+
+
+KNOWN PROBLEMS:
+
+The driver works fine with the usb-ohci and uhci host controller drivers,
+the default settings also work with usb-uhci. But sending more then one bulk
+transfer at a time with usb-uhci doesn't work yet.
+Users of usb-ohci and uhci can safely enlarge SE401_NUMSBUF in se401.h in
+order to increase the throughput (and thus framerate).
+
+
+HELP:
+
+The latest info on this driver can be found at:
+http://www.chello.nl/~j.vreeken/se401/
+And questions to me can be send to:
+pe1rxq@amsat.org
Edgeport/16 Dual
+REINER SCT cyberJack pinpad/e-com USB chipcard reader
+
+ Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs.
+
+Current status:
+ This is the kernel part of the driver for this USB card reader.
+ There is also a user part for a CT-API driver available. A site
+ for downloading is TBA. For now, you can request it from the
+ maintainer (linux-usb@sii.li).
+
+
Generic Serial driver
If your device is not one of the above listed devices, compatible with
L: linux-x25@vger.kernel.org
S: Maintained
+LINUX FOR IBM pSERIES (RS/6000)
+P: Paul Mackerras
+M: paulus@au.ibm.com
+W: http://www.ibm.com/linux/ltc/projects/ppc
+S: Supported
+
LINUX FOR POWERPC
-P: Cort Dougan
-M: cort@fsmlabs.com
+P: Paul Mackerras
+M: paulus@samba.org
W: http://www.fsmlabs.com/linuxppcbk.html
-S: Maintained
+S: Supported
LINUX FOR POWER MACINTOSH
-P: Paul Mackerras
-M: paulus@samba.org
+P: Benjamin Herrenschmidt
+M: benh@kernel.crashing.org
W: http://www.linuxppc.org/
L: linuxppc-dev@lists.linuxppc.org
S: Maintained
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
+USB SERIAL CYBERJACK PINPAD/E-COM DRIVER
+M: linux-usb@sii.li
+L: linux-usb-users@lists.sourceforge.net
+L: linux-usb-devel@lists.sourceforge.net
+S: Supported
+
USB MASS STORAGE DRIVER
P: Matthew Dharm
M: mdharm-usb@one-eyed-alien.net
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 6
-EXTRAVERSION =-pre5
+EXTRAVERSION =-pre6
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
DRIVERS-m :=
DRIVERS- :=
+DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
DRIVERS-y += drivers/char/char.o \
drivers/block/block.o \
DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
-DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/reboot.h>
#include <asm/ptrace.h>
#include <asm/system.h>
static void
alcor_kill_arch(int mode)
{
- /* Who said DEC engineer's have no sense of humor? ;-) */
- if (alpha_using_srm) {
- *(vuip) GRU_RESET = 0x0000dead;
- mb();
+ switch(mode) {
+ case LINUX_REBOOT_CMD_RESTART:
+ /* Who said DEC engineer's have no sense of humor? ;-) */
+ if (alpha_using_srm) {
+ *(vuip) GRU_RESET = 0x0000dead;
+ mb();
+ }
+ break;
+ case LINUX_REBOOT_CMD_HALT:
+ break;
+ case LINUX_REBOOT_CMD_POWER_OFF:
+ break;
}
+
+ halt();
}
apcs-$(CONFIG_CPU_26) :=-mcpu=arm3 -Os
arch-y :=
-arch-$(CONFIG_CPU_32v3) :=-march=armv3m
+arch-$(CONFIG_CPU_32v3) :=-march=armv3
arch-$(CONFIG_CPU_32v4) :=-march=armv4
arch-$(CONFIG_CPU_32v5) :=-march=armv5
MACHINE = clps711x
endif
+ifeq ($(CONFIG_ARCH_ANAKIN),y)
+MACHINE = anakin
+endif
+
export LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS
# Only set INCDIR if its not already defined above
LIBS := arch/arm/fastfpe/fast-math-emu.o $(LIBS)
endif
-ifeq ($(CONFIG_ARCH_CLPS7500),y)
+ifeq ($(findstring y,$(CONFIG_ARCH_CLPS7500) $(CONFIG_ARCH_L7200)),y)
SUBDIRS += drivers/acorn/char
DRIVERS += drivers/acorn/char/acorn-char.o
endif
@( \
CFG=$(@:_config=); \
if [ -f arch/arm/def-configs/$$CFG ]; then \
- $(RM) arch/arm/defconfig; \
- cp arch/arm/def-configs/$$CFG arch/arm/defconfig; \
+ [ -f .config ] && $(MV) .config .config.old; \
+ cp arch/arm/def-configs/$$CFG .config; \
echo "*** Default configuration for $$CFG installed"; \
echo "*** Next, you may run 'make oldconfig'"; \
else \
ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
ZTEXTADDR = 0xC0200000
endif
+ifeq ($(CONFIG_SA1100_YOPY),y)
+ ZTEXTADDR = 0x00080000
+ ZBSSADDR = 0xc0200000
+endif
ifeq ($(CONFIG_SA1111),y)
ZRELADDR = 0xc0208000
endif
endif
+ifeq ($(CONFIG_ARCH_ANAKIN),y)
+ZTEXTADDR = 0x20008000
+endif
+
#
# If you don't define ZRELADDR above,
# then it defaults to ZTEXTADDR
endif
ifeq ($(CONFIG_ARCH_INTEGRATOR),y)
-OBJS += head-netwinder.o
+OBJS += head-integrator.o
endif
ifeq ($(CONFIG_ARCH_FTVPCI),y)
--- /dev/null
+#include <asm/mach-types.h>
+
+ .section ".start", #alloc, #execinstr
+ mov r7, #MACH_TYPE_INTEGRATOR
/*
* Debugging stuff
+ *
+ * Note that these macros must not contain any code which is not
+ * 100% relocatable. Any attempt to do so will result in a crash.
+ * Please select one of the following when turning on debugging.
*/
+#ifdef DEBUG
+#if 0 /* DC21285-type */
+ .macro loadsp, rb
+ mov \rb, #0x7c000000
+ .endm
+ .macro writeb, rb
+ strb \rb, [r3, #0x3f8]
+ .endm
+#elif 0 /* RiscPC-type */
+ .macro loadsp, rb
+ mov \rb, #0x03000000
+ orr \rb, \rb, #0x00010000
+ .endm
+ .macro writeb, rb
+ strb \rb, [r3, #0x3f8 << 2]
+ .endm
+#elif 0 /* integrator-type */
+ .macro loadsp, rb
+ mov \rb, #0x16000000
+ .endm
+ .macro writeb, rb
+ strb \rb, [r3, #0]
+ .endm
+#else
+#error no serial architecture defined
+#endif
+#endif
+
.macro kputc,val
mov r0, \val
bl putc
.macro debug_reloc_start
#ifdef DEBUG
kputc #'\n'
- kphex r6, 8
+ kphex r6, 8 /* processor id */
kputc #':'
- kphex r5, 8
+ kphex r7, 8 /* architecture id */
+ kputc #':'
+ mrc p15, 0, r0, c1, c0
+ kphex r0, 8 /* control reg
+ kputc #'\n'
+ kphex r5, 8 /* decompressed kernel start */
kputc #'-'
- kphex r8, 8
+ kphex r8, 8 /* decompressed kernel end */
kputc #'>'
- kphex r4, 8
+ kphex r4, 8 /* kernel execution address */
kputc #'\n'
#endif
.endm
.macro debug_reloc_end
#ifdef DEBUG
- mov r8, r0
- kphex r5, 8
- kputc #'-'
- kphex r8, 8
+ kphex r5, 8 /* end of kernel */
kputc #'\n'
mov r0, r4
- bl memdump
+ bl memdump /* dump 256 bytes at start of kernel */
#endif
.endm
-/*
- * Note that these macros must not contain any code which is not
- * 100% relocatable. Any attempt to do so will result in a crash.
- */
-#if 0
- .macro loadsp, rb
- mov \rb, #0x7c000000
- .endm
-
- .macro writeb, rb
- strb \rb, [r3, #0x3f8]
- .endm
-#else
- .macro loadsp, rb
- mov \rb, #0x03000000
- orr \rb, \rb, #0x00010000
- .endm
-
- .macro writeb, rb
- strb \rb, [r3, #0x3f8 << 2]
- .endm
-#endif
-
-
.section ".start", #alloc, #execinstr
/*
* sort out different calling conventions
.word _edata @ zImage end address
1: mov r7, r1 @ save architecture ID
mov r8, #0 @ save r0
-#ifdef CONFIG_ANGELBOOT
+
/*
* Booting from Angel - need to enter SVC mode and disable
- * FIQs/IRQs (numeric definitions from angel arm.h source)
+ * FIQs/IRQs (numeric definitions from angel arm.h source).
+ * We only do this if we were in user mode on entry.
*/
+ mrs r0, cpsr @ get current mode
+ tst r0, #3 @ not user?
+ bne not_angel
mov r0, #0x17 @ angel_SWIreason_EnterSVC
swi 0x123456 @ angel_SWI_ARM
- mrs r0, cpsr @ turn off interrupts to
+not_angel: mrs r0, cpsr @ turn off interrupts to
orr r0, r0, #0xc0 @ prevent angel from running
msr cpsr_c, r0
* Note that some cache flushing and other stuff may
* be needed here - is there an Angel SWI call for this?
*/
-#endif
+
/*
* some architecture specific code can be inserted
* by the linker here, but it should preserve r7 and r8.
.size proc_sa1110_type, . - proc_sa1110_type
/*
- * Turn off StrongARM cache and MMU. It is safe to
- * leave the I-cache on.
+ * Turn off the Cache and MMU. ARMv3 does not support
+ * reading the control register, but ARMv4 does.
*
- * On entry,
- * r6 = processor ID
- * On exit,
- * r0, r1 corrupted
- * This routine must preserve:
- * r4, r6, r7
+ * On entry, r6 = processor ID
+ * On exit, r0, r1 corrupted
+ * This routine must preserve: r4, r6, r7
*/
.align 5
-cache_off: ldr r1, proc_sa110_type
- eor r1, r1, r6
- movs r1, r1, lsr #5 @ catch SA110 and SA1100
- beq 1f
- ldr r1, proc_sa1110_type
- eor r1, r1, r6
- movs r1, r1, lsr #4
- movne pc, lr
-1:
+cache_off:
+#ifdef CONFIG_CPU_ARM610
+ eor r1, r6, #0x41000000
+ eor r1, r1, #0x00560000
+ bic r1, r1, #0x0000001f
+ teq r1, #0x00000600
+ mov r0, #0x00000060 @ ARM6 control reg.
+ beq __armv3_cache_off
+#endif
+#ifdef CONFIG_CPU_ARM710
+ eor r1, r6, #0x41000000
+ bic r1, r1, #0x00070000
+ bic r1, r1, #0x000000ff
+ teq r1, #0x00007000 @ ARM7
+ teqne r1, #0x00007100 @ ARM710
+ mov r0, #0x00000070 @ ARM7 control reg.
+ beq __armv3_cache_off
+#endif
mrc p15, 0, r0, c1, c0
bic r0, r0, #0x000d
- mcr p15, 0, r0, c1, c0
- mov pc, lr
+ mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
+ mov r0, #0
+ mcr p15, 0, r0, c7, c7 @ invalidate whole cache v4
+ mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4
+ mov pc, lr
+
+__armv3_cache_off:
+ mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
+ mov r0, #0
+ mcr p15, 0, r0, c7, c0 @ invalidate whole cache v3
+ mcr p15, 0, r0, c5, c0 @ invalidate whole TLB v3
+ mov pc, lr
/*
* Clean and flush the cache to maintain consistency.
memdump: mov r12, r0
mov r10, lr
- mov r1, #8
- bl phex
- mov r0, #'\n'
- bl putc
mov r11, #0
2: mov r0, r11, lsl #2
- mov r1, #4
+ add r0, r0, r12
+ mov r1, #8
bl phex
mov r0, #':'
bl putc
.text
GPIO_BASE: .long 0x90040000
-#define GPLR 0x00
-#define GPDR 0x04
-#define GPSR 0x08
-#define GAFR 0x1c
+#define GPLR 0x00
+#define GPDR 0x04
+#define GPSR 0x08
+#define GAFR 0x1c
PPC_BASE: .long 0x90060000
-#define PPAR 0x08
+#define PPAR 0x08
IC_BASE: .long 0x90050000
-#define ICMR 0x04
+#define ICMR 0x04
UART1_BASE: .long 0x80010000
UART3_BASE: .long 0x80050000
@ Initialize UART (if bootloader has not done it yet)...
teq r3, #MACH_TYPE_BRUTUS
teqne r3, #MACH_TYPE_ASSABET
+ teqne r3, #MACH_TYPE_ITSY
+ teqne r3, #MACH_TYPE_OMNIMETER
+ teqne r3, #MACH_TYPE_JORNADA720
teqne r3, #MACH_TYPE_GRAPHICSCLIENT
+ teqne r3, #MACH_TYPE_FLEXANET
bne skip_uart
@ UART3 if Assabet is used with Neponset
#define NR_syscalls 256
#else
+__syscall_start:
/* 0 */ .long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_exit)
.long SYMBOL_NAME(sys_fork_wrapper)
/* 160 */ .long SYMBOL_NAME(sys_sched_get_priority_min)
.long SYMBOL_NAME(sys_sched_rr_get_interval)
.long SYMBOL_NAME(sys_nanosleep)
- .long SYMBOL_NAME(sys_mremap)
+ .long SYMBOL_NAME(sys_arm_mremap)
.long SYMBOL_NAME(sys_setresuid16)
/* 165 */ .long SYMBOL_NAME(sys_getresuid16)
.long SYMBOL_NAME(sys_ni_syscall)
/* 215 */ .long SYMBOL_NAME(sys_setfsuid)
.long SYMBOL_NAME(sys_setfsgid)
.long SYMBOL_NAME(sys_getdents64)
+ .long SYMBOL_NAME(sys_pivot_root)
+ .long SYMBOL_NAME(sys_mincore)
+/* 220 */ .long SYMBOL_NAME(sys_madvise)
+ .long SYMBOL_NAME(sys_fcntl64)
+__syscall_end:
- .rept NR_syscalls-217
+ .rept NR_syscalls - (__syscall_end - __syscall_start) / 4
.long SYMBOL_NAME(sys_ni_syscall)
.endr
#endif
/*
* linux/arch/arm/kernel/ecard.c
*
- * Copyright 1995-1998 Russell King
+ * Copyright 1995-2001 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 17-Apr-1999 RMK Support for EASI Type C cycles.
*/
#define ECARD_C
-#define __KERNEL_SYSCALLS__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/reboot.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
* We ignore all calls, unless it is a SYS_RESTART call - power down/halts
* will be followed by a SYS_RESTART if ctrl-alt-del is pressed again.
*/
-static void ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
+static int ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
{
struct ecard_request req;
if (val != SYS_RESTART)
- return;
+ return 0;
/*
* Disable the expansion card interrupt
have_expmask = ~0;
__raw_writeb(have_expmask, EXPMASK_ENABLE);
#endif
+ return 0;
}
static struct notifier_block ecard_reboot_notifier = {
stmfd sp!, {r4 - r6, lr}
adr r1, .LCvectors @ set up the vectors
- mov r0, #0
ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr}
stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}
#include <asm/system.h>
#include <asm/uaccess.h>
-#define FIQ_VECTOR 0x1c
+#define FIQ_VECTOR (vectors_base() + 0x1c)
static unsigned long no_fiq_insn;
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff)
{
- int error = -EBADF;
+ int error = -EINVAL;
struct file * file = NULL;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+ /*
+ * If we are doing a fixed mapping, and address < PAGE_SIZE,
+ * then deny it.
+ */
+ if (flags & MAP_FIXED && addr < PAGE_SIZE && vectors_base() == 0)
+ goto out;
+
+ error = -EBADF;
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
return error;
}
+asmlinkage unsigned long
+sys_arm_mremap(unsigned long addr, unsigned long old_len,
+ unsigned long new_len, unsigned long flags,
+ unsigned long new_addr)
+{
+ unsigned long ret = -EINVAL;
+
+ /*
+ * If we are doing a fixed mapping, and address < PAGE_SIZE,
+ * then deny it.
+ */
+ if (flags & MREMAP_FIXED && new_addr < PAGE_SIZE &&
+ vectors_base() == 0)
+ goto out;
+
+ down_write(¤t->mm->mmap_sem);
+ ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+ up_write(¤t->mm->mmap_sem);
+
+out:
+ return ret;
+}
+
/*
* Perform the select(nd, in, out, ex, tv) and mmap() system
* calls.
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/ptrace.h>
+#include <linux/elf.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+#include <asm/unistd.h>
#include "ptrace.h"
c_backtrace(fp, processor_mode(regs));
}
+/*
+ * This is called from SysRq-T (show_task) to display the current
+ * call trace for each process. Very useful.
+ */
+void show_trace_task(struct task_struct *tsk)
+{
+ if (tsk != current) {
+ unsigned int fp = tsk->thread.save->fp;
+ c_backtrace(fp, 0x10);
+ }
+}
+
spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
/*
* This function is protected against re-entrancy.
*/
-void die(const char *str, struct pt_regs *regs, int err)
+NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
{
struct task_struct *tsk = current;
fs = get_fs();
set_fs(KERNEL_DS);
- dump_instr(regs);
dump_stack(tsk, (unsigned long)(regs + 1));
dump_backtrace(regs, tsk);
+ dump_instr(regs);
set_fs(fs);
}
void __init trap_init(void)
{
- extern void __trap_init(void);
+ extern void __trap_init(void *);
- __trap_init();
+ __trap_init((void *)vectors_base());
+ if (vectors_base() != 0)
+ printk("Relocating machine vectors to 0x%08x\n",
+ vectors_base());
#ifdef CONFIG_CPU_32
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
#endif
/*
* linux/arch/arm/mach-ebsa110/arch.c
*
- * Architecture specific fixups. This is where any
- * parameters in the params struct are fixed up, or
- * any additional architecture specific information
- * is pulled from the params struct.
+ * Architecture specific fixups.
*/
#include <linux/tty.h>
#include <linux/delay.h>
--- /dev/null
+/*
+ * linux/arch/arm/mach-ebsa110/hardware.h
+ *
+ * Copyright (C) 2001 Russell King
+ *
+ * Local hardware definitions.
+ */
+#ifndef HARDWARE_H
+#define HARDWARE_H
+
+#define IRQ_MASK 0xfe000000 /* read */
+#define IRQ_MSET 0xfe000000 /* write */
+#define IRQ_STAT 0xff000000 /* read */
+#define IRQ_MCLR 0xff000000 /* write */
+
+#endif
u32 __inl(int port)
{
BUG();
+ return 0;
}
EXPORT_SYMBOL(__inb);
#endif
/*
- * free wasted pages. We skip the first page since
- * we know that it will have count = 1 and won't
- * require freeing.
+ * free wasted pages. We skip the first page since we know
+ * that it will have count = 1 and won't require freeing.
+ * We also mark the pages in use as reserved so that
+ * remap_page_range works.
*/
page = virt_to_page(virt);
free = page + (size >> PAGE_SHIFT);
end = page + (1 << order);
- while (++page < end) {
+ for (; page < end; page++) {
set_page_count(page, 1);
if (page >= free)
__free_page(page);
+ else
+ SetPageReserved(page);
}
return ret;
* free a page as defined by the above mapping. We expressly forbid
* calling this from interrupt context.
*/
-void consistent_free(void *vaddr)
+void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
{
+ struct page *page, *end;
+ void *virt;
+
if (in_interrupt())
BUG();
+ virt = bus_to_virt(handle);
+
+ /*
+ * More messing around with the MM internals. This is
+ * sick, but then so is remap_page_range().
+ */
+ size = PAGE_ALIGN(size);
+ page = virt_to_page(virt);
+ end = page + (size >> PAGE_SHIFT);
+
+ for (; page < end; page++)
+ ClearPageReserved(page);
+
__iounmap(vaddr);
}
#include <asm/system.h>
#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/unaligned.h>
*
* Speed optimisations and better fault handling by Russell King.
*
- * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet. Also,
- * it seems to give a severe performance impact (1 abort/ms - NW runs at
- * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS.
+ * *** NOTE ***
+ * This code is not portable to processors with late data abort handling.
*/
#define CODING_BITS(i) (i & 0x0e000000)
#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */
#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */
+#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
+
#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */
#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */
return TYPE_FAULT;
}
+/*
+ * LDM/STM alignment handler.
+ *
+ * There are 4 variants of this instruction:
+ *
+ * B = rn pointer before instruction, A = rn pointer after instruction
+ * ------ increasing address ----->
+ * | | r0 | r1 | ... | rx | |
+ * PU = 01 B A
+ * PU = 11 B A
+ * PU = 00 A B
+ * PU = 10 A B
+ */
static int
do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
{
unsigned int rd, rn, correction, nr_regs, regbits;
- unsigned long eaddr;
-
- correction = 4; /* sometimes 8 on ARMv3 */
- regs->ARM_pc += correction;
-
- rd = RD_BITS(instr);
- rn = RN_BITS(instr);
- eaddr = regs->uregs[rn];
+ unsigned long eaddr, newaddr;
if (LDM_S_BIT(instr))
goto bad;
+ correction = 4; /* processor implementation defined */
+ regs->ARM_pc += correction;
+
ai_multi += 1;
+ /* count the number of registers in the mask to be transferred */
for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
nr_regs += 4;
+ rn = RN_BITS(instr);
+ newaddr = eaddr = regs->uregs[rn];
+
+ if (!LDST_U_BIT(instr))
+ nr_regs = -nr_regs;
+ newaddr += nr_regs;
if (!LDST_U_BIT(instr))
- eaddr -= nr_regs;
+ eaddr = newaddr;
+
+ if (LDST_P_EQ_U(instr)) /* U = P */
+ eaddr += 4;
/*
* This is a "hint" - we already have eaddr worked out by the
"addr = %08lx, eaddr = %08lx\n",
instruction_pointer(regs), instr, addr, eaddr);
- if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
- (LDST_U_BIT(instr) && LDST_P_BIT(instr)))
- eaddr += 4;
-
for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
if (regbits & 1) {
- if (LDST_L_BIT(instr)) {
+ if (LDST_L_BIT(instr))
get32_unaligned_check(regs->uregs[rd], eaddr);
- if (rd == 15)
- correction = 0;
- } else
+ else
put32_unaligned_check(regs->uregs[rd], eaddr);
eaddr += 4;
}
- if (LDST_W_BIT(instr)) {
- if (LDST_P_BIT(instr) && !LDST_U_BIT(instr))
- eaddr -= nr_regs;
- else if (LDST_P_BIT(instr))
- eaddr -= 4;
- else if (!LDST_U_BIT(instr))
- eaddr -= 4 + nr_regs;
- regs->uregs[rn] = eaddr;
- }
- regs->ARM_pc -= correction;
+ if (LDST_W_BIT(instr))
+ regs->uregs[rn] = newaddr;
+ if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
+ regs->ARM_pc -= correction;
return TYPE_DONE;
fault:
+ regs->ARM_pc -= correction;
return TYPE_FAULT;
bad:
memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
- /*
- * This lock is here just to satisfy pmd_alloc and pte_lock
- */
- spin_lock(&mm->page_table_lock);
+ init_pgd = pgd_offset_k(0);
- /*
- * On ARM, first page must always be allocated since it contains
- * the machine vectors.
- */
- new_pmd = pmd_alloc(mm, new_pgd, 0);
- if (!new_pmd)
- goto no_pmd;
+ if (vectors_base() == 0) {
+ init_pmd = pmd_offset(init_pgd, 0);
+ init_pte = pte_offset(init_pmd, 0);
- new_pte = pte_alloc(mm, new_pmd, 0);
- if (!new_pte)
- goto no_pte;
+ /*
+ * This lock is here just to satisfy pmd_alloc and pte_lock
+ */
+ spin_lock(&mm->page_table_lock);
- init_pgd = pgd_offset_k(0);
- init_pmd = pmd_offset(init_pgd, 0);
- init_pte = pte_offset(init_pmd, 0);
+ /*
+ * On ARM, first page must always be allocated since it
+ * contains the machine vectors.
+ */
+ new_pmd = pmd_alloc(mm, new_pgd, 0);
+ if (!new_pmd)
+ goto no_pmd;
- set_pte(new_pte, *init_pte);
+ new_pte = pte_alloc(mm, new_pmd, 0);
+ if (!new_pte)
+ goto no_pte;
+
+ set_pte(new_pte, *init_pte);
+
+ spin_unlock(&mm->page_table_lock);
+ }
/*
* Copy over the kernel and IO PGD entries
*/
- memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+ memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
(PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
- spin_unlock(&mm->page_table_lock);
-
/*
* FIXME: this should not be necessary
*/
void free_pgd_slow(pgd_t *pgd)
{
- if (pgd) { /* can pgd be NULL? */
- pmd_t *pmd;
- pte_t *pte;
-
- /* pgd is always present and good */
- pmd = (pmd_t *)pgd;
- if (pmd_none(*pmd))
- goto free;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- goto free;
- }
-
- pte = pte_offset(pmd, 0);
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if (!pgd)
+ return;
+
+ /* pgd is always present and good */
+ pmd = (pmd_t *)pgd;
+ if (pmd_none(*pmd))
+ goto free;
+ if (pmd_bad(*pmd)) {
+ pmd_ERROR(*pmd);
pmd_clear(pmd);
- pte_free(pte);
- pmd_free(pmd);
+ goto free;
}
+
+ pte = pte_offset(pmd, 0);
+ pmd_clear(pmd);
+ pte_free(pte);
+ pmd_free(pmd);
free:
free_pages((unsigned long) pgd, 2);
}
init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE);
- p->physical = virt_to_phys(init_maps);
- p->virtual = 0;
- p->length = PAGE_SIZE;
- p->domain = DOMAIN_USER;
- p->prot_read = 0;
- p->prot_write = 0;
- p->cacheable = 1;
- p->bufferable = 0;
-
- p ++;
-
for (i = 0; i < mi->nr_banks; i++) {
if (mi->bank[i].size == 0)
continue;
p ++;
#endif
- /*
- * We may have a mapping in virtual address 0.
- * Clear it out.
- */
- clear_mapping(0);
-
/*
* Go through the initial mappings, but clear out any
* pgdir entries that are not in the description.
*/
- i = 0;
q = init_maps;
do {
if (address < q->virtual || q == p) {
}
} while (address != 0);
+ /*
+ * Create a mapping for the machine vectors at virtual address 0
+ * or 0xffff0000. We should always try the high mapping.
+ */
+ init_maps->physical = virt_to_phys(init_maps);
+ init_maps->virtual = vectors_base();
+ init_maps->length = PAGE_SIZE;
+ init_maps->domain = DOMAIN_USER;
+ init_maps->prot_read = 0;
+ init_maps->prot_write = 0;
+ init_maps->cacheable = 1;
+ init_maps->bufferable = 0;
+
+ create_mapping(init_maps);
+
flush_cache_all();
}
#include <asm/hardware.h>
#include <asm/page.h>
#include <asm/proc/domain.h>
-#include <asm/setup.h>
#include <asm/mach/map.h>
$(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c
$(CC) $(CFLAGS) -S -o - getconstants.c | \
- sed 's/^\(#define .* \)#\(.*\)/\1\2/;/^#define/!d' | \
+ sed 's/^\(#define .* \)[#$$]\(.*\)/\1\2/;/^#define/!d' | \
cat constants-hdr - > $@.tmp
cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@; $(RM) $@.tmp
DEFN("PAGE_SZ", PAGE_SIZE);
-DEFN("KSWI_BASE", 0x900000);
-DEFN("KSWI_SYS_BASE", 0x9f0000);
DEFN("SYS_ERROR0", 0x9f0000);
}
# To add an entry into this database, please see Documentation/arm/README,
# or contact rmk@arm.linux.org.uk
#
-# Last update: Sat Apr 7 09:45:09 2001
+# Last update: Sun Jun 17 00:53:17 2001
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
citygo SA1100_CITYGO CITYGO 51
pfs168 SA1100_PFS168 PFS168 52
spot SA1100_SPOT SPOT 53
-flexanet ARCH_FLEXANET FLEXANET 54
+flexanet SA1100_FLEXANET FLEXANET 54
webpal ARCH_WEBPAL WEBPAL 55
linpda SA1100_LINPDA LINPDA 56
anakin ARCH_ANAKIN ANAKIN 57
xfile SA1100_XFILE XFILE 65
accelent_ep9312 ARCH_ACCELENT_EP9312 ACCELENT_EP9312 66
ic200 ARCH_IC200 IC200 67
+creditlart SA1100_CREDITLART CREDITLART 68
+htm SA1100_HTM HTM 69
+iq80310 ARCH_IQ80310 IQ80310 70
+freebot SA1100_FREEBOT FREEBOT 71
+entel ARCH_ENTEL ENTEL 72
+enp3510 ARCH_ENP3510 ENP3510 73
+trizeps SA1100_TRIZEPS TRIZEPS 74
+nesa SA1100_NESA NESA 75
+venus ARCH_VENUS VENUS 76
+tardis ARCH_TARDIS TARDIS 77
+mercury ARCH_MERCURY MERCURY 78
+empeg SA1100_EMPEG EMPEG 79
+adi_eb ARCH_I80200FCC I80200FCC 80
+itt_cpb SA1100_ITT_CPB ITT_CPB 81
+sa1110_svc ARCH_SA1110_SVC SA1110_SVC 82
+alpha2 SA1100_ALPHA2 ALPHA2 84
+alpha1 SA1100_ALPHA1 ALPHA1 85
+netarm ARCH_NETARM NETARM 86
+simpad SA1100_SIMPAD SIMPAD 87
+pda1 ARCH_PDA1 PDA1 88
+lubbock ARCH_LUBBOCK LUBBOCK 89
# The following are unallocated
-empeg SA1100_EMPEG EMPEG
#
# CONFIG_MTD is not set
-#
-# RAM/ROM/Flash chip drivers
-#
-# CONFIG_MTD_CFI is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_JEDEC is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_SUN_UFLASH is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
-# CONFIG_MTD_SA1100 is not set
-# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set
-# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_DBOX2 is not set
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-# CONFIG_MTD_CFI_FLAGADM is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
-# CONFIG_MTD_OCELOT is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC1000 is not set
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_SPIA is not set
-
#
# Parallel port support
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_DGRS is not set
# CONFIG_DM9102 is not set
CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PM is not set
# CONFIG_LNE390 is not set
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_WINBOND_840 is not set
-# CONFIG_HAPPYMEAL is not set
# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
+# CONFIG_MYRI_SBUS is not set
# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
+# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_USB_IBMCAM is not set
# CONFIG_USB_OV511 is not set
# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
# CONFIG_USB_DSBR is not set
# CONFIG_USB_DABUSB is not set
#
# CONFIG_USB_PLUSB is not set
# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_CATC is not set
# CONFIG_USB_NET1080 is not set
#
* Set up machine check reporting on the Winchip C6 series
*/
-static void winchip_mcheck_init(struct cpuinfo_x86 *c)
+static void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
{
u32 lo, hi;
/* Not supported on C3 */
* This has to be run for each processor
*/
+
+static int mce_disabled = 0;
+
void __init mcheck_init(struct cpuinfo_x86 *c)
{
+ if(mce_disabled)
+ return;
+
switch(c->x86_vendor)
{
case X86_VENDOR_AMD:
break;
}
}
+
+static void __init mcheck_disable(char *str, int *unused)
+{
+ mce_disabled = 1;
+}
+__setup("nomce", mcheck_disable);
choice 'SuperH system type' \
"Generic CONFIG_SH_GENERIC \
SolutionEngine CONFIG_SH_SOLUTION_ENGINE \
- Overdrive CONFIG_SH_OVERDRIVE \
+ SolutionEngine7751 CONFIG_SH_7751_SOLUTION_ENGINE \
+ STB1_Harp CONFIG_SH_STB1_HARP \
+ STB1_Overdrive CONFIG_SH_STB1_OVERDRIVE \
HP620 CONFIG_SH_HP620 \
HP680 CONFIG_SH_HP680 \
HP690 CONFIG_SH_HP690 \
DMIDA CONFIG_SH_DMIDA \
EC3104 CONFIG_SH_EC3104 \
Dreamcast CONFIG_SH_DREAMCAST \
+ CAT68701 CONFIG_SH_CAT68701 \
+ BigSur CONFIG_SH_BIGSUR \
+ SH2000 CONFIG_SH_SH2000 \
BareCPU CONFIG_SH_UNKNOWN" Generic
-define_bool CONFIG_SH_RTC y
+# The SH7750 RTC module is disabled in the Dreamcast
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+ define_bool CONFIG_SH_RTC n
+else
+ define_bool CONFIG_SH_RTC y
+fi
if [ "$CONFIG_SH_HP620" = "y" -o "$CONFIG_SH_HP680" = "y" -o \
"$CONFIG_SH_HP690" = "y" ]; then
"SH7707 CONFIG_CPU_SUBTYPE_SH7707 \
SH7708 CONFIG_CPU_SUBTYPE_SH7708 \
SH7709 CONFIG_CPU_SUBTYPE_SH7709 \
- SH7750 CONFIG_CPU_SUBTYPE_SH7750" SH7708
+ SH7750 CONFIG_CPU_SUBTYPE_SH7750 \
+ SH7751 CONFIG_CPU_SUBTYPE_SH7751 \
+ ST40STB1 CONFIG_CPU_SUBTYPE_ST40STB1" SH7708
if [ "$CONFIG_CPU_SUBTYPE_SH7707" = "y" ]; then
define_bool CONFIG_CPU_SH3 y
define_bool CONFIG_CPU_SH4 n
define_bool CONFIG_CPU_SH3 n
define_bool CONFIG_CPU_SH4 y
fi
+if [ "$CONFIG_CPU_SUBTYPE_SH7751" = "y" ]; then
+ define_bool CONFIG_CPU_SH3 n
+ define_bool CONFIG_CPU_SH4 y
+fi
+if [ "$CONFIG_CPU_SUBTYPE_ST40STB1" = "y" ]; then
+ define_bool CONFIG_CPU_SH3 n
+ define_bool CONFIG_CPU_SH4 y
+fi
bool 'Little Endian' CONFIG_CPU_LITTLE_ENDIAN
if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_HP600" = "y" -o \
- "$CONFIG_SH_OVERDRIVE" = "y" ]; then
+ "$CONFIG_SH_BIGSUR" = "y" -o "$CONFIG_SH_7751_SOLUTION_ENGINE" = "y" -o \
+ "$CONFIG_SH_DREAMCAST" = "y" -o "$CONFIG_SH_SH2000" = "y" ]; then
define_hex CONFIG_MEMORY_START 0c000000
else
- hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
+ if [ "$CONFIG_CPU_SUBTYPE_ST40STB1" = "y" ]; then
+ bool 'Memory on LMI' CONFIG_ST40_LMI_MEMORY
+ if [ "$CONFIG_ST40_LMI_MEMORY" = "y" ] ; then
+ define_hex CONFIG_MEMORY_START 08000000
+ else
+ hex 'EMI physical memory start address' CONFIG_MEMORY_START 08000000
+ fi
+ else
+ hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
+ fi
fi
endmenu
bool 'Networking support' CONFIG_NET
-if [ "$CONFIG_SH_GENERIC" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_UNKNOWN" = "y" ]; then
+if [ "$CONFIG_SH_GENERIC" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o \
+ "$CONFIG_SH_UNKNOWN" = "y" -o "$CONFIG_SH_CAT68701" = "y" ]; then
bool 'Compact Flash Enabler support' CONFIG_CF_ENABLER
fi
bool 'Hitachi HD64465 companion chip support' CONFIG_HD64465
if [ "$CONFIG_HD64465" = "y" ]; then
+ hex 'HD64465 start address' CONFIG_HD64465_IOBASE b0000000
int 'HD64465 IRQ' CONFIG_HD64465_IRQ 5
fi
#
source drivers/input/Config.in
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+source drivers/maple/Config.in
+fi
+
mainmenu_option next_comment
comment 'Character devices'
fi
if [ "$CONFIG_SH_GENERIC" = "y" -o \
- "$CONFIG_SH_OVERDRIVE" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then
+ "$CONFIG_SH_CAT68701" = "y" -o \
+ "$CONFIG_SH_STB1_HARP" = "y" -o \
+ "$CONFIG_SH_STB1_OVERDRIVE" = "y" -o \
+ "$CONFIG_SH_BIGSUR" = "y" -o \
+ "$CONFIG_SH_7751_SOLUTION_ENGINE" = "y" -o \
+ "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then
bool 'Heartbeat LED' CONFIG_HEARTBEAT
fi
+if [ "$CONFIG_SH_DREAMCAST" = "y" -a "$CONFIG_MAPLE" != "n" ]; then
+ mainmenu_option next_comment
+ comment 'Maple Bus input peripherals'
+ if [ "$CONFIG_INPUT" != "n" ]; then
+ dep_tristate ' Maple Bus keyboard support' CONFIG_MAPLE_KEYBOARD $CONFIG_INPUT
+ dep_tristate ' Maple Bus mouse support' CONFIG_MAPLE_MOUSE $CONFIG_INPUT
+ else
+ comment 'Input core support is required for Maple input peripherals'
+ fi
+ endmenu
+fi
+
+source drivers/char/joystick/Config.in
+
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
if [ "$CONFIG_PRINTER" != "n" ]; then
fi
dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
fi
-endmenu
-
+bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
source drivers/char/pcmcia/Config.in
fi
+endmenu
source fs/Config.in
+source drivers/media/Config.in
+
if [ "$CONFIG_VT" = "y" ]; then
mainmenu_option next_comment
comment 'Console drivers'
obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
ifeq ($(CONFIG_PCI),y)
-obj-y += pci-sh.o
+ifeq ($(CONFIG_SH_DREAMCAST),y)
+obj-y += pci-dc.o
+else
+obj-y += pci-dma.o
obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)+= pci_st40.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751)+= pci-sh7751.o
+obj-$(CONFIG_SH_BIGSUR)+= pci-bigsur.o
+obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)+= pci-7751se.o
+endif
endif
obj-$(CONFIG_SH_HP600) += mach_hp600.o
obj-$(CONFIG_SH_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o
machine-specific-objs += mach_se.o setup_se.o io_se.o led_se.o
+obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o pci-7751se.o
+machine-specific-objs += mach_se.o setup_se.o io_se.o led_se.o pci-7751se.o
+
+obj-$(CONFIG_SH_BIGSUR) += mach_bigsur.o setup_bigsur.o io_bigsur.o led_bigsur.o
+machine-specific-objs += mach_bigsur.o setup_bigsur.o io_bigsur.o led_bigsur.o
+
+obj-$(CONFIG_SH_SH2000) += setup_sh2000.o io_sh2000.o
+machine-specific-objs += setup_sh2000.o io_sh2000.o
+
obj-$(CONFIG_SH_CAT68701) += mach_cat68701.o io_cat68701.o
machine-specific-objs += mach_cat68701.o io_cat68701.o
__syscall_ret_trace:
.long syscall_ret_trace
__syscall_ret:
- .long SYMBOL_NAME(syscall_ret)
-
+ .long syscall_ret
+__INV_IMASK:
+ .long 0xffffff0f ! ~(IMASK)
.align 2
.align 2
1: .long SYMBOL_NAME(schedule)
-ENTRY(ret_from_irq)
+ret_from_irq:
+ret_from_exception:
mov #OFF_SR, r0
mov.l @(r0,r15), r0 ! get status register
shll r0
shll r0 ! kernel space?
bt restore_all ! Yes, it's from kernel, go back soon
!
- STI()
- bra ret_with_reschedule
- nop
-
-ENTRY(ret_from_exception)
- mov #OFF_SR, r0
- mov.l @(r0,r15), r0 ! get status register
- shll r0
- shll r0 ! kernel space?
- bt restore_all ! Yes, it's from kernel, go back soon
- !
- STI()
bra ret_from_syscall
nop
- .align 2
-__INV_IMASK:
- .long 0xffffff0f ! ~(IMASK)
.align 2
#ifdef COMPAT_OLD_SYSCALL_ABI
/* fall through */
ENTRY(ret_from_syscall)
- mov.l __irq_stat, r0 ! softirq_active
- mov.l @r0, r1
- mov.l @(4,r0), r2 ! softirq_mask
- tst r2, r1
- bt ret_with_reschedule
-handle_softirq:
- mov.l __do_softirq, r0
- jsr @r0
- nop
-ret_with_reschedule:
+ /* CLI */
+ stc sr, r0
+ or #0xf0, r0
+ ldc r0, sr
+ !
stc k_current, r1
mov.l @(need_resched,r1), r0
tst r0, r0
.long SYMBOL_NAME(do_signal)
__irq_stat:
.long SYMBOL_NAME(irq_stat)
-__do_softirq:
- .long SYMBOL_NAME(do_softirq)
.align 2
restore_all:
bra handle_exception
mov.l @k2, k2
.align 2
-2: .long SYMBOL_NAME(ret_from_exception)
+2: .long ret_from_exception
1: .long EXPEVT
!
!
.align 2
1: .long EXPEVT
2: .long INTEVT
-3: .long SYMBOL_NAME(ret_from_irq)
-4: .long SYMBOL_NAME(ret_from_exception)
+3: .long ret_from_irq
+4: .long ret_from_exception
!
!
.long SYMBOL_NAME(do_IRQ) ! 63 pcc1i
#endif
#elif defined(__SH4__)
- .long SYMBOL_NAME(do_IRQ) ! Hitachi UDI
- .long SYMBOL_NAME(do_IRQ) ! GPIO
- .long SYMBOL_NAME(do_IRQ) ! DMAC dmte0
- .long SYMBOL_NAME(do_IRQ) ! dmte1
- .long SYMBOL_NAME(do_IRQ) ! dmte2
- .long SYMBOL_NAME(do_IRQ) ! dmte3
- .long SYMBOL_NAME(do_IRQ) ! dmae
- .long SYMBOL_NAME(do_IRQ)
- .long SYMBOL_NAME(do_IRQ) ! SCIF eri
- .long SYMBOL_NAME(do_IRQ) ! rxi
- .long SYMBOL_NAME(do_IRQ) ! bri
- .long SYMBOL_NAME(do_IRQ) ! txi
+ .long SYMBOL_NAME(do_IRQ) ! 32 Hitachi UDI
+ .long SYMBOL_NAME(do_IRQ) ! 33 GPIO
+ .long SYMBOL_NAME(do_IRQ) ! 34 DMAC dmte0
+ .long SYMBOL_NAME(do_IRQ) ! 35 dmte1
+ .long SYMBOL_NAME(do_IRQ) ! 36 dmte2
+ .long SYMBOL_NAME(do_IRQ) ! 37 dmte3
+ .long SYMBOL_NAME(do_IRQ) ! 38 dmae
+ .long error ! 39
+ .long SYMBOL_NAME(do_IRQ) ! 40 SCIF eri
+ .long SYMBOL_NAME(do_IRQ) ! 41 rxi
+ .long SYMBOL_NAME(do_IRQ) ! 42 bri
+ .long SYMBOL_NAME(do_IRQ) ! 43 txi
+ .long error ! 44
+ .long error ! 45
+ .long error ! 46
+ .long error ! 47
+ .long SYMBOL_NAME(do_fpu_state_restore) ! 48
+ .long SYMBOL_NAME(do_fpu_state_restore) ! 49
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+ .long error
+ .long error
+ .long error
+ .long error
+ .long error
+ .long error
+ .long error
+ .long error
+ .long error
+ .long error
.long error
.long error
.long error
.long error
- .long SYMBOL_NAME(do_fpu_state_restore)
- .long SYMBOL_NAME(do_fpu_state_restore)
+ .long SYMBOL_NAME(do_IRQ) ! PCI serr
+ .long SYMBOL_NAME(do_IRQ) ! dma3
+ .long SYMBOL_NAME(do_IRQ) ! dma2
+ .long SYMBOL_NAME(do_IRQ) ! dma1
+ .long SYMBOL_NAME(do_IRQ) ! dma0
+ .long SYMBOL_NAME(do_IRQ) ! pwon
+ .long SYMBOL_NAME(do_IRQ) ! pwdwn
+ .long SYMBOL_NAME(do_IRQ) ! err
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+ .long error ! 50 0x840
+ .long error ! 51 0x860
+ .long error ! 52 0x880
+ .long error ! 53 0x8a0
+ .long error ! 54 0x8c0
+ .long error ! 55 0x8e0
+ .long error ! 56 0x900
+ .long error ! 57 0x920
+ .long error ! 58 0x940
+ .long error ! 59 0x960
+ .long error ! 60 0x980
+ .long error ! 61 0x9a0
+ .long error ! 62 0x9c0
+ .long error ! 63 0x9e0
+ .long SYMBOL_NAME(do_IRQ) ! 64 0xa00 PCI serr
+ .long SYMBOL_NAME(do_IRQ) ! 65 0xa20 err
+ .long SYMBOL_NAME(do_IRQ) ! 66 0xa40 ad
+ .long SYMBOL_NAME(do_IRQ) ! 67 0xa60 pwr_dwn
+ .long error ! 68 0xa80
+ .long error ! 69 0xaa0
+ .long error ! 70 0xac0
+ .long error ! 71 0xae0
+ .long SYMBOL_NAME(do_IRQ) ! 72 0xb00 DMA INT0
+ .long SYMBOL_NAME(do_IRQ) ! 73 0xb20 INT1
+ .long SYMBOL_NAME(do_IRQ) ! 74 0xb40 INT2
+ .long SYMBOL_NAME(do_IRQ) ! 75 0xb60 INT3
+ .long SYMBOL_NAME(do_IRQ) ! 76 0xb80 INT4
+ .long error ! 77 0xba0
+ .long SYMBOL_NAME(do_IRQ) ! 78 0xbc0 DMA ERR
+ .long error ! 79 0xbe0
+ .long SYMBOL_NAME(do_IRQ) ! 80 0xc00 PIO0
+ .long SYMBOL_NAME(do_IRQ) ! 81 0xc20 PIO1
+ .long SYMBOL_NAME(do_IRQ) ! 82 0xc40 PIO2
+ .long error ! 83 0xc60
+ .long error ! 84 0xc80
+ .long error ! 85 0xca0
+ .long error ! 86 0xcc0
+ .long error ! 87 0xce0
+ .long error ! 88 0xd00
+ .long error ! 89 0xd20
+ .long error ! 90 0xd40
+ .long error ! 91 0xd60
+ .long error ! 92 0xd80
+ .long error ! 93 0xda0
+ .long error ! 94 0xdc0
+ .long error ! 95 0xde0
+ .long error ! 96 0xe00
+ .long error ! 97 0xe20
+ .long error ! 98 0xe40
+ .long error ! 99 0xe60
+ .long error ! 100 0xe80
+ .long error ! 101 0xea0
+ .long error ! 102 0xec0
+ .long error ! 103 0xee0
+ .long error ! 104 0xf00
+ .long error ! 105 0xf20
+ .long error ! 106 0xf40
+ .long error ! 107 0xf60
+ .long error ! 108 0xf80
+ .long error ! 109 0xfa0
+ .long error ! 110 0xfc0
+ .long error ! 111 0xfe0
+ .long SYMBOL_NAME(do_IRQ) ! 112 0x1000 Mailbox
+ .long error ! 113 0x1020
+ .long error ! 114 0x1040
+ .long error ! 115 0x1060
+ .long error ! 116 0x1080
+ .long error ! 117 0x10a0
+ .long error ! 118 0x10c0
+ .long error ! 119 0x10e0
+ .long error ! 120 0x1100
+ .long error ! 121 0x1120
+ .long error ! 122 0x1140
+ .long error ! 123 0x1160
+ .long error ! 124 0x1180
+ .long error ! 125 0x11a0
+ .long error ! 126 0x11c0
+ .long error ! 127 0x11e0
+ .long error ! 128 0x1200
+ .long error ! 129 0x1220
+ .long error ! 130 0x1240
+ .long error ! 131 0x1260
+ .long error ! 132 0x1280
+ .long error ! 133 0x12a0
+ .long error ! 134 0x12c0
+ .long error ! 135 0x12e0
+ .long error ! 136 0x1300
+ .long error ! 137 0x1320
+ .long error ! 138 0x1340
+ .long error ! 139 0x1360
+ .long SYMBOL_NAME(do_IRQ) ! 140 0x1380 EMPI INV_ADDR
+ .long error ! 141 0x13a0
+ .long error ! 142 0x13c0
+ .long error ! 143 0x13e0
#endif
ENTRY(sys_call_table)
/*
- * $Id: hd64465_gpio.c,v 1.1 2001/01/02 15:35:22 mjd Exp $
+ * $Id: hd64465_gpio.c,v 1.2 2001/05/24 00:13:47 gniibe Exp $
* by Greg Banks <gbanks@pocketpenguins.com>
* (c) 2000 PocketPenguins Inc
*
--- /dev/null
+/*
+ * include/asm-sh/io_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+ * By Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc.
+ * and from io_hd64461.h, which bore the message:
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * IO functions for a Hitachi Big Sur Evaluation Board.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/bigsur.h>
+
+//#define BIGSUR_DEBUG 2
+#undef BIGSUR_DEBUG
+
+#ifdef BIGSUR_DEBUG
+#define DPRINTK(args...) printk(args)
+#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
+#else
+#define DPRINTK(args...)
+#define DIPRINTK(n, args...)
+#endif
+
+
+/* Low iomap maps port 0-1K to addresses in 8byte chunks */
+#define BIGSUR_IOMAP_LO_THRESH 0x400
+#define BIGSUR_IOMAP_LO_SHIFT 3
+#define BIGSUR_IOMAP_LO_MASK ((1<<BIGSUR_IOMAP_LO_SHIFT)-1)
+#define BIGSUR_IOMAP_LO_NMAP (BIGSUR_IOMAP_LO_THRESH>>BIGSUR_IOMAP_LO_SHIFT)
+static u32 bigsur_iomap_lo[BIGSUR_IOMAP_LO_NMAP];
+static u8 bigsur_iomap_lo_shift[BIGSUR_IOMAP_LO_NMAP];
+
+/* High iomap maps port 1K-64K to addresses in 1K chunks */
+#define BIGSUR_IOMAP_HI_THRESH 0x10000
+#define BIGSUR_IOMAP_HI_SHIFT 10
+#define BIGSUR_IOMAP_HI_MASK ((1<<BIGSUR_IOMAP_HI_SHIFT)-1)
+#define BIGSUR_IOMAP_HI_NMAP (BIGSUR_IOMAP_HI_THRESH>>BIGSUR_IOMAP_HI_SHIFT)
+static u32 bigsur_iomap_hi[BIGSUR_IOMAP_HI_NMAP];
+static u8 bigsur_iomap_hi_shift[BIGSUR_IOMAP_HI_NMAP];
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x))
+
+void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift)
+{
+ u32 port, endport = baseport + nports;
+
+ DPRINTK("bigsur_port_map(base=0x%0x, n=0x%0x, addr=0x%08x)\n",
+ baseport, nports, addr);
+
+ for (port = baseport ;
+ port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
+ port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
+ DPRINTK(" maplo[0x%x] = 0x%08x\n", port, addr);
+ bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = addr;
+ bigsur_iomap_lo_shift[port>>BIGSUR_IOMAP_LO_SHIFT] = shift;
+ addr += (1<<(BIGSUR_IOMAP_LO_SHIFT));
+ }
+
+ for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
+ port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
+ port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
+ DPRINTK(" maphi[0x%x] = 0x%08x\n", port, addr);
+ bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = addr;
+ bigsur_iomap_hi_shift[port>>BIGSUR_IOMAP_HI_SHIFT] = shift;
+ addr += (1<<(BIGSUR_IOMAP_HI_SHIFT));
+ }
+}
+EXPORT_SYMBOL(bigsur_port_map);
+
+void bigsur_port_unmap(u32 baseport, u32 nports)
+{
+ u32 port, endport = baseport + nports;
+
+ DPRINTK("bigsur_port_unmap(base=0x%0x, n=0x%0x)\n", baseport, nports);
+
+ for (port = baseport ;
+ port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
+ port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
+ bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = 0;
+ }
+
+ for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
+ port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
+ port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
+ bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = 0;
+ }
+}
+EXPORT_SYMBOL(bigsur_port_unmap);
+
+unsigned long bigsur_isa_port2addr(unsigned long port)
+{
+ unsigned long addr = 0;
+ unsigned char shift;
+
+ /* Physical address not in P0, do nothing */
+ if (PXSEG(port)) addr = port;
+ /* physical address in P0, map to P2 */
+ else if (port >= 0x30000)
+ addr = P2SEGADDR(port);
+ /* Big Sur I/O + HD64465 registers 0x10000-0x30000 */
+ else if (port >= BIGSUR_IOMAP_HI_THRESH)
+ addr = BIGSUR_INTERNAL_BASE + (port - BIGSUR_IOMAP_HI_THRESH);
+ /* Handle remapping of high IO/PCI IO ports */
+ else if (port >= BIGSUR_IOMAP_LO_THRESH) {
+ addr = bigsur_iomap_hi[port >> BIGSUR_IOMAP_HI_SHIFT];
+ shift = bigsur_iomap_hi_shift[port >> BIGSUR_IOMAP_HI_SHIFT];
+ if (addr != 0)
+ addr += (port & BIGSUR_IOMAP_HI_MASK) << shift;
+ }
+ /* Handle remapping of low IO ports */
+ else {
+ addr = bigsur_iomap_lo[port >> BIGSUR_IOMAP_LO_SHIFT];
+ shift = bigsur_iomap_lo_shift[port >> BIGSUR_IOMAP_LO_SHIFT];
+ if (addr != 0)
+ addr += (port & BIGSUR_IOMAP_LO_MASK) << shift;
+ }
+
+ DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr);
+
+ return addr;
+}
+
+static inline void delay(void)
+{
+ ctrl_inw(0xa0000000);
+}
+
+unsigned char bigsur_inb(unsigned long port)
+{
+ unsigned long addr = PORT2ADDR(port);
+ unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
+
+ DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b);
+ return b;
+}
+
+unsigned char bigsur_inb_p(unsigned long port)
+{
+ unsigned long v;
+ unsigned long addr = PORT2ADDR(port);
+
+ v = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
+ delay();
+ DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v);
+ return v;
+}
+
+unsigned short bigsur_inw(unsigned long port)
+{
+ unsigned long addr = PORT2ADDR(port);
+ unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr);
+ DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b);
+ return b;
+}
+
+unsigned int bigsur_inl(unsigned long port)
+{
+ unsigned long addr = PORT2ADDR(port);
+ unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr);
+ DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b);
+ return b;
+}
+
+void bigsur_insb(unsigned long port, void *buffer, unsigned long count)
+{
+ unsigned char *buf=buffer;
+ while(count--) *buf++=inb(port);
+}
+
+void bigsur_insw(unsigned long port, void *buffer, unsigned long count)
+{
+ unsigned short *buf=buffer;
+ while(count--) *buf++=inw(port);
+}
+
+void bigsur_insl(unsigned long port, void *buffer, unsigned long count)
+{
+ unsigned long *buf=buffer;
+ while(count--) *buf++=inl(port);
+}
+
+void bigsur_outb(unsigned char b, unsigned long port)
+{
+ unsigned long addr = PORT2ADDR(port);
+
+ DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr);
+ if (addr != 0)
+ *(volatile unsigned char*)addr = b;
+}
+
+void bigsur_outb_p(unsigned char b, unsigned long port)
+{
+ unsigned long addr = PORT2ADDR(port);
+
+ DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr);
+ if (addr != 0)
+ *(volatile unsigned char*)addr = b;
+ delay();
+}
+
+void bigsur_outw(unsigned short b, unsigned long port)
+{
+ unsigned long addr = PORT2ADDR(port);
+ DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr);
+ if (addr != 0)
+ *(volatile unsigned short*)addr = b;
+}
+
+void bigsur_outl(unsigned int b, unsigned long port)
+{
+ unsigned long addr = PORT2ADDR(port);
+ DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr);
+ if (addr != 0)
+ *(volatile unsigned long*)addr = b;
+}
+
+void bigsur_outsb(unsigned long port, const void *buffer, unsigned long count)
+{
+ const unsigned char *buf=buffer;
+ while(count--) outb(*buf++, port);
+}
+
+void bigsur_outsw(unsigned long port, const void *buffer, unsigned long count)
+{
+ const unsigned short *buf=buffer;
+ while(count--) outw(*buf++, port);
+}
+
+void bigsur_outsl(unsigned long port, const void *buffer, unsigned long count)
+{
+ const unsigned long *buf=buffer;
+ while(count--) outl(*buf++, port);
+}
+
/*
- * $Id: io_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ * $Id: io_dc.c,v 1.2 2001/05/24 00:13:47 gniibe Exp $
* I/O routines for SEGA Dreamcast
*/
/*
- * $Id: io_hd64465.c,v 1.6 2001/02/15 09:13:51 dave_mckay Exp $
+ * $Id: io_hd64465.c,v 1.7 2001/05/09 07:39:36 gniibe Exp $
* by Greg Banks <gbanks@pocketpenguins.com>
* (c) 2000 PocketPenguins Inc
*
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
+#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x))
+
void hd64465_port_map(unsigned short baseport, unsigned int nports,
unsigned long addr, unsigned char shift)
{
}
EXPORT_SYMBOL(hd64465_port_unmap);
-static /*__inline__*/ unsigned long PORT2ADDR(unsigned long port)
+unsigned long hd64465_isa_port2addr(unsigned long port)
{
unsigned long addr = 0;
unsigned char shift;
--- /dev/null
+/*
+ * I/O routine for SH-2000
+ */
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+
+#define IDE_OFFSET 0xb6200000
+#define NIC_OFFSET 0xb6000000
+#define EXTBUS_OFFSET 0xba000000
+
+unsigned long sh2000_isa_port2addr(unsigned long offset)
+{
+ if((offset & ~7) == 0x1f0 || offset == 0x3f6)
+ return IDE_OFFSET + offset;
+ else if((offset & ~0x1f) == 0x300)
+ return NIC_OFFSET + offset;
+ return EXTBUS_OFFSET + offset;
+}
#include <asm/irq.h>
#include <linux/irq.h>
-/*
- * Micro-access to controllers is serialized over the whole
- * system. We never hold this lock when we call the actual
- * IRQ handler.
- */
-spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
/*
* Controller mappings for all interrupt sources:
*/
*/
void disable_irq_nosync(unsigned int irq)
{
+ irq_desc_t *desc = irq_desc + irq;
unsigned long flags;
- spin_lock_irqsave(&irq_controller_lock, flags);
- if (!irq_desc[irq].depth++) {
- irq_desc[irq].status |= IRQ_DISABLED;
- irq_desc[irq].handler->disable(irq);
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
}
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ spin_unlock_irqrestore(&desc->lock, flags);
}
/*
void enable_irq(unsigned int irq)
{
+ irq_desc_t *desc = irq_desc + irq;
unsigned long flags;
- spin_lock_irqsave(&irq_controller_lock, flags);
- switch (irq_desc[irq].depth) {
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
case 1: {
- unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED;
- irq_desc[irq].status = status;
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- irq_desc[irq].status = status | IRQ_REPLAY;
- hw_resend_irq(irq_desc[irq].handler,irq);
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
}
- irq_desc[irq].handler->enable(irq);
+ desc->handler->enable(irq);
/* fall-through */
}
default:
- irq_desc[irq].depth--;
+ desc->depth--;
break;
case 0:
printk("enable_irq() unbalanced from %p\n",
__builtin_return_address(0));
}
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ spin_unlock_irqrestore(&desc->lock, flags);
}
/*
kstat.irqs[cpu][irq]++;
desc = irq_desc + irq;
- spin_lock(&irq_controller_lock);
+ spin_lock(&desc->lock);
desc->handler->ack(irq);
/*
REPLAY is when Linux resends an IRQ that was dropped earlier
status |= IRQ_INPROGRESS; /* we are handling it */
}
desc->status = status;
- spin_unlock(&irq_controller_lock);
/*
* If there is no IRQ handler or it was disabled, exit early.
will take care of it.
*/
if (!action)
- return 1;
+ goto out;
/*
* Edge triggered interrupts need to remember
* SMP environment.
*/
for (;;) {
+ spin_unlock(&desc->lock);
handle_IRQ_event(irq, ®s, action);
- spin_lock(&irq_controller_lock);
+ spin_lock(&desc->lock);
if (!(desc->status & IRQ_PENDING))
break;
desc->status &= ~IRQ_PENDING;
- spin_unlock(&irq_controller_lock);
}
desc->status &= ~IRQ_INPROGRESS;
- if (!(desc->status & IRQ_DISABLED))
- desc->handler->end(irq);
- spin_unlock(&irq_controller_lock);
+out:
+ /*
+ * The ->end() handler has to deal with interrupts which got
+ * disabled while the handler was running.
+ */
+ desc->handler->end(irq);
+ spin_unlock(&desc->lock);
-#if 0
- __sti();
-#endif
- if (softirq_active(cpu)&softirq_mask(cpu))
+ if (softirq_pending(cpu))
do_softirq();
return 1;
}
void free_irq(unsigned int irq, void *dev_id)
{
+ irq_desc_t *desc;
struct irqaction **p;
unsigned long flags;
if (irq >= ACTUAL_NR_IRQS)
return;
- spin_lock_irqsave(&irq_controller_lock,flags);
- p = &irq_desc[irq].action;
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
for (;;) {
struct irqaction * action = *p;
if (action) {
/* Found it - now remove it from the list of entries */
*pp = action->next;
- if (!irq_desc[irq].action) {
- irq_desc[irq].status |= IRQ_DISABLED;
- irq_desc[irq].handler->shutdown(irq);
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->shutdown(irq);
}
- spin_unlock_irqrestore(&irq_controller_lock,flags);
+ spin_unlock_irqrestore(&desc->lock,flags);
kfree(action);
return;
}
printk("Trying to free free IRQ%d\n",irq);
- spin_unlock_irqrestore(&irq_controller_lock,flags);
+ spin_unlock_irqrestore(&desc->lock,flags);
return;
}
}
+static DECLARE_MUTEX(probe_sem);
+
/*
* IRQ autodetection code..
*
unsigned long probe_irq_on(void)
{
unsigned int i;
- unsigned long delay;
+ irq_desc_t *desc;
unsigned long val;
+ unsigned long delay;
+
+ down(&probe_sem);
+ /*
+ * something may have generated an irq long ago and we want to
+ * flush such a longstanding irq before considering it as spurious.
+ */
+ for (i = NR_IRQS-1; i > 0; i--) {
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!desc->action)
+ desc->handler->startup(i);
+ spin_unlock_irq(&desc->lock);
+ }
+
+ /* Wait for longstanding interrupts to trigger. */
+ for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+ /* about 20ms delay */ synchronize_irq();
/*
- * first, enable any unassigned irqs
+ * enable any unassigned irqs
+ * (we must startup again here because if a longstanding irq
+ * happened in the previous stage, it may have masked itself)
*/
- spin_lock_irq(&irq_controller_lock);
for (i = NR_IRQS-1; i > 0; i--) {
- if (!irq_desc[i].action) {
- irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
- if (irq_desc[i].handler->startup(i))
- irq_desc[i].status |= IRQ_PENDING;
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!desc->action) {
+ desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+ if (desc->handler->startup(i))
+ desc->status |= IRQ_PENDING;
}
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
/*
* Wait for spurious interrupts to trigger
* Now filter out any obviously spurious interrupts
*/
val = 0;
- spin_lock_irq(&irq_controller_lock);
for (i=0; i<NR_IRQS; i++) {
- unsigned int status = irq_desc[i].status;
-
- if (!(status & IRQ_AUTODETECT))
- continue;
-
- /* It triggered already - consider it spurious. */
- if (!(status & IRQ_WAITING)) {
- irq_desc[i].status = status & ~IRQ_AUTODETECT;
- irq_desc[i].handler->shutdown(i);
+ desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ /* It triggered already - consider it spurious. */
+ if (!(status & IRQ_WAITING)) {
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ } else
+ if (i < 32)
+ val |= 1 << i;
}
-
- if (i < 32)
- val |= 1 << i;
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
+ spin_unlock_irq(&desc->lock);
return val;
}
nr_irqs = 0;
irq_found = 0;
- spin_lock_irq(&irq_controller_lock);
for (i=0; i<NR_IRQS; i++) {
- unsigned int status = irq_desc[i].status;
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
- if (!(status & IRQ_AUTODETECT))
- continue;
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
- if (!(status & IRQ_WAITING)) {
- if (!nr_irqs)
- irq_found = i;
- nr_irqs++;
+ if (status & IRQ_AUTODETECT) {
+ if (!(status & IRQ_WAITING)) {
+ if (!nr_irqs)
+ irq_found = i;
+ nr_irqs++;
+ }
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
}
- irq_desc[i].status = status & ~IRQ_AUTODETECT;
- irq_desc[i].handler->shutdown(i);
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
+ up(&probe_sem);
if (nr_irqs > 1)
irq_found = -irq_found;
int shared = 0;
struct irqaction *old, **p;
unsigned long flags;
+ irq_desc_t *desc = irq_desc + irq;
/*
* Some drivers like serial.c use request_irq() heavily,
/*
* The following block of code has to be executed atomically
*/
- spin_lock_irqsave(&irq_controller_lock,flags);
- p = &irq_desc[irq].action;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ)) {
- spin_unlock_irqrestore(&irq_controller_lock,flags);
+ spin_unlock_irqrestore(&desc->lock,flags);
return -EBUSY;
}
*p = new;
if (!shared) {
- irq_desc[irq].depth = 0;
- irq_desc[irq].status &= ~IRQ_DISABLED;
- irq_desc[irq].handler->startup(irq);
+ desc->depth = 0;
+ desc->status &= ~IRQ_DISABLED;
+ desc->handler->startup(irq);
}
- spin_unlock_irqrestore(&irq_controller_lock,flags);
+ spin_unlock_irqrestore(&desc->lock,flags);
return 0;
}
}
static struct hw_interrupt_type intc2_irq_type = {
- "INTC2-based-IRQ",
+ "INTC2-IRQ",
startup_intc2_irq,
shutdown_intc2_irq,
enable_intc2_irq,
}
static struct hw_interrupt_type ipr_irq_type = {
- "IPR-based-IRQ",
+ "IPR-IRQ",
startup_ipr_irq,
shutdown_ipr_irq,
enable_ipr_irq,
void __init init_IRQ(void)
{
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
int i;
+#endif
make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
* Initialize the Interrupt Controller (INTC)
* registers to their power on values
*/
-#if 0
- /*
- * XXX: I think that this is the job of boot loader. -- gniibe
- *
- * When Takeshi released new boot loader following setting
- * will be removed shortly.
- */
- ctrl_outb(0, INTC_IRR0);
- ctrl_outb(0, INTC_IRR1);
- ctrl_outb(0, INTC_IRR2);
-
- ctrl_outw(0, INTC_ICR0);
- ctrl_outw(0, INTC_ICR1);/* Really? 0x4000?*/
- ctrl_outw(0, INTC_ICR2);
- ctrl_outw(0, INTC_INTER);
- ctrl_outw(0, INTC_IPRA);
- ctrl_outw(0, INTC_IPRB);
- ctrl_outw(0, INTC_IPRC);
- ctrl_outw(0, INTC_IPRD);
- ctrl_outw(0, INTC_IPRE);
-#endif
/*
* Enable external irq (INTC IRQ mode).
--- /dev/null
+/*
+ * linux/arch/sh/kernel/led_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from led_se.c and led.c, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains Big Sur specific LED code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/bigsur.h>
+
+static void mach_led(int position, int value)
+{
+ int word;
+
+ word = bigsur_inl(BIGSUR_CSLR);
+ if (value) {
+ bigsur_outl(word & ~BIGSUR_LED, BIGSUR_CSLR);
+ } else {
+ bigsur_outl(word | BIGSUR_LED, BIGSUR_CSLR);
+ }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* Cycle the LED on/off */
+void heartbeat_bigsur(void)
+{
+ static unsigned cnt = 0, period = 0, dist = 0;
+
+ if (cnt == 0 || cnt == dist)
+ mach_led( -1, 1);
+ else if (cnt == 7 || cnt == dist+7)
+ mach_led( -1, 0);
+
+ if (++cnt > period) {
+ cnt = 0;
+ /* The hyperbolic function below modifies the heartbeat period
+ * length in dependency of the current (5min) load. It goes
+ * through the points f(0)=126, f(1)=86, f(5)=51,
+ * f(inf)->30. */
+ period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+ dist = period / 4;
+ }
+}
+#endif /* CONFIG_HEARTBEAT */
+
--- /dev/null
+/*
+ * linux/arch/sh/kernel/mach_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from mach_se.h, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the Hitachi Big Sur Evaluation Board
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+#include <asm/io.h>
+#include <asm/io_bigsur.h>
+#include <asm/irq.h>
+
+/*
+ * The Machine Vector
+ */
+extern void heartbeat_bigsur(void);
+extern void setup_bigsur(void);
+extern void init_bigsur_IRQ(void);
+
+struct sh_machine_vector mv_bigsur __initmv = {
+ mv_name: "Big Sur",
+ mv_nr_irqs: NR_IRQS, // Defined in <asm/irq.h>
+ mv_inb: bigsur_inb,
+ mv_inw: bigsur_inw,
+ mv_inl: bigsur_inl,
+ mv_outb: bigsur_outb,
+ mv_outw: bigsur_outw,
+ mv_outl: bigsur_outl,
+
+ mv_inb_p: bigsur_inb_p,
+ mv_inw_p: bigsur_inw,
+ mv_inl_p: bigsur_inl,
+ mv_outb_p: bigsur_outb_p,
+ mv_outw_p: bigsur_outw,
+ mv_outl_p: bigsur_outl,
+
+ mv_insb: bigsur_insb,
+ mv_insw: bigsur_insw,
+ mv_insl: bigsur_insl,
+ mv_outsb: bigsur_outsb,
+ mv_outsw: bigsur_outsw,
+ mv_outsl: bigsur_outsl,
+
+ mv_readb: generic_readb,
+ mv_readw: generic_readw,
+ mv_readl: generic_readl,
+ mv_writeb: generic_writeb,
+ mv_writew: generic_writew,
+ mv_writel: generic_writel,
+
+ mv_ioremap: generic_ioremap,
+ mv_iounmap: generic_iounmap,
+
+ mv_isa_port2addr: bigsur_isa_port2addr,
+ mv_irq_demux: bigsur_irq_demux,
+
+ mv_init_arch: setup_bigsur,
+ mv_init_irq: init_bigsur_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ mv_heartbeat: heartbeat_bigsur,
+#endif
+ mv_rtc_gettimeofday: sh_rtc_gettimeofday,
+ mv_rtc_settimeofday: sh_rtc_settimeofday,
+
+};
+ALIAS_MV(bigsur)
/*
- * $Id: mach_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ * $Id: mach_dc.c,v 1.4 2001/05/24 05:09:16 mrbrown Exp $
* SEGA Dreamcast machine vector
*/
struct sh_machine_vector mv_dreamcast __initmv = {
mv_name: "dreamcast",
- mv_nr_irqs: 48,
+ mv_nr_irqs: NR_IRQS,
mv_inb: generic_inb,
mv_inw: generic_inw,
mv_iounmap: generic_iounmap,
mv_init_arch: setup_dreamcast,
-#ifdef CONFIG_PCI
- mv_init_pci: dreamcast_pcibios_init,
-#endif
mv_isa_port2addr: dreamcast_isa_port2addr,
+ mv_irq_demux: systemasic_irq_demux,
- mv_hw_dreamcast: 1,
+ mv_hw_dreamcast: 1,
};
ALIAS_MV(dreamcast)
--- /dev/null
+/*
+ * linux/arch/sh/kernel/pci-7751se.c
+ *
+ * Author: Ian DaSilva (idasilva@mvista.com)
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * PCI initialization for the Hitachi SH7751 Solution Engine board (MS7751SE01)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+
+#define PCIMCR_MRSET_OFF 0xBFFFFFFF
+#define PCIMCR_RFSH_OFF 0xFFFFFFFB
+
+/*
+ * Only long word accesses of the PCIC's internal local registers and the
+ * configuration registers from the CPU is supported.
+ */
+#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
+#define PCIC_READ(x) readl(PCI_REG(x))
+
+/*
+ * Description: This function sets up and initializes the pcic, sets
+ * up the BARS, maps the DRAM into the address space etc, etc.
+ */
+int __init pcibios_init_platform(void)
+{
+ unsigned long data;
+ unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
+ unsigned short bcr2;
+
+ //
+ // Initialize the slave bus controller on the pcic. The values used
+ // here should not be hardcoded, but they should be taken from the bsc
+ // on the processor, to make this function as generic as possible.
+ // (i.e. Another sbc may usr different SDRAM timing settings -- in order
+ // for the pcic to work, its settings need to be exactly the same.)
+ //
+ bcr1 = (*(volatile unsigned long*)(SH7751_BCR1));
+ bcr2 = (*(volatile unsigned short*)(SH7751_BCR2));
+ wcr1 = (*(volatile unsigned long*)(SH7751_WCR1));
+ wcr2 = (*(volatile unsigned long*)(SH7751_WCR2));
+ wcr3 = (*(volatile unsigned long*)(SH7751_WCR3));
+ mcr = (*(volatile unsigned long*)(SH7751_MCR));
+
+ bcr1 = bcr1 | 0x00080000; /* Enable Bit 19, BREQEN */
+ (*(volatile unsigned long*)(SH7751_BCR1)) = bcr1;
+
+ bcr1 = bcr1 | 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */
+ PCIC_WRITE(SH7751_PCIBCR1, bcr1); /* PCIC BCR1 */
+ PCIC_WRITE(SH7751_PCIBCR2, bcr2); /* PCIC BCR2 */
+ PCIC_WRITE(SH7751_PCIWCR1, wcr1); /* PCIC WCR1 */
+ PCIC_WRITE(SH7751_PCIWCR2, wcr2); /* PCIC WCR2 */
+ PCIC_WRITE(SH7751_PCIWCR3, wcr3); /* PCIC WCR3 */
+ mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+ PCIC_WRITE(SH7751_PCIMCR, mcr); /* PCIC MCR */
+
+ PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
+ PCIC_WRITE(SH7751_PCIAINTM, 0x0000980f);
+ PCIC_WRITE(SH7751_PCICONF1, 0xF39000C7); /* FB9000C7 */
+ PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */
+ PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O */
+ PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM0 old val: 0xb0000000 */
+ PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM1 */
+ PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Sub system ID & Sub system vendor ID */
+ PCIC_WRITE(SH7751_PCILSR0, 0x03f00000); /* PCI MEM0 */
+ PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* PCI MEM1 */
+ PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM0 */
+ PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM1 */
+
+ PCIC_WRITE(SH7751_PCICR, 0xa5000001);
+
+ printk("SH7751 PCI: Finished initialization of the PCI controller\n");
+
+ return 1;
+}
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+ switch (slot) {
+ case 0: return 13;
+ case 1: return 13; /* AMD Ethernet controller */
+ case 2: return -1;
+ case 3: return -1;
+ case 4: return -1;
+ default:
+ printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+ return -1;
+ }
+}
--- /dev/null
+/*
+ * linux/arch/sh/kernel/pci-bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * PCI initialization for the Hitachi Big Sur Evaluation Board
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+#include <asm/bigsur.h>
+
+#define PCI_REG(reg) (SH7751_PCIREG_BASE+reg)
+
+/*
+ * Initialize the Big Sur PCI interface
+ * Setup hardware to be Central Funtion
+ * Copy the BSR regs to the PCI interface
+ * Setup PCI windows into local RAM
+ */
+int __init pcibios_init_platform(void) {
+ u32 reg;
+ u32 word;
+
+ PCIDBG(1,"PCI: bigsur_pci_init called\n");
+ /* Set the BCR's to enable PCI access */
+ reg = inl(SH7751_BCR1);
+ reg |= 0x80000;
+ outl(reg, SH7751_BCR1);
+
+ /* Setup the host hardware */
+ if(inl(PCI_REG(SH7751_PCICONF0)) !=
+ (u32)((SH7751_DEVICE_ID <<16) | (SH7751_VENDOR_ID))) {
+ printk("PCI: Unkown PCI host bridge.\n");
+ return 0;
+ }
+ printk("PCI: SH7751 PCI host bridge found.\n");
+
+ /* Turn the clocks back on (not done in reset)*/
+ outl(0, PCI_REG(SH7751_PCICLKR));
+ /* Clear Powerdown IRQ's (not done in reset) */
+ word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0;
+ outl(word, PCI_REG(SH7751_PCICLKR));
+
+ /* toggle PCI reset pin */
+ word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST;
+ outl(word,PCI_REG(SH7751_PCICR));
+ /* Wait for a long time... not 1 sec. but long enough */
+ mdelay(100);
+ word = SH7751_PCICR_PREFIX;
+ outl(word,PCI_REG(SH7751_PCICR));
+
+ /* set the command/status bits to:
+ * Wait Cycle Control + Parity Enable + Bus Master +
+ * Mem space enable
+ */
+ word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
+ SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
+ outl(word, PCI_REG(SH7751_PCICONF1));
+
+ /* define this host as the host bridge */
+ word = SH7751_PCI_HOST_BRIDGE << 24;
+ outl(word, PCI_REG(SH7751_PCICONF2));
+
+ /* Set IO and Mem windows to local address
+ * Make PCI and local address the same for easy 1 to 1 mapping
+ * Window0 = BIGSUR_LSR0_SIZE @ non-cached CS3 base = SDRAM
+ * Window1 = BIGSUR_LSR1_SIZE @ cached CS3 base = SDRAM
+ */
+ word = BIGSUR_LSR0_SIZE - 1;
+ outl(word, PCI_REG(SH7751_PCILSR0));
+ word = BIGSUR_LSR1_SIZE - 1;
+ outl(word, PCI_REG(SH7751_PCILSR1));
+ /* Set the values on window 0 PCI config registers */
+ word = P2SEGADDR(SH7751_CS3_BASE_ADDR);
+ outl(word, PCI_REG(SH7751_PCILAR0));
+ outl(word, PCI_REG(SH7751_PCICONF5));
+ /* Set the values on window 1 PCI config registers */
+ word = PHYSADDR(SH7751_CS3_BASE_ADDR);
+ outl(word, PCI_REG(SH7751_PCILAR1));
+ outl(word, PCI_REG(SH7751_PCICONF6));
+
+ /* Set the local 16MB PCI memory space window to
+ * the lowest PCI mapped address
+ */
+ word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK;
+ PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word);
+ outl(word , PCI_REG(SH7751_PCIMBR));
+
+ /* Map IO space into PCI IO window
+ * The IO window is 64K-PCIBIOS_MIN_IO in size
+ * IO addresses will be translated to the
+ * PCI IO window base address
+ */
+ PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO,
+ (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO);
+ bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0);
+
+ /* Make sure the MSB's of IO window are set to access PCI space correctly */
+ word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK;
+ PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word);
+ outl(word, PCI_REG(SH7751_PCIIOBR));
+
+ /* Set PCI WCRx, BCRx's, copy from BSC locations */
+ word = inl(SH7751_BCR1);
+ /* check BCR for SDRAM in area 3 */
+ if(((word >> 3) & 1) == 0) {
+ printk("PCI: Area 3 is not configured for SDRAM. BCR1=0x%x\n", word);
+ return 0;
+ }
+ outl(word, PCI_REG(SH7751_PCIBCR1));
+ word = (u16)inw(SH7751_BCR2);
+ /* check BCR2 for 32bit SDRAM interface*/
+ if(((word >> 6) & 0x3) != 0x3) {
+ printk("PCI: Area 3 is not 32 bit SDRAM. BCR2=0x%x\n", word);
+ return 0;
+ }
+ outl(word, PCI_REG(SH7751_PCIBCR2));
+ /* configure the wait control registers */
+ word = inl(SH7751_WCR1);
+ outl(word, PCI_REG(SH7751_PCIWCR1));
+ word = inl(SH7751_WCR2);
+ outl(word, PCI_REG(SH7751_PCIWCR2));
+ word = inl(SH7751_WCR3);
+ outl(word, PCI_REG(SH7751_PCIWCR3));
+ word = inl(SH7751_MCR);
+ outl(word, PCI_REG(SH7751_PCIMCR));
+
+ /* NOTE: I'm ignoring the PCI error IRQs for now..
+ * TODO: add support for the internal error interrupts and
+ * DMA interrupts...
+ */
+
+ /* SH7751 init done, set central function init complete */
+ word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN;
+ outl(word,PCI_REG(SH7751_PCICR));
+ PCIDBG(2,"PCI: bigsur_pci_init finished\n");
+
+ return 1;
+}
+
+int pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+ /* The Big Sur can be used in a CPCI chassis, but the SH7751 PCI interface is on the
+ * wrong end of the board so that it can also support a V320 CPI interface chip...
+ * Therefor the IRQ mapping is somewhat use dependent... I'l assume a linear map for
+ * now, i.e. INTA=slot0,pin0... INTD=slot3,pin0...
+ */
+ int irq = (slot + pin-1)%4 + BIGSUR_SH7751_PCI_IRQ_BASE;
+ PCIDBG(2,"PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n", slot, pin-1+'A', irq);
+ return irq;
+
+}
--- /dev/null
+/*
+ $ $Id: pci-dc.c,v 1.2 2001/05/24 05:09:16 mrbrown Exp $
+ * Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dc_sysasic.h>
+
+#define GAPSPCI_REGS 0x01001400
+#define GAPSPCI_DMA_BASE 0x01840000
+#define GAPSPCI_DMA_SIZE 32768
+#define GAPSPCI_BBA_CONFIG 0x01001600
+
+#define GAPSPCI_IRQ HW_EVENT_EXTERNAL
+
+static int gapspci_dma_used;
+
+static struct pci_bus *pci_root_bus;
+
+struct pci_fixup pcibios_fixups[] = {
+ {0, 0, 0, NULL}
+};
+
+#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0)
+
+static int gapspci_read_config_byte(struct pci_dev *dev, int where,
+ u8 * val)
+{
+ if (BBA_SELECTED(dev))
+ *val = inb(GAPSPCI_BBA_CONFIG+where);
+ else
+ *val = 0xff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_read_config_word(struct pci_dev *dev, int where,
+ u16 * val)
+{
+ if (BBA_SELECTED(dev))
+ *val = inw(GAPSPCI_BBA_CONFIG+where);
+ else
+ *val = 0xffff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_read_config_dword(struct pci_dev *dev, int where,
+ u32 * val)
+{
+ if (BBA_SELECTED(dev))
+ *val = inl(GAPSPCI_BBA_CONFIG+where);
+ else
+ *val = 0xffffffff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write_config_byte(struct pci_dev *dev, int where,
+ u8 val)
+{
+ if (BBA_SELECTED(dev))
+ outb(val, GAPSPCI_BBA_CONFIG+where);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int gapspci_write_config_word(struct pci_dev *dev, int where,
+ u16 val)
+{
+ if (BBA_SELECTED(dev))
+ outw(val, GAPSPCI_BBA_CONFIG+where);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write_config_dword(struct pci_dev *dev, int where,
+ u32 val)
+{
+ if (BBA_SELECTED(dev))
+ outl(val, GAPSPCI_BBA_CONFIG+where);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_config_ops = {
+ gapspci_read_config_byte,
+ gapspci_read_config_word,
+ gapspci_read_config_dword,
+ gapspci_write_config_byte,
+ gapspci_write_config_word,
+ gapspci_write_config_dword
+};
+
+
+void pcibios_align_resource(void *data, struct resource *res,
+ unsigned long size)
+{
+}
+
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+}
+
+
+void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+}
+
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+ /* No special bus mastering setup handling */
+}
+
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for (idx = 0; idx < 6; idx++) {
+ r = dev->resource + idx;
+ if (!r->start && r->end) {
+ printk(KERN_ERR
+ "PCI: Device %s not available because"
+ " of resource collisions\n",
+ dev->slot_name);
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (cmd != old_cmd) {
+ printk("PCI: enabling device %s (%04x -> %04x)\n",
+ dev->slot_name, old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+
+}
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t * dma_handle)
+{
+ unsigned long buf;
+
+ if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE)
+ return NULL;
+
+ buf = GAPSPCI_DMA_BASE+gapspci_dma_used;
+
+ gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
+
+ printk("pci_alloc_consistent: %ld bytes at 0x%p\n", size, buf);
+
+ *dma_handle = (dma_addr_t)buf;
+
+ return (void *)P2SEGADDR(buf);
+}
+
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ /* XXX */
+}
+
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+{
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+ struct list_head *ln;
+ struct pci_dev *dev;
+
+ for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+ dev = pci_dev_b(ln);
+ if (!BBA_SELECTED(dev)) continue;
+
+ printk("PCI: MMIO fixup to %s\n", dev->name);
+ dev->resource[1].start=0x01001700;
+ dev->resource[1].end=0x010017ff;
+ }
+}
+
+
+static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+{
+ return PCI_SLOT(dev->devfn);
+}
+
+
+static int __init map_dc_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return GAPSPCI_IRQ;
+}
+
+
+void __init pcibios_init(void)
+{
+ pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+ /* pci_assign_unassigned_resources(); */
+ pci_fixup_irqs(no_swizzle, map_dc_irq);
+}
+
+
+/* Haven't done anything here as yet */
+char * __init pcibios_setup(char *str)
+{
+ return str;
+}
+
+
+int __init gapspci_init(void)
+{
+ int i;
+ char idbuf[16];
+
+ for(i=0; i<16; i++)
+ idbuf[i]=inb(GAPSPCI_REGS+i);
+
+ if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
+ return -1;
+
+ outl(0x5a14a501, GAPSPCI_REGS+0x18);
+
+ for(i=0; i<1000000; i++);
+
+ if(inl(GAPSPCI_REGS+0x18)!=1)
+ return -1;
+
+ outl(0x01000000, GAPSPCI_REGS+0x20);
+ outl(0x01000000, GAPSPCI_REGS+0x24);
+
+ outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
+ outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
+
+ outl(1, GAPSPCI_REGS+0x14);
+ outl(1, GAPSPCI_REGS+0x34);
+
+ gapspci_dma_used=0;
+
+ /* Setting Broadband Adapter */
+ outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
+ outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
+ outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
+ outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
+ outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
+ outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
+ outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t * dma_handle)
+{
+ void *ret;
+ int gfp = GFP_ATOMIC;
+
+ ret = (void *) __get_free_pages(gfp, get_order(size));
+
+ if (ret != NULL) {
+ /* Is it neccessary to do the memset? */
+ memset(ret, 0, size);
+ *dma_handle = virt_to_bus(ret);
+ }
+ /* We must flush the cache before we pass it on to the device */
+ flush_cache_all();
+ return P2SEGADDR(ret);
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
+
+ free_pages(p1addr, get_order(size));
+}
+++ /dev/null
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <asm/machvec.h>
-
-void __init pcibios_init(void)
-{
- if (sh_mv.mv_init_pci != NULL) {
- sh_mv.mv_init_pci();
- }
-}
-
-/* Haven't done anything here as yet */
-char * __init pcibios_setup(char *str)
-{
- return str;
-}
-
-/* We don't have anything here to fixup */
-struct pci_fixup pcibios_fixups[] = {
- {0, 0, 0, NULL}
-};
--- /dev/null
+/*
+ * Low-Level PCI Support for the SH7751
+ *
+ * Dustin McIntire (dustin@sensoria.com)
+ * Derived from arch/i386/kernel/pci-*.c which bore the message:
+ * (c) 1999--2000 Martin Mares <mj@suse.cz>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+*/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+
+#include <asm/segment.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+
+struct pci_ops *pci_check_direct(void);
+void pcibios_resource_survey(void);
+static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin);
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin);
+
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1;
+int pcibios_last_bus = -1;
+struct pci_bus *pci_root_bus;
+struct pci_ops *pci_root_ops;
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+#ifdef CONFIG_PCI_DIRECT
+
+
+#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+#define PCI_REG(reg) (SH7751_PCIREG_BASE+reg)
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+ u32 word;
+ unsigned long flags;
+
+ /* PCIPDR may only be accessed as 32 bit words,
+ * so we must do byte alignment by hand
+ */
+ __save_and_cli(flags);
+ outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+ word = inl(PCI_REG(SH7751_PCIPDR));
+ __restore_flags(flags);
+ switch (where & 0x3) {
+ case 3:
+ *value = (u8)(word >> 24);
+ break;
+ case 2:
+ *value = (u8)(word >> 16);
+ break;
+ case 1:
+ *value = (u8)(word >> 8);
+ break;
+ default:
+ *value = (u8)word;
+ break;
+ }
+ PCIDBG(4,"pci_conf1_read_config_byte@0x%08x=0x%x\n",
+ CONFIG_CMD(dev,where),*value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+ u32 word;
+ unsigned long flags;
+
+ /* PCIPDR may only be accessed as 32 bit words,
+ * so we must do word alignment by hand
+ */
+ __save_and_cli(flags);
+ outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+ word = inl(PCI_REG(SH7751_PCIPDR));
+ __restore_flags(flags);
+ switch (where & 0x3) {
+ case 3:
+ // This should never happen...
+ printk(KERN_ERR "PCI BIOS: read_config_word: Illegal u16 alignment");
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ case 2:
+ *value = (u16)(word >> 16);
+ break;
+ case 1:
+ *value = (u16)(word >> 8);
+ break;
+ default:
+ *value = (u16)word;
+ break;
+ }
+ PCIDBG(4,"pci_conf1_read_config_word@0x%08x=0x%x\n",
+ CONFIG_CMD(dev,where),*value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+ unsigned long flags;
+
+ __save_and_cli(flags);
+ outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+ *value = inl(PCI_REG(SH7751_PCIPDR));
+ __restore_flags(flags);
+ PCIDBG(4,"pci_conf1_read_config_dword@0x%08x=0x%x\n",
+ CONFIG_CMD(dev,where),*value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+ u32 word;
+ u32 shift = (where & 3) * 8;
+ u32 mask = ((1 << 8) - 1) << shift; // create the byte mask
+ unsigned long flags;
+
+ /* Since SH7751 only does 32bit access we'll have to do a
+ * read,mask,write operation
+ */
+ __save_and_cli(flags);
+ outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+ word = inl(PCI_REG(SH7751_PCIPDR)) ;
+ word &= ~mask;
+ word |= value << shift;
+
+ outl(word, PCI_REG(SH7751_PCIPDR));
+ __restore_flags(flags);
+ PCIDBG(4,"pci_conf1_write_config_byte@0x%08x=0x%x\n",
+ CONFIG_CMD(dev,where),word);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+ u32 word;
+ u32 shift = (where & 3) * 8;
+ u32 mask = ((1 << 16) - 1) << shift; // create the word mask
+ unsigned long flags;
+
+ /* Since SH7751 only does 32bit access we'll have to do a
+ * read,mask,write operation. We'll allow an odd byte offset,
+ * though it should be illegal.
+ */
+ if (shift == 24)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ __save_and_cli(flags);
+ outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+ word = inl(PCI_REG(SH7751_PCIPDR)) ;
+ word &= ~mask;
+ word |= value << shift;
+
+ outl(value, PCI_REG(SH7751_PCIPDR));
+ __restore_flags(flags);
+ PCIDBG(4,"pci_conf1_write_config_word@0x%08x=0x%x\n",
+ CONFIG_CMD(dev,where),word);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+ unsigned long flags;
+
+ __save_and_cli(flags);
+ outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+ outl(value, PCI_REG(SH7751_PCIPDR));
+ __restore_flags(flags);
+ PCIDBG(4,"pci_conf1_write_config_dword@0x%08x=0x%x\n",
+ CONFIG_CMD(dev,where),value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops pci_direct_conf1 = {
+ pci_conf1_read_config_byte,
+ pci_conf1_read_config_word,
+ pci_conf1_read_config_dword,
+ pci_conf1_write_config_byte,
+ pci_conf1_write_config_word,
+ pci_conf1_write_config_dword
+};
+
+struct pci_ops * __init pci_check_direct(void)
+{
+ unsigned int tmp, id;
+
+ /* check for SH7751 hardware */
+ id = (SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID;
+ if(inl(SH7751_PCIREG_BASE+SH7751_PCICONF0) != id) {
+ PCIDBG(2,"PCI: This is not an SH7751\n");
+ return NULL;
+ }
+ /*
+ * Check if configuration works.
+ */
+ if (pci_probe & PCI_PROBE_CONF1) {
+ tmp = inl (PCI_REG(SH7751_PCIPAR));
+ outl (0x80000000, PCI_REG(SH7751_PCIPAR));
+ if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) {
+ outl (tmp, PCI_REG(SH7751_PCIPAR));
+ printk(KERN_INFO "PCI: Using configuration type 1\n");
+ request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1");
+ return &pci_direct_conf1;
+ }
+ outl (tmp, PCI_REG(SH7751_PCIPAR));
+ }
+
+ PCIDBG(2,"PCI: pci_check_direct failed\n");
+ return NULL;
+}
+
+#endif
+
+/*
+ * BIOS32 and PCI BIOS handling.
+ *
+ * The BIOS version of the pci functions is not yet implemented but it is left
+ * in for completeness. Currently an error will be genereated at compile time.
+ */
+
+#ifdef CONFIG_PCI_BIOS
+
+#error PCI BIOS is not yet supported on SH7751
+
+#endif /* CONFIG_PCI_BIOS */
+
+/***************************************************************************************/
+
+/*
+ * Handle bus scanning and fixups ....
+ */
+
+
+/*
+ * Discover remaining PCI buses in case there are peer host bridges.
+ * We use the number of last PCI bus provided by the PCI BIOS.
+ */
+static void __init pcibios_fixup_peer_bridges(void)
+{
+ int n;
+ struct pci_bus bus;
+ struct pci_dev dev;
+ u16 l;
+
+ if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
+ return;
+ PCIDBG(2,"PCI: Peer bridge fixup\n");
+ for (n=0; n <= pcibios_last_bus; n++) {
+ if (pci_bus_exists(&pci_root_buses, n))
+ continue;
+ bus.number = n;
+ bus.ops = pci_root_ops;
+ dev.bus = &bus;
+ for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
+ if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
+ l != 0x0000 && l != 0xffff) {
+ PCIDBG(3,"Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
+ printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
+ pci_scan_bus(n, pci_root_ops, NULL);
+ break;
+ }
+ }
+}
+
+
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+ int i;
+
+ /*
+ * PCI IDE controllers use non-standard I/O port decoding, respect it.
+ */
+ if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+ return;
+ PCIDBG(3,"PCI: IDE base address fixup for %s\n", d->slot_name);
+ for(i=0; i<4; i++) {
+ struct resource *r = &d->resource[i];
+ if ((r->start & ~0x80) == 0x374) {
+ r->start |= 2;
+ r->end = r->start;
+ }
+ }
+}
+
+
+/* Add future fixups here... */
+struct pci_fixup pcibios_fixups[] = {
+ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases },
+ { 0 }
+};
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *b,
+ struct pbus_set_ranges_data *range)
+{
+ /* No fixups needed */
+}
+
+/*
+ * Called after each bus is probed, but before its children
+ * are examined.
+ */
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+ pci_read_bridge_bases(b);
+}
+
+/*
+ * Initialization. Try all known PCI access methods. Note that we support
+ * using both PCI BIOS and direct access: in such cases, we use I/O ports
+ * to access config space.
+ *
+ * Note that the platform specific initialization (BSC registers, and memory
+ * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it
+ * exitst and via the platform defined function pcibios_init_platform().
+ * See pci_bigsur.c for implementation;
+ *
+ * The BIOS version of the pci functions is not yet implemented but it is left
+ * in for completeness. Currently an error will be genereated at compile time.
+ */
+
+void __init pcibios_init(void)
+{
+ struct pci_ops *bios = NULL;
+ struct pci_ops *dir = NULL;
+
+ PCIDBG(1,"PCI: Starting intialization.\n");
+#ifdef CONFIG_PCI_BIOS
+ if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
+ pci_probe |= PCI_BIOS_SORT;
+ pci_bios_present = 1;
+ }
+#endif
+#ifdef CONFIG_PCI_DIRECT
+ if (pci_probe & PCI_PROBE_CONF1 )
+ dir = pci_check_direct();
+#endif
+ if (dir) {
+ pci_root_ops = dir;
+ if(!pcibios_init_platform())
+ PCIDBG(1,"PCI: Initialization failed\n");
+ if (sh_mv.mv_init_pci != NULL)
+ sh_mv.mv_init_pci();
+ }
+ else if (bios)
+ pci_root_ops = bios;
+ else {
+ PCIDBG(1,"PCI: No PCI bus detected\n");
+ return;
+ }
+
+ PCIDBG(1,"PCI: Probing PCI hardware\n");
+ pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
+ //pci_assign_unassigned_resources();
+ pci_fixup_irqs(pcibios_swizzle, pcibios_lookup_irq);
+ pcibios_fixup_peer_bridges();
+ pcibios_resource_survey();
+
+#ifdef CONFIG_PCI_BIOS
+ if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
+ pcibios_sort();
+#endif
+}
+
+char * __init pcibios_setup(char *str)
+{
+ if (!strcmp(str, "off")) {
+ pci_probe = 0;
+ return NULL;
+ }
+#ifdef CONFIG_PCI_BIOS
+ else if (!strcmp(str, "bios")) {
+ pci_probe = PCI_PROBE_BIOS;
+ return NULL;
+ } else if (!strcmp(str, "nobios")) {
+ pci_probe &= ~PCI_PROBE_BIOS;
+ return NULL;
+ } else if (!strcmp(str, "nosort")) {
+ pci_probe |= PCI_NO_SORT;
+ return NULL;
+ } else if (!strcmp(str, "biosirq")) {
+ pci_probe |= PCI_BIOS_IRQ_SCAN;
+ return NULL;
+ }
+#endif
+#ifdef CONFIG_PCI_DIRECT
+ else if (!strcmp(str, "conf1")) {
+ pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
+ return NULL;
+ }
+#endif
+ else if (!strcmp(str, "rom")) {
+ pci_probe |= PCI_ASSIGN_ROMS;
+ return NULL;
+ } else if (!strncmp(str, "lastbus=", 8)) {
+ pcibios_last_bus = simple_strtol(str+8, NULL, 0);
+ return NULL;
+ }
+ return str;
+}
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+ u32 new, check;
+ int reg;
+
+ new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+ if (resource < 6) {
+ reg = PCI_BASE_ADDRESS_0 + 4*resource;
+ } else if (resource == PCI_ROM_RESOURCE) {
+ res->flags |= PCI_ROM_ADDRESS_ENABLE;
+ new |= PCI_ROM_ADDRESS_ENABLE;
+ reg = dev->rom_base_reg;
+ } else {
+ /* Somebody might have asked allocation of a non-standard resource */
+ return;
+ }
+
+ pci_write_config_dword(dev, reg, new);
+ pci_read_config_dword(dev, reg, &check);
+ if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+ printk(KERN_ERR "PCI: Error while updating region "
+ "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+ new, check);
+ }
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ */
+void
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+ if (res->flags & IORESOURCE_IO) {
+ unsigned long start = res->start;
+
+ if (start & 0x300) {
+ start = (start + 0x3ff) & ~0x3ff;
+ res->start = start;
+ }
+ }
+}
+
+
+/*
+ * Allocate the bridge and device resources
+ */
+
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+ struct list_head *ln;
+ struct pci_bus *bus;
+ struct pci_dev *dev;
+ int idx;
+ struct resource *r, *pr;
+
+ PCIDBG(2,"PCI: pcibios_allocate_bus_reasources called\n" );
+ /* Depth-First Search on bus tree */
+ for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+ bus = pci_bus_b(ln);
+ if ((dev = bus->self)) {
+ for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start)
+ continue;
+ pr = pci_find_parent_resource(dev, r);
+ if (!pr || request_resource(pr, r) < 0)
+ printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+ }
+ }
+ pcibios_allocate_bus_resources(&bus->children);
+ }
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+ struct pci_dev *dev;
+ int idx, disabled;
+ u16 command;
+ struct resource *r, *pr;
+
+ PCIDBG(2,"PCI: pcibios_allocate_resources pass %d called\n", pass);
+ pci_for_each_dev(dev) {
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ for(idx = 0; idx < 6; idx++) {
+ r = &dev->resource[idx];
+ if (r->parent) /* Already allocated */
+ continue;
+ if (!r->start) /* Address not assigned at all */
+ continue;
+ if (r->flags & IORESOURCE_IO)
+ disabled = !(command & PCI_COMMAND_IO);
+ else
+ disabled = !(command & PCI_COMMAND_MEMORY);
+ if (pass == disabled) {
+ PCIDBG(3,"PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+ r->start, r->end, r->flags, disabled, pass);
+ pr = pci_find_parent_resource(dev, r);
+ if (!pr || request_resource(pr, r) < 0) {
+ printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
+ /* We'll assign a new address later */
+ r->end -= r->start;
+ r->start = 0;
+ }
+ }
+ }
+ if (!pass) {
+ r = &dev->resource[PCI_ROM_RESOURCE];
+ if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+ /* Turn the ROM off, leave the resource region, but keep it unregistered. */
+ u32 reg;
+ PCIDBG(3,"PCI: Switching off ROM of %s\n", dev->slot_name);
+ r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_read_config_dword(dev, dev->rom_base_reg, ®);
+ pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+ }
+ }
+ }
+}
+
+static void __init pcibios_assign_resources(void)
+{
+ struct pci_dev *dev;
+ int idx;
+ struct resource *r;
+
+ PCIDBG(2,"PCI: pcibios_assign_resources called\n");
+ pci_for_each_dev(dev) {
+ 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];
+
+ /*
+ * 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;
+
+ /*
+ * 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;
+ r->start = 0;
+ if (r->end)
+ pci_assign_resource(dev, PCI_ROM_RESOURCE);
+ }
+ }
+}
+
+void __init pcibios_resource_survey(void)
+{
+ PCIDBG(1,"PCI: Allocating resources\n");
+ pcibios_allocate_bus_resources(&pci_root_buses);
+ pcibios_allocate_resources(0);
+ pcibios_allocate_resources(1);
+ pcibios_assign_resources();
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for(idx=0; idx<6; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ cmd |= PCI_COMMAND_MEMORY;
+ if (cmd != old_cmd) {
+ printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", dev->name, old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+/*
+ * If we set up a device for bus mastering, we need to check and set
+ * the latency timer as it may not be properly set.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+ u8 lat;
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ if (lat < 16)
+ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+ else if (lat > pcibios_max_latency)
+ lat = pcibios_max_latency;
+ else
+ return;
+ printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", dev->name, lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+/***************************************************************************************/
+/*
+ * IRQ functions
+ */
+static u8 __init pcibios_swizzle(struct pci_dev *dev, u8 *pin)
+{
+ /* no swizzling */
+ return PCI_SLOT(dev->devfn);
+}
+
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq = -1;
+
+ /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+ irq = pcibios_map_platform_irq(slot,pin);
+ if( irq < 0 ) {
+ PCIDBG(3,"PCI: Error mapping IRQ on device %s\n", dev->name);
+ return irq;
+ }
+
+ PCIDBG(2,"Setting IRQ for slot %s to %d\n", dev->slot_name, irq);
+
+ return irq;
+}
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ PCIDBG(3,"PCI: Update IRQ for %s on irq %d\n", dev->name, irq);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
return tmp;
}
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+ int i;
+
+ /*
+ * PCI IDE controllers use non-standard I/O port decoding, respect it.
+ */
+ if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+ return;
+ printk("PCI: IDE base address fixup for %s\n", d->slot_name);
+ for(i=0; i<4; i++) {
+ struct resource *r = &d->resource[i];
+ if ((r->start & ~0x80) == 0x374) {
+ r->start |= 2;
+ r->end = r->start;
+ }
+ }
+}
+
+
+/* Add future fixups here... */
+struct pci_fixup pcibios_fixups[] = {
+ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases },
+ { 0 }
+};
int __init st40pci_init(unsigned memStart, unsigned memSize)
{
return 1;
}
+char * __init pcibios_setup(char *str)
+{
+ return str;
+}
+
#define SET_CONFIG_BITS(bus,devfn,where)\
(((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0))
ranges->mem_end -= bus->resource[1]->start;
}
-void __init st40_pcibios_init(void)
+void __init pcibios_init(void)
{
extern unsigned long memory_start, memory_end;
+ if (sh_mv.mv_init_pci != NULL) {
+ sh_mv.mv_init_pci();
+ }
+
/* The pci subsytem needs to know where memory is and how much
* of it there is. I've simply made these globals. A better mechanism
* is probably needed.
printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
+
+/*
+ * If we set up a device for bus mastering, we need to check the latency
+ * timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+ u8 lat;
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ if (lat < 16)
+ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+ else if (lat > pcibios_max_latency)
+ lat = pcibios_max_latency;
+ else
+ return;
+ printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
#include <asm/io.h>
#include <asm/rtc.h>
-/* RCR1 Bits */
-#define RCR1_CF 0x80 /* Carry Flag */
-#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
-#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
-#define RCR1_AF 0x01 /* Alarm Flag */
-
-/* RCR2 Bits */
-#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
-#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
-#define RCR2_RTCEN 0x08 /* ENable RTC */
-#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
-#define RCR2_RESET 0x02 /* Reset bit */
-#define RCR2_START 0x01 /* Start bit */
-
-#if defined(__sh3__)
-/* SH-3 RTC */
-#define R64CNT 0xfffffec0
-#define RSECCNT 0xfffffec2
-#define RMINCNT 0xfffffec4
-#define RHRCNT 0xfffffec6
-#define RWKCNT 0xfffffec8
-#define RDAYCNT 0xfffffeca
-#define RMONCNT 0xfffffecc
-#define RYRCNT 0xfffffece
-#define RSECAR 0xfffffed0
-#define RMINAR 0xfffffed2
-#define RHRAR 0xfffffed4
-#define RWKAR 0xfffffed6
-#define RDAYAR 0xfffffed8
-#define RMONAR 0xfffffeda
-#define RCR1 0xfffffedc
-#define RCR2 0xfffffede
-
-#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
-#elif defined(__SH4__)
-/* SH-4 RTC */
-#define R64CNT 0xffc80000
-#define RSECCNT 0xffc80004
-#define RMINCNT 0xffc80008
-#define RHRCNT 0xffc8000c
-#define RWKCNT 0xffc80010
-#define RDAYCNT 0xffc80014
-#define RMONCNT 0xffc80018
-#define RYRCNT 0xffc8001c /* 16bit */
-#define RSECAR 0xffc80020
-#define RMINAR 0xffc80024
-#define RHRAR 0xffc80028
-#define RWKAR 0xffc8002c
-#define RDAYAR 0xffc80030
-#define RMONAR 0xffc80034
-#define RCR1 0xffc80038
-#define RCR2 0xffc8003c
-
-#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
-#endif
-
#ifndef BCD_TO_BIN
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
#endif
PRINT_CLOCK("CPU", boot_cpu_data.cpu_clock);
PRINT_CLOCK("Bus", boot_cpu_data.bus_clock);
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+ PRINT_CLOCK("Memory", boot_cpu_data.memory_clock);
+#endif
PRINT_CLOCK("Peripheral module", boot_cpu_data.module_clock);
return p - buffer;
--- /dev/null
+/*
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ *
+ * Setup and IRQ handling code for the HD64465 companion chip.
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc
+ *
+ * Derived from setup_hd64465.c which bore the message:
+ * Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc and
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * and setup_cqreek.c which bore message:
+ * Copyright (C) 2000 Niibe Yutaka
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Setup and IRQ functions for a Hitachi Big Sur Evaluation Board.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#include <asm/io_bigsur.h>
+#include <asm/hd64465.h>
+#include <asm/bigsur.h>
+
+//#define BIGSUR_DEBUG 3
+#undef BIGSUR_DEBUG
+
+#ifdef BIGSUR_DEBUG
+#define DPRINTK(args...) printk(args)
+#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
+#else
+#define DPRINTK(args...)
+#define DIPRINTK(n, args...)
+#endif /* BIGSUR_DEBUG */
+
+#ifdef CONFIG_HD64465
+extern int hd64465_irq_demux(int irq);
+#endif /* CONFIG_HD64465 */
+
+
+/*===========================================================*/
+// Big Sur CPLD IRQ Routines
+/*===========================================================*/
+
+/* Level 1 IRQ routines */
+static void disable_bigsur_l1irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned char mask;
+ unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+ unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ DPRINTK("Disable L1 IRQ %d\n", irq);
+ DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+ save_and_cli(flags);
+
+ /* Disable IRQ - set mask bit */
+ mask = inb(mask_port) | bit;
+ outb(mask, mask_port);
+ restore_flags(flags);
+ return;
+ }
+ DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
+}
+
+static void enable_bigsur_l1irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned char mask;
+ unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+ unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ DPRINTK("Enable L1 IRQ %d\n", irq);
+ DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+ save_and_cli(flags);
+ /* Enable L1 IRQ - clear mask bit */
+ mask = inb(mask_port) & ~bit;
+ outb(mask, mask_port);
+ restore_flags(flags);
+ return;
+ }
+ DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
+}
+
+
+/* Level 2 irq masks and registers for L2 decoding */
+/* Level2 bitmasks for each level 1 IRQ */
+const u32 bigsur_l2irq_mask[] =
+ {0x40,0x80,0x08,0x01,0x01,0x3C,0x3E,0xFF,0x40,0x80,0x06,0x03};
+/* Level2 to ISR[n] map for each level 1 IRQ */
+const u32 bigsur_l2irq_reg[] =
+ { 2, 2, 3, 3, 1, 2, 1, 0, 1, 1, 3, 2};
+/* Level2 to Level 1 IRQ map */
+const u32 bigsur_l2_l1_map[] =
+ {7,7,7,7,7,7,7,7, 4,6,6,6,6,6,8,9, 11,11,5,5,5,5,0,1, 3,10,10,2,-1,-1,-1,-1};
+/* IRQ inactive level (high or low) */
+const u32 bigsur_l2_inactv_state[] = {0x00, 0xBE, 0xFC, 0xF7};
+
+/* CPLD external status and mask registers base and offsets */
+static const u32 isr_base = BIGSUR_IRQ0;
+static const u32 isr_offset = BIGSUR_IRQ0 - BIGSUR_IRQ1;
+static const u32 imr_base = BIGSUR_IMR0;
+static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1;
+
+#define REG_NUM(irq) ((irq-BIGSUR_2NDLVL_IRQ_LOW)/8 )
+
+/* Level 2 IRQ routines */
+static void disable_bigsur_l2irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned char mask;
+ unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+ unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+ DPRINTK("Disable L2 IRQ %d\n", irq);
+ DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+ save_and_cli(flags);
+
+ /* Disable L2 IRQ - set mask bit */
+ mask = inb(mask_port) | bit;
+ outb(mask, mask_port);
+ restore_flags(flags);
+ return;
+ }
+ DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+}
+
+static void enable_bigsur_l2irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned char mask;
+ unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+ unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+ DPRINTK("Enable L2 IRQ %d\n", irq);
+ DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+ save_and_cli(flags);
+
+ /* Enable L2 IRQ - clear mask bit */
+ mask = inb(mask_port) & ~bit;
+ outb(mask, mask_port);
+ restore_flags(flags);
+ return;
+ }
+ DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+}
+
+static void mask_and_ack_bigsur(unsigned int irq)
+{
+ DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ disable_bigsur_l1irq(irq);
+ else
+ disable_bigsur_l2irq(irq);
+}
+
+static void end_bigsur_irq(unsigned int irq)
+{
+ DPRINTK("end_bigsur_irq IRQ %d\n", irq);
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ enable_bigsur_l1irq(irq);
+ else
+ enable_bigsur_l2irq(irq);
+}
+
+static unsigned int startup_bigsur_irq(unsigned int irq)
+{
+ u8 mask;
+ u32 reg;
+
+ DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ /* Enable the L1 IRQ */
+ enable_bigsur_l1irq(irq);
+ /* Enable all L2 IRQs in this L1 IRQ */
+ mask = ~(bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]);
+ reg = imr_base - bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW] * imr_offset;
+ mask &= inb(reg);
+ outb(mask,reg);
+ DIPRINTK(2,"startup_bigsur_irq: IMR=0x%08x mask=0x%x\n",reg,inb(reg));
+ }
+ else {
+ /* Enable the L2 IRQ - clear mask bit */
+ enable_bigsur_l2irq(irq);
+ /* Enable the L1 bit masking this L2 IRQ */
+ enable_bigsur_l1irq(bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW]);
+ DIPRINTK(2,"startup_bigsur_irq: L1=%d L2=%d\n",
+ bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW],irq);
+ }
+ return 0;
+}
+
+static void shutdown_bigsur_irq(unsigned int irq)
+{
+ DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ disable_bigsur_l1irq(irq);
+ else
+ disable_bigsur_l2irq(irq);
+}
+
+/* Define the IRQ structures for the L1 and L2 IRQ types */
+static struct hw_interrupt_type bigsur_l1irq_type = {
+ "BigSur-CPLD-Level1-IRQ",
+ startup_bigsur_irq,
+ shutdown_bigsur_irq,
+ enable_bigsur_l1irq,
+ disable_bigsur_l1irq,
+ mask_and_ack_bigsur,
+ end_bigsur_irq
+};
+
+static struct hw_interrupt_type bigsur_l2irq_type = {
+ "BigSur-CPLD-Level2-IRQ",
+ startup_bigsur_irq,
+ shutdown_bigsur_irq,
+ enable_bigsur_l2irq,
+ disable_bigsur_l2irq,
+ mask_and_ack_bigsur,
+ end_bigsur_irq
+};
+
+
+static void make_bigsur_l1isr(unsigned int irq) {
+
+ /* sanity check first */
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ /* save the handler in the main description table */
+ irq_desc[irq].handler = &bigsur_l1irq_type;
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = 0;
+ irq_desc[irq].depth = 1;
+
+ disable_bigsur_l1irq(irq);
+ return;
+ }
+ DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
+ return;
+}
+
+static void make_bigsur_l2isr(unsigned int irq) {
+
+ /* sanity check first */
+ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+ /* save the handler in the main description table */
+ irq_desc[irq].handler = &bigsur_l2irq_type;
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = 0;
+ irq_desc[irq].depth = 1;
+
+ disable_bigsur_l2irq(irq);
+ return;
+ }
+ DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
+ return;
+}
+
+/* The IRQ's will be decoded as follows:
+ * If a level 2 handler exists and there is an unmasked active
+ * IRQ, the 2nd level handler will be called.
+ * If a level 2 handler does not exist for the active IRQ
+ * the 1st level handler will be called.
+ */
+
+int bigsur_irq_demux(int irq)
+{
+ int dmux_irq = irq;
+ u8 mask, actv_irqs;
+ u32 reg_num;
+
+ DIPRINTK(3,"bigsur_irq_demux, irq=%d\n", irq);
+ /* decode the 1st level IRQ */
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ /* Get corresponding L2 ISR bitmask and ISR number */
+ mask = bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW];
+ reg_num = bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW];
+ /* find the active IRQ's (XOR with inactive level)*/
+ actv_irqs = inb(isr_base-reg_num*isr_offset) ^
+ bigsur_l2_inactv_state[reg_num];
+ /* decode active IRQ's */
+ actv_irqs = actv_irqs & mask & ~(inb(imr_base-reg_num*imr_offset));
+ /* if NEZ then we have an active L2 IRQ */
+ if(actv_irqs) dmux_irq = ffz(~actv_irqs) + reg_num*8+BIGSUR_2NDLVL_IRQ_LOW;
+ /* if no 2nd level IRQ action, but has 1st level, use 1st level handler */
+ if(!irq_desc[dmux_irq].action && irq_desc[irq].action)
+ dmux_irq = irq;
+ DIPRINTK(1,"bigsur_irq_demux: irq=%d dmux_irq=%d mask=0x%04x reg=%d\n",
+ irq, dmux_irq, mask, reg_num);
+ }
+#ifdef CONFIG_HD64465
+ dmux_irq = hd64465_irq_demux(dmux_irq);
+#endif /* CONFIG_HD64465 */
+ DIPRINTK(3,"bigsur_irq_demux, demux_irq=%d\n", dmux_irq);
+
+ return dmux_irq;
+}
+
+/*===========================================================*/
+// Big Sur Init Routines
+/*===========================================================*/
+void __init init_bigsur_IRQ(void)
+{
+ int i;
+
+ if (!MACH_BIGSUR) return;
+
+ /* Create ISR's for Big Sur CPLD IRQ's */
+ /*==============================================================*/
+ for(i=BIGSUR_IRQ_LOW;i<BIGSUR_IRQ_HIGH;i++)
+ make_bigsur_l1isr(i);
+
+ printk(KERN_INFO "Big Sur CPLD L1 interrupts %d to %d.\n",
+ BIGSUR_IRQ_LOW,BIGSUR_IRQ_HIGH);
+
+ for(i=BIGSUR_2NDLVL_IRQ_LOW;i<BIGSUR_2NDLVL_IRQ_HIGH;i++)
+ make_bigsur_l2isr(i);
+
+ printk(KERN_INFO "Big Sur CPLD L2 interrupts %d to %d.\n",
+ BIGSUR_2NDLVL_IRQ_LOW,BIGSUR_2NDLVL_IRQ_HIGH);
+
+}
+
+int __init setup_bigsur(void)
+{
+ static int done = 0; /* run this only once */
+
+ if (!MACH_BIGSUR || done) return 0;
+ done = 1;
+
+ /* Mask all 2nd level IRQ's */
+ outb(-1,BIGSUR_IMR0);
+ outb(-1,BIGSUR_IMR1);
+ outb(-1,BIGSUR_IMR2);
+ outb(-1,BIGSUR_IMR3);
+
+ /* Mask 1st level interrupts */
+ outb(-1,BIGSUR_IRLMR0);
+ outb(-1,BIGSUR_IRLMR1);
+
+#if defined (CONFIG_HD64465) && defined (CONFIG_SERIAL)
+ /* remap IO ports for first ISA serial port to HD64465 UART */
+ bigsur_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1);
+#endif /* CONFIG_HD64465 && CONFIG_SERIAL */
+ /* TODO: setup IDE registers */
+ bigsur_port_map(BIGSUR_IDECTL_IOPORT, 2, BIGSUR_ICTL, 8);
+ /* Setup the Ethernet port to BIGSUR_ETHER_IOPORT */
+ bigsur_port_map(BIGSUR_ETHER_IOPORT, 16, BIGSUR_ETHR+BIGSUR_ETHER_IOPORT, 0);
+ /* set page to 1 */
+ outw(1, BIGSUR_ETHR+0xe);
+ /* set the IO port to BIGSUR_ETHER_IOPORT */
+ outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
+
+ return 0;
+}
+
+module_init(setup_bigsur);
-/*
- * $Id: setup_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+/* arch/sh/kernel/setup_dc.c
+ *
+ * Hardware support for the Sega Dreamcast.
+ *
+ * Copyright (c) 2001 M. R. Brown <mrbrown@linuxdc.org>
+ *
+ * This file is part of the LinuxDC project (www.linuxdc.org)
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * This file originally bore the message:
+ * $Id: setup_dc.c,v 1.5 2001/05/24 05:09:16 mrbrown Exp $
* SEGA Dreamcast support
*/
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
-#include <linux/pci.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/dc_sysasic.h>
-#define GAPSPCI_REGS 0x01001400
-#define GAPSPCI_DMA_BASE 0x01840000
-#define GAPSPCI_DMA_SIZE 32768
-#define GAPSPCI_BBA_CONFIG 0x01001600
+int __init gapspci_init(void);
-#define GAPSPCI_IRQ 11
-#define GAPSPCI_INTC 0x005f6924
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-static int gapspci_dma_used;
+/* Dreamcast System ASIC Hardware Events -
+
+ The Dreamcast's System ASIC (located on the PowerVR2 chip) is responsible
+ for receiving hardware events from system peripherals and triggering an
+ SH7750 IRQ. Hardware events can trigger IRQs 13, 11, or 9 depending on
+ which bits are set in the Event Mask Registers (EMRs). When a hardware
+ event is triggered, it's corresponding bit in the Event Status Registers
+ (ESRs) is set, and that bit should be rewritten to the ESR to acknowledge
+ that event.
-static struct pci_bus *pci_root_bus;
+ There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908. Event
+ types can be found in include/asm-sh/dc_sysasic.h. There are three groups
+ of EMRs that parallel the ESRs. Each EMR group corresponds to an IRQ, so
+ 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 triggers
+ IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
-static void disable_gapspci_irq(unsigned int irq)
-{
- unsigned long flags;
- unsigned long intc;
-
- save_and_cli(flags);
- intc = inl(GAPSPCI_INTC);
- intc &= ~(1<<3);
- outl(intc, GAPSPCI_INTC);
- restore_flags(flags);
-}
+ In the kernel, these events are mapped to virtual IRQs so that drivers can
+ respond to them as they would a normal interrupt. In order to keep this
+ mapping simple, the events are mapped as:
+
+ 6900/6910 - Events 0-31, IRQ 13
+ 6904/6924 - Events 32-63, IRQ 11
+ 6908/6938 - Events 64-95, IRQ 9
+
+*/
+
+#define ESR_BASE 0x005f6900 /* Base event status register */
+#define EMR_BASE 0x005f6910 /* Base event mask register */
+
+/* Helps us determine the EMR group that this event belongs to: 0 = 0x6910,
+ 1 = 0x6920, 2 = 0x6930; also determine the event offset */
+#define LEVEL(event) (((event) - HW_EVENT_IRQ_BASE) / 32)
+
+/* Return the hardware event's bit positon within the EMR/ESR */
+#define EVENT_BIT(event) (((event) - HW_EVENT_IRQ_BASE) & 31)
+/* For each of these *_irq routines, the IRQ passed in is the virtual IRQ
+ (logically mapped to the corresponding bit for the hardware event). */
-static void enable_gapspci_irq(unsigned int irq)
+/* Disable the hardware event by masking its bit in its EMR */
+static inline void disable_systemasic_irq(unsigned int irq)
{
- unsigned long flags;
- unsigned long intc;
-
- save_and_cli(flags);
- intc = inl(GAPSPCI_INTC);
- intc |= (1<<3);
- outl(intc, GAPSPCI_INTC);
- restore_flags(flags);
+ __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+ __u32 mask;
+ mask = inl(emr);
+ mask &= ~(1 << EVENT_BIT(irq));
+ outl(mask, emr);
}
-
-static void mask_and_ack_gapspci_irq(unsigned int irq)
+/* Enable the hardware event by setting its bit in its EMR */
+static inline void enable_systemasic_irq(unsigned int irq)
{
- unsigned long flags;
- unsigned long intc;
-
- save_and_cli(flags);
- intc = inl(GAPSPCI_INTC);
- intc &= ~(1<<3);
- outl(intc, GAPSPCI_INTC);
- restore_flags(flags);
+ __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+ __u32 mask;
+ mask = inl(emr);
+ mask |= (1 << EVENT_BIT(irq));
+ outl(mask, emr);
}
+/* Acknowledge a hardware event by writing its bit back to its ESR */
+static void ack_systemasic_irq(unsigned int irq)
+{
+ __u32 esr = ESR_BASE + (LEVEL(irq) << 2);
+ disable_systemasic_irq(irq);
+ outl((1 << EVENT_BIT(irq)), esr);
+}
-static void end_gapspci_irq(unsigned int irq)
+/* After a IRQ has been ack'd and responded to, it needs to be renabled */
+static void end_systemasic_irq(unsigned int irq)
{
- enable_gapspci_irq(irq);
+ enable_systemasic_irq(irq);
}
+static unsigned int startup_systemasic_irq(unsigned int irq)
+{
+ enable_systemasic_irq(irq);
-static unsigned int startup_gapspci_irq(unsigned int irq)
-{
- enable_gapspci_irq(irq);
return 0;
}
-
-static void shutdown_gapspci_irq(unsigned int irq)
+static void shutdown_systemasic_irq(unsigned int irq)
{
- disable_gapspci_irq(irq);
+ disable_systemasic_irq(irq);
}
-
-static struct hw_interrupt_type gapspci_irq_type = {
- "GAPSPCI-IRQ",
- startup_gapspci_irq,
- shutdown_gapspci_irq,
- enable_gapspci_irq,
- disable_gapspci_irq,
- mask_and_ack_gapspci_irq,
- end_gapspci_irq
+static struct hw_interrupt_type systemasic_int = {
+ typename: "System ASIC",
+ startup: startup_systemasic_irq,
+ shutdown: shutdown_systemasic_irq,
+ enable: enable_systemasic_irq,
+ disable: disable_systemasic_irq,
+ ack: ack_systemasic_irq,
+ end: end_systemasic_irq,
};
+/*
+ * Map the hardware event indicated by the processor IRQ to a virtual IRQ.
+ */
+int systemasic_irq_demux(int irq)
+{
+ __u32 emr, esr, status, level;
+ __u32 j, bit;
+
+ switch (irq) {
+ case 13:
+ level = 0;
+ break;
+ case 11:
+ level = 1;
+ break;
+ case 9:
+ level = 2;
+ break;
+ default:
+ return irq;
+ }
+ emr = EMR_BASE + (level << 4) + (level << 2);
+ esr = ESR_BASE + (level << 2);
+
+ /* Mask the ESR to filter any spurious, unwanted interrtupts */
+ status = inl(esr);
+ status &= inl(emr);
+
+ /* Now scan and find the first set bit as the event to map */
+ for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
+ if (status & bit) {
+ irq = HW_EVENT_IRQ_BASE + j + (level << 5);
+ return irq;
+ }
+ }
-static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
-{
- return PCI_SLOT(dev->devfn);
-}
-
-static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- return GAPSPCI_IRQ;
+ /* Not reached */
+ return irq;
}
int __init setup_dreamcast(void)
{
+ int i;
+
+ /* Mask all hardware events */
+ /* XXX */
+
+ /* Acknowledge any previous events */
+ /* XXX */
+
+ /* Assign all virtual IRQs to the System ASIC int. handler */
+ for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
+ irq_desc[i].handler = &systemasic_int;
+
+#ifdef CONFIG_PCI
gapspci_init();
+#endif
printk(KERN_INFO "SEGA Dreamcast support.\n");
#if 0
#endif
return 0;
}
-
-
-/*
- * Dreamcast PCI: Supports SEGA Broadband Adaptor only.
- */
-
-#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0)
-
-static int gapspci_read_config_byte(struct pci_dev *dev, int where,
- u8 * val)
-{
- if (BBA_SELECTED(dev))
- *val = inb(GAPSPCI_BBA_CONFIG+where);
- else
- *val = 0xff;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_read_config_word(struct pci_dev *dev, int where,
- u16 * val)
-{
- if (BBA_SELECTED(dev))
- *val = inw(GAPSPCI_BBA_CONFIG+where);
- else
- *val = 0xffff;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_read_config_dword(struct pci_dev *dev, int where,
- u32 * val)
-{
- if (BBA_SELECTED(dev))
- *val = inl(GAPSPCI_BBA_CONFIG+where);
- else
- *val = 0xffffffff;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_write_config_byte(struct pci_dev *dev, int where,
- u8 val)
-{
- if (BBA_SELECTED(dev))
- outb(val, GAPSPCI_BBA_CONFIG+where);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int gapspci_write_config_word(struct pci_dev *dev, int where,
- u16 val)
-{
- if (BBA_SELECTED(dev))
- outw(val, GAPSPCI_BBA_CONFIG+where);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_write_config_dword(struct pci_dev *dev, int where,
- u32 val)
-{
- if (BBA_SELECTED(dev))
- outl(val, GAPSPCI_BBA_CONFIG+where);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_config_ops = {
- gapspci_read_config_byte,
- gapspci_read_config_word,
- gapspci_read_config_dword,
- gapspci_write_config_byte,
- gapspci_write_config_word,
- gapspci_write_config_dword
-};
-
-
-void pcibios_align_resource(void *data, struct resource *res,
- unsigned long size)
-{
-}
-
-
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-}
-
-
-void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
- struct resource *res, int resource)
-{
-}
-
-
-int pcibios_enable_device(struct pci_dev *dev)
-{
-
- u16 cmd, old_cmd;
- int idx;
- struct resource *r;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- old_cmd = cmd;
- for (idx = 0; idx < 6; idx++) {
- r = dev->resource + idx;
- if (!r->start && r->end) {
- printk(KERN_ERR
- "PCI: Device %s not available because"
- " of resource collisions\n",
- dev->slot_name);
- return -EINVAL;
- }
- if (r->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- if (r->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- if (cmd != old_cmd) {
- printk("PCI: enabling device %s (%04x -> %04x)\n",
- dev->slot_name, old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- return 0;
-
-}
-
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t * dma_handle)
-{
- unsigned long buf;
-
- if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE)
- return NULL;
-
- buf = GAPSPCI_DMA_BASE+gapspci_dma_used;
-
- gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
-
- printk("pci_alloc_consistent: %d bytes at 0x%08x\n", size, buf);
-
- *dma_handle = (dma_addr_t)buf;
-
- return (void *)P2SEGADDR(buf);
-}
-
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
-}
-
-
-void __init
-pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
-{
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
- struct list_head *ln;
- struct pci_dev *dev;
-
- for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
- dev = pci_dev_b(ln);
- if (!BBA_SELECTED(dev)) continue;
-
- printk("PCI: MMIO fixup to %s\n", dev->name);
- dev->resource[1].start=0x01001700;
- dev->resource[1].end=0x010017ff;
- }
-}
-
-
-void __init dreamcast_pcibios_init(void)
-{
- pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
- /* pci_assign_unassigned_resources(); */
- pci_fixup_irqs(no_swizzle, map_od_irq);
-}
-
-
-static __init int gapspci_init(void)
-{
- int i;
- char idbuf[16];
-
- for(i=0; i<16; i++)
- idbuf[i]=inb(GAPSPCI_REGS+i);
-
- if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
- return -1;
-
- outl(0x5a14a501, GAPSPCI_REGS+0x18);
-
- for(i=0; i<1000000; i++);
-
- if(inl(GAPSPCI_REGS+0x18)!=1)
- return -1;
-
- outl(0x01000000, GAPSPCI_REGS+0x20);
- outl(0x01000000, GAPSPCI_REGS+0x24);
-
- outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
- outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
-
- outl(1, GAPSPCI_REGS+0x14);
- outl(1, GAPSPCI_REGS+0x34);
-
- gapspci_dma_used=0;
-
- /* */
- irq_desc[GAPSPCI_IRQ].handler = &gapspci_irq_type;
-
- /* Setting Broadband Adapter */
- outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
- outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
- outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
- outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
- outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
- outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
- outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
-
- return 0;
-}
+++ /dev/null
-/* $Id: setup_od.c,v 1.1 2000/06/14 09:35:59 stuart_menefy Exp $
- *
- * arch/sh/kernel/setup_od.c
- *
- * Copyright (C) 2000 Stuart Menefy
- *
- * STMicroelectronics Overdrive Support.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-/*
- * Initialize the board
- */
-int __init setup_od(void)
-{
- /* Enable RS232 receive buffers */
- volatile int* p = (volatile int*)0xa3000000;
-
-#if defined(CONFIG_SH_ORION)
- *p=1;
-#elif defined(CONFIG_SH_OVERDRIVE)
- *p=0x1e;
-#else
-#error Illegal configuration
-#endif
-
- printk(KERN_INFO "STMicroelectronics Overdrive Setup...done\n");
- return 0;
-}
-
-module_init(setup_od);
--- /dev/null
+/*
+ * linux/arch/sh/kernel/setup_sh2000.c
+ *
+ * Copyright (C) 2001 SUGIOKA Tochinobu
+ *
+ * SH-2000 Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/io_generic.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/rtc.h>
+
+#define CF_CIS_BASE 0xb4200000
+
+#define PORT_PECR 0xa4000108
+#define PORT_PHCR 0xa400010E
+#define PORT_ICR1 0xa4000010
+#define PORT_IRR0 0xa4000004
+
+/*
+ * Initialize the board
+ */
+int __init setup_sh2000(void)
+{
+ /* XXX: RTC setting comes here */
+
+ /* These should be done by BIOS/IPL ... */
+ /* Enable nCE2A, nCE2B output */
+ ctrl_outw(ctrl_inw(PORT_PECR) & ~0xf00, PORT_PECR);
+ /* Enable the Compact Flash card, and set the level interrupt */
+ ctrl_outw(0x0042, CF_CIS_BASE+0x0200);
+ /* Enable interrupt */
+ ctrl_outw(ctrl_inw(PORT_PHCR) & ~0x03f3, PORT_PHCR);
+ ctrl_outw(1, PORT_ICR1);
+ ctrl_outw(ctrl_inw(PORT_IRR0) & ~0xff3f, PORT_IRR0);
+ printk(KERN_INFO "SH-2000 Setup...done\n");
+ return 0;
+}
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_sh2000 __initmv = {
+ mv_name: "sh2000",
+
+ mv_nr_irqs: 80,
+
+ mv_inb: generic_inb,
+ mv_inw: generic_inw,
+ mv_inl: generic_inl,
+ mv_outb: generic_outb,
+ mv_outw: generic_outw,
+ mv_outl: generic_outl,
+
+ mv_inb_p: generic_inb_p,
+ mv_inw_p: generic_inw_p,
+ mv_inl_p: generic_inl_p,
+ mv_outb_p: generic_outb_p,
+ mv_outw_p: generic_outw_p,
+ mv_outl_p: generic_outl_p,
+
+ mv_insb: generic_insb,
+ mv_insw: generic_insw,
+ mv_insl: generic_insl,
+ mv_outsb: generic_outsb,
+ mv_outsw: generic_outsw,
+ mv_outsl: generic_outsl,
+
+ mv_readb: generic_readb,
+ mv_readw: generic_readw,
+ mv_readl: generic_readl,
+ mv_writeb: generic_writeb,
+ mv_writew: generic_writew,
+ mv_writel: generic_writel,
+
+ mv_init_arch: setup_sh2000,
+
+ mv_isa_port2addr: sh2000_isa_port2addr,
+
+ mv_ioremap: generic_ioremap,
+ mv_iounmap: generic_iounmap,
+
+ mv_rtc_gettimeofday: sh_rtc_gettimeofday,
+ mv_rtc_settimeofday: sh_rtc_settimeofday,
+
+ mv_hw_sh2000: 1,
+};
+ALIAS_MV(sh2000)
#include <asm/hardirq.h>
#include <asm/delay.h>
#include <asm/pgalloc.h>
+#include <asm/pci.h>
#include <linux/irq.h>
extern void dump_thread(struct pt_regs *, struct user *);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strncat);
+/* PCI exports */
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pcibios_penalize_isa_irq);
+#endif
+
/* mem exports */
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memcpy_toio);
EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memset_io);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(get_vm_area);
+/* semaphore exports */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__const_udelay);
+
#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL_NOVERS(name)
/* These symbols are generated by the compiler itself */
DECLARE_EXPORT(__udivsi3);
DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__ashrdi3);
+DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstr);
#ifdef __SH4__
DECLARE_EXPORT(__movstr_i4_even);
DECLARE_EXPORT(__movstr_i4_odd);
-DECLARE_EXPORT(__ashrdi3);
-DECLARE_EXPORT(__ashldi3);
/* needed by some modules */
+EXPORT_SYMBOL(flush_cache_all);
+EXPORT_SYMBOL(flush_cache_range);
EXPORT_SYMBOL(flush_dcache_page);
#endif
EXPORT_SYMBOL(flush_tlb_page);
#define CCN_PVR_CHIP_MASK 0xff
#define CCN_PVR_CHIP_ST40STB1 0x4
-#endif
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+#define CLOCKGEN_MEMCLKCR 0xbb040038
+#define MEMCLKCR_RATIO_MASK 0x7
+#endif /* CONFIG_CPU_SUBTYPE_ST40STB1 */
+#endif /* __sh3__ or __SH4__ */
extern rwlock_t xtime_lock;
extern unsigned long wall_jiffies;
void __init time_init(void)
{
unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+ unsigned int memory_clock;
+#endif
unsigned int timer_freq;
unsigned short frqcr, ifc, pfc, bfc;
unsigned long interval;
{ 0x123, {{1,4}, {1,4}, {1,8}}},
{ 0x16C, {{1,4}, {1,8}, {1,8}}},
};
+
+ struct memclk_data {
+ unsigned char multiplier;
+ unsigned char divisor;
+ };
+ static struct memclk_data st40_memclk_table[8] = {
+ {1,1}, // 000
+ {1,2}, // 001
+ {1,3}, // 010
+ {2,3}, // 011
+ {1,4}, // 100
+ {1,6}, // 101
+ {1,8}, // 110
+ {1,8} // 111
+ };
#endif
#endif
-#if defined(CONFIG_SH_DREAMCAST)
- xtime.tv_sec = 0;
- xtime.tv_usec = 0;
-#else
- rtc_gettimeofday(&xtime);
-#endif
+ if (MACH_DREAMCAST)
+ xtime.tv_sec = xtime.tv_usec = 0;
+ else
+ rtc_gettimeofday(&xtime);
setup_irq(TIMER_IRQ, &irq0);
-#if defined(CONFIG_SH_DREAMCAST)
- timer_freq = 50*1000*1000/4;
-#else
- timer_freq = get_timer_frequency();
-#endif
+ if (MACH_DREAMCAST)
+ timer_freq = 50*1000*1000/4;
+ else
+ timer_freq = get_timer_frequency();
module_clock = timer_freq * 4;
/* Unfortunatly the STB1 FRQCR values are different from the 7750 ones */
struct frqcr_data *d;
int a;
+ unsigned long memclkcr;
+ struct memclk_data *e;
for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) {
d = &st40_frqcr_table[a];
printk("ERROR: Unrecognised FRQCR value, using default multipliers\n");
}
- printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Periph: %d/%d\n",
+ memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR);
+ e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK];
+
+ printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n",
d->factor[0].multiplier, d->factor[0].divisor,
d->factor[1].multiplier, d->factor[1].divisor,
+ e->multiplier, e->divisor,
d->factor[2].multiplier, d->factor[2].divisor);
master_clock = module_clock * d->factor[2].divisor / d->factor[2].multiplier;
bus_clock = master_clock * d->factor[1].multiplier / d->factor[1].divisor;
+ memory_clock = master_clock * e->multiplier / e->divisor;
cpu_clock = master_clock * d->factor[0].multiplier / d->factor[0].divisor;
goto skip_calc;
} else
master_clock = module_clock * pfc;
bus_clock = master_clock / bfc;
cpu_clock = master_clock / ifc;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
skip_calc:
+#endif
printk("CPU clock: %d.%02dMHz\n",
(cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
printk("Bus clock: %d.%02dMHz\n",
(bus_clock/1000000), (bus_clock % 1000000)/10000);
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+ printk("Memory clock: %d.%02dMHz\n",
+ (memory_clock/1000000), (memory_clock % 1000000)/10000);
+#endif
printk("Module clock: %d.%02dMHz\n",
(module_clock/1000000), (module_clock % 1000000)/10000);
interval = (module_clock/4 + HZ/2) / HZ;
current_cpu_data.cpu_clock = cpu_clock;
current_cpu_data.master_clock = master_clock;
current_cpu_data.bus_clock = bus_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+ current_cpu_data.memory_clock = memory_clock;
+#endif
current_cpu_data.module_clock = module_clock;
/* Start TMU0 */
#elif defined(__SH4__)
#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
cpu_data->type = CPU_ST40STB1;
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751)
cpu_data->type = CPU_SH7750;
#else
#error Unknown SH4 CPU type
{
unsigned long flags;
unsigned long pteval;
- unsigned long pteaddr;
+ unsigned long vpn;
+#if defined(__SH4__)
unsigned long ptea;
+#endif
save_and_cli(flags);
-
#if defined(__SH4__)
if (pte_shared(pte)) {
struct page *pg;
}
/* Set PTEH register */
- pteaddr = (address & MMU_VPN_MASK) | get_asid();
- ctrl_outl(pteaddr, MMU_PTEH);
+ vpn = (address & MMU_VPN_MASK) | get_asid();
+ ctrl_outl(vpn, MMU_PTEH);
- /* Set PTEA register */
- /* TODO: make this look less hacky */
pteval = pte_val(pte);
#if defined(__SH4__)
+ /* Set PTEA register */
+ /* TODO: make this look less hacky */
ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1);
ctrl_outl(ptea, MMU_PTEA);
#endif
data = (page & 0xfffe0000) | asid; /* VALID bit is off */
ctrl_outl(data, addr);
#elif defined(__SH4__)
- jump_to_P2();
addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
data = page | asid; /* VALID bit is off */
+ jump_to_P2();
ctrl_outl(data, addr);
back_to_P1();
#endif
#if defined(__SH4__)
static void __flush_tlb_phys(unsigned long phys)
{
- int i;
- unsigned long addr, data;
+ unsigned long addr, data, pte;
- jump_to_P2();
- for (i = 0; i < MMU_UTLB_ENTRIES; i++) {
- addr = MMU_UTLB_DATA_ARRAY | (i<<MMU_U_ENTRY_SHIFT);
+ pte = phys | MMU_UTLB_VALID;
+ for (addr = MMU_UTLB_DATA_ARRAY;
+ addr < MMU_UTLB_DATA_ARRAY+(MMU_UTLB_ENTRIES<<MMU_U_ENTRY_SHIFT);
+ addr += (1<<MMU_U_ENTRY_SHIFT)) {
data = ctrl_inl(addr);
- if ((data & MMU_UTLB_VALID) && (data&PAGE_MASK) == phys) {
+ if ((data & (MMU_UTLB_VALID|PAGE_MASK)) == pte) {
data &= ~MMU_UTLB_VALID;
+ jump_to_P2();
ctrl_outl(data, addr);
+ back_to_P1();
+ break;
}
}
- for (i = 0; i < MMU_ITLB_ENTRIES; i++) {
- addr = MMU_ITLB_DATA_ARRAY | (i<<MMU_I_ENTRY_SHIFT);
+ pte = phys | MMU_ITLB_VALID;
+ for (addr = MMU_ITLB_DATA_ARRAY;
+ addr < MMU_ITLB_DATA_ARRAY+(MMU_ITLB_ENTRIES<<MMU_I_ENTRY_SHIFT);
+ addr += (1<<MMU_I_ENTRY_SHIFT)) {
data = ctrl_inl(addr);
- if ((data & MMU_ITLB_VALID) && (data&PAGE_MASK) == phys) {
+ if ((data & (MMU_ITLB_VALID|PAGE_MASK)) == pte) {
data &= ~MMU_ITLB_VALID;
+ jump_to_P2();
ctrl_outl(data, addr);
+ back_to_P1();
+ break;
}
}
- back_to_P1();
}
#endif
extern char _text, _etext, _edata, __bss_start, _end;
extern char __init_begin, __init_end;
-pgd_t swapper_pg_dir[1024];
+pgd_t swapper_pg_dir[PTRS_PER_PGD];
/* It'd be good if these lines were in the standard header file. */
#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
/* We don't need kernel mapping as hardware support that. */
pg_dir = swapper_pg_dir;
- for (i=0; i < USER_PTRS_PER_PGD*2; i++)
+ for (i=0; i < PTRS_PER_PGD; i++)
pgd_val(pg_dir[i]) = 0;
/* Enable MMU */
--- /dev/null
+#
+# Makefile for STMicroelectronics board specific parts of the kernel
+#
+# 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).
+#
+
+all: stboards.o
+O_TARGET := stboards.o
+obj-y := irq.o setup.o mach.o led.o
+
+clean:
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Defintions applicable to the STMicroelectronics ST40STB1 HARP and
+ * compatible boards.
+ */
+
+#if defined(CONFIG_SH_STB1_HARP)
+
+#define EPLD_BASE 0xa0800000
+
+#define EPLD_LED (EPLD_BASE+0x000c0000)
+#define EPLD_INTSTAT0 (EPLD_BASE+0x00200000)
+#define EPLD_INTSTAT1 (EPLD_BASE+0x00240000)
+#define EPLD_INTMASK0 (EPLD_BASE+0x00280000)
+#define EPLD_INTMASK1 (EPLD_BASE+0x002c0000)
+#define EPLD_PAGEADDR (EPLD_BASE+0x00300000)
+#define EPLD_REVID1 (EPLD_BASE+0x00380000)
+#define EPLD_REVID2 (EPLD_BASE+0x003c0000)
+
+#define EPLD_LED_ON 1
+#define EPLD_LED_OFF 0
+
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+
+#define EPLD_BASE 0xa7000000
+
+#define EPLD_REVID (EPLD_BASE+0x00000000)
+#define EPLD_LED (EPLD_BASE+0x00040000)
+#define EPLD_INTMASK0 (EPLD_BASE+0x001c0000)
+#define EPLD_INTMASK1 (EPLD_BASE+0x00200000)
+#define EPLD_INTSTAT0 (EPLD_BASE+0x00240000)
+#define EPLD_INTSTAT1 (EPLD_BASE+0x00280000)
+
+#define EPLD_LED_ON 0
+#define EPLD_LED_OFF 1
+
+#else
+#error Unknown board
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Looks after interrupts on the HARP board.
+ *
+ * Bases on the IPR irq system
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "harp.h"
+
+
+#define NUM_EXTERNAL_IRQS 16
+
+// Early versions of the STB1 Overdrive required this nasty frig
+//#define INVERT_INTMASK_WRITES
+
+static void enable_harp_irq(unsigned int irq);
+static void disable_harp_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_harp_irq disable_harp_irq
+
+static void mask_and_ack_harp(unsigned int);
+static void end_harp_irq(unsigned int irq);
+
+static unsigned int startup_harp_irq(unsigned int irq)
+{
+ enable_harp_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type harp_irq_type = {
+ "Harp-IRQ",
+ startup_harp_irq,
+ shutdown_harp_irq,
+ enable_harp_irq,
+ disable_harp_irq,
+ mask_and_ack_harp,
+ end_harp_irq
+};
+
+static void disable_harp_irq(unsigned int irq)
+{
+ unsigned val, flags;
+ unsigned maskReg;
+ unsigned mask;
+ int pri;
+
+ if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+ return;
+
+ pri = 15 - irq;
+
+ if (pri < 8) {
+ maskReg = EPLD_INTMASK0;
+ } else {
+ maskReg = EPLD_INTMASK1;
+ pri -= 8;
+ }
+
+ save_and_cli(flags);
+ mask = ctrl_inl(maskReg);
+ mask &= (~(1 << pri));
+#if defined(INVERT_INTMASK_WRITES)
+ mask ^= 0xff;
+#endif
+ ctrl_outl(mask, maskReg);
+ restore_flags(flags);
+}
+
+static void enable_harp_irq(unsigned int irq)
+{
+ unsigned flags;
+ unsigned maskReg;
+ unsigned mask;
+ int pri;
+
+ if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+ return;
+
+ pri = 15 - irq;
+
+ if (pri < 8) {
+ maskReg = EPLD_INTMASK0;
+ } else {
+ maskReg = EPLD_INTMASK1;
+ pri -= 8;
+ }
+
+ save_and_cli(flags);
+ mask = ctrl_inl(maskReg);
+
+
+ mask |= (1 << pri);
+
+#if defined(INVERT_INTMASK_WRITES)
+ mask ^= 0xff;
+#endif
+ ctrl_outl(mask, maskReg);
+
+ restore_flags(flags);
+}
+
+/* This functions sets the desired irq handler to be an overdrive type */
+static void __init make_harp_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &harp_irq_type;
+ disable_harp_irq(irq);
+}
+
+static void mask_and_ack_harp(unsigned int irq)
+{
+ disable_harp_irq(irq);
+}
+
+static void end_harp_irq(unsigned int irq)
+{
+ enable_harp_irq(irq);
+}
+
+void __init init_harp_irq(void)
+{
+ int i;
+
+#if !defined(INVERT_INTMASK_WRITES)
+ // On the harp these are set to enable an interrupt
+ ctrl_outl(0x00, EPLD_INTMASK0);
+ ctrl_outl(0x00, EPLD_INTMASK1);
+#else
+ // On the Overdrive the data is inverted before being stored in the reg
+ ctrl_outl(0xff, EPLD_INTMASK0);
+ ctrl_outl(0xff, EPLD_INTMASK1);
+#endif
+
+ for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
+ make_harp_irq(i);
+ }
+}
--- /dev/null
+/*
+ * linux/arch/sh/stboards/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains ST40STB1 HARP and compatible code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include "harp.h"
+
+/* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */
+/* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */
+/* Works for HARP and overdrive */
+static void mach_led(int position, int value)
+{
+ if (value) {
+ ctrl_outl(EPLD_LED_ON, EPLD_LED);
+ } else {
+ ctrl_outl(EPLD_LED_OFF, EPLD_LED);
+ }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* acts like an actual heart beat -- ie thump-thump-pause... */
+void heartbeat_harp(void)
+{
+ static unsigned cnt = 0, period = 0, dist = 0;
+
+ if (cnt == 0 || cnt == dist)
+ mach_led( -1, 1);
+ else if (cnt == 7 || cnt == dist+7)
+ mach_led( -1, 0);
+
+ if (++cnt > period) {
+ cnt = 0;
+ /* The hyperbolic function below modifies the heartbeat period
+ * length in dependency of the current (5min) load. It goes
+ * through the points f(0)=126, f(1)=86, f(5)=51,
+ * f(inf)->30. */
+ period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+ dist = period / 4;
+ }
+}
+#endif
--- /dev/null
+/*
+ * linux/arch/sh/stboards/mach.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the STMicroelectronics STB1 HARP and compatible boards
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+#include <asm/io_hd64465.h>
+#include <asm/hd64465.h>
+
+void setup_harp(void);
+void init_harp_irq(void);
+void heartbeat_harp(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_harp __initmv = {
+ mv_name: "STB1 Harp",
+
+ mv_nr_irqs: 89 + HD64465_IRQ_NUM,
+
+ mv_inb: hd64465_inb,
+ mv_inw: hd64465_inw,
+ mv_inl: hd64465_inl,
+ mv_outb: hd64465_outb,
+ mv_outw: hd64465_outw,
+ mv_outl: hd64465_outl,
+
+ mv_inb_p: hd64465_inb_p,
+ mv_inw_p: hd64465_inw,
+ mv_inl_p: hd64465_inl,
+ mv_outb_p: hd64465_outb_p,
+ mv_outw_p: hd64465_outw,
+ mv_outl_p: hd64465_outl,
+
+ mv_insb: hd64465_insb,
+ mv_insw: hd64465_insw,
+ mv_insl: hd64465_insl,
+ mv_outsb: hd64465_outsb,
+ mv_outsw: hd64465_outsw,
+ mv_outsl: hd64465_outsl,
+
+ mv_readb: generic_readb,
+ mv_readw: generic_readw,
+ mv_readl: generic_readl,
+ mv_writeb: generic_writeb,
+ mv_writew: generic_writew,
+ mv_writel: generic_writel,
+
+ mv_ioremap: generic_ioremap,
+ mv_iounmap: generic_iounmap,
+
+ mv_isa_port2addr: hd64465_isa_port2addr,
+
+ mv_init_arch: setup_harp,
+#ifdef CONFIG_PCI
+ mv_init_irq: init_harp_irq,
+#endif
+#ifdef CONFIG_HEARTBEAT
+ mv_heartbeat: heartbeat_harp,
+#endif
+ mv_rtc_gettimeofday: sh_rtc_gettimeofday,
+ mv_rtc_settimeofday: sh_rtc_settimeofday,
+};
+
+ALIAS_MV(harp)
--- /dev/null
+/*
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t * dma_handle)
+{
+ void *ret;
+ int gfp = GFP_ATOMIC;
+
+ ret = (void *) __get_free_pages(gfp, get_order(size));
+
+ if (ret != NULL) {
+ /* Is it neccessary to do the memset? */
+ memset(ret, 0, size);
+ *dma_handle = virt_to_bus(ret);
+ }
+ /* We must flush the cache before we pass it on to the device */
+ flush_cache_all();
+ return P2SEGADDR(ret);
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
+
+ free_pages(p1addr, get_order(size));
+}
--- /dev/null
+/*
+ * arch/sh/stboard/setup.c
+ *
+ * Copyright (C) 2001 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * STMicroelectronics ST40STB1 HARP and compatible support.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include "harp.h"
+/*
+ * Initialize the board
+ */
+int __init setup_harp(void)
+{
+#ifdef CONFIG_SH_STB1_HARP
+ unsigned long ic8_version, ic36_version;
+
+ ic8_version = ctrl_inl(EPLD_REVID2);
+ ic36_version = ctrl_inl(EPLD_REVID1);
+
+ printk("STMicroelectronics STB1 HARP initialisaton\n");
+ printk("EPLD versions: IC8: %d.%02d, IC36: %d.%02d\n",
+ (ic8_version >> 4) & 0xf, ic8_version & 0xf,
+ (ic36_version >> 4) & 0xf, ic36_version & 0xf);
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+ unsigned long version;
+
+ version = ctrl_inl(EPLD_REVID);
+
+ printk("STMicroelectronics STB1 Overdrive initialisaton\n");
+ printk("EPLD version: %d.%02d\n",
+ (version >> 4) & 0xf, version & 0xf);
+#else
+#error Undefined machine
+#endif
+
+ /* Currently all STB1 chips have problems with the sleep instruction,
+ * so disable it here.
+ */
+ disable_hlt();
+
+ return 0;
+}
-# $Id: config.in,v 1.144 2001/06/01 08:12:10 davem Exp $
+# $Id: config.in,v 1.146 2001/06/16 04:15:26 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
define_bool CONFIG_ISA n
+define_bool CONFIG_ISAPNP n
define_bool CONFIG_EISA n
define_bool CONFIG_MCA n
define_bool CONFIG_PCMCIA n
bool 'Network device support' CONFIG_NETDEVICES
if [ "$CONFIG_NETDEVICES" = "y" ]; then
- tristate ' Dummy net driver support' CONFIG_DUMMY
- tristate ' Bonding driver support' CONFIG_BONDING
- tristate ' Universal TUN/TAP device driver support' CONFIG_TUN
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_NETLINK" = "y" ]; then
- tristate ' Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
- fi
- fi
- tristate ' PPP (point-to-point) support' CONFIG_PPP
- if [ ! "$CONFIG_PPP" = "n" ]; then
- dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
- dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
- dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
- dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
- fi
- fi
- tristate ' SLIP (serial line) support' CONFIG_SLIP
- if [ "$CONFIG_SLIP" != "n" ]; then
- bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
- bool ' Keepalive and linefill' CONFIG_SLIP_SMART
- bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
- fi
-
- mainmenu_option next_comment
- comment 'Ethernet (10 or 100Mbit)'
-
- tristate 'Sun LANCE support' CONFIG_SUNLANCE
- tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC
- fi
- tristate ' Sun QuadEthernet support' CONFIG_SUNQE
- if [ "$CONFIG_PCI" = "y" ]; then
- tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
- tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
- tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
- tristate 'RealTek RTL-8139 support' CONFIG_8139TOO
- tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
- tristate 'VIA Rhine support' CONFIG_VIA_RHINE
- tristate 'EtherExpressPro/100 support' CONFIG_EEPRO100
- tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
- fi
- endmenu
-
- mainmenu_option next_comment
- comment 'Ethernet (1000 Mbit)'
-
- if [ "$CONFIG_PCI" = "y" ]; then
- tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
- if [ "$CONFIG_ACENIC" != "n" ]; then
- bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
- fi
- tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN
- tristate 'Sun GEM support' CONFIG_SUNGEM
- fi
- tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
- endmenu
-
- bool 'FDDI driver support' CONFIG_FDDI
- if [ "$CONFIG_FDDI" = "y" ]; then
- tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP
- fi
-
+ source drivers/net/Config.in
if [ "$CONFIG_ATM" = "y" ]; then
source drivers/atm/Config.in
fi
comment 'XFree86 DRI support'
bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
dep_tristate ' Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM
+dep_tristate ' 3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX $CONFIG_DRM
+dep_tristate ' ATI Rage 128' CONFIG_DRM_R128 $CONFIG_DRM
+if [ "$CONFIG_DRM_R128" != "n" ]; then
+ define_bool CONFIG_AGP y
+fi
endmenu
source drivers/input/Config.in
# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ISA is not set
+# CONFIG_ISAPNP is not set
# CONFIG_EISA is not set
# CONFIG_MCA is not set
# CONFIG_PCMCIA is not set
# Network device support
#
CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_APPLETALK is not set
CONFIG_DUMMY=m
CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
CONFIG_TUN=m
-CONFIG_PPP=m
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# CONFIG_PPP_BSDCOMP is not set
-CONFIG_PPPOE=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-# CONFIG_SLIP_MODE_SLIP6 is not set
#
# Ethernet (10 or 100Mbit)
#
+CONFIG_NET_ETHERNET=y
CONFIG_SUNLANCE=y
CONFIG_HAPPYMEAL=y
CONFIG_SUNBMAC=m
CONFIG_SUNQE=m
-CONFIG_DE4X5=m
-CONFIG_TULIP=m
+CONFIG_SUNLANCE=y
+CONFIG_SUNGEM=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_ELMC is not set
+# CONFIG_ELMC_II is not set
CONFIG_VORTEX=m
-CONFIG_8139TOO=m
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+CONFIG_DE4X5=m
+CONFIG_DGRS=m
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=m
+# CONFIG_LNE390 is not set
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
CONFIG_NE2K_PCI=m
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+CONFIG_EPIC100=m
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
CONFIG_VIA_RHINE=m
-CONFIG_EEPRO100=m
-CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_WINBOND_840=m
+# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
#
CONFIG_ACENIC=m
# CONFIG_ACENIC_OMIT_TIGON_I is not set
-CONFIG_SK98LIN=m
-CONFIG_SUNGEM=y
CONFIG_MYRI_SBUS=m
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_SK98LIN=m
CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
CONFIG_SKFP=m
+CONFIG_HIPPI=y
+# CONFIG_ROADRUNNER is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
#
# Unix 98 PTY support
#
CONFIG_DRM=y
CONFIG_DRM_FFB=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_AGP=y
#
# Input core support
kbd_state, keyval);
#endif
mdelay(1);
- inb(IOC_KARTRX);
+ ioc_readb(IOC_KARTRX);
a5kkbd_sendbyte (HRST);
kbd_state = KBD_INITRST;
return 0;
static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs)
{
kbd_pt_regs = regs;
- if (handle_rawcode(inb(IOC_KARTRX)))
+ if (handle_rawcode(ioc_readb(IOC_KARTRX)))
tasklet_schedule(&keyboard_tasklet);
}
static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs)
{
- outb (kbd_txval[kbd_txtail], IOC_KARTTX);
+ ioc_writeb (kbd_txval[kbd_txtail], IOC_KARTTX);
KBD_INCTXPTR(kbd_txtail);
if (kbd_txtail == kbd_txhead)
disable_irq(irq);
if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0)
panic("Could not allocate keyboard transmit IRQ!");
- (void)inb(IOC_KARTRX);
+ (void)ioc_readb(IOC_KARTRX);
if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0)
panic("Could not allocate keyboard receive IRQ!");
#include <linux/random.h>
#include <linux/ctype.h>
#include <linux/kbd_ll.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include <asm/bitops.h>
extern void kbd_reset_kdown(void);
int kbd_read_mask;
+#define TX_DONE 0
+#define TX_SENT 1
+#define TX_SEND 2
+
+static volatile int tx_state;
+
#define VERSION 100
#define KBD_REPORT_ERR
static inline void ps2kbd_sendbyte(unsigned char val)
{
- while(!(inb(IOMD_KCTRL) & (1 << 7)));
- outb(val, IOMD_KARTTX);
+ int tries = 3, timeout = 1000;
+
+ tx_state = TX_SEND;
+
+ do {
+ switch (tx_state) {
+ case TX_SEND:
+ tx_state = TX_SENT;
+ timeout = 1000;
+ tries --;
+
+ while(!(iomd_readb(IOMD_KCTRL) & (1 << 7)));
+ iomd_writeb(val, IOMD_KARTTX);
+ break;
+
+ case TX_SENT:
+ udelay(1000);
+ if (--timeout == 0) {
+ printk(KERN_ERR "Keyboard timeout\n");
+ tx_state = TX_DONE;
+ }
+ break;
+
+ case TX_DONE:
+ break;
+ }
+ } while (tries > 0 && tx_state != TX_DONE);
}
static unsigned char status;
if (keyval > 0x83) {
switch (keyval) {
- case KBD_ESCAPEE0:
- ncodes = 2;
- bi = 0;
- break;
- case KBD_ESCAPEE1:
- ncodes = 3;
- bi = 0;
- break;
- case KBD_BREAK:
- status |= CODE_BREAK;
- default:
- return;
+ case KBD_ESCAPEE0:
+ ncodes = 2;
+ bi = 0;
+ break;
+
+ case KBD_ESCAPEE1:
+ ncodes = 3;
+ bi = 0;
+ break;
+
+ case KBD_ACK:
+ tx_state = TX_DONE;
+ return;
+
+ case KBD_RESEND:
+ tx_state = TX_SEND;
+ return;
+
+ case KBD_BREAK:
+ status |= CODE_BREAK;
+ return;
+
+ default:
+ return;
}
}
switch (buffer[0] << 8 | buffer[1]) {
case ESCE0(0x11): keysym = K_RALT; break;
case ESCE0(0x14): keysym = K_RCTL; break;
+ /*
+ * take care of MS extra keys (actually
+ * 0x7d - 0x7f, but last one is already K_NONE
+ */
+ case ESCE0(0x1f): keysym = 124; break;
+ case ESCE0(0x27): keysym = 125; break;
+ case ESCE0(0x2f): keysym = 126; break;
case ESCE0(0x4a): keysym = KP_SLH; break;
case ESCE0(0x5a): keysym = KP_ENT; break;
case ESCE0(0x69): keysym = K_END; break;
{
kbd_pt_regs = regs;
- while (inb(IOMD_KCTRL) & (1 << 5))
- handle_rawcode(inb(IOMD_KARTRX));
+ while (iomd_readb(IOMD_KCTRL) & (1 << 5))
+ handle_rawcode(iomd_readb(IOMD_KARTRX));
tasklet_schedule(&keyboard_tasklet);
}
int __init ps2kbd_init_hw(void)
{
/* Reset the keyboard state machine. */
- outb(0, IOMD_KCTRL);
- outb(8, IOMD_KCTRL);
+ iomd_writeb(0, IOMD_KCTRL);
+ iomd_writeb(8, IOMD_KCTRL);
+ iomd_readb(IOMD_KARTRX);
- (void)IOMD_KARTRX;
if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0)
panic("Could not allocate keyboard receive IRQ!");
if (request_irq (IRQ_KEYBOARDTX, ps2kbd_tx, 0, "keyboard", NULL) != 0)
--- /dev/null
+/*
+ * Driver for PS/2 mouse on IOMD interface
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/random.h>
+#include <linux/ctype.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/hardware/iomd.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/*
+ * PS/2 Auxiliary Device
+ */
+
+static struct aux_queue *queue; /* Mouse data buffer. */
+static int aux_count = 0;
+/* used when we send commands to the mouse that expect an ACK. */
+static unsigned char mouse_reply_expected = 0;
+
+#define MAX_RETRIES 60 /* some aux operations take long time*/
+
+/*
+ * Mouse Commands
+ */
+
+#define AUX_SET_RES 0xE8 /* Set resolution */
+#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
+#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
+#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
+#define AUX_SET_STREAM 0xEA /* Set stream mode */
+#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
+#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
+#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
+#define AUX_RESET 0xFF /* Reset aux device */
+#define AUX_ACK 0xFA /* Command byte ACK. */
+
+#define AUX_BUF_SIZE 2048 /* This might be better divisible by
+ three to make overruns stay in sync
+ but then the read function would
+ need a lock etc - ick */
+
+struct aux_queue {
+ unsigned long head;
+ unsigned long tail;
+ wait_queue_head_t proc_list;
+ struct fasync_struct *fasync;
+ unsigned char buf[AUX_BUF_SIZE];
+};
+
+/*
+ * Send a byte to the mouse.
+ */
+static void aux_write_dev(int val)
+{
+ while (!(iomd_readb(IOMD_MSECTL) & 0x80));
+ iomd_writeb(val, IOMD_MSEDAT);
+}
+
+/*
+ * Send a byte to the mouse & handle returned ack
+ */
+static void aux_write_ack(int val)
+{
+ while (!(iomd_readb(IOMD_MSECTL) & 0x80));
+ iomd_writeb(val, IOMD_MSEDAT);
+
+ /* we expect an ACK in response. */
+ mouse_reply_expected++;
+}
+
+static unsigned char get_from_queue(void)
+{
+ unsigned char result;
+
+ result = queue->buf[queue->tail];
+ queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+ return result;
+}
+
+static void psaux_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int val = iomd_readb(IOMD_MSEDAT);
+
+ if (mouse_reply_expected) {
+ if (val == AUX_ACK) {
+ mouse_reply_expected--;
+ return;
+ }
+ mouse_reply_expected = 0;
+ }
+
+ add_mouse_randomness(val);
+ if (aux_count) {
+ int head = queue->head;
+
+ queue->buf[head] = val;
+ head = (head + 1) & (AUX_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->head = head;
+ kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+ wake_up_interruptible(&queue->proc_list);
+ }
+ }
+}
+
+static inline int queue_empty(void)
+{
+ return queue->head == queue->tail;
+}
+
+static int fasync_aux(int fd, struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper(fd, filp, on, &queue->fasync);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+
+/*
+ * Random magic cookie for the aux device
+ */
+#define AUX_DEV ((void *)queue)
+
+static int release_aux(struct inode * inode, struct file * file)
+{
+ fasync_aux(-1, file, 0);
+ if (--aux_count)
+ return 0;
+ free_irq(IRQ_MOUSERX, AUX_DEV);
+ return 0;
+}
+
+/*
+ * Install interrupt handler.
+ * Enable auxiliary device.
+ */
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+ if (aux_count++)
+ return 0;
+
+ queue->head = queue->tail = 0; /* Flush input queue */
+ if (request_irq(IRQ_MOUSERX, psaux_interrupt, SA_SHIRQ, "ps/2 mouse",
+ AUX_DEV)) {
+ aux_count--;
+ return -EBUSY;
+ }
+
+ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
+
+ return 0;
+}
+
+/*
+ * Put bytes from input queue to buffer.
+ */
+
+static ssize_t read_aux(struct file * file, char * buffer,
+ size_t count, loff_t *ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t i = count;
+ unsigned char c;
+
+ if (queue_empty()) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ add_wait_queue(&queue->proc_list, &wait);
+repeat:
+ current->state = TASK_INTERRUPTIBLE;
+ if (queue_empty() && !signal_pending(current)) {
+ schedule();
+ goto repeat;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&queue->proc_list, &wait);
+ }
+ while (i > 0 && !queue_empty()) {
+ c = get_from_queue();
+ put_user(c, buffer++);
+ i--;
+ }
+ if (count-i) {
+ file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+ return count-i;
+ }
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+/*
+ * Write to the aux device.
+ */
+
+static ssize_t write_aux(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t retval = 0;
+
+ if (count) {
+ ssize_t written = 0;
+
+ if (count > 32)
+ count = 32; /* Limit to 32 bytes. */
+ do {
+ char c;
+ get_user(c, buffer++);
+ aux_write_dev(c);
+ written++;
+ } while (--count);
+ retval = -EIO;
+ if (written) {
+ retval = written;
+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+ }
+ }
+
+ return retval;
+}
+
+static unsigned int aux_poll(struct file *file, poll_table * wait)
+{
+ poll_wait(file, &queue->proc_list, wait);
+ if (!queue_empty())
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+struct file_operations psaux_fops = {
+ read: read_aux,
+ write: write_aux,
+ poll: aux_poll,
+ open: open_aux,
+ release: release_aux,
+ fasync: fasync_aux,
+};
+
+/*
+ * Initialize driver.
+ */
+static struct miscdevice psaux_mouse = {
+ PSMOUSE_MINOR, "psaux", &psaux_fops
+};
+
+int __init psaux_init(void)
+{
+ /* Reset the mouse state machine. */
+ iomd_writeb(0, IOMD_MSECTL);
+ iomd_writeb(8, IOMD_MSECTL);
+
+ misc_register(&psaux_mouse);
+ queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+ memset(queue, 0, sizeof(*queue));
+ queue->head = queue->tail = 0;
+ init_waitqueue_head(&queue->proc_list);
+
+ aux_write_ack(AUX_SET_SAMPLE);
+ aux_write_ack(100); /* 100 samples/sec */
+ aux_write_ack(AUX_SET_RES);
+ aux_write_ack(3); /* 8 counts per mm */
+ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
+
+ return 0;
+}
short x, y, dx, dy;
int buttons;
- x = (short)inl(IOMD_MOUSEX);
- y = (short)inl(IOMD_MOUSEY);
- buttons = (inl (0x800C4000) >> 4) & 7;
+ x = (short)iomd_readl(IOMD_MOUSEX);
+ y = (short)iomd_readl(IOMD_MOUSEY);
+ buttons = (__raw_readl(0xe0310000) >> 4) & 7;
dx = x - old_x;
old_x = x;
if (mousedev < 0)
printk("rpcmouse: could not register mouse driver\n");
else {
- old_x = (short)inl(IOMD_MOUSEX);
- old_y = (short)inl(IOMD_MOUSEY);
- old_b = (inl (0x800C4000) >> 4) & 7;
+ old_x = (short)iomd_readl(IOMD_MOUSEX);
+ old_y = (short)iomd_readl(IOMD_MOUSEY);
+ old_b = (__raw_readl(0xe0310000) >> 4) & 7;
if (request_irq(IRQ_VSYNCPULSE, mouse_rpc_irq, SA_SHIRQ, "mouse", &mousedev)) {
printk("rpcmouse: unable to allocate VSYNC interrupt\n");
unregister_busmouse(mousedev);
/* ------------------------------------------------------------------------- */
-static const char version[] __initdata = KERN_INFO "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
#define BUS_16 16
#define BUS_8 8
static unsigned int version_printed = 0;
if (net_debug && version_printed++ == 0)
- printk (version);
+ printk(KERN_INFO "%s", version);
}
static struct net_device * __init ether1_init_one(struct expansion_card *ec)
release:
release_region(dev->base_addr, 16);
release_region(dev->base_addr + 0x800, 4096);
-free:
unregister_netdev(dev);
kfree(dev);
out:
#include <asm/io.h>
#include <asm/irq.h>
-static const char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
+static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
#include "ether3.h"
static unsigned version_printed = 0;
if (net_debug && version_printed++ == 0)
- printk(version);
+ printk(KERN_INFO "%s", version);
}
static const char * __init
#include <linux/ioport.h>
#include <linux/blk.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/bitops.h>
#include <asm/system.h>
#include "acornscsi.h"
#include "msgqueue.h"
+#include <scsi/scsicam.h>
+
#define VER_MAJOR 2
#define VER_MINOR 0
#define VER_PATCH 6
static inline void
sbic_arm_write(unsigned int io_port, int reg, int value)
{
- outb_t(reg, io_port);
- outb_t(value, io_port + 4);
+ __raw_writeb(reg, io_port);
+ __raw_writeb(value, io_port + 4);
}
#define sbic_arm_writenext(io,val) \
- outb_t((val), (io) + 4)
+ __raw_writeb((val), (io) + 4)
static inline
int sbic_arm_read(unsigned int io_port, int reg)
{
if(reg == ASR)
- return inl_t(io_port) & 255;
- outb_t(reg, io_port);
- return inl_t(io_port + 4) & 255;
+ return __raw_readl(io_port) & 255;
+ __raw_writeb(reg, io_port);
+ return __raw_readl(io_port + 4) & 255;
}
#define sbic_arm_readnext(io) \
- inb_t((io) + 4)
+ __raw_readb((io) + 4)
#ifdef USE_DMAC
#define dmac_read(io_port,reg) \
* Params : host - host to setup
*/
static
-void acornscsi_init(AS_Host *host)
+void acornscsi_host_init(AS_Host *host)
{
memset(&host->stats, 0, sizeof (host->stats));
queue_initialise(&host->queues.issue);
host->scsi.irq = NO_IRQ;
}
- acornscsi_init(host);
+ acornscsi_host_init(host);
++count;
}
return pos;
}
-#ifdef MODULE
+static Scsi_Host_Template acornscsi_template = {
+ module: THIS_MODULE,
+ proc_info: acornscsi_proc_info,
+ name: "AcornSCSI",
+ detect: acornscsi_detect,
+ release: acornscsi_release,
+ info: acornscsi_info,
+ queuecommand: acornscsi_queuecmd,
+ abort: acornscsi_abort,
+ reset: acornscsi_reset,
+ bios_param: scsicam_bios_param,
+ can_queue: 16,
+ this_id: 7,
+ sg_tablesize: SG_ALL,
+ cmd_per_lun: 2,
+ unchecked_isa_dma: 0,
+ use_clustering: DISABLE_CLUSTERING
+};
-Scsi_Host_Template driver_template = ACORNSCSI_3;
+static int __init acornscsi_init(void)
+{
+ acornscsi_template.module = THIS_MODULE;
+ scsi_register_module(MODULE_SCSI_HA, &acornscsi_template);
+ if (acornscsi_template.present)
+ return 0;
-#include "../../scsi/scsi_module.c"
-#endif
+ scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template);
+ return -ENODEV;
+}
+
+static void __exit acornscsi_exit(void)
+{
+ scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template);
+}
+
+module_init(acornscsi_init);
+module_exit(acornscsi_exit);
#ifndef ACORNSCSI_H
#define ACORNSCSI_H
-#ifndef ASM
-extern int acornscsi_detect (Scsi_Host_Template *);
-extern int acornscsi_release (struct Scsi_Host *);
-extern const char *acornscsi_info (struct Scsi_Host *);
-extern int acornscsi_queuecmd (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int acornscsi_abort (Scsi_Cmnd *);
-extern int acornscsi_reset (Scsi_Cmnd *, unsigned int);
-extern int acornscsi_proc_info (char *, char **, off_t, int, int, int);
-extern int acornscsi_biosparam (Disk *, kdev_t, int []);
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 16
-#endif
-
-#include "linux/proc_fs.h"
-
-#include <scsi/scsicam.h>
-
-#define ACORNSCSI_3 { \
-proc_info: acornscsi_proc_info, \
-name: "AcornSCSI", \
-detect: acornscsi_detect, \
-release: acornscsi_release, /* Release */ \
-info: acornscsi_info, \
-queuecommand: acornscsi_queuecmd, \
-abort: acornscsi_abort, \
-reset: acornscsi_reset, \
-bios_param: scsicam_bios_param, \
-can_queue: CAN_QUEUE, /* can_queue */ \
-this_id: 7, /* this id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CMD_PER_LUN, /* cmd_per_lun */ \
-unchecked_isa_dma: 0, /* unchecked isa dma */ \
-use_clustering: DISABLE_CLUSTERING \
- }
-
-#ifndef HOSTS_C
-
/* SBIC registers */
#define OWNID 0
#define OWNID_FS1 (1<<7)
struct status_entry status[9][STATUS_BUFFER_SIZE];
} AS_Host;
-#endif /* ndef HOSTS_C */
-
-#endif /* ndef ASM */
#endif /* ACORNSCSI_H */
void
acpi_os_mem_out8 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT8 value)
{
- *(u8*) (u32) phys_addr = value;
+ *(u8*) phys_to_virt(phys_addr) = value;
}
void
acpi_os_mem_out16 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT16 value)
{
- *(u16*) (u32) phys_addr = value;
+ *(u16*) phys_to_virt(phys_addr) = value;
}
void
acpi_os_mem_out32 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT32 value)
{
- *(u32*) (u32) phys_addr = value;
+ *(u32*) phys_to_virt(phys_addr) = value;
}
ACPI_STATUS
while (timeout) {
// go to sleep
// PRINTD (DBG_CMD, "wait: sleeping %lu for command", timeout);
+ set_current_state(TASK_UNINTERRUPTIBLE);
timeout = schedule_timeout (timeout);
- // woken up by timeout or signal
}
// wait for my slot to be reached (all waiters are here or above, until...)
while (ptrs->out != my_slot) {
PRINTD (DBG_CMD, "wait: command slot (now at %p)", ptrs->out);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
}
// wait on my slot (... one gets to its slot, and... )
while (ptrs->out->request != cpu_to_be32 (SRB_COMPLETE)) {
PRINTD (DBG_CMD, "wait: command slot completion");
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
}
while (!lb->result || lb->result == cpu_to_be32 (COMMAND_IN_PROGRESS))
if (timeout) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
timeout = schedule_timeout (timeout);
} else {
PRINTD (DBG_LOAD|DBG_ERR, "command %d timed out", cmd);
unsigned long timeout;
// 4.2 second wait
timeout = HZ*42/10;
- while (timeout)
+ while (timeout) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
timeout = schedule_timeout (timeout);
+ }
// half second time-out
timeout = HZ/2;
while (!rd_plain (dev, offsetof(amb_mem, mb.loader.ready)))
if (timeout) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
timeout = schedule_timeout (timeout);
} else {
PRINTD (DBG_LOAD|DBG_ERR, "reset timed out");
u32 minor;
command cmd;
cmd.request = cpu_to_be32 (SRB_GET_VERSION);
- while (command_do (dev, &cmd))
+ while (command_do (dev, &cmd)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
+ }
major = be32_to_cpu (cmd.args.version.major);
minor = be32_to_cpu (cmd.args.version.minor);
PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor);
}
cmd.request = cpu_to_be32 (SRB_GET_BIA);
- while (command_do (dev, &cmd))
+ while (command_do (dev, &cmd)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
+ }
lower4 = be32_to_cpu (cmd.args.bia.lower4);
upper2 = be32_to_cpu (cmd.args.bia.upper2);
PRINTD (DBG_LOAD, "BIA: lower4: %08x, upper2 %04x", lower4, upper2);
struct pci_dev * pci_dev;
int devs;
- void do_pci_device (void) {
+ void __init do_pci_device (void) {
amb_dev * dev;
// read resources from PCI configuration space
if (!prom)
return -ENOMEM;
ok = fore200e->bus->prom_read(fore200e, prom);
- if (ok < 0)
+ if (ok < 0) {
+ fore200e_kfree(prom);
return -EBUSY;
+ }
printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n",
fore200e->name,
static int fetch_stats(struct atm_dev *dev,struct idt77105_stats *arg,int zero)
{
unsigned long flags;
- int error;
+ struct idt77105_stats stats;
- error = 0;
save_flags(flags);
cli();
- if (arg)
- error = copy_to_user(arg,&PRIV(dev)->stats,
- sizeof(struct idt77105_stats));
- if (zero && !error)
- memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
+ memcpy(&stats, &PRIV(dev)->stats, sizeof(struct idt77105_stats));
+ if (zero)
+ memset(&PRIV(dev)->stats, 0, sizeof(struct idt77105_stats));
restore_flags(flags);
- return error ? -EFAULT : sizeof(struct idt77105_stats);
+ if (arg == NULL)
+ return 0;
+ return copy_to_user(arg, &PRIV(dev)->stats,
+ sizeof(struct idt77105_stats)) ? -EFAULT : 0;
}
MODULE_PARM(IADebugFlag, "i");
#endif
+#if BITS_PER_LONG != 32
+# error FIXME: this driver only works on 32-bit platforms
+#endif
+
/**************************** IA_LIB **********************************/
static void ia_init_rtn_q (IARTN_Q *que)
#include "idt77105.h"
#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
+#if BITS_PER_LONG != 32
+# error FIXME: this driver requires a 32-bit platform
+#endif
/* Additional code ************************************************************/
static int get_sense(struct atm_dev *dev,u8 *arg)
{
unsigned long flags;
- int error;
+ unsigned char s[3];
save_flags(flags);
cli();
- error = put_user(GET(C11R),arg) || put_user(GET(C12R),arg+1) ||
- put_user(GET(C13R),arg+2);
+ s[0] = GET(C11R);
+ s[1] = GET(C12R);
+ s[2] = GET(C13R);
restore_flags(flags);
- error = error || put_user(0xff,arg+3) || put_user(0xff,arg+4) ||
- put_user(0xff,arg+5);
- return error ? -EFAULT : 0;
+ return (put_user(s[0], arg) || put_user(s[1], arg+1) ||
+ put_user(s[2], arg+2) || put_user(0xff, arg+3) ||
+ put_user(0xff, arg+4) || put_user(0xff, arg+5)) ? -EFAULT : 0;
}
static void drain_free(struct atm_dev *dev,int pool)
{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&ZATM_DEV(dev)->pool[pool]))) kfree_skb(skb);
+ skb_queue_purge(&ZATM_DEV(dev)->pool[pool]);
}
DPRINTK("zatm_start\n");
zatm_dev = ZATM_DEV(dev);
+ zatm_dev->rx_map = zatm_dev->tx_map = NULL;
+ for (i = 0; i < NR_MBX; i++)
+ zatm_dev->mbx_start[i] = 0;
if (request_irq(zatm_dev->irq,&zatm_int,SA_SHIRQ,DEV_LABEL,dev)) {
printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
dev->number,zatm_dev->irq);
"%ld VCs\n",dev->number,NR_SHAPERS,pools,rx,
(zatm_dev->mem-curr*4)/VC_SIZE);
/* create mailboxes */
- for (i = 0; i < NR_MBX; i++) zatm_dev->mbx_start[i] = 0;
for (i = 0; i < NR_MBX; i++)
if (mbx_entries[i]) {
unsigned long here;
here = (unsigned long) kmalloc(2*MBX_SIZE(i),
GFP_KERNEL);
- if (!here) return -ENOMEM;
+ if (!here) {
+ error = -ENOMEM;
+ goto out;
+ }
if ((here^(here+MBX_SIZE(i))) & ~0xffffUL)/* paranoia */
here = (here & ~0xffffUL)+0x10000;
+ zatm_dev->mbx_start[i] = here;
if ((here^virt_to_bus((void *) here)) & 0xffff) {
printk(KERN_ERR DEV_LABEL "(itf %d): system "
"bus incompatible with driver\n",
dev->number);
- kfree((void *) here);
- return -ENODEV;
+ error = -ENODEV;
+ goto out;
}
DPRINTK("mbx@0x%08lx-0x%08lx\n",here,here+MBX_SIZE(i));
- zatm_dev->mbx_start[i] = here;
zatm_dev->mbx_end[i] = (here+MBX_SIZE(i)) & 0xffff;
zout(virt_to_bus((void *) here) >> 16,MSH(i));
zout(virt_to_bus((void *) here),MSL(i));
zout(here & 0xffff,MWA(i));
}
error = start_tx(dev);
- if (error) return error;
+ if (error) goto out;
error = start_rx(dev);
- if (error) return error;
+ if (error) goto out;
error = dev->phy->start(dev);
- if (error) return error;
+ if (error) goto out;
zout(0xffffffff,IMR); /* enable interrupts */
/* enable TX & RX */
zout(zin(GMR) | uPD98401_GMR_SE | uPD98401_GMR_RE,GMR);
return 0;
+ out:
+ for (i = 0; i < NR_MBX; i++)
+ if (zatm_dev->mbx_start[i] != 0)
+ kfree((void *) zatm_dev->mbx_start[i]);
+ if (zatm_dev->rx_map != NULL)
+ kfree(zatm_dev->rx_map);
+ if (zatm_dev->tx_map != NULL)
+ kfree(zatm_dev->tx_map);
+ free_irq(zatm_dev->irq, dev);
+ return error;
}
case ZATM_GETTHIST:
{
int i;
-
+ struct zatm_t_hist hs[ZATM_TIMER_HISTORY_SIZE];
save_flags(flags);
cli();
- for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++) {
- if (!copy_to_user(
- (struct zatm_t_hist *) arg+i,
- &zatm_dev->timer_history[
+ for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++)
+ hs[i] = zatm_dev->timer_history[
(zatm_dev->th_curr+i) &
- (ZATM_TIMER_HISTORY_SIZE-1)],
- sizeof(struct zatm_t_hist)))
- continue;
- restore_flags(flags);
- return -EFAULT;
- }
+ (ZATM_TIMER_HISTORY_SIZE-1)];
restore_flags(flags);
- return 0;
+ return copy_to_user((struct zatm_t_hist *) arg,
+ hs, sizeof(hs)) ? -EFAULT : 0;
}
#endif
default:
zatm_dev),GFP_KERNEL);
if (!zatm_dev) {
printk(KERN_EMERG "zatm.c: memory shortage\n");
- goto out;
+ return devs;
}
}
}
-out:
+ kfree(zatm_dev);
return devs;
}
{
/* Copy the data into the buffer we created */
if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
+ {
+ kfree(buff);
return -EFAULT;
+ }
}
if ((c = cmd_alloc(h , 0)) == NULL)
{
{
kfree(buff);
cmd_free(h, c, 0);
+ return -EFAULT;
}
}
kfree(buff);
pt_rewind(unit);
return 0;
+ case MTWEOF:
+ pt_write_fm(unit);
+ return 0;
+
default:
printk("%s: Unimplemented mt_op %d\n",PT.name,
mtop.mt_op);
request_dma(dma_arb_level, "ed");
request_region(io_base, 4, "ed");
blksize_size[MAJOR_NR] = ps2esdi_blocksizes;
+ max_sectors[MAJOR_NR] = ps2esdi_maxsect;
for (i = 0; i < ps2esdi_drives; i++) {
register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6,
#define MAJOR_NR FLOPPY_MAJOR
#include <linux/blk.h>
+#include <linux/devfs_fs_kernel.h>
static int floppy_blocksizes[2] = {512,512};
static int floppy_sizes[2] = {2880,2880};
int swim3_init(void);
#ifndef CONFIG_PMAC_PBOOK
-static inline int check_media_bay(struct device_node *which_bay, int what)
-{
- return 1;
-}
+#define check_media_bay(which, what) 1
#endif
static void swim3_select(struct floppy_state *fs, int sel)
revalidate: floppy_revalidate,
};
+static devfs_handle_t floppy_devfs_handle;
+
int swim3_init(void)
{
struct device_node *swim;
+ floppy_devfs_handle = devfs_mk_dir(NULL, "floppy", NULL);
+
swim = find_devices("floppy");
while (swim && (floppy_count < MAX_FLOPPIES))
{
if (floppy_count > 0)
{
- if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
+ if (devfs_register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
printk(KERN_ERR "Unable to get major %d for floppy\n",
MAJOR_NR);
return -EBUSY;
{
struct device_node *mediabay;
struct floppy_state *fs = &floppy_states[floppy_count];
-
+ char floppy_name[16];
+ devfs_handle_t floppy_handle;
+
if (swim->n_addrs < 2)
{
printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count,
mediabay ? "in media bay" : "");
+ sprintf(floppy_name, "%s%d", floppy_devfs_handle ? "" : "floppy",
+ floppy_count);
+ floppy_handle = devfs_register(floppy_devfs_handle, floppy_name,
+ DEVFS_FL_DEFAULT, MAJOR_NR, floppy_count,
+ S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP,
+ &floppy_fops, NULL);
floppy_count++;
#define mcdx_drive_map mcdx
#include "mcdx.h"
+#if BITS_PER_LONG != 32
+# error FIXME: this driver only works on 32-bit platforms
+#endif
+
#ifndef HZ
#error HZ not defined
#endif
} else {
agp_segment *segment;
+ if (reserve.seg_count >= 16384)
+ return -EINVAL;
+
segment = kmalloc((sizeof(agp_segment) * reserve.seg_count),
GFP_KERNEL);
#define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
#ifdef MODULE
-static int maddr[NR_CARDS] = { 0, };
+static long maddr[NR_CARDS] = { 0, };
static int irq[NR_CARDS] = { 0, };
MODULE_PARM(maddr, "1-" __MODULE_STRING(NR_CARDS) "l");
return 0;
}
- CY_LOCK(info, flags);
if (from_user) {
down(&tmp_buf_sem);
while (1) {
+ int c1;
+
c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0)
}
break;
}
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ CY_LOCK(info, flags);
+ c1 = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
+
+ if (c1 < c)
+ c = c1;
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
info->xmit_cnt += c;
+ CY_UNLOCK(info, flags);
buf += c;
count -= c;
ret += c;
}
up(&tmp_buf_sem);
} else {
+ CY_LOCK(info, flags);
while (1) {
c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0) {
+
+ if (c <= 0)
break;
- }
+
memcpy(info->xmit_buf + info->xmit_head, buf, c);
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt += c;
count -= c;
ret += c;
}
+ CY_UNLOCK(info, flags);
}
- CY_UNLOCK(info, flags);
info->idle_stats.xmit_bytes += ret;
info->idle_stats.xmit_idle = jiffies;
atomic_dec(&dev->queuelist[i]->use_count);
}
/* Allocate a new queue */
- down(&dev->struct_sem);
queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+ if(queue == NULL)
+ return -ENOMEM;
+
memset(queue, 0, sizeof(*queue));
+ down(&dev->struct_sem);
atomic_set(&queue->use_count, 1);
++dev->queue_count;
{
int i;
- dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER);
+ if (!(dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER))) {
+ printk(KERN_ERR "drm_dma_setup: can't drm_alloc dev->dma");
+ return;
+ }
memset(dev->dma, 0, sizeof(*dev->dma));
for (i = 0; i <= DRM_MAX_ORDER; i++)
memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
vertex.idx, vertex.used, vertex.discard);
+ if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
i810_dma_dispatch_vertex( dev,
dma->buflist[ vertex.idx ],
vertex.discard, vertex.used );
if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d)))
return -EFAULT;
- if(d.idx > dma->buf_count) return -EINVAL;
+ if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
buf = dma->buflist[ d.idx ];
buf_priv = buf->dev_private;
if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM;
return -EINVAL;
}
+ if(iload.idx < 0 || iload.idx > dma->buf_count) return -EINVAL;
buf = dma->buflist[iload.idx];
buf_priv = buf->dev_private;
bus_address = buf->bus_address;
return -EINVAL;
}
+ if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
buf = dma->buflist[vertex.idx];
buf_priv = buf->dev_private;
return -EINVAL;
}
+ if(indices.idx < 0 || indices.idx > dma->buf_count) return -EINVAL;
buf = dma->buflist[indices.idx];
buf_priv = buf->dev_private;
if (!drm_dev_root) {
DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name);
remove_proc_entry("dri", NULL);
+ break;
}
if (drm_dev_root->nlink == 2) break;
drm_dev_root = NULL;
buf->dev_priv_size = sizeof(drm_radeon_buf_priv_t);
buf->dev_private = drm_alloc(sizeof(drm_radeon_buf_priv_t),
DRM_MEM_BUFS);
+ if (!buf->dev_private) {
+ up(&dev->struct_sem);
+ atomic_dec(&dev->buf_alloc);
+ return -ENOMEM;
+ }
memset(buf->dev_private, 0, buf->dev_priv_size);
#if DRM_DMA_HISTOGRAM
#include "epca.h"
#include "epcaconfig.h"
+#if BITS_PER_LONG != 32
+# error FIXME: this driver only works on 32-bit platforms
+#endif
+
/* ---------------------- Begin defines ------------------------ */
#define VERSION "1.3.0.1-LK"
if (!dma_buffer)
info->stat_flags |= ESP_STAT_USE_PIO;
else if (request_dma(dma, "esp serial")) {
- free_pages((unsigned int)dma_buffer,
+ free_pages((unsigned long)dma_buffer,
get_order(DMA_BUFFER_SZ));
dma_buffer = 0;
info->stat_flags |= ESP_STAT_USE_PIO;
if (!current_port) {
free_dma(dma);
- free_pages((unsigned int)dma_buffer,
+ free_pages((unsigned long)dma_buffer,
get_order(DMA_BUFFER_SZ));
dma_buffer = 0;
}
}
if (dma_buffer)
- free_pages((unsigned int)dma_buffer,
+ free_pages((unsigned long)dma_buffer,
get_order(DMA_BUFFER_SZ));
if (tmp_buf)
}
}
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id i810tco_pci_tbl[] __initdata = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, },
+ { 0, },
+};
+MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
+
static struct pci_dev *i810tco_pci;
static unsigned char i810tco_getdevice (void)
{
+ struct pci_dev *dev;
u8 val1, val2;
u16 badr;
/*
- * Find the PCI device which has vendor id 0x8086
- * and device ID 0x2410
+ * Find the PCI device
*/
- i810tco_pci = pci_find_device (PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82801AA_0, NULL);
- if (i810tco_pci) {
+
+ pci_for_each_dev(dev) {
+ if (pci_match_device(i810tco_pci_tbl, dev))
+ break;
+ }
+
+ if ((i810tco_pci = dev)) {
/*
* Find the ACPI base I/O address which is the base
* for the TCO registers (TCOBASE=ACPIBASE + 0x60)
static int r3964_open(struct tty_struct *tty);
static void r3964_close(struct tty_struct *tty);
-static int r3964_read(struct tty_struct *tty, struct file *file,
- unsigned char *buf, unsigned int nr);
-static int r3964_write(struct tty_struct * tty, struct file * file,
- const unsigned char * buf, unsigned int nr);
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+ unsigned char *buf, size_t nr);
+static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
+ const unsigned char * buf, size_t nr);
static int r3964_ioctl(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
static void r3964_set_termios(struct tty_struct *tty, struct termios * old);
MOD_DEC_USE_COUNT;
}
-static int r3964_read(struct tty_struct *tty, struct file *file,
- unsigned char *buf, unsigned int nr)
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+ unsigned char *buf, size_t nr)
{
struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
struct r3964_client_info *pClient;
return -EPERM;
}
-static int r3964_write(struct tty_struct * tty, struct file * file,
- const unsigned char *data, unsigned int count)
+static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
+ const unsigned char *data, size_t count)
{
struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
struct r3964_block_header *pHeader;
#define NVRAM_EXCL 2 /* opened with O_EXCL */
#define RTC_FIRST_BYTE 14 /* RTC register number of first NVRAM byte */
-#define NVRAM_BYTES 50 /* number of NVRAM bytes */
+#define NVRAM_BYTES 128 /* number of NVRAM bytes */
static int mach_check_checksum( void );
*
* 20/08/2000 RMK use __ioremap to map flash into virtual memory
* make a few more places use "volatile"
+ * 22/05/2001 RMK - Lock read against write
+ * - merge printk level changes (with mods) from Alan Cox.
+ * - use *ppos as the file position, not file->f_pos.
+ * - fix check for out of range pos and r/w size
+ *
+ * Please note that we are tampering with the only flash chip in the
+ * machine, which contains the bootup code. We therefore have the
+ * power to convert these machines into doorstops...
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
+#include <linux/rwsem.h>
#include <linux/init.h>
#include <asm/hardware/dec21285.h>
/*****************************************************************************/
#include <asm/nwflash.h>
-//#define MINIKERNEL 1 //export flash write, erase routines for MiniKernel
-
-#ifndef MINIKERNEL
-#define MSTATIC static
-#else
-#define MSTATIC
-#endif
-
-#define NWFLASH_VERSION "6.3"
+#define NWFLASH_VERSION "6.4"
-MSTATIC void kick_open(void);
-MSTATIC int get_flash_id(void);
-MSTATIC int erase_block(int nBlock);
-MSTATIC int write_block(unsigned long p, const char *buf, int count);
-static int open_flash(struct inode *inodep, struct file *filep);
+static void kick_open(void);
+static int get_flash_id(void);
+static int erase_block(int nBlock);
+static int write_block(unsigned long p, const char *buf, int count);
static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg);
static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos);
static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos);
static int gbWriteEnable;
static int gbWriteBase64Enable;
static volatile unsigned char *FLASH_BASE;
-MSTATIC int gbFlashSize = KFLASH_SIZE;
+static int gbFlashSize = KFLASH_SIZE;
extern spinlock_t gpio_lock;
-static struct file_operations flash_fops =
-{
- owner: THIS_MODULE,
- llseek: flash_llseek,
- read: flash_read,
- write: flash_write,
- ioctl: flash_ioctl,
- open: open_flash,
-};
-
-static struct miscdevice flash_miscdev =
-{
- FLASH_MINOR,
- "nwflash",
- &flash_fops
-};
-
/*
* the delay routine - it is often required to let the flash "breeze"...
*/
schedule_timeout(timeout);
}
-MSTATIC int get_flash_id(void)
+static int get_flash_id(void)
{
volatile unsigned int c1, c2;
return c2;
}
-static int open_flash(struct inode *inodep, struct file *filep)
-{
- int id;
-
- id = get_flash_id();
- if ((id != KFLASH_ID) && (id != KFLASH_ID4)) {
- printk("Flash: incorrect ID 0x%04X.\n", id);
- return -ENXIO;
- }
-
- return 0;
-}
-
static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg)
{
-// printk("Flash_ioctl: cmd = 0x%X.\n",cmd);
-
switch (cmd) {
case CMD_WRITE_DISABLE:
gbWriteBase64Enable = 0;
gbWriteEnable = 0;
return -EINVAL;
}
-
return 0;
}
-
-
-static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+static ssize_t flash_read(struct file *file, char *buf, size_t size, loff_t * ppos)
{
- unsigned long p = file->f_pos;
- int read;
+ struct inode *inode = file->f_dentry->d_inode;
+ unsigned long p = *ppos;
+ unsigned int count = size;
+ int ret = 0;
if (flashdebug)
- printk("Flash_dev: flash_read: offset=0x%X, buffer=0x%X, count=0x%X.\n",
- (unsigned int) p, (unsigned int) buf, count);
+ printk(KERN_DEBUG "flash_read: flash_read: offset=0x%lX, buffer=%p, count=0x%X.\n",
+ p, buf, count);
+ if (count)
+ ret = -ENXIO;
- if (count < 0)
- return -EINVAL;
+ if (p < gbFlashSize) {
+ if (count > gbFlashSize - p)
+ count = gbFlashSize - p;
- if (count > gbFlashSize - p)
- count = gbFlashSize - p;
-
- read = 0;
+ /*
+ * We now lock against reads and writes. --rmk
+ */
+ if (down_interruptible(&inode->i_sem))
+ return -ERESTARTSYS;
- if (copy_to_user(buf, (void *)(FLASH_BASE + p), count))
- return -EFAULT;
- read += count;
- file->f_pos += read;
- return read;
+ ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count);
+ if (ret == 0) {
+ ret = count;
+ *ppos += count;
+ }
+ up(&inode->i_sem);
+ }
+ return ret;
}
-static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+static ssize_t flash_write(struct file *file, const char *buf, size_t size, loff_t * ppos)
{
struct inode *inode = file->f_dentry->d_inode;
- unsigned long p = file->f_pos;
+ unsigned long p = *ppos;
+ unsigned int count = size;
int written;
int nBlock, temp, rc;
int i, j;
return -EINVAL;
/*
- * if byte count is -ve or to big - error!
+ * check for out of range pos or count
*/
- if (count < 0 || count > gbFlashSize - p)
- return -EINVAL;
+ if (p >= gbFlashSize)
+ return count ? -ENXIO : 0;
+ if (count > gbFlashSize - p)
+ count = gbFlashSize - p;
+
if (verify_area(VERIFY_READ, buf, count))
return -EFAULT;
-
/*
- * We now should lock around writes. Really, we shouldn't
- * allow the flash to be opened more than once in write
- * mode though (note that you can't stop two processes having
- * it open even then). --rmk
+ * We now lock against reads and writes. --rmk
*/
if (down_interruptible(&inode->i_sem))
return -ERESTARTSYS;
temp -= 1;
if (flashdebug)
- printk("FlashWrite: writing %d block(s) starting at %d.\n", temp, nBlock);
+ printk(KERN_DEBUG "flash_write: writing %d block(s) "
+ "starting at %d.\n", temp, nBlock);
for (; temp; temp--, nBlock++) {
if (flashdebug)
- printk("FlashWrite: erasing block %d.\n", nBlock);
+ printk(KERN_DEBUG "flash_write: erasing block %d.\n", nBlock);
/*
* first we have to erase the block(s), where we will write...
} while (rc && i < 10);
if (rc) {
- if (flashdebug)
- printk("FlashWrite: erase error %X. Aborting...\n", rc);
-
+ printk(KERN_ERR "flash_write: erase error %x\n", rc);
break;
}
if (flashdebug)
- printk("FlashWrite: writing offset %X, from buf %X, bytes left %X.\n",
- (unsigned int) p, (unsigned int) buf, count - written);
+ printk(KERN_DEBUG "flash_write: writing offset %lX, from buf "
+ "%p, bytes left %X.\n", p, buf, count - written);
/*
* write_block will limit write to space left in this block
}
if (rc < 0) {
- if (flashdebug)
- printk("FlashWrite: write error %X. Aborting...\n", rc);
+ printk(KERN_ERR "flash_write: write error %X\n", rc);
break;
}
p += rc;
buf += rc;
written += rc;
- file->f_pos += rc;
+ *ppos += rc;
if (flashdebug)
- printk("FlashWrite: written 0x%X bytes OK.\n", written);
+ printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written);
}
/*
static long long flash_llseek(struct file *file, long long offset, int orig)
{
if (flashdebug)
- printk("Flash_dev: flash_lseek, offset=0x%X, orig=0x%X.\n",
- (unsigned int) offset, (unsigned int) orig);
+ printk(KERN_DEBUG "flash_llseek: offset=0x%X, orig=0x%X.\n",
+ (unsigned int) offset, orig);
switch (orig) {
case 0:
* so just go ahead and erase, what requested!
*/
-MSTATIC int erase_block(int nBlock)
+static int erase_block(int nBlock)
{
volatile unsigned int c1;
volatile unsigned char *pWritePtr;
* check if erase errors were reported
*/
if (c1 & 0x20) {
- if (flashdebug)
- printk("Flash_erase: err at %X.\n", (unsigned int) pWritePtr);
+ printk(KERN_ERR "flash_erase: err at %p\n", pWritePtr);
+
/*
* reset error
*/
*(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50;
-
return -2;
}
for (temp = 0; temp < 16 * 1024; temp++, pWritePtr += 4) {
if ((temp1 = *(volatile unsigned int *) pWritePtr) != 0xFFFFFFFF) {
- if (flashdebug)
- printk("Flash_erase: verify err at %X = %X.\n",
- (unsigned int) pWritePtr, temp1);
+ printk(KERN_ERR "flash_erase: verify err at %p = %X\n",
+ pWritePtr, temp1);
return -1;
}
}
/*
* write_block will limit number of bytes written to the space in this block
*/
-MSTATIC int write_block(unsigned long p, const char *buf, int count)
+static int write_block(unsigned long p, const char *buf, int count)
{
volatile unsigned int c1;
volatile unsigned int c2;
*/
if (time_before(jiffies, timeout)) {
if (flashdebug)
- printk("FlashWrite: Retrying write (addr=0x%X)...\n",
+ printk(KERN_DEBUG "write_block: Retrying write at 0x%X)n",
pWritePtr - FLASH_BASE);
/*
goto WriteRetry;
} else {
- printk("Timeout in flash write! (addr=0x%X) Aborting...\n",
+ printk(KERN_ERR "write_block: timeout at 0x%X\n",
pWritePtr - FLASH_BASE);
/*
* return error -2
return -EFAULT;
buf++;
if ((c1 = *pWritePtr++) != c) {
- if (flashdebug)
- printk("flash write verify error at 0x%X! (%02X!=%02X) Retrying...\n",
- (unsigned int) pWritePtr, c1, c);
+ printk(KERN_ERR "write_block: verify error at 0x%X (%02X!=%02X)\n",
+ pWritePtr - FLASH_BASE, c1, c);
return 0;
}
}
}
-MSTATIC void kick_open(void)
+static void kick_open(void)
{
unsigned long flags;
udelay(25);
}
-MSTATIC int __init nwflash_init(void)
+static struct file_operations flash_fops =
+{
+ owner: THIS_MODULE,
+ llseek: flash_llseek,
+ read: flash_read,
+ write: flash_write,
+ ioctl: flash_ioctl,
+};
+
+static struct miscdevice flash_miscdev =
+{
+ FLASH_MINOR,
+ "nwflash",
+ &flash_fops
+};
+
+static int __init nwflash_init(void)
{
int ret = -ENODEV;
goto out;
id = get_flash_id();
+ if ((id != KFLASH_ID) && (id != KFLASH_ID4)) {
+ ret = -ENXIO;
+ iounmap((void *)FLASH_BASE);
+ printk("Flash: incorrect ID 0x%04X.\n", id);
+ goto out;
+ }
+
printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n",
NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024));
return ret;
}
-MSTATIC void __exit nwflash_exit(void)
+static void __exit nwflash_exit(void)
{
misc_deregister(&flash_miscdev);
iounmap((void *)FLASH_BASE);
break;
minor = rq.raw_minor;
- if (minor == 0 || minor > MINORMASK) {
+ if (minor <= 0 || minor > MINORMASK) {
err = -EINVAL;
break;
}
/* now scan */
for(ofs = 0; ofs != count; ofs++)
+ {
+ char c;
+ if(get_user(c, buf+ofs))
+ return -EFAULT;
if(buf[ofs] == 'V')
wdt_expect_close = 1;
-
+ }
/* Well, anyhow someone wrote to us, we should return that favour */
next_heartbeat = jiffies + WDT_HEARTBEAT;
return 1;
memset(&sci_driver, 0, sizeof(sci_driver));
sci_driver.magic = TTY_DRIVER_MAGIC;
sci_driver.driver_name = "sci";
+#ifdef CONFIG_DEVFS_FS
+ sci_driver.name = "ttsc/%d";
+#else
sci_driver.name = "ttySC";
+#endif
sci_driver.major = SCI_MAJOR;
sci_driver.minor_start = SCI_MINOR_START;
sci_driver.num = SCI_NPORTS;
#endif
sci_callout_driver = sci_driver;
+#ifdef CONFIG_DEVFS_FS
+ sci_callout_driver.name = "cusc/%d";
+#else
sci_callout_driver.name = "cusc";
+#endif
sci_callout_driver.major = SCI_MAJOR+1;
sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
sci_callout_driver.read_proc = NULL;
# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_AND_SCIF
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
# define SCI_NPORTS 2
# define SCI_INIT { \
{ {}, PORT_SCI, 0xffe00000, SCI_IRQS, sci_init_pins_sci }, \
return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
return 1;
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
static inline int sci_rxd_in(struct sci_port *port)
{
#ifndef SCIF_ONLY
int i, j, ch;
for (i=0;i<len;i+=16) {
- printk ("%08x ", (int) addr+i);
+ printk ("%p ", addr+i);
for (j=0;j<16;j++) {
printk ("%02x %s", addr[j+i], (j==7)?" ":"");
}
int rc = 0;
int *descr = (int *)arg, i;
static struct sx_board *board = NULL;
- int nbytes, offset, data;
+ int nbytes, offset;
+ unsigned long data;
char *tmp;
func_enter();
func_enter();
if (!IS_CF_BOARD (board)) {
- sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %x.\n",
+ sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %lx.\n",
board->base + SX_VPD_ROM);
if (sx_debug & SX_DEBUG_PROBE)
printheader ();
if (!IS_CF_BOARD (board)) {
- printk (KERN_DEBUG "sx: Found an SX board at %x\n", board->hw_base);
+ printk (KERN_DEBUG "sx: Found an SX board at %lx\n", board->hw_base);
printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ",
vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
printk ( "Manufactured: %d/%d\n",
if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
if (board->base & 0x8000) {
- printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %x.\n", board->base);
+ printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->base);
printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
}
}
int i;
func_enter();
- sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %x.\n",
+ sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %lx.\n",
board->base + SI2_ISA_ID_BASE);
if (sx_debug & SX_DEBUG_PROBE)
printheader ();
- printk (KERN_DEBUG "sx: Found an SI board at %x\n", board->hw_base);
+ printk (KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
/* Compared to the SX boards, it is a complete guess as to what
this card is up to... */
board->irq = get_irq (pdev);
- sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%x(%d) %x.\n",
+ sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%lx(%d) %x.\n",
tint, boards[found].base, board->irq, board->flags);
if (probe_sx (board)) {
board->base2 =
board->base = (ulong) ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
- sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %x\n", board->hw_base);
- sx_dprintk(SX_DEBUG_PROBE, "base: %x\n", board->base);
+ sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
+ sx_dprintk(SX_DEBUG_PROBE, "base: %lx\n", board->base);
board->irq = inb(board->eisa_base+0xc02)>>4;
sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
for (i = 0; i < SX_NBOARDS; i++) {
board = &boards[i];
if (board->flags & SX_BOARD_INITIALIZED) {
- sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %x\n", board->base);
+ sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %lx\n", board->base);
/* The board should stop messing with us.
(actually I mean the interrupt) */
sx_reset (board);
struct sx_board {
int magic;
- unsigned int base;
- unsigned int base2;
- unsigned int hw_base;
+ unsigned long base;
+ unsigned long base2;
+ unsigned long hw_base;
int eisa_base;
int port_base; /* Number of the first port */
struct sx_port *ports;
extern long serial167_console_init(void);
extern void console_8xx_init(void);
extern int rs_8xx_init(void);
+extern void mac_scc_console_init(void);
extern void hwc_console_init(void);
extern void hwc_tty_init(void);
extern void con3215_init(void);
#ifdef CONFIG_SERIAL_CONSOLE
#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
console_8xx_init();
+#elif defined(CONFIG_MAC_SERIAL)
+ mac_scc_console_init();
#elif defined(CONFIG_SERIAL)
serial_console_init();
#endif /* CONFIG_8xx */
#ifdef CONFIG_COMPUTONE
ip2_init();
#endif
-#ifdef CONFIG_MAC_SERIAL
- macserial_init();
-#endif
#ifdef CONFIG_ROCKETPORT
rp_init();
#endif
};
const char *bad_ata100_5[] = {
+ "IBM-DTLA-307075",
+ "IBM-DTLA-307060",
+ "IBM-DTLA-307045",
+ "IBM-DTLA-307030",
+ "IBM-DTLA-307020",
+ "IBM-DTLA-307015",
+ "IBM-DTLA-305040",
+ "IBM-DTLA-305030",
+ "IBM-DTLA-305020",
+ "WDC AC310200R",
NULL
};
#endif
#ifdef CONFIG_BLK_DEV_SL82C105
+extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
+extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
extern void ide_init_sl82c105(ide_hwif_t *);
-extern void ide_dmacapable_sl82c105(ide_hwif_t *, unsigned long);
+#define PCI_W82C105 &pci_init_sl82c105
+#define DMA_W82C105 &dma_init_sl82c105
#define INIT_W82C105 &ide_init_sl82c105
-#define DMA_W82C105 &ide_dmacapable_sl82c105
#else
-#define INIT_W82C105 IDE_IGNORE
+#define PCI_W82C105 NULL
#define DMA_W82C105 NULL
+#define INIT_W82C105 IDE_IGNORE
#endif
#ifdef CONFIG_BLK_DEV_TRM290
{DEVID_AEC6210, "AEC6210", PCI_AEC62XX, NULL, INIT_AEC62XX, DMA_AEC62XX, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 },
{DEVID_AEC6260, "AEC6260", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0 },
{DEVID_AEC6260R,"AEC6260R", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 },
- {DEVID_W82C105, "W82C105", NULL, NULL, INIT_W82C105, DMA_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 },
+ {DEVID_W82C105, "W82C105", PCI_W82C105, NULL, INIT_W82C105, DMA_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 },
{DEVID_UM8673F, "UM8673F", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
#include <asm/ecard.h>
-static const card_ids __init rapide_cids[] = {
+static card_ids __init rapide_cids[] = {
{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
{ 0xffff, 0xffff }
};
}
/*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
+ * Configure the drive and chipset for PIO
*/
-static void tune_sl82c105(ide_drive_t *drive, byte pio)
+static void config_for_pio(ide_drive_t *drive, int pio, int report)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
if (ide_config_drive_speed(drive, xfer_mode) == 0)
drv_ctrl = get_timing_sl82c105(&p);
+ if (drive->using_dma == 0) {
+ /*
+ * If we are actually using MW DMA, then we can not
+ * reprogram the interface drive control register.
+ */
+ pci_write_config_word(dev, reg, drv_ctrl);
+ pci_read_config_word(dev, reg, &drv_ctrl);
+
+ if (report) {
+ printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+ ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+ }
+ }
+}
+
+/*
+ * Configure the drive and the chipset for DMA
+ */
+static int config_for_dma(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned short drv_ctrl = 0x909;
+ unsigned int reg;
+
+ reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+ if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
+ drv_ctrl = 0x0240;
+
pci_write_config_word(dev, reg, drv_ctrl);
- pci_read_config_word(dev, reg, &drv_ctrl);
- printk("%s: selected %s (%dns) (%04X)\n", drive->name,
- ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+ return 0;
}
-#endif
-void __init ide_dmacapable_sl82c105(ide_hwif_t *hwif, unsigned long dmabase)
+/*
+ * Check to see if the drive and
+ * chipset is capable of DMA mode
+ */
+static int sl82c105_check_drive(ide_drive_t *drive)
{
+ ide_dma_action_t dma_func = ide_dma_off_quietly;
+
+ do {
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (!hwif->autodma)
+ break;
+
+ if (!id || !(id->capability & 1))
+ break;
+
+ /* Consult the list of known "bad" drives */
+ if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+ dma_func = ide_dma_off;
+ break;
+ }
+
+ if (id->field_valid & 2) {
+ if (id->dma_mword & 7 || id->dma_1word & 7)
+ dma_func = ide_dma_on;
+ break;
+ }
+
+ if (ide_dmaproc(ide_dma_good_drive, drive)) {
+ dma_func = ide_dma_on;
+ break;
+ }
+ } while (0);
+
+ return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * Our own dmaproc, only to intercept ide_dma_check
+ */
+static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+ switch (func) {
+ case ide_dma_check:
+ return sl82c105_check_drive(drive);
+ case ide_dma_on:
+ if (config_for_dma(drive))
+ func = ide_dma_off;
+ /* fall through */
+ case ide_dma_off_quietly:
+ case ide_dma_off:
+ config_for_pio(drive, 4, 0);
+ break;
+ default:
+ break;
+ }
+ return ide_dmaproc(func, drive);
+}
+
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, byte pio)
+{
+ config_for_pio(drive, pio, 1);
+
+ /*
+ * We support 32-bit I/O on this interface, and it
+ * doesn't have problems with interrupts.
+ */
+ drive->io_32bit = 1;
+ drive->unmask = 1;
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+{
+ struct pci_dev *bridge;
unsigned char rev;
- pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &rev);
+ bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
+
+ /*
+ * If we are part of a Winbond 553
+ */
+ if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
+ return -1;
+
+ if (bridge->bus != dev->bus ||
+ PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
+ return -1;
+
+ /*
+ * We need to find function 0's revision, not function 1
+ */
+ pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+ return rev;
+}
+
+/*
+ * Enable the PCI device
+ */
+unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
+{
+ unsigned char ctrl_stat;
+
+ /*
+ * Enable the ports
+ */
+ pci_read_config_byte(dev, 0x40, &ctrl_stat);
+ pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
+ return dev->irq;
+}
+
+void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+ unsigned int rev;
+ byte dma_state;
+
+ dma_state = inb(dma_base + 2);
+ rev = sl82c105_bridge_revision(hwif->pci_dev);
if (rev <= 5) {
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
- printk(" %s: revision %d, Bus-Master DMA disabled\n",
+ printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
hwif->name, rev);
+ dma_state &= ~0x60;
+ } else {
+ dma_state |= 0x60;
+ hwif->autodma = 1;
}
- ide_setup_dma(hwif, dmabase, 8);
+ outb(dma_state, dma_base + 2);
+
+ hwif->dmaproc = NULL;
+ ide_setup_dma(hwif, dma_base, 8);
+ if (hwif->dmaproc)
+ hwif->dmaproc = sl82c105_dmaproc;
}
+/*
+ * Initialise the chip
+ */
void __init ide_init_sl82c105(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
+ hwif->tuneproc = tune_sl82c105;
+}
-#ifdef CONFIG_ARCH_NETWINDER
- unsigned char ctrl_stat;
+#else
- pci_read_config_byte(dev, 0x40, &ctrl_stat);
- pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
+unsigned int pci_init_sl82c105(struct pci_dev *dev, const char *msg)
+{
+ return ide_special_settings(dev, msg);
+}
- hwif->tuneproc = tune_sl82c105;
-#else
+void dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+ ide_setup_dma(hwif, dma_base, 8);
+}
+
+void __init ide_init_sl82c105(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
unsigned short t16;
unsigned int t32;
pci_read_config_word(dev, PCI_COMMAND, &t16);
printk("IDE control/status register: %08x\n",t32);
pci_write_config_dword(dev, 0x40, 0x10ff08a1);
#endif /* CONFIG_MBX */
-#endif
}
+#endif
+
/*
- * $Id: c4.c,v 1.20.6.8 2001/05/17 21:15:33 kai Exp $
+ * $Id: c4.c,v 1.20.6.10 2001/06/09 15:14:15 kai Exp $
*
* Module for AVM C4 & C2 card.
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.20.6.9 $";
+static char *revision = "$Revision: 1.20.6.10 $";
#undef CONFIG_C4_DEBUG
#undef CONFIG_C4_POLLDEBUG
/*
- * $Id: capi.c,v 1.44.6.11 2001/05/17 20:41:51 kai Exp $
+ * $Id: capi.c,v 1.44.6.12 2001/06/09 15:14:15 kai Exp $
*
* CAPI 2.0 Interface for Linux
*
#include "capifs.h"
#endif
-static char *revision = "$Revision: 1.44.6.11 $";
+static char *revision = "$Revision: 1.44.6.12 $";
MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
void capiminor_free(struct capiminor *mp)
{
struct capiminor **pp;
- struct sk_buff *skb;
pp = &minors;
while (*pp) {
*pp = (*pp)->next;
if (mp->ttyskb) kfree_skb(mp->ttyskb);
mp->ttyskb = 0;
- while ((skb = skb_dequeue(&mp->recvqueue)) != 0)
- kfree_skb(skb);
- while ((skb = skb_dequeue(&mp->inqueue)) != 0)
- kfree_skb(skb);
- while ((skb = skb_dequeue(&mp->outqueue)) != 0)
- kfree_skb(skb);
+ skb_queue_purge(&mp->recvqueue);
+ skb_queue_purge(&mp->inqueue);
+ skb_queue_purge(&mp->outqueue);
capiminor_del_all_ack(mp);
kmem_cache_free(capiminor_cachep, mp);
MOD_DEC_USE_COUNT;
static void capidev_free(struct capidev *cdev)
{
struct capidev **pp;
- struct sk_buff *skb;
if (cdev->applid)
(*capifuncs->capi_release) (cdev->applid);
cdev->applid = 0;
- while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) {
- kfree_skb(skb);
- }
+ skb_queue_purge(&cdev->recvqueue);
pp=&capidev_openlist;
while (*pp && *pp != cdev) pp = &(*pp)->next;
/*
- * $Id: kcapi.c,v 1.21.6.6 2001/05/17 20:41:51 kai Exp $
+ * $Id: kcapi.c,v 1.21.6.7 2001/06/09 15:14:15 kai Exp $
*
* Kernel CAPI 2.0 Module
*
#include <linux/b1lli.h>
#endif
-static char *revision = "$Revision: 1.21.6.6 $";
+static char *revision = "$Revision: 1.21.6.7 $";
/* ------------------------------------------------------------- */
static __u16 capi_release(__u16 applid)
{
- struct sk_buff *skb;
int i;
if (!VALID_APPLID(applid) || APPL(applid)->releasing)
return CAPI_ILLAPPNR;
APPL(applid)->releasing++;
- while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
- kfree_skb(skb);
+ skb_queue_purge(&APPL(applid)->recv_queue);
for (i = 0; i < CAPI_MAXCONTR; i++) {
if (cards[i].cardstate != CARD_RUNNING)
continue;
{
int i;
- bzero(card_list, sizeof(dia_card_list_t));
+ memset(card_list, 0, sizeof(dia_card_list_t));
for(i = 0; i < DivasCardNext; i++)
{
int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile,
unsigned int command, unsigned long arg)
{
- dia_load_t *pDivaLoad;
- dia_start_t *pDivaStart;
- dia_config_t *pDivaConfig;
- dia_log_t *pDivaLog;
byte *pUserCards, card_i;
word wCardNum;
- mem_block_t *mem_block;
switch (command)
{
case DIA_IOCTL_CONFIG:
- pDivaConfig = (dia_config_t *) arg;
-
- if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t)))
- {
- DivasCardConfig(pDivaConfig);
- }
- else
- {
- printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n");
- return -1;
- }
- return 0;
+ {
+ dia_config_t DivaConfig;
+ if (copy_from_user(&DivaConfig, (void *)arg, sizeof(dia_config_t)))
+ return -EFAULT;
+ DivasCardConfig(&DivaConfig);
+ return 0;
+ }
case DIA_IOCTL_DETECT:
pUserCards = (byte *) arg;
if (!verify_area(VERIFY_WRITE, pUserCards, 20))
{
- put_user(DivasCardNext, pUserCards++);
+ if(__put_user(DivasCardNext, pUserCards++))
+ return -EFAULT;
for (card_i=1; card_i < 20; card_i++)
{
- put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++);
+ if(__put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++))
+ return -EFAULT;
}
}
- else
- {
- printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n");
- return -1;
- }
+ else return -EFAULT;
+
return 0;
case DIA_IOCTL_START:
- pDivaStart = (dia_start_t *) arg;
-
- if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t)))
- {
- return DivasCardStart(pDivaStart->card_id);
- }
- else
- {
- printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n");
- return -1;
- }
-
+ {
+ dia_start_t DivaStart;
+ if (copy_from_user(&DivaStart, (void *)arg, sizeof(dia_start_t)))
+ return -EFAULT;
+ return DivasCardStart(DivaStart.card_id);
+ }
case DIA_IOCTL_FLAVOUR:
return 0;
case DIA_IOCTL_LOAD:
- pDivaLoad = (dia_load_t *) arg;
- if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length))
+ {
+ dia_load_t DivaLoad;
+ if(copy_from_user(&DivaLoad, (void *)arg, sizeof(dia_load_t)))
+ return -EFAULT;
+ if (!verify_area(VERIFY_READ, DivaLoad.code,DivaLoad.length))
{
- if (DivasCardLoad(pDivaLoad))
+ if (DivasCardLoad(&DivaLoad))
{
printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n");
return -EINVAL;
}
+ return 0;
}
- else
- {
- printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n");
- return -EINVAL;
- }
- return 0;
-
+ return -EFAULT;
+ }
case DIA_IOCTL_LOG:
- pDivaLog = (dia_log_t *) arg;
-
- if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t)))
- {
- DivasLog(pDivaLog);
- }
- else
- {
- printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n");
- return -1;
- }
+ {
+ dia_log_t DivaLog;
+ if (copy_from_user(&DivaLog, (void *) arg, sizeof(dia_log_t)))
+ return -EFAULT;
+ DivasLog(&DivaLog);
return 0;
+ }
case DIA_IOCTL_XLOG_REQ:
-
- if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word)))
- {
- wCardNum = * (word *) arg;
- DivasXlogReq(wCardNum);
- }
- else
- {
- printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n");
- return -1;
- }
+ if(get_user(wCardNum, (word *) arg))
+ return -EFAULT;
+ DivasXlogReq(wCardNum);
return 0;
case DIA_IOCTL_GET_NUM:
-
- if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)))
- {
- * (int *) arg = DivasCardNext;
- }
- else
- {
- printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n");
- return -1;
- }
+ if(put_user(DivasCardNext, (int *)arg))
+ return -EFAULT;
return 0;
case DIA_IOCTL_GET_LIST:
+ {
+ dia_card_list_t cards;
DPRINTF(("divas: DIA_IOCTL_GET_LIST"));
-
- if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t)))
- {
- DivasGetList((dia_card_list_t *)arg);
- }
- else
- {
- printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n");
- return -1;
- }
+ DivasGetList(&cards);
+ if(copy_to_user((void *)arg, &cards, sizeof(cards)))
+ return -EFAULT;
return 0;
-
+ }
case DIA_IOCTL_GET_MEM:
- mem_block = (mem_block_t *) arg;
-
- if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t)))
- {
- DivasGetMem(mem_block);
- }
- else
- {
- printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n");
- return -1;
- }
+ {
+ mem_block_t mem_block;
+ if (copy_from_user(&mem_block, (void *)arg, sizeof(mem_block_t)))
+ return -EFAULT;
+ DivasGetMem(&mem_block);
return 0;
+ }
case DIA_IOCTL_UNLOCK:
UnlockDivas();
return 0;
default:
- printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command);
return -EINVAL;
}
-
return -EINVAL;
}
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <linux/input.h>
+#include <linux/module.h>
#ifdef CONFIG_MAC_ADBKEYCODES
#include <linux/keyboard.h>
return keyboard_sends_linux_keycodes;
}
+EXPORT_SYMBOL(mac_hid_keyboard_sends_linux_keycodes);
+
static int __init mac_hid_setup(char *str)
{
int ints[2];
return 0;
}
+EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons);
+
static void emumousebtn_input_register(void)
{
emumousebtn.name = "Macintosh mouse button emulation";
#ifdef CONFIG_MAC_ADBKEYCODES
memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
- if (!keyboard_sends_linux_keycodes)
+ if (!keyboard_sends_linux_keycodes) {
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
+ SYSRQ_KEY = 0x69;
+#endif
memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+ } else {
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
#endif
+ }
+#endif /* CONFIG_MAC_ADBKEYCODES */
#ifdef CONFIG_MAC_EMUMOUSEBTN
emumousebtn_input_register();
return 1;
}
-int mackbd_unexpected_up(unsigned char keycode)
+char mackbd_unexpected_up(unsigned char keycode)
{
return 0x80;
}
goto out;
info->tx_active = 0;
- if (info->x_char) {
+ if (info->x_char && !info->power_wait) {
/* Send next char */
write_zsdata(info->zs_channel, info->x_char);
info->x_char = 0;
goto out;
}
- if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
+ if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped
+ || info->power_wait) {
write_zsreg(info->zs_channel, 0, RES_Tx_P);
goto out;
}
restore_flags(flags);
}
+static void powerup_done(unsigned long data)
+{
+ struct mac_serial *info = (struct mac_serial *) data;
+
+ info->power_wait = 0;
+ transmit_chars(info);
+}
+
static _INLINE_ void status_handle(struct mac_serial *info)
{
unsigned char status;
}
}
-static int startup(struct mac_serial * info, int can_sleep)
+static int startup(struct mac_serial * info)
{
int delay;
setup_scc(info);
+ if (delay) {
+ unsigned long flags;
+
+ /* delay is in ms */
+ save_flags(flags);
+ cli();
+ info->power_wait = 1;
+ mod_timer(&info->powerup_timer,
+ jiffies + (delay * HZ + 999) / 1000);
+ restore_flags(flags);
+ }
+
OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
info->flags |= ZILOG_INITIALIZED;
enable_irq(info->rx_dma_irq);
}
- if (delay) {
- if (can_sleep) {
- /* we need to wait a bit before using the port */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(delay * HZ / 1000);
- } else
- mdelay(delay);
- }
-
return 0;
}
queue_task(&tty->flip.tqueue, &tq_timer);
}
-static void poll_rxdma(void *private_)
+static void poll_rxdma(unsigned long private_)
{
struct mac_serial *info = (struct mac_serial *) private_;
unsigned long flags;
* Start up serial port
*/
- retval = startup(info, 1);
+ retval = startup(info);
if (retval)
return retval;
zss->rx_dma_irq = ch->intrs[2].line;
spin_lock_init(&zss->rx_dma_lock);
}
+
+ init_timer(&zss->powerup_timer);
+ zss->powerup_timer.function = powerup_done;
+ zss->powerup_timer.data = (unsigned long) zss;
}
/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
return 0;
}
-#ifdef MODULE
-int init_module(void)
-{
- macserial_init();
- return 0;
-}
-
-void cleanup_module(void)
+void macserial_cleanup(void)
{
int i;
unsigned long flags;
pmu_unregister_sleep_notifier(&serial_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
}
-#endif /* MODULE */
+
+module_init(macserial_init);
+module_exit(macserial_cleanup);
#if 0
/*
struct mac_serial *info = &zs_soft[i];
if (info->flags & ZILOG_SLEEPING) {
info->flags &= ~ZILOG_SLEEPING;
- startup(info, 0);
+ startup(info);
}
}
break;
char is_irda; /* is connected to an IrDA codec */
unsigned char tx_active; /* character is being xmitted */
unsigned char tx_stopped; /* output is suspended */
+ unsigned char power_wait; /* waiting for power-up delay to expire */
/* We need to know the current clock divisor
* to read the bps rate the chip has currently
void *dma_priv;
struct timer_list poll_dma_timer;
#define RX_DMA_TIMER (jiffies + 10*HZ/1000)
+
+ struct timer_list powerup_timer;
};
{
struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus),
GFP_KERNEL);
+ if (!b) {
+ printk(KERN_ERR "i2c_parport: Memory allocation failed. Not attaching.\n");
+ return;
+ }
b->i2c = parport_i2c_bus_template;
b->i2c.data = parport_get_port (port);
strncpy(b->i2c.name, port->name, 32);
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/irq.h>
+#include <asm/semaphore.h>
#include "planb.h"
#include "saa7196.h"
/* misc. supporting functions */
/******************************/
-static void __planb_wait(struct planb *pb)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&pb->lockq, &wait);
-repeat:
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (pb->lock) {
- schedule();
- goto repeat;
- }
- remove_wait_queue(&pb->lockq, &wait);
- current->state = TASK_RUNNING;
-}
-
-static inline void planb_wait(struct planb *pb)
-{
- DEBUG("PlanB: planb_wait\n");
- if(pb->lock)
- __planb_wait(pb);
-}
-
static inline void planb_lock(struct planb *pb)
{
- DEBUG("PlanB: planb_lock\n");
- if(pb->lock)
- __planb_wait(pb);
- pb->lock = 1;
+ down(&pb->lock);
}
static inline void planb_unlock(struct planb *pb)
{
- DEBUG("PlanB: planb_unlock\n");
- pb->lock = 0;
- wake_up(&pb->lockq);
+ up(&pb->lock);
}
/***************/
pb->tab_size = PLANB_MAXLINES + 40;
pb->suspend = 0;
pb->lock = 0;
- init_waitqueue_head(&pb->lockq);
+ init_MUTEX(&pb->lock);
pb->ch1_cmd = 0;
pb->ch2_cmd = 0;
pb->mask = 0;
int user;
unsigned int tab_size;
int maxlines;
- int lock;
- wait_queue_head_t lockq;
+ struct semaphore lock;
unsigned int irq; /* interrupt number */
volatile unsigned int intr_mask;
return;
p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry);
+ if (!p)
+ return;
p->data = vfd;
p->read_proc = videodev_proc_read;
v.norm=VIDEO_MODE_PAL;
#endif
/* too many inputs? no decoder -> no channels */
- if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
+ if (!ztv->have_decoder || v.channel < 0 || v.channel >= ztv->card->video_inputs)
return -EINVAL;
/* now determine the name of the channel */
if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then
bool ' Write support for NFTL (BETA)' CONFIG_NFTL_RW
fi
-fi
-source drivers/mtd/chips/Config.in
+ source drivers/mtd/chips/Config.in
+
+ source drivers/mtd/maps/Config.in
-source drivers/mtd/maps/Config.in
+ source drivers/mtd/devices/Config.in
-source drivers/mtd/devices/Config.in
+ source drivers/mtd/nand/Config.in
-source drivers/mtd/nand/Config.in
+fi
endmenu
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098),
(long) "3Com Etherlink III (TPC)" },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+ ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f7),
+ (long) "3Com Etherlink III compatible" },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8),
(long) "3Com Etherlink III compatible" },
MODULE_PARM_DESC(irq, "EtherLink III IRQ number(s) (assigned)");
MODULE_PARM_DESC(xcvr,"EtherLink III tranceiver(s) (0=internal, 1=external)");
MODULE_PARM_DESC(max_interrupt_work, "EtherLink III maximum events handled per interrupt");
+#ifdef CONFIG_ISAPNP
MODULE_PARM(nopnp, "i");
MODULE_PARM_DESC(nopnp, "EtherLink III disable ISA PnP support (0-1)");
+#endif /* CONFIG_ISAPNP */
int
init_module(void)
fi
fi
-tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000
+if [ "$CONFIG_ISAPNP" = "y" ]; then
+ tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000 $CONFIG_ISAPNP
+fi
#
# Ethernet
bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
- if [ "$CONFIG_ARM" = "y" ]; then
- if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
- tristate ' AM79C961A support' CONFIG_ARM_AM79C961A
- else
- source drivers/acorn/net/Config.in
- fi
+ dep_bool ' ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110
+ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+ source drivers/acorn/net/Config.in
fi
if [ "$CONFIG_PPC" = "y" ]; then
tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE
if [ "$CONFIG_SUPERH" = "y" ]; then
tristate ' National DP83902AV support' CONFIG_STNIC
fi
+ dep_tristate ' Sun LANCE support' CONFIG_SUNLANCE $CONFIG_SBUS
+ if [ "$CONFIG_SBUS" = "y" -o "$CONFIG_PCI" = "y" ]; then
+ tristate ' Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
+ fi
+ dep_tristate ' Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC $CONFIG_SBUS $CONFIG_EXPERIMENTAL
+ dep_tristate ' Sun QuadEthernet support' CONFIG_SUNQE $CONFIG_SBUS
+ dep_tristate ' Sun LANCE support' CONFIG_SUNLANCE $CONFIG_SBUS
+ dep_tristate ' Sun GEM support' CONFIG_SUNGEM $CONFIG_PCI
bool ' 3COM cards' CONFIG_NET_VENDOR_3COM
if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
dep_tristate ' 3c501 "EtherLink" support' CONFIG_EL1 $CONFIG_ISA
dep_tristate ' AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE $CONFIG_ISA
bool ' Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
- tristate ' WD80*3 support' CONFIG_WD80x3
- if [ "$CONFIG_MCA" = "y" ]; then
- tristate ' SMC Ultra MCA support' CONFIG_ULTRAMCA
+ dep_tristate ' WD80*3 support' CONFIG_WD80x3 $CONFIG_ISA
+ dep_tristate ' SMC Ultra MCA support' CONFIG_ULTRAMCA $CONFIG_MCA
+ if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ISAPNP" = "y" ]; then
+ tristate ' SMC Ultra support' CONFIG_ULTRA
fi
- tristate ' SMC Ultra support' CONFIG_ULTRA
dep_tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA
- tristate ' SMC 9194 support' CONFIG_SMC9194
+ dep_tristate ' SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA
fi
bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
- dep_tristate ' NI5010 support (EXPERIMENTAL)' CONFIG_NI5010 $CONFIG_EXPERIMENTAL
- tristate ' NI5210 support' CONFIG_NI52
- tristate ' NI6510 support' CONFIG_NI65
+ dep_tristate ' NI5010 support (EXPERIMENTAL)' CONFIG_NI5010 $CONFIG_ISA $CONFIG_EXPERIMENTAL
+ dep_tristate ' NI5210 support' CONFIG_NI52 $CONFIG_ISA
+ dep_tristate ' NI6510 support' CONFIG_NI65 $CONFIG_ISA
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
+ if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+ tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
+ fi
+ fi
+ if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+ tristate ' DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
fi
- tristate ' DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
fi
tristate ' NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
tristate ' IBM LAN Adapter/A support' CONFIG_IBMLANA
fi
- bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
+ dep_bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
if [ "$CONFIG_NET_PCI" = "y" ]; then
dep_tristate ' AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
dep_tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 $CONFIG_EXPERIMENTAL
fi
- tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT
+ dep_tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA
dep_tristate ' CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA
dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
+ if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then
+ dep_bool ' New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL
+ bool ' Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO
+ fi
if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
fi
dep_tristate ' Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
- dep_mbool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL
dep_tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
dep_tristate ' Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
dep_tristate ' National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
fi
dep_tristate ' VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI
dep_tristate ' Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
- dep_tristate ' Sun Happy Meal 10/100baseT PCI support' CONFIG_HAPPYMEAL $CONFIG_PCI
if [ "$CONFIG_OBSOLETE" = "y" ]; then
- bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
+ dep_bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET $CONFIG_ISA
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ORION" = "y" ]; then
bool ' Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730
if [ "$CONFIG_ISA" = "y" -a "$CONFIG_X86" = "y" ]; then
tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
fi
- tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600
- tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620
+ dep_tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600 $CONFIG_ISA
+ dep_tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620 $CONFIG_ISA
fi
fi
if [ "$CONFIG_ACENIC" != "n" ]; then
bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
fi
+dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI
-fi
+dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI
endmenu
if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
fi
- tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP
+ dep_tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ "$CONFIG_INET" = "y" ]; then
bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
if [ "$CONFIG_HIPPI" = "y" -a "$CONFIG_PCI" = "y" ]; then
- tristate ' Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
+ dep_tristate ' Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER $CONFIG_PCI
if [ "$CONFIG_ROADRUNNER" != "n" ]; then
bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
fi
fi
fi
-if [ ! "$CONFIG_PARPORT" = "n" ]; then
- dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
-fi
+dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
if [ ! "$CONFIG_PPP" = "n" ]; then
/*
* linux/drivers/net/am79c961.c
*
- * by Russell King <rmk@arm.linux.org.uk> 1995-2000.
+ * by Russell King <rmk@arm.linux.org.uk> 1995-2001.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* Derived from various things including skeleton.c
*
* This is a special driver for the am79c961A Lance chip used in the
- * Intel (formally Digital Equipment Corp) EBSA110 platform.
+ * Intel (formally Digital Equipment Corp) EBSA110 platform. Please
+ * note that this can not be built as a module (it doesn't make sense).
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/ecard.h>
#define TX_BUFFERS 15
#define RX_BUFFERS 25
static unsigned int net_debug = NET_DEBUG;
-static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.02\n";
+static const char version[] =
+ "am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n";
/* --------------------------------------------------------------------------- */
#ifdef __arm__
-static void
-write_rreg (unsigned long base, unsigned int reg, unsigned short val)
+static void write_rreg(u_long base, u_int reg, u_int val)
{
__asm__("str%?h %1, [%2] @ NET_RAP
str%?h %0, [%2, #-4] @ NET_RDP
- " : : "r" (val), "r" (reg), "r" (0xf0000464));
+ " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
}
-static inline unsigned short
-read_rreg (unsigned int base_addr, unsigned int reg)
+static inline unsigned short read_rreg(u_long base_addr, u_int reg)
{
unsigned short v;
__asm__("str%?h %1, [%2] @ NET_RAP
ldr%?h %0, [%2, #-4] @ NET_RDP
- " : "=r" (v): "r" (reg), "r" (0xf0000464));
+ " : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
return v;
}
-static inline void
-write_ireg (unsigned long base, unsigned int reg, unsigned short val)
+static inline void write_ireg(u_long base, u_int reg, u_int val)
{
__asm__("str%?h %1, [%2] @ NET_RAP
str%?h %0, [%2, #8] @ NET_IDP
- " : : "r" (val), "r" (reg), "r" (0xf0000464));
+ " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
}
-#define am_writeword(dev,off,val)\
- __asm__("str%?h %0, [%1]" : : \
- "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
+#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
+#define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1))
static inline void
am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
{
- offset = 0xe0000000 + (offset << 1);
+ offset = ISAMEM_BASE + (offset << 1);
length = (length + 1) & ~1;
if ((int)buf & 2) {
__asm__ __volatile__("str%?h %2, [%0], #4"
}
}
-/*
- * This reads a 16-bit quantity in little-endian
- * mode from the am79c961 buffer.
- */
-static inline unsigned short am_readword(struct net_device *dev, u_int off)
-{
- unsigned long address = 0xe0000000 + (off << 1);
- unsigned short val;
-
- __asm__("ldr%?h %0, [%1]" : "=r" (val): "r" (address));
- return val;
-}
-
static inline void
am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
{
- offset = 0xe0000000 + (offset << 1);
+ offset = ISAMEM_BASE + (offset << 1);
length = (length + 1) & ~1;
if ((int)buf & 2) {
unsigned int tmp;
}
/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
+ * Open/initialize the board.
*/
static int
am79c961_open(struct net_device *dev)
}
/*
- * Get the current statistics. This may be called with the card open or
- * closed.
+ * Get the current statistics.
*/
static struct net_device_stats *am79c961_getstats (struct net_device *dev)
{
}
/*
- * Set or clear promiscuous/multicast mode filter for this adaptor.
+ * Set or clear promiscuous/multicast mode filter for this adapter.
*/
static void am79c961_setmulticastlist (struct net_device *dev)
{
* then the tx ring is full and we can't add another
* packet.
*/
- if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN) {
- printk(KERN_DEBUG"tx ring full, stopping queue\n");
+ if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
netif_stop_queue(dev);
- }
dev_kfree_skb(skb);
do {
u_int hdraddr;
u_int status;
-int bufnum;
-bufnum = priv->txtail;
hdraddr = priv->txhdr + (priv->txtail << 3);
status = am_readword (dev, hdraddr + 2);
if (status & TMD_OWN)
if (!dev)
goto out;
- SET_MODULE_OWNER(dev);
priv = dev->priv;
/*
/*
* Reset the device.
*/
- inb((dev->base_addr + NET_RESET) >> 1);
+ inb(dev->base_addr + NET_RESET);
udelay(5);
/*
* ether address.
*/
ret = -ENODEV;
- if (inb(dev->base_addr >> 1) != 0x08 ||
- inb((dev->base_addr >> 1) + 1) != 00 ||
- inb((dev->base_addr >> 1) + 2) != 0x2b)
+ if (inb(dev->base_addr) != 0x08 ||
+ inb(dev->base_addr + 2) != 0x00 ||
+ inb(dev->base_addr + 4) != 0x2b)
goto nodev;
if (!request_region(dev->base_addr, 0x18, dev->name))
goto nodev;
am79c961_banner();
- printk(KERN_INFO "%s: am79c961 found at %08lx, IRQ%d, ether address ",
- dev->name, dev->base_addr, dev->irq);
+ printk(KERN_INFO "%s: ether address ", dev->name);
/* Retrive and print the ethernet address. */
for (i = 0; i < 6; i++) {
- dev->dev_addr[i] = inb((dev->base_addr >> 1) + i) & 0xff;
+ dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
}
return ret;
}
-module_init(am79c961_init);
+__initcall(am79c961_init);
static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
+ struct ipddp_route rcp;
if(!capable(CAP_NET_ADMIN))
return -EPERM;
+ if(copy_from_user(&rcp, rt, sizeof(rcp)))
+ return -EFAULT;
+
switch(cmd)
{
case SIOCADDIPDDPRT:
- return (ipddp_create(rt));
+ return (ipddp_create(&rcp));
case SIOCFINDIPDDPRT:
- if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
+ if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route)))
return -EFAULT;
return 0;
case SIOCDELIPDDPRT:
- return (ipddp_delete(rt));
+ return (ipddp_delete(&rcp));
default:
return -EINVAL;
#include <asm/io.h>
#include <asm/dma.h>
+#if BITS_PER_LONG == 64
+#error FIXME: driver does not support 64-bit platforms
+#endif
+
/* Board/System/Debug information/definition ---------------- */
#define PCI_DM9132_ID 0x91321282 /* Davicom DM9132 ID */
u_long iobase = dev->base_addr;
int i, j, status = 0;
u_char csr;
- union {
+ union ewrk3_addr {
u_char addr[HASH_TABLE_LEN * ETH_ALEN];
u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
- } tmp;
+ };
+
+ union ewrk3_addr *tmp;
+
+ tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL);
+ if(tmp==NULL)
+ return -ENOMEM;
switch (ioc->cmd) {
case EWRK3_GET_HWADDR: /* Get the hardware address */
for (i = 0; i < ETH_ALEN; i++) {
- tmp.addr[i] = dev->dev_addr[i];
+ tmp->addr[i] = dev->dev_addr[i];
}
ioc->len = ETH_ALEN;
- if (copy_to_user(ioc->data, tmp.addr, ioc->len)) {
+ if (copy_to_user(ioc->data, tmp->addr, ioc->len))
status = -EFAULT;
- break;
- }
+ break;
+
case EWRK3_SET_HWADDR: /* Set the hardware address */
if (capable(CAP_NET_ADMIN)) {
- csr = inb(EWRK3_CSR);
- csr |= (CSR_TXD | CSR_RXD);
- outb(csr, EWRK3_CSR); /* Disable the TX and RX */
+ csr = inb(EWRK3_CSR);
+ csr |= (CSR_TXD | CSR_RXD);
+ outb(csr, EWRK3_CSR); /* Disable the TX and RX */
- if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) {
- status = -EFAULT;
- break;
- }
- for (i = 0; i < ETH_ALEN; i++) {
- dev->dev_addr[i] = tmp.addr[i];
- outb(tmp.addr[i], EWRK3_PAR0 + i);
- }
+ if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) {
+ status = -EFAULT;
+ break;
+ }
+ for (i = 0; i < ETH_ALEN; i++) {
+ dev->dev_addr[i] = tmp->addr[i];
+ outb(tmp->addr[i], EWRK3_PAR0 + i);
+ }
- csr &= ~(CSR_TXD | CSR_RXD); /* Enable the TX and RX */
- outb(csr, EWRK3_CSR);
+ csr &= ~(CSR_TXD | CSR_RXD); /* Enable the TX and RX */
+ outb(csr, EWRK3_CSR);
} else {
status = -EPERM;
}
status = -EPERM;
}
- break;
- case EWRK3_SAY_BOO: /* Say "Boo!" to the kernel log file */
- printk("%s: Boo!\n", dev->name);
-
break;
case EWRK3_GET_MCA: /* Get the multicast address table */
spin_lock_irq(&lp->hw_lock);
outb(0, EWRK3_IOPR);
outw(PAGE0_HTE, EWRK3_PIR1);
for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
- tmp.addr[i] = inb(EWRK3_DATA);
+ tmp->addr[i] = inb(EWRK3_DATA);
}
} else {
outb(0, EWRK3_MPR);
- isa_memcpy_fromio(tmp.addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
+ isa_memcpy_fromio(tmp->addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
}
spin_unlock_irq(&lp->hw_lock);
ioc->len = (HASH_TABLE_LEN >> 3);
- if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+ if (copy_to_user(ioc->data, tmp->addr, ioc->len))
status = -EFAULT;
break;
case EWRK3_SET_MCA: /* Set a multicast address */
if (capable(CAP_NET_ADMIN)) {
- if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) {
+ if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) {
status = -EFAULT;
break;
}
break;
case EWRK3_GET_CSR: /* Get the CSR Register contents */
- tmp.addr[0] = inb(EWRK3_CSR);
+ tmp->addr[0] = inb(EWRK3_CSR);
ioc->len = 1;
- if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+ if (copy_to_user(ioc->data, tmp->addr, ioc->len))
status = -EFAULT;
break;
case EWRK3_SET_CSR: /* Set the CSR Register contents */
if (capable(CAP_NET_ADMIN)) {
- if (copy_from_user(tmp.addr, ioc->data, 1)) {
+ if (copy_from_user(tmp->addr, ioc->data, 1)) {
status = -EFAULT;
break;
}
- outb(tmp.addr[0], EWRK3_CSR);
+ outb(tmp->addr[0], EWRK3_CSR);
} else {
status = -EPERM;
}
case EWRK3_GET_EEPROM: /* Get the EEPROM contents */
if (capable(CAP_NET_ADMIN)) {
for (i = 0; i < (EEPROM_MAX >> 1); i++) {
- tmp.val[i] = (short) Read_EEPROM(iobase, i);
+ tmp->val[i] = (short) Read_EEPROM(iobase, i);
}
i = EEPROM_MAX;
- tmp.addr[i++] = inb(EWRK3_CMR); /* Config/Management Reg. */
+ tmp->addr[i++] = inb(EWRK3_CMR); /* Config/Management Reg. */
for (j = 0; j < ETH_ALEN; j++) {
- tmp.addr[i++] = inb(EWRK3_PAR0 + j);
+ tmp->addr[i++] = inb(EWRK3_PAR0 + j);
}
ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
- if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+ if (copy_to_user(ioc->data, tmp->addr, ioc->len))
status = -EFAULT;
} else {
status = -EPERM;
break;
case EWRK3_SET_EEPROM: /* Set the EEPROM contents */
if (capable(CAP_NET_ADMIN)) {
- if (copy_from_user(tmp.addr, ioc->data, EEPROM_MAX)) {
+ if (copy_from_user(tmp->addr, ioc->data, EEPROM_MAX)) {
status = -EFAULT;
break;
}
for (i = 0; i < (EEPROM_MAX >> 1); i++) {
- Write_EEPROM(tmp.val[i], iobase, i);
+ Write_EEPROM(tmp->val[i], iobase, i);
}
} else {
status = -EPERM;
break;
case EWRK3_GET_CMR: /* Get the CMR Register contents */
- tmp.addr[0] = inb(EWRK3_CMR);
+ tmp->addr[0] = inb(EWRK3_CMR);
ioc->len = 1;
- if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+ if (copy_to_user(ioc->data, tmp->addr, ioc->len))
status = -EFAULT;
break;
case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */
default:
status = -EOPNOTSUPP;
}
-
+ kfree(tmp);
return status;
}
1 1 1 256
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
-#if defined(__powerpc__)
+#if defined(__powerpc__) || defined(__sparc__)
// 89/9/1 modify,
// np->bcrvalue=0x04 | 0x0x38; /* big-endian, 256 burst length */
np->bcrvalue = 0x04 | 0x10; /* big-endian, tx 8 burst length */
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
" resetting...\n", dev->name, readl(ioaddr + ISR));
-#ifndef __alpha__
{
int i;
- printk(KERN_DEBUG " Rx ring %8.8x: ", (int) np->rx_ring);
+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int) np->rx_ring[i].status);
- printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int) np->tx_ring);
+ printk("\n" KERN_DEBUG " Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" %4.4x", np->tx_ring[i].status);
printk("\n");
}
-#endif
/* Perhaps we should reinitialize the hardware here. Just trigger a
Tx demand for now. */
*/
static int bpq_check_devices(struct net_device *dev)
{
- struct bpqdev *bpq, *bpq_prev;
+ struct bpqdev *bpq, *bpq_prev, *bpq_next;
int result = 0;
unsigned long flags;
bpq_prev = NULL;
- for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) {
+ for (bpq = bpq_devices; bpq != NULL; bpq = bpq_next) {
+ bpq_next = bpq->next;
if (!dev_get(bpq->ethname)) {
if (bpq_prev)
bpq_prev->next = bpq->next;
unregister_netdevice(&bpq->axdev);
kfree(bpq);
}
-
- bpq_prev = bpq;
+ else
+ bpq_prev = bpq;
}
restore_flags(flags);
static unsigned char SCC_DriverName[] = "scc";
-static struct irqflags { unsigned char used : 1; } Ivec[16];
+static struct irqflags { unsigned char used : 1; } Ivec[NR_IRQS];
static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS]; /* information per channel */
printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2);
flag=" ";
- for (k = 0; k < 16; k++)
+ for (k = 0; k < NR_IRQS; k++)
if (Ivec[k].used)
{
printk("%s%d", flag, k);
if (hwcfg.irq == 2) hwcfg.irq = 9;
+ if (hwcfg.irq <0 || hwcfg.irq > NR_IRQS)
+ return -EINVAL;
+
if (!Ivec[hwcfg.irq].used && hwcfg.irq)
{
if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL))
}
}
- for (k=0; k < 16 ; k++)
+ for (k=0; k < NR_IRQS ; k++)
if (Ivec[k].used) free_irq(k, NULL);
if (Vector_Latch)
#ifdef __i386__
+#include <asm/msr.h>
+
/*
* only do 32bit cycle counter arithmetic; we hope we won't overflow.
* in fact, overflowing modems would require over 2THz CPU clock speeds :-)
#define time_exec(var,cmd) \
({ \
if (cpu_has_tsc) { \
- unsigned int cnt1, cnt2, cnt3; \
- __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \
+ unsigned int cnt1, cnt2; \
+ rdtscl(cnt1); \
cmd; \
- __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \
+ rdtscl(cnt2); \
var = cnt2-cnt1; \
} else { \
cmd; \
/* MCE and interface config reg */
write_codec(dev, 0x49, fdx ? 0x8 : 0xc);
outb(0xb, WSS_CODEC_IA(dev->base_addr)); /* leave MCE */
- if (SCSTATE->crystal && !fullcalib)
+ if (SCSTATE->crystal && !fullcalib) {
+ restore_flags(flags);
return 0;
+ }
/*
* wait for ACI start
*/
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
" resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr));
-#ifndef __alpha__
{
int i;
- printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring);
+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status);
- printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring);
+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" %4.4x", np->tx_ring[i].cmd_status);
printk("\n");
}
-#endif
spin_lock_irq(&np->lock);
natsemi_reset(dev);
drain_ring(dev);
shaper->dev->name,newskb->priority);
dev_queue_xmit(newskb);
- shaper->stats.tx_bytes+=newskb->len;
+ shaper->stats.tx_bytes += skb->len;
shaper->stats.tx_packets++;
if(sh_debug)
static void sis630_set_eq(struct net_device *net_dev, u8 revision)
{
struct sis900_private *sis_priv = net_dev->priv;
- u16 reg14h, eq_value, max_value=0, min_value=0;
+ u16 reg14h, eq_value=0, max_value=0, min_value=0;
u8 host_bridge_rev;
int i, maxcount=10;
struct pci_dev *dev=NULL;
printk(KERN_WARNING "%s: Transmit timed out, status %2.2x,"
" resetting...\n", dev->name, readb(ioaddr + TxStatus));
-#ifndef __alpha__
{
int i;
- printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring);
+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
- printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring);
+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" %4.4x", np->tx_ring[i].status);
printk("\n");
}
-#endif
/* Perhaps we should reinitialize the hardware here. */
dev->if_port = 0;
* 1. Multicast support.
*/
-#if defined(__alpha__) || defined(__ia64__)
-#error FIXME: driver does not support 64-bit platforms
-#endif
-
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#include <linux/skbuff.h>
#include <linux/trdevice.h>
+#if BITS_PER_LONG == 64
+#error FIXME: driver does not support 64-bit platforms
+#endif
+
#include "smctr.h" /* Our Stuff */
#include "smctr_firmware.h" /* SMC adapter firmware */
struct mixcom_privdata *hw = ch->HW_privdata;
struct proc_dir_entry *procfile = ch->procdir->subdir;
unsigned long flags;
+ int ret = -ENODEV;
- if (!dev->base_addr || !dev->irq) return -ENODEV;
+ if (!dev->base_addr || !dev->irq)
+ goto err_ret;
if(hw->channel==1) {
if(!TWIN(dev) || !(COMX_CHANNEL(TWIN(dev))->init_status &
IRQ_ALLOCATED)) {
printk(KERN_ERR "%s: channel 0 not yet initialized\n",dev->name);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto err_ret;
}
}
/* Is our hw present at all ? Not checking for channel 0 if it is already
open */
if(hw->channel!=0 || !(ch->init_status & IRQ_ALLOCATED)) {
- if (check_region(dev->base_addr, MIXCOM_IO_EXTENT)) {
- return -EAGAIN;
+ if (!request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name)) {
+ ret = -EAGAIN;
+ goto err_ret;
}
if (mixcom_probe(dev)) {
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_release_region;
}
}
- save_flags(flags); cli();
-
- if(hw->channel==1) {
- request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name);
- }
-
if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {
if (request_irq(dev->irq, MIXCOM_interrupt, 0,
dev->name, (void *)dev)) {
printk(KERN_ERR "MIXCOM: unable to obtain irq %d\n", dev->irq);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto err_release_region;
}
+ }
+
+ save_flags(flags); cli();
+
+ if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {
ch->init_status|=IRQ_ALLOCATED;
- request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name);
mixcom_board_on(dev);
}
}
return 0;
+
+err_restore_flags:
+ restore_flags(flags);
+err_release_region:
+ release_region(dev->base_addr, MIXCOM_IO_EXTENT);
+err_ret:
+ return ret;
}
static int MIXCOM_close(struct net_device *dev)
if (dev != fr->master) {
struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
+ if (!newskb)
+ return -ENOMEM;
newskb->dev=fr->master;
dev_queue_xmit(newskb);
ch->stats.tx_bytes += skb->len;
} else {
printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n",
entry->name);
- return -EBADF;
+ count = -EBADF;
}
free_page((unsigned long)page);
}
static struct comx_protocol fr_master_protocol = {
- "frad",
- VERSION,
- ARPHRD_FRAD,
- fr_master_init,
- fr_exit,
- NULL
+ name: "frad",
+ version: VERSION,
+ encap_type: ARPHRD_FRAD,
+ line_init: fr_master_init,
+ line_exit: fr_exit,
};
static struct comx_protocol fr_slave_protocol = {
- "ietf-ip",
- VERSION,
- ARPHRD_DLCI,
- fr_slave_init,
- fr_exit,
- NULL
+ name: "ietf-ip",
+ version: VERSION,
+ encap_type: ARPHRD_DLCI,
+ line_init: fr_slave_init,
+ line_exit: fr_exit,
};
static struct comx_hardware fr_dlci = {
- "dlci",
- VERSION,
- dlci_init,
- dlci_exit,
- dlci_dump,
- NULL
+ name: "dlci",
+ version: VERSION,
+ hw_init: dlci_init,
+ hw_exit: dlci_exit,
+ hw_dump: dlci_dump,
};
#ifdef MODULE
__get_user(code, &(d->code)))
return -EFAULT;
- if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE)
+ if (addr < 0 || addr > COSA_MAX_FIRMWARE_SIZE)
return -EINVAL;
- if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE)
+ if (len < 0 || len > COSA_MAX_FIRMWARE_SIZE)
return -EINVAL;
/* If something fails, force the user to reset the card */
cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_DOWNLOAD);
- if ((i=download(cosa, d->code, len, addr)) < 0) {
+ if ((i=download(cosa, code, len, addr)) < 0) {
printk(KERN_NOTICE "cosa%d: microcode download failed: %d\n",
cosa->num, i);
return -EIO;
*/
static int lapbeth_check_devices(struct net_device *dev)
{
- struct lapbethdev *lapbeth, *lapbeth_prev;
+ struct lapbethdev *lapbeth, *lapbeth_prev, *lapbeth_next;
int result = 0;
unsigned long flags;
lapbeth_prev = NULL;
- for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) {
+ for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth_next) {
+ lapbeth_next = lapbeth->next;
if (!dev_get(lapbeth->ethname)) {
if (lapbeth_prev)
lapbeth_prev->next = lapbeth->next;
dev_put(lapbeth->ethdev);
kfree(lapbeth);
}
-
- lapbeth_prev = lapbeth;
+ else
+ lapbeth_prev = lapbeth;
}
restore_flags(flags);
break;
}
- LMC_COPY_FROM_USER(data, xc.data, xc.len);
+ if(copy_from_user(data, xc.data, xc.len))
+ {
+ kfree(data);
+ ret = -ENOMEM;
+ break;
+ }
printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data);
static char *sppp_ipcp_type_name (u8 type);
static void sppp_print_bytes (u8 *p, u16 len);
-static int debug = 0;
+static int debug;
/*
}
/* Send Configure-Ack packet. */
sp->pp_loopcnt = 0;
- sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
- h->ident, len-4, h+1);
+ if (sp->lcp.state != LCP_STATE_OPENED) {
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+ h->ident, len-4, h+1);
+ }
/* Change the state. */
switch (sp->lcp.state) {
case LCP_STATE_CLOSED:
sp->ipcp.state = IPCP_STATE_CLOSED;
/* Initiate renegotiation. */
sppp_lcp_open (sp);
- /* An ACK has already been sent. */
+ /* Send ACK after our REQ in attempt to break loop */
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+ h->ident, len-4, h+1);
sp->lcp.state = LCP_STATE_ACK_SENT;
break;
}
return 0;
}
-
-struct packet_type sppp_packet_type=
-{
- 0,
- NULL,
- sppp_rcv,
- NULL,
- NULL
+struct packet_type sppp_packet_type = {
+ type: __constant_htons(ETH_P_WAN_PPP),
+ func: sppp_rcv,
};
-
+static const char banner[] __initdata =
+ KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"
+ KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & "
+ "Jan \"Yenya\" Kasprzak.\n";
static int __init sync_ppp_init(void)
{
if(debug)
debug=PP_DEBUG;
- printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n");
- printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n");
- sppp_packet_type.type=htons(ETH_P_WAN_PPP);
+ printk(banner);
dev_add_pack(&sppp_packet_type);
return 0;
}
C000 32 longwords 0400 4 longwords
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
-#if defined(__powerpc__) /* Big-endian */
+#if defined(__powerpc__) || defined(__sparc__) /* Big-endian */
writel(0x00100080 | 0xE010, ioaddr + PCIBusCfg);
#elif defined(__alpha__)
writel(0xE010, ioaddr + PCIBusCfg);
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
" resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
-#ifndef __alpha__
{
int i;
- printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring);
+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
- printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring);
+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" %8.8x", np->tx_ring[i].status);
printk("\n");
np->cur_tx, np->dirty_tx, np->tx_full,np->tx_q_bytes);
printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",readl(ioaddr+0x4C));
-#endif
spin_lock_irq(&np->lock);
/*
* Under high load dirty_tx and the internal tx descriptor pointer
{
long ioaddr = dev->base_addr;
struct netdev_private *np = dev->priv;
- int i;
netif_stop_queue(dev);
#ifdef __i386__
if (debug > 2) {
+ int i;
+
printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
(int)np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
/* Now clobber the whole thing */
if (size > sizeof(mode) - 1)
size = sizeof(mode) - 1;
- memset(&mode, sizeof(mode), 0);
+ memset(&mode, 0, sizeof(mode));
nubus_get_rsrc_mem(&mode, &ent, size);
printk (KERN_INFO " %02X: (%02X) %s\n", ent.type,
mode.id, mode.name);
Make tw_setfeature() call with interrupts disabled.
Register interrupt handler before enabling interrupts.
Clear attention interrupt before draining aen queue.
+ 1.02.00.005 - Allocate bounce buffers and custom queue depth for raid5 for
+ 6000 and 5000 series controllers.
+ Reduce polling mdelays causing problems on some systems.
+ Fix use_sg = 1 calculation bug.
+ Check for scsi_register returning NULL.
+ Add aen count to /proc/scsi/3w-xxxx.
+ Remove aen code unit masking in tw_aen_complete().
+ 1.02.00.006 - Remove unit from printk in tw_scsi_eh_abort(), causing
+ possible oops.
+ Fix possible null pointer dereference in tw_scsi_queue()
+ if done function pointer was invalid.
+ 1.02.00.007 - Fix possible null pointer dereferences in tw_ioctl().
+ Remove check for invalid done function pointer from
+ tw_scsi_queue().
*/
#include <linux/module.h>
};
/* Globals */
-char *tw_driver_version="1.02.00.004";
+char *tw_driver_version="1.02.00.007";
TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
int tw_device_extension_count = 0;
int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id)
{
TW_Param *param;
- unsigned short aen, aen_code;
+ unsigned short aen;
if (tw_dev->alignment_virtual_address[request_id] == NULL) {
printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n");
}
param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
aen = *(unsigned short *)(param->data);
- aen_code = (aen & 0x0ff);
- dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen_code);
+ dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen);
/* Now queue the code */
- tw_dev->aen_queue[tw_dev->aen_tail] = aen_code;
+ tw_dev->aen_queue[tw_dev->aen_tail] = aen;
if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
tw_dev->aen_tail = TW_Q_START;
} else {
/* Now poll for completion */
for (i=0;i<imax;i++) {
- mdelay(10);
+ mdelay(5);
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
return 1;
}
- if (which == 0) {
+ switch(which) {
+ case 0:
tw_dev->command_packet_virtual_address[request_id] = virt_addr;
- tw_dev->command_packet_physical_address[request_id] =
- virt_to_bus(virt_addr);
- } else {
+ tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
+ break;
+ case 1:
tw_dev->alignment_virtual_address[request_id] = virt_addr;
tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
+ break;
+ case 2:
+ tw_dev->bounce_buffer[request_id] = virt_addr;
+ break;
+ default:
+ printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
+ return 1;
}
return 0;
} /* End tw_allocate_memory() */
/* Register the card with the kernel SCSI layer */
host = scsi_register(tw_host, sizeof(TW_Device_Extension));
- if( host == NULL)
- {
+ if (host == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1);
release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
tw_free_device_extension(tw_dev);
kfree(tw_dev);
if (tw_dev->alignment_virtual_address[i])
kfree(tw_dev->alignment_virtual_address[i]);
+
+ if (tw_dev->bounce_buffer[i])
+ kfree(tw_dev->bounce_buffer[i]);
}
} /* End tw_free_device_extension() */
/* Poll for completion */
imax = TW_POLL_MAX_RETRIES;
for (i=0;i<imax;i++) {
- mdelay(10);
+ mdelay(5);
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
tw_dev->aen_queue[i] = 0;
}
- for (i=0;i<TW_MAX_UNITS;i++)
+ for (i=0;i<TW_MAX_UNITS;i++) {
tw_dev->is_unit_present[i] = 0;
+ tw_dev->is_raid_five[i] = 0;
+ }
tw_dev->num_units = 0;
tw_dev->num_aborts = 0;
tw_dev->aen_tail = 0;
tw_dev->sector_count = 0;
tw_dev->max_sector_count = 0;
+ tw_dev->aen_count = 0;
+ tw_dev->num_raid_five = 0;
spin_lock_init(&tw_dev->tw_lock);
tw_dev->flags = 0;
return 0;
unsigned char request_id = 0;
TW_Command *command_packet;
TW_Param *param;
- int i, imax, num_units = 0;
+ int i, j, imax, num_units = 0, num_raid_five = 0;
u32 status_reg_addr, status_reg_value;
u32 command_que_addr, command_que_value;
u32 response_que_addr;
TW_Response_Queue response_queue;
u32 param_value;
unsigned char *is_unit_present;
+ unsigned char *raid_level;
dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
/* Poll for completion */
imax = TW_POLL_MAX_RETRIES;
for(i=0; i<imax; i++) {
- mdelay(10);
+ mdelay(5);
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
printk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n");
return 1;
}
+
+ /* Find raid 5 arrays */
+ for (j=0;j<TW_MAX_UNITS;j++) {
+ if (tw_dev->is_unit_present[j] == 0)
+ continue;
+ command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+ if (command_packet == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
+ return 1;
+ }
+ memset(command_packet, 0, sizeof(TW_Sector));
+ command_packet->byte0.opcode = TW_OP_GET_PARAM;
+ command_packet->byte0.sgl_offset = 2;
+ command_packet->size = 4;
+ command_packet->request_id = request_id;
+ command_packet->byte3.unit = 0;
+ command_packet->byte3.host_id = 0;
+ command_packet->status = 0;
+ command_packet->flags = 0;
+ command_packet->byte6.block_count = 1;
+
+ /* Now setup the param */
+ if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
+ return 1;
+ }
+ param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+ memset(param, 0, sizeof(TW_Sector));
+ param->table_id = 0x300+j; /* unit summary table */
+ param->parameter_id = 0x6; /* unit descriptor */
+ param->parameter_size_bytes = 0xc;
+ param_value = tw_dev->alignment_physical_address[request_id];
+ if (param_value == 0) {
+ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
+ return 1;
+ }
+
+ command_packet->byte8.param.sgl[0].address = param_value;
+ command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+ /* Post the command packet to the board */
+ command_que_value = tw_dev->command_packet_physical_address[request_id];
+ if (command_que_value == 0) {
+ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
+ return 1;
+ }
+ outl(command_que_value, command_que_addr);
+
+ /* Poll for completion */
+ imax = TW_POLL_MAX_RETRIES;
+ for(i=0; i<imax; i++) {
+ mdelay(5);
+ status_reg_value = inl(status_reg_addr);
+ if (tw_check_bits(status_reg_value)) {
+ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
+ return 1;
+ }
+ if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+ response_queue.value = inl(response_que_addr);
+ request_id = (unsigned char)response_queue.u.response_id;
+ if (request_id != 0) {
+ /* unexpected request id */
+ printk(KERN_WARNING "3w-xxxx: tw_initia
+lize_units(): Unexpected request id.\n");
+ return 1;
+ }
+ if (command_packet->status != 0) {
+ /* bad response */
+ printk(KERN_WARNING "3w-xxxx: tw_initia
+lize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
+ return 1;
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (found == 0) {
+ /* response never received */
+ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No
+ response.\n");
+ return 1;
+ }
+
+ param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+ raid_level = (unsigned char *)&(param->data[1]);
+ if (*raid_level == 5) {
+ dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j);
+ tw_dev->is_raid_five[j] = 1;
+ num_raid_five++;
+ }
+ }
+ tw_dev->num_raid_five = num_raid_five;
+
+ /* Now allocate raid5 bounce buffers */
+ if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
+ for (i=0;i<TW_Q_LENGTH;i++) {
+ tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*256, 2);
+ if (tw_dev->bounce_buffer[i] == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bounce buffer allocation failed.\n");
+ return 1;
+ }
+ memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*256);
+ }
+ }
return 0;
} /* End tw_initialize_units() */
case TW_OP_SET_PARAM:
dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_SET_PARAM: table_id = %d, parameter_id = %d, parameter_size_bytes = %d.\n",
ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes);
- command_packet->byte0.opcode = TW_OP_SET_PARAM;
- param->table_id = ioctl->table_id;
- param->parameter_id = ioctl->parameter_id;
- param->parameter_size_bytes = ioctl->parameter_size_bytes;
- memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
- break;
+ if (ioctl->data != NULL) {
+ command_packet->byte0.opcode = TW_OP_SET_PARAM;
+ param->table_id = ioctl->table_id;
+ param->parameter_id = ioctl->parameter_id;
+ param->parameter_size_bytes = ioctl->parameter_size_bytes;
+ memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
+ break;
+ } else {
+ printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
+ return 1;
+ }
case TW_OP_AEN_LISTEN:
dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_AEN_LISTEN.\n");
if (tw_dev->aen_head == tw_dev->aen_tail) {
tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
return 0;
case TW_CMD_PACKET:
- memcpy(command_packet, ioctl->data, sizeof(TW_Command));
- command_packet->request_id = request_id;
- tw_post_command_packet(tw_dev, request_id);
-
- return 0;
+ if (ioctl->data != NULL) {
+ memcpy(command_packet, ioctl->data, sizeof(TW_Command));
+ command_packet->request_id = request_id;
+ tw_post_command_packet(tw_dev, request_id);
+ return 0;
+ } else {
+ printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
+ return 1;
+ }
default:
printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
tw_dev->state[request_id] = TW_S_COMPLETED;
return 0;
}
- spin_unlock_irq(&io_request_lock);
ret = tw_findcards(tw_host);
- spin_lock_irq(&io_request_lock);
-
+
return ret;
} /* End tw_scsi_detect() */
tw_copy_info(&info, "Max sector count: %3d\n", tw_dev->max_sector_count);
tw_copy_info(&info, "Resets: %3d\n", tw_dev->num_resets);
tw_copy_info(&info, "Aborts: %3d\n", tw_dev->num_aborts);
+ tw_copy_info(&info, "AEN's: %3d\n", tw_dev->aen_count);
}
if (info.position > info.offset) {
return (info.position - info.offset);
int flags = 0;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata;
+ if (tw_dev == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n");
+ SCpnt->result = (DID_ERROR << 16);
+ done(SCpnt);
+ return 0;
+ }
+
spin_lock_irqsave(&tw_dev->tw_lock, flags);
dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
return 0;
}
- if (done == NULL) {
- printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid done function.\n");
- SCpnt->result = (DID_ERROR << 16);
- done(SCpnt);
- spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
- return 0;
- }
- if (tw_dev == NULL) {
- printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n");
- SCpnt->result = (DID_ERROR << 16);
- done(SCpnt);
- spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
- return 0;
- }
/* Save done function into Scsi_Cmnd struct */
SCpnt->scsi_done = done;
TW_Command *command_packet;
u32 command_que_addr, command_que_value = 0;
u32 lba = 0x0, num_sectors = 0x0;
- int i;
+ int i, count = 0;
Scsi_Cmnd *srb;
struct scatterlist *sglist;
command_packet->byte8.io.lba = lba;
command_packet->byte6.block_count = num_sectors;
- /* Do this if there are no sg list entries */
- if (tw_dev->srb[request_id]->use_sg == 0) {
- dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
- command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
- command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
- }
+ if ((tw_dev->is_raid_five[tw_dev->srb[request_id]->target] == 0) || (srb->cmnd[0] == READ_6) || (srb->cmnd[0] == READ_10) || (tw_dev->tw_pci_dev->device == TW_DEVICE_ID2)) {
+ /* Do this if there are no sg list entries */
+ if (tw_dev->srb[request_id]->use_sg == 0) {
+ dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
+ command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
+ command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+ }
- /* Do this if we have multiple sg list entries */
- if (tw_dev->srb[request_id]->use_sg > 0) {
- for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
- command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
- command_packet->byte8.io.sgl[i].length = sglist[i].length;
- command_packet->size+=2;
+ /* Do this if we have multiple sg list entries */
+ if (tw_dev->srb[request_id]->use_sg > 0) {
+ for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
+ command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
+ command_packet->byte8.io.sgl[i].length = sglist[i].length;
+ command_packet->size+=2;
+ }
+ if (tw_dev->srb[request_id]->use_sg >= 1)
+ command_packet->size-=2;
}
- if (tw_dev->srb[request_id]->use_sg > 1)
- command_packet->size-=2;
- }
+ } else {
+ /* Do this if there are no sg list entries for raid 5 */
+ if (tw_dev->srb[request_id]->use_sg == 0) {
+ dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
+ memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
+ command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+ command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+ }
+
+ /* Do this if we have multiple sg list entries for raid 5 */
+ if (tw_dev->srb[request_id]->use_sg > 0) {
+ dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
+ for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
+ memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
+ count+=sglist[i].length;
+ }
+ command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+ command_packet->byte8.io.sgl[0].length = count;
+ command_packet->size = 5; /* single sgl */
+ }
+ }
/* Update SG statistics */
tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
/* Poll for completion */
imax = TW_POLL_MAX_RETRIES;
for (i=0;i<imax;i++) {
- mdelay(10);
+ mdelay(5);
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
#define TW_COMMAND_ALIGNMENT_MASK 0x1ff
#define TW_INIT_MESSAGE_CREDITS 0x100
#define TW_INIT_COMMAND_PACKET_SIZE 0x3
-#define TW_POLL_MAX_RETRIES 10000
+#define TW_POLL_MAX_RETRIES 20000
#define TW_MAX_SGL_LENGTH 62
-#define TW_Q_LENGTH 256
+#define TW_Q_LENGTH 16
#define TW_Q_START 0
#define TW_MAX_SLOT 32
#define TW_MAX_PCI_BUSES 255
TW_Registers registers;
u32 *alignment_virtual_address[TW_Q_LENGTH];
u32 alignment_physical_address[TW_Q_LENGTH];
+ u32 *bounce_buffer[TW_Q_LENGTH];
int is_unit_present[TW_MAX_UNITS];
+ int is_raid_five[TW_MAX_UNITS];
int num_units;
+ int num_raid_five;
u32 *command_packet_virtual_address[TW_Q_LENGTH];
u32 command_packet_physical_address[TW_Q_LENGTH];
struct pci_dev *tw_pci_dev;
u32 num_resets;
u32 sector_count;
u32 max_sector_count;
+ u32 aen_count;
struct Scsi_Host *host;
spinlock_t tw_lock;
unsigned char ioctl_size[TW_Q_LENGTH];
}
-static void wait_intr() {
+static void wait_intr(void) {
int i = jiffies + WATCHDOG;
while(time_after(i,jiffies) && !(inb(STAT_REG)&0xe0)) /* wait for a pseudo-interrupt */
}
#ifndef IRQ_LEV
-static int irq_probe()
+static int irq_probe(void)
{
int irqs, irq;
int i;
}
#endif /* IRQ_LEV */
-static void chip_init()
+static void chip_init(void)
{
REG1;
#if USE_DMA
if (!HOSTDATA(shpnt)->commands)
SETPORT(PORTA, 0); /* turn led off */
- kfree(DONE_SC->host_scribble);
- DONE_SC->host_scribble=0;
-
DO_UNLOCK(flags);
DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC);
DONE_SC->scsi_done(DONE_SC);
DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC);
DO_LOCK(flags);
+
+ kfree(DONE_SC->host_scribble);
+ DONE_SC->host_scribble=0;
}
DONE_SC=0;
if (!ptr->device->soft_reset) {
remove_SC(&DISCONNECTED_SC, ptr);
- kfree(ptr->host_scribble);
- ptr->host_scribble=0;
-
ptr->result = DID_RESET << 16;
ptr->scsi_done(ptr);
+
+ kfree(ptr->host_scribble);
+ ptr->host_scribble=0;
}
ptr = next;
struct pci_dev *pdev = NULL;
if (!pci_present()) {
- dmx3191d_printk("PCI support not enabled\n");
+ printk(KERN_WARNING "dmx3191: PCI support not enabled\n");
return 0;
}
port = pci_resource_start (pdev, 0);
if (!request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME)) {
- dmx3191d_printk("region 0x%lx-0x%lx already reserved\n",
+ printk(KERN_ERR "dmx3191: region 0x%lx-0x%lx already reserved\n",
port, port + DMX3191D_REGION);
continue;
}
if (request_irq(pdev->irq, dmx3191d_do_intr, SA_SHIRQ,
DMX3191D_DRIVER_NAME, instance)) {
- dmx3191d_printk("irq %d not available\n", pdev->irq);
+ printk(KERN_WARNING "dmx3191: IRQ %d not available - switching to polled mode.\n", pdev->irq);
/* Steam powered scsi controllers run without an IRQ
anyway */
instance->irq = IRQ_NONE;
#define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001
#endif
-#define dmx3191d_printk( args... ) printk(__FILE__": " ##args)
-
#ifndef ASM
int dmx3191d_abort(Scsi_Cmnd *);
int dmx3191d_detect(Scsi_Host_Template *);
DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
cmd->result = DID_OK << 16;
done(cmd);
+ restore_flags(flags);
return(0);
}
retval->loaded_as_module = 1;
if (flag_new) {
shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
+ if (!shn) {
+ kfree(retval);
+ printk(KERN_ERR "scsi: out of memory(2) in scsi_register.\n");
+ return NULL;
+ }
shn->name = kmalloc(hname_len + 1, GFP_ATOMIC);
if (hname_len > 0)
strncpy(shn->name, hname, hname_len);
if(test_and_set_bit(QLA1280_IN_ISR_BIT, &ha->flags))
{
COMTRACE('X')
+ spin_unlock_irqrestore(&io_request_lock, cpu_flags);
return;
}
ha->isr_count++;
char * page;
char *start;
+ if (hpnt->hostt->proc_info == NULL)
+ ret = -ENOSYS;
+
if (count > PROC_BLOCK_SIZE)
return -EOVERFLOW;
return -EFAULT;
}
- if (hpnt->hostt->proc_info == NULL)
- ret = -ENOSYS;
- else
- ret = hpnt->hostt->proc_info(page, &start, 0, count,
- hpnt->host_no, 1);
+ ret = hpnt->hostt->proc_info(page, &start, 0, count,
+ hpnt->host_no, 1);
+
free_page((ulong) page);
return(ret);
}
char name[10]; /* see scsi_unregister_host() */
tpnt->proc_dir = proc_mkdir(tpnt->proc_name, proc_scsi);
+ if (!tpnt->proc_dir) {
+ printk(KERN_ERR "Unable to proc_mkdir in scsi.c/build_proc_dir_entries");
+ return;
+ }
tpnt->proc_dir->owner = tpnt->module;
hpnt = scsi_hostlist;
* Changes :
*
* Marcelo Tosatti <marcelo@conectiva.com.br> : Added io_request_lock locking
+ * Alan Cox <alan@redhat.com> : Cleaned up code formatting
+ * Fixed an irq locking bug
+ * Added ISAPnP support
*
* LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>]
*
#include <asm/io.h>
#include <linux/blk.h>
#include <linux/version.h>
+#include <linux/isapnp.h>
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
#include "sym53c416.h"
-#define VERSION_STRING "Version 1.0.0"
+#define VERSION_STRING "Version 1.0.0-ac"
#define TC_LOW 0x00 /* Transfer counter low */
#define TC_MID 0x01 /* Transfer counter mid */
#define MAXHOSTS 4
enum phases
- {
- idle,
- data_out,
- data_in,
- command_ph,
- status_ph,
- message_out,
- message_in
- };
+{
+ idle,
+ data_out,
+ data_in,
+ command_ph,
+ status_ph,
+ message_out,
+ message_in
+};
typedef struct
- {
- int base;
- int irq;
- int scsi_id;
- } host;
+{
+ int base;
+ int irq;
+ int scsi_id;
+} host;
-host hosts[MAXHOSTS] = {
+static host hosts[MAXHOSTS] = {
{0, 0, SYM53C416_SCSI_ID},
{0, 0, SYM53C416_SCSI_ID},
{0, 0, SYM53C416_SCSI_ID},
};
static int host_index = 0;
-
static char info[120];
-
static Scsi_Cmnd *current_command = NULL;
+static int fastpio = 1;
-int fastpio = 1;
-
-int probeaddrs[] = {0x200, 0x220, 0x240, 0};
+static int probeaddrs[] = {0x200, 0x220, 0x240, 0};
static void sym53c416_set_transfer_counter(int base, unsigned int len)
- {
- /* Program Transfer Counter */
- outb(len & 0x0000FF, base + TC_LOW);
- outb((len & 0x00FF00) >> 8, base + TC_MID);
- outb((len & 0xFF0000) >> 16, base + TC_HIGH);
- }
+{
+ /* Program Transfer Counter */
+ outb(len & 0x0000FF, base + TC_LOW);
+ outb((len & 0x00FF00) >> 8, base + TC_MID);
+ outb((len & 0xFF0000) >> 16, base + TC_HIGH);
+}
/* Returns the number of bytes read */
static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len)
- {
- unsigned int orig_len = len;
- unsigned long flags = 0;
- unsigned int bytes_left;
- int i;
- int timeout = READ_TIMEOUT;
-
- /* Do transfer */
- save_flags(flags);
- cli();
- while(len && timeout)
- {
- bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
- if(fastpio && bytes_left > 3)
- {
- insl(base + PIO_FIFO_1, buffer, bytes_left >> 2);
- buffer += bytes_left & 0xFC;
- len -= bytes_left & 0xFC;
- }
- else if(bytes_left > 0)
- {
- len -= bytes_left;
- for(; bytes_left > 0; bytes_left--)
- *(buffer++) = inb(base + PIO_FIFO_1);
- }
- else
- {
- i = jiffies + timeout;
- restore_flags(flags);
- while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
- if(inb(base + PIO_INT_REG) & SCI)
- timeout = 0;
- save_flags(flags);
- cli();
- if(inb(base + PIO_INT_REG) & EMPTY)
- timeout = 0;
- }
- }
- restore_flags(flags);
- return orig_len - len;
- }
+{
+ unsigned int orig_len = len;
+ unsigned long flags = 0;
+ unsigned int bytes_left;
+ int i;
+ int timeout = READ_TIMEOUT;
+
+ /* Do transfer */
+ save_flags(flags);
+ cli();
+ while(len && timeout)
+ {
+ bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
+ if(fastpio && bytes_left > 3)
+ {
+ insl(base + PIO_FIFO_1, buffer, bytes_left >> 2);
+ buffer += bytes_left & 0xFC;
+ len -= bytes_left & 0xFC;
+ }
+ else if(bytes_left > 0)
+ {
+ len -= bytes_left;
+ for(; bytes_left > 0; bytes_left--)
+ *(buffer++) = inb(base + PIO_FIFO_1);
+ }
+ else
+ {
+ i = jiffies + timeout;
+ restore_flags(flags);
+ while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
+ if(inb(base + PIO_INT_REG) & SCI)
+ timeout = 0;
+ save_flags(flags);
+ cli();
+ if(inb(base + PIO_INT_REG) & EMPTY)
+ timeout = 0;
+ }
+ }
+ restore_flags(flags);
+ return orig_len - len;
+}
/* Returns the number of bytes written */
static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len)
- {
- unsigned int orig_len = len;
- unsigned long flags = 0;
- unsigned int bufferfree;
- unsigned int i;
- unsigned int timeout = WRITE_TIMEOUT;
-
- /* Do transfer */
- save_flags(flags);
- cli();
- while(len && timeout)
- {
- bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
- if(bufferfree > len)
- bufferfree = len;
- if(fastpio && bufferfree > 3)
- {
- outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2);
- buffer += bufferfree & 0xFC;
- len -= bufferfree & 0xFC;
- }
- else if(bufferfree > 0)
- {
- len -= bufferfree;
- for(; bufferfree > 0; bufferfree--)
- outb(*(buffer++), base + PIO_FIFO_1);
- }
- else
- {
- i = jiffies + timeout;
- restore_flags(flags);
- while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout)
- ;
- save_flags(flags);
- cli();
- if(inb(base + PIO_INT_REG) & FULL)
- timeout = 0;
- }
- }
- restore_flags(flags);
- return orig_len - len;
- }
+{
+ unsigned int orig_len = len;
+ unsigned long flags = 0;
+ unsigned int bufferfree;
+ unsigned int i;
+ unsigned int timeout = WRITE_TIMEOUT;
+
+ /* Do transfer */
+ save_flags(flags);
+ cli();
+ while(len && timeout)
+ {
+ bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
+ if(bufferfree > len)
+ bufferfree = len;
+ if(fastpio && bufferfree > 3)
+ {
+ outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2);
+ buffer += bufferfree & 0xFC;
+ len -= bufferfree & 0xFC;
+ }
+ else if(bufferfree > 0)
+ {
+ len -= bufferfree;
+ for(; bufferfree > 0; bufferfree--)
+ outb(*(buffer++), base + PIO_FIFO_1);
+ }
+ else
+ {
+ i = jiffies + timeout;
+ restore_flags(flags);
+ while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout)
+ ;
+ save_flags(flags);
+ cli();
+ if(inb(base + PIO_INT_REG) & FULL)
+ timeout = 0;
+ }
+ }
+ restore_flags(flags);
+ return orig_len - len;
+}
static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
- {
- int base = 0;
- int i;
- unsigned long flags = 0;
- unsigned char status_reg, pio_int_reg, int_reg;
- struct scatterlist *sglist;
- unsigned int sgcount;
- unsigned int tot_trans = 0;
-
- /* We search the base address of the host adapter which caused the interrupt */
- for(i = 0; i < host_index && !base; i++)
- if(irq == hosts[i].irq)
- base = hosts[i].base;
- /* If no adapter found, we cannot handle the interrupt. Leave a message */
- /* and continue. This should never happen... */
- if(!base)
- {
- printk("sym53c416: No host adapter defined for interrupt %d\n", irq);
- return;
- }
- /* Now we have the base address and we can start handling the interrupt */
- save_flags(flags);
- cli();
- status_reg = inb(base + STATUS_REG);
- pio_int_reg = inb(base + PIO_INT_REG);
- int_reg = inb(base + INT_REG);
- restore_flags(flags);
-
- /* First, we handle error conditions */
- if(int_reg & SCI) /* SCSI Reset */
- {
- printk("sym53c416: Warning: Reset received\n");
- current_command->SCp.phase = idle;
- current_command->result = DID_RESET << 16;
- spin_lock_irqsave(&io_request_lock, flags);
- current_command->scsi_done(current_command);
- spin_unlock_irqrestore(&io_request_lock, flags);
- return;
- }
- if(int_reg & ILCMD) /* Illegal Command */
- {
- printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG));
- current_command->SCp.phase = idle;
- current_command->result = DID_ERROR << 16;
- spin_lock_irqsave(&io_request_lock, flags);
- current_command->scsi_done(current_command);
- spin_unlock_irqrestore(&io_request_lock, flags);
- return;
- }
- if(status_reg & GE) /* Gross Error */
- {
- printk("sym53c416: Warning: Gross Error\n");
- current_command->SCp.phase = idle;
- current_command->result = DID_ERROR << 16;
- spin_lock_irqsave(&io_request_lock, flags);
- current_command->scsi_done(current_command);
- spin_unlock_irqrestore(&io_request_lock, flags);
- return;
- }
- if(status_reg & PE) /* Parity Error */
- {
- printk("sym53c416: Warning: Parity Error\n");
- current_command->SCp.phase = idle;
- current_command->result = DID_PARITY << 16;
- spin_lock_irqsave(&io_request_lock, flags);
- current_command->scsi_done(current_command);
- spin_unlock_irqrestore(&io_request_lock, flags);
- return;
- }
- if(pio_int_reg & (CE | OUE))
- {
- printk("sym53c416: Warning: PIO Interrupt Error\n");
- current_command->SCp.phase = idle;
- current_command->result = DID_ERROR << 16;
- spin_lock_irqsave(&io_request_lock, flags);
- current_command->scsi_done(current_command);
- spin_unlock_irqrestore(&io_request_lock, flags);
- return;
- }
- if(int_reg & DIS) /* Disconnect */
- {
- if(current_command->SCp.phase != message_in)
- current_command->result = DID_NO_CONNECT << 16;
- else
- current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
- current_command->SCp.phase = idle;
-
- spin_lock_irqsave(&io_request_lock, flags);
- current_command->scsi_done(current_command);
- spin_unlock_irqrestore(&io_request_lock, flags);
- return;
- }
- /* Now we handle SCSI phases */
- switch(status_reg & PHBITS) /* Filter SCSI phase out of status reg */
- {
- case PHASE_DATA_OUT:
- {
- if(int_reg & BS)
- {
- current_command->SCp.phase = data_out;
- outb(FLUSH_FIFO, base + COMMAND_REG);
- sym53c416_set_transfer_counter(base, current_command->request_bufflen);
- outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
- if(!current_command->use_sg)
- tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
- else
- {
- sgcount = current_command->use_sg;
- sglist = current_command->request_buffer;
- while(sgcount--)
- {
- tot_trans += sym53c416_write(base, sglist->address, sglist->length);
- sglist++;
- }
- }
- if(tot_trans < current_command->underflow)
- printk("sym53c416: Warning: underflow, wrote %d bytes, request for %d bytes\n", tot_trans, current_command->underflow);
- }
- break;
- }
- case PHASE_DATA_IN:
- {
- if(int_reg & BS)
- {
- current_command->SCp.phase = data_in;
- outb(FLUSH_FIFO, base + COMMAND_REG);
- sym53c416_set_transfer_counter(base, current_command->request_bufflen);
- outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
- if(!current_command->use_sg)
- tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
- else
- {
- sgcount = current_command->use_sg;
- sglist = current_command->request_buffer;
- while(sgcount--)
- {
- tot_trans += sym53c416_read(base, sglist->address, sglist->length);
- sglist++;
- }
- }
- if(tot_trans < current_command->underflow)
- printk("sym53c416: Warning: underflow, read %d bytes, request for %d bytes\n", tot_trans, current_command->underflow);
- }
- break;
- }
- case PHASE_COMMAND:
- {
- current_command->SCp.phase = command_ph;
- printk("sym53c416: Warning: Unknown interrupt in command phase\n");
- break;
- }
- case PHASE_STATUS:
- {
- current_command->SCp.phase = status_ph;
- outb(FLUSH_FIFO, base + COMMAND_REG);
- outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG);
- break;
- }
- case PHASE_RESERVED_1:
- case PHASE_RESERVED_2:
- {
- printk("sym53c416: Warning: Reserved phase\n");
- break;
- }
- case PHASE_MESSAGE_OUT:
- {
- current_command->SCp.phase = message_out;
- outb(SET_ATN, base + COMMAND_REG);
- outb(MSG_ACCEPTED, base + COMMAND_REG);
- break;
- }
- case PHASE_MESSAGE_IN:
- {
- current_command->SCp.phase = message_in;
- current_command->SCp.Status = inb(base + SCSI_FIFO);
- current_command->SCp.Message = inb(base + SCSI_FIFO);
- if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT)
- outb(SET_ATN, base + COMMAND_REG);
- outb(MSG_ACCEPTED, base + COMMAND_REG);
- break;
- }
- }
- }
+{
+ int base = 0;
+ int i;
+ unsigned long flags = 0;
+ unsigned char status_reg, pio_int_reg, int_reg;
+ struct scatterlist *sglist;
+ unsigned int sgcount;
+ unsigned int tot_trans = 0;
+
+ /* We search the base address of the host adapter which caused the interrupt */
+ /* FIXME: should pass dev_id sensibly as hosts[i] */
+ for(i = 0; i < host_index && !base; i++)
+ if(irq == hosts[i].irq)
+ base = hosts[i].base;
+ /* If no adapter found, we cannot handle the interrupt. Leave a message */
+ /* and continue. This should never happen... */
+ if(!base)
+ {
+ printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq);
+ return;
+ }
+ /* Now we have the base address and we can start handling the interrupt */
+
+ spin_lock_irqsave(&io_request_lock,flags);
+ status_reg = inb(base + STATUS_REG);
+ pio_int_reg = inb(base + PIO_INT_REG);
+ int_reg = inb(base + INT_REG);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+
+ /* First, we handle error conditions */
+ if(int_reg & SCI) /* SCSI Reset */
+ {
+ printk(KERN_DEBUG "sym53c416: Reset received\n");
+ current_command->SCp.phase = idle;
+ current_command->result = DID_RESET << 16;
+ spin_lock_irqsave(&io_request_lock, flags);
+ current_command->scsi_done(current_command);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+ if(int_reg & ILCMD) /* Illegal Command */
+ {
+ printk(KERN_WARNING "sym53c416: Illegal Command: 0x%02x.\n", inb(base + COMMAND_REG));
+ current_command->SCp.phase = idle;
+ current_command->result = DID_ERROR << 16;
+ spin_lock_irqsave(&io_request_lock, flags);
+ current_command->scsi_done(current_command);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+ if(status_reg & GE) /* Gross Error */
+ {
+ printk(KERN_WARNING "sym53c416: Controller reports gross error.\n");
+ current_command->SCp.phase = idle;
+ current_command->result = DID_ERROR << 16;
+ spin_lock_irqsave(&io_request_lock, flags);
+ current_command->scsi_done(current_command);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+ if(status_reg & PE) /* Parity Error */
+ {
+ printk(KERN_WARNING "sym53c416:SCSI parity error.\n");
+ current_command->SCp.phase = idle;
+ current_command->result = DID_PARITY << 16;
+ spin_lock_irqsave(&io_request_lock, flags);
+ current_command->scsi_done(current_command);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+ if(pio_int_reg & (CE | OUE))
+ {
+ printk(KERN_WARNING "sym53c416: PIO interrupt error.\n");
+ current_command->SCp.phase = idle;
+ current_command->result = DID_ERROR << 16;
+ spin_lock_irqsave(&io_request_lock, flags);
+ current_command->scsi_done(current_command);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+ if(int_reg & DIS) /* Disconnect */
+ {
+ if(current_command->SCp.phase != message_in)
+ current_command->result = DID_NO_CONNECT << 16;
+ else
+ current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
+ current_command->SCp.phase = idle;
+ spin_lock_irqsave(&io_request_lock, flags);
+ current_command->scsi_done(current_command);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+ /* Now we handle SCSI phases */
+
+ switch(status_reg & PHBITS) /* Filter SCSI phase out of status reg */
+ {
+ case PHASE_DATA_OUT:
+ {
+ if(int_reg & BS)
+ {
+ current_command->SCp.phase = data_out;
+ outb(FLUSH_FIFO, base + COMMAND_REG);
+ sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+ outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+ if(!current_command->use_sg)
+ tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
+ else
+ {
+ sgcount = current_command->use_sg;
+ sglist = current_command->request_buffer;
+ while(sgcount--)
+ {
+ tot_trans += sym53c416_write(base, sglist->address, sglist->length);
+ sglist++;
+ }
+ }
+ if(tot_trans < current_command->underflow)
+ printk(KERN_WARNING "sym53c416: Underflow, wrote %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
+ }
+ break;
+ }
+
+ case PHASE_DATA_IN:
+ {
+ if(int_reg & BS)
+ {
+ current_command->SCp.phase = data_in;
+ outb(FLUSH_FIFO, base + COMMAND_REG);
+ sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+ outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+ if(!current_command->use_sg)
+ tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
+ else
+ {
+ sgcount = current_command->use_sg;
+ sglist = current_command->request_buffer;
+ while(sgcount--)
+ {
+ tot_trans += sym53c416_read(base, sglist->address, sglist->length);
+ sglist++;
+ }
+ }
+ if(tot_trans < current_command->underflow)
+ printk(KERN_WARNING "sym53c416: Underflow, read %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
+ }
+ break;
+ }
+
+ case PHASE_COMMAND:
+ {
+ current_command->SCp.phase = command_ph;
+ printk(KERN_ERR "sym53c416: Unknown interrupt in command phase.\n");
+ break;
+ }
+
+ case PHASE_STATUS:
+ {
+ current_command->SCp.phase = status_ph;
+ outb(FLUSH_FIFO, base + COMMAND_REG);
+ outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG);
+ break;
+ }
+
+ case PHASE_RESERVED_1:
+ case PHASE_RESERVED_2:
+ {
+ printk(KERN_ERR "sym53c416: Reserved phase occurred.\n");
+ break;
+ }
+
+ case PHASE_MESSAGE_OUT:
+ {
+ current_command->SCp.phase = message_out;
+ outb(SET_ATN, base + COMMAND_REG);
+ outb(MSG_ACCEPTED, base + COMMAND_REG);
+ break;
+ }
+
+ case PHASE_MESSAGE_IN:
+ {
+ current_command->SCp.phase = message_in;
+ current_command->SCp.Status = inb(base + SCSI_FIFO);
+ current_command->SCp.Message = inb(base + SCSI_FIFO);
+ if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT)
+ outb(SET_ATN, base + COMMAND_REG);
+ outb(MSG_ACCEPTED, base + COMMAND_REG);
+ break;
+ }
+ }
+}
static void sym53c416_init(int base, int scsi_id)
- {
- outb(RESET_CHIP, base + COMMAND_REG);
- outb(NOOP, base + COMMAND_REG);
- outb(0x99, base + TOM); /* Time out of 250 ms */
- outb(0x05, base + STP);
- outb(0x00, base + SYNC_OFFSET);
- outb(EPC | scsi_id, base + CONF_REG_1);
- outb(FE | SCSI2 | TBPA, base + CONF_REG_2);
- outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3);
- outb(0x83 | EAN, base + CONF_REG_4);
- outb(IE | WSE0, base + CONF_REG_5);
- outb(0, base + FEATURE_EN);
- }
+{
+ outb(RESET_CHIP, base + COMMAND_REG);
+ outb(NOOP, base + COMMAND_REG);
+ outb(0x99, base + TOM); /* Time out of 250 ms */
+ outb(0x05, base + STP);
+ outb(0x00, base + SYNC_OFFSET);
+ outb(EPC | scsi_id, base + CONF_REG_1);
+ outb(FE | SCSI2 | TBPA, base + CONF_REG_2);
+ outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3);
+ outb(0x83 | EAN, base + CONF_REG_4);
+ outb(IE | WSE0, base + CONF_REG_5);
+ outb(0, base + FEATURE_EN);
+}
static int sym53c416_probeirq(int base, int scsi_id)
- {
- int irq, irqs, i;
-
- /* Clear interrupt register */
- inb(base + INT_REG);
- /* Start probing for irq's */
- irqs = probe_irq_on();
- /* Reinit chip */
- sym53c416_init(base, scsi_id);
- /* Cause interrupt */
- outb(NOOP, base + COMMAND_REG);
- outb(ILLEGAL, base + COMMAND_REG);
- outb(0x07, base + DEST_BUS_ID);
- outb(0x00, base + DEST_BUS_ID);
- /* Wait for interrupt to occur */
- i = jiffies + 20;
- while(i > jiffies && !(inb(base + STATUS_REG) & SCI))
- barrier();
- if(i <= jiffies) /* timed out */
- return 0;
- /* Get occurred irq */
- irq = probe_irq_off(irqs);
- sym53c416_init(base, scsi_id);
- return irq;
- }
+{
+ int irq, irqs, i;
+
+ /* Clear interrupt register */
+ inb(base + INT_REG);
+ /* Start probing for irq's */
+ irqs = probe_irq_on();
+ /* Reinit chip */
+ sym53c416_init(base, scsi_id);
+ /* Cause interrupt */
+ outb(NOOP, base + COMMAND_REG);
+ outb(ILLEGAL, base + COMMAND_REG);
+ outb(0x07, base + DEST_BUS_ID);
+ outb(0x00, base + DEST_BUS_ID);
+ /* Wait for interrupt to occur */
+ i = jiffies + 20;
+ while(i > jiffies && !(inb(base + STATUS_REG) & SCI))
+ barrier();
+ if(i <= jiffies) /* timed out */
+ return 0;
+ /* Get occurred irq */
+ irq = probe_irq_off(irqs);
+ sym53c416_init(base, scsi_id);
+ return irq;
+}
/* Setup: sym53c416=base,irq */
void sym53c416_setup(char *str, int *ints)
- {
- int i;
-
- if(host_index >= MAXHOSTS)
- {
- printk("sym53c416.c: Too many hosts defined\n");
- }
- else
- {
- if(ints[0] < 1 || ints[0] > 2)
- {
- printk("sym53c416.c: Wrong number of parameters:\n");
- printk("sym53c416.c: usage: sym53c416=<base>[,<irq>]\n");
- }
- else
- {
- for(i = 0; i < host_index && i >= 0; i++)
- if(hosts[i].base == ints[1])
- i = -2;
- if(i >= 0)
- {
- hosts[host_index].base = ints[1];
- hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0;
- host_index++;
- }
- }
- }
- }
+{
+ int i;
+
+ if(host_index >= MAXHOSTS)
+ {
+ printk(KERN_WARNING "sym53c416: Too many hosts defined\n");
+ return;
+ }
+ if(ints[0] < 1 || ints[0] > 2)
+ {
+ printk(KERN_ERR "sym53c416: Wrong number of parameters:\n");
+ printk(KERN_ERR "sym53c416: usage: sym53c416=<base>[,<irq>]\n");
+ return;
+ }
+ for(i = 0; i < host_index && i >= 0; i++)
+ if(hosts[i].base == ints[1])
+ i = -2;
+ if(i >= 0)
+ {
+ hosts[host_index].base = ints[1];
+ hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0;
+ host_index++;
+ }
+}
static int sym53c416_test(int base)
- {
- outb(RESET_CHIP, base + COMMAND_REG);
- outb(NOOP, base + COMMAND_REG);
- if(inb(base + COMMAND_REG) != NOOP)
- return 0;
- if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF)
- return 0;
- if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY)
- return 0;
- return 1;
- }
+{
+ outb(RESET_CHIP, base + COMMAND_REG);
+ outb(NOOP, base + COMMAND_REG);
+ if(inb(base + COMMAND_REG) != NOOP)
+ return 0;
+ if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF)
+ return 0;
+ if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY)
+ return 0;
+ return 1;
+}
+
+
+static struct isapnp_device_id id_table[] = {
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+ ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4163), 0 },
+ {0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
void sym53c416_probe(void)
- {
- int *base = probeaddrs;
- int ints[2];
-
- ints[0] = 1;
- for(; *base; base++)
- if(!check_region(*base, IO_RANGE) && sym53c416_test(*base))
- {
- ints[1] = *base;
- sym53c416_setup(NULL, ints);
- }
- }
+{
+ int *base = probeaddrs;
+ int ints[2];
+
+ ints[0] = 1;
+ for(; *base; base++)
+ {
+ if(!check_region(*base, IO_RANGE) && sym53c416_test(*base))
+ {
+ ints[1] = *base;
+ sym53c416_setup(NULL, ints);
+ }
+ }
+}
int sym53c416_detect(Scsi_Host_Template *tpnt)
- {
- unsigned long flags;
- struct Scsi_Host * shpnt = NULL;
- int i;
- int count;
-
+{
+ unsigned long flags;
+ struct Scsi_Host * shpnt = NULL;
+ int i;
+ int count;
+ struct pci_dev *idev = NULL;
+
#ifdef MODULE
- int ints[3];
-
- ints[0] = 2;
- if(sym53c416_base)
- {
- ints[1] = sym53c416_base[0];
- ints[2] = sym53c416_base[1];
- sym53c416_setup(NULL, ints);
- }
- if(sym53c416_base_1)
- {
- ints[1] = sym53c416_base_1[0];
- ints[2] = sym53c416_base_1[1];
- sym53c416_setup(NULL, ints);
- }
- if(sym53c416_base_2)
- {
- ints[1] = sym53c416_base_2[0];
- ints[2] = sym53c416_base_2[1];
- sym53c416_setup(NULL, ints);
- }
- if(sym53c416_base_3)
- {
- ints[1] = sym53c416_base_3[0];
- ints[2] = sym53c416_base_3[1];
- sym53c416_setup(NULL, ints);
- }
+ int ints[3];
+
+ ints[0] = 2;
+ if(sym53c416_base)
+ {
+ ints[1] = sym53c416_base[0];
+ ints[2] = sym53c416_base[1];
+ sym53c416_setup(NULL, ints);
+ }
+ if(sym53c416_base_1)
+ {
+ ints[1] = sym53c416_base_1[0];
+ ints[2] = sym53c416_base_1[1];
+ sym53c416_setup(NULL, ints);
+ }
+ if(sym53c416_base_2)
+ {
+ ints[1] = sym53c416_base_2[0];
+ ints[2] = sym53c416_base_2[1];
+ sym53c416_setup(NULL, ints);
+ }
+ if(sym53c416_base_3)
+ {
+ ints[1] = sym53c416_base_3[0];
+ ints[2] = sym53c416_base_3[1];
+ sym53c416_setup(NULL, ints);
+ }
#endif
-
- printk("sym53c416.c: %s\n", VERSION_STRING);
-
- sym53c416_probe();
-
- /* Now we register and set up each host adapter found... */
- for(count = 0, i = 0; i < host_index; i++)
- if(!sym53c416_test(hosts[i].base))
- printk("No sym53c416 found at address 0x%03x\n", hosts[i].base);
- else
- {
- if(hosts[i].irq == 0)
- /* We don't have an irq yet, so we should probe for one */
- if((hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id)) == 0)
- printk("irq autoprobing failed for sym53c416 at address 0x%03x\n", hosts[i].base);
- if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE))
- {
- shpnt = scsi_register(tpnt, 0);
- if(shpnt==NULL)
- continue;
- save_flags(flags);
- cli();
- /* Request for specified IRQ */
- if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL))
- {
- restore_flags(flags);
- printk("Unable to assign IRQ %d\n", hosts[i].irq);
- scsi_unregister(shpnt);
- }
- else
- {
- /* Inform the kernel of our IO range */
- request_region(hosts[i].base, IO_RANGE, ID);
- shpnt->unique_id = hosts[i].base;
- shpnt->io_port = hosts[i].base;
- shpnt->n_io_port = IO_RANGE;
- shpnt->irq = hosts[i].irq;
- shpnt->this_id = hosts[i].scsi_id;
- sym53c416_init(hosts[i].base, hosts[i].scsi_id);
- count++;
- restore_flags(flags);
- }
- }
- }
- return count;
- }
+ printk(KERN_INFO "sym53c416.c: %s\n", VERSION_STRING);
+
+ while((idev=isapnp_find_dev(NULL, ISAPNP_VENDOR('S','L','I'),
+ ISAPNP_FUNCTION(0x4163), idev))!=NULL)
+ {
+ int i[3];
+
+ if(idev->prepare(idev)<0)
+ {
+ printk(KERN_WARNING "sym53c416: unable to prepare PnP card.\n");
+ continue;
+ }
+ if(idev->activate(idev)<0)
+ {
+ printk(KERN_WARNING "sym53c416: unable to activate PnP card.\n");
+ continue;
+ }
+
+ i[0] = 2;
+ i[1] = idev->resource[0].start;
+ i[2] = idev->irq_resource[0].start;
+
+ printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n",
+ i[1], i[2]);
+ sym53c416_setup(NULL, i);
+ }
+ sym53c416_probe();
+
+ /* Now we register and set up each host adapter found... */
+ for(count = 0, i = 0; i < host_index; i++)
+ {
+ if(!sym53c416_test(hosts[i].base))
+ printk(KERN_WARNING "No sym53c416 found at address 0x%03x\n", hosts[i].base);
+ else
+ {
+ if(hosts[i].irq == 0)
+ /* We don't have an irq yet, so we should probe for one */
+ if((hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id)) == 0)
+ printk(KERN_WARNING "IRQ autoprobing failed for sym53c416 at address 0x%03x\n", hosts[i].base);
+ if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE))
+ {
+ shpnt = scsi_register(tpnt, 0);
+ if(shpnt==NULL)
+ continue;
+ save_flags(flags);
+ cli();
+ /* FIXME: Request_irq with CLI is not safe */
+ /* Request for specified IRQ */
+ if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL))
+ {
+ restore_flags(flags);
+ printk(KERN_ERR "sym53c416: Unable to assign IRQ %d\n", hosts[i].irq);
+ scsi_unregister(shpnt);
+ }
+ else
+ {
+ /* Inform the kernel of our IO range */
+ request_region(hosts[i].base, IO_RANGE, ID);
+ shpnt->unique_id = hosts[i].base;
+ shpnt->io_port = hosts[i].base;
+ shpnt->n_io_port = IO_RANGE;
+ shpnt->irq = hosts[i].irq;
+ shpnt->this_id = hosts[i].scsi_id;
+ sym53c416_init(hosts[i].base, hosts[i].scsi_id);
+ count++;
+ restore_flags(flags);
+ }
+ }
+ }
+ }
+ return count;
+}
const char *sym53c416_info(struct Scsi_Host *SChost)
- {
- int i;
- int base = SChost->io_port;
- int irq = SChost->irq;
- int scsi_id = 0;
- int rev = inb(base + TC_HIGH);
-
- for(i = 0; i < host_index; i++)
- if(hosts[i].base == base)
- scsi_id = hosts[i].scsi_id;
- sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow");
- return info;
- }
+{
+ int i;
+ int base = SChost->io_port;
+ int irq = SChost->irq;
+ int scsi_id = 0;
+ int rev = inb(base + TC_HIGH);
+
+ for(i = 0; i < host_index; i++)
+ if(hosts[i].base == base)
+ scsi_id = hosts[i].scsi_id;
+ sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow");
+ return info;
+}
int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
- {
- int base;
- unsigned long flags = 0;
- int i;
-
- /* Store base register as we can have more than one controller in the system */
- base = SCpnt->host->io_port;
- current_command = SCpnt; /* set current command */
- current_command->scsi_done = done; /* set ptr to done function */
- current_command->SCp.phase = command_ph; /* currect phase is the command phase */
- current_command->SCp.Status = 0;
- current_command->SCp.Message = 0;
-
- save_flags(flags);
- cli();
- outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target */
- outb(FLUSH_FIFO, base + COMMAND_REG); /* Flush SCSI and PIO FIFO's */
- /* Write SCSI command into the SCSI fifo */
- for(i = 0; i < SCpnt->cmd_len; i++)
- outb(SCpnt->cmnd[i], base + SCSI_FIFO);
- /* Start selection sequence */
- outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
- /* Now an interrupt will be generated which we will catch in out interrupt routine */
- restore_flags(flags);
- return 0;
- }
+{
+ int base;
+ unsigned long flags = 0;
+ int i;
+
+ /* Store base register as we can have more than one controller in the system */
+ base = SCpnt->host->io_port;
+ current_command = SCpnt; /* set current command */
+ current_command->scsi_done = done; /* set ptr to done function */
+ current_command->SCp.phase = command_ph; /* currect phase is the command phase */
+ current_command->SCp.Status = 0;
+ current_command->SCp.Message = 0;
+
+ save_flags(flags);
+ cli();
+ outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target */
+ outb(FLUSH_FIFO, base + COMMAND_REG); /* Flush SCSI and PIO FIFO's */
+ /* Write SCSI command into the SCSI fifo */
+ for(i = 0; i < SCpnt->cmd_len; i++)
+ outb(SCpnt->cmnd[i], base + SCSI_FIFO);
+ /* Start selection sequence */
+ outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
+ /* Now an interrupt will be generated which we will catch in out interrupt routine */
+ restore_flags(flags);
+ return 0;
+}
static void internal_done(Scsi_Cmnd *SCpnt)
- {
- SCpnt->SCp.Status++;
- }
-
-int sym53c416_command(Scsi_Cmnd *SCpnt)
- {
- sym53c416_queuecommand(SCpnt, internal_done);
- SCpnt->SCp.Status = 0;
- while(!SCpnt->SCp.Status)
- barrier();
- return SCpnt->result;
- }
-
-int sym53c416_abort(Scsi_Cmnd *SCpnt)
- {
- printk("sym53c416_abort\n");
-
- /* We don't know how to abort for the moment */
- return SCSI_ABORT_SNOOZE;
- }
-
-int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
- {
- int base;
- int scsi_id = -1;
- int i;
-
- printk("sym53c416_reset\n");
- base = SCpnt->host->io_port;
- /* search scsi_id */
- for(i = 0; i < host_index && scsi_id != -1; i++)
- if(hosts[i].base == base)
- scsi_id = hosts[i].scsi_id;
- outb(RESET_CHIP, base + COMMAND_REG);
- outb(NOOP | PIO_MODE, base + COMMAND_REG);
- outb(RESET_SCSI_BUS, base + COMMAND_REG);
- sym53c416_init(base, scsi_id);
- return SCSI_RESET_PENDING;
- }
-
-int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
- {
- int size;
-
- size = disk->capacity;
- ip[0] = 64; /* heads */
- ip[1] = 32; /* sectors */
- if((ip[2] = size >> 11) > 1024) /* cylinders, test for big disk */
- {
- ip[0] = 255; /* heads */
- ip[1] = 63; /* sectors */
- ip[2] = size / (255 * 63); /* cylinders */
- }
- return 0;
- }
+{
+ SCpnt->SCp.Status++;
+}
+
+static int sym53c416_command(Scsi_Cmnd *SCpnt)
+{
+ sym53c416_queuecommand(SCpnt, internal_done);
+ SCpnt->SCp.Status = 0;
+ while(!SCpnt->SCp.Status)
+ barrier();
+ return SCpnt->result;
+}
+
+static int sym53c416_abort(Scsi_Cmnd *SCpnt)
+{
+ //printk("sym53c416_abort\n");
+ /* We don't know how to abort for the moment */
+ return SCSI_ABORT_SNOOZE;
+}
+
+static int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+ int base;
+ int scsi_id = -1;
+ int i;
+
+ //printk("sym53c416_reset\n");
+ base = SCpnt->host->io_port;
+ /* search scsi_id */
+ for(i = 0; i < host_index && scsi_id != -1; i++)
+ if(hosts[i].base == base)
+ scsi_id = hosts[i].scsi_id;
+ outb(RESET_CHIP, base + COMMAND_REG);
+ outb(NOOP | PIO_MODE, base + COMMAND_REG);
+ outb(RESET_SCSI_BUS, base + COMMAND_REG);
+ sym53c416_init(base, scsi_id);
+ return SCSI_RESET_PENDING;
+}
+
+static int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
+{
+ int size;
+
+ size = disk->capacity;
+ ip[0] = 64; /* heads */
+ ip[1] = 32; /* sectors */
+ if((ip[2] = size >> 11) > 1024) /* cylinders, test for big disk */
+ {
+ ip[0] = 255; /* heads */
+ ip[1] = 63; /* sectors */
+ ip[2] = size / (255 * 63); /* cylinders */
+ }
+ return 0;
+}
/* Loadable module support */
#ifdef MODULE
#define SYM53C416_SCSI_ID 7
-extern int sym53c416_detect(Scsi_Host_Template *);
-extern const char *sym53c416_info(struct Scsi_Host *);
-extern int sym53c416_command(Scsi_Cmnd *);
-extern int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int sym53c416_abort(Scsi_Cmnd *);
-extern int sym53c416_reset(Scsi_Cmnd *, unsigned int);
-extern int sym53c416_bios_param(Disk *, kdev_t, int *);
-extern void sym53c416_setup(char *str, int *ints);
+static int sym53c416_detect(Scsi_Host_Template *);
+static const char *sym53c416_info(struct Scsi_Host *);
+static int sym53c416_command(Scsi_Cmnd *);
+static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sym53c416_abort(Scsi_Cmnd *);
+static int sym53c416_reset(Scsi_Cmnd *, unsigned int);
+static int sym53c416_bios_param(Disk *, kdev_t, int *);
+static void sym53c416_setup(char *str, int *ints);
#define SYM53C416 { \
proc_name: "sym53c416", \
/*****************************************************************************/
-
/*
* cmpci.c -- C-Media PCI audio driver.
*
- * Copyright (C) 1999 ChenLi Tien (cltien@home.com)
+ * Copyright (C) 1999 ChenLi Tien (cltien@cmedia.com.tw)
+ * C-media support (support@cmedia.com.tw)
*
- * Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
*
+ * For update, visit:
+ * http://members.home.net/puresoft/cmedia.html
+ * http://www.cmedia.com.tw
+ *
* 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
* reported by Johan Maes <joma@telindus.be>
* 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
* read/write cannot be executed
- * 20 09 99 0.13 merged the generic changes in sonicvibes since this
- * diverged.
* 18.08.99 1.5 Only deallocate DMA buffer when unloading.
* 02.09.99 1.6 Enable SPDIF LOOP
* Change the mixer read back
* Add support for modem, S/PDIF loop and 4 channels.
* (8738 only)
* Fix bug cause x11amp cannot play.
- * $Log: cmpci.c,v $
- * Revision 2.41 1999/10/27 02:00:05 cltien
- * Now the fragsize for modem is activated by parameter.
- *
- * Revision 2.40 1999/10/26 23:38:26 cltien
- * Remove debugging message in cm_write which may cause module counter not 0.
- *
- * Revision 2.39 1999/10/26 21:52:50 cltien
- * I forgor too adjust mic recording volume, as it should be moved to 5MUTEMONO.
- * Change the DYNAMIC macro to FIXEDDMA, which means static DMA buffer.
- *
- * Revision 2.38 1999/10/08 21:59:03 cltien
- * Set FLINKON and reset FLINKOFF for modem.
*
- * Revision 2.37 1999/09/28 02:57:04 cltien
- * Add set_bus_master() to make sure bus master enabled.
- *
- * Revision 2.36 1999/09/22 14:15:03 cltien
- * Use open_sem to avoid multiple access to open_mode.
- * Use wakeup in IntrClose to activate process in waiting queue.
- *
- * Revision 2.35 1999/09/22 13:20:53 cltien
- * Use open_mode to check if DAC in used. Also more check in IntrWrite and IntrClose. Now the modem can access DAC safely.
- *
- * Revision 2.34 1999/09/22 03:29:57 cltien
- * Use module count to decide which one to access the dac.
+ * Fixes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * 18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it
+ * was calling prog_dmabuf with s->lock held, call missing
+ * unlock_kernel in cm_midi_release
*
+ * Fri May 25 2001 - Carlos Eduardo Gorges <carlos@techlinux.com.br>
+ * - some driver cleanups
+ * - spin[un]lock* revision ( fix SMP support )
+ * - cosmetic code changes
*
*/
-
+
/*****************************************************************************/
-#include <linux/config.h>
+#define EXPORT_SYMTAB
#include <linux/version.h>
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/sound.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
#include <linux/soundcard.h>
#include <linux/pci.h>
#include <linux/wrapper.h>
#ifndef PCI_DEVICE_ID_CMEDIA_CM8738
#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111
#endif
+#ifndef PCI_DEVICE_ID_CMEDIA_CM8738B
+#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112
+#endif
#define CM_MAGIC ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A)
#define CM_CFMT_STEREO 0x01
#define CM_CFMT_16BIT 0x02
#define CM_CFMT_MASK 0x03
-#define CM_CFMT_DACSHIFT 0
-#define CM_CFMT_ADCSHIFT 2
+#define CM_CFMT_DACSHIFT 2
+#define CM_CFMT_ADCSHIFT 0
static const unsigned sample_size[] = { 1, 2, 2, 4 };
static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-#define CM_CENABLE_RE 0x2
-#define CM_CENABLE_PE 0x1
+#define CM_ENABLE_CH1 0x2
+#define CM_ENABLE_CH0 0x1
/* MIDI buffer sizes */
#define FMODE_DMFM 0x10
+#define SND_DEV_DSP16 5
+
/* --------------------------------------------------------------------- */
struct cm_state {
/* hardware resources */
unsigned int iosb, iobase, iosynth, iomidi, iogame, irq;
+ unsigned short deviceid;
/* mixer stuff */
struct {
struct dmabuf {
void *rawbuf;
+ unsigned rawphys;
unsigned buforder;
unsigned numfrag;
unsigned fragshift;
unsigned char ibuf[MIDIINBUF];
unsigned char obuf[MIDIOUTBUF];
} midi;
+
+ /* misc stuff */
+ int chip_version;
+ int max_channels;
+ int curr_channels;
+ int speakers; // number of speakers
+ int capability; // HW capability, various for chip versions
+ int status; // HW or SW state
+
+ /* spdif frame counter */
+ int spdif_counter;
};
+/* flags used for capability */
+#define CAN_AC3_HW 0x00000001 // 037 or later
+#define CAN_AC3_SW 0x00000002 // 033 or later
+#define CAN_AC3 (CAN_AC3_HW | CAN_AC3_SW)
+#define CAN_DUAL_DAC 0x00000004 // 033 or later
+#define CAN_MULTI_CH_HW 0x00000008 // 039 or later
+#define CAN_MULTI_CH (CAN_MULTI_CH_HW | CAN_DUAL_DAC)
+#define CAN_LINE_AS_REAR 0x00000010 // 033 or later
+#define CAN_LINE_AS_BASS 0x00000020 // 039 or later
+#define CAN_MIC_AS_BASS 0x00000040 // 039 or later
+
+/* flags used for status */
+#define DO_AC3_HW 0x00000001
+#define DO_AC3_SW 0x00000002
+#define DO_AC3 (DO_AC3_HW | DO_AC3_SW)
+#define DO_DUAL_DAC 0x00000004
+#define DO_MULTI_CH_HW 0x00000008
+#define DO_MULTI_CH (DO_MULTI_CH_HW | DO_DUAL_DAC)
+#define DO_LINE_AS_REAR 0x00000010 // 033 or later
+#define DO_LINE_AS_BASS 0x00000020 // 039 or later
+#define DO_MIC_AS_BASS 0x00000040 // 039 or later
+#define DO_SPDIF_OUT 0x00000100
+#define DO_SPDIF_IN 0x00000200
+#define DO_SPDIF_LOOP 0x00000400
+
/* --------------------------------------------------------------------- */
-static struct cm_state *devs = NULL;
-static unsigned long wavetable_mem = 0;
+static struct cm_state *devs;
+static unsigned long wavetable_mem;
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
-static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
+/*
+ * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver.
+ */
+
+#undef DMABYTEIO
+
+static void maskb(unsigned int addr, unsigned int mask, unsigned int value)
{
- count--;
- outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
- outw(count, s->iobase + CODEC_CMI_CH0_FRAME2);
- outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) & ~1, s->iobase + CODEC_CMI_FUNCTRL0);
-// outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ outb((inb(addr) & mask) | value, addr);
+}
+
+static void maskw(unsigned int addr, unsigned int mask, unsigned int value)
+{
+ outw((inw(addr) & mask) | value, addr);
+}
+
+static void maskl(unsigned int addr, unsigned int mask, unsigned int value)
+{
+ outl((inl(addr) & mask) | value, addr);
+}
+
+static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count)
+{
+ if (addr)
+ outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
+ outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);
+ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~1, 0);
}
static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
{
- count--;
+ outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
+ outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);
+ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 1);
+}
+
+static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
+{
outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1);
- outw(count, s->iobase + CODEC_CMI_CH1_FRAME2);
- outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) | 2, s->iobase + CODEC_CMI_FUNCTRL0);
-// outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2);
+ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 0);
+ if (s->status & DO_DUAL_DAC)
+ set_dmadac1(s, 0, count);
+}
+
+static void set_countadc(struct cm_state *s, unsigned count)
+{
+ outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+}
+
+static void set_countdac(struct cm_state *s, unsigned count)
+{
+ outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+ if (s->status & DO_DUAL_DAC)
+ set_countadc(s, count);
}
extern __inline__ unsigned get_dmadac(struct cm_state *s)
{
unsigned int curr_addr;
- if (!s->dma_dac.dmasize || !(s->enable & CM_CENABLE_PE))
- return 0;
-
- curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);
- curr_addr -= virt_to_bus(s->dma_dac.rawbuf);
+#if 1
+ curr_addr = inw(s->iobase + CODEC_CMI_CH1_FRAME2) + 1;
+ curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
curr_addr = s->dma_dac.dmasize - curr_addr;
+#else
+ curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);
curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]-1);
+ curr_addr -= s->dma_dac.rawphys;
+#endif
return curr_addr;
}
{
unsigned int curr_addr;
- if (!s->dma_adc.dmasize || !(s->enable & CM_CENABLE_RE))
- return 0;
-
- curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);
- curr_addr -= virt_to_bus(s->dma_adc.rawbuf);
+#if 1
+ curr_addr = inw(s->iobase + CODEC_CMI_CH0_FRAME2) + 1;
+ curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];
curr_addr = s->dma_adc.dmasize - curr_addr;
+#else
+ curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);
curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK]-1);
+ curr_addr -= s->dma_adc.rawphys;
+#endif
return curr_addr;
}
static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data)
{
outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
outb(data, s->iobase + CODEC_SB16_DATA);
- udelay(10);
}
static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
unsigned char v;
outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
v = inb(s->iobase + CODEC_SB16_DATA);
- udelay(10);
return v;
}
+static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data)
+{
+ if (mask)
+ s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
+ s->fmt = (s->fmt & mask) | data;
+ outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
+}
+
static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data)
{
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
- if (mask) {
- s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
- udelay(10);
- }
- s->fmt = (s->fmt & mask) | data;
- outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
+ set_fmt_unlocked(s,mask,data);
spin_unlock_irqrestore(&s->lock, flags);
- udelay(10);
}
static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data)
{
outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);
- udelay(10);
}
static struct {
{ 22050, (16000 + 22050) / 2, (22050 + 32000) / 2, 2 },
{ 32000, (22050 + 32000) / 2, (32000 + 44100) / 2, 6 },
{ 44100, (32000 + 44100) / 2, (44100 + 48000) / 2, 3 },
- { 48000, (44100 + 48000) /2, 48000, 7 }
+ { 48000, (44100 + 48000) / 2, 48000, 7 }
};
-static void set_dac_rate(struct cm_state *s, unsigned rate)
+static void set_spdifout_unlocked(struct cm_state *s, unsigned rate)
+{
+ if (rate == 48000 || rate == 44100) {
+ // SPDIFI48K SPDF_ACc97
+ maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~0x01008000, rate == 48000 ? 0x01008000 : 0);
+ // ENSPDOUT
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, 0x80);
+ // SPDF_1 SPD2DAC
+ maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x240);
+ // CDPLAY
+ if (s->chip_version >= 39)
+ maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 1);
+ s->status |= DO_SPDIF_OUT;
+ } else {
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0x80, 0);
+ maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0x240, 0);
+ if (s->chip_version >= 39)
+ maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0);
+ s->status &= ~DO_SPDIF_OUT;
+ }
+}
+
+static void set_spdifout(struct cm_state *s, unsigned rate)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ set_spdifout_unlocked(s,rate);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+/* find parity for bit 4~30 */
+static unsigned parity(unsigned data)
+{
+ unsigned parity = 0;
+ int counter = 4;
+
+ data >>= 4; // start from bit 4
+ while (counter <= 30) {
+ if (data & 1)
+ parity++;
+ data >>= 1;
+ counter++;
+ }
+ return parity & 1;
+}
+
+static void set_ac3_unlocked(struct cm_state *s, unsigned rate)
+{
+ /* enable AC3 */
+ if (rate == 48000 || rate == 44100) {
+ // mute DAC
+ maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 0x40);
+ // AC3EN for 037, 0x10
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
+ // AC3EN for 039, 0x04
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0x04);
+ if (s->capability & CAN_AC3_HW) {
+ // SPD24SEL for 037, 0x02
+ // SPD24SEL for 039, 0x20, but cannot be set
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
+ s->status |= DO_AC3_HW;
+ if (s->chip_version >= 39)
+ maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0);
+ } else {
+ // SPD32SEL for 037 & 039, 0x20
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0x20);
+ // set 176K sample rate to fix 033 HW bug
+ if (s->chip_version == 33) {
+ if (rate == 48000)
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08);
+ else
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+ }
+ s->status |= DO_AC3_SW;
+ }
+ } else {
+ maskb(s->iobase + CODEC_CMI_MIXER1, ~0x40, 0);
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0x32, 0);
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0x24, 0);
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+ if (s->chip_version == 33)
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+ if (s->chip_version >= 39)
+ maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 1);
+ s->status &= ~DO_AC3;
+ }
+ s->spdif_counter = 0;
+
+}
+
+static void set_ac3(struct cm_state *s, unsigned rate)
{
unsigned long flags;
- unsigned char freq = 4, val;
+
+ spin_lock_irqsave(&s->lock, flags);
+ set_spdifout_unlocked(s, rate);
+ set_ac3_unlocked(s,rate);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void trans_ac3(struct cm_state *s, void *dest, const char *source, int size)
+{
+ int i = size / 2;
+ unsigned long data;
+ unsigned long *dst = (unsigned long *) dest;
+ unsigned short *src = (unsigned short *)source;
+
+ do {
+ data = (unsigned long) *src++;
+ data <<= 12; // ok for 16-bit data
+ if (s->spdif_counter == 2 || s->spdif_counter == 3)
+ data |= 0x40000000; // indicate AC-3 raw data
+ if (parity(data))
+ data |= 0x80000000; // parity
+ if (s->spdif_counter == 0)
+ data |= 3; // preamble 'M'
+ else if (s->spdif_counter & 1)
+ data |= 5; // odd, 'W'
+ else
+ data |= 9; // even, 'M'
+ *dst++ = data;
+ s->spdif_counter++;
+ if (s->spdif_counter == 384)
+ s->spdif_counter = 0;
+ } while (--i);
+}
+
+static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate)
+{
+ unsigned char freq = 4;
int i;
if (rate > 48000)
rate = 48000;
- if (rate < 5512)
- rate = 5512;
- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++)
- {
- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper)
- {
+ if (rate < 8000)
+ rate = 8000;
+ for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+ if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
rate = rate_lookup[i].rate;
freq = rate_lookup[i].freq;
break;
}
}
- s->ratedac = rate;
+ s->rateadc = rate;
freq <<= 2;
- spin_lock_irqsave(&s->lock, flags);
- val = inb(s->iobase + CODEC_CMI_FUNCTRL1 + 1) & ~0x1c;
- outb(val | freq, s->iobase + CODEC_CMI_FUNCTRL1 + 1);
- spin_unlock_irqrestore(&s->lock, flags);
+
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq);
}
static void set_adc_rate(struct cm_state *s, unsigned rate)
{
unsigned long flags;
- unsigned char freq = 4, val;
+ unsigned char freq = 4;
int i;
if (rate > 48000)
rate = 48000;
- if (rate < 5512)
- rate = 5512;
- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++)
- {
- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper)
- {
+ if (rate < 8000)
+ rate = 8000;
+ for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+ if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
rate = rate_lookup[i].rate;
freq = rate_lookup[i].freq;
break;
}
}
s->rateadc = rate;
+ freq <<= 2;
+
+ spin_lock_irqsave(&s->lock, flags);
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void set_dac_rate(struct cm_state *s, unsigned rate)
+{
+ unsigned long flags;
+ unsigned char freq = 4;
+ int i;
+
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 8000)
+ rate = 8000;
+ for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+ if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
+ rate = rate_lookup[i].rate;
+ freq = rate_lookup[i].freq;
+ break;
+ }
+ }
+ s->ratedac = rate;
freq <<= 5;
+
spin_lock_irqsave(&s->lock, flags);
- val = inb(s->iobase + CODEC_CMI_FUNCTRL1 + 1) & ~0xe0;
- outb(val | freq, s->iobase + CODEC_CMI_FUNCTRL1 + 1);
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0xe0, freq);
+
+
+ if (s->curr_channels <= 2)
+ set_spdifout_unlocked(s, rate);
+ if (s->status & DO_DUAL_DAC)
+ set_adc_rate_unlocked(s, rate);
+
spin_unlock_irqrestore(&s->lock, flags);
}
/* --------------------------------------------------------------------- */
+static inline void reset_adc(struct cm_state *s)
+{
+ /* reset bus master */
+ outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+}
+
+static inline void reset_dac(struct cm_state *s)
+{
+ /* reset bus master */
+ outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ if (s->status & DO_DUAL_DAC)
+ reset_adc(s);
+}
+
+static inline void pause_adc(struct cm_state *s)
+{
+ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 4);
+}
+
+static inline void pause_dac(struct cm_state *s)
+{
+ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 8);
+ if (s->status & DO_DUAL_DAC)
+ pause_adc(s);
+}
+
+extern inline void disable_adc(struct cm_state *s)
+{
+ /* disable channel */
+ s->enable &= ~CM_ENABLE_CH0;
+ outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ reset_adc(s);
+}
+
+extern inline void disable_dac(struct cm_state *s)
+{
+ /* disable channel */
+ s->enable &= ~CM_ENABLE_CH1;
+ outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ reset_dac(s);
+ if (s->status & DO_DUAL_DAC)
+ disable_adc(s);
+}
+
+extern inline void enable_adc(struct cm_state *s)
+{
+ if (!(s->enable & CM_ENABLE_CH0)) {
+ /* enable channel */
+ s->enable |= CM_ENABLE_CH0;
+ outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ }
+ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~4, 0);
+}
+
+extern inline void enable_dac_unlocked(struct cm_state *s)
+{
+ if (!(s->enable & CM_ENABLE_CH1)) {
+ /* enable channel */
+ s->enable |= CM_ENABLE_CH1;
+ outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ }
+ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~8, 0);
+
+ if (s->status & DO_DUAL_DAC)
+ enable_adc(s);
+}
+
+extern inline void enable_dac(struct cm_state *s)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ enable_dac_unlocked(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+extern inline void stop_adc_unlocked(struct cm_state *s)
+{
+ if (s->enable & CM_ENABLE_CH0) {
+ /* disable interrupt */
+ maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~1, 0);
+ disable_adc(s);
+ }
+}
extern inline void stop_adc(struct cm_state *s)
{
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
- /* disable channel */
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- s->enable &= ~CM_CENABLE_RE;
- /* disable interrupt */
- outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- /* reset */
- outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- udelay(10);
- outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ stop_adc_unlocked(s);
spin_unlock_irqrestore(&s->lock, flags);
-}
+
+}
+
+extern inline void stop_dac_unlocked(struct cm_state *s)
+{
+ if (s->enable & CM_ENABLE_CH1) {
+ /* disable interrupt */
+ maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~2, 0);
+ disable_dac(s);
+ }
+ if (s->status & DO_DUAL_DAC)
+ stop_adc_unlocked(s);
+}
extern inline void stop_dac(struct cm_state *s)
{
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
- /* disable channel */
- s->enable &= ~CM_CENABLE_PE;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- /* disable interrupt */
- outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- /* reset */
- outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- udelay(10);
- outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ stop_dac_unlocked(s);
spin_unlock_irqrestore(&s->lock, flags);
-}
+}
-static void start_dac(struct cm_state *s)
+static void start_adc_unlocked(struct cm_state *s)
+{
+ if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+ && s->dma_adc.ready) {
+ /* enable interrupt */
+ maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1);
+ enable_adc(s);
+ }
+}
+
+static void start_adc(struct cm_state *s)
{
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
+ start_adc_unlocked(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void start_dac1_unlocked(struct cm_state *s)
+{
+ if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {
+ /* enable interrupt */
+// maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1);
+ enable_dac_unlocked(s);
+ }
+}
+
+//static void start_dac1(struct cm_state *s)
+//{
+// unsigned long flags;
+//
+// spin_lock_irqsave(&s->lock, flags);
+// start_dac1_unlocked(s);
+// spin_unlock_irqrestore(&s->lock, flags);
+//}
+
+static void start_dac_unlocked(struct cm_state *s)
+{
if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
- outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- s->enable |= CM_CENABLE_PE;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ /* enable interrupt */
+ maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 2);
+ enable_dac_unlocked(s);
}
+ if (s->status & DO_DUAL_DAC)
+ start_dac1_unlocked(s);
+}
+
+static void start_dac(struct cm_state *s)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ start_dac_unlocked(s);
spin_unlock_irqrestore(&s->lock, flags);
}
-static void start_adc(struct cm_state *s)
+static int prog_dmabuf(struct cm_state *s, unsigned rec);
+
+static int set_dac_channels(struct cm_state *s, int channels)
{
unsigned long flags;
-
spin_lock_irqsave(&s->lock, flags);
- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- s->enable |= CM_CENABLE_RE;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+
+ if ((channels > 2) && (channels <= s->max_channels)
+ && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) {
+ set_spdifout_unlocked(s, 0);
+ if (s->capability & CAN_MULTI_CH_HW) {
+ // NXCHG
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, 0x80);
+ // CHB3D or CHB3D5C
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~0xa0, channels > 4 ? 0x80 : 0x20);
+ // CHB3D6C
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x80, channels == 6 ? 0x80 : 0);
+ // ENCENTER
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0x80, channels == 6 ? 0x80 : 0);
+ s->status |= DO_MULTI_CH_HW;
+ } else if (s->capability & CAN_DUAL_DAC) {
+ unsigned char fmtm = ~0, fmts = 0;
+ ssize_t ret;
+
+ // ENDBDAC, turn on double DAC mode
+ // XCHGDAC, CH0 -> back, CH1->front
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0xC0);
+ s->status |= DO_DUAL_DAC;
+ // prepare secondary buffer
+
+ spin_unlock_irqrestore(&s->lock, flags);
+ ret = prog_dmabuf(s, 1);
+ spin_lock_irqsave(&s->lock, flags);
+
+ if (ret) return ret;
+ // copy the hw state
+ fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
+ fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
+ // the HW only support 16-bit stereo
+ fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
+ fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
+ fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+ fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+
+ set_fmt_unlocked(s, fmtm, fmts);
+ set_adc_rate_unlocked(s, s->ratedac);
+
+ }
+ // N4SPK3D, disable 4 speaker mode (analog duplicate)
+ if (s->speakers > 2)
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0x04, 0);
+ s->curr_channels = channels;
+ } else {
+ if (s->status & DO_MULTI_CH_HW) {
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x80, 0);
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~0xa0, 0);
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x80, 0);
+ } else if (s->status & DO_DUAL_DAC) {
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0x80, 0);
+ }
+ // N4SPK3D, enable 4 speaker mode (analog duplicate)
+ if (s->speakers > 2)
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, 0x04);
+ s->status &= ~DO_MULTI_CH;
+ s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
}
+
spin_unlock_irqrestore(&s->lock, flags);
-}
+ return s->curr_channels;
+}
/* --------------------------------------------------------------------- */
static void dealloc_dmabuf(struct dmabuf *db)
{
struct page *pstart, *pend;
-
+
if (db->rawbuf) {
/* undo marking the pages as reserved */
pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
db->mapped = db->ready = 0;
}
-
-/* Ch0 is used for playback, Ch1 is used for recording */
+/* Ch1 is used for playback, Ch0 is used for recording */
static int prog_dmabuf(struct cm_state *s, unsigned rec)
{
unsigned char fmt;
unsigned long flags;
- spin_lock_irqsave(&s->lock, flags);
fmt = s->fmt;
if (rec) {
- s->enable &= ~CM_CENABLE_RE;
+ stop_adc(s);
fmt >>= CM_CFMT_ADCSHIFT;
} else {
- s->enable &= ~CM_CENABLE_PE;
+ stop_dac(s);
fmt >>= CM_CFMT_DACSHIFT;
}
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- spin_unlock_irqrestore(&s->lock, flags);
+
fmt &= CM_CFMT_MASK;
db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
if (!db->rawbuf) {
if (!db->rawbuf)
return -ENOMEM;
db->buforder = order;
- if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
- printk(KERN_DEBUG "cmpci: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
- if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
- printk(KERN_DEBUG "cmpci: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
+ db->rawphys = virt_to_bus(db->rawbuf);
+ if ((db->rawphys ^ (db->rawphys + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
+ printk(KERN_DEBUG "cm: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
+ (long) db->rawphys, PAGE_SIZE << db->buforder);
+ if ((db->rawphys + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
+ printk(KERN_DEBUG "cm: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
+ (long) db->rawphys, PAGE_SIZE << db->buforder);
/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
db->numfrag = db->ossmaxfrags;
/* to make fragsize >= 4096 */
-#if 0
- if(s->modem)
- {
- while (db->fragsize < 4096 && db->numfrag >= 4)
- {
- db->fragsize *= 2;
- db->fragshift++;
- db->numfrag /= 2;
- }
- }
-#endif
db->fragsamples = db->fragsize >> sample_shift[fmt];
db->dmasize = db->numfrag << db->fragshift;
db->dmasamples = db->dmasize >> sample_shift[fmt];
memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
spin_lock_irqsave(&s->lock, flags);
if (rec) {
- set_dmaadc(s, virt_to_bus(db->rawbuf), db->dmasize >> sample_shift[fmt]);
+ if (s->status & DO_DUAL_DAC)
+ set_dmadac1(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
+ else
+ set_dmaadc(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
/* program sample counts */
- outw(db->fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+ set_countdac(s, db->fragsamples);
} else {
- set_dmadac(s, virt_to_bus(db->rawbuf), db->dmasize >> sample_shift[fmt]);
+ set_dmadac(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
/* program sample counts */
- outw(db->fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+ set_countdac(s, db->fragsamples);
}
spin_unlock_irqrestore(&s->lock, flags);
db->ready = 1;
{
unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;
unsigned char *buf = s->dma_dac.rawbuf;
+ unsigned char *buf1 = s->dma_adc.rawbuf;
unsigned bsize = s->dma_dac.dmasize;
unsigned bptr = s->dma_dac.swptr;
unsigned len = s->dma_dac.fragsize;
if (bptr + len > bsize) {
unsigned x = bsize - bptr;
memset(buf + bptr, c, x);
+ if (s->status & DO_DUAL_DAC)
+ memset(buf1 + bptr, c, x);
bptr = 0;
len -= x;
}
memset(buf + bptr, c, len);
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ if (s->status & DO_DUAL_DAC)
+ memset(buf1 + bptr, c, len);
}
/* call with spinlock held! */
/* update ADC pointer */
if (s->dma_adc.ready) {
- hwptr = (s->dma_adc.dmasize - get_dmaadc(s)) % s->dma_adc.dmasize;
+ if (s->status & DO_DUAL_DAC) {
+ hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
+ diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+ s->dma_adc.hwptr = hwptr;
+ s->dma_adc.total_bytes += diff;
+ if (s->dma_adc.mapped) {
+ s->dma_adc.count += diff;
+ if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+ wake_up(&s->dma_adc.wait);
+ } else {
+ s->dma_adc.count -= diff;
+ if (s->dma_adc.count <= 0) {
+ pause_adc(s);
+ s->dma_adc.error++;
+ } else if (s->dma_adc.count <= (signed)s->dma_adc.fragsize && !s->dma_adc.endcleared) {
+ clear_advance(s);
+ s->dma_adc.endcleared = 1;
+ }
+ if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
+ wake_up(&s->dma_adc.wait);
+ }
+ } else {
+ hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
s->dma_adc.hwptr = hwptr;
s->dma_adc.total_bytes += diff;
wake_up(&s->dma_adc.wait);
if (!s->dma_adc.mapped) {
if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- s->enable &= ~CM_CENABLE_RE;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ pause_adc(s);
s->dma_adc.error++;
}
}
+ }
}
/* update DAC pointer */
if (s->dma_dac.ready) {
- hwptr = (s->dma_dac.dmasize - get_dmadac(s)) % s->dma_dac.dmasize;
+ hwptr = get_dmadac(s) % s->dma_dac.dmasize;
diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
s->dma_dac.hwptr = hwptr;
s->dma_dac.total_bytes += diff;
} else {
s->dma_dac.count -= diff;
if (s->dma_dac.count <= 0) {
- s->enable &= ~CM_CENABLE_PE;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+ pause_dac(s);
s->dma_dac.error++;
} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
clear_advance(s);
}
}
+#ifdef CONFIG_SOUND_CMPCI_MIDI
/* hold spinlock for the following! */
static void cm_handle_midi(struct cm_state *s)
{
if (wake)
wake_up(&s->midi.owait);
}
+#endif
static void cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct cm_state *s = (struct cm_state *)dev_id;
unsigned int intsrc, intstat;
+ unsigned char mask = 0;
/* fastpath out, to ease interrupt sharing */
intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
/* acknowledge interrupt */
if (intsrc & CM_INT_CH0)
- {
- outb(intstat & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- udelay(10);
- outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- }
+ mask |= 1;
if (intsrc & CM_INT_CH1)
- {
- outb(intstat & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- udelay(10);
- outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- }
+ mask |= 2;
+ outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+ outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
cm_update_ptr(s);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
cm_handle_midi(s);
+#endif
spin_unlock(&s->lock);
}
+#ifdef CONFIG_SOUND_CMPCI_MIDI
static void cm_midi_timer(unsigned long data)
{
struct cm_state *s = (struct cm_state *)data;
s->midi.timer.expires = jiffies+1;
add_timer(&s->midi.timer);
}
+#endif
/* --------------------------------------------------------------------- */
-static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
+static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n";
#ifdef CONFIG_SOUND_CMPCI /* support multiple chips */
#define VALIDATE_STATE(s)
[SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, DSP_MIX_MICVOLIDX, MT_5MUTEMONO, 0x01, 0x01 },
[SOUND_MIXER_SYNTH] = { DSP_MIX_FMVOLIDX_L, DSP_MIX_FMVOLIDX_R, MT_5MUTE, 0x40, 0x00 },
[SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
- [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 }
+ [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
+ [SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX, DSP_MIX_SPKRVOLIDX, MT_5MUTEMONO, 0x01, 0x01 }
};
#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
[SOUND_MIXER_MIC] = 3,
[SOUND_MIXER_SYNTH] = 4,
[SOUND_MIXER_VOLUME] = 5,
- [SOUND_MIXER_PCM] = 6
+ [SOUND_MIXER_PCM] = 6,
+ [SOUND_MIXER_SPEAKER]= 7
};
#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
}
if (cmd == OSS_GETVERSION)
return put_user(SOUND_VERSION, (int *)arg);
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+ if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
+ if (_IOC_DIR(cmd) == _IOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
return put_user(mixer_recmask(s), (int *)arg);
#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
}
}
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
+ if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
return -EINVAL;
s->mix.modcnt++;
switch (_IOC_NR(cmd)) {
rl = (l < 4 ? 0 : (l - 5) / 3) & 31;
rr = (rl >> 2) & 7;
wrmixer(s, mixtable[i].left, rl<<3);
- outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
+ maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
break;
case MT_5MUTEMONO:
rl = l < 4 ? 0 : (l - 5) / 3;
rr = rl >> 2;
wrmixer(s, mixtable[i].left, rl<<3);
- outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
+ maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
break;
case MT_5MUTE:
wrmixer(s, mixtable[i].left, rl<<3);
wrmixer(s, mixtable[i].right, rr<<3);
break;
-
+
case MT_6MUTE:
if (l < 6)
rl = 0x00;
release: cm_release_mixdev,
};
+
/* --------------------------------------------------------------------- */
static int drain_dac(struct cm_state *s, int nonblock)
{
- DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int count, tmo;
if (s->dma_dac.mapped || !s->dma_dac.ready)
return 0;
+ current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&s->dma_dac.wait, &wait);
for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
current->state = TASK_RUNNING;
return -EBUSY;
}
- tmo = (count * HZ) / s->ratedac;
+ tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
- if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "cmpci: dma timed out??\n");
+ if (!schedule_timeout(tmo + 1))
+ printk(KERN_DEBUG "cm: dma timed out??\n");
}
remove_wait_queue(&s->dma_dac.wait, &wait);
current->state = TASK_RUNNING;
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
- printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+ printk(KERN_DEBUG "cm: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
spin_lock_irqsave(&s->lock, flags);
- set_dmaadc(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.dmasamples);
+ stop_adc_unlocked(s);
+ set_dmaadc(s, s->dma_adc.rawphys, s->dma_adc.dmasamples);
/* program sample counts */
- outw(s->dma_adc.fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+ set_countadc(s, s->dma_adc.fragsamples);
s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
spin_unlock_irqrestore(&s->lock, flags);
}
spin_lock_irqsave(&s->lock, flags);
s->dma_adc.swptr = swptr;
s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
count -= cnt;
buffer += cnt;
ret += cnt;
- start_adc(s);
+ start_adc_unlocked(s);
+ spin_unlock_irqrestore(&s->lock, flags);
}
return ret;
}
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
+ if (s->status & DO_DUAL_DAC) {
+ if (s->dma_adc.mapped)
+ return -ENXIO;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+ }
ret = 0;
#if 0
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
spin_unlock_irqrestore(&s->lock, flags);
-#endif
+#endif
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
if (s->dma_dac.count < 0) {
s->dma_dac.count = 0;
s->dma_dac.swptr = s->dma_dac.hwptr;
}
+ if (s->status & DO_DUAL_DAC) {
+ s->dma_adc.swptr = s->dma_dac.swptr;
+ s->dma_adc.count = s->dma_dac.count;
+ s->dma_adc.endcleared = s->dma_dac.endcleared;
+ }
swptr = s->dma_dac.swptr;
cnt = s->dma_dac.dmasize-swptr;
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
+ if (s->status & DO_AC3_SW) {
+ if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize)
+ cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2;
+ } else {
+ if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+ cnt = s->dma_dac.dmasize - s->dma_dac.count;
+ }
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
+ if ((s->status & DO_DUAL_DAC) && (cnt > count / 2))
+ cnt = count / 2;
if (cnt <= 0) {
start_dac(s);
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
- printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+ printk(KERN_DEBUG "cm: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
s->dma_dac.hwptr, s->dma_dac.swptr);
- stop_dac(s);
spin_lock_irqsave(&s->lock, flags);
- set_dmadac(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.dmasamples);
+ stop_dac_unlocked(s);
+ set_dmadac(s, s->dma_dac.rawphys, s->dma_dac.dmasamples);
/* program sample counts */
- outw(s->dma_dac.fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+ set_countdac(s, s->dma_dac.fragsamples);
s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+ if (s->status & DO_DUAL_DAC) {
+ set_dmadac1(s, s->dma_adc.rawphys, s->dma_adc.dmasamples);
+ s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+ }
spin_unlock_irqrestore(&s->lock, flags);
}
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
}
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+ if (s->status & DO_AC3_SW) {
+ // clip exceeded data, caught by 033 and 037
+ if (swptr + 2 * cnt > s->dma_dac.dmasize)
+ cnt = (s->dma_dac.dmasize - swptr) / 2;
+ trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt);
+ swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize;
+ } else if (s->status & DO_DUAL_DAC) {
+ int i;
+ unsigned long *src, *dst0, *dst1;
+
+ src = (unsigned long *) buffer;
+ dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr);
+ dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr);
+ // copy left/right sample at one time
+ for (i = 0; i <= cnt / 4; i++) {
+ *dst0++ = *src++;
+ *dst1++ = *src++;
+ }
+ swptr = (swptr + cnt) % s->dma_dac.dmasize;
+ } else {
+ if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
+ return ret ? ret : -EFAULT;
+ swptr = (swptr + cnt) % s->dma_dac.dmasize;
+ }
spin_lock_irqsave(&s->lock, flags);
s->dma_dac.swptr = swptr;
s->dma_dac.count += cnt;
+ if (s->status & DO_AC3_SW)
+ s->dma_dac.count += cnt;
s->dma_dac.endcleared = 0;
spin_unlock_irqrestore(&s->lock, flags);
count -= cnt;
buffer += cnt;
ret += cnt;
+ if (s->status & DO_DUAL_DAC) {
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ }
start_dac(s);
}
return ret;
}
-/* No kernel lock - fine (we have our own spinlock) */
static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
{
struct cm_state *s = (struct cm_state *)file->private_data;
unsigned int mask = 0;
VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf(s, 0))
- return 0;
+ if (file->f_mode & FMODE_WRITE)
poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf(s, 1))
- return 0;
+ if (file->f_mode & FMODE_READ)
poll_wait(file, &s->dma_adc.wait, wait);
- }
-
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
if (file->f_mode & FMODE_READ) {
VALIDATE_STATE(s);
lock_kernel();
if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
+ if ((ret = prog_dmabuf(s, 0)) != 0)
goto out;
db = &s->dma_dac;
} else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
+ if ((ret = prog_dmabuf(s, 1)) != 0)
goto out;
db = &s->dma_adc;
- } else
+ } else
goto out;
ret = -EINVAL;
if (vma->vm_pgoff != 0)
size = vma->vm_end - vma->vm_start;
if (size > (PAGE_SIZE << db->buforder))
goto out;
- ret = -EAGAIN;
+ ret = -EINVAL;
if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
goto out;
db->mapped = 1;
return 0;
case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+ return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, (int *)arg);
case SNDCTL_DSP_RESET:
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
synchronize_irq();
s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+ if (s->status & DO_DUAL_DAC)
+ s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
}
if (file->f_mode & FMODE_READ) {
stop_adc(s);
return 0;
case SNDCTL_DSP_SPEED:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *)arg))
return -EFAULT;
if (val >= 0) {
if (file->f_mode & FMODE_READ) {
- stop_adc(s);
+ spin_lock_irqsave(&s->lock, flags);
+ stop_adc_unlocked(s);
s->dma_adc.ready = 0;
- set_adc_rate(s, val);
+ set_adc_rate_unlocked(s, val);
+ spin_unlock_irqrestore(&s->lock, flags);
}
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
s->dma_dac.ready = 0;
+ if (s->status & DO_DUAL_DAC)
+ s->dma_adc.ready = 0;
set_dac_rate(s, val);
}
}
return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
-
+
case SNDCTL_DSP_STEREO:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *)arg))
return -EFAULT;
fmtd = 0;
fmtm = ~0;
fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
else
fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
+ if (s->status & DO_DUAL_DAC) {
+ s->dma_adc.ready = 0;
+ if (val)
+ fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+ else
+ fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+ }
}
set_fmt(s, fmtm, fmtd);
return 0;
case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *)arg))
return -EFAULT;
if (val != 0) {
fmtd = 0;
fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
else
fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
+ if (s->status & DO_DUAL_DAC) {
+ s->dma_adc.ready = 0;
+ if (val >= 2)
+ fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+ else
+ fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+ }
}
set_fmt(s, fmtm, fmtd);
- }
+ if ((s->capability & CAN_MULTI_CH)
+ && (file->f_mode & FMODE_WRITE)) {
+ val = set_dac_channels(s, val);
+ return put_user(val, (int *)arg);
+ }
+ }
return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT)
: (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, (int *)arg);
case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
+ return put_user(AFMT_S16_LE|AFMT_U8|AFMT_AC3, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
if (get_user(val, (int *)arg))
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
+ if (val == AFMT_S16_LE || val == AFMT_AC3)
fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
else
fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT);
+ if (val == AFMT_AC3) {
+ fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+ set_ac3(s, s->ratedac);
+ } else
+ set_ac3(s, 0);
+ if (s->status & DO_DUAL_DAC) {
+ s->dma_adc.ready = 0;
+ if (val == AFMT_S16_LE)
+ fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+ else
+ fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+ }
}
set_fmt(s, fmtm, fmtd);
}
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
+ if (s->status & DO_AC3) return put_user(AFMT_AC3, (int *)arg);
+ return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
: (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? AFMT_S16_LE : AFMT_U8, (int *)arg);
-
+
case SNDCTL_DSP_POST:
return 0;
case SNDCTL_DSP_GETTRIGGER:
val = 0;
- if (file->f_mode & FMODE_READ && s->enable & CM_CENABLE_RE)
+ if (s->status & DO_DUAL_DAC) {
+ if (file->f_mode & FMODE_WRITE &&
+ (s->enable & CM_ENABLE_CH1) &&
+ (s->enable & CM_ENABLE_CH0))
+ val |= PCM_ENABLE_OUTPUT;
+ return put_user(val, (int *)arg);
+ }
+ if (file->f_mode & FMODE_READ && s->enable & CM_ENABLE_CH0)
val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->enable & CM_CENABLE_PE)
+ if (file->f_mode & FMODE_WRITE && s->enable & CM_ENABLE_CH1)
val |= PCM_ENABLE_OUTPUT;
return put_user(val, (int *)arg);
-
+
case SNDCTL_DSP_SETTRIGGER:
if (get_user(val, (int *)arg))
return -EFAULT;
if (val & PCM_ENABLE_OUTPUT) {
if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
return ret;
+ if (s->status & DO_DUAL_DAC) {
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
+ }
start_dac(s);
} else
stop_dac(s);
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
+ if (!(s->enable & CM_ENABLE_CH1) && (val = prog_dmabuf(s, 0)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+ abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
+ if (!(s->enable & CM_ENABLE_CH0) && (val = prog_dmabuf(s, 1)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
val = s->dma_dac.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
cinfo.ptr = s->dma_dac.hwptr;
if (s->dma_dac.mapped)
s->dma_dac.count &= s->dma_dac.fragsize-1;
+ if (s->status & DO_DUAL_DAC) {
+ if (s->dma_adc.mapped)
+ s->dma_adc.count &= s->dma_adc.fragsize-1;
+ }
spin_unlock_irqrestore(&s->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf(s, 0)))
return val;
+ if (s->status & DO_DUAL_DAC) {
+ if ((val = prog_dmabuf(s, 1)))
+ return val;
+ return put_user(2 * s->dma_dac.fragsize, (int *)arg);
+ }
return put_user(s->dma_dac.fragsize, (int *)arg);
}
if ((val = prog_dmabuf(s, 1)))
return put_user(s->dma_adc.fragsize, (int *)arg);
case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *)arg))
return -EFAULT;
if (file->f_mode & FMODE_READ) {
s->dma_adc.ossfragshift = val & 0xffff;
s->dma_dac.ossfragshift = 15;
if (s->dma_dac.ossmaxfrags < 4)
s->dma_dac.ossmaxfrags = 4;
+ if (s->status & DO_DUAL_DAC) {
+ s->dma_adc.ossfragshift = s->dma_dac.ossfragshift;
+ s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags;
+ }
}
return 0;
if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
(file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
return -EINVAL;
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *)arg))
return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
if (file->f_mode & FMODE_READ)
s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
+ if (file->f_mode & FMODE_WRITE) {
s->dma_dac.subdivision = val;
+ if (s->status & DO_DUAL_DAC)
+ s->dma_adc.subdivision = val;
+ }
return 0;
case SOUND_PCM_READ_RATE:
case SOUND_PCM_READ_FILTER:
return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
- case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_GETCHANNELMASK:
+ return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, (int *)arg);
+
+ case SNDCTL_DSP_BIND_CHANNEL:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val == DSP_BIND_QUERY) {
+ val = DSP_BIND_FRONT;
+ if (s->status & DO_SPDIF_OUT)
+ val |= DSP_BIND_SPDIF;
+ else {
+ if (s->curr_channels == 4)
+ val |= DSP_BIND_SURR;
+ if (s->curr_channels > 4)
+ val |= DSP_BIND_CENTER_LFE;
+ }
+ } else {
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val & DSP_BIND_SPDIF) {
+ set_spdifout(s, s->ratedac);
+ set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1);
+ if (!(s->status & DO_SPDIF_OUT))
+ val &= ~DSP_BIND_SPDIF;
+ } else {
+ int channels;
+ int mask;
+
+ mask = val & (DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE);
+ switch (mask) {
+ case DSP_BIND_FRONT:
+ channels = 2;
+ break;
+ case DSP_BIND_FRONT|DSP_BIND_SURR:
+ channels = 4;
+ break;
+ case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
+ channels = 6;
+ break;
+ default:
+ channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
+ break;
+ }
+ set_dac_channels(s, channels);
+ }
+ }
+ }
+ return put_user(val, (int *)arg);
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
case SNDCTL_DSP_SETSYNCRO:
return -EINVAL;
fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
set_dac_rate(s, 8000);
+ // clear previous multichannel, spdif, ac3 state
+ set_spdifout(s, 0);
+ if (s->deviceid == PCI_DEVICE_ID_CMEDIA_CM8738) {
+ set_ac3(s, 0);
+ set_dac_channels(s, 1);
+ }
}
set_fmt(s, fmtm, fmts);
s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
down(&s->open_sem);
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
+#ifndef FIXEDDMA
dealloc_dmabuf(&s->dma_dac);
+ if (s->status & DO_DUAL_DAC)
+ dealloc_dmabuf(&s->dma_adc);
+#endif
+ if (s->status & DO_MULTI_CH)
+ set_dac_channels(s, 0);
+ if (s->status & DO_AC3)
+ set_ac3(s, 0);
+ if (s->status & DO_SPDIF_OUT)
+ set_spdifout(s, 0);
}
if (file->f_mode & FMODE_READ) {
stop_adc(s);
+#ifndef FIXEDDMA
dealloc_dmabuf(&s->dma_adc);
+#endif
}
s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
up(&s->open_sem);
release: cm_release,
};
+#ifdef CONFIG_SOUND_CMPCI_MIDI
/* --------------------------------------------------------------------- */
static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
return -ESPIPE;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
- if (count == 0)
- return 0;
ret = 0;
add_wait_queue(&s->midi.iwait, &wait);
while (count > 0) {
- set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
ptr = s->midi.ird;
cnt = MIDIINBUF - ptr;
if (cnt > count)
cnt = count;
if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK)
{
if (!ret)
ret = -EAGAIN;
break;
}
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule();
- if (signal_pending(current))
+ if (signal_pending(current))
{
if (!ret)
ret = -ERESTARTSYS;
}
continue;
}
- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+ if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
+ {
if (!ret)
ret = -EFAULT;
break;
ret = 0;
add_wait_queue(&s->midi.owait, &wait);
while (count > 0) {
- set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
ptr = s->midi.owr;
cnt = MIDIOUTBUF - ptr;
if (cnt > count)
cnt = count;
if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
+ if (file->f_flags & O_NONBLOCK)
+ {
if (!ret)
ret = -EAGAIN;
break;
}
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
}
continue;
}
- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+ if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
+ {
if (!ret)
ret = -EFAULT;
break;
s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
/* enable MPU-401 */
- outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 4, s->iobase + CODEC_CMI_FUNCTRL1);
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 4);
outb(0xff, s->iomidi+1); /* reset command */
if (!(inb(s->iomidi+1) & 0x80))
inb(s->iomidi);
spin_unlock_irqrestore(&s->lock, flags);
s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
up(&s->open_sem);
+ MOD_INC_USE_COUNT;
return 0;
}
static int cm_midi_release(struct inode *inode, struct file *file)
{
struct cm_state *s = (struct cm_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
unsigned count, tmo;
VALIDATE_STATE(s);
-
lock_kernel();
+
if (file->f_mode & FMODE_WRITE) {
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->midi.ocnt;
spin_unlock_irqrestore(&s->lock, flags);
if (file->f_flags & O_NONBLOCK) {
remove_wait_queue(&s->midi.owait, &wait);
set_current_state(TASK_RUNNING);
+ unlock_kernel();
return -EBUSY;
}
tmo = (count * HZ) / 3100;
if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "cmpci: midi timed out??\n");
+ printk(KERN_DEBUG "cm: midi timed out??\n");
}
remove_wait_queue(&s->midi.owait, &wait);
set_current_state(TASK_RUNNING);
if (!(inb(s->iomidi+1) & 0x80))
inb(s->iomidi);
/* disable MPU-401 */
- outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~4, s->iobase + CODEC_CMI_FUNCTRL1);
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~4, 0);
}
spin_unlock_irqrestore(&s->lock, flags);
up(&s->open_sem);
open: cm_midi_open,
release: cm_midi_release,
};
+#endif
/* --------------------------------------------------------------------- */
+#ifdef CONFIG_SOUND_CMPCI_FM
static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
static const unsigned char op_offset[18] = {
outb(5, s->iosynth+2);
outb(arg & 1, s->iosynth+3);
return 0;
-
- default:
- return -EINVAL;
}
+ return -EINVAL;
}
static int cm_dmfm_open(struct inode *inode, struct file *file)
outb(1, s->iosynth+3); /* enable OPL3 */
s->open_mode |= FMODE_DMFM;
up(&s->open_sem);
+ MOD_INC_USE_COUNT;
return 0;
}
open: cm_dmfm_open,
release: cm_dmfm_release,
};
+#endif /* CONFIG_SOUND_CMPCI_FM */
/* --------------------------------------------------------------------- */
int mixch;
int vol;
} initvol[] __initdata = {
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x4040 },
- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 }
+ { SOUND_MIXER_WRITE_CD, 0x4f4f },
+ { SOUND_MIXER_WRITE_LINE, 0x4f4f },
+ { SOUND_MIXER_WRITE_MIC, 0x4f4f },
+ { SOUND_MIXER_WRITE_SYNTH, 0x4f4f },
+ { SOUND_MIXER_WRITE_VOLUME, 0x4f4f },
+ { SOUND_MIXER_WRITE_PCM, 0x4f4f }
};
-#ifdef MODULE
-static int spdif_loop = 0;
-static int four_ch = 0;
-static int rear_out = 0;
-MODULE_PARM(spdif_loop, "i");
-MODULE_PARM(four_ch, "i");
-MODULE_PARM(rear_out, "i");
+/* check chip version and capability */
+static int query_chip(struct cm_state *s)
+{
+ int ChipVersion = -1;
+ unsigned char RegValue;
+
+ // check reg 0Ch, bit 24-31
+ RegValue = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 3);
+ if (RegValue == 0) {
+ // check reg 08h, bit 24-28
+ RegValue = inb(s->iobase + CODEC_CMI_CHFORMAT + 3);
+ RegValue &= 0x1f;
+ if (RegValue == 0) {
+ ChipVersion = 33;
+ s->max_channels = 4;
+ s->capability |= CAN_AC3_SW;
+ s->capability |= CAN_DUAL_DAC;
+ } else {
+ ChipVersion = 37;
+ s->max_channels = 4;
+ s->capability |= CAN_AC3_HW;
+ s->capability |= CAN_DUAL_DAC;
+ }
+ } else {
+ // check reg 0Ch, bit 26
+ if (RegValue & (1 << (26-24))) {
+ ChipVersion = 39;
+ if (RegValue & (1 << (24-24)))
+ s->max_channels = 6;
+ else
+ s->max_channels = 4;
+ s->capability |= CAN_AC3_HW;
+ s->capability |= CAN_DUAL_DAC;
+ s->capability |= CAN_MULTI_CH_HW;
+ } else {
+ ChipVersion = 55; // 4 or 6 channels
+ s->max_channels = 6;
+ s->capability |= CAN_AC3_HW;
+ s->capability |= CAN_DUAL_DAC;
+ s->capability |= CAN_MULTI_CH_HW;
+ }
+ }
+ // still limited to number of speakers
+ if (s->max_channels > s->speakers)
+ s->max_channels = s->speakers;
+ return ChipVersion;
+}
+
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+static int mpu_io = CONFIG_SOUND_CMPCI_MPUIO;
#else
+static int mpu_io;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+static int fm_io = CONFIG_SOUND_CMPCI_FMIO;
+#else
+static int fm_io;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_SPDIFINVERSE
+static int spdif_inverse = 1;
+#else
+static int spdif_inverse;
+#endif
#ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP
-static int spdif_loop = 1;
+static int spdif_loop = 1;
#else
-static int spdif_loop = 0;
+static int spdif_loop;
#endif
-#ifdef CONFIG_SOUND_CMPCI_4CH
-static int four_ch = 1;
+#ifdef CONFIG_SOUND_CMPCI_SPEAKERS
+static int speakers = CONFIG_SOUND_CMPCI_SPEAKERS;
#else
-static int four_ch = 0;
+static int speakers = 2;
#endif
-#ifdef CONFIG_SOUND_CMPCI_REAR
-static int rear_out = 1;
+#ifdef CONFIG_SOUND_CMPCI_LINE_REAR
+static int use_line_as_rear = 1;
#else
-static int rear_out = 0;
+static int use_line_as_rear;
#endif
+#ifdef CONFIG_SOUND_CMPCI_LINE_BASS
+static int use_line_as_bass = 1;
+#else
+static int use_line_as_bass;
#endif
-
-static int __init init_cmpci(void)
+#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
+static int joystick = 1;
+#else
+static int joystick;
+#endif
+MODULE_PARM(mpu_io, "i");
+MODULE_PARM(fm_io, "i");
+MODULE_PARM(spdif_inverse, "i");
+MODULE_PARM(spdif_loop, "i");
+MODULE_PARM(speakers, "i");
+MODULE_PARM(use_line_as_rear, "i");
+MODULE_PARM(use_line_as_bass, "i");
+MODULE_PARM(joystick, "i");
+MODULE_PARM_DESC(mpu_io, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");
+MODULE_PARM_DESC(fm_io, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");
+MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");
+MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly");
+MODULE_PARM_DESC(speakers, "(2-6) Number of speakers you connect");
+MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");
+MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");
+MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");
+
+void initialize_chip(struct pci_dev *pcidev)
{
struct cm_state *s;
- struct pci_dev *pcidev = NULL;
mm_segment_t fs;
- int i, val, index = 0;
-
+ int i, val;
+ unsigned char reg_mask = 0;
struct {
unsigned short deviceid;
char *devicename;
{ PCI_DEVICE_ID_CMEDIA_CM8338A, "CM8338A" },
{ PCI_DEVICE_ID_CMEDIA_CM8338B, "CM8338B" },
{ PCI_DEVICE_ID_CMEDIA_CM8738, "CM8738" },
+ { PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" },
};
char *devicename = "unknown";
-
-#ifdef CONFIG_PCI
- if (!pci_present()) /* No PCI bus in this machine! */
-#endif
- return -ENODEV;
- printk(KERN_INFO "cmpci: version v2.41-nomodem time " __TIME__ " " __DATE__ "\n");
-#if 0
- if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
- printk(KERN_INFO "cmpci: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
-#endif
- while (index < NR_DEVICE && pcidev == NULL && (
- (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)) ||
- (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, pcidev)) ||
- (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) {
+ {
if (pci_enable_device(pcidev))
- continue;
+ return;
if (pcidev->irq == 0)
- continue;
- if (!(s = kmalloc(sizeof(struct cm_state), GFP_KERNEL))) {
- printk(KERN_WARNING "cmpci: out of memory\n");
- continue;
+ return;
+ s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (!s) {
+ printk(KERN_WARNING "cm: out of memory\n");
+ return;
}
/* search device name */
- for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++)
- {
+ for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
if (devicetable[i].deviceid == pcidev->device)
{
devicename = devicetable[i].devicename;
spin_lock_init(&s->lock);
s->magic = CM_MAGIC;
s->iobase = pci_resource_start(pcidev, 0);
- s->iosynth = 0x388;
- s->iomidi = 0x330;
- spin_lock_init(&s->lock);
+ s->iosynth = fm_io;
+ s->iomidi = mpu_io;
+ s->status = 0;
+ /* range check */
+ if (speakers < 2)
+ speakers = 2;
+ else if (speakers > 6)
+ speakers = 6;
+ s->speakers = speakers;
if (s->iobase == 0)
- continue;
+ return;
s->irq = pcidev->irq;
if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
- printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
+ printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
goto err_region5;
}
- if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) {
- printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, midi disabled.\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+ /* disable MPU-401 */
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
+ if (s->iomidi) {
+ if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) {
+ printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
s->iomidi = 0;
+ } else {
+ /* set IO based at 0x330 */
+ switch (s->iomidi) {
+ case 0x330:
+ reg_mask = 0;
+ break;
+ case 0x320:
+ reg_mask = 0x20;
+ break;
+ case 0x310:
+ reg_mask = 0x40;
+ break;
+ case 0x300:
+ reg_mask = 0x60;
+ break;
+ default:
+ s->iomidi = 0;
+ break;
+ }
+ outb((inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60) | reg_mask, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
+ /* enable MPU-401 */
+ if (s->iomidi) {
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
+ }
+ }
}
- else
- {
- /* set IO based at 0x330 */
- outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
- }
- if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) {
- printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, synth disabled.\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+ /* disable FM */
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
+ if (s->iosynth) {
+ if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) {
+ printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
s->iosynth = 0;
+ } else {
+ /* set IO based at 0x388 */
+ switch (s->iosynth) {
+ case 0x388:
+ reg_mask = 0;
+ break;
+ case 0x3C8:
+ reg_mask = 0x01;
+ break;
+ case 0x3E0:
+ reg_mask = 0x02;
+ break;
+ case 0x3E8:
+ reg_mask = 0x03;
+ break;
+ default:
+ s->iosynth = 0;
+ break;
+ }
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
+ /* enable FM */
+ if (s->iosynth) {
+ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
+ }
+ }
}
+#endif
+ /* enable joystick */
+ if (joystick)
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
else
- {
- /* enable FM */
- outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL);
- }
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
/* initialize codec registers */
outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
/* request irq */
if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) {
- printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
+ printk(KERN_ERR "cm: irq %u in use\n", s->irq);
goto err_irq;
}
- printk(KERN_INFO "cmpci: found %s adapter at io %#06x irq %u\n",
+ printk(KERN_INFO "cm: found %s adapter at io %#06x irq %u\n",
devicename, s->iobase, s->irq);
/* register devices */
if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0)
goto err_dev1;
if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0)
goto err_dev2;
- if (s->iomidi && (s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+ if ((s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
goto err_dev3;
- if (s->iosynth && (s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+ if ((s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
goto err_dev4;
- pci_set_master(pcidev);
+#endif
+ pci_set_master(pcidev); /* enable bus mastering */
/* initialize the chips */
fs = get_fs();
set_fs(KERNEL_DS);
val = initvol[i].vol;
mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
}
- set_fs(fs);
- if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738)
- {
+ /* use channel 0 for record, channel 1 for play */
+ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 1);
+ s->deviceid = pcidev->device;
+ if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738) {
+ /* chip version and hw capability check */
+ s->chip_version = query_chip(s);
+ printk(KERN_INFO "chip version = 0%d\n", s->chip_version);
+ /* seet SPDIF-in inverse before enable SPDIF loop */
+ if (spdif_inverse) {
+ /* turn on spdif-in inverse */
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
+ printk(KERN_INFO "cm: Inverse SPDIF-in\n");
+ } else {
+ /* turn off spdif-ininverse */
+ maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
+ }
+
/* enable SPDIF loop */
- if (spdif_loop)
- {
+ if (spdif_loop) {
+ s->status |= DO_SPDIF_LOOP;
/* turn on spdif-in to spdif-out */
- outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 0x80, s->iobase + CODEC_CMI_FUNCTRL1);
- printk(KERN_INFO "cmpci: Enable SPDIF loop\n");
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x80);
+ printk(KERN_INFO "cm: Enable SPDIF loop\n");
+ } else {
+ s->status &= ~DO_SPDIF_LOOP;
+ /* turn off spdif-in to spdif-out */
+ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x80, 0);
}
- else
- outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~0x80, s->iobase + CODEC_CMI_FUNCTRL1);
- /* enable 4 channels mode */
- if (four_ch)
- {
- /* 4 channel mode (analog duplicate) */
- outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) | 0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
- printk(KERN_INFO "cmpci: Enable 4 channels mode\n");
- /* has separate rear-out jack ? */
- if (rear_out)
- {
- /* has separate rear out jack */
- outb(inb(s->iobase + CODEC_CMI_MIXER1) & ~0x20, s->iobase + CODEC_CMI_MIXER1);
- }
- else
- {
- outb(inb(s->iobase + CODEC_CMI_MIXER1) | 0x20, s->iobase + CODEC_CMI_MIXER1);
- printk(KERN_INFO "cmpci: line-in routed as rear-out\n");
- }
+ if (use_line_as_rear) {
+ s->capability |= CAN_LINE_AS_REAR;
+ s->status |= DO_LINE_AS_REAR;
+ maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 0x20);
+ } else
+ maskb(s->iobase + CODEC_CMI_MIXER1, ~0x20, 0);
+ if (s->chip_version >= 39) {
+ if (use_line_as_bass) {
+ s->capability |= CAN_LINE_AS_BASS;
+ s->status |= DO_LINE_AS_BASS;
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, 0x60);
+ } else
+ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x60, 0);
}
- else
- outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) & ~0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
+ } else {
+ /* 8338 will fall here */
+ s->max_channels = 2;
}
/* queue it for later freeing */
s->next = devs;
devs = s;
- index++;
- continue;
+ return;
+#ifdef CONFIG_SOUND_CMPCI_FM
+ unregister_sound_special(s->dev_dmfm);
err_dev4:
+#endif
+#ifdef CONFIG_SOUND_CMPCI_MIDI
unregister_sound_midi(s->dev_midi);
err_dev3:
+#endif
unregister_sound_mixer(s->dev_mixer);
err_dev2:
unregister_sound_dsp(s->dev_audio);
err_dev1:
- printk(KERN_ERR "cmpci: cannot register misc device\n");
+ printk(KERN_ERR "cm: cannot register misc device\n");
free_irq(s->irq, s);
err_irq:
- if(s->iosynth)
- release_region(s->iosynth, CM_EXTENT_SYNTH);
- if(s->iomidi)
- release_region(s->iomidi, CM_EXTENT_MIDI);
+#ifdef CONFIG_SOUND_CMPCI_FM
+ if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+ if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
+#endif
release_region(s->iobase, CM_EXTENT_CODEC);
err_region5:
kfree(s);
if (!devs) {
if (wavetable_mem)
free_pages(wavetable_mem, 20-PAGE_SHIFT);
+ return;
+ }
+ return;
+}
+
+static int __init init_cmpci(void)
+{
+ struct pci_dev *pcidev = NULL;
+ int index = 0;
+
+#ifdef CONFIG_PCI
+ if (!pci_present()) /* No PCI bus in this machine! */
+#endif
return -ENODEV;
+ printk(KERN_INFO "cm: version $Revision: 5.64 $ time " __TIME__ " " __DATE__ "\n");
+#if 0
+ if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
+ printk(KERN_INFO "cm: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
+#endif
+ while (index < NR_DEVICE && (
+ (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) {
+ initialize_chip(pcidev);
+ index++;
+ }
+ while (index < NR_DEVICE && (
+ (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)))) {
+ initialize_chip(pcidev);
+ index++;
+ }
+ while (index < NR_DEVICE && (
+ (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, pcidev)))) {
+ initialize_chip(pcidev);
+ index++;
}
return 0;
}
/* --------------------------------------------------------------------- */
-MODULE_AUTHOR("ChenLi Tien, cltien@home.com");
-MODULE_DESCRIPTION("CMPCI Audio Driver");
+MODULE_AUTHOR("ChenLi Tien, cltien@cmedia.com.tw");
+MODULE_DESCRIPTION("CM8x38 Audio Driver");
static void __exit cleanup_cmpci(void)
{
synchronize_irq();
outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
free_irq(s->irq, s);
+#ifdef FIXEDDMA
+ dealloc_dmabuf(&s->dma_dac);
+ dealloc_dmabuf(&s->dma_adc);
+#endif
/* reset mixer */
wrmixer(s, DSP_MIX_DATARESETIDX, 0);
release_region(s->iobase, CM_EXTENT_CODEC);
- if(s->iomidi)
- {
- release_region(s->iomidi, CM_EXTENT_MIDI);
- unregister_sound_midi(s->dev_midi);
- }
- if(s->iosynth)
- {
- release_region(s->iosynth, CM_EXTENT_SYNTH);
- unregister_sound_special(s->dev_dmfm);
- }
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+ if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+ if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
+#endif
unregister_sound_dsp(s->dev_audio);
unregister_sound_mixer(s->dev_mixer);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+ unregister_sound_midi(s->dev_midi);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+ unregister_sound_special(s->dev_dmfm);
+#endif
kfree(s);
}
if (wavetable_mem)
free_pages(wavetable_mem, 20-PAGE_SHIFT);
- printk(KERN_INFO "cmpci: unloading\n");
+ printk(KERN_INFO "cm: unloading\n");
}
module_init(init_cmpci);
card->pBA0 + BA0_ACCTL);
// Wait for the write to occur.
- for (count = 0; count < 10; count++) {
+ for (count = 0; count < 100; count++) {
// First, we want to wait for a short time.
udelay(25);
// Now, check to see if the write has completed.
unregister_sound_midi(s->dev_midi);
iounmap(s->pBA1);
iounmap(s->pBA0);
- kfree(s);
pci_set_drvdata(pci_dev,NULL);
list_del(&s->list);
+ kfree(s);
CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
"cs4281: cs4281_remove()-: remove successful\n"));
}
* 20010409-tw add hercules game theatre XP amp code.
* 20010420-tw cleanup powerdown/up code.
* 20010521-tw eliminate pops, and fixes for powerdown.
+ * 20010525-tw added fixes for thinkpads with powerdown logic.
*
* Status:
* Playback/Capture supported from 8k-48k.
MODULE_PARM(hercules_egpio_disable, "i");
static unsigned long initdelay=700; /* PM delay in millisecs */
MODULE_PARM(initdelay, "i");
-static unsigned long powerdown=1; /* turn on/off powerdown processing in driver */
+static unsigned long powerdown=-1; /* turn on/off powerdown processing in driver */
MODULE_PARM(powerdown, "i");
#define DMABUF_DEFAULTORDER 3
static unsigned long defaultorder=DMABUF_DEFAULTORDER;
static int thinkpad;
MODULE_PARM(thinkpad, "i");
+/*
+* set the powerdown module parm to 0 to disable all
+* powerdown. also set thinkpad to 1 to disable powerdown,
+* but also to enable the clkrun functionality.
+*/
+static unsigned cs_powerdown=1;
+static unsigned cs_laptop_wait=1;
+
/* An instance of the 4610 channel */
struct cs_channel
{
};
#define CS46XX_MAJOR_VERSION "1"
-#define CS46XX_MINOR_VERSION "27"
+#define CS46XX_MINOR_VERSION "28"
#ifdef __ia64__
#define CS46XX_ARCH "64" //architecture key
int ossmaxfrags;
unsigned subdivision;
} dmabuf;
+ /* Guard against mmap/write/read races */
+ struct semaphore sem;
};
struct cs_card {
static loff_t cs_llseek(struct file *file, loff_t offset, int origin);
static int cs_hardware_init(struct cs_card *card);
static int cs46xx_powerup(struct cs_card *card, unsigned int type);
-static int cs461x_powerdown(struct cs_card *card, unsigned int type);
+static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
+static void cs46xx_suspend_tbl(struct pci_dev *pcidev);
+static void cs46xx_resume_tbl(struct pci_dev *pcidev);
static inline unsigned ld2(unsigned int x)
{
{
struct ac97_codec *dev=card->ac97_codec[0];
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mute()+ %s\n",
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()+ %s\n",
(state == CS_TRUE) ? "Muting" : "UnMuting") );
if(state == CS_TRUE)
cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume);
}
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mute()-\n"));
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()-\n"));
}
/* set playback sample rate */
dmabuf->SGok = 0;
}
-static int prog_dmabuf(struct cs_state *state)
+static int __prog_dmabuf(struct cs_state *state)
{
struct dmabuf *dmabuf = &state->dmabuf;
unsigned long flags;
return 1;
}
+static int prog_dmabuf(struct cs_state *state)
+{
+ int ret;
+
+ down(&state->sem);
+ ret = __prog_dmabuf(state);
+ up(&state->sem);
+
+ return ret;
+}
+
static void cs_clear_tail(struct cs_state *state)
{
}
return -ESPIPE;
if (dmabuf->mapped)
return -ENXIO;
- if (!dmabuf->ready && (ret = prog_dmabuf(state)))
- return ret;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
- ret = 0;
+
+ down(&state->sem);
+ if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
+ goto out;
add_wait_queue(&state->dmabuf.wait, &wait);
while (count > 0) {
{
schedule();
if (signal_pending(current)) {
- ret = ret ? ret : -ERESTARTSYS;
- break;
+ if(!ret) ret = -ERESTARTSYS;
+ goto out;
}
}
spin_lock_irqsave(&state->card->lock, flags);
start_adc(state);
if (file->f_flags & O_NONBLOCK) {
if (!ret) ret = -EAGAIN;
- break;
+ goto out;
}
+ up(&state->sem);
schedule();
if (signal_pending(current)) {
- ret = ret ? ret : -ERESTARTSYS;
- break;
+ if(!ret) ret = -ERESTARTSYS;
+ goto out;
+ }
+ down(&state->sem);
+ if (dmabuf->mapped)
+ {
+ if(!ret)
+ ret = -ENXIO;
+ goto out;
}
continue;
}
(void *)((unsigned)dmabuf->rawbuf + swptr), cnt, &copied))
{
if (!ret) ret = -EFAULT;
- break;
+ goto out;
}
swptr = (swptr + cnt) % dmabuf->dmasize;
spin_lock_irqsave(&card->lock, flags);
ret += copied;
start_adc(state);
}
+out:
+ up(&state->sem);
remove_wait_queue(&state->dmabuf.wait, &wait);
set_current_state(TASK_RUNNING);
CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
if (ppos != &file->f_pos)
return -ESPIPE;
+
+ down(&state->sem);
if (dmabuf->mapped)
- return -ENXIO;
- if (!dmabuf->ready && (ret = prog_dmabuf(state)))
- return ret;
+ {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
+ goto out;
if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
+ {
+ ret = -EFAULT;
+ goto out;
+ }
add_wait_queue(&state->dmabuf.wait, &wait);
ret = 0;
/*
{
schedule();
if (signal_pending(current)) {
- ret = ret ? ret : -ERESTARTSYS;
- break;
+ if(!ret) ret = -ERESTARTSYS;
+ goto out;
}
}
spin_lock_irqsave(&state->card->lock, flags);
start_dac(state);
if (file->f_flags & O_NONBLOCK) {
if (!ret) ret = -EAGAIN;
- break;
+ goto out;
}
+ up(&state->sem);
schedule();
if (signal_pending(current)) {
- ret = ret ? ret : -ERESTARTSYS;
- break;
+ if(!ret) ret = -ERESTARTSYS;
+ goto out;
}
+ down(&state->sem);
+ if (dmabuf->mapped)
+ {
+ if(!ret)
+ ret = -ENXIO;
+ goto out;
+ }
continue;
}
if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
if (!ret) ret = -EFAULT;
- return ret;
+ goto out;
}
spin_lock_irqsave(&state->card->lock, flags);
swptr = (swptr + cnt) % dmabuf->dmasize;
ret += cnt;
start_dac(state);
}
+out:
+ up(&state->sem);
remove_wait_queue(&state->dmabuf.wait, &wait);
set_current_state(TASK_RUNNING);
struct cs_card *card = (struct cs_card *)file->private_data;
struct cs_state *state;
struct dmabuf *dmabuf;
- int ret;
+ int ret = 0;
unsigned long size;
-
+
CS_DBGOUT(CS_FUNCTION | CS_PARMS, 2, printk("cs46xx: cs_mmap()+ file=0x%x %s %s\n",
(unsigned)file, vma->vm_flags & VM_WRITE ? "VM_WRITE" : "",
vma->vm_flags & VM_READ ? "VM_READ" : "") );
*/
state = card->states[1];
if(!(unsigned)state)
- return -EINVAL;
+ {
+ ret = -EINVAL;
+ goto out;
+ }
+ down(&state->sem);
dmabuf = &state->dmabuf;
if (cs4x_pgoff(vma) != 0)
- return -EINVAL;
+ {
+ ret = -EINVAL;
+ goto out;
+ }
size = vma->vm_end - vma->vm_start;
CS_DBGOUT(CS_PARMS, 2, printk("cs46xx: cs_mmap(): size=%d\n",(unsigned)size) );
if (size > (PAGE_SIZE << dmabuf->buforder))
- return -EINVAL;
+ {
+ ret = -EINVAL;
+ goto out;
+ }
if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
size, vma->vm_page_prot))
- return -EAGAIN;
+ {
+ ret = -EAGAIN;
+ goto out;
+ }
dmabuf->mapped = 1;
CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mmap()-\n") );
- return 0;
+out:
+ up(&state->sem);
+ return ret;
}
static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
if (state == NULL)
return -ENOMEM;
memset(state, 0, sizeof(struct cs_state));
+ init_MUTEX(&state->sem);
dmabuf = &state->dmabuf;
dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL | GFP_DMA);
if(dmabuf->pbuf==NULL)
if (state == NULL)
return -ENOMEM;
memset(state, 0, sizeof(struct cs_state));
+ init_MUTEX(&state->sem);
dmabuf = &state->dmabuf;
dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL | GFP_DMA);
if(dmabuf->pbuf==NULL)
if((ret = prog_dmabuf(state)))
return ret;
}
-
CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n") );
return 0;
}
state->card->states[state->virt] = NULL;
state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
- if( (tmp = cs461x_powerdown(card, CS_POWER_DAC )) )
+ if( (tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE )) )
{
CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
"cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
- return -EIO;
}
/* Now turn off external AMP if needed */
state->card->states[state->virt] = NULL;
state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
- if( (tmp = cs461x_powerdown(card, CS_POWER_ADC )) )
+ if( (tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE )) )
{
CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
"cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
- return -EIO;
}
/* Now turn off external AMP if needed */
void cs46xx_ac97_suspend(struct cs_card *card)
{
int Count,i;
- unsigned int tmp;
struct ac97_codec *dev=card->ac97_codec[0];
+ unsigned int tmp;
CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
* Save the ac97 volume registers as well as the current powerdown state.
* Now, mute the all the outputs (master, headphone, and mono), as well
* as the PCM volume, in preparation for powering down the entire part.
-*/
card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
(u8)BA0_AC97_MASTER_VOLUME);
card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
(u8)BA0_AC97_MASTER_VOLUME_MONO);
card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
(u8)BA0_AC97_PCM_OUT_VOLUME);
-
+*/
+/*
+* mute the outputs
+*/
cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
+/*
+* save the registers that cause pops
+*/
card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL);
card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE);
-
/*
* And power down everything on the AC97 codec.
* well, for now, only power down the DAC/ADC and MIXER VREFON components.
* trouble with removing VREF.
*/
if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON )) )
+ CS_POWER_MIXVON, CS_TRUE )) )
{
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
"cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) );
*/
cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE,
(u16)card->pm.u32AC97_general_purpose);
-
- cs_ac97_set(dev, (u8)AC97_POWER_CONTROL,
- (u16)card->pm.u32AC97_powerdown);
- mdelay(10);
-
/*
* Now, while the outputs are still muted, restore the state of power
* on the AC97 part.
*/
cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown);
- mdelay(5);
+ mdelay(5 * cs_laptop_wait);
/*
* Restore just the first set of registers, from register number
* 0x02 to the register number that ulHighestRegToRestore specifies.
dmabuf->ready = 0;
resync_dma_ptrs(card->states[1]);
cs_set_divisor(dmabuf);
- if(prog_dmabuf(card->states[1]))
+ if(__prog_dmabuf(card->states[1]))
{
CS_DBGOUT(CS_PM | CS_ERROR, 1,
printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
dmabuf->ready = 0;
resync_dma_ptrs(card->states[0]);
cs_set_divisor(dmabuf);
- if(prog_dmabuf(card->states[0]))
+ if(__prog_dmabuf(card->states[0]))
{
CS_DBGOUT(CS_PM | CS_ERROR, 1,
printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
{
CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
"cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
- mdelay(10);
+ mdelay(10 * cs_laptop_wait);
cs461x_reset(card);
continue;
}
if(!(card->pm.flags & CS46XX_PM_IDLE))
loopcnt = 2000;
else
- loopcnt = 500;
+ loopcnt = 500 * cs_laptop_wait;
+ loopcnt *= cs_laptop_wait;
for (count = 0; count < loopcnt; count++) {
/*
* First, we want to wait for a short time.
*/
- udelay(10);
+ udelay(10 * cs_laptop_wait);
/*
* Now, check to see if the read has completed.
* ACCTL = 460h, DCV should be reset by now and 460h = 17h
if(!(card->pm.flags & CS46XX_PM_IDLE))
loopcnt = 2000;
else
- loopcnt = 100;
+ loopcnt = 1000;
+ loopcnt *= cs_laptop_wait;
for (count = 0; count < loopcnt; count++) {
/*
* Read the AC97 status register.
*/
if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
break;
- udelay(10);
+ udelay(10 * cs_laptop_wait);
}
/*
* Make sure we got valid status.
*/
if (!( (tmp=cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x \n", reg, tmp));
- CS_DBGOUT(CS_ERROR, 9, printk(KERN_WARNING "returning 0xffff\n"));
+ CS_DBGOUT(CS_ERROR, 2, printk(KERN_WARNING
+ "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x 0xffff \n",
+ reg, tmp));
return 0xffff;
}
"cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n",
reg, cs461x_peekBA0(card, BA0_ACSDA),
cs461x_peekBA0(card, BA0_ACCAD)));
- return (cs461x_peekBA0(card, BA0_ACSDA));
+ return(cs461x_peekBA0(card, BA0_ACSDA));
}
static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
/*
* First, we want to wait for a short time.
*/
- udelay(10);
+ udelay(10 * cs_laptop_wait);
/*
* Now, check to see if the write has completed.
* ACCTL = 460h, DCV should be reset by now and 460h = 07h
return -ENODEV;
}
match:
- card->active_ctrl(card, -1);
- card->amplifier_ctrl(card, -1);
MOD_DEC_USE_COUNT;
if(!CS_DEC_AND_TEST(&card->mixer_use_cnt))
{
CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
+ card->active_ctrl(card, -1);
+ card->amplifier_ctrl(card, -1);
return 0;
}
/*
* ok, no outstanding mixer opens, so powerdown.
*/
- if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON )) )
+ if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE )) )
{
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
"cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) );
+ card->active_ctrl(card, -1);
+ card->amplifier_ctrl(card, -1);
return -EIO;
}
+ card->active_ctrl(card, -1);
+ card->amplifier_ctrl(card, -1);
CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n"));
return 0;
}
-static int cs461x_powerdown(struct cs_card *card, unsigned int type)
+static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag)
{
int count;
- unsigned int tmp=0;
+ unsigned int tmp=0,muted=0;
CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
"cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
- if(!powerdown)
+ if(!cs_powerdown && !suspendflag)
{
CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
"cs46xx: cs461x_powerdown() DISABLED exiting\n"));
type &= ~CS_POWER_MIXVON;
type &= ~CS_POWER_MIXVOFF;
- cs_mute(card, CS_TRUE);
-
/*
* Power down indicated areas.
*/
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)
{
+ if(!muted)
+ {
+ cs_mute(card, CS_TRUE);
+ muted=1;
+ }
tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
/*
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)
{
+ if(!muted)
+ {
+ cs_mute(card, CS_TRUE);
+ muted=1;
+ }
tmp |= CS_AC97_POWER_CONTROL_MIXVON;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
/*
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
if (tmp & CS_AC97_POWER_CONTROL_ADC_ON)
{
+ if(!muted)
+ {
+ cs_mute(card, CS_TRUE);
+ muted=1;
+ }
tmp |= CS_AC97_POWER_CONTROL_ADC;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
if (tmp & CS_AC97_POWER_CONTROL_DAC_ON)
{
+ if(!muted)
+ {
+ cs_mute(card, CS_TRUE);
+ muted=1;
+ }
tmp |= CS_AC97_POWER_CONTROL_DAC;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
/*
}
}
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- cs_mute(card, CS_FALSE);
+ if(muted)
+ cs_mute(card, CS_FALSE);
CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
"cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
return 0;
static int cs46xx_powerup(struct cs_card *card, unsigned int type)
{
int count;
- unsigned int tmp=0;
+ unsigned int tmp=0,muted=0;
CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
"cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
if(type & (CS_POWER_DAC | CS_POWER_ADC))
type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
- cs_mute(card, CS_TRUE);
/*
* Power up indicated areas.
*/
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON))
{
+ if(!muted)
+ {
+ cs_mute(card, CS_TRUE);
+ muted=1;
+ }
tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
/*
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON))
{
+ if(!muted)
+ {
+ cs_mute(card, CS_TRUE);
+ muted=1;
+ }
tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
/*
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON))
{
+ if(!muted)
+ {
+ cs_mute(card, CS_TRUE);
+ muted=1;
+ }
tmp &= ~CS_AC97_POWER_CONTROL_ADC;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON))
{
+ if(!muted)
+ {
+ cs_mute(card, CS_TRUE);
+ muted=1;
+ }
tmp &= ~CS_AC97_POWER_CONTROL_DAC;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
/*
}
}
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- cs_mute(card, CS_FALSE);
+ if(muted)
+ cs_mute(card, CS_FALSE);
CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
"cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
return 0;
* generating bit clock (so we don't try to start the PLL without an
* input clock).
*/
- mdelay(5); /* 1 should be enough ?? (and pigs might fly) */
+ mdelay(5 * cs_laptop_wait); /* 1 should be enough ?? (and pigs might fly) */
/*
* Set the serial port timing configuration, so that
/*
* Wait until the PLL has stabilized.
*/
- mdelay(5); /* Again 1 should be enough ?? */
+ mdelay(5 * cs_laptop_wait); /* Again 1 should be enough ?? */
/*
* Turn on clocking of the core so that we can setup the serial ports.
cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
- mdelay(5); /* Shouldnt be needed ?? */
+ mdelay(5 * cs_laptop_wait); /* Shouldnt be needed ?? */
/*
* If we are resuming under 2.2.x then we can not schedule a timeout.
{
for (count = 0; count < 100; count++) {
// First, we want to wait for a short time.
- udelay(25);
+ udelay(25 * cs_laptop_wait);
if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
break;
{
for (count = 0; count < 100; count++) {
// First, we want to wait for a short time.
- udelay(25);
+ udelay(25 * cs_laptop_wait);
if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
break;
*/
if(card->pm.flags & CS46XX_PM_IDLE)
{
- if(!powerdown)
+ if(!cs_powerdown)
{
if( (tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
CS_POWER_MIXVON )) )
else
{
if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON )) )
+ CS_POWER_MIXVON, CS_FALSE )) )
{
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
printk(KERN_INFO "cs46xx: probe()+\n"));
+ dma_mask = 0xffffffff; /* this enables playback and recording */
if (pci_enable_device(pci_dev)) {
CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
"cs46xx: pci_enable_device() failed\n"));
"cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n"));
return -1;
}
- dma_mask = 0xffffffff; /* this enables playback and recording */
-
pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
card->active_ctrl = clkrun_hack;
}
-
+/*
+* The thinkpads don't work well without runtime updating on their kernel
+* delay values (or any laptop with variable CPU speeds really).
+* so, just to be safe set the init delay to 2100. Eliminates
+* failures on T21 Thinkpads. remove this code when the udelay
+* and mdelay kernel code is replaced by a pm timer, or the delays
+* work well for battery and/or AC power both.
+*/
+ if(card->active_ctrl == clkrun_hack)
+ {
+ initdelay = 2100;
+ cs_laptop_wait = 5;
+ }
+ if((card->active_ctrl == clkrun_hack) && !(powerdown == 1))
+ {
+/*
+* for some currently unknown reason, powering down the DAC and ADC component
+* blocks on thinkpads causes some funky behavior... distoorrrtion and ac97
+* codec access problems. probably the serial clock becomes unsynced.
+* added code to sync the chips back up, but only helped about 70% the time.
+*/
+ cs_powerdown = 0;
+ }
+ if(powerdown == 0)
+ cs_powerdown = 0;
card->active_ctrl(card, 1);
/* claim our iospace and irq */
unregister_sound_mixer(card->ac97_codec[j]->dev_mixer);
kfree (card->ac97_codec[j]);
}
- mdelay(10);
+ mdelay(10 * cs_laptop_wait);
continue;
}
break;
* them.
*/
if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON )) )
+ CS_POWER_MIXVON, CS_TRUE )) )
{
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
return 0;
}
-static void cs46xx_suspend_tbl(struct pci_dev *pcidev)
+#if CS46XX_ACPI_SUPPORT
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state)
{
struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
cs46xx_suspend(s);
- return;
+ return 0;
}
-static void cs46xx_resume_tbl(struct pci_dev *pcidev)
+static int cs46xx_resume_tbl(struct pci_dev *pcidev)
{
struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n"));
cs46xx_resume(s);
- return;
+ return 0;
}
-
+#endif
* for now (12/22/00) only enable the pm_register PM support.
* allow these table entries to be null.
*/
-static void cs46xx_suspend_tbl(struct pci_dev *pcidev);
-static void cs46xx_resume_tbl(struct pci_dev *pcidev);
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state);
+static int cs46xx_resume_tbl(struct pci_dev *pcidev);
#define cs_pm_register(a, b, c) 0
#define cs_pm_unregister_all(a)
#define CS46XX_SUSPEND_TBL cs46xx_suspend_tbl
* I'm not very good at laying out functions in a file :)
*/
static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-static void m3_suspend(struct pci_dev *pci_dev);
+static int m3_suspend(struct pci_dev *pci_dev, u32 state);
static void check_suspend(struct m3_card *card);
struct notifier_block m3_reboot_nb = {m3_notifier, NULL, 0};
for(card = devs; card != NULL; card = card->next) {
if(!card->in_suspend)
- m3_suspend(card->pcidev); /* XXX legal? */
+ m3_suspend(card->pcidev, 3); /* XXX legal? */
}
return 0;
}
-static void m3_suspend(struct pci_dev *pci_dev)
+static int m3_suspend(struct pci_dev *pci_dev, u32 state)
{
unsigned long flags;
int i;
card->in_suspend = 1;
restore_flags(flags);
+
+ return 0;
}
-static void m3_resume(struct pci_dev *pci_dev)
+static int m3_resume(struct pci_dev *pci_dev)
{
unsigned long flags;
int index;
* when we suspended
*/
wake_up(&card->suspend_queue);
+
+ return 0;
}
MODULE_AUTHOR("Zach Brown <zab@zabbo.net>");
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
+ {"Sound Blaster 16",
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed),
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+ 0,0,0,0,
+ 0,1,1,-1},
{"Sound Blaster Vibra16S",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
+ { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed),
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
+
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), 0 },
switch (cmd) {
case SNDCTL_SYNTH_INFO:
- memcpy (&((char *) arg)[0], &wavefront_info,
- sizeof (wavefront_info));
+ if(copy_to_user(&((char *) arg)[0], &wavefront_info,
+ sizeof (wavefront_info)))
+ return -EFAULT;
return 0;
- break;
case SNDCTL_SEQ_RESETSAMPLES:
- printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
+// printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
return 0; /* don't force an error */
- break;
case SNDCTL_SEQ_PERCMODE:
return 0; /* don't force an error */
- break;
case SNDCTL_SYNTH_MEMAVL:
if ((dev.freemem = wavefront_freemem ()) < 0) {
break;
case SNDCTL_SYNTH_CONTROL:
- copy_from_user (&wc, arg, sizeof (wc));
-
- if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
- copy_to_user (arg, &wc, sizeof (wc));
+ if(copy_from_user (&wc, arg, sizeof (wc)))
+ err = -EFAULT;
+ else if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
+ if(copy_to_user (arg, &wc, sizeof (wc)))
+ err = -EFAULT;
}
return err;
switch (cmd) {
case SNDCTL_SYNTH_INFO:
- copy_to_user (&((char *) arg)[0],
+ if(copy_to_user (&((char *) arg)[0],
&wf_mpu_synth_info[index],
- sizeof (struct synth_info));
-
+ sizeof (struct synth_info)))
+ return -EFAULT;
return 0;
- break;
case SNDCTL_SYNTH_MEMAVL:
return 0x7fffffff;
- break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
if (lcp == NULL)
return -ENOMEM;
if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_FILTER_CADENCE)))
+ {
+ kfree(lcp);
return -EFAULT;
+ }
if (lcp->filter >= 4)
+ {
+ kfree(lcp);
return -1;
+ }
j->cadence_f[lcp->filter].state = 0;
j->cadence_f[lcp->filter].enable = lcp->enable;
j->filter_en[lcp->filter] = j->cadence_f[lcp->filter].en_filter = lcp->en_filter;
}
}
-static int capabilities_check(IXJ *j, struct phone_capability *pcreq)
+static int capabilities_check(IXJ *j, struct phone_capability *u_pcreq)
{
int cnt;
int retval = 0;
+ struct phone_capability pcreq;
+
+ if(copy_from_user(&pcreq, u_pcreq, sizeof(struct phone_capability)))
+ return -EFAULT;
+
for (cnt = 0; cnt < j->caps; cnt++) {
- if (pcreq->captype == j->caplist[cnt].captype
- && pcreq->cap == j->caplist[cnt].cap) {
+ if (pcreq.captype == j->caplist[cnt].captype
+ && pcreq.cap == j->caplist[cnt].cap) {
retval = 1;
break;
}
return -EFAULT;
break;
case PHONE_RING_CADENCE:
- j->ring_cadence = arg;
+ if(get_user(j->ring_cadence, (int *)arg))
+ return -EFAULT;
break;
case IXJCTL_CIDCW:
if(arg) {
dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_PLUSB) += plusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
+obj-$(CONFIG_USB_SE401) += se401.o
obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_CATC) += catc.o
obj-$(CONFIG_USB_RIO500) += rio500.o
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.4.18 2001/03/18 (C) 1999-2000"
-#define DRIVER_AUTHOR "Petko Manolov <petkan@dce.bg>"
+#define DRIVER_VERSION "v0.4.19 2001/06/07 (C) 1999-2001"
+#define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
#define DRIVER_DESC "ADMtek AN986 Pegasus USB Ethernet driver"
#define PEGASUS_USE_INTR
warn( __FUNCTION__ " status %d", urb->status);
}
pegasus->flags &= ~ETH_REGS_CHANGED;
- if ( pegasus->flags & CTRL_URB_SLEEP ) {
- pegasus->flags &= ~CTRL_URB_SLEEP;
+ if ( waitqueue_active(&pegasus->ctrl_wait) ) {
wake_up_interruptible( &pegasus->ctrl_wait );
}
}
}
memcpy(buffer,data,size);
- while ( pegasus->flags & ETH_REGS_CHANGED ) {
- pegasus->flags |= CTRL_URB_SLEEP;
+ while ( pegasus->flags & ETH_REGS_CHANGED )
interruptible_sleep_on( &pegasus->ctrl_wait );
- }
+
pegasus->dr.requesttype = PEGASUS_REQT_READ;
pegasus->dr.request = PEGASUS_REQ_GET_REGS;
pegasus->dr.value = cpu_to_le16 (0);
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_INTERRUPTIBLE );
- pegasus->flags |= CTRL_URB_SLEEP;
if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRLs %d", ret);
}
schedule();
- remove_wait_queue( &pegasus->ctrl_wait, &wait );
out:
+ remove_wait_queue( &pegasus->ctrl_wait, &wait );
memcpy(data,buffer,size);
kfree(buffer);
- return ret;
+
+ return ret;
}
}
memcpy(buffer, data, size);
- while ( pegasus->flags & ETH_REGS_CHANGED ) {
- pegasus->flags |= CTRL_URB_SLEEP ;
+ while ( pegasus->flags & ETH_REGS_CHANGED )
interruptible_sleep_on( &pegasus->ctrl_wait );
- }
+
pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
pegasus->dr.request = PEGASUS_REQ_SET_REGS;
pegasus->dr.value = cpu_to_le16 (0);
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_INTERRUPTIBLE );
- pegasus->flags |= CTRL_URB_SLEEP;
if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRL %d", ret);
- kfree(buffer);
- return ret;
+ goto out;
}
-
+
schedule();
+out:
remove_wait_queue( &pegasus->ctrl_wait, &wait );
-
kfree(buffer);
- return ret;
+
+ return ret;
}
}
memcpy(buffer, &data, 1);
- while ( pegasus->flags & ETH_REGS_CHANGED ) {
- pegasus->flags |= CTRL_URB_SLEEP;
+ while ( pegasus->flags & ETH_REGS_CHANGED )
interruptible_sleep_on( &pegasus->ctrl_wait );
- }
+
pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
pegasus->dr.request = PEGASUS_REQ_SET_REG;
pegasus->dr.value = cpu_to_le16p( &dat);
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_INTERRUPTIBLE );
- pegasus->flags |= CTRL_URB_SLEEP;
if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRL %d", ret);
- kfree(buffer);
- return ret;
+ goto out;
}
schedule();
+out:
remove_wait_queue( &pegasus->ctrl_wait, &wait );
-
kfree(buffer);
- return ret;
+
+ return ret;
}
return 1;
if ( usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
- usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK1 ) {
+ usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) {
__u16 auxmode;
read_mii_word( pegasus, 0, 0x1b, &auxmode );
} else {
pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
- info("%s: set Rx mode", net->name);
}
pegasus->flags |= ETH_REGS_CHANGE;
};
#define VENDOR_3COM 0x0506
-#define VENDOR_ACCTON 0x083a
-#define VENDOR_ADMTEK 0x07a6
-#define VENDOR_BILLIONTON 0x08dd
-#define VENDOR_COREGA 0x07aa
-#define VENDOR_DLINK1 0x2001
-#define VENDOR_DLINK2 0x07b8
-#define VENDOR_IODATA 0x04bb
-#define VENDOR_LANEED 0x056e
-#define VENDOR_LINKSYS 0x066b
-#define VENDOR_MELCO 0x0411
-#define VENDOR_SMARTBRIDGES 0x08d1
-#define VENDOR_SMC 0x0707
-#define VENDOR_SOHOWARE 0x15e8
+#define VENDOR_ABOCOM 0x07b8
+#define VENDOR_ACCTON 0x083a
+#define VENDOR_ADMTEK 0x07a6
+#define VENDOR_BILLIONTON 0x08dd
+#define VENDOR_COREGA 0x07aa
+#define VENDOR_DLINK 0x2001
+#define VENDOR_ELSA 0x05cc
+#define VENDOR_IODATA 0x04bb
+#define VENDOR_LANEED 0x056e
+#define VENDOR_LINKSYS 0x066b
+#define VENDOR_MELCO 0x0411
+#define VENDOR_SMARTBRIDGES 0x08d1
+#define VENDOR_SMC 0x0707
+#define VENDOR_SOHOWARE 0x15e8
#else /* PEGASUS_DEV */
PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
+ DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)",
+PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
VENDOR_ADMTEK, 0x0986,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4001,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
LINKSYS_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4002,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
LINKSYS_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK1, 0x4003,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
+ LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
+ LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
+ LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK1, 0xabc1,
+PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DU-E10", VENDOR_DLINK2, 0xabc1,
+PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DU-E100", VENDOR_DLINK2, 0x4002,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "FiberLine USB", VENDOR_DLINK2, 0x4102,
- DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
LINKSYS_GPIO_RESET )
PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
LINKSYS_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "Linksys USB Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB USB10TX", VENDOR_LINKSYS, 0x400b,
+ LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
+ LINKSYS_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
--- /dev/null
+/*
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
+ * their chipset available and supporting me while writing this driver.
+ * - Jeroen Vreeken
+ */
+
+static const char version[] = "0.22";
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/pagemap.h>
+#include <linux/usb.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
+#define virt_to_page(arg) MAP_NR(arg)
+#define vmalloc_32 vmalloc
+#endif
+
+#include "se401.h"
+
+static int flickerless=0;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
+static __devinitdata struct usb_device_id device_table [] = {
+ { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
+ { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
+ { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
+ { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
+ { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+#endif
+
+static int video_nr = -1;
+
+MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
+MODULE_DESCRIPTION("SE401 USB Camera Driver");
+MODULE_PARM(flickerless, "i");
+MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
+EXPORT_NO_SYMBOLS;
+
+
+static struct usb_driver se401_driver;
+
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the ov511 driver -claudio
+ *
+ * Same for the se401 driver -Jeroen
+ **********************************************************************/
+
+/* 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 = (unsigned long) page_address(pte_page(pte));
+ ret |= (adr & (PAGE_SIZE - 1));
+ }
+ }
+ }
+
+ 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);
+ 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_32(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(virt_to_page(__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(virt_to_page(__va(page)));
+ adr += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+ vfree(mem);
+}
+
+
+
+/****************************************************************************
+ *
+ * /proc interface
+ *
+ ***************************************************************************/
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry *se401_proc_entry = NULL;
+extern struct proc_dir_entry *video_proc_entry;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+static int se401_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ char *out = page;
+ int i, len;
+ struct usb_se401 *se401 = data;
+
+ /* Stay under PAGE_SIZE or else bla bla bla.... */
+
+ out+=sprintf(out, "driver_version : %s\n", version);
+ out+=sprintf(out, "model : %s\n", se401->camera_name);
+ out+=sprintf(out, "in use : %s\n", YES_NO (se401->user));
+ out+=sprintf(out, "streaming : %s\n", YES_NO (se401->streaming));
+ out+=sprintf(out, "button state : %s\n", YES_NO (se401->button));
+ out+=sprintf(out, "button pressed : %s\n", YES_NO (se401->buttonpressed));
+ out+=sprintf(out, "num_frames : %d\n", SE401_NUMFRAMES);
+
+ out+=sprintf(out, "Sizes :");
+ for (i=0; i<se401->sizes; i++) {
+ out+=sprintf(out, " %dx%d", se401->width[i],
+ se401->height[i]);
+ }
+ out+=sprintf(out, "\n");
+
+ out+=sprintf(out, "Frames total : %d\n", se401->readcount);
+ out+=sprintf(out, "Frames read : %d\n", se401->framecount);
+ out+=sprintf(out, "Packets dropped : %d\n", se401->dropped);
+ out+=sprintf(out, "Decoding Errors : %d\n", se401->error);
+
+ len = out - page;
+ len -= off;
+ if (len < count) {
+ *eof = 1;
+ if (len <= 0) return 0;
+ } else
+ len = count;
+
+ *start = page + off;
+
+ return len;
+}
+
+static int se401_write_proc(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ return -EINVAL;
+}
+
+static void create_proc_se401_cam (struct usb_se401 *se401)
+{
+ char name[7];
+ struct proc_dir_entry *ent;
+
+ if (!se401_proc_entry || !se401)
+ return;
+
+ sprintf (name, "video%d", se401->vdev.minor);
+
+ ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+ se401_proc_entry);
+
+ if (!ent)
+ return;
+
+ ent->data = se401;
+ ent->read_proc = se401_read_proc;
+ ent->write_proc = se401_write_proc;
+ se401->proc_entry = ent;
+}
+
+static void destroy_proc_se401_cam (struct usb_se401 *se401)
+{
+ /* One to much, just to be sure :) */
+ char name[9];
+
+ if (!se401 || !se401->proc_entry)
+ return;
+
+ sprintf(name, "video%d", se401->vdev.minor);
+ remove_proc_entry(name, se401_proc_entry);
+ se401->proc_entry = NULL;
+}
+
+static void proc_se401_create (void)
+{
+ if (video_proc_entry == NULL) {
+ err("/proc/video/ doesn't exist");
+ return;
+ }
+
+ se401_proc_entry=create_proc_entry("se401", S_IFDIR, video_proc_entry);
+
+ if (se401_proc_entry)
+ se401_proc_entry->owner = THIS_MODULE;
+ else
+ err("Unable to initialize /proc/video/se401");
+}
+
+static void proc_se401_destroy(void)
+{
+ if (se401_proc_entry == NULL)
+ return;
+
+ remove_proc_entry("se401", video_proc_entry);
+}
+#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
+
+
+/****************************************************************************
+ *
+ * se401 register read/write functions
+ *
+ ***************************************************************************/
+
+static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
+ unsigned short value, unsigned char *cp, int size)
+{
+ return usb_control_msg (
+ se401->dev,
+ set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
+ req,
+ (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ 0,
+ cp,
+ size,
+ HZ
+ );
+}
+
+static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
+ unsigned short param)
+{
+ /* specs say that the selector (address) should go in the value field
+ and the param in index, but in the logs of the windows driver they do
+ this the other way around...
+ */
+ return usb_control_msg (
+ se401->dev,
+ usb_sndctrlpipe(se401->dev, 0),
+ SE401_REQ_SET_EXT_FEATURE,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ param,
+ selector,
+ NULL,
+ 0,
+ HZ
+ );
+}
+
+static unsigned short se401_get_feature(struct usb_se401 *se401,
+ unsigned short selector)
+{
+ /* For 'set' the selecetor should be in index, not sure if the spec is
+ wrong here to....
+ */
+ unsigned char cp[2];
+ usb_control_msg (
+ se401->dev,
+ usb_rcvctrlpipe(se401->dev, 0),
+ SE401_REQ_GET_EXT_FEATURE,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0,
+ selector,
+ cp,
+ 2,
+ HZ
+ );
+ return cp[0]+cp[1]*256;
+}
+
+/****************************************************************************
+ *
+ * Camera control
+ *
+ ***************************************************************************/
+
+
+static int se401_send_pict(struct usb_se401 *se401)
+{
+ se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
+ se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
+ se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
+ se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
+ se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
+ se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
+ se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
+
+ return 0;
+}
+
+static void se401_set_exposure(struct usb_se401 *se401, int brightness)
+{
+ int integration=brightness<<5;
+
+ if (flickerless==50) {
+ integration=integration-integration%106667;
+ }
+ if (flickerless==60) {
+ integration=integration-integration%88889;
+ }
+ se401->brightness=integration>>5;
+ se401->expose_h=(integration>>16)&0xff;
+ se401->expose_m=(integration>>8)&0xff;
+ se401->expose_l=integration&0xff;
+}
+
+static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+ p->brightness=se401->brightness;
+ if (se401->enhance) {
+ p->whiteness=32768;
+ } else {
+ p->whiteness=0;
+ }
+ p->colour=65535;
+ p->contrast=65535;
+ p->hue=se401->rgain<<10;
+ p->palette=se401->palette;
+ p->depth=3; /* rgb24 */
+ return 0;
+}
+
+
+static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+ if (p->palette != VIDEO_PALETTE_RGB24)
+ return 1;
+ se401->palette=p->palette;
+ if (p->hue!=se401->hue) {
+ se401->rgain= p->hue>>10;
+ se401->bgain= 0x40-(p->hue>>10);
+ se401->hue=p->hue;
+ }
+ if (p->brightness!=se401->brightness) {
+ se401_set_exposure(se401, p->brightness);
+ }
+ if (p->whiteness>=32768) {
+ se401->enhance=1;
+ } else {
+ se401->enhance=0;
+ }
+ se401_send_pict(se401);
+ se401_send_pict(se401);
+ return 0;
+}
+
+/*
+ Hyundai have some really nice docs about this and other sensor related
+ stuff on their homepage: www.hei.co.kr
+*/
+static void se401_auto_resetlevel(struct usb_se401 *se401)
+{
+ unsigned int ahrc, alrc;
+ int oldreset=se401->resetlevel;
+
+ /* For some reason this normally read-only register doesn't get reset
+ to zero after reading them just once...
+ */
+ se401_get_feature(se401, HV7131_REG_HIREFNOH);
+ se401_get_feature(se401, HV7131_REG_HIREFNOL);
+ se401_get_feature(se401, HV7131_REG_LOREFNOH);
+ se401_get_feature(se401, HV7131_REG_LOREFNOL);
+ ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
+ se401_get_feature(se401, HV7131_REG_HIREFNOL);
+ alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
+ se401_get_feature(se401, HV7131_REG_LOREFNOL);
+
+ /* Not an exact science, but it seems to work pretty well... */
+ if (alrc > 10) {
+ while (alrc>=10 && se401->resetlevel < 63) {
+ se401->resetlevel++;
+ alrc /=2;
+ }
+ } else if (ahrc > 20) {
+ while (ahrc>=20 && se401->resetlevel > 0) {
+ se401->resetlevel--;
+ ahrc /=2;
+ }
+ }
+ if (se401->resetlevel!=oldreset)
+ se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
+
+ return;
+}
+
+/* irq handler for snapshot button */
+static void se401_button_irq(struct urb *urb)
+{
+ struct usb_se401 *se401=urb->context;
+
+ if (!urb) {
+ info("ohoh: null urb");
+ return;
+ }
+ if (!se401->dev) {
+ info("ohoh: device vapourished");
+ return;
+ }
+
+ if (urb->actual_length >=2 && !urb->status) {
+ if (se401->button)
+ se401->buttonpressed=1;
+ }
+}
+
+static void se401_video_irq(struct urb *urb)
+{
+ struct usb_se401 *se401=urb->context;
+ int length=urb->actual_length;
+
+ /* ohoh... */
+ if (!se401->streaming) {
+ return;
+ }
+ if (!urb) {
+ info ("ohoh: null urb");
+ return;
+ }
+ if (!se401->dev) {
+ info ("ohoh: device vapourished");
+ return;
+ }
+
+ /* 0 sized packets happen if we are to fast, but sometimes the camera
+ keeps sending them forever...
+ */
+ if (length && !urb->status) {
+ se401->nullpackets=0;
+ switch(se401->scratch[se401->scratch_next].state) {
+ case BUFFER_READY:
+ case BUFFER_BUSY: {
+ se401->dropped++;
+ break;
+ }
+ case BUFFER_UNUSED: {
+ memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
+ se401->scratch[se401->scratch_next].state=BUFFER_READY;
+ se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
+ se401->scratch[se401->scratch_next].length=length;
+ if (waitqueue_active(&se401->wq)) {
+ wake_up_interruptible(&se401->wq);
+ }
+ se401->scratch_overflow=0;
+ se401->scratch_next++;
+ if (se401->scratch_next>=SE401_NUMSCRATCH)
+ se401->scratch_next=0;;
+ break;
+ }
+ }
+ se401->bayeroffset+=length;
+ if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
+ se401->bayeroffset=0;
+ }
+ } else {
+ se401->nullpackets++;
+ if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+ if (waitqueue_active(&se401->wq)) {
+ wake_up_interruptible(&se401->wq);
+ }
+ }
+ }
+
+ /* Resubmit urb for new data */
+ urb->status=0;
+ urb->dev=se401->dev;
+ if(usb_submit_urb(urb))
+ info("urb burned down");
+ return;
+}
+
+static void se401_send_size(struct usb_se401 *se401, int width, int height)
+{
+ int i=0;
+ int mode=0x03; /* No compression */
+ int sendheight=height;
+ int sendwidth=width;
+
+ /* JangGu compression can only be used with the camera supported sizes,
+ but bayer seems to work with any size that fits on the sensor.
+ We check if we can use compression with the current size with either
+ 4 or 16 times subcapturing, if not we use uncompressed bayer data
+ but this will result in cutouts of the maximum size....
+ */
+ while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
+ i++;
+ while (i<se401->sizes) {
+ if (se401->width[i]==width*2 && se401->height[i]==height*2) {
+ sendheight=se401->height[i];
+ sendwidth=se401->width[i];
+ mode=0x40;
+ }
+ if (se401->width[i]==width*4 && se401->height[i]==height*4) {
+ sendheight=se401->height[i];
+ sendwidth=se401->width[i];
+ mode=0x42;
+ }
+ i++;
+ }
+
+ se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
+ se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
+ se401_set_feature(se401, SE401_OPERATINGMODE, mode);
+
+ if (mode==0x03) {
+ se401->format=FMT_BAYER;
+ } else {
+ se401->format=FMT_JANGGU;
+ }
+
+ return;
+}
+
+/*
+ In this function se401_send_pict is called several times,
+ for some reason (depending on the state of the sensor and the phase of
+ the moon :) doing this only in either place doesn't always work...
+*/
+static int se401_start_stream(struct usb_se401 *se401)
+{
+ urb_t *urb;
+ int err=0, i;
+ se401->streaming=1;
+
+ se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+ se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+ /* Set picture settings */
+ se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
+ se401_send_pict(se401);
+
+ se401_send_size(se401, se401->cwidth, se401->cheight);
+
+ se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+ /* Do some memory allocation */
+ for (i=0; i<SE401_NUMFRAMES; i++) {
+ se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
+ se401->frame[i].curpix=0;
+ }
+ for (i=0; i<SE401_NUMSBUF; i++) {
+ se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+ }
+
+ se401->bayeroffset=0;
+ se401->scratch_next=0;
+ se401->scratch_use=0;
+ se401->scratch_overflow=0;
+ for (i=0; i<SE401_NUMSCRATCH; i++) {
+ se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+ se401->scratch[i].state=BUFFER_UNUSED;
+ }
+
+ for (i=0; i<SE401_NUMSBUF; i++) {
+ urb=usb_alloc_urb(0);
+ if(!urb)
+ return ENOMEM;
+
+ FILL_BULK_URB(urb, se401->dev,
+ usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
+ se401->sbuf[i].data, SE401_PACKETSIZE,
+ se401_video_irq,
+ se401);
+ urb->transfer_flags |= USB_QUEUE_BULK;
+
+ se401->urb[i]=urb;
+
+ err=usb_submit_urb(se401->urb[i]);
+ if(err)
+ err("urb burned down");
+ }
+
+ se401->framecount=0;
+
+ return 0;
+}
+
+static int se401_stop_stream(struct usb_se401 *se401)
+{
+ int i;
+
+ if (!se401->streaming || !se401->dev)
+ return 1;
+
+ se401->streaming=0;
+
+ se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+ se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+ se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+
+ for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+ se401->urb[i]->next=NULL;
+ usb_unlink_urb(se401->urb[i]);
+ usb_free_urb(se401->urb[i]);
+ se401->urb[i]=NULL;
+ kfree(se401->sbuf[i].data);
+ }
+ for (i=0; i<SE401_NUMSCRATCH; i++) {
+ kfree(se401->scratch[i].data);
+ se401->scratch[i].data=NULL;
+ }
+
+ return 0;
+}
+
+static int se401_set_size(struct usb_se401 *se401, int width, int height)
+{
+ int wasstreaming=se401->streaming;
+ /* Check to see if we need to change */
+ if (se401->cwidth==width && se401->cheight==height)
+ return 0;
+
+ /* Check for a valid mode */
+ if (!width || !height)
+ return 1;
+ if ((width & 1) || (height & 1))
+ return 1;
+ if (width>se401->width[se401->sizes-1])
+ return 1;
+ if (height>se401->height[se401->sizes-1])
+ return 1;
+
+ /* Stop a current stream and start it again at the new size */
+ if (wasstreaming)
+ se401_stop_stream(se401);
+ se401->cwidth=width;
+ se401->cheight=height;
+ if (wasstreaming)
+ se401_start_stream(se401);
+ return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video Decoding
+ *
+ ***************************************************************************/
+
+/*
+ This shouldn't really be done in a v4l driver....
+ But it does make the image look a lot more usable.
+ Basicly it lifts the dark pixels more than the light pixels.
+*/
+static inline void enhance_picture(unsigned char *frame, int len)
+{
+ while (len--) {
+ *frame++=(((*frame^255)*(*frame^255))/255)^255;
+ }
+}
+
+static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
+{
+ struct se401_frame *frame=&se401->frame[se401->curframe];
+ int linelength=se401->cwidth*3;
+
+ if (frame->curlinepix >= linelength) {
+ frame->curlinepix=0;
+ frame->curline+=linelength;
+ }
+
+ /* First three are absolute, all others relative.
+ * Format is rgb from right to left (mirrorred image),
+ * we flip it to get bgr from left to right. */
+ if (frame->curlinepix < 3) {
+ *(frame->curline-frame->curlinepix)=1+data*4;
+ } else {
+ *(frame->curline-frame->curlinepix)=
+ *(frame->curline-frame->curlinepix+3)+data*4;
+ }
+ frame->curlinepix++;
+}
+
+static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
+{
+ int pos=0;
+ int vlc_cod=0;
+ int vlc_size=0;
+ int vlc_data=0;
+ int bit_cur;
+ int bit;
+ data+=4;
+ while (pos < packetlength) {
+ bit_cur=8;
+ while (bit_cur && bit_exp) {
+ bit=((*data)>>(bit_cur-1))&1;
+ if (!vlc_cod) {
+ if (bit) {
+ vlc_size++;
+ } else {
+ if (!vlc_size) {
+ decode_JangGu_integrate(se401, 0);
+ } else {
+ vlc_cod=2;
+ vlc_data=0;
+ }
+ }
+ } else {
+ if (vlc_cod==2) {
+ if (!bit) vlc_data=-(1<<vlc_size)+1;
+ vlc_cod--;
+ }
+ vlc_size--;
+ vlc_data+=bit<<vlc_size;
+ if (!vlc_size) {
+ decode_JangGu_integrate(se401, vlc_data);
+ vlc_cod=0;
+ }
+ }
+ bit_cur--;
+ bit_exp--;
+ }
+ pos++;
+ data++;
+ }
+}
+
+static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+ unsigned char *data=buffer->data;
+ int len=buffer->length;
+ int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
+ int datapos=0;
+
+ /* New image? */
+ if (!se401->frame[se401->curframe].curpix) {
+ se401->frame[se401->curframe].curlinepix=0;
+ se401->frame[se401->curframe].curline=
+ se401->frame[se401->curframe].data+
+ se401->cwidth*3-1;
+ if (se401->frame[se401->curframe].grabstate==FRAME_READY)
+ se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
+ se401->vlcdatapos=0;
+ }
+ while (datapos < len) {
+ size=1024-se401->vlcdatapos;
+ if (size+datapos > len)
+ size=len-datapos;
+ memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
+ se401->vlcdatapos+=size;
+ packetlength=0;
+ if (se401->vlcdatapos >= 4) {
+ bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
+ pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
+ frameinfo=se401->vlcdata[0]&0xc0;
+ packetlength=((bit_exp+47)>>4)<<1;
+ if (packetlength > 1024) {
+ se401->vlcdatapos=0;
+ datapos=len;
+ packetlength=0;
+ se401->error++;
+ se401->frame[se401->curframe].curpix=0;
+ }
+ }
+ if (packetlength && se401->vlcdatapos >= packetlength) {
+ decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
+ se401->frame[se401->curframe].curpix+=pix_exp*3;
+ datapos+=size-(se401->vlcdatapos-packetlength);
+ se401->vlcdatapos=0;
+ if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
+ if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
+ if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
+ se401->frame[se401->curframe].grabstate=FRAME_DONE;
+ se401->framecount++;
+ se401->readcount++;
+ }
+ if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+ se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+ }
+ } else {
+ se401->error++;
+ }
+ se401->frame[se401->curframe].curpix=0;
+ datapos=len;
+ }
+ } else {
+ datapos+=size;
+ }
+ }
+}
+
+static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+ unsigned char *data=buffer->data;
+ int len=buffer->length;
+ int offset=buffer->offset;
+ int datasize=se401->cwidth*se401->cheight;
+ struct se401_frame *frame=&se401->frame[se401->curframe];
+
+ unsigned char *framedata=frame->data, *curline, *nextline;
+ int width=se401->cwidth;
+ int blineoffset=0, bline;
+ int linelength=width*3, i;
+
+
+ if (frame->curpix==0) {
+ if (frame->grabstate==FRAME_READY) {
+ frame->grabstate=FRAME_GRABBING;
+ }
+ frame->curline=framedata+linelength;
+ frame->curlinepix=0;
+ }
+
+ if (offset!=frame->curpix) {
+ /* Regard frame as lost :( */
+ frame->curpix=0;
+ se401->error++;
+ return;
+ }
+
+ /* Check if we have to much data */
+ if (frame->curpix+len > datasize) {
+ len=datasize-frame->curpix;
+ }
+ if (se401->cheight%4)
+ blineoffset=1;
+ bline=frame->curpix/se401->cwidth+blineoffset;
+
+ curline=frame->curline;
+ nextline=curline+linelength;
+ if (nextline >= framedata+datasize*3)
+ nextline=curline;
+ while (len) {
+ if (frame->curlinepix>=width) {
+ frame->curlinepix-=width;
+ bline=frame->curpix/width+blineoffset;
+ curline+=linelength*2;
+ nextline+=linelength*2;
+ if (curline >= framedata+datasize*3) {
+ frame->curlinepix++;
+ curline-=3;
+ nextline-=3;
+ len--;
+ data++;
+ frame->curpix++;
+ }
+ if (nextline >= framedata+datasize*3)
+ nextline=curline;
+ }
+ if ((bline&1)) {
+ if ((frame->curlinepix&1)) {
+ *(curline+2)=*data;
+ *(curline-1)=*data;
+ *(nextline+2)=*data;
+ *(nextline-1)=*data;
+ } else {
+ *(curline+1)=
+ (*(curline+1)+*data)/2;
+ *(curline-2)=
+ (*(curline-2)+*data)/2;
+ *(nextline+1)=*data;
+ *(nextline-2)=*data;
+ }
+ } else {
+ if ((frame->curlinepix&1)) {
+ *(curline+1)=
+ (*(curline+1)+*data)/2;
+ *(curline-2)=
+ (*(curline-2)+*data)/2;
+ *(nextline+1)=*data;
+ *(nextline-2)=*data;
+ } else {
+ *curline=*data;
+ *(curline-3)=*data;
+ *nextline=*data;
+ *(nextline-3)=*data;
+ }
+ }
+ frame->curlinepix++;
+ curline-=3;
+ nextline-=3;
+ len--;
+ data++;
+ frame->curpix++;
+ }
+ frame->curline=curline;
+
+ if (frame->curpix>=datasize) {
+ /* Fix the top line */
+ framedata+=linelength;
+ for (i=0; i<linelength; i++) {
+ *--framedata=*(framedata+linelength);
+ }
+ /* Fix the left side (green is already present) */
+ for (i=0; i<se401->cheight; i++) {
+ *framedata=*(framedata+3);
+ *(framedata+1)=*(framedata+4);
+ *(framedata+2)=*(framedata+5);
+ framedata+=linelength;
+ }
+ frame->curpix=0;
+ frame->grabstate=FRAME_DONE;
+ se401->framecount++;
+ se401->readcount++;
+ if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+ se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+ }
+ }
+}
+
+static int se401_newframe(struct usb_se401 *se401, int framenr)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int errors=0;
+
+ while (se401->streaming &&
+ (se401->frame[framenr].grabstate==FRAME_READY ||
+ se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
+ if(!se401->frame[framenr].curpix) {
+ errors++;
+ }
+ wait_interruptible(
+ se401->scratch[se401->scratch_use].state!=BUFFER_READY,
+ &se401->wq,
+ &wait
+ );
+ if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+ se401->nullpackets=0;
+ info("to many null length packets, restarting capture");
+ se401_stop_stream(se401);
+ se401_start_stream(se401);
+ } else {
+ if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
+ se401->frame[framenr].grabstate=FRAME_ERROR;
+ return -EIO;
+ }
+ se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
+ if (se401->format==FMT_JANGGU) {
+ decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
+ } else {
+ decode_bayer(se401, &se401->scratch[se401->scratch_use]);
+ }
+ se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
+ se401->scratch_use++;
+ if (se401->scratch_use>=SE401_NUMSCRATCH)
+ se401->scratch_use=0;
+ if (errors > SE401_MAX_ERRORS) {
+ errors=0;
+ info("to much errors, restarting capture");
+ se401_stop_stream(se401);
+ se401_start_stream(se401);
+ }
+ }
+ }
+
+ if (se401->frame[framenr].grabstate==FRAME_DONE)
+ if (se401->enhance)
+ enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
+ return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video4Linux
+ *
+ ***************************************************************************/
+
+
+static int se401_open(struct video_device *dev, int flags)
+{
+ struct usb_se401 *se401 = (struct usb_se401 *)dev;
+ int err = 0;
+
+ MOD_INC_USE_COUNT;
+ down(&se401->lock);
+
+ se401->fbuf=rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
+ if(!se401->fbuf) err=-ENOMEM;
+
+ if (err) {
+ MOD_DEC_USE_COUNT;
+ up(&se401->lock);
+ return err;
+ }
+
+ se401->user=1;
+
+ up(&se401->lock);
+
+ return 0;
+}
+
+static void se401_close(struct video_device *dev)
+{
+ struct usb_se401 *se401 = (struct usb_se401 *)dev;
+ int i;
+
+ down(&se401->lock);
+
+ for (i=0; i<SE401_NUMFRAMES; i++)
+ se401->frame[i].grabstate=FRAME_UNUSED;
+ if (se401->streaming)
+ se401_stop_stream(se401);
+
+ rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
+ se401->user=0;
+ up(&se401->lock);
+
+ if (!se401->dev) {
+ video_unregister_device(&se401->vdev);
+ kfree(se401->width);
+ kfree(se401->height);
+ kfree(se401);
+ se401 = NULL;
+ info("device unregistered");
+ }
+
+ MOD_DEC_USE_COUNT;
+}
+
+static int se401_init_done(struct video_device *dev)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ create_proc_se401_cam((struct usb_se401 *)dev);
+#endif
+
+ return 0;
+}
+
+static long se401_write(struct video_device *dev, const char *buf, unsigned long
+ count, int noblock)
+{
+ return -EINVAL;
+}
+
+static int se401_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+ struct usb_se401 *se401 = (struct usb_se401 *)vdev;
+
+ if (!se401->dev)
+ return -EIO;
+
+ switch (cmd) {
+ case VIDIOCGCAP:
+ {
+ struct video_capability b;
+ strcpy(b.name, se401->camera_name);
+ b.type = VID_TYPE_CAPTURE;
+ b.channels = 1;
+ b.audios = 0;
+ b.maxwidth = se401->width[se401->sizes-1];
+ b.maxheight = se401->height[se401->sizes-1];
+ b.minwidth = se401->width[0];
+ b.minheight = se401->height[0];
+
+ 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;
+
+ se401_get_pict(se401, &p);
+
+ 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;
+
+ if (se401_set_pict(se401, &p))
+ return -EINVAL;
+ 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 (se401_set_size(se401, vw.width, vw.height))
+ return -EINVAL;
+
+ return 0;
+ }
+ case VIDIOCGWIN:
+ {
+ struct video_window vw;
+
+ vw.x = 0; /* FIXME */
+ vw.y = 0;
+ vw.chromakey = 0;
+ vw.flags = 0;
+ vw.clipcount = 0;
+ vw.width = se401->cwidth;
+ vw.height = se401->cheight;
+
+ if (copy_to_user(arg, &vw, sizeof(vw)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf vm;
+ int i;
+
+ memset(&vm, 0, sizeof(vm));
+ vm.size = SE401_NUMFRAMES * se401->maxframesize;
+ vm.frames = SE401_NUMFRAMES;
+ for (i=0; i<SE401_NUMFRAMES; i++)
+ vm.offsets[i] = se401->maxframesize * i;
+
+ if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case VIDIOCMCAPTURE:
+ {
+ struct video_mmap vm;
+
+ if (copy_from_user(&vm, arg, sizeof(vm)))
+ return -EFAULT;
+ if (vm.format != VIDEO_PALETTE_RGB24)
+ return -EINVAL;
+ if (vm.frame >= SE401_NUMFRAMES)
+ return -EINVAL;
+ if (se401->frame[vm.frame].grabstate != FRAME_UNUSED)
+ return -EBUSY;
+
+ /* Is this according to the v4l spec??? */
+ if (se401_set_size(se401, vm.width, vm.height))
+ return -EINVAL;
+ se401->frame[vm.frame].grabstate=FRAME_READY;
+
+ if (!se401->streaming)
+ se401_start_stream(se401);
+
+ /* Set the picture properties */
+ if (se401->framecount==0)
+ se401_send_pict(se401);
+ /* Calibrate the reset level after a few frames. */
+ if (se401->framecount%20==1)
+ se401_auto_resetlevel(se401);
+
+ return 0;
+ }
+ case VIDIOCSYNC:
+ {
+ int frame, ret=0;
+
+ if (copy_from_user((void *)&frame, arg, sizeof(int)))
+ return -EFAULT;
+
+ ret=se401_newframe(se401, frame);
+ se401->frame[frame].grabstate=FRAME_UNUSED;
+ return ret;
+ }
+ 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;
+ } /* end switch */
+
+ return 0;
+}
+
+static long se401_read(struct video_device *dev, char *buf, unsigned long count,
+ int noblock)
+{
+ int realcount=count, ret=0;
+ struct usb_se401 *se401 = (struct usb_se401 *)dev;
+
+
+ if (se401->dev == NULL)
+ return -EIO;
+ if (realcount > se401->cwidth*se401->cheight*3)
+ realcount=se401->cwidth*se401->cheight*3;
+
+ /* Shouldn't happen: */
+ if (se401->frame[0].grabstate==FRAME_GRABBING)
+ return -EBUSY;
+ se401->frame[0].grabstate=FRAME_READY;
+ se401->frame[1].grabstate=FRAME_UNUSED;
+ se401->curframe=0;
+
+ if (!se401->streaming)
+ se401_start_stream(se401);
+
+ /* Set the picture properties */
+ if (se401->framecount==0)
+ se401_send_pict(se401);
+ /* Calibrate the reset level after a few frames. */
+ if (se401->framecount%20==1)
+ se401_auto_resetlevel(se401);
+
+ ret=se401_newframe(se401, 0);
+
+ if (!ret) {
+ copy_to_user(buf, se401->frame[0].data, realcount);
+ } else {
+ realcount=ret;
+ }
+ se401->frame[0].grabstate=FRAME_UNUSED;
+
+ return realcount;
+}
+
+static int se401_mmap(struct video_device *dev, const char *adr,
+ unsigned long size)
+{
+ struct usb_se401 *se401 = (struct usb_se401 *)dev;
+ unsigned long start = (unsigned long)adr;
+ unsigned long page, pos;
+
+ down(&se401->lock);
+
+ if (se401->dev == NULL) {
+ up(&se401->lock);
+ return -EIO;
+ }
+ if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+ up(&se401->lock);
+ return -EINVAL;
+ }
+ pos = (unsigned long)se401->fbuf;
+ while (size > 0) {
+ page = kvirt_to_pa(pos);
+ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+ up(&se401->lock);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+ up(&se401->lock);
+
+ return 0;
+}
+
+static struct video_device se401_template = {
+ name: "se401 USB camera",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_SE401,
+ open: se401_open,
+ close: se401_close,
+ read: se401_read,
+ write: se401_write,
+ ioctl: se401_ioctl,
+ mmap: se401_mmap,
+ initialize: se401_init_done,
+};
+
+
+
+/***************************/
+static int se401_init(struct usb_se401 *se401)
+{
+ int i=0, rc;
+ unsigned char cp[0x40];
+ char temp[200];
+
+ /* led on */
+ se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+ /* get camera descriptor */
+ rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
+ if (cp[1]!=0x41) {
+ err("Wrong descriptor type");
+ return 1;
+ }
+ sprintf (temp, "ExtraFeatures: %d", cp[3]);
+
+ se401->sizes=cp[4]+cp[5]*256;
+ se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+ se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+ for (i=0; i<se401->sizes; i++) {
+ se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
+ se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
+ }
+ sprintf (temp, "%s Sizes:", temp);
+ for (i=0; i<se401->sizes; i++) {
+ sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
+ }
+ info("%s", temp);
+ se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
+
+ rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
+ se401->cwidth=cp[0]+cp[1]*256;
+ rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
+ se401->cheight=cp[0]+cp[1]*256;
+
+ if (!cp[2] && SE401_FORMAT_BAYER) {
+ err("Bayer format not supported!");
+ return 1;
+ }
+ /* set output mode (BAYER) */
+ se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
+
+ rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
+ se401->brightness=cp[0]+cp[1]*256;
+ /* some default values */
+ se401->resetlevel=0x2d;
+ se401->rgain=0x20;
+ se401->ggain=0x20;
+ se401->bgain=0x20;
+ se401_set_exposure(se401, 20000);
+ se401->palette=VIDEO_PALETTE_RGB24;
+ se401->enhance=1;
+ se401->dropped=0;
+ se401->error=0;
+ se401->framecount=0;
+ se401->readcount=0;
+
+ /* Start interrupt transfers for snapshot button */
+ se401->inturb=usb_alloc_urb(0);
+ if (!se401->inturb) {
+ info("Allocation of inturb failed");
+ return 1;
+ }
+ FILL_INT_URB(se401->inturb, se401->dev,
+ usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
+ &se401->button, sizeof(se401->button),
+ se401_button_irq,
+ se401,
+ HZ/10
+ );
+ if (usb_submit_urb(se401->inturb)) {
+ info("int urb burned down");
+ return 1;
+ }
+
+ /* Flash the led */
+ se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+ se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+ se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+ se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
+static void* se401_probe(struct usb_device *dev, unsigned int ifnum)
+#else
+static void* __devinit se401_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
+#endif
+{
+ struct usb_interface_descriptor *interface;
+ struct usb_se401 *se401;
+ char *camera_name=NULL;
+
+ /* We don't handle multi-config cameras */
+ if (dev->descriptor.bNumConfigurations != 1)
+ return NULL;
+
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
+
+ /* Is it an se401? */
+ if (dev->descriptor.idVendor == 0x03e8 &&
+ dev->descriptor.idProduct == 0x0004) {
+ camera_name="Endpoints/Aox SE401";
+ } else if (dev->descriptor.idVendor == 0x0471 &&
+ dev->descriptor.idProduct == 0x030b) {
+ camera_name="Philips PCVC665K";
+ } else if (dev->descriptor.idVendor == 0x047d &&
+ dev->descriptor.idProduct == 0x5001) {
+ camera_name="Kensington VideoCAM 67014";
+ } else if (dev->descriptor.idVendor == 0x047d &&
+ dev->descriptor.idProduct == 0x5002) {
+ camera_name="Kensington VideoCAM 6701(5/7)";
+ } else if (dev->descriptor.idVendor == 0x047d &&
+ dev->descriptor.idProduct == 0x5003) {
+ camera_name="Kensington VideoCAM 67016";
+ } else
+ return NULL;
+
+ /* Checking vendor/product should be enough, but what the hell */
+ if (interface->bInterfaceClass != 0x00)
+ return NULL;
+ if (interface->bInterfaceSubClass != 0x00)
+ return NULL;
+
+ /* We found one */
+ info("SE401 camera found: %s", camera_name);
+
+ if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+ err("couldn't kmalloc se401 struct");
+ return NULL;
+ }
+
+ memset(se401, 0, sizeof(*se401));
+
+ se401->dev = dev;
+ se401->iface = interface->bInterfaceNumber;
+ se401->camera_name = camera_name;
+
+ info("firmware version: %02x", dev->descriptor.bcdDevice & 255);
+
+ if (se401_init(se401))
+ return NULL;
+ memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
+ memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
+ if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ err("video_register_device failed");
+ return NULL;
+ }
+ info("registered new video device: video%d", se401->vdev.minor);
+
+ init_waitqueue_head(&se401->wq);
+ init_MUTEX(&se401->lock);
+
+ return se401;
+}
+
+static void se401_disconnect(struct usb_device *dev, void *ptr)
+{
+ int i;
+ struct usb_se401 *se401 = (struct usb_se401 *) ptr;
+
+ /* We don't want people trying to open up the device */
+ if (!se401->user)
+ video_unregister_device(&se401->vdev);
+
+ usb_driver_release_interface(&se401_driver,
+ &se401->dev->actconfig->interface[se401->iface]);
+
+ se401->dev = NULL;
+ se401->frame[0].grabstate = FRAME_ERROR;
+ se401->frame[1].grabstate = FRAME_ERROR;
+
+ se401->streaming = 0;
+
+ if (waitqueue_active(&se401->wq))
+ wake_up_interruptible(&se401->wq);
+
+ for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+ se401->urb[i]->next = NULL;
+ usb_unlink_urb(se401->urb[i]);
+ usb_free_urb(se401->urb[i]);
+ se401->urb[i] = NULL;
+ kfree(se401->sbuf[i].data);
+ }
+ for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) {
+ kfree(se401->scratch[i].data);
+ }
+ if (se401->inturb) {
+ usb_unlink_urb(se401->inturb);
+ usb_free_urb(se401->inturb);
+ }
+ info("%s disconnected", se401->camera_name);
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ destroy_proc_se401_cam(se401);
+#endif
+
+ /* Free the memory */
+ if (!se401->user) {
+ kfree(se401->width);
+ kfree(se401->height);
+ kfree(se401);
+ se401 = NULL;
+ }
+}
+
+
+static struct usb_driver se401_driver = {
+ name: "se401",
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
+ id_table: device_table,
+#endif
+ probe: se401_probe,
+ disconnect: se401_disconnect
+};
+
+
+
+/****************************************************************************
+ *
+ * Module routines
+ *
+ ***************************************************************************/
+
+static int __init usb_se401_init(void)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ proc_se401_create();
+#endif
+
+ info("SE401 usb camera driver version %s registering", version);
+ if (flickerless)
+ if (flickerless!=50 && flickerless!=60) {
+ info("Invallid flickerless value, use 0, 50 or 60.");
+ return -1;
+ }
+ if (usb_register(&se401_driver) < 0)
+ return -1;
+ return 0;
+}
+
+static void __exit usb_se401_exit(void)
+{
+ usb_deregister(&se401_driver);
+ info("SE401 driver deregistered");
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ proc_se401_destroy();
+#endif
+}
+
+module_init(usb_se401_init);
+module_exit(usb_se401_exit);
--- /dev/null
+
+#ifndef __LINUX_se401_H
+#define __LINUX_se401_H
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
+#define se401_DEBUG /* Turn on debug messages */
+
+#ifdef se401_DEBUG
+# define PDEBUG(level, fmt, args...) \
+if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+#else
+# define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* An almost drop-in replacement for sleep_on_interruptible */
+#define wait_interruptible(test, queue, wait) \
+{ \
+ add_wait_queue(queue, wait); \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ if (test) \
+ schedule(); \
+ remove_wait_queue(queue, wait); \
+ set_current_state(TASK_RUNNING); \
+ if (signal_pending(current)) \
+ break; \
+}
+
+#define SE401_REQ_GET_CAMERA_DESCRIPTOR 0x06
+#define SE401_REQ_START_CONTINUOUS_CAPTURE 0x41
+#define SE401_REQ_STOP_CONTINUOUS_CAPTURE 0x42
+#define SE401_REQ_CAPTURE_FRAME 0x43
+#define SE401_REQ_GET_BRT 0x44
+#define SE401_REQ_SET_BRT 0x45
+#define SE401_REQ_GET_WIDTH 0x4c
+#define SE401_REQ_SET_WIDTH 0x4d
+#define SE401_REQ_GET_HEIGHT 0x4e
+#define SE401_REQ_SET_HEIGHT 0x4f
+#define SE401_REQ_GET_OUTPUT_MODE 0x50
+#define SE401_REQ_SET_OUTPUT_MODE 0x51
+#define SE401_REQ_GET_EXT_FEATURE 0x52
+#define SE401_REQ_SET_EXT_FEATURE 0x53
+#define SE401_REQ_CAMERA_POWER 0x56
+#define SE401_REQ_LED_CONTROL 0x57
+#define SE401_REQ_BIOS 0xff
+
+#define SE401_BIOS_READ 0x07
+
+#define SE401_FORMAT_BAYER 0x40
+
+/* Hyundai hv7131b registers
+ 7121 and 7141 should be the same (haven't really checked...) */
+/* Mode registers: */
+#define HV7131_REG_MODE_A 0x00
+#define HV7131_REG_MODE_B 0x01
+#define HV7131_REG_MODE_C 0x02
+/* Frame registers: */
+#define HV7131_REG_FRSU 0x10
+#define HV7131_REG_FRSL 0x11
+#define HV7131_REG_FCSU 0x12
+#define HV7131_REG_FCSL 0x13
+#define HV7131_REG_FWHU 0x14
+#define HV7131_REG_FWHL 0x15
+#define HV7131_REG_FWWU 0x16
+#define HV7131_REG_FWWL 0x17
+/* Timing registers: */
+#define HV7131_REG_THBU 0x20
+#define HV7131_REG_THBL 0x21
+#define HV7131_REG_TVBU 0x22
+#define HV7131_REG_TVBL 0x23
+#define HV7131_REG_TITU 0x25
+#define HV7131_REG_TITM 0x26
+#define HV7131_REG_TITL 0x27
+#define HV7131_REG_TMCD 0x28
+/* Adjust Registers: */
+#define HV7131_REG_ARLV 0x30
+#define HV7131_REG_ARCG 0x31
+#define HV7131_REG_AGCG 0x32
+#define HV7131_REG_ABCG 0x33
+#define HV7131_REG_APBV 0x34
+#define HV7131_REG_ASLP 0x54
+/* Offset Registers: */
+#define HV7131_REG_OFSR 0x50
+#define HV7131_REG_OFSG 0x51
+#define HV7131_REG_OFSB 0x52
+/* REset level statistics registers: */
+#define HV7131_REG_LOREFNOH 0x57
+#define HV7131_REG_LOREFNOL 0x58
+#define HV7131_REG_HIREFNOH 0x59
+#define HV7131_REG_HIREFNOL 0x5a
+
+/* se401 registers */
+#define SE401_OPERATINGMODE 0x2000
+
+
+/* size of usb transfers */
+#define SE401_PACKETSIZE 4096
+/* number of queued bulk transfers to use, should be about 8 */
+#define SE401_NUMSBUF 1
+/* read the usb specs for this one :) */
+#define SE401_VIDEO_ENDPOINT 1
+#define SE401_BUTTON_ENDPOINT 2
+/* number of frames supported by the v4l part */
+#define SE401_NUMFRAMES 2
+/* scratch buffers for passing data to the decoders */
+#define SE401_NUMSCRATCH 32
+/* maximum amount of data in a JangGu packet */
+#define SE401_VLCDATALEN 1024
+/* number of nul sized packets to receive before kicking the camera */
+#define SE401_MAX_NULLPACKETS 4000
+/* number of decoding errors before kicking the camera */
+#define SE401_MAX_ERRORS 200
+
+struct usb_device;
+
+struct se401_sbuf {
+ unsigned char *data;
+};
+
+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 */
+};
+
+enum {
+ FMT_BAYER,
+ FMT_JANGGU,
+};
+
+enum {
+ BUFFER_UNUSED,
+ BUFFER_READY,
+ BUFFER_BUSY,
+ BUFFER_DONE,
+};
+
+struct se401_scratch {
+ unsigned char *data;
+ volatile int state;
+ int offset;
+ int length;
+};
+
+struct se401_frame {
+ unsigned char *data; /* Frame buffer */
+
+ volatile int grabstate; /* State of grabbing */
+
+ unsigned char *curline;
+ int curlinepix;
+ int curpix;
+};
+
+struct usb_se401 {
+ struct video_device vdev;
+
+ /* Device structure */
+ struct usb_device *dev;
+
+ unsigned char iface;
+
+ char *camera_name;
+
+ int change;
+ int brightness;
+ int hue;
+ int rgain;
+ int ggain;
+ int bgain;
+ int expose_h;
+ int expose_m;
+ int expose_l;
+ int resetlevel;
+
+ int enhance;
+
+ int format;
+ int sizes;
+ int *width;
+ int *height;
+ int cwidth; /* current width */
+ int cheight; /* current height */
+ int palette;
+ int maxframesize;
+ int cframesize; /* current framesize */
+
+ struct semaphore lock;
+ int user; /* user count for exclusive use */
+
+ int streaming; /* Are we streaming video? */
+
+ char *fbuf; /* Videodev buffer area */
+
+ urb_t *urb[SE401_NUMSBUF];
+ urb_t *inturb;
+
+ int button;
+ int buttonpressed;
+
+ int curframe; /* Current receiving frame */
+ struct se401_frame frame[SE401_NUMFRAMES];
+ int readcount;
+ int framecount;
+ int error;
+ int dropped;
+
+ int scratch_next;
+ int scratch_use;
+ int scratch_overflow;
+ struct se401_scratch scratch[SE401_NUMSCRATCH];
+
+ /* Decoder specific data: */
+ unsigned char vlcdata[SE401_VLCDATALEN];
+ int vlcdatapos;
+ int bayeroffset;
+
+ struct se401_sbuf sbuf[SE401_NUMSBUF];
+
+ wait_queue_head_t wq; /* Processes waiting */
+
+ /* proc interface */
+ struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */
+
+ int nullpackets;
+};
+
+
+#endif
+
bool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
fi
dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
fi
obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o
+obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
+obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
# Objects that export symbols.
export-objs := usbserial.o
--- /dev/null
+/*
+ * REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver
+ *
+ * Copyright (C) 2001 REINER SCT
+ * Author: Matthias Bruestle
+ *
+ * Contact: linux-usb@sii.li (see MAINTAINERS)
+ *
+ * This program is largely derived from work by the linux-usb group
+ * and associated source files. Please see the usb/serial files for
+ * individual credits and copyrights.
+ *
+ * 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.
+ *
+ * Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
+ * patience.
+ *
+ * In case of problems, please write to the contact e-mail address
+ * mentioned above.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ static int debug = 1;
+#else
+ static int debug;
+#endif
+
+#include "usb-serial.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Matthias Bruestle"
+#define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver"
+
+
+#define CYBERJACK_VENDOR_ID 0x0C4B
+#define CYBERJACK_PRODUCT_ID 0x0100
+
+/* Function prototypes */
+static int cyberjack_startup (struct usb_serial *serial);
+static void cyberjack_shutdown (struct usb_serial *serial);
+static int cyberjack_open (struct usb_serial_port *port, struct file *filp);
+static void cyberjack_close (struct usb_serial_port *port, struct file *filp);
+static int cyberjack_write (struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count);
+static void cyberjack_read_int_callback( struct urb *urb );
+static void cyberjack_read_bulk_callback (struct urb *urb);
+static void cyberjack_write_bulk_callback (struct urb *urb);
+
+static __devinitdata struct usb_device_id id_table [] = {
+ { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct usb_serial_device_type cyberjack_device = {
+ name: "Reiner SCT Cyberjack USB card reader",
+ id_table: id_table,
+ needs_interrupt_in: MUST_HAVE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ startup: cyberjack_startup,
+ shutdown: cyberjack_shutdown,
+ open: cyberjack_open,
+ close: cyberjack_close,
+ write: cyberjack_write,
+ read_int_callback: cyberjack_read_int_callback,
+ read_bulk_callback: cyberjack_read_bulk_callback,
+ write_bulk_callback: cyberjack_write_bulk_callback,
+};
+
+struct cyberjack_private {
+ short rdtodo; /* Bytes still to read */
+ unsigned char wrbuf[5*64]; /* Buffer for collecting data to write */
+ short wrfilled; /* Overall data size we already got */
+ short wrsent; /* Data akready sent */
+};
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int cyberjack_startup (struct usb_serial *serial)
+{
+ struct cyberjack_private *priv;
+
+ dbg (__FUNCTION__);
+
+ /* allocate the private data structure */
+ serial->port->private = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
+ if (!serial->port->private)
+ return (-1); /* error */
+
+ /* set initial values */
+ priv = (struct cyberjack_private *)serial->port->private;
+ priv->rdtodo = 0;
+ priv->wrfilled = 0;
+ priv->wrsent = 0;
+
+ init_waitqueue_head(&serial->port->write_wait);
+
+ return( 0 );
+}
+
+static void cyberjack_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ cyberjack_close (&serial->port[i], NULL);
+ }
+ /* My special items, the standard routines free my urbs */
+ if (serial->port[i].private)
+ kfree(serial->port[i].private);
+ }
+}
+
+static int cyberjack_open (struct usb_serial_port *port, struct file *filp)
+{
+ struct cyberjack_private *priv;
+ int result = 0;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return -ENODEV;
+
+ MOD_INC_USE_COUNT;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ down (&port->sem);
+
+ ++port->open_count;
+
+ if (!port->active) {
+ port->active = 1;
+ /* force low_latency on so that our tty_push actually forces
+ * the data through, otherwise it is scheduled, and with high
+ * data rates (like with OHCI) data can get lost.
+ */
+ port->tty->low_latency = 1;
+
+ priv = (struct cyberjack_private *)port->private;
+ priv->rdtodo = 0;
+ priv->wrfilled = 0;
+ priv->wrsent = 0;
+
+ /* shutdown any bulk reads that might be going on */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
+
+ port->interrupt_in_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->interrupt_in_urb);
+ if (result)
+ err(" usb_submit_urb(read int) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
+ }
+
+ up (&port->sem);
+
+ return result;
+}
+
+static void cyberjack_close (struct usb_serial_port *port, struct file *filp)
+{
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ down (&port->sem);
+
+ --port->open_count;
+
+ if (port->open_count <= 0) {
+ /* shutdown any bulk reads that might be going on */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
+
+ port->active = 0;
+ port->open_count = 0;
+ }
+
+ up (&port->sem);
+ MOD_DEC_USE_COUNT;
+}
+
+static int cyberjack_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+ int result;
+ int wrexpected;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+ dbg(__FUNCTION__ " - from_user %d", from_user);
+
+ if (count == 0) {
+ dbg(__FUNCTION__ " - write request of 0 bytes");
+ return (0);
+ }
+
+ if (port->write_urb->status == -EINPROGRESS) {
+ dbg (__FUNCTION__ " - already writing");
+ return (0);
+ }
+
+ down (&port->sem);
+
+ if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
+ /* To much data for buffer. Reset buffer. */
+ priv->wrfilled=0;
+ return (0);
+ }
+
+ /* Copy data */
+ if (from_user) {
+ copy_from_user(priv->wrbuf+priv->wrfilled, buf, count);
+ } else {
+ memcpy (priv->wrbuf+priv->wrfilled, buf, count);
+ }
+ usb_serial_debug_data (__FILE__, __FUNCTION__, count,
+ priv->wrbuf+priv->wrfilled);
+ priv->wrfilled += count;
+
+ if( priv->wrfilled >= 3 ) {
+ wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
+ dbg(__FUNCTION__ " - expected data: %d", wrexpected);
+ } else {
+ wrexpected = sizeof(priv->wrbuf);
+ }
+
+ if( priv->wrfilled >= wrexpected ) {
+ /* We have enough data to begin transmission */
+ int length;
+
+ dbg(__FUNCTION__ " - transmitting data (frame 1)");
+ length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected;
+
+ memcpy (port->write_urb->transfer_buffer, priv->wrbuf, length );
+ priv->wrsent=length;
+
+ /* set up our urb */
+ FILL_BULK_URB(port->write_urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, length,
+ ((serial->type->write_bulk_callback) ?
+ serial->type->write_bulk_callback :
+ cyberjack_write_bulk_callback),
+ port);
+
+ /* send the data out the bulk port */
+ result = usb_submit_urb(port->write_urb);
+ if (result) {
+ err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+ /* Throw away data. No better idea what to do with it. */
+ priv->wrfilled=0;
+ priv->wrsent=0;
+ up (&port->sem);
+ return 0;
+ }
+
+ dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent);
+ dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled);
+
+ if( priv->wrsent>=priv->wrfilled ) {
+ dbg(__FUNCTION__ " - buffer cleaned");
+ memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
+ priv->wrfilled=0;
+ priv->wrsent=0;
+ }
+ }
+
+ up (&port->sem);
+ return (count);
+}
+
+static void cyberjack_read_int_callback( struct urb *urb )
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+ struct usb_serial *serial;
+ unsigned char *data = urb->transfer_buffer;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ /* the urb might have been killed. */
+ if (urb->status)
+ return;
+
+ if (port_paranoia_check (port, "cyberjack_read_interrupt")) return;
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "cyberjack_read_interrupt")) return;
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+ /* React only to interrupts signaling a bulk_in transfer */
+ if( (urb->actual_length==4) && (data[0]==0x01) ) {
+ short old_rdtodo = priv->rdtodo;
+ int result;
+
+ /* This is a announcement of comming bulk_ins. */
+ unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
+
+ if( (size>259) || (size==0) ) {
+ dbg( "Bad announced bulk_in data length: %d", size );
+ /* Dunno what is most reliable to do here. */
+ /* return; */
+ }
+
+ if( (old_rdtodo+size)<(old_rdtodo) ) {
+ dbg( "To many bulk_in urbs to do." );
+ return;
+ }
+
+ /* "+=" is probably more fault tollerant than "=" */
+ priv->rdtodo += size;
+
+ dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo);
+
+ if( !old_rdtodo ) {
+ port->read_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->read_urb);
+ if( result )
+ err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+ dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
+ }
+ }
+}
+
+static void cyberjack_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int i;
+ int result;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
+ return;
+ }
+
+ if (urb->status) {
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+ dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+ tty = port->tty;
+ if (urb->actual_length) {
+ for (i = 0; i < urb->actual_length ; ++i) {
+ /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+ if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty_flip_buffer_push(tty);
+ }
+ /* this doesn't actually push the data through unless tty->low_latency is set */
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Reduce urbs to do by one. */
+ priv->rdtodo-=urb->actual_length;
+ /* Just to be sure */
+ if( priv->rdtodo<0 ) priv->rdtodo=0;
+
+ dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo);
+
+ /* Continue to read if we have still urbs to do. */
+ if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
+ port->read_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->read_urb);
+ if (result)
+ err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+ dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
+ }
+}
+
+static void cyberjack_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
+ return;
+ }
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ /* only do something if we have more data to send */
+ if( priv->wrfilled ) {
+ int length, blksize, result;
+
+ if (port->write_urb->status == -EINPROGRESS) {
+ dbg (__FUNCTION__ " - already writing");
+ return;
+ }
+
+ down (&port->sem);
+
+ dbg(__FUNCTION__ " - transmitting data (frame n)");
+
+ length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
+ port->bulk_out_size : (priv->wrfilled - priv->wrsent);
+
+ memcpy (port->write_urb->transfer_buffer, priv->wrbuf + priv->wrsent,
+ length );
+ priv->wrsent+=length;
+
+ /* set up our urb */
+ FILL_BULK_URB(port->write_urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, length,
+ ((serial->type->write_bulk_callback) ?
+ serial->type->write_bulk_callback :
+ cyberjack_write_bulk_callback),
+ port);
+
+ /* send the data out the bulk port */
+ result = usb_submit_urb(port->write_urb);
+ if (result) {
+ err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+ /* Throw away data. No better idea what to do with it. */
+ priv->wrfilled=0;
+ priv->wrsent=0;
+ up (&port->sem);
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return;
+ }
+
+ dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent);
+ dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled);
+
+ blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
+
+ if( (priv->wrsent>=priv->wrfilled) || (priv->wrsent>=blksize) ) {
+ dbg(__FUNCTION__ " - buffer cleaned");
+ memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
+ priv->wrfilled=0;
+ priv->wrsent=0;
+ }
+
+ up (&port->sem);
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return;
+ }
+
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ return;
+}
+
+static int __init cyberjack_init (void)
+{
+ usb_serial_register (&cyberjack_device);
+
+ info(DRIVER_VERSION " " DRIVER_AUTHOR);
+ info(DRIVER_DESC);
+
+ return 0;
+}
+
+static void __exit cyberjack_exit (void)
+{
+ usb_serial_deregister (&cyberjack_device);
+}
+
+module_init(cyberjack_init);
+module_exit(cyberjack_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
--- /dev/null
+/*
+ * Prolific PL2303 USB to serial adaptor driver
+ *
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * Original driver for 2.2.x by anonymous
+ *
+ * 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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * 2001_Jun_06 gkh
+ * finished porting to 2.4 format.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ static int debug = 1;
+#else
+ static int debug;
+#endif
+
+#include "usb-serial.h"
+#include "pl2303.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.5"
+#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
+
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+#define PL2303_LOCK(port,flags) \
+ do { \
+ spin_lock_irqsave(&((struct pl2303_private *)(port->private))->lock, flags); \
+ } while (0)
+
+#define PL2303_UNLOCK(port,flags) \
+ do { \
+ spin_unlock_irqrestore(&((struct pl2303_private *)(port->private))->lock, flags); \
+ } while (0)
+
+
+
+static __devinitdata struct usb_device_id id_table [] = {
+ { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
+ { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct pl2303_private {
+ spinlock_t lock;
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+};
+
+/* function prototypes for a PL2303 serial converter */
+static int pl2303_startup (struct usb_serial *serial);
+static int pl2303_open (struct usb_serial_port *port, struct file *filp);
+static void pl2303_close (struct usb_serial_port *port, struct file *filp);
+static void pl2303_set_termios (struct usb_serial_port *port,
+ struct termios *old);
+static int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg);
+static void pl2303_throttle (struct usb_serial_port *port);
+static void pl2303_unthrottle (struct usb_serial_port *port);
+static void pl2303_read_int_callback (struct urb *urb);
+static void pl2303_read_bulk_callback (struct urb *urb);
+static void pl2303_write_bulk_callback (struct urb *urb);
+static int pl2303_write (struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count);
+static int pl2303_write_room(struct usb_serial_port *port);
+static int pl2303_chars_in_buffer(struct usb_serial_port *port);
+static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
+static void start_xmit (struct usb_serial_port *port);
+
+
+/* All of the device info needed for the PL2303 SIO serial converter */
+static struct usb_serial_device_type pl2303_device = {
+ name: "PL-2303",
+ id_table: id_table,
+ needs_interrupt_in: DONT_CARE, /* 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: NUM_DONT_CARE,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: pl2303_open,
+ close: pl2303_close,
+ throttle: pl2303_throttle,
+ unthrottle: pl2303_unthrottle,
+ write: pl2303_write,
+ ioctl: pl2303_ioctl,
+ write_room: pl2303_write_room,
+ chars_in_buffer: pl2303_chars_in_buffer,
+ break_ctl: pl2303_break_ctl,
+ set_termios: pl2303_set_termios,
+ read_bulk_callback: pl2303_read_bulk_callback,
+ read_int_callback: pl2303_read_int_callback,
+ write_bulk_callback: pl2303_write_bulk_callback,
+ startup: pl2303_startup,
+};
+
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+static unsigned char *tmp_buf;
+static DECLARE_MUTEX (tmp_buf_sem);
+
+
+
+static int
+pl2303_write (struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count)
+{ /* pl2303_write */
+ struct pl2303_private *info = (struct pl2303_private *)port->private;
+ unsigned long flags;
+ int c,ret=0;
+ struct tty_struct *tty=port->tty;
+
+ dbg ("pl2303_write port %d, %d bytes", port->number, count);
+
+ if (!info) {
+ return -ENODEV;
+ }
+
+ if (!tty || !info->xmit_buf || !tmp_buf) {
+ return 0;
+ }
+
+
+ PL2303_LOCK(port,flags);
+
+
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!ret) {
+ ret = -EFAULT;
+ }
+ break;
+ }
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ break;
+ }
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ }
+ PL2303_UNLOCK(port, flags);
+
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ start_xmit(port);
+ }
+ return ret;
+}
+
+static int pl2303_write_room(struct usb_serial_port *port)
+{
+ struct pl2303_private *info = (struct pl2303_private *)port->private;
+ int ret;
+
+ if (!info)
+ return 0;
+
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+static int pl2303_chars_in_buffer(struct usb_serial_port *port)
+{
+ struct pl2303_private *info = (struct pl2303_private *)port->private;
+
+ if (!info)
+ return 0;
+
+ return info->xmit_cnt;
+}
+
+static void pl2303_throttle(struct usb_serial_port *port)
+{
+#if 0
+ //struct usb_serial *serial = port->serial;
+ struct tty_struct *tty=port->tty;
+ unsigned long flags;
+
+
+ char buf[64];
+
+ dbg("throttle %s: %d....", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+
+//FIXME FIXME FIXME
+ if (I_IXOFF(tty))
+ rs_send_xchar(tty, STOP_CHAR(tty));
+
+ PL2303_LOCK(port,flags);
+ //Should remove read request if one is present
+ PL2303_UNLOCK(port,flags);
+#endif
+}
+
+static void pl2303_unthrottle(struct usb_serial_port *port)
+{
+#if 0
+ //struct usb_serial *serial = port->serial;
+ struct tty_struct *tty=port->tty;
+ unsigned long flags;
+
+
+ char buf[64];
+
+ dbg("unthrottle %s: %d....", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+
+ //FIXME FIXME FIXME FIXME FIXME
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ rs_send_xchar(tty, START_CHAR(tty));
+ }
+
+ PL2303_LOCK(port,flags);
+ //Should add read request if one is not present
+ PL2303_UNLOCK(fport,flags);
+#endif
+}
+
+
+static void
+pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{ /* pl2303_set_termios */
+ struct usb_serial *serial = port->serial;
+ unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned char buf[7] = { 0, 0, 0, 0, 0, 0, 0};
+ int baud;
+ int i;
+
+
+ dbg ("pl2303_set_termios port %d", port->number);
+
+
+ i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+ 0x21, 0xa1, 0, 0, buf, 7, 100);
+
+ dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+
+ i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+ 1, 0x40, 0, 1, NULL, 0, 100);
+
+ dbg ("0x40:1:0:1 %d", i);
+
+
+
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+ case CS6:
+ buf[6] = 6;
+ dbg ("Setting CS6");
+ break;
+ case CS7:
+ buf[6] = 7;
+ dbg ("Setting CS7");
+ break;
+ case CS8:
+ buf[6] = 8;
+ dbg ("Setting CS8");
+ break;
+ default:
+ err ("CSIZE was set but not CS6-CS8");
+ }
+ }
+
+ baud = 0;
+ switch (cflag & CBAUD) {
+ case B0:
+ err ("Can't do B0 yet"); //FIXME
+ break;
+ case B300:
+ baud = 300;
+ break;
+ case B600:
+ baud = 600;
+ break;
+ case B1200:
+ baud = 1200;
+ break;
+ case B2400:
+ baud = 2400;
+ break;
+ case B4800:
+ baud = 4800;
+ break;
+ case B9600:
+ baud = 9600;
+ break;
+ case B19200:
+ baud = 19200;
+ break;
+ case B38400:
+ baud = 38400;
+ break;
+ case B57600:
+ baud = 57600;
+ break;
+ case B115200:
+ baud = 115200;
+ break;
+ default:
+ dbg ("pl2303 driver does not support the baudrate requested (fix it)");
+ break;
+ }
+
+ if (baud) {
+ buf[0] = baud & 0xff;
+ buf[1] = (baud >> 8) & 0xff;
+ buf[2] = (baud >> 16) & 0xff;
+ buf[3] = (baud >> 24) & 0xff;
+ }
+
+
+ /* For reference buf[4]=1 is 1.5 stop bits */
+
+ if (cflag & CSTOPB) {
+ buf[4] = 2;
+ }
+
+
+ if (cflag & PARENB) {
+ /* For reference buf[5]=3 is mark parity */
+ /* For reference buf[5]=4 is space parity */
+ if (cflag & PARODD) {
+ buf[5] = 1;
+ } else {
+ buf[5] = 2;
+ }
+ }
+
+ i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+ 0x20, 0x21, 0, 0, buf, 7, 100);
+
+ dbg ("0x21:0x20:0:0 %d", i);
+
+ i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+ 0x22, 0x21, 1, 0, NULL, 0, 100);
+
+ dbg ("0x21:0x22:1:0 %d", i);
+
+ i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+ 0x22, 0x21, 3, 0, NULL, 0, 100);
+
+ dbg ("0x21:0x22:3:0 %d", i);
+
+ buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
+
+ i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+ 0x21, 0xa1, 0, 0, buf, 7, 100);
+
+ dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+ if (cflag & CRTSCTS) {
+
+ i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+ 0x01, 0x40, 0x0, 0x41, NULL, 0, 100);
+
+ dbg ("0x40:0x1:0x0:0x41 %d", i);
+
+ }
+
+
+ return;
+}
+
+
+static int
+pl2303_open (struct usb_serial_port *port, struct file *filp)
+{ /* pl2303_open */
+ struct termios tmp_termios;
+ struct usb_serial *serial = port->serial;
+ unsigned char buf[10];
+ int i;
+
+ dbg ("pl2303_open port %d", port->number);
+
+ port->active++;
+
+#define FISH(a,b,c,d) \
+ i=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
+ b, a,c , d, buf, 1, 100); \
+ dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,i,buf[0]);
+
+#define SOUP(a,b,c,d) \
+ i=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
+ b, a,c , d, NULL, 0, 100); \
+ dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,i);
+
+
+ FISH (0xc0, 1, 0x8484, 0);
+ SOUP (0x40, 1, 0x0404, 0);
+ FISH (0xc0, 1, 0x8484, 0);
+ FISH (0xc0, 1, 0x8383, 0);
+ FISH (0xc0, 1, 0x8484, 0);
+ SOUP (0x40, 1, 0x0404, 1);
+ FISH (0xc0, 1, 0x8484, 0);
+ FISH (0xc0, 1, 0x8383, 0);
+ SOUP (0x40, 1, 0, 1);
+ SOUP (0x40, 1, 1, 0xc0);
+ SOUP (0x40, 1, 2, 4);
+
+ /* Setup termios */
+
+ if (port->active == 1) {
+ *(port->tty->termios) = tty_std_termios;
+ port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ }
+
+
+ pl2303_set_termios (port, &tmp_termios);
+
+ //FIXME: need to assert RTS and DTR if CRTSCTS off
+
+
+ if (port->active == 1) {
+ struct pl2303_private *info;
+ unsigned long flags,page;
+ int i;
+
+ info = (struct pl2303_private *)kmalloc (sizeof(struct pl2303_private), GFP_KERNEL);
+ if (info == NULL) {
+ err(__FUNCTION__ " - out of memory");
+ pl2303_close (port, NULL);
+ return -ENOMEM;
+ }
+ spin_lock_init(&info->lock);
+ port->private = info;
+
+
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+ pl2303_close (port, NULL);
+ return -ENOMEM;
+ }
+
+ PL2303_LOCK(port,flags);
+
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
+
+ PL2303_UNLOCK(port,flags);
+
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+ pl2303_close (port, NULL);
+ return -ENOMEM;
+ }
+
+ PL2303_LOCK(port,flags);
+
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf=(unsigned char *) page;
+
+ PL2303_UNLOCK(port,flags);
+
+
+ if ((i = usb_submit_urb (port->read_urb))) {
+ err ("usb_submit_urb(read bulk 1) failed");
+ dbg ("i=%d", i);
+ pl2303_close (port, NULL);
+ return -EPROTO;
+
+ }
+
+ if ((i = usb_submit_urb (port->interrupt_in_urb))) {
+ err ("usb_submit_urb(interrupt ink) failed");
+ dbg ("i=%d", i);
+ pl2303_close (port, NULL);
+
+ return -EPROTO;
+ }
+ }
+
+ return(0);
+} /* pl2303_open */
+
+
+static void
+pl2303_close (struct usb_serial_port *port, struct file *filp)
+{ /* pl2303_close */
+ struct pl2303_private *info;
+ unsigned int c_cflag = port->tty->termios->c_cflag;
+ unsigned long flags;
+
+ dbg ("pl2303_close port %d", port->number);
+
+ /* shutdown our bulk reads and writes */
+ if (port->active == 1) {
+
+ if (c_cflag & HUPCL) {
+ //FIXME: Do drop DTR
+ //FIXME: Do drop RTS
+ }
+
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
+
+ info = (struct pl2303_private *)port->private;
+ if (info) {
+ PL2303_LOCK(port,flags);
+ if (info->xmit_buf) {
+ unsigned char * temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = 0;
+ free_page((unsigned long) temp);
+ }
+ PL2303_UNLOCK(port,flags);
+ }
+
+ //FIXME: tmp_buf memory leak
+
+
+ }
+ port->active--;
+} /* pl2303_close */
+
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int
+pl2303_startup (struct usb_serial *serial)
+{
+ return(0);
+}
+
+
+static int
+pl2303_ioctl (struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+// struct usb_serial *serial = port->serial;
+// __u16 urb_value=0; /* Will hold the new flags */
+// char buf[1];
+// int ret, mask;
+
+
+ dbg ("pl2303_sio ioctl 0x%04x", cmd);
+
+ /* Based on code from acm.c and others */
+ switch (cmd) {
+
+ case TIOCMGET:
+ dbg ("TIOCMGET");
+
+
+ return put_user (0, (unsigned long *) arg);
+ break;
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return 0;
+
+ default:
+ /* This is not an error - turns out the higher layers will do
+ * some ioctls itself (see comment above)
+ */
+ dbg ("pl2303_sio ioctl arg not supported - it was 0x%04x", cmd);
+ return(-ENOIOCTLCMD);
+ break;
+ }
+ dbg ("pl2303_ioctl returning 0");
+
+ return 0;
+} /* pl2303_ioctl */
+
+
+static void pl2303_break_ctl(struct usb_serial_port *port,int break_state)
+{
+//FIXME
+}
+
+
+static void
+pl2303_read_int_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial *serial = get_usb_serial (port, "pl2303_read_int_callback");
+ //unsigned char *data = urb->transfer_buffer;
+ //int i;
+
+//ints auto restart...
+
+ if (!serial) {
+ return;
+ }
+
+ if (urb->status) {
+ urb->status = 0;
+ return;
+ }
+
+
+#if 0
+//FIXME need to update state of terminal lines variable
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": INT data read - length = %d, data = ",
+ urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
+ return;
+}
+
+static void
+pl2303_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial *serial = get_usb_serial (port, "pl2303_read_bulk_callback");
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int i;
+
+ if (!serial) {
+ return;
+ }
+
+// PL2303 mysteriously fails with -EPROTO reschedule the read
+ if (urb->status) {
+ urb->status = 0;
+ if (usb_submit_urb (urb))
+ dbg ("failed resubmitting read bulk urb");
+ return;
+ }
+
+ if (debug) {
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": BULK data read - length = %d, data = ",
+ urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+ }
+
+ tty = port->tty;
+ if (urb->actual_length) {
+ for (i = 0; i < urb->actual_length; ++i) {
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ dbg ("ARGH ------------ Flip buffer overrun...");
+
+ break;
+ }
+ tty_insert_flip_char (tty, data[i], 0);
+ }
+ tty_flip_buffer_push (tty);
+ }
+
+
+ /* Schedule the next read*/
+ if (usb_submit_urb (urb))
+ dbg ("failed submitting read bulk urb");
+
+ return;
+}
+
+
+
+static void
+pl2303_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty = port->tty;
+
+ dbg ("pl2303_write_bulk_callback");
+
+
+ if (port_paranoia_check (port, "pl2303_write_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "pl2303_write_bulk_callback")) {
+ return;
+ }
+
+
+ if (urb->status) {
+ dbg ("Overflow in write");
+ dbg ("nonzero write bulk status received: %d", urb->status);
+ //need to resubmit frame;
+
+ port->write_urb->transfer_buffer_length = 1;
+
+ //Resubmit ourselves
+
+ if (usb_submit_urb (port->write_urb))
+ err ("usb_submit_urb(write bulk) failed");
+
+ return;
+ }
+
+ wake_up_interruptible (&port->write_wait);
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+
+ wake_up_interruptible (&tty->write_wait);
+
+ start_xmit(port);
+
+ return;
+}
+
+
+
+static void
+start_xmit (struct usb_serial_port *port)
+{
+ struct usb_serial *serial;
+ struct pl2303_private *info;
+ unsigned long flags;
+
+ serial = port->serial;
+ info = (struct pl2303_private *)port->private;
+
+ if (info) {
+ PL2303_LOCK(port,flags);
+
+ if (port->write_urb->status != -EINPROGRESS) {
+ if (info->xmit_tail != info->xmit_head) {
+
+ memcpy (port->write_urb->transfer_buffer, &info->xmit_buf[info->xmit_tail],1);
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+
+
+ port->write_urb->transfer_buffer_length = 1;
+
+
+ if (usb_submit_urb (port->write_urb))
+ err ("usb_submit_urb(write bulk) failed");
+
+
+ }
+ }
+
+ PL2303_UNLOCK(port,flags);
+ }
+}
+
+
+static int __init pl2303_init (void)
+{
+ usb_serial_register (&pl2303_device);
+ info(DRIVER_VERSION " : " DRIVER_DESC);
+ return 0;
+}
+
+
+static void __exit pl2303_exit (void)
+{
+ usb_serial_deregister (&pl2303_device);
+}
+
+
+module_init(pl2303_init);
+module_exit(pl2303_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
/*-------------------------------------------------------------------------*/
-static void
-ohci_pci_suspend (struct pci_dev *dev)
+static int
+ohci_pci_suspend (struct pci_dev *dev, u32 state)
{
ohci_t *ohci = (ohci_t *) dev->driver_data;
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
- return;
+ return -EIO;
}
/* act as if usb suspend can always be used */
ohci->hc_control = OHCI_USB_SUSPEND;
writel (ohci->hc_control, &ohci->regs->control);
wait_ms (10);
+
+ return 0;
}
/*-------------------------------------------------------------------------*/
-static void
+static int
ohci_pci_resume (struct pci_dev *dev)
{
ohci_t *ohci = (ohci_t *) dev->driver_data;
if (atomic_read (&ohci->resume_count) != 1) {
err ("concurrent PCI resumes for usb-%s", dev->slot_name);
atomic_dec (&ohci->resume_count);
- return;
+ return -EBUSY;
}
/* did we suspend, or were we powered off? */
if (temp != OHCI_USB_RESUME) {
err ("controller usb-%s won't resume", dev->slot_name);
ohci->disabled = 1;
- return;
+ return -EIO;
}
ohci->disabled = 0;
/* controller is operational, extra resumes are harmless */
atomic_dec (&ohci->resume_count);
+
+ return 0;
}
#endif /* CONFIG_PM */
}
#ifdef CONFIG_PM
-_static void
-uhci_pci_suspend (struct pci_dev *dev)
+_static int
+uhci_pci_suspend (struct pci_dev *dev, u32 state)
{
reset_hc((uhci_t *) dev->driver_data);
+ return 0;
}
-_static void
+_static int
uhci_pci_resume (struct pci_dev *dev)
{
start_hc((uhci_t *) dev->driver_data);
+ return 0;
}
#endif
}
}
-static void cyberpro_suspend(struct pci_dev *dev)
+static int cyberpro_suspend(struct pci_dev *dev, u32 state)
{
+ return 0;
}
/*
* Re-initialise the CyberPro hardware
*/
-static void cyberpro_resume(struct pci_dev *dev)
+static int cyberpro_resume(struct pci_dev *dev)
{
struct cfb_info *cfb = (struct cfb_info *)dev->driver_data;
cfb->fb.var.activate = FB_ACTIVATE_NOW;
cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
}
+
+ return 0;
}
static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
* With additional hacking by Jeffrey Kuskin (jsk@mojave.stanford.edu)
* Modified by Danilo Beuche 1998
* Some register values added by Damien Doligez, INRIA Rocquencourt
+ * Various cleanups by Paul Mundt (lethal@chaoticdreams.org)
*
* This file was written by Ryan Nielsen (ran@krazynet.com)
* Most of the frame buffer device stuff was copied from atyfb.c
#define CURSOR_DRAW_DELAY 2
static int currcon = 0;
+static int inverse = 0;
static char fontname[40] __initdata = { 0 };
static char curblink __initdata = 1;
static char noaccel __initdata = 0;
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
u_int bpp = fb_display[currcon].var.bits_per_pixel;
- u_int i;
if (regno > 255)
return 1;
disp->type_aux = p->fix.type_aux;
disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
disp->can_soft_blank = 1;
- disp->inverse = 0;
+ disp->inverse = inverse;
disp->ypanstep = 1;
disp->ywrapstep = 0;
if (accel) {
struct pci_dev *pdev = NULL;
struct fb_info_imstt *p;
unsigned long addr, size;
- __u16 cmd;
while ((pdev = pci_find_device(PCI_VENDOR_ID_IMS, PCI_ANY_ID, pdev))) {
if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
curblink = 0;
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
+ } else if (!strncmp(this_opt, "inverse", 7)) {
+ inverse = 1;
+ fb_invert_cmaps();
}
#if defined(CONFIG_PPC)
else if (!strncmp(this_opt, "vmode:", 6)) {
}
#else /* MODULE */
-
-int __init
-init_module (void)
-{
-
- return imsttfb_init();
-}
-
-void
-cleanup_module (void)
+static void __exit
+imsttfb_exit(void)
{
struct fb_info_imstt *p;
__u32 i;
p = fb_info_imstt_p[i];
if (!p)
continue;
+ unregister_framebuffer(&p->info);
iounmap(p->cmap_regs);
iounmap(p->dc_regs);
iounmap(p->frame_buffer);
- kfree(p);
release_mem_region(p->frame_buffer_phys, p->board_size);
+ kfree(p);
}
}
#include "macmodes.c"
+
+module_init(imsttfb_init);
+module_exit(imsttfb_exit);
#endif /* MODULE */
+
/* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
"mac20", 75, 1280, 1024, 7408, 232, 64, 38, 1, 112, 3,
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
+ }, {
+ /* 1152x768, 60 Hz, Titanium PowerBook */
+ "mac21", 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }, {
+ /* 1600x1024, 60 Hz, Non-Interlaced (112.27 MHz dotclock) */
+ "mac22", 60, 1600, 1024, 8908, 88, 104, 1, 10, 16, 1,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
#if 0
/* Anyone who has timings for these? */
{ VMODE_1024_768_75V, &mac_modedb[9] },
{ VMODE_1024_768_70, &mac_modedb[8] },
{ VMODE_1024_768_60, &mac_modedb[7] },
+ /* 1152x768 */
+ { VMODE_1152_768_60, &mac_modedb[14] },
/* 1152x870 */
{ VMODE_1152_870_75, &mac_modedb[11] },
/* 1280x960 */
{ VMODE_1280_960_75, &mac_modedb[12] },
/* 1280x1024 */
{ VMODE_1280_1024_75, &mac_modedb[13] },
+ /* 1600x1024 */
+ { VMODE_1600_1024_60, &mac_modedb[15] },
{ -1, NULL }
};
{ 0x730, VMODE_768_576_50I }, /* PAL (Alternate) */
{ 0x73a, VMODE_1152_870_75 }, /* 3rd party 19" */
{ 0x73f, VMODE_640_480_67 }, /* no sense lines connected at all */
+ { 0xBEEF, VMODE_1600_1024_60 }, /* 22" Apple Cinema Display */
{ -1, VMODE_640_480_60 }, /* catch-all, must be last */
};
*
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
*
- * Version: 1.52 2001/02/02
+ * Version: 1.53 2001/06/18
*
* See matroxfb_base.c for contributors.
*
#define DAC1064_OPT_RESERVED 0x10
static void matroxfb_DAC1064_flashcursor(unsigned long ptr) {
+ unsigned long flags;
+
#define minfo ((struct matrox_fb_info*)ptr)
- matroxfb_DAC_lock();
+ matroxfb_DAC_lock_irqsave(flags);
outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA);
ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
add_timer(&ACCESS_FBINFO(cursor.timer));
- matroxfb_DAC_unlock();
+ matroxfb_DAC_unlock_irqrestore(flags);
#undef minfo
}
ACCESS_FBINFO(capable.vxres) = vxres_g100;
ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
- ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG100;
+ ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
+ ? ACCESS_FBINFO(devflags.sgram) : 1;
ACCESS_FBINFO(primout) = &m1064;
0x00, 0x00, TVP3026_XCURCTRL_DIS };
static void matroxfb_ti3026_flashcursor(unsigned long ptr) {
+ unsigned long flags;
+
#define minfo ((struct matrox_fb_info*)ptr)
- matroxfb_DAC_lock();
+ matroxfb_DAC_lock_irqsave(flags);
outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA);
ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
add_timer(&ACCESS_FBINFO(cursor.timer));
- matroxfb_DAC_unlock();
+ matroxfb_DAC_unlock_irqrestore(flags);
#undef minfo
}
*
* Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
*
- * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
*
- * Version: 1.50 2000/08/10
+ * Version: 1.51 2001/06/18
*
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
*
mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
if (ACCESS_FBINFO(capable.plnwt))
mga_outl(M_PLNWT, -1);
+ if (ACCESS_FBINFO(capable.srcorg)) {
+ mga_outl(M_SRCORG, 0);
+ mga_outl(M_DSTORG, 0);
+ }
mga_outl(M_OPMODE, mopmode);
mga_outl(M_CXBNDRY, 0xFFFF0000);
mga_outl(M_YTOP, 0);
*
* (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
*
- * Version: 1.52 2001/02/02
+ * Version: 1.53 2001/06/18
*
* MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
*
* "Ken Aaker" <kdaaker@rchland.vnet.ibm.com>
* memtype extension (needed for GXT130P RS/6000 adapter)
*
+ * "Uns Lider" <unslider@miranda.org>
+ * G100 PLNWT fixes
+ *
* (following author is not in any relation with this code, but his code
* is included in this driver)
*
#define DEVF_VIDEO64BIT 0x0001
#define DEVF_SWAPS 0x0002
-/* #define DEVF_recycled 0x0004 */
+#define DEVF_SRCORG 0x0004
/* #define DEVF_recycled 0x0008 */
#define DEVF_CROSS4MB 0x0010
#define DEVF_TEXT4B 0x0020
#define DEVF_G450DAC 0x4000
#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
-#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE)
+#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG)
#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */
#define DEVF_G200 (DEVF_G2CORE)
#define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
/* if you'll find how to drive DFP... */
-#define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC)
+#define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG)
static struct board {
unsigned short vendor, device, rev, svid, sid;
DEVF_G200,
230000,
&vbG200,
- "unknown G200 (AGP)"},
+ "G200 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0x80,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP,
DEVF_G400,
DEVF_G400,
300000,
&vbG400,
- "unknown G400 (AGP)"},
+ "G400 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF,
0, 0,
DEVF_G450,
500000, /* ??? vco goes up to 900MHz... */
&vbG400,
- "unknown G450 (AGP)"},
+ "G450 (AGP)"},
#endif
{0, 0, 0xFF,
0, 0,
printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
ACCESS_FBINFO(capable.plnwt) = 1;
+ ACCESS_FBINFO(capable.srcorg) = b->flags & DEVF_SRCORG;
ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
if (b->flags & DEVF_TEXT4B) {
ACCESS_FBINFO(devflags.vgastep) = 4;
return 0;
}
-static int initialized __initdata = 0;
+static int __initdata initialized = 0;
int __init matroxfb_init(void)
{
initialized = 1;
matrox_init();
}
+ hotplug = 1;
/* never return failure, user can hotplug matrox later... */
return 0;
}
MODULE_PARM(mtrr, "i");
MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
MODULE_PARM(sgram, "i");
-MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+MODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
MODULE_PARM(inv24, "i");
MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
MODULE_PARM(inverse, "i");
int cross4MB;
int text;
int plnwt;
+ int srcorg;
} capable;
struct {
unsigned int size;
/* G200 only */
#define M_SRCORG 0x2CB4
+#define M_DSTORG 0x2CB8
#define M_RAMDAC_BASE 0x3C00
static int matroxfb_g450_get_reg(WPMINFO int reg) {
int val;
+ unsigned long flags;
- matroxfb_DAC_lock();
+ matroxfb_DAC_lock_irqsave(flags);
val = matroxfb_DAC_in(PMINFO reg);
- matroxfb_DAC_unlock();
+ matroxfb_DAC_unlock_irqrestore(flags);
return val;
}
static int matroxfb_g450_set_reg(WPMINFO int reg, int val) {
- matroxfb_DAC_lock();
+ unsigned long flags;
+
+ matroxfb_DAC_lock_irqsave(flags);
matroxfb_DAC_out(PMINFO reg, val);
- matroxfb_DAC_unlock();
+ matroxfb_DAC_unlock_irqrestore(flags);
return 0;
}
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
+ *
+ * Changelog:
+ * Paul G. (03/2001) Fix mdacon= boot prompt to use __setup().
*/
#include <linux/types.h>
spin_unlock_irqrestore(&mda_lock, flags);
}
+#ifdef TEST_MDA_B
static int test_mda_b(unsigned char val, unsigned char reg)
{
unsigned long flags;
spin_unlock_irqrestore(&mda_lock, flags);
return val;
}
+#endif
static inline void mda_set_origin(unsigned int location)
{
#ifndef MODULE
-void __init mdacon_setup(char *str, int *ints)
+static int __init mdacon_setup(char *str)
{
/* command line format: mdacon=<first>,<last> */
+ int ints[3];
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+
if (ints[0] < 2)
- return;
+ return 0;
if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES ||
ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
- return;
+ return 0;
- mda_first_vc = ints[1]-1;
- mda_last_vc = ints[2]-1;
+ mda_first_vc = ints[1];
+ mda_last_vc = ints[2];
+ return 1;
}
+
+__setup("mdacon=", mdacon_setup);
#endif
static int __init mda_detect(void)
* memory location, so now we do an I/O port test.
*/
+#ifdef TEST_MDA_B
/* Edward: These two mess `tests' mess up my cursor on bootup */
/* cursor low register */
- /* if (! test_mda_b(0x66, 0x0f)) {
+ if (! test_mda_b(0x66, 0x0f)) {
return 0;
- } */
+ }
/* cursor low register */
- /* if (! test_mda_b(0x99, 0x0f)) {
+ if (! test_mda_b(0x99, 0x0f)) {
return 0;
- } */
+ }
+#endif
/* See if the card is a Hercules, by checking whether the vsync
* bit of the status register is changing. This test lasts for
* SUCH DAMAGE.
*/
-#ident "$Id: vxfs_bmap.c,v 1.20 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_bmap.c,v 1.22 2001/05/26 22:41:23 hch Exp hch $"
/*
* Veritas filesystem driver - filesystem to disk block mapping.
struct super_block *sbp = ip->i_sb;
kdev_t dev = ip->i_dev;
u_long bsize = sbp->s_blocksize;
- u_long size = 0;
+ long size = 0;
int i;
for (i = 0; i < VXFS_NDADDR; i++) {
for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
struct vxfs_typed *typ;
- u_int64_t off;
+ int64_t off;
bp = bread(ip->i_dev,
indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)),
goto out;
case VXFS_TYPED_INDIRECT_DEV4:
case VXFS_TYPED_DATA_DEV4: {
- struct vxfs_typed_dev4 *typ4 = (struct vxfs_typed_dev4 *)typ;
+ struct vxfs_typed_dev4 *typ4 =
+ (struct vxfs_typed_dev4 *)typ;
+
printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
- printk(KERN_INFO "block: %Ld\tsize: %Ld\tdev: %d\n",
- (long long)typ4->vd4_block, (long long)typ4->vd4_size, typ4->vd4_dev);
+ printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
+ typ4->vd4_block, typ4->vd4_size, typ4->vd4_dev);
goto fail;
}
default:
for (i = 0; i < VXFS_NTYPED; i++) {
struct vxfs_typed *typ = vip->vii_org.typed + i;
- u_int64_t off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+ int64_t off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
#ifdef DIAGNOSTIC
vxfs_typdump(typ);
break;
case VXFS_TYPED_INDIRECT_DEV4:
case VXFS_TYPED_DATA_DEV4: {
- struct vxfs_typed_dev4 *typ4 = (struct vxfs_typed_dev4 *)typ;
+ struct vxfs_typed_dev4 *typ4 =
+ (struct vxfs_typed_dev4 *)typ;
+
printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
- printk(KERN_INFO "block: %Ld\tsize: %Ld\tdev: %d\n",
- (long long)typ4->vd4_block, (long long)typ4->vd4_size, typ4->vd4_dev);
+ printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
+ typ4->vd4_block, typ4->vd4_size, typ4->vd4_dev);
return 0;
}
default:
#ifndef _VXFS_FSHEAD_H_
#define _VXFS_FSHEAD_H_
-#ident "$Id: vxfs_fshead.h,v 1.6 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_fshead.h,v 1.7 2001/05/23 17:27:39 hch Exp hch $"
/*
* Veritas filesystem driver - fileset header structures.
/*
* Slightly more fields follow, but they
- * a) are not of any interested for us, and
- * b) differ much in different vxfs versions/ports
+ * a) are not of any interest for us, and
+ * b) differ a lot in different vxfs versions/ports
*/
};
* SUCH DAMAGE.
*/
-#ident "$Id: vxfs_inode.c,v 1.34 2001/05/21 15:33:08 hch Exp hch $"
+#ident "$Id: vxfs_inode.c,v 1.36 2001/05/26 22:28:02 hch Exp hch $"
/*
* Veritas filesystem driver - inode routines.
extern struct inode_operations vxfs_immed_symlink_iops;
static struct file_operations vxfs_file_operations = {
+ .llseek = generic_file_llseek,
.read = generic_file_read,
.mmap = generic_file_mmap,
};
* Returns the matching VxFS inode on success, else a NULL pointer.
*
* NOTE:
- * While __vxfs_iget uses that pagecache this function uses the
+ * While __vxfs_iget uses the pagecache vxfs_blkiget uses the
* buffercache. This function should not be used outside the
* read_super() method, othwerwise the data may be incoherent.
*/
* Returns the matching VxFS inode on success, else a NULL pointer.
*/
static struct vxfs_inode_info *
-__vxfs_iget(struct super_block *sbp, ino_t ino, struct inode *ilistp)
+__vxfs_iget(ino_t ino, struct inode *ilistp)
{
struct page *pp;
u_long offset;
struct vxfs_inode_info *
vxfs_stiget(struct super_block *sbp, ino_t ino)
{
- return __vxfs_iget(sbp, ino, VXFS_SBI(sbp)->vsi_stilist);
+ return __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
}
/**
struct address_space_operations *aops;
ino_t ino = ip->i_ino;
- if (!(vip = __vxfs_iget(sbp, ino, VXFS_SBI(sbp)->vsi_ilist)))
+ if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist)))
return;
vxfs_iinit(ip, vip);
#ifndef _VXFS_INODE_H_
#define _VXFS_INODE_H_
-#ident "$Id: vxfs_inode.h,v 1.14 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_inode.h,v 1.15 2001/05/26 22:41:23 hch Exp hch $"
/*
* Veritas filesystem driver - inode structure.
vx_daddr_t ve4_indir[VXFS_NIADDR]; /* Indirect extents */
struct direct { /* Direct extents */
vx_daddr_t extent; /* Extent number */
- u_int32_t size; /* Size of extent */
+ int32_t size; /* Size of extent */
} ve4_direct[VXFS_NDADDR];
};
* SUCH DAMAGE.
*/
-#ident "$Id: vxfs_lookup.c,v 1.17 2001/05/21 15:23:53 hch Exp hch $"
+#ident "$Id: vxfs_lookup.c,v 1.19 2001/05/30 19:50:20 hch Exp hch $"
/*
* Veritas filesystem driver - lookup and other directory related code.
struct inode *ip = fp->f_dentry->d_inode;
struct super_block *sbp = ip->i_sb;
u_long bsize = sbp->s_blocksize;
- u_long page, npages, block, nblocks, offset;
+ u_long page, npages, block, pblocks, nblocks, offset;
loff_t pos;
- int pblocks;
switch ((long)fp->f_pos) {
case 0:
if (pos > VXFS_DIRROUND(ip->i_size))
return 0;
- page = pos >> PAGE_CACHE_SHIFT;
- offset = pos & ~PAGE_CACHE_MASK;
- block = pos >> sbp->s_blocksize_bits;
-
npages = dir_pages(ip);
nblocks = dir_blocks(ip);
pblocks = VXFS_BLOCK_PER_PAGE(sbp);
+ page = pos >> PAGE_CACHE_SHIFT;
+ offset = pos & ~PAGE_CACHE_MASK;
+ block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
+
for (; page < npages; page++, block = 0) {
caddr_t kaddr;
struct page *pp;
goto done;
}
}
+ offset = 0;
}
vxfs_put_page(pp);
offset = 0;
* SUCH DAMAGE.
*/
-#ident "$Id: vxfs_super.c,v 1.24 2001/05/20 15:21:14 hch Exp hch $"
+#ident "$Id: vxfs_super.c,v 1.25 2001/05/25 18:25:55 hch Exp hch $"
/*
* Veritas filesystem driver - superblock related routines.
bp = bread(dev, 1, bsize);
if (!bp) {
printk(KERN_WARNING "vxfs: unable to read disk superblock\n");
- return NULL;
+ goto out;
}
rsbp = (struct vxfs_sb *)bp->b_data;
if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
- return NULL;
+ goto out;
}
if (rsbp->vs_version < 2 || rsbp->vs_version > 4) {
printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", rsbp->vs_version);
- return NULL;
+ goto out;
}
#ifdef DIAGNOSTIC
default:
printk(KERN_WARNING "vxfs: unsupported blocksise: %d\n",
rsbp->vs_bsize);
- return NULL;
+ goto out;
}
if (vxfs_read_olt(sbp, bsize)) {
printk(KERN_WARNING "vxfs: unable to read olt\n");
- return NULL;
+ goto out;
}
if (vxfs_read_fshead(sbp)) {
return (sbp);
printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
+out:
+ kfree(infp);
return NULL;
}
* Ported to Linux 2.3.x and MTD:
* Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB
*
+ * Copyright 2000, 2001 Red Hat, Inc.
*/
/* inode.c -- Contains the code that is called from the VFS. */
static int __init
init_jffs_fs(void)
{
- printk("JFFS version "
- JFFS_VERSION_STRING
- ", (C) 1999, 2000 Axis Communications AB\n");
return register_filesystem(&jffs_fs_type);
}
tristate 'Codepage 852 (Central/Eastern Europe)' CONFIG_NLS_CODEPAGE_852
tristate 'Codepage 855 (Cyrillic)' CONFIG_NLS_CODEPAGE_855
tristate 'Codepage 857 (Turkish)' CONFIG_NLS_CODEPAGE_857
- tristate 'Codepage 860 (Portugese)' CONFIG_NLS_CODEPAGE_860
+ tristate 'Codepage 860 (Portuguese)' CONFIG_NLS_CODEPAGE_860
tristate 'Codepage 861 (Icelandic)' CONFIG_NLS_CODEPAGE_861
tristate 'Codepage 862 (Hebrew)' CONFIG_NLS_CODEPAGE_862
tristate 'Codepage 863 (Canadian French)' CONFIG_NLS_CODEPAGE_863
tristate 'Korean charset (CP949, EUC-KR)' CONFIG_NLS_CODEPAGE_949
tristate 'Thai charset (CP874, TIS-620)' CONFIG_NLS_CODEPAGE_874
tristate 'Hebrew charsets (ISO-8859-8, CP1255)' CONFIG_NLS_ISO8859_8
- tristate 'Windows CP1251 (Bulgarian, Belarussian)' CONFIG_NLS_CODEPAGE_1251
+ tristate 'Windows CP1251 (Bulgarian, Belarusian)' CONFIG_NLS_CODEPAGE_1251
tristate 'NLS ISO 8859-1 (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1
tristate 'NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages)' CONFIG_NLS_ISO8859_2
tristate 'NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3
tristate 'NLS ISO 8859-14 (Latin 8; Celtic)' CONFIG_NLS_ISO8859_14
tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15
tristate 'NLS KOI8-R (Russian)' CONFIG_NLS_KOI8_R
- tristate 'NLS KOI8-U/RU (Ukrainian, Belarussian)' CONFIG_NLS_KOI8_U
+ tristate 'NLS KOI8-U/RU (Ukrainian, Belarusian)' CONFIG_NLS_KOI8_U
tristate 'NLS UTF8' CONFIG_NLS_UTF8
endmenu
fi
#define MAY_PTRACE(p) \
(p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED))
+
+static int mem_open(struct inode* inode, struct file* file)
+{
+ file->private_data = (void*)(current->self_exec_id);
+ return 0;
+}
+
static ssize_t mem_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
char *page;
unsigned long src = *ppos;
int copied = 0;
+ struct mm_struct *mm;
+
if (!MAY_PTRACE(task))
return -ESRCH;
if (!page)
return -ENOMEM;
+ task_lock(task);
+ mm = task->mm;
+ if (mm)
+ atomic_inc(&mm->mm_users);
+ task_unlock(task);
+
+ if (file->private_data != (void*)(current->self_exec_id) ) {
+ mmput(mm);
+ return -EIO;
+ }
+
+
while (count > 0) {
int this_len, retval;
count -= retval;
}
*ppos = src;
+ mmput(mm);
free_page((unsigned long) page);
return copied;
}
static struct file_operations proc_mem_operations = {
read: mem_read,
write: mem_write,
+ open: mem_open,
};
static struct inode_operations proc_mem_inode_operations = {
static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8];
+spinlock_t proc_alloc_map_lock = SPIN_LOCK_UNLOCKED;
+
static int make_inode_number(void)
{
- int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
- if (i<0 || i>=PROC_NDYNAMIC)
- return -1;
+ int i;
+ spin_lock(&proc_alloc_map_lock);
+ i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
+ if (i<0 || i>=PROC_NDYNAMIC) {
+ i = -1;
+ goto out;
+ }
set_bit(i, (void *) proc_alloc_map);
- return PROC_DYNAMIC_FIRST + i;
+ i += PROC_DYNAMIC_FIRST;
+out:
+ spin_unlock(&proc_alloc_map_lock);
+ return i;
}
static int proc_readlink(struct dentry *dentry, char *buffer, int buflen)
fd_set_bits fds;
char *bits;
long timeout;
- int ret, size;
+ int ret, size, max_fdset;
timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
if (n < 0)
goto out_nofds;
- if (n > current->files->max_fdset)
- n = current->files->max_fdset;
+ /* max_fdset can increase, so grab it once to avoid race */
+ max_fdset = current->files->max_fdset;
+ if (n > max_fdset)
+ n = max_fdset;
/*
* We need 6 bitmaps (in/out/ex for both incoming and outgoing),
* Function prototypes to keep gcc -Wall happy.
*/
extern void set_bit(int nr, volatile void * addr);
+
+static inline void __set_bit(int nr, volatile void *addr)
+{
+ ((unsigned char *) addr)[nr >> 3] |= (1U << (nr & 7));
+}
+
extern void clear_bit(int nr, volatile void * addr);
+
+static inline void __clear_bit(int nr, volatile void *addr)
+{
+ ((unsigned char *) addr)[nr >> 3] &= ~(1U << (nr & 7));
+}
+
extern void change_bit(int nr, volatile void * addr);
+static inline void __change_bit(int nr, volatile void *addr)
+{
+ ((unsigned char *) addr)[nr >> 3] ^= (1U << (nr & 7));
+}
+
extern int test_and_set_bit(int nr, volatile void * addr);
+
+static inline int __test_and_set_bit(int nr, volatile void *addr)
+{
+ unsigned int mask = 1 << (nr & 7);
+ unsigned int oldval;
+
+ oldval = ((unsigned char *) addr)[nr >> 3];
+ ((unsigned char *) addr)[nr >> 3] = oldval | mask;
+ return oldval & mask;
+}
+
extern int test_and_clear_bit(int nr, volatile void * addr);
+
+static inline int __test_and_clear_bit(int nr, volatile void *addr)
+{
+ unsigned int mask = 1 << (nr & 7);
+ unsigned int oldval;
+
+ oldval = ((unsigned char *) addr)[nr >> 3];
+ ((unsigned char *) addr)[nr >> 3] = oldval & ~mask;
+ return oldval & mask;
+}
+
extern int test_and_change_bit(int nr, volatile void * addr);
+
+static inline int __test_and_change_bit(int nr, volatile void *addr)
+{
+ unsigned int mask = 1 << (nr & 7);
+ unsigned int oldval;
+
+ oldval = ((unsigned char *) addr)[nr >> 3];
+ ((unsigned char *) addr)[nr >> 3] = oldval ^ mask;
+ return oldval & mask;
+}
+
extern int find_first_zero_bit(void * addr, unsigned size);
extern int find_next_zero_bit(void * addr, int size, int offset);
* is in pci.h
*/
extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
-extern void consistent_free(void *vaddr);
+extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
extern void consistent_sync(void *vaddr, size_t size, int rw);
#define __raw_writeb(v,a) __arch_putb(v,a)
pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
- consistent_free(vaddr);
+ consistent_free(vaddr, size, dma_handle);
}
/* Map a single buffer of the indicated size for DMA in streaming mode.
#include <asm/proc-fns.h>
+#define vectors_base() (0)
+
extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{
extern void __bad_xchg(volatile void *, int);
"mcr p15, 0, %0, c1, c0 @ set CR" \
: : "r" (x))
+#define CR_M (1 << 0) /* MMU enable */
+#define CR_A (1 << 1) /* Alignment abort enable */
+#define CR_C (1 << 2) /* Dcache enable */
+#define CR_W (1 << 3) /* Write buffer enable */
+#define CR_P (1 << 4) /* 32-bit exception handler */
+#define CR_D (1 << 5) /* 32-bit data address range */
+#define CR_L (1 << 6) /* Implementation defined */
+#define CD_B (1 << 7) /* Big endian */
+#define CR_S (1 << 8) /* System MMU protection */
+#define CD_R (1 << 9) /* ROM MMU protection */
+#define CR_F (1 << 10) /* Implementation defined */
+#define CR_Z (1 << 11) /* Implementation defined */
+#define CR_I (1 << 12) /* Icache enable */
+#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */
+#define CR_RR (1 << 14) /* Round Robin cache replacement */
+
extern unsigned long cr_no_alignment; /* defined in entry-armv.S */
extern unsigned long cr_alignment; /* defined in entry-armv.S */
+#ifdef __ARM_ARCH_4__
+#define vectors_base() ((cr_alignment & CR_V) ? 0xffff0000 : 0)
+#else
+#define vectors_base() (0)
+#endif
+
/*
* A couple of speedups for the ARM
*/
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
-/*
- * linux/include/asm-arm/xor.h
- *
- * Copyright (C) 2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * linux/include/asm-arm/xor.h
- *
- * Copyright (C) 2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
#include <asm-generic/xor.h>
#define __XOR(a1, a2) a1 ^= a2
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_32regs); \
} while (0)
-
-#define __XOR(a1, a2) a1 ^= a2
-
-#define GET_BLOCK_2(dst) \
- __asm__("ldmia %0, {%1, %2}" \
- : "=r" (dst), "=r" (a1), "=r" (a2) \
- : "0" (dst))
-
-#define GET_BLOCK_4(dst) \
- __asm__("ldmia %0, {%1, %2, %3, %4}" \
- : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
- : "0" (dst))
-
-#define XOR_BLOCK_2(src) \
- __asm__("ldmia %0!, {%1, %2}" \
- : "=r" (src), "=r" (b1), "=r" (b2) \
- : "0" (src)); \
- __XOR(a1, b1); __XOR(a2, b2);
-
-#define XOR_BLOCK_4(src) \
- __asm__("ldmia %0!, {%1, %2, %3, %4}" \
- : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
- : "0" (src)); \
- __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
-
-#define PUT_BLOCK_2(dst) \
- __asm__ __volatile__("stmia %0!, {%2, %3}" \
- : "=r" (dst) \
- : "0" (dst), "r" (a1), "r" (a2))
-
-#define PUT_BLOCK_4(dst) \
- __asm__ __volatile__("stmia %0!, {%2, %3, %4, %5}" \
- : "=r" (dst) \
- : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
-
-static void
-xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
- unsigned int lines = bytes / sizeof(unsigned long) / 4;
- register unsigned int a1 __asm__("r4");
- register unsigned int a2 __asm__("r5");
- register unsigned int a3 __asm__("r6");
- register unsigned int a4 __asm__("r7");
- register unsigned int b1 __asm__("r8");
- register unsigned int b2 __asm__("r9");
- register unsigned int b3 __asm__("ip");
- register unsigned int b4 __asm__("lr");
-
- do {
- GET_BLOCK_4(p1);
- XOR_BLOCK_4(p2);
- PUT_BLOCK_4(p1);
- } while (--lines);
-}
-
-static void
-xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3)
-{
- unsigned int lines = bytes / sizeof(unsigned long) / 4;
- register unsigned int a1 __asm__("r4");
- register unsigned int a2 __asm__("r5");
- register unsigned int a3 __asm__("r6");
- register unsigned int a4 __asm__("r7");
- register unsigned int b1 __asm__("r8");
- register unsigned int b2 __asm__("r9");
- register unsigned int b3 __asm__("ip");
- register unsigned int b4 __asm__("lr");
-
- do {
- GET_BLOCK_4(p1);
- XOR_BLOCK_4(p2);
- XOR_BLOCK_4(p3);
- PUT_BLOCK_4(p1);
- } while (--lines);
-}
-
-static void
-xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3, unsigned long *p4)
-{
- unsigned int lines = bytes / sizeof(unsigned long) / 2;
- register unsigned int a1 __asm__("r8");
- register unsigned int a2 __asm__("r9");
- register unsigned int b1 __asm__("ip");
- register unsigned int b2 __asm__("lr");
-
- do {
- GET_BLOCK_2(p1);
- XOR_BLOCK_2(p2);
- XOR_BLOCK_2(p3);
- XOR_BLOCK_2(p4);
- PUT_BLOCK_2(p1);
- } while (--lines);
-}
-
-static void
-xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
- unsigned int lines = bytes / sizeof(unsigned long) / 2;
- register unsigned int a1 __asm__("r8");
- register unsigned int a2 __asm__("r9");
- register unsigned int b1 __asm__("ip");
- register unsigned int b2 __asm__("lr");
-
- do {
- GET_BLOCK_2(p1);
- XOR_BLOCK_2(p2);
- XOR_BLOCK_2(p3);
- XOR_BLOCK_2(p4);
- XOR_BLOCK_2(p5);
- PUT_BLOCK_2(p1);
- } while (--lines);
-}
-
-static struct xor_block_template xor_block_arm4regs = {
- name: "arm4regs",
- do_2: xor_arm4regs_2,
- do_3: xor_arm4regs_3,
- do_4: xor_arm4regs_4,
- do_5: xor_arm4regs_5,
-};
-
-#undef XOR_TRY_TEMPLATES
-#define XOR_TRY_TEMPLATES \
- do { \
- xor_speed(&xor_block_arm4regs); \
- xor_speed(&xor_block_8regs); \
- xor_speed(&xor_block_32regs); \
- } while (0)
-
-#define __XOR(a1, a2) a1 ^= a2
-
-#define GET_BLOCK_2(dst) \
- __asm__("ldmia %0, {%1, %2}" \
- : "=r" (dst), "=r" (a1), "=r" (a2) \
- : "0" (dst))
-
-#define GET_BLOCK_4(dst) \
- __asm__("ldmia %0, {%1, %2, %3, %4}" \
- : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
- : "0" (dst))
-
-#define XOR_BLOCK_2(src) \
- __asm__("ldmia %0!, {%1, %2}" \
- : "=r" (src), "=r" (b1), "=r" (b2) \
- : "0" (src)); \
- __XOR(a1, b1); __XOR(a2, b2);
-
-#define XOR_BLOCK_4(src) \
- __asm__("ldmia %0!, {%1, %2, %3, %4}" \
- : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
- : "0" (src)); \
- __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
-
-#define PUT_BLOCK_2(dst) \
- __asm__ __volatile__("stmia %0!, {%2, %3}" \
- : "=r" (dst) \
- : "0" (dst), "r" (a1), "r" (a2))
-
-#define PUT_BLOCK_4(dst) \
- __asm__ __volatile__("stmia %0!, {%2, %3, %4, %5}" \
- : "=r" (dst) \
- : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
-
-static void
-xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
- unsigned int lines = bytes / sizeof(unsigned long) / 4;
- register unsigned int a1 __asm__("r4");
- register unsigned int a2 __asm__("r5");
- register unsigned int a3 __asm__("r6");
- register unsigned int a4 __asm__("r7");
- register unsigned int b1 __asm__("r8");
- register unsigned int b2 __asm__("r9");
- register unsigned int b3 __asm__("ip");
- register unsigned int b4 __asm__("lr");
-
- do {
- GET_BLOCK_4(p1);
- XOR_BLOCK_4(p2);
- PUT_BLOCK_4(p1);
- } while (--lines);
-}
-
-static void
-xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3)
-{
- unsigned int lines = bytes / sizeof(unsigned long) / 4;
- register unsigned int a1 __asm__("r4");
- register unsigned int a2 __asm__("r5");
- register unsigned int a3 __asm__("r6");
- register unsigned int a4 __asm__("r7");
- register unsigned int b1 __asm__("r8");
- register unsigned int b2 __asm__("r9");
- register unsigned int b3 __asm__("ip");
- register unsigned int b4 __asm__("lr");
-
- do {
- GET_BLOCK_4(p1);
- XOR_BLOCK_4(p2);
- XOR_BLOCK_4(p3);
- PUT_BLOCK_4(p1);
- } while (--lines);
-}
-
-static void
-xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3, unsigned long *p4)
-{
- unsigned int lines = bytes / sizeof(unsigned long) / 2;
- register unsigned int a1 __asm__("r8");
- register unsigned int a2 __asm__("r9");
- register unsigned int b1 __asm__("ip");
- register unsigned int b2 __asm__("lr");
-
- do {
- GET_BLOCK_2(p1);
- XOR_BLOCK_2(p2);
- XOR_BLOCK_2(p3);
- XOR_BLOCK_2(p4);
- PUT_BLOCK_2(p1);
- } while (--lines);
-}
-
-static void
-xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
- unsigned int lines = bytes / sizeof(unsigned long) / 2;
- register unsigned int a1 __asm__("r8");
- register unsigned int a2 __asm__("r9");
- register unsigned int b1 __asm__("ip");
- register unsigned int b2 __asm__("lr");
-
- do {
- GET_BLOCK_2(p1);
- XOR_BLOCK_2(p2);
- XOR_BLOCK_2(p3);
- XOR_BLOCK_2(p4);
- XOR_BLOCK_2(p5);
- PUT_BLOCK_2(p1);
- } while (--lines);
-}
-
-static struct xor_block_template xor_block_arm4regs = {
- name: "arm4regs",
- do_2: xor_arm4regs_2,
- do_3: xor_arm4regs_3,
- do_4: xor_arm4regs_4,
- do_5: xor_arm4regs_5,
-};
-
-#undef XOR_TRY_TEMPLATES
-#define XOR_TRY_TEMPLATES \
- do { \
- xor_speed(&xor_block_arm4regs); \
- xor_speed(&xor_block_8regs); \
- xor_speed(&xor_block_32regs); \
- } while (0)
--- /dev/null
+/*
+ *
+ * Hitachi Big Sur Eval Board support
+ *
+ * Dustin McIntire (dustin@sensoria.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Derived from Hitachi SH7751 reference manual
+ *
+ */
+
+#ifndef _ASM_BIGSUR_H_
+#define _ASM_BIGSUR_H_
+
+#include <asm/irq.h>
+#include <asm/hd64465.h>
+
+/* 7751 Internal IRQ's used by external CPLD controller */
+#define BIGSUR_IRQ_LOW 0
+#define BIGSUR_IRQ_NUM 14 /* External CPLD level 1 IRQs */
+#define BIGSUR_IRQ_HIGH (BIGSUR_IRQ_LOW + BIGSUR_IRQ_NUM)
+#define BIGSUR_2NDLVL_IRQ_LOW (HD64465_IRQ_BASE+HD64465_IRQ_NUM)
+#define BIGSUR_2NDLVL_IRQ_NUM 32 /* Level 2 IRQs = 4 regs * 8 bits */
+#define BIGSUR_2NDLVL_IRQ_HIGH (BIGSUR_2NDLVL_IRQ_LOW + \
+ BIGSUR_2NDLVL_IRQ_NUM)
+
+/* PCI interrupt base number (A_INTA-A_INTD) */
+#define BIGSUR_SH7751_PCI_IRQ_BASE (BIGSUR_2NDLVL_IRQ_LOW+10)
+
+/* CPLD registers and external chip addresses */
+#define BIGSUR_HD64464_ADDR 0xB2000000
+#define BIGSUR_DGDR 0xB1FFFE00
+#define BIGSUR_BIDR 0xB1FFFD00
+#define BIGSUR_CSLR 0xB1FFFC00
+#define BIGSUR_SW1R 0xB1FFFB00
+#define BIGSUR_DBGR 0xB1FFFA00
+#define BIGSUR_BDTR 0xB1FFF900
+#define BIGSUR_BDRR 0xB1FFF800
+#define BIGSUR_PPR1 0xB1FFF700
+#define BIGSUR_PPR2 0xB1FFF600
+#define BIGSUR_IDE2 0xB1FFF500
+#define BIGSUR_IDE3 0xB1FFF400
+#define BIGSUR_SPCR 0xB1FFF300
+#define BIGSUR_ETHR 0xB1FE0000
+#define BIGSUR_PPDR 0xB1FDFF00
+#define BIGSUR_ICTL 0xB1FDFE00
+#define BIGSUR_ICMD 0xB1FDFD00
+#define BIGSUR_DMA0 0xB1FDFC00
+#define BIGSUR_DMA1 0xB1FDFB00
+#define BIGSUR_IRQ0 0xB1FDFA00
+#define BIGSUR_IRQ1 0xB1FDF900
+#define BIGSUR_IRQ2 0xB1FDF800
+#define BIGSUR_IRQ3 0xB1FDF700
+#define BIGSUR_IMR0 0xB1FDF600
+#define BIGSUR_IMR1 0xB1FDF500
+#define BIGSUR_IMR2 0xB1FDF400
+#define BIGSUR_IMR3 0xB1FDF300
+#define BIGSUR_IRLMR0 0xB1FDF200
+#define BIGSUR_IRLMR1 0xB1FDF100
+#define BIGSUR_V320USC_ADDR 0xB1000000
+#define BIGSUR_HD64465_ADDR 0xB0000000
+#define BIGSUR_INTERNAL_BASE 0xB0000000
+
+/* SMC ethernet card parameters */
+#define BIGSUR_ETHER_IOPORT 0x220
+
+/* IDE register paramters */
+#define BIGSUR_IDECMD_IOPORT 0x1f0
+#define BIGSUR_IDECTL_IOPORT 0x1f8
+
+/* LED bit position in BIGSUR_CSLR */
+#define BIGSUR_LED (1<<4)
+
+/* PCI: default LOCAL memory window sizes (seen from PCI bus) */
+#define BIGSUR_LSR0_SIZE (64*(1<<20)) //64MB
+#define BIGSUR_LSR1_SIZE (64*(1<<20)) //64MB
+
+#endif /* _ASM_BIGSUR_H_ */
restore_flags(flags);
}
+static __inline__ void __set_bit(int nr, volatile void * addr)
+{
+ int mask;
+ volatile unsigned int *a = addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ *a |= mask;
+}
+
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
restore_flags(flags);
}
+static __inline__ void __clear_bit(int nr, volatile void * addr)
+{
+ int mask;
+ volatile unsigned int *a = addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ *a &= ~mask;
+}
+
static __inline__ void change_bit(int nr, volatile void * addr)
{
int mask;
restore_flags(flags);
}
+static __inline__ void __change_bit(int nr, volatile void * addr)
+{
+ int mask;
+ volatile unsigned int *a = addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ *a ^= mask;
+}
+
static __inline__ int test_and_set_bit(int nr, volatile void * addr)
{
int mask, retval;
return retval;
}
+static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a |= mask;
+
+ return retval;
+}
+
static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
{
int mask, retval;
return retval;
}
+static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a &= ~mask;
+
+ return retval;
+}
+
static __inline__ int test_and_change_bit(int nr, volatile void * addr)
{
int mask, retval;
return retval;
}
+static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a ^= mask;
+
+ return retval;
+}
static __inline__ int test_bit(int nr, const volatile void *addr)
{
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
#ifdef __LITTLE_ENDIAN__
#define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
break;
case CPU_SH7750:
*p++ = '4';
- printk("CPU: SH7750\n");
+ printk("CPU: SH7750/SH7751\n");
break;
case CPU_ST40STB1:
*p++ = '4';
--- /dev/null
+/* include/asm-sh/dc_sysasic.h
+ *
+ * Definitions for the Dreamcast System ASIC and related peripherals.
+ *
+ * Copyright (c) 2001 M. R. Brown <mrbrown@linuxdc.org>
+ *
+ * This file is part of the LinuxDC project (www.linuxdc.org)
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#include <asm/irq.h>
+
+/* Hardware events -
+
+ Each of these events correspond to a bit within the Event Mask Registers/
+ Event Status Registers. Because of the virtual IRQ numbering scheme, a
+ base offset must be used when calculating the virtual IRQ that each event
+ takes.
+*/
+
+#define HW_EVENT_IRQ_BASE OFFCHIP_IRQ_BASE /* 48 */
+
+/* IRQ 13 */
+#define HW_EVENT_VSYNC (HW_EVENT_IRQ_BASE + 5) /* VSync */
+#define HW_EVENT_MAPLE_DMA (HW_EVENT_IRQ_BASE + 12) /* Maple DMA complete */
+#define HW_EVENT_GDROM_DMA (HW_EVENT_IRQ_BASE + 14) /* GD-ROM DMA complete */
+
+/* IRQ 11 */
+#define HW_EVENT_GDROM_CMD (HW_EVENT_IRQ_BASE + 32) /* GD-ROM cmd. complete */
+#define HW_EVENT_AICA_SYS (HW_EVENT_IRQ_BASE + 33) /* AICA-related */
+#define HW_EVENT_EXTERNAL (HW_EVENT_IRQ_BASE + 35) /* Ext. (expansion) */
+
+#define HW_EVENT_IRQ_MAX (HW_EVENT_IRQ_BASE + 95)
/* entry.S is sensitive to the offsets of these fields */
typedef struct {
- unsigned int __softirq_active;
- unsigned int __softirq_mask;
+ unsigned int __softirq_pending;
unsigned int __local_irq_count;
unsigned int __local_bh_count;
unsigned int __syscall_count;
#ifndef _ASM_SH_HD64465_GPIO_
#define _ASM_SH_HD64465_GPIO_ 1
/*
- * $Id: hd64465_gpio.h,v 1.1 2001/01/02 15:35:22 mjd Exp $
+ * $Id: hd64465_gpio.h,v 1.2 2001/05/24 00:14:13 gniibe Exp $
*
* Hitachi HD64465 companion chip: General Purpose IO pins support.
* This layer enables other device drivers to configure GPIO
# if defined(CONFIG_SH_HP600)
# include <asm/io_hd64461.h>
-# elif defined(CONFIG_SH_7750_OVERDRIVE)
-# include <asm/io_od.h>
-# elif defined(CONFIG_SH_SOLUTION_ENGINE)
+# elif (defined(CONFIG_SH_SOLUTION_ENGINE) || defined(CONFIG_SH_7751_SOLUTION_ENGINE))
# include <asm/io_se.h>
+# elif defined(CONFIG_SH_SH2000)
+# include <asm/io_sh2000.h>
# elif defined(CONFIG_SH_DMIDA) || \
defined(CONFIG_SH_STB1_HARP) || \
defined(CONFIG_SH_STB1_OVERDRIVE)
# include <asm/io_dc.h>
# elif defined(CONFIG_SH_CAT68701)
# include <asm/io_cat68701.h>
+# elif defined(CONFIG_SH_BIGSUR)
+# include <asm/io_bigsur.h>
# elif defined(CONFIG_SH_UNKNOWN)
# include <asm/io_unknown.h>
# else
--- /dev/null
+/*
+ * include/asm-sh/io_bigsur.h
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+ * By Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc.
+ * and from io_hd64461.h, which bore the message:
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * IO functions for a Hitachi Big Sur Evaluation Board.
+ */
+
+#ifndef _ASM_SH_IO_BIGSUR_H
+#define _ASM_SH_IO_BIGSUR_H
+
+#include <linux/types.h>
+#include <asm/io_generic.h>
+
+extern unsigned char bigsur_inb(unsigned long port);
+extern unsigned short bigsur_inw(unsigned long port);
+extern unsigned int bigsur_inl(unsigned long port);
+
+extern void bigsur_outb(unsigned char value, unsigned long port);
+extern void bigsur_outw(unsigned short value, unsigned long port);
+extern void bigsur_outl(unsigned int value, unsigned long port);
+
+extern unsigned char bigsur_inb_p(unsigned long port);
+extern void bigsur_outb_p(unsigned char value, unsigned long port);
+
+extern void bigsur_insb(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_insw(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_insl(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void bigsur_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void bigsur_outsl(unsigned long port, const void *addr, unsigned long count);
+extern unsigned long bigsur_isa_port2addr(unsigned long offset);
+extern int bigsur_irq_demux(int irq);
+extern void bigsur_init_pci(void);
+/* Provision for generic secondary demux step -- used by PCMCIA code */
+extern void bigsur_register_irq_demux(int irq,
+ int (*demux)(int irq, void *dev), void *dev);
+extern void bigsur_unregister_irq_demux(int irq);
+/* Set this variable to 1 to see port traffic */
+extern int bigsur_io_debug;
+/* Map a range of ports to a range of kernel virtual memory. */
+extern void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift);
+extern void bigsur_port_unmap(u32 baseport, u32 nports);
+
+#endif /* _ASM_SH_IO_BIGSUR_H */
+
+#ifdef __WANT_IO_DEF
+
+# define __inb bigsur_inb
+# define __inw bigsur_inw
+# define __inl bigsur_inl
+# define __outb bigsur_outb
+# define __outw bigsur_outw
+# define __outl bigsur_outl
+
+# define __inb_p bigsur_inb_p
+# define __inw_p bigsur_inw
+# define __inl_p bigsur_inl
+# define __outb_p bigsur_outb_p
+# define __outw_p bigsur_outw
+# define __outl_p bigsur_outl
+
+# define __insb bigsur_insb
+# define __insw bigsur_insw
+# define __insl bigsur_insl
+# define __outsb bigsur_outsb
+# define __outsw bigsur_outsw
+# define __outsl bigsur_outsl
+
+# define __readb generic_readb
+# define __readw generic_readw
+# define __readl generic_readl
+# define __writeb generic_writeb
+# define __writew generic_writew
+# define __writel generic_writel
+
+# define __isa_port2addr bigsur_isa_port2addr
+# define __ioremap generic_ioremap
+# define __iounmap generic_iounmap
+
+#endif
+++ /dev/null
-/*
- * include/asm-sh/io_od.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * IO functions for an STMicroelectronics Overdrive
- */
-
-#ifndef _ASM_SH_IO_OD_H
-#define _ASM_SH_IO_OD_H
-
-#include <asm/io_generic.h>
-
-extern unsigned char od_inb(unsigned long port);
-extern unsigned short od_inw(unsigned long port);
-extern unsigned int od_inl(unsigned long port);
-
-extern void od_outb(unsigned char value, unsigned long port);
-extern void od_outw(unsigned short value, unsigned long port);
-extern void od_outl(unsigned int value, unsigned long port);
-
-extern unsigned char od_inb_p(unsigned long port);
-extern unsigned short od_inw_p(unsigned long port);
-extern unsigned int od_inl_p(unsigned long port);
-extern void od_outb_p(unsigned char value, unsigned long port);
-extern void od_outw_p(unsigned short value, unsigned long port);
-extern void od_outl_p(unsigned int value, unsigned long port);
-
-extern void od_insb(unsigned long port, void *addr, unsigned long count);
-extern void od_insw(unsigned long port, void *addr, unsigned long count);
-extern void od_insl(unsigned long port, void *addr, unsigned long count);
-extern void od_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void od_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void od_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned long od_isa_port2addr(unsigned long offset);
-
-#ifdef __WANT_IO_DEF
-
-# define __inb od_inb
-# define __inw od_inw
-# define __inl od_inl
-# define __outb od_outb
-# define __outw od_outw
-# define __outl od_outl
-
-# define __inb_p od_inb_p
-# define __inw_p od_inw_p
-# define __inl_p od_inl_p
-# define __outb_p od_outb_p
-# define __outw_p od_outw_p
-# define __outl_p od_outl_p
-
-# define __insb od_insb
-# define __insw od_insw
-# define __insl od_insl
-# define __outsb od_outsb
-# define __outsw od_outsw
-# define __outsl od_outsl
-
-# define __readb generic_readb
-# define __readw generic_readw
-# define __readl generic_readl
-# define __writeb generic_writeb
-# define __writew generic_writew
-# define __writel generic_writel
-
-# define __isa_port2addr od_isa_port2addr
-# define __ioremap generic_ioremap
-# define __iounmap generic_iounmap
-
-#endif
-
-#endif /* _ASM_SH_IO_OD_H */
--- /dev/null
+/*
+ * include/asm-sh/io_sh2000.h
+ *
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ * 2001 SUGIOKA Toshinobu (sugioka@itonet.co.jp)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * IO functions for use when we don't know what machine we are on
+ */
+
+#ifndef _ASM_SH_IO_SH2000_H
+#define _ASM_SH_IO_SH2000_H
+
+#include <asm/io_generic.h>
+
+unsigned long sh2000_isa_port2addr(unsigned long offset);
+
+#ifdef __WANT_IO_DEF
+
+# define __inb generic_inb
+# define __inw generic_inw
+# define __inl generic_inl
+# define __outb generic_outb
+# define __outw generic_outw
+# define __outl generic_outl
+
+# define __inb_p generic_inb_p
+# define __inw_p generic_inw
+# define __inl_p generic_inl
+# define __outb_p generic_outb_p
+# define __outw_p generic_outw
+# define __outl_p generic_outl
+
+# define __insb generic_insb
+# define __insw generic_insw
+# define __insl generic_insl
+# define __outsb generic_outsb
+# define __outsw generic_outsw
+# define __outsl generic_outsl
+
+# define __readb generic_readb
+# define __readw generic_readw
+# define __readl generic_readl
+# define __writeb generic_writeb
+# define __writew generic_writew
+# define __writel generic_writel
+
+# define __isa_port2addr sh2000_isa_port2addr
+# define __ioremap generic_ioremap
+# define __iounmap generic_iounmap
+
+#endif
+
+#endif /* _ASM_SH_IO_SH2000_H */
#define DMA_PRIORITY 7
#if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \
- defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750)
+ defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined (CONFIG_CPU_SUBTYPE_SH7751)
#define SCI_ERI_IRQ 23
#define SCI_RXI_IRQ 24
#define SCI_TXI_IRQ 25
#define IRDA_IPR_ADDR INTC_IPRE
#define IRDA_IPR_POS 2
#define IRDA_PRIORITY 3
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_ST40STB1)
#define SCIF_ERI_IRQ 40
#define SCIF_RXI_IRQ 41
#define SCIF_BRI_IRQ 42
/* 1. ONCHIP_NR_IRQS */
#ifdef CONFIG_SH_GENERIC
-# define ONCHIP_NR_IRQS 89
+# define ONCHIP_NR_IRQS 144
#else
# if defined(CONFIG_CPU_SUBTYPE_SH7707)
# define ONCHIP_NR_IRQS 64
# define PINT_NR_IRQS 16
# elif defined(CONFIG_CPU_SUBTYPE_SH7750)
# define ONCHIP_NR_IRQS 48 // Actually 44
+# elif defined(CONFIG_CPU_SUBTYPE_SH7751)
+# define ONCHIP_NR_IRQS 72
# elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
-# define ONCHIP_NR_IRQS 89
+# define ONCHIP_NR_IRQS 144
# endif
#endif
#else
# if defined(CONFIG_HD64461)
# define OFFCHIP_NR_IRQS 16
+# elif defined (CONFIG_SH_BIGSUR) /* must be before CONFIG_HD64465 */
+# define OFFCHIP_NR_IRQS 48
# elif defined(CONFIG_HD64465)
# define OFFCHIP_NR_IRQS 16
# elif defined (CONFIG_SH_EC3104)
# define OFFCHIP_NR_IRQS 16
+# elif defined (CONFIG_SH_DREAMCAST)
+# define OFFCHIP_NR_IRQS 96
# else
# define OFFCHIP_NR_IRQS 0
# endif
#define __irq_demux(irq) irq
#endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+#define INTC_ICR 0xffd00000
+#define INTC_ICR_NMIL (1<<15)
+#define INTC_ICR_MAI (1<<14)
+#define INTC_ICR_NMIB (1<<9)
+#define INTC_ICR_NMIE (1<<8)
+#define INTC_ICR_IRLM (1<<7)
+#endif
+
#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
#define INTC2_FIRST_IRQ 64
#define NR_INTC2_IRQS 25
return __irq_demux(irq);
}
+#elif defined(CONFIG_SH_BIGSUR)
+
+extern int bigsur_irq_demux(int irq);
+#define irq_demux(irq) bigsur_irq_demux(irq)
+
#elif defined(CONFIG_HD64461)
extern int hd64461_irq_demux(int irq);
extern int cat68701_irq_demux(int irq);
#define irq_demux cat68701_irq_demux
+#elif defined(CONFIG_SH_DREAMCAST)
+
+extern int systemasic_irq_demux(int irq);
+#define irq_demux systemasic_irq_demux
+
#else
#define irq_demux(irq) __irq_demux(irq)
unsigned int mv_hw_hp680 : 1;
unsigned int mv_hw_hp690 : 1;
unsigned int mv_hw_hd64461 : 1;
+ unsigned int mv_hw_sh2000 : 1;
unsigned int mv_hw_hd64465 : 1;
unsigned int mv_hw_dreamcast : 1;
+ unsigned int mv_hw_bigsur : 1;
};
extern struct sh_machine_vector sh_mv;
#define MACH_HP690 (sh_mv.mv_hw_hp690)
#define MACH_HD64461 (sh_mv.mv_hw_hd64461)
#define MACH_HD64465 (sh_mv.mv_hw_hd64465)
+#define MACH_SH2000 (sh_mv.mv_hw_sh2000)
#define MACH_DREAMCAST (sh_mv.mv_hw_dreamcast)
+#define MACH_BIGSUR (sh_mv.mv_hw_bigsur)
#else
-# ifdef CONFIG_SH_SOLUTION_ENGINE
+# if defined(CONFIG_SH_SOLUTION_ENGINE) || \
+ defined(CONFIG_SH_7751_SOLUTION_ENGINE)
# define MACH_SE 1
# else
# define MACH_SE 0
# else
# define MACH_HP690 0
# endif
+# endif
# ifdef CONFIG_HD64461
# define MACH_HD64461 1
# else
# else
# define MACH_HD64465 0
# endif
+# ifdef CONFIG_SH_SH2000
+# define MACH_SH2000 1
+# else
+# define MACH_SH2000 0
+# endif
# ifdef CONFIG_SH_EC3104
# define MACH_EC3104 1
# else
# else
# define MACH_DREAMCAST 0
# endif
+# ifdef CONFIG_SH_BIGSUR
+# define MACH_BIGSUR 1
+# else
+# define MACH_BIGSUR 0
#endif
#endif /* _ASM_SH_MACHVEC_H */
--- /dev/null
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+#include <asm/rtc.h>
+
+#define RTC_ALWAYS_BCD 1
+
+/* FIXME:RTC Interrupt feature is not implemented yet. */
+#undef RTC_IRQ
+#define RTC_IRQ 0
+
+#if defined(__sh3__)
+#define RTC_PORT(n) (R64CNT+(n)*2)
+#define CMOS_READ(addr) __CMOS_READ(addr,b)
+#define CMOS_WRITE(val,addr) __CMOS_WRITE(val,addr,b)
+
+#elif defined(__SH4__)
+#define RTC_PORT(n) (R64CNT+(n)*4)
+#define CMOS_READ(addr) __CMOS_READ(addr,w)
+#define CMOS_WRITE(val,addr) __CMOS_WRITE(val,addr,w)
+#endif
+
+#define __CMOS_READ(addr, s) ({ \
+ unsigned char val=0, rcr1, rcr2, r64cnt, retry; \
+ switch(addr) { \
+ case RTC_SECONDS: \
+ val = ctrl_inb(RSECCNT); \
+ break; \
+ case RTC_SECONDS_ALARM: \
+ val = ctrl_inb(RSECAR); \
+ break; \
+ case RTC_MINUTES: \
+ val = ctrl_inb(RMINCNT); \
+ break; \
+ case RTC_MINUTES_ALARM: \
+ val = ctrl_inb(RMINAR); \
+ break; \
+ case RTC_HOURS: \
+ val = ctrl_inb(RHRCNT); \
+ break; \
+ case RTC_HOURS_ALARM: \
+ val = ctrl_inb(RHRAR); \
+ break; \
+ case RTC_DAY_OF_WEEK: \
+ val = ctrl_inb(RWKCNT); \
+ break; \
+ case RTC_DAY_OF_MONTH: \
+ val = ctrl_inb(RDAYCNT); \
+ break; \
+ case RTC_MONTH: \
+ val = ctrl_inb(RMONCNT); \
+ break; \
+ case RTC_YEAR: \
+ val = ctrl_in##s(RYRCNT); \
+ break; \
+ case RTC_REG_A: /* RTC_FREQ_SELECT */ \
+ rcr2 = ctrl_inb(RCR2); \
+ val = (rcr2 & RCR2_PESMASK) >> 4; \
+ rcr1 = ctrl_inb(RCR1); \
+ rcr1 = (rcr1 & (RCR1_CIE | RCR1_AIE)) | RCR1_AF;\
+ retry = 0; \
+ do { \
+ ctrl_outb(rcr1, RCR1); /* clear CF */ \
+ r64cnt = ctrl_inb(R64CNT); \
+ } while((ctrl_inb(RCR1) & RCR1_CF) && retry++ < 1000);\
+ r64cnt ^= RTC_BIT_INVERTED; \
+ if(r64cnt == 0x7f || r64cnt == 0) \
+ val |= RTC_UIP; \
+ break; \
+ case RTC_REG_B: /* RTC_CONTROL */ \
+ rcr1 = ctrl_inb(RCR1); \
+ rcr2 = ctrl_inb(RCR2); \
+ if(rcr1 & RCR1_CIE) val |= RTC_UIE; \
+ if(rcr1 & RCR1_AIE) val |= RTC_AIE; \
+ if(rcr2 & RCR2_PESMASK) val |= RTC_PIE; \
+ if(!(rcr2 & RCR2_START))val |= RTC_SET; \
+ val |= RTC_24H; \
+ break; \
+ case RTC_REG_C: /* RTC_INTR_FLAGS */ \
+ rcr1 = ctrl_inb(RCR1); \
+ rcr1 &= ~(RCR1_CF | RCR1_AF); \
+ ctrl_outb(rcr1, RCR1); \
+ rcr2 = ctrl_inb(RCR2); \
+ rcr2 &= ~RCR2_PEF; \
+ ctrl_outb(rcr2, RCR2); \
+ break; \
+ case RTC_REG_D: /* RTC_VALID */ \
+ /* Always valid ... */ \
+ val = RTC_VRT; \
+ break; \
+ default: \
+ break; \
+ } \
+ val; \
+})
+
+#define __CMOS_WRITE(val, addr, s) ({ \
+ unsigned char rcr1,rcr2; \
+ switch(addr) { \
+ case RTC_SECONDS: \
+ ctrl_outb(val, RSECCNT); \
+ break; \
+ case RTC_SECONDS_ALARM: \
+ ctrl_outb(val, RSECAR); \
+ break; \
+ case RTC_MINUTES: \
+ ctrl_outb(val, RMINCNT); \
+ break; \
+ case RTC_MINUTES_ALARM: \
+ ctrl_outb(val, RMINAR); \
+ break; \
+ case RTC_HOURS: \
+ ctrl_outb(val, RHRCNT); \
+ break; \
+ case RTC_HOURS_ALARM: \
+ ctrl_outb(val, RHRAR); \
+ break; \
+ case RTC_DAY_OF_WEEK: \
+ ctrl_outb(val, RWKCNT); \
+ break; \
+ case RTC_DAY_OF_MONTH: \
+ ctrl_outb(val, RDAYCNT); \
+ break; \
+ case RTC_MONTH: \
+ ctrl_outb(val, RMONCNT); \
+ break; \
+ case RTC_YEAR: \
+ ctrl_out##s((ctrl_in##s(RYRCNT) & 0xff00) | (val & 0xff), RYRCNT);\
+ break; \
+ case RTC_REG_A: /* RTC_FREQ_SELECT */ \
+ rcr2 = ctrl_inb(RCR2); \
+ if((val & RTC_DIV_CTL) == RTC_DIV_RESET2) \
+ rcr2 |= RCR2_RESET; \
+ ctrl_outb(rcr2, RCR2); \
+ break; \
+ case RTC_REG_B: /* RTC_CONTROL */ \
+ rcr1 = (ctrl_inb(RCR1) & 0x99) | RCR1_AF; \
+ if(val & RTC_AIE) rcr1 |= RCR1_AIE; \
+ else rcr1 &= ~RCR1_AIE; \
+ if(val & RTC_UIE) rcr1 |= RCR1_CIE; \
+ else rcr1 &= ~RCR1_CIE; \
+ ctrl_outb(rcr1, RCR1); \
+ rcr2 = ctrl_inb(RCR2); \
+ if(val & RTC_SET) rcr2 &= ~RCR2_START; \
+ else rcr2 |= RCR2_START; \
+ ctrl_outb(rcr2, RCR2); \
+ break; \
+ case RTC_REG_C: /* RTC_INTR_FLAGS */ \
+ break; \
+ case RTC_REG_D: /* RTC_VALID */ \
+ break; \
+ default: \
+ break; \
+ } \
+})
+#endif /* _ASM_MC146818RTC_H */
--- /dev/null
+/*
+ * Low-Level PCI Support for SH7751 targets
+ *
+ * Dustin McIntire (dustin@sensoria.com) (c) 2001
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ */
+
+#ifndef _PCI_SH7751_H_
+#define _PCI_SH7751_H_
+
+#include <linux/pci.h>
+
+/* set debug level 4=verbose...1=terse */
+//#define DEBUG_PCI 3
+#undef DEBUG_PCI
+
+#ifdef DEBUG_PCI
+#define PCIDBG(n, x...) { if(DEBUG_PCI>=n) printk(x); }
+#else
+#define PCIDBG(n, x...)
+#endif
+
+/* startup values */
+#define PCI_PROBE_BIOS 1
+#define PCI_PROBE_CONF1 2
+#define PCI_PROBE_CONF2 4
+#define PCI_NO_SORT 0x100
+#define PCI_BIOS_SORT 0x200
+#define PCI_NO_CHECKS 0x400
+#define PCI_ASSIGN_ROMS 0x1000
+#define PCI_BIOS_IRQ_SCAN 0x2000
+
+/* Platform Specific Values */
+#define SH7751_VENDOR_ID 0x1054
+#define SH7751_DEVICE_ID 0x3505
+
+/* SH7751 Specific Values */
+#define SH7751_PCI_CONFIG_BASE 0xFD000000 /* Config space base addr */
+#define SH7751_PCI_CONFIG_SIZE 0x1000000 /* Config space size */
+#define SH7751_PCI_MEMORY_BASE 0xFD000000 /* Memory space base addr */
+#define SH7751_PCI_MEM_SIZE 0x01000000 /* Size of Memory window */
+#define SH7751_PCI_IO_BASE 0xFE240000 /* IO space base address */
+#define SH7751_PCI_IO_SIZE 0x40000 /* Size of IO window */
+
+#define SH7751_PCIREG_BASE 0xFE200000 /* PCI regs base address */
+#define PCI_REG(n) (SH7751_PCIREG_BASE+ n)
+
+#define SH7751_PCICONF0 0x0 /* PCI Config Reg 0 */
+ #define SH7751_PCICONF0_DEVID 0xFFFF0000 /* Device ID */
+ #define SH7751_PCICONF0_VNDID 0x0000FFFF /* Vendor ID */
+#define SH7751_PCICONF1 0x4 /* PCI Config Reg 1 */
+ #define SH7751_PCICONF1_DPE 0x80000000 /* Data Parity Error */
+ #define SH7751_PCICONF1_SSE 0x40000000 /* System Error Status */
+ #define SH7751_PCICONF1_RMA 0x20000000 /* Master Abort */
+ #define SH7751_PCICONF1_RTA 0x10000000 /* Target Abort Rx Status */
+ #define SH7751_PCICONF1_STA 0x08000000 /* Target Abort Exec Status */
+ #define SH7751_PCICONF1_DEV 0x06000000 /* Timing Status */
+ #define SH7751_PCICONF1_DPD 0x01000000 /* Data Parity Status */
+ #define SH7751_PCICONF1_FBBC 0x00800000 /* Back 2 Back Status */
+ #define SH7751_PCICONF1_UDF 0x00400000 /* User Defined Status */
+ #define SH7751_PCICONF1_66M 0x00200000 /* 66Mhz Operation Status */
+ #define SH7751_PCICONF1_PM 0x00100000 /* Power Management Status */
+ #define SH7751_PCICONF1_PBBE 0x00000200 /* Back 2 Back Control */
+ #define SH7751_PCICONF1_SER 0x00000100 /* SERR Output Control */
+ #define SH7751_PCICONF1_WCC 0x00000080 /* Wait Cycle Control */
+ #define SH7751_PCICONF1_PER 0x00000040 /* Parity Error Response */
+ #define SH7751_PCICONF1_VPS 0x00000020 /* VGA Pallet Snoop */
+ #define SH7751_PCICONF1_MWIE 0x00000010 /* Memory Write+Invalidate */
+ #define SH7751_PCICONF1_SPC 0x00000008 /* Special Cycle Control */
+ #define SH7751_PCICONF1_BUM 0x00000004 /* Bus Master Control */
+ #define SH7751_PCICONF1_MES 0x00000002 /* Memory Space Control */
+ #define SH7751_PCICONF1_IOS 0x00000001 /* I/O Space Control */
+#define SH7751_PCICONF2 0x8 /* PCI Config Reg 2 */
+ #define SH7751_PCICONF2_BCC 0xFF000000 /* Base Class Code */
+ #define SH7751_PCICONF2_SCC 0x00FF0000 /* Sub-Class Code */
+ #define SH7751_PCICONF2_RLPI 0x0000FF00 /* Programming Interface */
+ #define SH7751_PCICONF2_REV 0x000000FF /* Revision ID */
+#define SH7751_PCICONF3 0xC /* PCI Config Reg 3 */
+ #define SH7751_PCICONF3_BIST7 0x80000000 /* Bist Supported */
+ #define SH7751_PCICONF3_BIST6 0x40000000 /* Bist Executing */
+ #define SH7751_PCICONF3_BIST3_0 0x0F000000 /* Bist Passed */
+ #define SH7751_PCICONF3_HD7 0x00800000 /* Single Funtion device */
+ #define SH7751_PCICONF3_HD6_0 0x007F0000 /* Configuration Layout */
+ #define SH7751_PCICONF3_LAT 0x0000FF00 /* Latency Timer */
+ #define SH7751_PCICONF3_CLS 0x000000FF /* Cache Line Size */
+#define SH7751_PCICONF4 0x10 /* PCI Config Reg 4 */
+ #define SH7751_PCICONF4_BASE 0xFFFFFFFC /* I/O Space Base Addr */
+ #define SH7751_PCICONF4_ASI 0x00000001 /* Address Space Type */
+#define SH7751_PCICONF5 0x14 /* PCI Config Reg 5 */
+ #define SH7751_PCICONF5_BASE 0xFFFFFFF0 /* Mem Space Base Addr */
+ #define SH7751_PCICONF5_LAP 0x00000008 /* Prefetch Enabled */
+ #define SH7751_PCICONF5_LAT 0x00000006 /* Local Memory type */
+ #define SH7751_PCICONF5_ASI 0x00000001 /* Address Space Type */
+#define SH7751_PCICONF6 0x18 /* PCI Config Reg 6 */
+ #define SH7751_PCICONF6_BASE 0xFFFFFFF0 /* Mem Space Base Addr */
+ #define SH7751_PCICONF6_LAP 0x00000008 /* Prefetch Enabled */
+ #define SH7751_PCICONF6_LAT 0x00000006 /* Local Memory type */
+ #define SH7751_PCICONF6_ASI 0x00000001 /* Address Space Type */
+/* PCICONF7 - PCICONF10 are undefined */
+#define SH7751_PCICONF11 0x2C /* PCI Config Reg 11 */
+ #define SH7751_PCICONF11_SSID 0xFFFF0000 /* Subsystem ID */
+ #define SH7751_PCICONF11_SVID 0x0000FFFF /* Subsystem Vendor ID */
+/* PCICONF12 is undefined */
+#define SH7751_PCICONF13 0x34 /* PCI Config Reg 13 */
+ #define SH7751_PCICONF13_CPTR 0x000000FF /* PM function pointer */
+/* PCICONF14 is undefined */
+#define SH7751_PCICONF15 0x3C /* PCI Config Reg 15 */
+ #define SH7751_PCICONF15_IPIN 0x000000FF /* Interrupt Pin */
+#define SH7751_PCICONF16 0x40 /* PCI Config Reg 16 */
+ #define SH7751_PCICONF16_PMES 0xF8000000 /* PME Support */
+ #define SH7751_PCICONF16_D2S 0x04000000 /* D2 Support */
+ #define SH7751_PCICONF16_D1S 0x02000000 /* D1 Support */
+ #define SH7751_PCICONF16_DSI 0x00200000 /* Bit Device Init. */
+ #define SH7751_PCICONF16_PMCK 0x00080000 /* Clock for PME req. */
+ #define SH7751_PCICONF16_VER 0x00070000 /* PM Version */
+ #define SH7751_PCICONF16_NIP 0x0000FF00 /* Next Item Pointer */
+ #define SH7751_PCICONF16_CID 0x000000FF /* Capability Identifier */
+#define SH7751_PCICONF17 0x44 /* PCI Config Reg 17 */
+ #define SH7751_PCICONF17_DATA 0xFF000000 /* Data field for PM */
+ #define SH7751_PCICONF17_PMES 0x00800000 /* PME Status */
+ #define SH7751_PCICONF17_DSCL 0x00600000 /* Data Scaling Value */
+ #define SH7751_PCICONF17_DSEL 0x001E0000 /* Data Select */
+ #define SH7751_PCICONF17_PMEN 0x00010000 /* PME Enable */
+ #define SH7751_PCICONF17_PWST 0x00000003 /* Power State */
+/* SH7715 Internal PCI Registers */
+#define SH7751_PCICR 0x100 /* PCI Control Register */
+ #define SH7751_PCICR_PREFIX 0xA5000000 /* CR prefix for write */
+ #define SH7751_PCICR_TRSB 0x00000200 /* Target Read Single */
+ #define SH7751_PCICR_BSWP 0x00000100 /* Target Byte Swap */
+ #define SH7751_PCICR_PLUP 0x00000080 /* Enable PCI Pullup */
+ #define SH7751_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */
+ #define SH7751_PCICR_MD 0x00000030 /* MD9 and MD10 status */
+ #define SH7751_PCICR_SERR 0x00000008 /* SERR output assert */
+ #define SH7751_PCICR_INTA 0x00000004 /* INTA output assert */
+ #define SH7751_PCICR_PRST 0x00000002 /* PCI Reset Assert */
+ #define SH7751_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */
+#define SH7751_PCILSR0 0x104 /* PCI Local Space Register0 */
+#define SH7751_PCILSR1 0x108 /* PCI Local Space Register1 */
+#define SH7751_PCILAR0 0x10C /* PCI Local Address Register1 */
+#define SH7751_PCILAR1 0x110 /* PCI Local Address Register1 */
+#define SH7751_PCIINT 0x114 /* PCI Interrupt Register */
+ #define SH7751_PCIINT_MLCK 0x00008000 /* Master Lock Error */
+ #define SH7751_PCIINT_TABT 0x00004000 /* Target Abort Error */
+ #define SH7751_PCIINT_TRET 0x00000200 /* Target Retry Error */
+ #define SH7751_PCIINT_MFDE 0x00000100 /* Master Func. Disable Error */
+ #define SH7751_PCIINT_PRTY 0x00000080 /* Address Parity Error */
+ #define SH7751_PCIINT_SERR 0x00000040 /* SERR Detection Error */
+ #define SH7751_PCIINT_TWDP 0x00000020 /* Tgt. Write Parity Error */
+ #define SH7751_PCIINT_TRDP 0x00000010 /* Tgt. Read Parity Error Det. */
+ #define SH7751_PCIINT_MTABT 0x00000008 /* Master-Tgt. Abort Error */
+ #define SH7751_PCIINT_MMABT 0x00000004 /* Master-Master Abort Error */
+ #define SH7751_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */
+ #define SH7751_PCIINT_MRPD 0x00000002 /* Master Read PERR Detect */
+#define SH7751_PCIINTM 0x118 /* PCI Interrupt Mask Register */
+#define SH7751_PCIALR 0x11C /* Error Address Register */
+#define SH7751_PCICLR 0x120 /* Error Command/Data Register */
+ #define SH7751_PCICLR_MPIO 0x80000000 /* Error Command/Data Register */
+ #define SH7751_PCICLR_MDMA0 0x40000000 /* DMA0 Transfer Error */
+ #define SH7751_PCICLR_MDMA1 0x20000000 /* DMA1 Transfer Error */
+ #define SH7751_PCICLR_MDMA2 0x10000000 /* DMA2 Transfer Error */
+ #define SH7751_PCICLR_MDMA3 0x08000000 /* DMA3 Transfer Error */
+ #define SH7751_PCICLR_TGT 0x04000000 /* Target Transfer Error */
+ #define SH7751_PCICLR_CMDL 0x0000000F /* PCI Command at Error */
+#define SH7751_PCIAINT 0x130 /* Arbiter Interrupt Register */
+ #define SH7751_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */
+ #define SH7751_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */
+ #define SH7751_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */
+ #define SH7751_PCIAINT_TABT 0x00000008 /* Target Abort */
+ #define SH7751_PCIAINT_MABT 0x00000004 /* Master Abort */
+ #define SH7751_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */
+ #define SH7751_PCIAINT_WDPE 0x00000002 /* Write Data Parity Error */
+#define SH7751_PCIAINTM 0x134 /* Arbiter Int. Mask Register */
+#define SH7751_PCIBMLR 0x138 /* Error Bus Master Register */
+ #define SH7751_PCIBMLR_REQ4 0x00000010 /* REQ4 bus master at error */
+ #define SH7751_PCIBMLR_REQ3 0x00000008 /* REQ3 bus master at error */
+ #define SH7751_PCIBMLR_REQ2 0x00000004 /* REQ2 bus master at error */
+ #define SH7751_PCIBMLR_REQ1 0x00000002 /* REQ1 bus master at error */
+ #define SH7751_PCIBMLR_REQ0 0x00000001 /* REQ0 bus master at error */
+#define SH7751_PCIDMABT 0x140 /* DMA Transfer Arb. Register */
+ #define SH7751_PCIDMABT_RRBN 0x00000001 /* DMA Arbitor Round-Robin */
+#define SH7751_PCIDPA0 0x180 /* DMA0 Transfer Addr. Register */
+#define SH7751_PCIDLA0 0x184 /* DMA0 Local Addr. Register */
+#define SH7751_PCIDTC0 0x188 /* DMA0 Transfer Cnt. Register */
+#define SH7751_PCIDCR0 0x18C /* DMA0 Control Register */
+ #define SH7751_PCIDCR_ALGN 0x00000600 /* DMA Alignment Mode */
+ #define SH7751_PCIDCR_MAST 0x00000100 /* DMA Termination Type */
+ #define SH7751_PCIDCR_INTM 0x00000080 /* DMA Interrupt Done Mask*/
+ #define SH7751_PCIDCR_INTS 0x00000040 /* DMA Interrupt Done Status */
+ #define SH7751_PCIDCR_LHLD 0x00000020 /* Local Address Control */
+ #define SH7751_PCIDCR_PHLD 0x00000010 /* PCI Address Control*/
+ #define SH7751_PCIDCR_IOSEL 0x00000008 /* PCI Address Space Type */
+ #define SH7751_PCIDCR_DIR 0x00000004 /* DMA Transfer Direction */
+ #define SH7751_PCIDCR_STOP 0x00000002 /* Force DMA Stop */
+ #define SH7751_PCIDCR_STRT 0x00000001 /* DMA Start */
+#define SH7751_PCIDPA1 0x190 /* DMA1 Transfer Addr. Register */
+#define SH7751_PCIDLA1 0x194 /* DMA1 Local Addr. Register */
+#define SH7751_PCIDTC1 0x198 /* DMA1 Transfer Cnt. Register */
+#define SH7751_PCIDCR1 0x19C /* DMA1 Control Register */
+#define SH7751_PCIDPA2 0x1A0 /* DMA2 Transfer Addr. Register */
+#define SH7751_PCIDLA2 0x1A4 /* DMA2 Local Addr. Register */
+#define SH7751_PCIDTC2 0x1A8 /* DMA2 Transfer Cnt. Register */
+#define SH7751_PCIDCR2 0x1AC /* DMA2 Control Register */
+#define SH7751_PCIDPA3 0x1B0 /* DMA3 Transfer Addr. Register */
+#define SH7751_PCIDLA3 0x1B4 /* DMA3 Local Addr. Register */
+#define SH7751_PCIDTC3 0x1B8 /* DMA3 Transfer Cnt. Register */
+#define SH7751_PCIDCR3 0x1BC /* DMA3 Control Register */
+#define SH7751_PCIPAR 0x1C0 /* PIO Address Register */
+ #define SH7751_PCIPAR_CFGEN 0x80000000 /* Configuration Enable */
+ #define SH7751_PCIPAR_BUSNO 0x00FF0000 /* Config. Bus Number */
+ #define SH7751_PCIPAR_DEVNO 0x0000FF00 /* Config. Device Number */
+ #define SH7751_PCIPAR_REGAD 0x000000FC /* Register Address Number */
+#define SH7751_PCIMBR 0x1C4 /* Memory Base Address Register */
+ #define SH7751_PCIMBR_MASK 0xFF000000 /* Memory Space Mask */
+ #define SH7751_PCIMBR_LOCK 0x00000001 /* Lock Memory Space */
+#define SH7751_PCIIOBR 0x1C8 /* I/O Base Address Register */
+ #define SH7751_PCIIOBR_MASK 0xFFFC0000 /* IO Space Mask */
+ #define SH7751_PCIIOBR_LOCK 0x00000001 /* Lock IO Space */
+#define SH7751_PCIPINT 0x1CC /* Power Mgmnt Int. Register */
+ #define SH7751_PCIPINT_D3 0x00000002 /* D3 Pwr Mgmt. Interrupt */
+ #define SH7751_PCIPINT_D0 0x00000001 /* D0 Pwr Mgmt. Interrupt */
+#define SH7751_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */
+#define SH7751_PCICLKR 0x1D4 /* Clock Ctrl. Register */
+ #define SH7751_PCICLKR_PCSTP 0x00000002 /* PCI Clock Stop */
+ #define SH7751_PCICLKR_BCSTP 0x00000002 /* BCLK Clock Stop */
+/* For definitions of BCR, MCR see ... */
+#define SH7751_PCIBCR1 0x1E0 /* Memory BCR1 Register */
+#define SH7751_PCIBCR2 0x1E4 /* Memory BCR2 Register */
+#define SH7751_PCIWCR1 0x1E8 /* Wait Control 1 Register */
+#define SH7751_PCIWCR2 0x1EC /* Wait Control 2 Register */
+#define SH7751_PCIWCR3 0x1F0 /* Wait Control 3 Register */
+#define SH7751_PCIMCR 0x1F4 /* Memory Control Register */
+#define SH7751_PCIPCTR 0x200 /* Port Control Register */
+ #define SH7751_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */
+ #define SH7751_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */
+ #define SH7751_PCIPCTR_P0EN 0x000100000 /* Port 0 Enable */
+ #define SH7751_PCIPCTR_P2UP 0x000000020 /* Port2 Pull Up Enable */
+ #define SH7751_PCIPCTR_P2IO 0x000000010 /* Port2 Output Enable */
+ #define SH7751_PCIPCTR_P1UP 0x000000008 /* Port1 Pull Up Enable */
+ #define SH7751_PCIPCTR_P1IO 0x000000004 /* Port1 Output Enable */
+ #define SH7751_PCIPCTR_P0UP 0x000000002 /* Port0 Pull Up Enable */
+ #define SH7751_PCIPCTR_P0IO 0x000000001 /* Port0 Output Enable */
+#define SH7751_PCIPDTR 0x204 /* Port Data Register */
+ #define SH7751_PCIPDTR_PB5 0x000000020 /* Port 5 Enable */
+ #define SH7751_PCIPDTR_PB4 0x000000010 /* Port 4 Enable */
+ #define SH7751_PCIPDTR_PB3 0x000000008 /* Port 3 Enable */
+ #define SH7751_PCIPDTR_PB2 0x000000004 /* Port 2 Enable */
+ #define SH7751_PCIPDTR_PB1 0x000000002 /* Port 1 Enable */
+ #define SH7751_PCIPDTR_PB0 0x000000001 /* Port 0 Enable */
+#define SH7751_PCIPDR 0x220 /* Port IO Data Register */
+
+/* Memory Control Registers */
+#define SH7751_BCR1 0xFF800000 /* Memory BCR1 Register */
+#define SH7751_BCR2 0xFF800004 /* Memory BCR2 Register */
+#define SH7751_WCR1 0xFF800008 /* Wait Control 1 Register */
+#define SH7751_WCR2 0xFF80000C /* Wait Control 2 Register */
+#define SH7751_WCR3 0xFF800010 /* Wait Control 3 Register */
+#define SH7751_MCR 0xFF800014 /* Memory Control Register */
+
+/* General Memory Config Addresses */
+#define SH7751_CS0_BASE_ADDR 0x0
+#define SH7751_MEM_REGION_SIZE 0x04000000
+#define SH7751_CS1_BASE_ADDR (SH7751_CS0_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS2_BASE_ADDR (SH7751_CS1_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS3_BASE_ADDR (SH7751_CS2_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS4_BASE_ADDR (SH7751_CS3_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS5_BASE_ADDR (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS6_BASE_ADDR (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+
+/* General PCI values */
+#define SH7751_PCI_HOST_BRIDGE 0x6
+
+/* External functions defined per platform i.e. Big Sur, SE... (these could be routed
+ * through the machine vectors... */
+extern int pcibios_init_platform(void);
+extern int pcibios_map_platform_irq(u8 slot, u8 pin);
+
+#endif /* _PCI_SH7751_H_ */
+
#define pcibios_assign_all_busses() 1
+#if defined(CONFIG_CPU_SUBTYPE_ST40STB1)
/* These are currently the correct values for the STM overdrive board.
* We need some way of setting this on a board specific way, it will
* not be the same on other boards I think
*/
-#if 1 /* def CONFIG_SH_7750_OVERDRIVE || def CONFIG_CPU_SUBTYPE_ST40STB1 */
#define PCIBIOS_MIN_IO 0x2000
#define PCIBIOS_MIN_MEM 0x10000000
+
+#elif defined(CONFIG_SH_DREAMCAST)
+#define PCIBIOS_MIN_IO 0x2000
+#define PCIBIOS_MIN_MEM 0x10000000
+#elif defined(CONFIG_SH_BIGSUR) && defined(CONFIG_CPU_SUBTYPE_SH7751)
+#define PCIBIOS_MIN_IO 0x2000
+#define PCIBIOS_MIN_MEM 0xFD000000
+
+#elif defined(CONFIG_SH_7751_SOLUTION_ENGINE) && defined(CONFIG_CPU_SUBTYPE_SH7751)
+#define PCIBIOS_MIN_IO 0x4000
+#define PCIBIOS_MIN_MEM 0xFD000000
#endif
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
+struct pci_dev;
+
+extern void pcibios_set_master(struct pci_dev *dev);
+//static inline void pcibios_set_master(struct pci_dev *dev)
+//{
/* No special bus mastering setup handling */
-}
+//}
static inline void pcibios_penalize_isa_irq(int irq)
{
#include <linux/string.h>
#include <asm/io.h>
-struct pci_dev;
-
/* Allocate and map kernel buffer using consistent mode DMA for a device.
* hwdev should be valid struct pci_dev pointer for PCI devices,
* NULL for PCI-like buses (ISA, EISA).
* Allocate and free page tables.
*/
-static __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
{
unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
return pgd;
}
-static __inline__ pgd_t *get_pgd_fast(void)
+static inline pgd_t *get_pgd_fast(void)
{
unsigned long *ret;
return (pgd_t *)ret;
}
-static __inline__ void free_pgd_fast(pgd_t *pgd)
+static inline void free_pgd_fast(pgd_t *pgd)
{
*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
pgd_quicklist = (unsigned long *) pgd;
pgtable_cache_size++;
}
-static __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void free_pgd_slow(pgd_t *pgd)
{
kfree(pgd);
}
if ((ret = (unsigned long *)pte_quicklist) != NULL) {
pte_quicklist = (unsigned long *)(*ret);
- ret[0] = ret[1];
+ ret[0] = 0;
pgtable_cache_size--;
}
return (pte_t *)ret;
}
-static __inline__ void pte_free_fast(pte_t *pte)
+static inline void pte_free_fast(pte_t *pte)
{
*(unsigned long *)pte = (unsigned long) pte_quicklist;
pte_quicklist = (unsigned long *) pte;
pgtable_cache_size++;
}
-static __inline__ void pte_free_slow(pte_t *pte)
+static inline void pte_free_slow(pte_t *pte)
{
free_page((unsigned long)pte);
}
-#define pte_free(pte) pte_free_slow(pte)
-#define pgd_free(pgd) free_pgd_slow(pgd)
+#define pte_free(pte) pte_free_fast(pte)
+#define pgd_free(pgd) free_pgd_fast(pgd)
#define pgd_alloc(mm) get_pgd_fast()
/*
* allocating and freeing a pmd is trivial: the 1-entry pmd is
* inside the pgd, so has no extra memory associated with it.
*/
-static __inline__ void pmd_free(pmd_t * pmd)
+static inline void pmd_free(pmd_t * pmd)
{
}
* - flush_tlb_mm(mm) flushes the specified mm context TLB's
* - flush_tlb_page(vma, vmaddr) flushes one page
* - flush_tlb_range(mm, start, end) flushes a range of pages
- *
+ * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
*/
extern void flush_tlb(void);
unsigned long end);
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
-static __inline__ void flush_tlb_pgtables(struct mm_struct *mm,
- unsigned long start, unsigned long end)
-{
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{ /* Nothing to do */
}
#endif /* __ASM_SH_PGALLOC_H */
#define PTRS_PER_PTE 1024
+#ifndef __ASSEMBLY__
#define pte_ERROR(e) \
printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
#define pmd_ERROR(e) \
static inline int pgd_none(pgd_t pgd) { return 0; }
static inline int pgd_bad(pgd_t pgd) { return 0; }
static inline int pgd_present(pgd_t pgd) { return 1; }
-static inline void pgd_clear (pgd_t * pgd) { }
+static inline void pgd_clear (pgd_t * pgdp) { pgd_val(*(pgdp)) = 0; }
/*
* Certain architectures need to do special things when PTEs
{
return (pmd_t *) dir;
}
+#endif /* !__ASSEMBLY__ */
#endif /* __ASM_SH_PGTABLE_2LEVEL_H */
/* Copyright (C) 1999 Niibe Yutaka */
+#include <asm/pgtable-2level.h>
+
/*
* This file contains the functions and defines necessary to modify and use
* the SuperH page table tree.
#include <asm/addrspace.h>
#include <linux/threads.h>
-extern pgd_t swapper_pg_dir[1024];
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern void paging_init(void);
#if defined(__sh3__)
#endif /* !__ASSEMBLY__ */
-#include <asm/pgtable-2level.h>
-
#define __beep() asm("")
#define PMD_SIZE (1UL << PMD_SHIFT)
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#define FIRST_USER_PGD_NR 0
-#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
-#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-
-#define TWOLEVEL_PGDIR_SHIFT 22
-#define BOOT_USER_PGD_PTRS (PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
-#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
-
#ifndef __ASSEMBLY__
#define VMALLOC_START P3SEG
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
/* Mask which drop software flags */
+#if defined(__sh3__)
+/*
+ * MMU on SH-3 has bug on SH-bit: We can't use it if MMUCR.IX=1.
+ * Work around: Just drop SH-bit.
+ */
+#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff1fc
+#else
#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff1fe
+#endif
/* Hardware flags: SZ=1 (4k-byte) */
#define _PAGE_FLAGS_HARD 0x00000010
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-#define __pmd_offset(address) \
- (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
-
/* Find an entry in the third-level page table.. */
#define __pte_offset(address) \
((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
+/*
+ * Routines for update of PTE
+ *
+ * We just can use generic implementation, as SuperH has no SMP feature.
+ * (We needed atomic implementation for SMP)
+ */
#include <asm-generic/pgtable.h>
#endif /* !__ASSEMBLY__ */
enum cpu_type {
CPU_SH7708, /* Represents 7707, 7708, 7708S, 7708R, 7709 */
CPU_SH7729, /* Represents 7709A, 7729 */
- CPU_SH7750,
+ CPU_SH7750, /* Represents 7750, 7751 */
CPU_ST40STB1,
CPU_SH_NONE
};
unsigned long *pte_quick;
unsigned long pgtable_cache_sz;
unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+ unsigned int memory_clock;
+#endif
};
extern struct sh_cpuinfo boot_cpu_data;
struct sh_fpu_hard_struct {
unsigned long fp_regs[16];
- unsigned long long xd_regs[8];
+ unsigned long xfp_regs[16];
unsigned long fpscr;
unsigned long fpul;
/* Dummy fpu emulator */
struct sh_fpu_soft_struct {
unsigned long fp_regs[16];
- unsigned long long xd_regs[8];
+ unsigned long xfp_regs[16];
unsigned long fpscr;
unsigned long fpul;
};
#define INIT_MMAP \
-{ &init_mm, 0x80000000, 0xa0000000, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
#define INIT_THREAD { \
sizeof(init_stack) + (long) &init_stack, /* sp */ \
extern void sh_rtc_gettimeofday(struct timeval *tv);
extern int sh_rtc_settimeofday(const struct timeval *tv);
+/* RCR1 Bits */
+#define RCR1_CF 0x80 /* Carry Flag */
+#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
+#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
+#define RCR1_AF 0x01 /* Alarm Flag */
+
+/* RCR2 Bits */
+#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
+#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
+#define RCR2_RTCEN 0x08 /* ENable RTC */
+#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
+#define RCR2_RESET 0x02 /* Reset bit */
+#define RCR2_START 0x01 /* Start bit */
+
+#if defined(__sh3__)
+/* SH-3 RTC */
+#define R64CNT 0xfffffec0
+#define RSECCNT 0xfffffec2
+#define RMINCNT 0xfffffec4
+#define RHRCNT 0xfffffec6
+#define RWKCNT 0xfffffec8
+#define RDAYCNT 0xfffffeca
+#define RMONCNT 0xfffffecc
+#define RYRCNT 0xfffffece
+#define RSECAR 0xfffffed0
+#define RMINAR 0xfffffed2
+#define RHRAR 0xfffffed4
+#define RWKAR 0xfffffed6
+#define RDAYAR 0xfffffed8
+#define RMONAR 0xfffffeda
+#define RCR1 0xfffffedc
+#define RCR2 0xfffffede
+
+#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
+#elif defined(__SH4__)
+/* SH-4 RTC */
+#define R64CNT 0xffc80000
+#define RSECCNT 0xffc80004
+#define RMINCNT 0xffc80008
+#define RHRCNT 0xffc8000c
+#define RWKCNT 0xffc80010
+#define RDAYCNT 0xffc80014
+#define RMONCNT 0xffc80018
+#define RYRCNT 0xffc8001c /* 16bit */
+#define RSECAR 0xffc80020
+#define RMINAR 0xffc80024
+#define RHRAR 0xffc80028
+#define RWKAR 0xffc8002c
+#define RDAYAR 0xffc80030
+#define RMONAR 0xffc80034
+#define RCR1 0xffc80038
+#define RCR2 0xffc8003c
+
+#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
+#endif
+
#endif /* _ASM_RTC_H */
#include <linux/linkage.h>
+#ifdef __KERNEL__
/*
* SMP- and interrupt-safe semaphores.
*
asmlinkage int __down_interruptible(struct semaphore * sem);
asmlinkage int __down_trylock(struct semaphore * sem);
asmlinkage void __up(struct semaphore * sem);
-extern struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry);
-extern struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry);
-asmlinkage struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem);
extern spinlock_t semaphore_wake_lock;
-extern __inline__ void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
{
#if WAITQUEUE_DEBUG
CHECK_MAGIC(sem->__magic);
__down(sem);
}
-extern __inline__ int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
{
int ret = 0;
#if WAITQUEUE_DEBUG
return ret;
}
-extern __inline__ int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
{
int ret = 0;
#if WAITQUEUE_DEBUG
* Note! This is subtle. We jump to wake people up only if
* the semaphore was negative (== somebody was waiting on it).
*/
-extern __inline__ void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
{
#if WAITQUEUE_DEBUG
CHECK_MAGIC(sem->__magic);
__up(sem);
}
+#endif
#endif /* __ASM_SH_SEMAPHORE_H */
--- /dev/null
+/*
+ * include/asm-sh/serial-bigsur.h
+ *
+ * Configuration details for Big Sur 16550 based serial ports
+ * i.e. HD64465, PCMCIA, etc.
+ */
+
+#ifndef _ASM_SERIAL_BIGSUR_H
+#define _ASM_SERIAL_BIGSUR_H
+#include <asm/hd64465.h>
+
+#define BASE_BAUD (3379200 / 16)
+
+/* Leave 2 spare for possible PCMCIA serial cards */
+#define RS_TABLE_SIZE 3
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+
+#define STD_SERIAL_PORT_DEFNS \
+ /* UART CLK PORT IRQ FLAGS */ \
+ { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */
+
+
+#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
+
+/* XXX: This should be moved ino irq.h */
+#define irq_cannonicalize(x) (x)
+
+#endif /* _ASM_SERIAL_BIGSUR_H */
#ifdef CONFIG_SH_EC3104
#include <asm/serial-ec3104.h>
+#elif defined (CONFIG_SH_BIGSUR)
+#include <asm/serial-bigsur.h>
#else
-
/*
* This assumes you have a 1.8432 MHz clock for your UART.
*
#include <asm/atomic.h>
#include <asm/hardirq.h>
-#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0)
+#define local_bh_disable() \
+do { \
+ local_bh_count(smp_processor_id())++; \
+ barrier(); \
+} while (0)
-#define local_bh_disable() cpu_bh_disable(smp_processor_id())
-#define local_bh_enable() cpu_bh_enable(smp_processor_id())
+#define __local_bh_enable() \
+do { \
+ barrier(); \
+ local_bh_count(smp_processor_id())--; \
+} while (0)
+
+#define local_bh_enable() \
+do { \
+ if (!--local_bh_count(smp_processor_id()) \
+ && softirq_pending(smp_processor_id())) { \
+ do_softirq(); \
+ __sti(); \
+ } \
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) set_bit((nr), &softirq_pending(cpu));
+#define raise_softirq(nr) __cpu_raise_softirq(smp_processor_id(), (nr))
#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
*/
#define __HAVE_ARCH_STRCPY
-extern __inline__ char *strcpy(char *__dest, const char *__src)
+static __inline__ char *strcpy(char *__dest, const char *__src)
{
register char *__xdest = __dest;
unsigned long __dummy;
}
#define __HAVE_ARCH_STRNCPY
-extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
+static __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
{
register char *__xdest = __dest;
unsigned long __dummy;
}
#define __HAVE_ARCH_STRCMP
-extern __inline__ int strcmp(const char *__cs, const char *__ct)
+static __inline__ int strcmp(const char *__cs, const char *__ct)
{
register int __res;
unsigned long __dummy;
}
#define __HAVE_ARCH_STRNCMP
-extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
+static __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
{
register int __res;
unsigned long __dummy;
struct user_fpu_struct {
unsigned long fp_regs[16];
- unsigned long long xd_regs[8];
+ unsigned long xfp_regs[16];
unsigned long fpscr;
unsigned long fpul;
};
#ifndef __LINUX_MII_H__
#define __LINUX_MII_H__
+#include <linux/types.h>
+
/* Inside the Happy Meal transceiver is the physical layer, they use an
* implementations for National Semiconductor, part number DP83840VCE.
* You can retrieve the data sheets and programming docs for this beast
#define CSCONFIG_RESV4 0x4000 /* Unused... */
#define CSCONFIG_NDISABLE 0x8000 /* Disable NRZI */
+
+/* This structure is used in all SIOCxMIIxxx ioctl calls */
+struct mii_ioctl_data {
+ u16 phy_id;
+ u16 reg_num;
+ u16 val_in;
+ u16 val_out;
+};
+
+
/**
* mii_nway_result
* @negotiated: value of MII ANAR and'd with ANLPAR
#define SIOCETHTOOL 0x8946 /* Ethtool interface */
+#define SIOCGMIIPHY 0x8947 /* Get address of MII PHY in use. */
+#define SIOCGMIIREG 0x8948 /* Read MII PHY register. */
+#define SIOCSMIIREG 0x8949 /* Write MII PHY register. */
+
/* ARP cache control calls. */
/* 0x8950 - 0x8952 * obsolete calls, don't re-use */
#define SIOCDARP 0x8953 /* delete ARP table entry */
#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */
#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */
#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */
-#define VMODE_MAX 20
+#define VMODE_1152_768_60 21 /* 1152x768, 60Hz Titanium PowerBook */
+#define VMODE_1600_1024_60 22 /* 1600x1024, 60Hz 22" Cinema Display */
+#define VMODE_MAX 22
#define VMODE_CHOOSE 99
#define CMODE_NVRAM -1
int state;
static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
- printk("%-8s ", p->comm);
+ printk("%-13.13s ", p->comm);
state = p->state ? ffz(~p->state) + 1 : 0;
if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
printk(stat_nam[state]);
printk("%5d ", p->p_cptr->pid);
else
printk(" ");
- if (!p->mm)
- printk(" (L-TLB) ");
- else
- printk(" (NOTLB) ");
if (p->p_ysptr)
printk("%7d", p->p_ysptr->pid);
else
printk(" ");
if (p->p_osptr)
- printk(" %5d\n", p->p_osptr->pid);
+ printk(" %5d", p->p_osptr->pid);
+ else
+ printk(" ");
+ if (!p->mm)
+ printk(" (L-TLB)\n");
else
- printk("\n");
+ printk(" (NOTLB)\n");
-#if defined(CONFIG_X86) || defined(CONFIG_SPARC64)
-/* This is very useful, but only works on x86 and sparc64 right now */
+#if defined(CONFIG_X86) || defined(CONFIG_SPARC64) || defined(CONFIG_ARM)
+/* This is very useful, but only works on ARM, x86 and sparc64 right now */
{
extern void show_trace_task(struct task_struct *tsk);
show_trace_task(p);
* to give up than to deadlock the kernel looping here.
*/
if (gfp_mask & __GFP_WAIT) {
- memory_pressure++;
if (!order || free_shortage()) {
int progress = try_to_free_pages(gfp_mask);
if (progress || (gfp_mask & __GFP_IO))
goto out;
found_page:
+ memory_pressure++;
del_page_from_inactive_clean_list(page);
UnlockPage(page);
page->age = PAGE_AGE_START;
out:
spin_unlock(&pagemap_lru_lock);
spin_unlock(&pagecache_lock);
- memory_pressure++;
return page;
}
static void atmarpd_close(struct atm_vcc *vcc)
{
- struct sk_buff *skb;
-
DPRINTK("atmarpd_close\n");
atmarpd = NULL; /* assumed to be atomic */
barrier();
if (skb_peek(&vcc->recvq))
printk(KERN_ERR "atmarpd_close: closing with requests "
"pending\n");
- while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
+ skb_queue_purge(&vcc->recvq);
DPRINTK("(done)\n");
}
{
struct atm_dev *dev;
struct atm_vcc *vcc;
- int *tmp_buf;
+ int *tmp_buf, *tmp_p;
void *buf;
int error,len,size,number, ret_val;
ret_val = -ENOMEM;
goto done;
}
+ tmp_p = tmp_buf;
for (dev = atm_devs; dev; dev = dev->next)
- *tmp_buf++ = dev->number;
- if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
- ret_val = -EFAULT;
- goto done;
- }
- ret_val = put_user(size,
- &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+ *tmp_p++ = dev->number;
+ ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
+ put_user(size, &((struct atm_iobuf *) arg)->length)
+ ) ? -EFAULT : 0;
+ kfree(tmp_buf);
goto done;
case SIOCGSTAMP: /* borrowed from IP */
if (!vcc->timestamp.tv_sec) {
dev->name,
skb->len,skb->truesize);
nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
+ if (nb == NULL) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
memcpy(nb,skb->data,skb->len);
kfree(skb->head);
skb->head = skb->data = nb;
entry = lec_arp_find(priv, mac_addr);
if (!entry) {
entry = make_entry(priv, mac_addr);
+ if (!entry) {
+ lec_arp_unlock(priv);
+ return;
+ }
entry->status = ESI_UNKNOWN;
lec_arp_put(priv->lec_arp_tables, entry);
/* Temporary, changes before end of function */
ioc_data->atm_addr[16],ioc_data->atm_addr[17],
ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
entry = make_entry(priv, bus_mac);
+ if (entry == NULL) {
+ lec_arp_unlock(priv);
+ return;
+ }
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
memset(entry->mac_addr, 0, ETH_ALEN);
entry->recv_vcc = vcc;
/* Not found, snatch address from first data packet that arrives from
this vcc */
entry = make_entry(priv, bus_mac);
+ if (!entry) {
+ lec_arp_unlock(priv);
+ return;
+ }
entry->vcc = vcc;
entry->old_push = old_push;
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
if (mpc == NULL) {
dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg);
mpc = alloc_mpc();
+ if (mpc == NULL)
+ return -ENOMEM;
mpc->dev_num = arg;
mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */
}
static void sigd_close(struct atm_vcc *vcc)
{
- struct sk_buff *skb;
struct atm_dev *dev;
DPRINTK("sigd_close\n");
sigd = NULL;
if (skb_peek(&vcc->recvq))
printk(KERN_ERR "sigd_close: closing with requests pending\n");
- while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
+ skb_queue_purge(&vcc->recvq);
purge_vccs(nodev_vccs);
spin_lock (&atm_dev_lock);
default:
#ifdef CONFIG_NETFILTER
{
- int val, len = *optlen;
+ int val, len;
+
+ if(get_user(len, optlen))
+ return -EFAULT;
+
val = nf_getsockopt(sk, PF_DECnet, optname,
optval, &len);
if (val >= 0)
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith
+ * added netlink_proto_exit
+ *
*/
#include <linux/config.h>
return 0;
}
+static void __exit netlink_proto_exit(void)
+{
+ sock_unregister(PF_NETLINK);
+ remove_proc_entry("net/netlink", NULL);
+}
+
module_init(netlink_proto_init);
+module_exit(netlink_proto_exit);
struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
struct sk_buff *skbn;
unsigned char *bp = skb->data;
+ int len;
if (arp_find(bp + 7, skb)) {
return 1;
kfree_skb(skb);
+ len = skbn->len;
+
if (!nr_route_frame(skbn, NULL)) {
kfree_skb(skbn);
stats->tx_errors++;
}
stats->tx_packets++;
- stats->tx_bytes += skbn->len;
+ stats->tx_bytes += len;
return 1;
}
void __exit nr_loopback_clear(void)
{
- struct sk_buff *skb;
-
del_timer(&loopback_timer);
-
- while ((skb = skb_dequeue(&loopback_queue)) != NULL)
- kfree_skb(skb);
+ skb_queue_purge(&loopback_queue);
}
*/
void nr_clear_queues(struct sock *sk)
{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
- kfree_skb(skb);
-
- while ((skb = skb_dequeue(&sk->protinfo.nr->ack_queue)) != NULL)
- kfree_skb(skb);
-
- while ((skb = skb_dequeue(&sk->protinfo.nr->reseq_queue)) != NULL)
- kfree_skb(skb);
-
- while ((skb = skb_dequeue(&sk->protinfo.nr->frag_queue)) != NULL)
- kfree_skb(skb);
+ skb_queue_purge(&sk->write_queue);
+ skb_queue_purge(&sk->protinfo.nr->ack_queue);
+ skb_queue_purge(&sk->protinfo.nr->reseq_queue);
+ skb_queue_purge(&sk->protinfo.nr->frag_queue);
}
/*
if (!rose_route_frame(skbn, NULL)) {
kfree_skb(skbn);
stats->tx_errors++;
+ return 1;
}
stats->tx_packets++;
if (conf->data_size && conf->data){
if(conf->data_size > 128000 || conf->data_size < 0) {
- kfree(conf);
printk(KERN_INFO
"%s: ERROR, Invalid firmware data size %i !\n",
wandev->name, conf->data_size);
+ kfree(conf);
return -EINVAL;;
}
{
wanif_conf_t conf;
netdevice_t *dev=NULL;
- #ifdef CONFIG_WANPIPE_MULTPPP
+#ifdef CONFIG_WANPIPE_MULTPPP
struct ppp_device *pppdev=NULL;
- #endif
+#endif
int err;
if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL))
return -ENODEV;
- #if defined (LINUX_2_1) || defined (LINUX_2_4)
+#if defined (LINUX_2_1) || defined (LINUX_2_4)
if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t)))
return -EFAULT;
- #else
+#else
err = verify_area(VERIFY_READ, u_conf, sizeof(wanif_conf_t));
if (err)
return err;
memcpy_fromfs((void*)&conf, (void*)u_conf, sizeof(wanif_conf_t));
- #endif
+#endif
if (conf.magic != ROUTER_MAGIC)
return -EINVAL;
}
memset(pppdev, 0, sizeof(struct ppp_device));
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
pppdev->dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL);
if (pppdev->dev == NULL){
+ kfree(pppdev);
return -ENOBUFS;
}
memset(pppdev->dev, 0, sizeof(netdevice_t));
- #endif
+#endif
err = wandev->new_if(wandev, (netdevice_t *)pppdev, &conf);
offs = file->f_pos;
if (offs < pos) {
len = min(pos - offs, count);
- if(copy_to_user(buf, (page + offs), len))
+ if (copy_to_user(buf, (page + offs), len)) {
+ kfree(page);
return -EFAULT;
+ }
file->f_pos += len;
}
else