### Don't know what's going on here.
###
#
+YAM driver for AX.25
+CONFIG_YAM
+ Support for the YAM modem on serial port. If you want to compile this
+ as a module ( = code which can be inserted in and removed from the
+ running kernel whenever you want), say M here and read
+ Documentation/modules.txt.
+
BAYCOM picpar and par96 driver for AX.25
CONFIG_BAYCOM_PAR
This is a driver for Baycom style simple amateur radio modems that
say M here and read Documentation/modules.txt. The module will be
called x25_asy.o. If unsure, say N.
-Shortwave radio modem driver
-CONFIG_HFMODEM
- This experimental driver is used by a package (to be released)
- that implements the shortwave radio protocols RTTY, Sitor (Amtor),
- Pactor 1 and GTOR using a standard PC sound card. If unsure,
- say N.
-
-Shortwave radio modem driver support for Sound Blaster and compatible cards
-CONFIG_HFMODEM_SBC
- This option enables the hfmodem driver to use Sound Blaster and
- compatible cards. It requires a 16bit capable card, i.e.
- SB16 or better, or ESS1688 or newer.
-
-Shortwave radio modem driver support for WSS and Crystal cards
-CONFIG_HFMODEM_WSS
- This option enables the hfmodem driver to use WindowsSoundSystem
- compatible cards. These cards feature a codec chip from either
- Analog Devices (such as AD1848, AD1845) or Crystal Semiconductors
- (such as CS4248, CS423x).
-
PLIP (parallel port) support
CONFIG_PLIP
PLIP (Parallel Line Internet Protocol) is used to create a
If you run Linux on a multiprocessor machine and said Y to
"Symmetric Multi Processing" above, you should say Y here to read
- and set the RTC clock in an SMP compatible fashion.
+ and set the RTC in an SMP compatible fashion.
If you think you have a use for such a device (such as periodic data
sampling), then say Y here, and read Documentation/rtc.txt for
mknod /dev/ttyACM2 c 166 2
mknod /dev/ttyACM3 c 166 3
+USS720 parport driver
+CONFIG_USB_USS720
+ This driver is for USB parallel port adapters that use the USS-720
+ chip.
+
USB /proc filesystem entry support (Preliminary)
CONFIG_USB_PROC
This reports USB drivers and devices in the /proc filesystem.
# LocalWords: KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb
# LocalWords: dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS
# LocalWords: nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY
-# LocalWords: HFMODEM shortwave Sitor Amtor Pactor GTOR hfmodem hayes TX TMOUT
+# LocalWords: hayes TX TMOUT
# LocalWords: IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu
# LocalWords: unam mx miguel koobera uic EMUL solaris pp ieee lpsg co DMAs TOS
# LocalWords: BLDCONFIG preloading jumperless BOOTINIT modutils multipath GRE
-Behaviour of cards under Multicast. This is how they currently
-behave not what the hardware can do - i.e. the lance driver doesn't
-use its filter, even though the code for loading it is in the DEC
-lance based driver.
+Behaviour of Cards Under Multicast
+==================================
-The following multicast requirements are needed
+This is how they currently behave, not what the hardware can do--for example,
+the Lance driver doesn't use its filter, even though the code for loading
+it is in the DEC Lance-based driver.
+
+The following are requirements for multicasting
-----------------------------------------------
-Appletalk Multicast hardware filtering not important but
+AppleTalk Multicast hardware filtering not important but
avoid cards only doing promisc
IP-Multicast Multicast hardware filters really help
IP-MRoute AllMulti hardware filters are of no help
* How do I enable the magic SysRQ key?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You need to say yes to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when
-configuring the kernel. This option is only available it 2.1.x or later
+You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when
+configuring the kernel. This option is only available in 2.1.x or later
kernels.
* How do I use the magic SysRQ key?
W: http://www.torque.net/sg
S: Maintained
-SCSI GENERIC
-L: linux-scsi@vger.rutgers.edu
-M: douglas.gilbert@rbcds.com
-S: Maintained
-
SCSI SUBSYSTEM
L: linux-scsi@vger.rutgers.edu
S: Unmaintained
io_apic_irqs = 0;
#endif
cpu_online_map = cpu_present_map;
+ smp_num_cpus = 1;
goto smp_done;
}
-#include <stdarg.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <stdarg.h>
#define DN_DEBUG_BUFFER_BASE 0x82800000
#define DN_DEBUG_BUFFER_SIZE 8*1024*1024
{
joystick[0].active = joystick[1].active = 0;
joystick[0].ready = joystick[1].ready = 0;
- joystick[0].wait = joystick[1].wait = NULL;
+ init_waitqueue_head(&joystick[0].wait);
+ init_waitqueue_head(&joystick[1].wait);
if (register_chrdev(MAJOR_NR, "Joystick", &atari_joystick_fops))
printk("unable to get major %d for joystick devices\n", MAJOR_NR);
static int stram_swap_type;
/* Semaphore for get_stram_region. */
-static struct semaphore stram_swap_sem = MUTEX;
+static DECLARE_MUTEX(stram_swap_sem);
/* major and minor device number of the ST-RAM device; for the major, we use
* the same as Amiga z2ram, which is really similar and impossible on Atari,
"swap=%08lx-%08lx\n", swap_start, swap_end );
/* reserve some amount of memory for maintainance of
- * swapping itself: 1 page for the lockmap, and one page
- * for each 2048 (PAGE_SIZE/2) swap pages. (2 bytes for
- * each page) */
+ * swapping itself: one page for each 2048 (PAGE_SIZE/2)
+ * swap pages. (2 bytes for each page) */
swap_data = start_mem;
- start_mem += (((SWAP_NR(swap_end) + PAGE_SIZE/2 - 1)
- >> (PAGE_SHIFT-1)) + 1) << PAGE_SHIFT;
+ start_mem += ((SWAP_NR(swap_end) + PAGE_SIZE/2 - 1)
+ >> (PAGE_SHIFT-1)) << PAGE_SHIFT;
/* correct swap_start if necessary */
if (swap_start == swap_data)
swap_start = start_mem;
p->flags = SWP_USED;
p->swap_file = &fake_dentry[0];
p->swap_device = 0;
- p->swap_lockmap = (unsigned char *)(swap_data);
- p->swap_map = (unsigned short *)(swap_data + PAGE_SIZE);
+ p->swap_map = (unsigned short *)swap_data;
p->cluster_nr = 0;
p->next = -1;
p->prio = 0x7ff0; /* a rather high priority, but not the higest
stram_open( &swap_inode, MAGIC_FILE_P );
p->max = SWAP_NR(swap_end);
- /* initialize lockmap */
- memset( p->swap_lockmap, 0, PAGE_SIZE );
-
/* initialize swap_map: set regions that are already allocated or belong
* to kernel data space to SWAP_MAP_BAD, otherwise to free */
j = 0; /* # of free pages */
* for more details.
*/
-#include <stdarg.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
bool '/proc/hardware support' CONFIG_PROC_HARDWARE
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Parallel port support (EXPERIMENTAL, disables old lp driver!)' CONFIG_PARPORT
+ tristate 'Parallel port support (EXPERIMENTAL)' CONFIG_PARPORT
if [ "$CONFIG_PARPORT" != "n" ]; then
if [ "$CONFIG_AMIGA" != "n" ]; then
dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
if [ "$CONFIG_ATARI" == "y" ]; then
dep_tristate ' Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
fi
+ dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+ if [ "$CONFIG_PRINTER" != "n" ]; then
+ bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+ fi
fi
define_bool CONFIG_NVRAM y
fi
-if [ "$CONFIG_PARPORT" = "n" ]; then
- tristate 'Parallel printer support' CONFIG_M68K_PRINTER
- if [ "$CONFIG_ZORRO" = "y" ]; then
- dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
- fi
-else
- dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
- if [ "$CONFIG_PRINTER" != "n" ]; then
- bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
- fi
-fi
if [ "$CONFIG_AMIGA" = "y" ]; then
tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
+ if [ "$CONFIG_AMIGAMOUSE" != "n" ]; then
+ define_bool CONFIG_MOUSE y
+ fi
fi
if [ "$CONFIG_ATARI" = "y" ]; then
tristate 'Atari mouse support' CONFIG_ATARIMOUSE
+ if [ "$CONFIG_ATARIMOUSE" != "n" ]; then
+ define_bool CONFIG_MOUSE y
+ fi
fi
if [ "$CONFIG_MAC" = "y" ]; then
bool 'Mac ADB mouse support' CONFIG_ADBMOUSE
+ if [ "$CONFIG_ADBMOUSE" != "n" ]; then
+ define_bool CONFIG_MOUSE y
+ fi
fi
if [ "$CONFIG_ATARI" = "y" ]; then
tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD
bool 'Sun mouse support' CONFIG_SUN_MOUSE
+ if [ "$CONFIG_SUN_MOUSE" != "n" ]; then
+ define_bool CONFIG_MOUSE y
+ fi
define_bool CONFIG_SBUS y
define_bool CONFIG_SBUSCHAR y
define_bool CONFIG_SUN_SERIAL y
ENTRY(reschedule)
| save top of frame
- movel %sp,%curptr@(TASK_TSS+TSS_ESP0)
+ movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
pea SYMBOL_NAME(ret_from_exception)
jmp SYMBOL_NAME(schedule)
SAVE_SWITCH_STACK
jbsr SYMBOL_NAME(syscall_trace)
+ | After a fork we jump here directly from resume,
+ | so that %d1 contains the previous task
+ | Theoretically only needed on SMP, but let's watch
+ | what happens in schedule_tail() in future...
+ENTRY(ret_from_fork)
+ movel %d1,%sp@-
+ jsr SYMBOL_NAME(schedule_tail)
+ addql #4,%sp
+ jra SYMBOL_NAME(ret_from_exception)
+
SYMBOL_NAME_LABEL(ret_from_signal)
RESTORE_SWITCH_STACK
addql #4,%sp
GET_CURRENT(%d0)
| save top of frame
- movel %sp,%curptr@(TASK_TSS+TSS_ESP0)
+ movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
cmpl #NR_syscalls,%d2
jcc badsys
andw #ALLOWINT,%sr
tstl %curptr@(TASK_NEEDRESCHED)
jne SYMBOL_NAME(reschedule)
+#if 0
cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals
jeq 2f
+#endif
| check for delayed trace
bclr #PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF)
jne do_delayed_trace
*/
/* save sr */
- movew %sr,%a0@(TASK_TSS+TSS_SR)
+ movew %sr,%a0@(TASK_THREAD+THREAD_SR)
/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
movec %sfc,%d0
- movew %d0,%a0@(TASK_TSS+TSS_FS)
+ movew %d0,%a0@(TASK_THREAD+THREAD_FS)
/* save usp */
/* it is better to use a movel here instead of a movew 8*) */
movec %usp,%d0
- movel %d0,%a0@(TASK_TSS+TSS_USP)
+ movel %d0,%a0@(TASK_THREAD+THREAD_USP)
/* save non-scratch registers on stack */
SAVE_SWITCH_STACK
/* save current kernel stack pointer */
- movel %sp,%a0@(TASK_TSS+TSS_KSP)
+ movel %sp,%a0@(TASK_THREAD+THREAD_KSP)
/* save floating point context */
- fsave %a0@(TASK_TSS+TSS_FPSTATE)
+ fsave %a0@(TASK_THREAD+THREAD_FPSTATE)
#if defined(CONFIG_M68060)
#if !defined(CPU_M68060_ONLY)
beqs 1f
#endif
/* The 060 FPU keeps status in bits 15-8 of the first longword */
- tstb %a0@(TASK_TSS+TSS_FPSTATE+2)
+ tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2)
jeq 3f
#if !defined(CPU_M68060_ONLY)
jra 2f
#endif
#endif /* CONFIG_M68060 */
#if !defined(CPU_M68060_ONLY)
-1: tstb %a0@(TASK_TSS+TSS_FPSTATE)
+1: tstb %a0@(TASK_THREAD+THREAD_FPSTATE)
jeq 3f
#endif
-2: fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG)
- fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL)
+2: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
+ fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
3:
/* Return previous task in %d1 */
movel %curptr,%d1
/* switch to new task (a1 contains new task) */
movel %a1,%curptr
- /* Skip address space switching if they are the same. */
- movel %a0@(TASK_MM),%d0
- cmpl %a1@(TASK_MM),%d0
- jeq 4f
-
-#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
- /* 68040 or 68060 ? */
- tstl SYMBOL_NAME(m68k_is040or060)
- bnes 1f
-#endif
-#if defined(CPU_M68020_OR_M68030)
- /*
- * switch address space
- */
-
- /* flush MC68030/MC68020 caches (they are virtually addressed) */
- movec %cacr,%d0
- oriw #LFLUSH_I_AND_D,%d0
- movec %d0,%cacr
-
- /* switch the root pointer */
-#ifdef CPU_M68030_ONLY
- .chip 68030
- pmovefd %a1@(TASK_TSS+TSS_CRP),%crp
- .chip 68k
- pflush #0,#4
-#else
- pmove %a1@(TASK_TSS+TSS_CRP),%crp
-#endif
-#endif
-
-#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
- jra 2f /* skip m68040 stuff */
-1:
-#endif
-#if defined(CPU_M68040_OR_M68060)
- /*
- * switch address space
- */
- .chip 68040
-
- /* flush address translation cache (user entries) */
- pflushan
-
- /* switch the root pointer */
- movel %a1@(TASK_TSS+TSS_CRP+4),%d0
- movec %d0,%urp
-
-#if defined (CONFIG_M68060)
- /* is it a '060 ? */
-#if !defined(CPU_M68060_ONLY)
- btst #3,SYMBOL_NAME(m68k_cputype)+3
- beqs 2f
-#endif
- /* clear user entries in the branch cache */
- movec %cacr,%d0
- orl #0x00200000,%d0
- movec %d0,%cacr
-#endif /* CONFIG_M68060 */
- .chip 68k
-#endif /* CPU_M68040_OR_M68060 */
-2:
-4:
/* restore floating point context */
#if defined(CONFIG_M68060)
beqs 1f
#endif
/* The 060 FPU keeps status in bits 15-8 of the first longword */
- tstb %a1@(TASK_TSS+TSS_FPSTATE+2)
+ tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2)
jeq 3f
#if !defined(CPU_M68060_ONLY)
jra 2f
#endif
#endif /* CONFIG_M68060 */
#if !defined(CPU_M68060_ONLY)
-1: tstb %a1@(TASK_TSS+TSS_FPSTATE)
+1: tstb %a1@(TASK_THREAD+THREAD_FPSTATE)
jeq 3f
#endif
-2: fmovemx %a1@(TASK_TSS+TSS_FPREG),%fp0-%fp7
- fmoveml %a1@(TASK_TSS+TSS_FPCNTL),%fpcr/%fpsr/%fpiar
-3: frestore %a1@(TASK_TSS+TSS_FPSTATE)
+2: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
+ fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
+3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
/* restore the kernel stack pointer */
- movel %a1@(TASK_TSS+TSS_KSP),%sp
+ movel %a1@(TASK_THREAD+THREAD_KSP),%sp
/* restore non-scratch registers */
RESTORE_SWITCH_STACK
/* restore user stack pointer */
- movel %a1@(TASK_TSS+TSS_USP),%a0
+ movel %a1@(TASK_THREAD+THREAD_USP),%a0
movel %a0,%usp
/* restore fs (sfc,%dfc) */
- movew %a1@(TASK_TSS+TSS_FS),%a0
+ movew %a1@(TASK_THREAD+THREAD_FS),%a0
movec %a0,%sfc
movec %a0,%dfc
/* restore status register */
- movew %a1@(TASK_TSS+TSS_SR),%sr
+ movew %a1@(TASK_THREAD+THREAD_SR),%sr
rts
.long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */
.long SYMBOL_NAME(sys_vhangup)
- .long SYMBOL_NAME(sys_idle)
+ .long SYMBOL_NAME(sys_ni_syscall) /* obsolete idle() syscall */
.long SYMBOL_NAME(sys_ni_syscall) /* vm86old for i386 */
.long SYMBOL_NAME(sys_wait4)
.long SYMBOL_NAME(sys_swapoff) /* 115 */
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending));
DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched));
- DEFINE(TASK_TSS, offsetof(struct task_struct, tss));
+ DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+ DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
/* offsets into the thread struct */
- DEFINE(TSS_KSP, offsetof(struct thread_struct, ksp));
- DEFINE(TSS_USP, offsetof(struct thread_struct, usp));
- DEFINE(TSS_SR, offsetof(struct thread_struct, sr));
- DEFINE(TSS_FS, offsetof(struct thread_struct, fs));
- DEFINE(TSS_CRP, offsetof(struct thread_struct, crp));
- DEFINE(TSS_ESP0, offsetof(struct thread_struct, esp0));
- DEFINE(TSS_FPREG, offsetof(struct thread_struct, fp));
- DEFINE(TSS_FPCNTL, offsetof(struct thread_struct, fpcntl));
- DEFINE(TSS_FPSTATE, offsetof(struct thread_struct, fpstate));
+ DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+ DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+ DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
+ DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
+ DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
+ DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+ DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
+ DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
+ DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
/* offsets into the pt_regs */
DEFINE(PT_D0, offsetof(struct pt_regs, d0));
DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+ DEFINE(PT_D1, offsetof(struct pt_regs, d1));
+ DEFINE(PT_D2, offsetof(struct pt_regs, d2));
+ DEFINE(PT_D3, offsetof(struct pt_regs, d3));
+ DEFINE(PT_D4, offsetof(struct pt_regs, d4));
+ DEFINE(PT_D5, offsetof(struct pt_regs, d5));
+ DEFINE(PT_A0, offsetof(struct pt_regs, a0));
+ DEFINE(PT_A1, offsetof(struct pt_regs, a1));
+ DEFINE(PT_A2, offsetof(struct pt_regs, a2));
+ DEFINE(PT_PC, offsetof(struct pt_regs, pc));
DEFINE(PT_SR, offsetof(struct pt_regs, sr));
-
/* bitfields are a bit difficult */
DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data));
DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref));
+ /* signal defines */
+ DEFINE(SIGSEGV, SIGSEGV);
+ DEFINE(SEGV_MAPERR, SEGV_MAPERR);
+ DEFINE(SIGTRAP, SIGTRAP);
+ DEFINE(TRAP_TRACE, TRAP_TRACE);
+
/* offsets into the custom struct */
DEFINE(CUSTOMBASE, &custom);
DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(kernel_set_cachemode);
EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(register_serial);
-EXPORT_SYMBOL(unregister_serial);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
struct mm_struct init_mm = INIT_MM(init_mm);
union task_union init_task_union
- __attribute__((section("init_task"), aligned(2*PAGE_SIZE)))
- = { task: INIT_TASK };
+__attribute__((section("init_task"), aligned(THREAD_SIZE)))
+ = { task: INIT_TASK(init_task_union.task) };
+
+asmlinkage void ret_from_fork(void);
-asmlinkage void ret_from_exception(void);
/*
* The idle loop on an m68k..
*/
-asmlinkage int sys_idle(void)
+static void default_idle(void)
{
- if (current->pid != 0)
- return -EPERM;
-
- /* endless idle loop with no priority at all */
- current->priority = 0;
- current->counter = -100;
- for (;;) {
+ while(1) {
if (!current->need_resched)
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
+#ifdef MACH_ATARI_ONLY
/* block out HSYNC on the atari (falcon) */
__asm__("stop #0x2200" : : : "cc");
-#else /* portable version */
+#else
__asm__("stop #0x2000" : : : "cc");
-#endif /* machine compilation types */
+#endif
schedule();
check_pgt_cache();
}
}
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+ /* endless idle loop with no priority at all */
+ init_idle();
+ current->priority = 0;
+ current->counter = -100;
+ idle();
+}
+
void machine_restart(char * __unused)
{
if (mach_reset)
{
unsigned long zero = 0;
set_fs(USER_DS);
- current->tss.fs = __USER_DS;
+ current->thread.fs = __USER_DS;
asm volatile (".chip 68k/68881\n\t"
"frestore %0@\n\t"
".chip 68k" : : "a" (&zero));
struct switch_stack * childstack, *stack;
unsigned long stack_offset, *retp;
- stack_offset = 2*PAGE_SIZE - sizeof(struct pt_regs);
+ stack_offset = THREAD_SIZE - sizeof(struct pt_regs);
childregs = (struct pt_regs *) ((unsigned long) p + stack_offset);
*childregs = *regs;
childstack = ((struct switch_stack *) childregs) - 1;
*childstack = *stack;
- childstack->retpc = (unsigned long) ret_from_exception;
+ childstack->retpc = (unsigned long)ret_from_fork;
- p->tss.usp = usp;
- p->tss.ksp = (unsigned long)childstack;
+ p->thread.usp = usp;
+ p->thread.ksp = (unsigned long)childstack;
/*
* Must save the current SFC/DFC value, NOT the value when
* the parent was last descheduled - RGH 10-08-96
*/
- p->tss.fs = get_fs().seg;
+ p->thread.fs = get_fs().seg;
/* Copy the current fpu state */
- asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory");
+ asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
- if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2])
+ if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
- : : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0])
+ : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
: "memory");
/* Restore the state in case the fpu was busy */
- asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0]));
+ asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
return 0;
}
int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
{
- char fpustate[216];
+ char fpustate[216];
/* First dump the fpu context to avoid protocol violation. */
asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
/* sets the trace bits. */
#define TRACE_BITS 0x8000
-/* Find the stack offset for a register, relative to tss.esp0. */
+/* Find the stack offset for a register, relative to thread.esp0. */
#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
- sizeof(struct switch_stack))
unsigned long *addr;
if (regno == PT_USP)
- addr = &task->tss.usp;
+ addr = &task->thread.usp;
else if (regno < sizeof(regoff)/sizeof(regoff[0]))
- addr = (unsigned long *)(task->tss.esp0 + regoff[regno]);
+ addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
else
return 0;
return *addr;
unsigned long *addr;
if (regno == PT_USP)
- addr = &task->tss.usp;
+ addr = &task->thread.usp;
else if (regno < sizeof(regoff)/sizeof(regoff[0]))
- addr = (unsigned long *) (task->tss.esp0 + regoff[regno]);
+ addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
else
return -1;
*addr = data;
tmp >>= 16;
}
else if (addr >= 21 && addr < 49)
- tmp = child->tss.fp[addr - 21];
+ tmp = child->thread.fp[addr - 21];
else
goto out;
ret = put_user(tmp,(unsigned long *) data);
}
if (addr >= 21 && addr < 48)
{
- child->tss.fp[addr - 21] = data;
+ child->thread.fp[addr - 21] = data;
ret = 0;
}
goto out;
case PTRACE_GETFPREGS: { /* Get the child FPU state. */
ret = 0;
- if (copy_to_user((void *)data, &child->tss.fp,
+ if (copy_to_user((void *)data, &child->thread.fp,
sizeof(struct user_m68kfp_struct)))
ret = -EFAULT;
goto out;
case PTRACE_SETFPREGS: { /* Set the child FPU state. */
ret = 0;
- if (copy_from_user(&child->tss.fp, (void *)data,
+ if (copy_from_user(&child->thread.fp, (void *)data,
sizeof(struct user_m68kfp_struct)))
ret = -EFAULT;
goto out;
/*
* Do a signal return; undo the signal stack.
+ *
+ * Keep the return code on the stack quadword aligned!
+ * That makes the cache flush below easier.
*/
struct sigframe
int sig;
struct siginfo *pinfo;
void *puc;
+ char retcode[8];
struct siginfo info;
struct ucontext uc;
- char retcode[8];
};
struct switch_stack *sw = (struct switch_stack *) &__unused;
struct pt_regs *regs = (struct pt_regs *) (sw + 1);
unsigned long usp = rdusp();
- struct sigframe *frame = (struct sigframe *)(usp - 24);
+ struct sigframe *frame = (struct sigframe *)(usp - 4);
sigset_t set;
int d0;
"cpushl %%bc,(%0)\n\t"
".chip 68k"
: : "a" (temp));
- if (((vaddr + 8) ^ vaddr) & ~15) {
- if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
- __asm__ __volatile__ (".chip 68040\n\t"
- "nop\n\t"
- "ptestr (%1)\n\t"
- "movec %%mmusr,%0\n\t"
- ".chip 68k"
- : "=r" (temp)
- : "a" (vaddr + 8));
-
- temp &= PAGE_MASK;
- temp |= (vaddr + 8) & ~PAGE_MASK;
-
- __asm__ __volatile__ (".chip 68040\n\t"
- "nop\n\t"
- "cpushl %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (temp));
- }
}
else if (CPU_IS_060) {
unsigned long temp;
"cpushl %%bc,(%0)\n\t"
".chip 68k"
: : "a" (temp));
- if (((vaddr + 8) ^ vaddr) & ~15) {
- if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
- __asm__ __volatile__ (".chip 68060\n\t"
- "plpar (%0)\n\t"
- ".chip 68k"
- : "=a" (temp)
- : "0" (vaddr + 8));
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpushl %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (temp));
- }
}
else {
/*
/* Set up to return from userspace. */
err |= __put_user(frame->retcode, &frame->pretcode);
- /* addaw #20,sp */
- err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0));
/* moveq #,d0; trap #0 */
err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
- (long *)(frame->retcode + 4));
+ (long *)(frame->retcode));
if (err)
goto give_sigsegv;
/* Set up to return from userspace. */
err |= __put_user(frame->retcode, &frame->pretcode);
- /* movel #,d0; trap #0 */
- err |= __put_user(0x203c, (short *)(frame->retcode + 0));
- err |= __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
- err |= __put_user(0x4e40, (short *)(frame->retcode + 6));
+ /* moveq #,d0; notb d0; trap #0 */
+ err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
+ (long *)(frame->retcode + 0));
+ err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
if (err)
goto give_sigsegv;
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
- if (!(ka->sa.sa_flags & SA_NODEFER)) {
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
sigaddset(¤t->blocked,sig);
- recalc_sigpending(current);
- }
+ recalc_sigpending(current);
}
/*
siginfo_t info;
struct k_sigaction *ka;
- current->tss.esp0 = (unsigned long) regs;
+ current->thread.esp0 = (unsigned long) regs;
if (!oldset)
oldset = ¤t->blocked;
default:
sigaddset(¤t->signal, signr);
+ recalc_sigpending(current);
current->flags |= PF_SIGNALED;
do_exit(exit_code);
/* NOTREACHED */
{
/* Only set esp0 if coming from user mode */
if (user_mode(&fp->ptregs))
- current->tss.esp0 = (unsigned long) fp;
+ current->thread.esp0 = (unsigned long) fp;
#if DEBUG
printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
* MSch (1/98) Integrated start of IIsi driver by Robert Thompson
*/
-#include <stdarg.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
struct mm_struct *mm = current->mm;
struct vm_area_struct * vma;
unsigned long fixup;
- int write;
+ int write, fault;
#ifdef DEBUG
printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
current->mm->pgd);
#endif
-
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- if (!handle_mm_fault(current, vma, address, write))
+ fault = handle_mm_fault(current, vma, address, write);
+ if (fault < 0)
+ goto out_of_memory;
+ if (!fault)
goto do_sigbus;
/* There seems to be a missing invalidate somewhere in do_no_page.
* We ran out of memory, or some other thing happened to us that made
* us unable to handle the page fault gracefully.
*/
+out_of_memory:
+ up(&mm->mmap_sem);
+ printk("VM: killing process %s\n", current->comm);
+ if (error_code & 4)
+ do_exit(SIGKILL);
+ goto no_context;
+
do_sigbus:
up(&mm->mmap_sem);
#include <asm/atari_stram.h>
#endif
-#undef DEBUG
-
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
reserved++;
else if (PageSwapCache(mem_map+i))
cached++;
- else if (!atomic_read(&mem_map[i].count))
+ else if (!page_count(mem_map+i))
free++;
- else if (atomic_read(&mem_map[i].count) == 1)
+ else if (page_count(mem_map+i) == 1)
nonshared++;
else
- shared += atomic_read(&mem_map[i].count) - 1;
+ shared += page_count(mem_map+i) - 1;
}
printk("%d pages of RAM\n",total);
printk("%d free pages\n",free);
}
static pmd_t *last_pgtable __initdata = NULL;
+static pmd_t *zero_pgtable __initdata = NULL;
__initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp))
{
{
#define PTRTREESIZE (256*1024)
#define ROOTTREESIZE (32*1024*1024)
- static unsigned long virtaddr = 0;
+ static unsigned long virtaddr = PAGE_OFFSET;
unsigned long physaddr;
pgd_t *pgd_dir;
pmd_t *pmd_dir;
#ifdef DEBUG
printk ("[zero map]");
#endif
- pte_dir = (pte_t *)kernel_ptr_table(memavailp);
+ zero_pgtable = kernel_ptr_table(memavailp);
+ pte_dir = (pte_t *)zero_pgtable;
pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
_PAGE_TABLE | _PAGE_ACCESSED;
pte_val(*pte_dir++) = 0;
start_mem += PAGE_SIZE;
memset((void *)empty_zero_page, 0, PAGE_SIZE);
- /*
- * allocate the "swapper" page directory and
- * record in task 0 (swapper) tss
- */
- init_mm.pgd = (pgd_t *)kernel_ptr_table(&start_mem);
- memset (init_mm.pgd, 0, sizeof(pgd_t)*PTRS_PER_PGD);
-
- /* setup CPU root pointer for swapper task */
- task[0]->tss.crp[0] = 0x80000000 | _PAGE_TABLE;
- task[0]->tss.crp[1] = virt_to_phys(init_mm.pgd);
-
-#ifdef DEBUG
- printk ("task 0 pagedir at %p virt, %#lx phys\n",
- swapper_pg_dir, task[0]->tss.crp[1]);
-#endif
-
- if (CPU_IS_040_OR_060)
- asm __volatile__ (".chip 68040\n\t"
- "movec %0,%%urp\n\t"
- ".chip 68k"
- : /* no outputs */
- : "r" (task[0]->tss.crp[1]));
- else
- asm __volatile__ (".chip 68030\n\t"
- "pmove %0,%%crp\n\t"
- ".chip 68k"
- : /* no outputs */
- : "m" (task[0]->tss.crp[0]));
-#ifdef DEBUG
- printk ("set crp\n");
-#endif
-
/*
* Set up SFC/DFC registers (user data space)
*/
atari_stram_reserve_pages( start_mem );
#endif
- for (tmp = 0 ; tmp < end_mem ; tmp += PAGE_SIZE) {
+ for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
if (virt_to_phys ((void *)tmp) >= mach_max_dma_address)
clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
if (PageReserved(mem_map+MAP_NR(tmp))) {
datapages++;
continue;
}
- atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
+ set_page_count(mem_map+MAP_NR(tmp), 1);
#ifdef CONFIG_BLK_DEV_INITRD
if (!initrd_start ||
(tmp < (initrd_start & PAGE_MASK) || tmp >= initrd_end))
init_pointer_table(pgd_page(kernel_pg_dir[i]));
}
+ /* insert also pointer table that we used to unmap the zero page */
+ if (zero_pgtable)
+ init_pointer_table((unsigned long)zero_pgtable);
+
printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
max_mapnr << (PAGE_SHIFT-10),
addr = (unsigned long)&__init_begin;
for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+ set_page_count(mem_map+MAP_NR(addr), 1);
free_page(addr);
}
}
if (PageReserved(mem_map+i))
continue;
val->totalram++;
- if (!atomic_read(&mem_map[i].count))
+ if (!page_count(mem_map+i))
continue;
- val->sharedram += atomic_read(&mem_map[i].count) - 1;
+ val->sharedram += page_count(mem_map+i) - 1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
/* address match? */
base = regval & 0xff000000;
mask = ~(regval << 8) & 0xff000000;
- return ((vaddr ^ base) & mask) == 0;
+ return (((unsigned long)vaddr ^ base) & mask) == 0;
}
+#if DEBUG_INVALID_PTOV
+int mm_inv_cnt = 5;
+#endif
+
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
/*
* The following two routines map from a physical address to a kernel
* virtual address and vice versa.
*/
-unsigned long mm_vtop (unsigned long vaddr)
+unsigned long mm_vtop(unsigned long vaddr)
{
int i=0;
- unsigned long voff = vaddr;
- unsigned long offset = 0;
+ unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET;
- do{
- if (voff < offset + m68k_memory[i].size) {
+ do {
+ if (voff < m68k_memory[i].size) {
#ifdef DEBUGPV
- printk ("VTOP(%lx)=%lx\n", vaddr,
- m68k_memory[i].addr + voff - offset);
+ printk ("VTOP(%p)=%lx\n", vaddr,
+ m68k_memory[i].addr + voff);
#endif
- return m68k_memory[i].addr + voff - offset;
- } else
- offset += m68k_memory[i].size;
- i++;
- }while (i < m68k_num_memory);
+ return m68k_memory[i].addr + voff;
+ }
+ voff -= m68k_memory[i].size;
+ } while (++i < m68k_num_memory);
return mm_vtop_fallback(vaddr);
}
/* Separate function to make the common case faster (needs to save less
registers) */
-unsigned long mm_vtop_fallback (unsigned long vaddr)
+unsigned long mm_vtop_fallback(unsigned long vaddr)
{
/* not in one of the memory chunks; test for applying transparent
* translation */
".chip 68k"
: : "a" (&ttreg) );
if (transp_transl_matches( ttreg, vaddr ))
- return vaddr;
+ return (unsigned long)vaddr;
asm volatile( ".chip 68030\n\t"
"pmove %/tt1,%0@\n\t"
".chip 68k"
: : "a" (&ttreg) );
if (transp_transl_matches( ttreg, vaddr ))
- return vaddr;
+ return (unsigned long)vaddr;
}
else if (CPU_IS_040_OR_060) {
unsigned long ttreg;
".chip 68k"
: "=d" (ttreg) );
if (transp_transl_matches( ttreg, vaddr ))
- return vaddr;
+ return (unsigned long)vaddr;
asm volatile( ".chip 68040\n\t"
"movec %%dtt1,%0\n\t"
".chip 68k"
: "=d" (ttreg) );
if (transp_transl_matches( ttreg, vaddr ))
- return vaddr;
+ return (unsigned long)vaddr;
}
/* no match, too, so get the actual physical address from the MMU. */
set_fs (MAKE_MM_SEG(SUPER_DATA));
/* The PLPAR instruction causes an access error if the translation
- * is not possible. We don't catch that here, so a bad kernel trap
- * will be reported in this case. */
- asm volatile (".chip 68060\n\t"
- "plpar (%0)\n\t"
- ".chip 68k"
+ * is not possible. To catch this we use the same exception mechanism
+ * as for user space accesses in <asm/uaccess.h>. */
+ asm volatile (".chip 68060\n"
+ "1: plpar (%0)\n"
+ ".chip 68k\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ " .even\n"
+ "3: lea -1,%0\n"
+ " jra 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,3b\n"
+ ".previous"
: "=a" (paddr)
: "0" (vaddr));
set_fs (fs);
set_fs (fs);
if (mmusr & MMU_T_040) {
- return (vaddr); /* Transparent translation */
+ return (unsigned long)vaddr; /* Transparent translation */
}
if (mmusr & MMU_R_040)
- return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+ return (mmusr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1));
- panic ("VTOP040: bad virtual address %08lx (%lx)", vaddr, mmusr);
+ printk("VTOP040: bad virtual address %lx (%lx)", vaddr, mmusr);
+ return -1;
} else {
volatile unsigned short temp;
unsigned short mmusr;
mmusr = temp;
if (mmusr & (MMU_I|MMU_B|MMU_L))
- panic ("VTOP030: bad virtual address %08lx (%x)", vaddr, mmusr);
+ printk("VTOP030: bad virtual address %lx (%x)\n", vaddr, mmusr);
descaddr = phys_to_virt((unsigned long)descaddr);
switch (mmusr & MMU_NUM) {
case 1:
- return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
+ return (*descaddr & 0xfe000000) | ((unsigned long)vaddr & 0x01ffffff);
case 2:
- return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
+ return (*descaddr & 0xfffc0000) | ((unsigned long)vaddr & 0x0003ffff);
case 3:
- return (*descaddr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+ return (*descaddr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1));
default:
- panic ("VTOP: bad levels (%u) for virtual address %08lx",
+ printk("VTOP: bad levels (%u) for virtual address %lx\n",
mmusr & MMU_NUM, vaddr);
}
}
- panic ("VTOP: bad virtual address %08lx", vaddr);
+ printk("VTOP: bad virtual address %lx\n", vaddr);
+ return -1;
}
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
-unsigned long mm_ptov (unsigned long paddr)
+void *mm_ptov (unsigned long paddr)
{
int i = 0;
- unsigned long offset = 0;
+ unsigned long poff, voff = PAGE_OFFSET;
- do{
- if (paddr >= m68k_memory[i].addr &&
- paddr < (m68k_memory[i].addr
- + m68k_memory[i].size)) {
+ do {
+ poff = paddr - m68k_memory[i].addr;
+ if (poff < m68k_memory[i].size) {
#ifdef DEBUGPV
- printk ("PTOV(%lx)=%lx\n", paddr,
- (paddr - m68k_memory[i].addr) + offset);
+ printk ("PTOV(%lx)=%lx\n", paddr, poff + voff);
+#endif
+ return (void *)(poff + voff);
+ }
+ voff += m68k_memory[i].size;
+ } while (++i < m68k_num_memory);
+
+#if DEBUG_INVALID_PTOV
+ if (mm_inv_cnt > 0) {
+ mm_inv_cnt--;
+ printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!\n",
+ paddr, __builtin_return_address(0));
+ }
#endif
- return (paddr - m68k_memory[i].addr) + offset;
- } else
- offset += m68k_memory[i].size;
- i++;
- }while (i < m68k_num_memory);
-
/*
* assume that the kernel virtual address is the same as the
* physical address.
* to the ZTWO_VADDR range
*/
if (MACH_IS_AMIGA && paddr < 16*1024*1024)
- return ZTWO_VADDR(paddr);
+ return (void *)ZTWO_VADDR(paddr);
#endif
- return paddr;
+ return (void *)-1;
}
#endif
* for more details.
*/
-#include <stdarg.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
*/
#include <linux/config.h>
-#include <stdarg.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
* for more details.
*/
-#include <stdarg.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
CONSTRUCTORS
}
- .bss : { *(.bss) } /* BSS */
-
_edata = .; /* End of data section */
- . = ALIGN(16);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ . = ALIGN(8192);
+ init_task : { *(init_task) }
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
+ . = ALIGN(16);
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
. = ALIGN(8192);
__init_end = .;
- init_task : { *(init_task) } /* The initial task and kernel stack */
+ . = ALIGN(16);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ __bss_start = .; /* BSS */
+ .bss : {
+ *(.bss)
+ }
_end = . ;
/* Stabs debugging sections. */
switch (cmode)
{
- case KERNELMAP_FULL_CACHING:
+ case IOMAP_FULL_CACHING:
mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
flags = 0;
break;
- case KERNELMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_SER:
mask = ~0;
flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
break;
EXPORT_SYMBOL(abs);
EXPORT_SYMBOL(device_is_compatible);
+
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(screen_info);
+#endif
-/* $Id: srmmu.c,v 1.189 1999/07/30 09:35:08 davem Exp $
+/* $Id: srmmu.c,v 1.190 1999/08/07 17:47:01 anton Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
#define srmmu_ahashfn(addr) ((addr) >> 24)
int viking_mxcc_present = 0;
+static spinlock_t srmmu_context_spinlock = SPIN_LOCK_UNLOCKED;
/* Physical memory can be _very_ non-contiguous on the sun4m, especially
* the SS10/20 class machines and with the latest openprom revisions.
static void srmmu_switch_to_context(struct task_struct *tsk)
{
if(tsk->mm->context == NO_CONTEXT) {
+ spin_lock(&srmmu_context_spinlock);
alloc_context(tsk->mm);
+ spin_unlock(&srmmu_context_spinlock);
ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
}
srmmu_set_context(tsk->mm->context);
static void srmmu_init_new_context(struct mm_struct *mm)
{
+ spin_lock(&srmmu_context_spinlock);
alloc_context(mm);
+ spin_unlock(&srmmu_context_spinlock);
flush_cache_mm(mm);
ctxd_set(&srmmu_context_table[mm->context], mm->pgd);
if(tsk->mm->context == NO_CONTEXT) {
ctxd_t *ctxp;
+ spin_lock(&srmmu_context_spinlock);
alloc_context(tsk->mm);
+ spin_unlock(&srmmu_context_spinlock);
ctxp = &srmmu_context_table[tsk->mm->context];
srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
hypersparc_flush_page_to_ram((unsigned long)ctxp);
{
ctxd_t *ctxp;
+ spin_lock(&srmmu_context_spinlock);
alloc_context(mm);
+ spin_unlock(&srmmu_context_spinlock);
ctxp = &srmmu_context_table[mm->context];
srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
-/* $Id: ioctl32.c,v 1.65 1999/07/30 09:35:19 davem Exp $
+/* $Id: ioctl32.c,v 1.66 1999/08/08 01:37:06 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
--- /dev/null
+
+The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by
+Geert Uytterhoeven based on the following specifications:
+
+------------------------------------------------------------------------
+
+Register map of the Buddha IDE controller and the
+Buddha-part of the Catweasel Zorro-II version
+
+The Autoconfiguration has been implemented just as Commodore
+described in their manuals, no tricks have been used (for
+example leaving some address lines out of the equations...).
+If you want to configure the board yourself (for example let
+a Linux kernel configure the card), look at the Commodore
+Docs. Reading the nibbles should give this information:
+
+Vendor number: 4626 ($1212)
+product number: 0 (42 for Catweasel Z-II)
+Serial number: 0
+Rom-vector: $1000
+
+The card should be a Z-II board, size 64K, not for freemem
+list, Rom-Vektor is valid, no second Autoconfig-board on the
+same card, no space preferrence, supports "Shutup_forever".
+
+Setting the base address should be done in two steps, just
+as the Amiga Kickstart does: The lower nibble of the 8-Bit
+address is written to $4a, then the whole Byte is written to
+$48, while it doesn't matter how often you're writing to $4a
+as long as $48 is not touched. After $48 has been written,
+the whole card disappears from $e8 and is mapped to the new
+addrress just written. Make shure $4a is written befor $48,
+otherwise your chance is only 1:16 to find the board :-).
+
+The local memory-map is even active when mapped to $e8:
+
+$0-$7e Autokonfig-space, see Z-II docs.
+
+$80-$7fd reserved
+
+$7fe Speed-select Register: Read & Write
+ (description see further down)
+
+$800-$8ff IDE-Select 0 (Port 0, Register set 0)
+
+$900-$9ff IDE-Select 1 (Port 0, Register set 1)
+
+$a00-$aff IDE-Select 2 (Port 1, Register set 0)
+
+$b00-$bff IDE-Select 3 (Port 1, Register set 1)
+
+$c00-$cff IDE-Select 4 (Port 2, Register set 0,
+ Catweasel only!)
+
+$d00-$dff IDE-Select 5 (Port 3, Register set 1,
+ Catweasel only!)
+
+$e00-$eff local expansion port, on Catweasel Z-II the
+ Catweasel registers are also mapped here.
+ Never touch, use multidisk.device!
+
+$f00 read only, Byte-access: Bit 7 shows the
+ level of the IRQ-line of IDE port 0.
+
+$f01-$f3f mirror of $f00
+
+$f40 read only, Byte-access: Bit 7 shows the
+ level of the IRQ-line of IDE port 1.
+
+$f41-$f7f mirror of $f40
+
+$f80 read only, Byte-access: Bit 7 shows the
+ level of the IRQ-line of IDE port 2.
+ (Catweasel only!)
+
+$f81-$fbf mirror of $f80
+
+$fc0 write-only: Writing any value to this
+ register enables IRQs to be passed from the
+ IDE ports to the Zorro bus. This mechanism
+ has been implemented to be compatible with
+ harddisks that are either defective or have
+ a buggy firmware and pull the IRQ line up
+ while starting up. If interrupts would
+ always be passed to the bus, the computer
+ might not start up. Once enabled, this flag
+ can not be disabled again. The level of the
+ flag can not be determined by software
+ (what for? Write to me if it's necessary!).
+
+$fc1-$fff mirror of $fc0
+
+$1000-$ffff Buddha-Rom with offset $1000 in the rom
+ chip. The addresses $0 to $fff of the rom
+ chip cannot be read. Rom is Byte-wide and
+ mapped to even addresses.
+
+The IDE ports issue an INT2. You can read the level of the
+IRQ-lines of the IDE-ports by reading from the three (two
+for Buddha-only) registers $f00, $f40 and $f80. This way
+more than one I/O request can be handled and you can easily
+determine what driver has to serve the INT2. Buddha and
+Catweasel expansion boards can issue an INT6. A seperate
+memory map is available for the I/O module and the sysop's
+I/O module.
+
+The IDE ports are fed by the address lines A2 to A4, just as
+the Amiga 1200 and Amiga 4000 IDE ports are. This way
+existing drivers can be easily ported to Buddha. A move.l
+polls two words out of the same address of IDE port since
+every word is mirrored once. movem is not possible, but
+it's not necessary either, because you can only speedup
+68000 systems with this technique. A 68020 system with
+fastmem is faster with move.l.
+
+If you're using the mirrored registers of the IDE-ports with
+A6=1, the Buddha doesn't care about the speed that you have
+selected in the speed register (see further down). With
+A6=1 (for example $840 for port 0, register set 0), a 780ns
+access is being made. These registers should be used for a
+command access to the harddisk/CD-Rom, since command
+accesses are Byte-wide and have to be made slower according
+to the ATA-X3T9 manual.
+
+Now for the speed-register: The register is byte-wide, and
+only the upper three bits are used (Bits 7 to 5). Bit 4
+must always be set to 1 to be compatible with later Buddha
+versions (if I'll ever update this one). I presume that
+I'll never use the lower four bits, but they have to be set
+to 1 by definition.
+ The values in this table have to be shifted 5 bits to the
+left and or'd with $1f (this sets the lower 5 bits).
+
+All the timings have in common: Select and IOR/IOW rise at
+the same time. IOR and IOW have a propagation delay of
+about 30ns to the clocks on the Zorro bus, that's why the
+values are no multiple of 71. One clock-cycle is 71ns long
+(exactly 70,5 at 14,18 Mhz on PAL systems).
+
+value 0 (Default after reset)
+
+497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles)
+(same timing as the Amiga 1200 does on it's IDE port without
+accelerator card)
+
+value 1
+
+639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles)
+
+value 2
+
+781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles)
+
+value 3
+
+355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)
+
+value 4
+
+355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles)
+
+value 5
+
+355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles)
+
+value 6
+
+1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles)
+
+value 7
+
+355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)
+
+When accessing IDE registers with A6=1 (for example $84x),
+the timing will always be mode 0 8-bit compatible, no matter
+what you have selected in the speed register:
+
+781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive.
+
+All the timings with a very short select-signal (the 355ns
+fast accesses) depend on the accelerator card used in the
+system: Sometimes two more clock cycles are inserted by the
+bus interface, making the whole access 497ns long. This
+doesn't affect the reliability of the controller nor the
+performance of the card, since this doesn't happen very
+often.
+
+All the timings are calculated and only confirmed by
+measurements that allowed me to count the clock cycles. If
+the system is clocked by an oscillator other than 28,37516
+Mhz (for example the NTSC-frequency 28,63636 Mhz), each
+clock cycle is shortened to a bit less than 70ns (not worth
+mentioning). You could think of a small performance boost
+by overclocking the system, but you would either need a
+multisync monitor, or a graphics card, and your internal
+diskdrive would go crazy, that's why you shouldn't tune your
+Amiga this way.
+
+Giving you the possibility to write software that is
+compatible with both the Buddha and the Catweasel Z-II, The
+Buddha acts just like a Catweasel Z-II with no device
+connected to the third IDE-port. The IRQ-register $f80
+always shows a "no IRQ here" on the Buddha, and accesses to
+the third IDE port are going into data's Nirwana on the
+Buddha.
+
+ Jens Schönfeld february 19th, 1997
+ updated may 27th, 1997
+ eMail: sysop@nostlgic.tng.oche.de
+
static char *CurrentBuffer;
-#define SET_TIMER() \
- do { \
- del_timer( &acsi_timer ); \
- acsi_timer.expires = jiffies + ACSI_TIMEOUT; \
- add_timer( &acsi_timer ); \
- } while(0)
-
-#define CLEAR_TIMER() \
- do { \
- del_timer( &acsi_timer ); \
- } while(0)
+#define SET_TIMER() mod_timer(&acsi_timer, jiffies + ACSI_TIMEOUT)
+#define CLEAR_TIMER() del_timer(&acsi_timer)
static unsigned long STramMask;
#define STRAM_ADDR(a) (((a) & STramMask) == 0)
{
if (INT_LEVEL < 6) {
- unsigned long maxjif;
- for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); )
+ unsigned long maxjif = jiffies + timeout;
+ while (time_before(jiffies, maxjif))
if (!(mfp.par_dt_reg & 0x20)) return( 1 );
}
else {
{
if (INT_LEVEL < 6) {
- unsigned long maxjif;
- for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); )
+ unsigned long maxjif = jiffies + timeout;
+ while (time_before(jiffies, maxjif))
if (mfp.par_dt_reg & 0x20) return( 1 );
}
else {
#endif
rwflag = rwflag ? 0x100 : 0;
- paddr = VTOP( buffer );
+ paddr = virt_to_phys( buffer );
acsi_delay_end(COMMAND_DELAY);
DISABLE_IRQ();
if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 );
if (!acsi_wait_for_IRQ( 10 )) return( 0 );
acsi_getstatus();
- dma_cache_maintenance( VTOP(buffer), 16, 0 );
+ dma_cache_maintenance( virt_to_phys(buffer), 16, 0 );
return( 1 );
}
return;
}
- dma_cache_maintenance( VTOP(CurrentBuffer), CurrentNSect*512, 0 );
+ dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 );
if (CurrentBuffer == acsi_buffer)
copy_from_acsibuffer();
* consecutive buffers and thus can be done with a single command.
*/
buffer = CURRENT->buffer;
- pbuffer = VTOP(buffer);
+ pbuffer = virt_to_phys(buffer);
nsect = CURRENT->current_nr_sectors;
CurrentNReq = 1;
unsigned long pendadr, pnewadr;
pendadr = pbuffer + nsect*512;
while( (bh = bh->b_reqnext) ) {
- pnewadr = VTOP(bh->b_data);
+ pnewadr = virt_to_phys(bh->b_data);
if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break;
nsect += bh->b_size >> 9;
pendadr = pnewadr + bh->b_size;
unregister_blkdev( MAJOR_NR, "ad" );
return -ENOMEM;
}
- phys_acsi_buffer = VTOP( acsi_buffer );
+ phys_acsi_buffer = virt_to_phys( acsi_buffer );
STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
CMDSET_TARG_LUN( slmprint_cmd, sip->target, sip->lun );
cmd = slmprint_cmd;
- paddr = VTOP( SLMBuffer );
- dma_cache_maintenance( paddr, VTOP(BufferP)-paddr, 1 );
+ paddr = virt_to_phys( SLMBuffer );
+ dma_cache_maintenance( paddr, virt_to_phys(BufferP)-paddr, 1 );
DISABLE_IRQ();
/* Low on A1 */
addr = get_dma_addr();
stat = acsi_getstatus();
SLMError = (stat < 0) ? SLMSTAT_ACSITO :
- (addr < VTOP(BufferP)) ? SLMSTAT_NOTALL :
+ (addr < virt_to_phys(BufferP)) ? SLMSTAT_NOTALL :
stat;
dma_wd.dma_mode_status = 0x80;
* restored upon disk change by floppy_revalidate() if valid (as seen by
* default_params[].blocks > 0 - a bit in unit[].flags might be used for this?)
*/
-static struct atari_disk_type default_params[FD_MAX_UNITS] = {
- { NULL, 0, 0, 0, 0}, };
+static struct atari_disk_type default_params[FD_MAX_UNITS];
static int floppy_sizes[256];
-static int floppy_blocksizes[256] = { 0, };
+static int floppy_blocksizes[256];
/* current info on each unit */
static struct atari_floppy_struct {
* will give up. */
-#define START_MOTOR_OFF_TIMER(delay) \
- do { \
- motor_off_timer.expires = jiffies + (delay); \
- add_timer( &motor_off_timer ); \
- MotorOffTrys = 0; \
- } while(0)
-
-#define START_CHECK_CHANGE_TIMER(delay) \
- do { \
- timer_table[FLOPPY_TIMER].expires = jiffies + (delay); \
- timer_active |= (1 << FLOPPY_TIMER); \
- } while(0)
-
-#define START_TIMEOUT() \
- mod_timer(&timeout_timer, jiffies + FLOPPY_TIMEOUT)
-
-#define STOP_TIMEOUT() \
- del_timer(&timeout_timer)
-
-
/*
* The driver is trying to determine the correct media format
* while Probing is set. fd_rwsec_done() clears it after a
{ NULL, NULL, 0, 0, fd_times_out };
+static inline void
+start_motor_off_timer(void)
+{
+ mod_timer(&motor_off_timer, jiffies + FD_MOTOR_OFF_DELAY);
+ MotorOffTrys = 0;
+}
+
+static inline void
+start_check_change_timer(void)
+{
+ timer_table[FLOPPY_TIMER].expires = jiffies + CHECK_CHANGE_DELAY;
+ timer_active |= (1 << FLOPPY_TIMER);
+}
+
+static inline void
+start_timeout(void)
+{
+ mod_timer(&timeout_timer, jiffies + FLOPPY_TIMEOUT);
+}
+
+static inline void
+stop_timeout(void)
+{
+ del_timer(&timeout_timer);
+}
/* Select the side to use. */
static void fd_motor_off_timer( unsigned long dummy )
{
-/* unsigned long flags; */
unsigned char status;
- int delay;
- del_timer( &motor_off_timer );
-
if (SelectedDrive < 0)
/* no drive selected, needn't deselect anyone */
return;
-/* save_flags(flags);
- cli(); */
-
if (stdma_islocked())
goto retry;
/* motor already turned off by FDC -> deselect drives */
MotorOn = 0;
fd_deselect();
-/* restore_flags(flags); */
return;
}
/* not yet off, try again */
retry:
-/* restore_flags(flags); */
/* Test again later; if tested too often, it seems there is no disk
* in the drive and the FDC will leave the motor on forever (or,
* at least until a disk is inserted). So we'll test only twice
* per second from then on...
*/
- delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
- (++MotorOffTrys, HZ/20) : HZ/2;
- START_MOTOR_OFF_TIMER( delay );
+ mod_timer(&motor_off_timer,
+ jiffies + (MotorOffTrys++ < FD_MOTOR_OFF_MAXTRY ? HZ/20 : HZ/2));
}
}
restore_flags(flags);
- START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
+ start_check_change_timer();
}
unsigned char status;
void (*handler)( int );
- handler = FloppyIRQHandler;
- FloppyIRQHandler = NULL;
+ handler = xchg(&FloppyIRQHandler, NULL);
if (handler) {
nop();
NeedSeek = 1;
MotorOn = 1;
- START_TIMEOUT();
+ start_timeout();
/* wait for IRQ */
}
static void fd_calibrate_done( int status )
{
DPRINT(("fd_calibrate_done()\n"));
- STOP_TIMEOUT();
+ stop_timeout();
/* set the correct speed now */
if (ATARIHW_PRESENT(FDCSPEED))
MotorOn = 1;
set_head_settle_flag();
- START_TIMEOUT();
+ start_timeout();
/* wait for IRQ */
}
static void fd_seek_done( int status )
{
DPRINT(("fd_seek_done()\n"));
- STOP_TIMEOUT();
+ stop_timeout();
/* set the correct speed */
if (ATARIHW_PRESENT(FDCSPEED))
DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n",ReqSector, ReqCmd == WRITE ? 'w' : 'r' ));
if (ReqCmd == WRITE) {
if (ATARIHW_PRESENT(EXTD_DMA)) {
- paddr = (unsigned long)VTOP(ReqData);
+ paddr = virt_to_phys(ReqData);
}
else {
copy_buffer( ReqData, DMABuffer );
if (read_track)
paddr = PhysTrackBuffer;
else
- paddr = ATARIHW_PRESENT(EXTD_DMA) ? VTOP(ReqData) : PhysDMABuffer;
+ paddr = ATARIHW_PRESENT(EXTD_DMA) ?
+ virt_to_phys(ReqData) : PhysDMABuffer;
rwflag = 0;
}
* search for the first non-existent sector and need 1 sec to
* recognise that it isn't present :-(
*/
- del_timer (&readtrack_timer);
- readtrack_timer.expires =
- jiffies + HZ/5 + (old_motoron ? 0 : HZ);
- /* 1 rot. + 5 rot.s if motor was off */
MultReadInProgress = 1;
- add_timer( &readtrack_timer );
+ mod_timer(&readtrack_timer,
+ /* 1 rot. + 5 rot.s if motor was off */
+ jiffies + HZ/5 + (old_motoron ? 0 : HZ));
}
- START_TIMEOUT();
+ start_timeout();
}
save_flags(flags);
cli();
- del_timer( &readtrack_timer );
-
if (!MultReadInProgress) {
/* This prevents a race condition that could arise if the
* interrupt is triggered while the calling of this timer
/* not yet finished, wait another tenth rotation */
restore_flags(flags);
DPRINT(("fd_readtrack_check(): not yet finished\n"));
- readtrack_timer.expires = jiffies + HZ/5/10;
- add_timer( &readtrack_timer );
+ mod_timer(&readtrack_timer, jiffies + HZ/5/10);
}
}
{
unsigned int track;
- STOP_TIMEOUT();
+ stop_timeout();
/* Correct the track if stretch != 0 */
if (SUDT->stretch) {
if (!read_track) {
void *addr;
addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer;
- dma_cache_maintenance( VTOP(addr), 512, 0 );
+ dma_cache_maintenance( virt_to_phys(addr), 512, 0 );
if (!ATARIHW_PRESENT( EXTD_DMA ))
copy_buffer (addr, ReqData);
} else {
dma_wd.fdc_acces_seccount = FDCCMD_WRTRA | get_head_settle_flag();
MotorOn = 1;
- START_TIMEOUT();
+ start_timeout();
/* wait for interrupt */
}
{
DPRINT(("fd_writetrack_done()\n"));
- STOP_TIMEOUT();
+ stop_timeout();
if (status & FDCSTAT_WPROT) {
printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive );
SET_IRQ_HANDLER( finish_fdc_done );
FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK);
MotorOn = 1;
- START_TIMEOUT();
+ start_timeout();
/* we must wait for the IRQ here, because the ST-DMA
is released immediately afterwards and the interrupt
may be delivered to the wrong driver. */
unsigned long flags;
DPRINT(("finish_fdc_done entered\n"));
- STOP_TIMEOUT();
+ stop_timeout();
NeedSeek = 0;
if ((timer_active & (1 << FLOPPY_TIMER)) &&
- timer_table[FLOPPY_TIMER].expires < jiffies + 5)
+ time_before(timer_table[FLOPPY_TIMER].expires, jiffies + 5))
/* If the check for a disk change is done too early after this
* last seek command, the WP bit still reads wrong :-((
*/
timer_table[FLOPPY_TIMER].expires = jiffies + 5;
else
- START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
- del_timer( &motor_off_timer );
- START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
+ start_check_change_timer();
+ start_motor_off_timer();
save_flags(flags);
cli();
FDC_WRITE (FDCREG_TRACK, 0xff00);
FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 );
- for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; time_before(jiffies, timeout); ) {
+ timeout = jiffies + 2*HZ+HZ/2;
+ while (time_before(jiffies, timeout))
if (!(mfp.par_dt_reg & 0x20))
break;
- }
status = FDC_READ( FDCREG_STATUS );
ok = (status & FDCSTAT_TR00) != 0;
}
if (cnt > 0) {
- START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
+ start_motor_off_timer();
if (cnt == 1) fd_select_drive( 0 );
- START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
+ start_check_change_timer();
}
}
return -ENOMEM;
}
TrackBuffer = DMABuffer + 512;
- PhysDMABuffer = (unsigned long) VTOP(DMABuffer);
- PhysTrackBuffer = (unsigned long) VTOP(TrackBuffer);
+ PhysDMABuffer = virt_to_phys(DMABuffer);
+ PhysTrackBuffer = virt_to_phys(TrackBuffer);
BufferDrive = BufferSide = BufferTrack = -1;
for (i = 0; i < FD_MAX_UNITS; i++) {
struct packet_command pc;
ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ /* here we queue the commands from the uniform CD-ROM
+ layer. the packet must be complete, as we do not
+ touch it at all. */
memset(&pc, 0, sizeof(pc));
memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
pc.buffer = cgc->buffer;
* settings of split-mirror pci-config space, place chipset into init-mode,
* and/or preserve an interrupt if the card is not native ide support.
*/
-__initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const char *name))
+static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
{
switch(dev->device) {
case PCI_DEVICE_ID_TTI_HPT343:
* Match a PCI IDE port against an entry in ide_hwifs[],
* based on io_base port if possible.
*/
-__initfunc(static ide_hwif_t *ide_match_hwif (unsigned long io_base, byte bootable, const char *name))
+static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)
{
int h;
ide_hwif_t *hwif;
return NULL;
}
-__initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name))
+static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
{
byte reg, progif = 0;
* we "know" about, this information is in the ide_pci_device_t struct;
* for all other chipsets, we just assume both interfaces are enabled.
*/
-__initfunc(static void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d))
+static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
{
unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
unsigned short pcicmd = 0, tried_config = 0;
* ide_scan_pcibus() gets invoked at boot time from ide.c.
* It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
*/
-__initfunc(void ide_scan_pcibus (void))
+void __init ide_scan_pcibus (void)
{
struct pci_dev *dev;
ide_pci_devid_t devid;
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-__initfunc(static void
-pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif))
+static void __init
+pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif)
{
hwif->dma_base = (unsigned long) ioremap(np->addrs[1].address, 0x200);
* stridx() returns the offset of c within s,
* or -1 if c is '\0' or not found within s.
*/
-__initfunc(static int stridx (const char *s, char c))
+static int __init stridx (const char *s, char c)
{
char *i = strchr(s, c);
return (i && c) ? i - s : -1;
* and base16 is allowed when prefixed with "0x".
* 4. otherwise, zero is returned.
*/
-__initfunc(static int match_parm (char *s, const char *keywords[], int vals[], int max_vals))
+static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals)
{
static const char *decimal = "0123456789";
static const char *hex = "0123456789abcdef";
* "ide0=ali14xx" : probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
* "ide0=umc8672" : probe/support umc8672 chipsets
* "idex=dc4030" : probe/support Promise DC4030VL interface
+ * "ide=doubler" : probe/support IDE doublers on Amiga
*/
-__initfunc(void ide_setup (char *s))
+void __init ide_setup (char *s)
{
int i, vals[3];
ide_hwif_t *hwif;
/*
* probe_for_hwifs() finds/initializes "known" IDE interfaces
*/
-__initfunc(static void probe_for_hwifs (void))
+static void __init probe_for_hwifs (void)
{
#ifdef CONFIG_PCI
if (pci_present())
#endif /* CONFIG_BLK_DEV_BUDDHA */
}
-__initfunc(void ide_init_builtin_drivers (void))
+void __init ide_init_builtin_drivers (void)
{
/*
* Probe for special PCI and other "known" interface chipsets
/*
* This is gets invoked once during initialization, to set *everything* up
*/
-__initfunc(int ide_init (void))
+int __init ide_init (void)
{
static char banner_printed = 0;
char *options = NULL;
MODULE_PARM(options,"s");
-__initfunc(static void parse_options (char *line))
+static void __init parse_options (char *line)
{
char *next = line;
#ifndef MODULE
-__initfunc(void linear_init (void))
+void __init linear_init (void)
{
register_md_personality (LINEAR, &linear_personality);
}
* with the request-lists in peace. Thus it should be called with no spinlocks
* held.
*
- * By this point, req->cmd is always either READ/WRITE, never READA/WRITEA,
+ * By this point, req->cmd is always either READ/WRITE, never READA,
* which is important for drive_stat_acct() above.
*/
}
}
- rw_ahead = 0; /* normal case; gets changed below for READA/WRITEA */
+ rw_ahead = 0; /* normal case; gets changed below for READA */
switch (rw) {
case READA:
rw_ahead = 1;
case WRITERAW:
rw = WRITE;
goto do_write; /* Skip the buffer refile */
- case WRITEA:
- rw_ahead = 1;
- rw = WRITE; /* drop into WRITE */
case WRITE:
if (!test_and_clear_bit(BH_Dirty, &bh->b_state))
goto end_io; /* Hmmph! Nothing to write */
struct blk_dev_struct * dev;
int i;
- /* Make sure that the first block contains something reasonable */
- while (!*bh) {
- bh++;
- if (--nr <= 0)
- return;
- }
-
dev = NULL;
if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
dev = blk_dev + major;
}
for (i = 0; i < nr; i++) {
- if (bh[i]) {
- set_bit(BH_Req, &bh[i]->b_state);
+ set_bit(BH_Req, &bh[i]->b_state);
#ifdef CONFIG_BLK_DEV_MD
- if (MAJOR(bh[i]->b_dev) == MD_MAJOR) {
- md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]);
- continue;
- }
-#endif
- make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]);
+ if (MAJOR(bh[i]->b_dev) == MD_MAJOR) {
+ md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]);
+ continue;
}
+#endif
+ make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]);
}
return;
sorry:
for (i = 0; i < nr; i++) {
- if (bh[i]) {
- clear_bit(BH_Dirty, &bh[i]->b_state);
- clear_bit(BH_Uptodate, &bh[i]->b_state);
- bh[i]->b_end_io(bh[i], 0);
- }
+ clear_bit(BH_Dirty, &bh[i]->b_state);
+ clear_bit(BH_Uptodate, &bh[i]->b_state);
+ bh[i]->b_end_io(bh[i], 0);
}
return;
}
};
/* called from init/main.c */
-__initfunc(void md_setup(char *str,int *ints))
+void __init md_setup(char *str,int *ints)
{
int i;
for(i=0;i<=ints[0];i++) {
return;
}
-__initfunc(void do_md_setup(char *str,int *ints))
+void __init do_md_setup(char *str,int *ints)
{
int minor, pers, factor, fault;
kdev_t dev;
void raid1_init (void);
void raid5_init (void);
-__initfunc(int md_init (void))
+int __init md_init (void)
{
printk ("md driver %d.%d.%d MAX_MD_DEV=%d, MAX_REAL=%d\n",
MD_MAJOR_VERSION, MD_MINOR_VERSION, MD_PATCHLEVEL_VERSION,
}
#ifdef CONFIG_MD_BOOT
-__initfunc(void md_setup_drive(void))
+void __init md_setup_drive(void)
{
if(md_setup_args.set)
do_md_setup(md_setup_args.str, md_setup_args.ints);
}
}
-__initfunc(void ide_init_ns87415 (ide_hwif_t *hwif))
+void __init ide_init_ns87415 (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int ctrl, using_inta;
};
/* initialization routine called by ll_rw_blk.c */
-__initfunc(int ps2esdi_init(void))
+int __init ps2esdi_init(void)
{
/* register the device - pass the name, major number and operations
#endif /* MODULE */
/* handles boot time command line parameters */
-__initfunc(void tp720_setup(char *str, int *ints))
+void __init tp720_setup(char *str, int *ints)
{
/* no params, just sets the tp720esdi flag if it exists */
tp720esdi = 1;
}
-__initfunc(void ed_setup(char *str, int *ints))
+void __init ed_setup(char *str, int *ints)
{
int hdind = 0;
}
/* ps2 esdi specific initialization - called thru the gendisk chain */
-__initfunc(static void ps2esdi_geninit(struct gendisk *ignored))
+static void __init ps2esdi_geninit(struct gendisk *ignored)
{
/*
The first part contains the initialization code
} /* ps2esdi_geninit */
-__initfunc(static void ps2esdi_get_device_cfg(void))
+static void __init ps2esdi_get_device_cfg(void)
{
u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];
--- /dev/null
+/*
+ * linux/drivers/block/q40ide.c -- Q40 I/O port IDE Driver
+ *
+ * original file created 12 Jul 1997 by Geert Uytterhoeven
+ *
+ * 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.
+ *
+ * RZ:
+ * almost identical with pcide.c, maybe we can merge it later.
+ * Differences:
+ * max 2 HWIFS for now
+ * translate portaddresses to q40 native addresses (not yet...) instead rely on in/out[bw]
+ * address translation
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include "ide.h"
+
+ /*
+ * Bases of the IDE interfaces
+ */
+
+#define PCIDE_NUM_HWIFS 2
+
+#define PCIDE_BASE1 0x1f0
+#define PCIDE_BASE2 0x170
+#define PCIDE_BASE3 0x1e8
+#define PCIDE_BASE4 0x168
+#define PCIDE_BASE5 0x1e0
+#define PCIDE_BASE6 0x160
+
+static const q40ide_ioreg_t pcide_bases[PCIDE_NUM_HWIFS] = {
+ PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5,
+ PCIDE_BASE6 */
+};
+
+
+ /*
+ * Offsets from one of the above bases
+ */
+
+#undef HD_DATA
+#define HD_DATA 0x1f0
+
+#define PCIDE_REG(x) ((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
+
+static const int pcide_offsets[IDE_NR_PORTS] = {
+ PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
+ PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
+ PCIDE_REG(CMD)
+};
+
+int q40ide_default_irq(q40ide_ioreg_t base)
+{
+ switch (base) {
+ case 0x1f0: return 14;
+ case 0x170: return 15;
+ case 0x1e8: return 11;
+ default:
+ return 0;
+ }
+}
+
+void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq)
+{
+ q40ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = base + 0x206;
+ if (irq != NULL)
+ *irq = 0;
+}
+
+
+ /*
+ * Probe for PC IDE interfaces
+ */
+
+int q40ide_probe_hwif(int index, ide_hwif_t *hwif)
+{
+ static int pcide_index[PCIDE_NUM_HWIFS] = { 0, };
+ int i;
+
+ if (!MACH_IS_Q40)
+ return 0;
+
+ for (i = 0; i < PCIDE_NUM_HWIFS; i++) {
+ if (!pcide_index[i]) {
+ /*printk("ide%d: Q40 IDE interface\n", index);*/
+ pcide_index[i] = index+1;
+ }
+ if (pcide_index[i] == index+1) {
+ ide_setup_ports(hwif,(ide_ioreg_t) pcide_bases[i], pcide_offsets, 0, /*q40_ack_intr???*/ NULL);
+ hwif->irq = ide_default_irq((ide_ioreg_t)pcide_bases[i]); /*q40_ide_irq[i]; */ /* 14 */
+ return 1;
+ }
+ }
+ return 0;
+}
};
/* This is the registration and initialization section of the RAM disk driver */
-__initfunc(int rd_init(void))
+int __init rd_init(void)
{
int i;
* romfs
* gzip
*/
-__initfunc(int
-identify_ramdisk_image(kdev_t device, struct file *fp, int start_block))
+int __init
+identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)
{
const int size = 512;
struct minix_super_block *minixsb;
/*
* This routine loads in the RAM disk image.
*/
-__initfunc(static void rd_load_image(kdev_t device, int offset, int unit))
+static void __init rd_load_image(kdev_t device, int offset, int unit)
{
struct inode inode, out_inode;
struct file infile, outfile;
}
-__initfunc(static void rd_load_disk(int n))
+static void __init rd_load_disk(int n)
{
#ifdef CONFIG_BLK_DEV_INITRD
extern kdev_t real_root_dev;
}
-__initfunc(void rd_load(void))
+void __init rd_load(void)
{
rd_load_disk(0);
}
-__initfunc(void rd_load_secondary(void))
+void __init rd_load_secondary(void)
{
rd_load_disk(1);
}
#ifdef CONFIG_BLK_DEV_INITRD
-__initfunc(void initrd_load(void))
+void __init initrd_load(void)
{
rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0);
}
#include "../../lib/inflate.c"
-__initfunc(static void *malloc(int size))
+static void __init *malloc(int size)
{
return kmalloc(size, GFP_KERNEL);
}
-__initfunc(static void free(void *where))
+static void __init free(void *where)
{
kfree(where);
}
-__initfunc(static void gzip_mark(void **ptr))
+static void __init gzip_mark(void **ptr)
{
}
-__initfunc(static void gzip_release(void **ptr))
+static void __init gzip_release(void **ptr)
{
}
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
-__initfunc(static int fill_inbuf(void))
+static int __init fill_inbuf(void)
{
if (exit_code) return -1;
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
-__initfunc(static void flush_window(void))
+static void __init flush_window(void)
{
ulg c = crc; /* temporary variable */
unsigned n;
outcnt = 0;
}
-__initfunc(static void error(char *x))
+static void __init error(char *x)
{
printk(KERN_ERR "%s", x);
exit_code = 1;
}
-__initfunc(static int
-crd_load(struct file * fp, struct file *outfp))
+static int __init
+crd_load(struct file * fp, struct file *outfp)
{
int result;
#ifdef CONFIG_BLK_DEV_IDEPCI
-__initfunc(void ide_init_rz1000 (ide_hwif_t *hwif)) /* called from ide-pci.c */
+void __init ide_init_rz1000 (ide_hwif_t *hwif) /* called from ide-pci.c */
{
unsigned short reg;
struct pci_dev *dev = hwif->pci_dev;
#else
-__initfunc(static void init_rz1000 (struct pci_dev *dev, const char *name))
+static void __init init_rz1000 (struct pci_dev *dev, const char *name)
{
unsigned short reg, h;
}
}
-__initfunc(void ide_probe_for_rz100x (void)) /* called from ide.c */
+void __init ide_probe_for_rz100x (void) /* called from ide.c */
{
struct pci_dev *dev = NULL;
/*
* Invoked from ide-dma.c at boot time.
*/
-__initfunc(void ide_init_trm290 (ide_hwif_t *hwif))
+void __init ide_init_trm290 (ide_hwif_t *hwif)
{
unsigned int cfgbase = 0;
unsigned long flags;
static int nodma = XD_DONT_USE_DMA;
/* xd_init: register the block device number and set up pointer tables */
-__initfunc(int xd_init (void))
+int __init xd_init (void)
{
if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
printk("xd: Unable to get major number %d\n",MAJOR_NR);
}
/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-__initfunc(static u_char xd_detect (u_char *controller, unsigned int *address))
+static __init u_char xd_detect (u_char *controller, unsigned int *address)
{
u_char i,j,found = 0;
/* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
/* and set up the "raw" device entries in the table */
-__initfunc(static void xd_geninit (struct gendisk *ignored))
+static void __init xd_geninit (struct gendisk *ignored)
{
u_char i,controller;
unsigned int address;
return (csb & CSB_ERROR);
}
-__initfunc(static u_char xd_initdrives (void (*init_drive)(u_char drive)))
+static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
{
u_char cmdblk[6],i,count = 0;
return (count);
}
-__initfunc(static void xd_manual_geo_set (u_char drive))
+static void __init xd_manual_geo_set (u_char drive)
{
xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
}
-__initfunc(static void xd_dtc_init_controller (unsigned int address))
+static void __init xd_dtc_init_controller (unsigned int address)
{
switch (address) {
case 0x00000:
}
-__initfunc(static void xd_dtc5150cx_init_drive (u_char drive))
+static void __init xd_dtc5150cx_init_drive (u_char drive)
{
/* values from controller's BIOS - BIOS chip may be removed */
static u_short geometry_table[][4] = {
xd_recalibrate(drive);
}
-__initfunc(static void xd_dtc_init_drive (u_char drive))
+static void __init xd_dtc_init_drive (u_char drive)
{
u_char cmdblk[6],buf[64];
printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
}
-__initfunc(static void xd_wd_init_controller (unsigned int address))
+static void __init xd_wd_init_controller (unsigned int address)
{
switch (address) {
case 0x00000:
sleep_on(&xdc_wait);
}
-__initfunc(static void xd_wd_init_drive (u_char drive))
+static void __init xd_wd_init_drive (u_char drive)
{
/* values from controller's BIOS - BIOS may be disabled */
static u_short geometry_table[][4] = {
}
-__initfunc(static void xd_seagate_init_controller (unsigned int address))
+static void __init xd_seagate_init_controller (unsigned int address)
{
switch (address) {
case 0x00000:
outb(0,XD_RESET); /* reset the controller */
}
-__initfunc(static void xd_seagate_init_drive (u_char drive))
+static void __init xd_seagate_init_drive (u_char drive)
{
u_char cmdblk[6],buf[0x200];
}
/* Omti support courtesy Dirk Melchers */
-__initfunc(static void xd_omti_init_controller (unsigned int address))
+static void __init xd_omti_init_controller (unsigned int address)
{
switch (address) {
case 0x00000:
outb(0,XD_RESET); /* reset the controller */
}
-__initfunc(static void xd_omti_init_drive (u_char drive))
+static void __init xd_omti_init_drive (u_char drive)
{
/* gets infos from drive */
xd_override_init_drive(drive);
}
/* Xebec support (AK) */
-__initfunc(static void xd_xebec_init_controller (unsigned int address))
+static void __init xd_xebec_init_controller (unsigned int address)
{
/* iobase may be set manually in range 0x300 - 0x33C
irq may be set manually to 2(9),3,4,5,6,7
sleep_on(&xdc_wait);
}
-__initfunc(static void xd_xebec_init_drive (u_char drive))
+static void __init xd_xebec_init_drive (u_char drive)
{
/* values from controller's BIOS - BIOS chip may be removed */
static u_short geometry_table[][5] = {
/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
-__initfunc(static void xd_override_init_drive (u_char drive))
+static void __init xd_override_init_drive (u_char drive)
{
u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
u_char cmdblk[6],i;
}
/* xd_setup: initialise controler from command line parameters */
-__initfunc(void xd_setup (char *command,int *integers))
+void __init xd_setup (char *command,int *integers)
{
switch (integers[0]) {
case 4: if (integers[4] < 0)
#ifndef MODULE
/* xd_manual_geo_init: initialise drive geometry from command line parameters
(used only for WD drives) */
-__initfunc(void xd_manual_geo_init (char *command,int *integers))
+void __init xd_manual_geo_init (char *command,int *integers)
{
int i;
if (integers[0]%3 != 0) {
#endif /* MODULE */
/* xd_setparam: set the drive characteristics */
-__initfunc(static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc))
+static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
{
u_char cmdblk[14];
#include <linux/malloc.h>
#include <linux/blk.h>
#include <linux/init.h>
-
-#if defined(MODULE)
#include <linux/module.h>
-#endif
#include <asm/setup.h>
#include <asm/bitops.h>
#include <asm/amigahw.h>
-#ifdef CONFIG_APUS
#include <asm/pgtable.h>
#include <asm/io.h>
-#endif
#include <linux/zorro.h>
-extern int num_memory;
-extern struct mem_info memory[NUM_MEMINFO];
+extern int m68k_realnum_memory;
+extern struct mem_info m68k_memory[NUM_MEMINFO];
#define TRUE (1)
#define FALSE (0)
int index = device - Z2MINOR_MEMLIST1 + 1;
unsigned long size, paddr, vaddr;
- if (index >= num_memory) {
+ if (index >= m68k_realnum_memory) {
printk( KERN_ERR DEVICE_NAME
": no such entry in z2ram_map\n" );
return -ENOMEM;
}
- paddr = memory[index].addr;
- size = memory[index].size & ~(Z2RAM_CHUNKSIZE-1);
+ paddr = m68k_memory[index].addr;
+ size = m68k_memory[index].size & ~(Z2RAM_CHUNKSIZE-1);
#ifdef __powerpc__
/* FIXME: ioremap doesn't build correct memory tables. */
_PAGE_WRITETHRU);
#else
- vaddr = kernel_map (paddr, size, KERNELMAP_FULL_CACHING,
- NULL);
+ vaddr = (unsigned long)ioremap(paddr, size);
#endif
z2ram_map =
kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]),
blk_size[ MAJOR_NR ] = z2_sizes;
}
-#if defined(MODULE)
MOD_INC_USE_COUNT;
-#endif
return 0;
}
sync_dev( inode->i_rdev );
-#if defined(MODULE)
+ /*
+ * FIXME: unmap memory
+ */
+
MOD_DEC_USE_COUNT;
-#endif
return 0;
}
NULL, /* revalidate */
};
-__initfunc(int
-z2_init( void ))
+int __init
+z2_init( void )
{
if ( !MACH_IS_AMIGA )
correctly.
-- Fix up ioctl handling so the device specific ones actually get
called :).
+
+ 3.02 Aug 8, 1999 - Jens Axboe <axboe@image.dk>
+ -- Fixed volume control on SCSI drives (or others with longer audio
+ page).
+ -- Fixed a couple of DVD minors. Thanks to Andrew T. Veliath
+ <andrewtv@usa.net> for telling me and for having defined the various
+ DVD structures and ioctls in the first place! He designed the original
+ DVD patches for ide-cd and while I rearranged and unified them, the
+ interface is still the same.
-------------------------------------------------------------------------*/
-#define REVISION "Revision: 3.01"
-#define VERSION "Id: cdrom.c 3.01 1999/08/06"
+#define REVISION "Revision: 3.02"
+#define VERSION "Id: cdrom.c 3.02 1999/08/08"
/* I use an error-log mask to give fine grain control over the type of
messages dumped to the system logs. The available masks include: */
* for example, need bit CDO_CHECK_TYPE cleared! */
if (tracks.data==0) {
if (cdi->options & CDO_CHECK_TYPE) {
+ /* give people a warning shot, now that CDO_CHECK_TYPE
+ is the default case! */
+ printk("cdrom: pid %d is buggy!\n", (unsigned int)current->pid);
cdinfo(CD_OPEN, "bummer. wrong media type.\n");
ret=-EMEDIUMTYPE;
goto clean_up_and_return;
case DVD_LU_SEND_ASF:
cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_ASF\n");
- setup_report_key (&cgc, ai->lsasf.agid, 5);
+ setup_report_key (&cgc, ai->lsasf.asf, 5);
cgc.buflen = cgc.cmd[9] = 8;
rv = cdo->generic_packet(cdi, &cgc);
/* Misc */
case DVD_INVALIDATE_AGID:
cdinfo(CD_DO_IOCTL, "entering DVD_INVALIDATE_AGID\n");
- setup_report_key (&cgc, ai->lsasf.agid, 0x3f);
+ setup_report_key (&cgc, ai->lsa.agid, 0x3f);
rv = cdo->generic_packet(cdi, &cgc);
if (rv)
int page_code, int page_control)
{
struct cdrom_device_ops *cdo = cdi->ops;
-
+
memset(cgc->cmd, 0, sizeof(cgc->cmd));
cgc->cmd[0] = 0x5a; /* MODE_SENSE_10 */
cgc->cmd[0] = 0x55; /* MODE_SELECT_10 */
cgc->cmd[1] = 0x10; /* PF */
- cgc->cmd[2] = 0x0e; /* PF */
/* generic_packet() wants the length as seen from the drive, i.e.
it will transfer data _to_ us. The CD-ROM wants the absolute
case CDROMVOLREAD: {
struct cdrom_volctrl volctrl;
char buffer[32], mask[32];
+ unsigned short offset;
cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");
IOCTL_IN(arg, struct cdrom_volctrl, volctrl);
cgc.buffer = buffer;
cgc.buflen = 24;
- rv = cdrom_mode_sense(cdi, &cgc, 0x0e, 0);
+ rv = cdrom_mode_sense(cdi, &cgc, 0xe, 0);
if (rv) return rv;
+ /* some drives have longer pages, adjust and reread. */
+ if (buffer[1] > cgc.buflen) {
+ cgc.buflen = buffer[1] + 2;
+ rv = cdrom_mode_sense(cdi, &cgc, 0xe, 0);
+ if (rv) return rv;
+ }
+
+ /* get the offset from the length of the page. length
+ is measure from byte 2 an on, thus the 14. */
+ offset = buffer[1] - 14;
+
/* now we have the current volume settings. if it was only
a CDROMVOLREAD, return these values */
if (cmd == CDROMVOLREAD) {
- volctrl.channel0 = buffer[17];
- volctrl.channel1 = buffer[19];
- volctrl.channel2 = buffer[21];
- volctrl.channel3 = buffer[23];
+ volctrl.channel0 = buffer[offset+9];
+ volctrl.channel1 = buffer[offset+11];
+ volctrl.channel2 = buffer[offset+13];
+ volctrl.channel3 = buffer[offset+15];
IOCTL_OUT(arg, struct cdrom_volctrl, volctrl);
return 0;
}
/* get the volume mask */
cgc.buffer = mask;
- rv = cdrom_mode_sense(cdi, &cgc, 0x0e, 1);
+ rv = cdrom_mode_sense(cdi, &cgc, 0xe, 1);
if (rv) return rv;
- buffer[17] = volctrl.channel0 & mask[17];
- buffer[19] = volctrl.channel1 & mask[19];
- buffer[21] = volctrl.channel2 & mask[21];
- buffer[23] = volctrl.channel3 & mask[23];
+ buffer[offset+9] = volctrl.channel0 & mask[offset+9];
+ buffer[offset+11] = volctrl.channel1 & mask[offset+11];
+ buffer[offset+13] = volctrl.channel2 & mask[offset+13];
+ buffer[offset+15] = volctrl.channel3 & mask[offset+15];
/* clear the first three */
memset(buffer, 0, 3);
/* set volume */
- cgc.buflen = -24;
+ cgc.buflen = -cgc.buflen;
cgc.buffer = buffer;
return cdrom_mode_select(cdi, &cgc);
}
}
case CDROM_SEND_PACKET: {
+ if (!CDROM_CAN(CDC_GENERIC_PACKET))
+ return -ENOSYS;
cdinfo(CD_DO_IOCTL, "entering send_packet\n");
IOCTL_IN(arg, struct cdrom_generic_command, cgc);
cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL);
amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
add_timer(&amikeyb_rep_timer);
}
- handle_scancode(scancode, !break_flag);
+ handle_scancode(keycode, !break_flag);
} else
switch (keycode) {
case 0x78:
return( 0 );
}
-
-/* for "kbd-reset" cmdline param */
-void __init amiga_kbd_reset_setup(char *str, int *ints)
-{
-}
/* read PCI configuration area */
cy_pci_irq = pdev->irq;
- cy_pci_addr0 = pdev->base_address[0];
- cy_pci_addr1 = pdev->base_address[1];
- cy_pci_addr2 = pdev->base_address[2];
+ cy_pci_addr0 = pdev->resource[0].start;
+ cy_pci_addr1 = pdev->resource[1].start;
+ cy_pci_addr2 = pdev->resource[2].start;
pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
device_id &= ~PCI_DEVICE_ID_MASK;
printk("Cyclom-Y/PCI:found winaddr=0x%lx ctladdr=0x%lx\n",
(ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
#endif
- cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK;
- cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
- if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) {
+ if (pdev->resource[2].flags & ~PCI_BASE_ADDRESS_IO_MASK) {
printk(" Warning: PCI I/O bit incorrectly set. "
"Ignoring it...\n");
cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK;
static u_char debug_buf1[4096],debug_buf2[4096],*debug_buf=&debug_buf1[0];
static u_char *shadow_buf=&debug_buf2[0];
static short debug_buf_count=0;
-static int debug_buf_overrun=0,debug_timer_running=0,debug_buffer_updated=0;
+static int debug_buf_overrun=0,debug_timer_running=0;
+static unsigned long debug_buffer_updated=0;
static struct timer_list debug_keyb_timer = { NULL, NULL, 0, 0,
debug_keyb_timer_handler };
#endif
u_char *swap;
short length,i;
- if((jiffies-debug_buffer_updated) > 100) {
+ if (time_after(jiffies, debug_buffer_updated + 100)) {
save_flags(flags);
cli();
length=debug_buf_count;
!(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT ||
prev_scancode==DNKEY_RSHIFT || prev_scancode==DNKEY_REPT ||
prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) {
- if(jiffies-lastkeypress > DNKEY_REPEAT_DELAY) {
+ if (time_after(jiffies, lastkeypress + DNKEY_REPEAT_DELAY)) {
/* printk("handle_scancode: %02x\n",prev_scancode); */
handle_scancode(prev_scancode, 1);
}
debug_buf[debug_buf_count++]=data;
debug_buffer_updated=jiffies;
if(!debug_timer_running) {
- add_timer(&debug_keyb_timer);
debug_keyb_timer.expires=jiffies+10;
+ add_timer(&debug_keyb_timer);
debug_timer_running=1;
}
}
dsp56k.in_use = 0;
printk("DSP56k driver installed\n");
+
+ return 0;
}
#ifdef MODULE
break;
/* found a PCI ISI card! */
- ioaddr = dev->base_address[3]; /* i.e at offset 0x1c in the
+ ioaddr = dev->resource[3].start; /* i.e at offset 0x1c in the
* PCI configuration register
* space.
*/
* Probe and initialize the specified board.
*/
-__initfunc(static int stli_brdinit(stlibrd_t *brdp))
+static int __init stli_brdinit(stlibrd_t *brdp)
{
#if DEBUG
printk("stli_brdinit(brdp=%x)\n", (int) brdp);
/*****************************************************************************/
-__initfunc(int stli_init(void))
+int __init stli_init(void)
{
printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
static int parport_ptr = 0;
-__initfunc(void lp_setup(char *str, int *ints))
+void __init lp_setup(char *str, int *ints)
{
if (!str) {
if (ints[0] == 0 || ints[1] == 0) {
NULL,
};
-__initfunc(int lp_internal_init(void))
+int __init lp_internal_init(void)
{
#ifdef CONFIG_AMIGA
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
EXPORT_SYMBOL(register_parallel);
EXPORT_SYMBOL(unregister_parallel);
-__initfunc(int lp_m68k_init(void))
+int __init lp_m68k_init(void)
{
extern char m68k_debug_device[];
/*
* Currently we do not accept any lp-parameters, but that may change.
*/
-__initfunc(void lp_setup(char *str, int *ints))
+void __init lp_setup(char *str, int *ints)
{
}
+++ /dev/null
-/*
- * Macintosh ADB Mouse driver for Linux
- *
- * 27 Oct 1997 Michael Schmitz
- *
- * Apple mouse protocol according to:
- *
- * Device code shamelessly stolen from:
- */
-/*
- * Atari Mouse Driver for Linux
- * by Robert de Vries (robert@and.nl) 19Jul93
- *
- * 16 Nov 1994 Andreas Schwab
- * Compatibility with busmouse
- * Support for three button mouse (shamelessly stolen from MiNT)
- * third button wired to one of the joystick directions on joystick 1
- *
- * 1996/02/11 Andreas Schwab
- * Module support
- * Allow multiple open's
- *
- * Converted to use new generic busmouse code. 5 Apr 1998
- * Russell King <rmk@arm.uk.linux.org>
- */
-
-#include <linux/module.h>
-
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/mac_mouse.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
-#include "busmouse.h"
-
-static int msedev;
-static int mac_mouse_x_threshold = 2, mac_mouse_y_threshold = 2;
-static int mac_mouse_buttons = 0;
-
-extern void (*mac_mouse_interrupt_hook) (char *, int);
-extern int mac_emulate_button2;
-extern int mac_emulate_button3;
-
-extern int console_loglevel;
-
-/*
- * XXX: need to figure out what ADB mouse packets mean ...
- * This is the stuff stolen from the Atari driver ...
- */
-static void mac_mouse_interrupt(char *buf, int nb)
-{
- static int buttons = 7; /* all mouse buttons _up_ !! */
-
- /*
- Handler 1 -- 100cpi original Apple mouse protocol.
- Handler 2 -- 200cpi original Apple mouse protocol.
-
- For Apple's standard one-button mouse protocol the data array will
- contain the following values:
-
- BITS COMMENTS
- data[0] = 0000 0000 ADB packet identifer.
- data[1] = ???? ???? (?)
- data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
- data[3] = bxxx xxxx First button and x-axis motion.
- data[4] = byyy yyyy Second button and y-axis motion.
-
- NOTE: data[0] is confirmed by the parent function and need not be
- checked here.
- */
-
- /*
- Handler 4 -- Apple Extended mouse protocol.
-
- For Apple's 3-button mouse protocol the data array will contain the
- following values:
-
- BITS COMMENTS
- data[0] = 0000 0000 ADB packet identifer.
- data[1] = 0100 0000 Extended protocol register.
- Bits 6-7 are the device id, which should be 1.
- Bits 4-5 are resolution which is in "units/inch".
- The Logitech MouseMan returns these bits clear but it has
- 200/300cpi resolution.
- Bits 0-3 are unique vendor id.
- data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
- Bits 2-3 should be 8 + 4.
- Bits 4-7 should be 3 for a mouse device.
- data[3] = bxxx xxxx Left button and x-axis motion.
- data[4] = byyy yyyy Second button and y-axis motion.
- data[5] = byyy bxxx Third button and fourth button.
- Y is additiona. high bits of y-axis motion.
- X is additional high bits of x-axis motion.
-
- NOTE: data[0] and data[2] are confirmed by the parent function and
- need not be checked here.
- */
-
- /*
- * 'buttons' here means 'button down' states!
- * Button 1 (left) : bit 2, busmouse button 3
- * Button 2 (right) : bit 0, busmouse button 1
- * Button 3 (middle): bit 1, busmouse button 2
- */
-
- /* x/y and buttons swapped */
-
- if (buf[0] == 0) { /* real packet : use buttons? */
-#ifdef DEBUG_ADBMOUSE
- if (console_loglevel >= 8)
- printk("mac_mouse: real data; ");
-#endif
- /* button 1 (left, bit 2) : always significant ! */
- buttons = (buttons&3) | (buf[3] & 0x80 ? 4 : 0); /* 1+2 unchanged */
- /* button 2 (right, bit 0) present ? */
- if ( !mac_emulate_button2 )
- buttons = (buttons&6) | (buf[4] & 0x80 ? 1 : 0); /* 2+3 unchanged */
- /* button 2 (middle) present? */
- /* data valid only if extended mouse format ! (buf[3] = 0 else)*/
- if ( !mac_emulate_button3 && buf[1]&0x40 )
- buttons = (buttons&5) | (buf[5] & 0x80 ? 2 : 0); /* 1+3 unchanged */
- } else { /* fake packet : use 2+3 */
-#ifdef DEBUG_ADBMOUSE
- if (console_loglevel >= 8)
- printk("mac_mouse: fake data; ");
-#endif
- /* we only see state changes here, but the fake driver takes care
- * to preserve state... button 1 state must stay unchanged! */
- buttons = (buttons&4) | ((buf[4] & 0x80 ? 1 : 0) | (buf[5] & 0x80 ? 2 : 0));
- }
-
- busmouse_add_movementbuttons(msedev,
- ((buf[4]&0x7f) < 64 ? (buf[4]&0x7f) : (buf[4]&0x7f)-128 ),
- -((buf[3]&0x7f) < 64 ? (buf[3]&0x7f) : (buf[3]&0x7f)-128 ),
- buttons & 7);
-}
-
-static int release_mouse(struct inode *inode, struct file *file)
-{
- mac_mouse_interrupt_hook = NULL;
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int open_mouse(struct inode *inode, struct file *file)
-{
- MOD_INC_USE_COUNT;
- mac_mouse_interrupt_hook = mac_mouse_interrupt;
- return 0;
-}
-
-#define ADB_MOUSE_MINOR 10
-
-static struct busmouse macmouse = {
- ADB_MOUSE_MINOR, "adbmouse", open_mouse, release_mouse, 0
-};
-
-__initfunc(int mac_mouse_init(void))
-{
- if (!MACH_IS_MAC)
- return -ENODEV;
-
- msedev = register_busmouse(&macmouse);
- if (msedev < 0)
- printk(KERN_WARNING "Unable to register ADB mouse driver.\n");
- else
- printk(KERN_INFO "Macintosh ADB mouse installed.\n");
- return msedev < 0 ? msedev : 0;
-}
-
-
-#define MIN_THRESHOLD 1
-#define MAX_THRESHOLD 20 /* more seems not reasonable... */
-
-__initfunc(void mac_mouse_setup(char *str, int *ints))
-{
- if (ints[0] < 1) {
- printk( "mac_mouse_setup: no arguments!\n" );
- return;
- }
- else if (ints[0] > 2) {
- printk( "mac_mouse_setup: too many arguments\n" );
- }
-
- if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
- printk( "mac_mouse_setup: bad threshold value (ignored)\n" );
- else {
- mac_mouse_x_threshold = ints[1];
- mac_mouse_y_threshold = ints[1];
- if (ints[0] > 1) {
- if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
- printk("mac_mouse_setup: bad threshold value (ignored)\n" );
- else
- mac_mouse_y_threshold = ints[2];
- }
- }
-
-}
-
-#ifdef MODULE
-#include <asm/setup.h>
-
-int init_module(void)
-{
- return mac_mouse_init();
-}
-
-void cleanup_module(void)
-{
- unregister_busmouse(msedev);
-}
-#endif
#include <linux/joystick.h>
#include <linux/i2c.h>
#include <linux/raw.h>
+#include <linux/capability.h>
#include <asm/uaccess.h>
#include <asm/io.h>
}
}
+static int open_port(struct inode * inode, struct file * filp)
+{
+ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static int open_mem(struct inode * inode, struct file * filp)
+{
+ return (capable(CAP_SYS_RAWIO)
+ || !(filp->f_mode & FMODE_WRITE)) ? 0 : -EPERM;
+}
+
#define mmap_kmem mmap_mem
#define zero_lseek null_lseek
#define full_lseek null_lseek
#define write_zero write_null
#define read_full read_zero
+#define open_kmem open_mem
static struct file_operations mem_fops = {
memory_lseek,
NULL, /* mem_poll */
NULL, /* mem_ioctl */
mmap_mem,
- NULL, /* no special open code */
+ open_mem,
NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
NULL, /* kmem_poll */
NULL, /* kmem_ioctl */
mmap_kmem,
- NULL, /* no special open code */
+ open_kmem,
NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
NULL, /* port_poll */
NULL, /* port_ioctl */
NULL, /* port_mmap */
- NULL, /* no special open code */
+ open_port,
NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
extern int dsp56k_init(void);
extern int nvram_init(void);
extern int radio_init(void);
-extern void hfmodem_init(void);
extern int pc110pad_init(void);
extern int pmu_device_init(void);
extern int qpmouse_init(void);
#ifdef CONFIG_ATARI_DSP56K
dsp56k_init();
#endif
-#ifdef CONFIG_HFMODEM
- hfmodem_init();
-#endif
#ifdef CONFIG_NVRAM
nvram_init();
#endif
#ifdef CONFIG_MISC_RADIO
radio_init();
#endif
-#ifdef CONFIG_HFMODEM
- hfmodem_init();
-#endif
#ifdef CONFIG_PMAC_PBOOK
pmu_device_init();
#endif
--- /dev/null
+/*
+ * linux/drivers/char/q40_keyb.c
+ *
+ */
+
+#include <linux/config.h>
+
+#include <asm/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/sysrq.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/q40_master.h>
+#include <asm/irq.h>
+#include <asm/q40ints.h>
+
+/* Some configuration switches are present in the include file... */
+
+#define KBD_REPORT_ERR
+
+/* Simple translation table for the SysRq keys */
+
+#define SYSRQ_KEY 0x54
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char q40kbd_sysrq_xlate[128] =
+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+ "\r\000/"; /* 0x60 - 0x6f */
+#endif
+
+/* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/
+/* 0x00 means not a valid entry or no conversion known */
+
+unsigned static char q40cl[256] =
+{/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */
+ 0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00, /* 0x00 - 0x0f */
+ 0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00, /* 0x10 - 0x1f */
+ 0x00,0x2e,0x2d,0x20,0x12,0x05,0x04,0x00,0x21,0x39,0x2f,0x21,0x14,0x13,0x06,0x00, /* 0x20 - 0x2f 'f' is at 0x2b, what is 0x28 ???*/
+ 0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00, /* 0x30 - 0x3f */
+ 0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00, /* 0x40 - 0x4f */
+ 0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00, /* 0x50 - 0x5f*/
+ 0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00, /* 0x60 - 0x6f */
+ 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00, /* 0x70 - 0x7f */
+ 0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x80 - 0x8f 0x84/0x37 is SySrq*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x90 - 0x9f */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xa0 - 0xaf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xb0 - 0xbf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xc0 - 0xcf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xd0 - 0xdf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xe0 - 0xef */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xf0 - 0xff */
+};
+
+/* another table, AT 0xe0 codes to PC 0xe0 codes,
+ 0xff special entry for SysRq - DROPPED right now */
+static unsigned char q40ecl[]=
+{/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x00 - 0x0f*/
+ 0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x10 - 0x1f */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x20 - 0x2f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x30 - 0x3f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00, /* 0x40 - 0x4f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00, /* 0x50 - 0x5f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00, /* 0x60 - 0x6f*/
+ 0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00, /* 0x70 - 0x7f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x80 - 0x8f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x90 - 0x9f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xa0 - 0xaf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xb0 - 0xbf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xc0 - 0xcf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xd0 - 0xdf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xe0 - 0xef*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 0xf0 - 0xff*/
+};
+
+
+spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL 97
+#define E0_KPSLASH 98
+#define E0_PRSCR 99
+#define E0_RALT 100
+#define E0_BREAK 101 /* (control-pause) */
+#define E0_HOME 102
+#define E0_UP 103
+#define E0_PGUP 104
+#define E0_LEFT 105
+#define E0_RIGHT 106
+#define E0_END 107
+#define E0_DOWN 108
+#define E0_PGDN 109
+#define E0_INS 110
+#define E0_DEL 111
+
+#define E1_PAUSE 119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85 /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86 124
+/* tfj@olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+ RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */
+ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */
+ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */
+ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO 112
+/* LK450 */
+#define E0_F13 113
+#define E0_F14 114
+#define E0_HELP 115
+#define E0_DO 116
+#define E0_F17 117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for the "OMNI" key and the
+ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
+ */
+#define E0_OK 124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW 125
+#define E0_MSRW 126
+#define E0_MSTM 127
+
+/* this can be changed using setkeys : */
+static unsigned char e0_keys[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
+ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
+ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
+};
+
+static unsigned int prev_scancode = 0; /* remember E0, E1 */
+
+int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+ if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+ return -EINVAL;
+ if (scancode < 128)
+ high_keys[scancode - SC_LIM] = keycode;
+ else
+ e0_keys[scancode - 128] = keycode;
+ return 0;
+}
+
+int q40kbd_getkeycode(unsigned int scancode)
+{
+ return
+ (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+ (scancode < 128) ? high_keys[scancode - SC_LIM] :
+ e0_keys[scancode - 128];
+}
+
+
+#define disable_keyboard()
+#define enable_keyboard()
+
+
+
+int q40kbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+ if (scancode == 0xff) {
+ /* in scancode mode 1, my ESC key generates 0xff */
+ /* the calculator keys on a FOCUS 9000 generate 0xff */
+#ifndef KBD_IS_FOCUS_9000
+#ifdef KBD_REPORT_ERR
+ if (!raw_mode)
+ printk(KERN_DEBUG "Keyboard error\n");
+#endif
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
+ return 0;
+ }
+ return 1;
+}
+
+int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+ /*printk("translate ...\n");*/
+ if (prev_scancode) {
+ /*
+ * usually it will be 0xe0, but a Pause key generates
+ * e1 1d 45 e1 9d c5 when pressed, and nothing when released
+ */
+ if (prev_scancode != 0xe0) {
+ if (prev_scancode == 0xe1 && scancode == 0x1d) {
+ prev_scancode = 0x100;
+ return 0;
+ } else if (prev_scancode == 0x100 && scancode == 0x45) {
+ *keycode = E1_PAUSE;
+ prev_scancode = 0;
+ } else {
+#ifdef KBD_REPORT_UNKN
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+ } else {
+ prev_scancode = 0;
+ /*
+ * The keyboard maintains its own internal caps lock and
+ * num lock statuses. In caps lock mode E0 AA precedes make
+ * code and E0 2A follows break code. In num lock mode,
+ * E0 2A precedes make code and E0 AA follows break code.
+ * We do our own book-keeping, so we will just ignore these.
+ */
+ /*
+ * For my keyboard there is no caps lock mode, but there are
+ * both Shift-L and Shift-R modes. The former mode generates
+ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+ * So, we should also ignore the latter. - aeb@cwi.nl
+ */
+ if (scancode == 0x2a || scancode == 0x36)
+ return 0;
+
+ if (e0_keys[scancode])
+ *keycode = e0_keys[scancode];
+ else {
+#ifdef KBD_REPORT_UNKN
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+ scancode);
+#endif
+ return 0;
+ }
+ }
+ } else if (scancode >= SC_LIM) {
+ /* This happens with the FOCUS 9000 keyboard
+ Its keys PF1..PF12 are reported to generate
+ 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
+ Moreover, unless repeated, they do not generate
+ key-down events, so we have to zero up_flag below */
+ /* Also, Japanese 86/106 keyboards are reported to
+ generate 0x73 and 0x7d for \ - and \ | respectively. */
+ /* Also, some Brazilian keyboard is reported to produce
+ 0x73 and 0x7e for \ ? and KP-dot, respectively. */
+
+ *keycode = high_keys[scancode - SC_LIM];
+
+ if (!*keycode) {
+ if (!raw_mode) {
+#ifdef KBD_REPORT_UNKN
+ printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+ " - ignored\n", scancode);
+#endif
+ }
+ return 0;
+ }
+ } else
+ *keycode = scancode;
+ return 1;
+}
+
+char q40kbd_unexpected_up(unsigned char keycode)
+{
+ /* unexpected, but this can happen: maybe this was a key release for a
+ FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
+ if (keycode >= SC_LIM || keycode == 85)
+ return 0;
+ else
+ return 0200;
+}
+
+static int keyup=0;
+static int qprev=0;
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+ unsigned char status;
+
+ disable_keyboard();
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kbd_pt_regs = regs;
+
+ status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
+ if (status )
+ {
+ unsigned char scancode,qcode;
+
+ qcode = master_inb(KEYCODE_REG);
+
+ if (qcode != 0xf0)
+ {
+ if (qcode == 0xe0)
+ {
+ qprev=0xe0;
+ handle_scancode(qprev);
+ goto exit;
+ }
+
+ scancode=qprev ? q40ecl[qcode] : q40cl[qcode];
+#if 0
+/* next line is last resort to hanlde some oddities */
+ if (qprev && !scancode) scancode=q40cl[qcode];
+#endif
+ qprev=0;
+ if (!scancode)
+ {
+ printk("unknown scancode %x\n",qcode);
+ goto exit;
+ }
+ if (scancode==0xff) /* SySrq */
+ scancode=SYSRQ_KEY;
+
+ handle_scancode(scancode | (keyup ? 0200 : 0));
+ keyup=0;
+ mark_bh(KEYBOARD_BH);
+
+ }
+ else
+ keyup=1;
+ }
+exit:
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+ master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */
+ enable_keyboard();
+}
+
+
+
+
+#ifdef CONFIG_MAGIC_SYSRQ
+int kbd_is_sysrq(unsigned char keycode)
+{
+ return( keycode == SYSRQ_KEY );
+}
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+
+
+
+#define KBD_NO_DATA (-1) /* No data */
+#define KBD_BAD_DATA (-2) /* Parity or other error */
+
+static int __init kbd_read_input(void)
+{
+ int retval = KBD_NO_DATA;
+ unsigned char status;
+
+ status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
+ if (status) {
+ unsigned char data = master_inb(KEYCODE_REG);
+
+ retval = data;
+ master_outb(-1,KEYBOARD_UNLOCK_REG);
+ }
+ return retval;
+}
+
+extern void q40kbd_leds(unsigned char leds)
+{ /* nothing can be done */ }
+
+static void __init kbd_clear_input(void)
+{
+ int maxread = 100; /* Random number */
+
+ do {
+ if (kbd_read_input() == KBD_NO_DATA)
+ break;
+ } while (--maxread);
+}
+
+
+void __init q40kbd_init_hw(void)
+{
+#if 0
+ /* Get the keyboard controller registers (incomplete decode) */
+ request_region(0x60, 16, "keyboard");
+#endif
+ /* Flush any pending input. */
+ kbd_clear_input();
+
+ /* Ok, finally allocate the IRQ, and off we go.. */
+ request_irq(Q40_IRQ_KEYBOARD, keyboard_interrupt, 0, "keyboard", NULL);
+ master_outb(-1,KEYBOARD_UNLOCK_REG);
+ master_outb(1,KEY_IRQ_ENABLE_REG);
+
+}
+
#include <linux/major.h>
#include <linux/blkdev.h>
#include <linux/raw.h>
+#include <linux/capability.h>
#include <asm/uaccess.h>
#define dprintk(x...)
}
if (command == RAW_SETBIND) {
+ /*
+ * This is like making block devices, so demand the
+ * same capability
+ */
+ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ break;
+ }
+
/*
* For now, we don't need to check that the underlying
* block device is present or not: we can do that when
}
-__initfunc(void mackbd_init_hw(void))
+void __init mackbd_init_hw(void)
{
if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
return;
* - initialize the serial port
* Return non-zero if we didn't find a serial port.
*/
-__initfunc(static int serial_console_setup(struct console *co, char *options))
+static int __init serial_console_setup(struct console *co, char *options)
{
struct mac_serial *info = zs_soft + co->index;
int baud = 38400;
/*
* Register console.
*/
-__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+long __init serial_console_init(long kmem_start, long kmem_end)
{
register_console(&sercons);
return kmem_start;
* boot command line flags.
* XXX at the moment probably only channel A will work
*/
-__initfunc(void zs_kgdb_hook(int tty_num))
+void __init zs_kgdb_hook(int tty_num)
{
/* Find out how many Z8530 SCCs we have */
if (zs_chain == 0)
&nvram_fops
};
-__initfunc(int nvram_init(void))
+int nvram_init(void)
{
printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
NVRAM_VERSION);
M_OBJS += hplance.o
endif
endif
+
+ifeq ($(CONFIG_MVME147_NET),y)
+L_OBJS += mvme147.o
+CONFIG_7990_BUILTIN = y
+else
+ ifeq ($(CONFIG_MVME147_NET),m)
+ CONFIG_7990_MODULE = y
+ M_OBJS += mvme147.o
+ endif
+endif
+
# If we need generic LANCE support, either in the kernel or as a module,
# build it in the appropriate way.
ifdef CONFIG_7990_BUILTIN
endif
endif
+ifeq ($(CONFIG_MACSONIC),y)
+L_OBJS += macsonic.o
+endif
+
ifeq ($(CONFIG_BMAC),y)
L_OBJS += bmac.o
else
extern int hplance_probe(struct device *dev);
extern int bagetlance_probe(struct device *);
extern int dec_lance_probe(struct device *);
+extern int mvme147lance_probe(struct device *dev);
extern int via_rhine_probe(struct device *dev);
extern int tc515_probe(struct device *dev);
extern int lance_probe(struct device *dev);
extern int rcpci_probe(struct device *);
+extern int mac_onboard_sonic_probe(struct device *dev);
/* Gigabit Ethernet adapters */
extern int yellowfin_probe(struct device *dev);
#endif
#ifdef CONFIG_HPLANCE /* HP300 internal Ethernet */
{hplance_probe, 0},
+#endif
+#ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */
+ {mvme147lance_probe, 0},
+#endif
+#ifdef CONFIG_MACSONIC /* Mac 68k Quadra builtin Ethernet */
+ {mac_onboard_sonic_probe, 0},
#endif
{NULL, 0},
};
name = "NE2000";
dev->base_addr = ioaddr;
+ dev->irq = IRQ_AMIGA_PORTS;
/* Install the Interrupt handler */
if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, 0, "AriadNE2 Ethernet",
((struct ei_device *)dev->priv)->priv = key;
for(i = 0; i < ETHER_ADDR_LEN; i++) {
+#ifdef DEBUG
printk(" %2.2x", SA_prom[i]);
+#endif
dev->dev_addr[i] = SA_prom[i];
}
}
else {
int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned long buf = VTOP(skb->data);
+ unsigned long buf = virt_to_phys(skb->data);
int stat;
stdma_lock(bionet_intr, NULL);
unsigned char *buffer;
{
int ret = -1;
- unsigned char *vbuffer = (unsigned char *)PTOV(buffer);
+ unsigned char *vbuffer = phys_to_virt((unsigned long)buffer);
unsigned char cmd_buffer[5];
if (send_first(target, INQUIRY))
!acsi_wait_for_IRQ(TIMEOUTDMA) ||
get_status())
goto bad;
- ret = (HADDR *)PTOV(&(((DMAHWADDR *)buffer)->hwaddr));
+ ret = phys_to_virt(&(((DMAHWADDR *)buffer)->hwaddr));
dma_cache_maintenance((unsigned long)buffer, 512, 0);
bad:
return (ret);
}
else {
int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned long buf = VTOP(skb->data);
+ unsigned long buf = virt_to_phys(skb->data);
int stat;
stdma_lock(pamsnet_intr, NULL);
void *mem = kmalloc(sizeof(*sp), GFP_KERNEL);
dev->priv = sp = mem; /* Cache align here if kmalloc does not. */
sp->priv_addr = mem;
- } else
- memset(sp, 0, sizeof(*sp));
+ }
+ memset(sp, 0, sizeof(*sp));
sp->next_module = root_speedo_dev;
root_speedo_dev = dev;
--- /dev/null
+/*
+ * macsonic.c
+ *
+ * (C) 1998 Alan Cox
+ *
+ * Debugging Andreas Ehliar, Michael Schmitz
+ *
+ * Based on code
+ * (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de)
+ *
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+ *
+ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
+ *
+ * A driver for the Mac onboard Sonic ethernet chip.
+ *
+ * 98/12/21 MSch: judged from tests on Q800, it's basically working,
+ * but eating up both receive and transmit resources
+ * and duplicating packets. Needs more testing.
+ *
+ * 99/01/03 MSch: upgraded to version 0.92 of the core driver, fixed.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/nubus.h>
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/macintosh.h>
+
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <config/macsonic.h>
+
+#define SREGS_PAD(n) u16 n;
+
+#include "sonic.h"
+
+extern int mac_onboard_sonic_probe(void);
+
+static int setup_debug = -1;
+static int setup_offset = -1;
+static int setup_shift = -1;
+
+/*
+ * This seems to be the right default for the Q800
+ */
+
+static int reg_offset = 0;
+static int reg_shift = 0;
+
+/*
+ * Macros to access SONIC registers
+ */
+
+#define MAC_SONIC_REGISTERS 0x50F0A000
+#define MAC_SONIC_PROM_BASE 0x50f08000
+#define MAC_SONIC_IRQ 9 /* Nubus 9 */
+
+/*
+ * FIXME: We may need to invert the byte ordering. These should
+ * be ok for other aspects as they are uncached spaces.
+ * The original macros from jazzsonic.c works for me
+ * on my LC 630, YMMV /Andreas Ehliar
+ */
+
+#if 0
+#define SONIC_READ(reg) \
+ *((volatile unsigned int *)base_addr+((reg)<<2)+2)
+
+#define SONIC_WRITE(reg,val) \
+ *((volatile unsigned int *)base_addr+((reg)<<2)+2) = val
+#else
+#define SONIC_READ(reg) \
+ *((volatile unsigned int *)base_addr+reg)
+
+#define SONIC_WRITE(reg,val) \
+ *((volatile unsigned int *)base_addr+reg) = val
+#endif
+
+#define SONIC_READ_PROM(addr) \
+ *((volatile unsigned char *)prom_addr+addr)
+/*
+ * Function : mac_sonic_setup(char *str, int *ints)
+ *
+ * Purpose : booter command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ * equal to the number of ints.
+ *
+ * Currently unused in the new driver; need to add settable parameters to the
+ * detect function.
+ *
+ */
+
+void mac_sonic_setup(char *str, int *ints) {
+ /* Format of macsonic parameter is:
+ * macsonic=<debug>,<offset>,<shift>
+ * Negative values mean don't change.
+ */
+
+ /* Grmbl... the standard parameter parsing can't handle negative numbers
+ * :-( So let's do it ourselves!
+ */
+
+ int i = ints[0]+1, fact;
+
+ while( str && (isdigit(*str) || *str == '-') && i <= 10) {
+ if (*str == '-')
+ fact = -1, ++str;
+ else
+ fact = 1;
+ ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
+ if ((str = strchr( str, ',' )) != NULL)
+ ++str;
+ }
+ ints[0] = i-1;
+
+ if (ints[0] < 1) {
+ printk( "mac_sonic_setup: no arguments!\n" );
+ return;
+ }
+
+ if (ints[0] >= 1) {
+ /* 0 <= n <= 2 */
+ if (ints[1] >= 0 && ints[1] <= 8)
+ setup_debug = ints[1];
+ else if (ints[1] > 16)
+ printk( "mac_sonic_setup: invalid debug level %d !\n", ints[1] );
+ }
+ if (ints[0] >= 2) {
+ /* 0 <= n <= 2 */
+ if (ints[2] >= 0 && ints[2] <= 16)
+ setup_offset = ints[2];
+ else if (ints[2] > 16)
+ printk( "mac_sonic_setup: invalid offset %d !\n", ints[2] );
+ }
+ if (ints[0] >= 3) {
+ /* 0 <= n <= 2 */
+ if (ints[3] >= 0 && ints[3] <= 16)
+ setup_shift = ints[3];
+ else if (ints[3] > 16)
+ printk( "mac_sonic_setup: invalid shift %d !\n", ints[3] );
+ }
+}
+
+static int sonic_debug = 0;
+
+/*
+ * For reversing the PROM address
+ */
+
+static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
+ 1, 9, 5, 13, 3, 11, 7, 15};
+
+__initfunc(int mac_onboard_sonic_probe(void))
+{
+ struct device *dev;
+ unsigned int silicon_revision;
+ unsigned int val;
+ struct sonic_local *lp;
+ int i;
+ int base_addr = MAC_SONIC_REGISTERS;
+ int prom_addr = MAC_SONIC_PROM_BASE;
+ static int one=0;
+
+ if (!MACH_IS_MAC)
+ return -ENODEV;
+
+ if(++one!=1) /* Only one is allowed */
+ return -ENODEV;
+
+ printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
+
+ if (macintosh_config->ether_type != MAC_ETHER_SONIC)
+ {
+ printk("none.\n");
+ return -ENODEV;
+ }
+
+ printk("yes\n");
+
+ if (setup_debug >= 0)
+ sonic_debug = setup_debug;
+
+ /*
+ * This may depend on the actual Mac model ... works for me.
+ */
+ reg_offset =
+ (setup_offset >= 0) ? setup_offset : 0;
+ reg_shift =
+ (setup_shift >= 0) ? setup_shift : 0;
+
+ /*
+ * get the Silicon Revision ID. If this is one of the known
+ * one assume that we found a SONIC ethernet controller at
+ * the expected location.
+ * (This is not implemented in the Macintosh driver yet; need
+ * to collect values from various sources. Mine is 0x4 ...)
+ */
+
+ silicon_revision = SONIC_READ(SONIC_SR);
+ if (sonic_debug > 1)
+ printk("SONIC Silicon Revision = 0x%04x\n", silicon_revision);
+
+ /*
+ * We need to allocate sonic_local later on, making sure it's
+ * aligned on a 64k boundary. So, no space for dev->priv allocated
+ * here ...
+ */
+ dev = init_etherdev(0,0);
+
+ if(dev==NULL)
+ return -ENOMEM;
+
+ printk("%s: %s found at 0x%08x, ",
+ dev->name, "SONIC ethernet", base_addr);
+
+ if (sonic_debug > 1)
+ printk("using offset %d shift %d,", reg_offset, reg_shift);
+
+ /* Fill in the 'dev' fields. */
+ dev->base_addr = base_addr;
+ dev->irq = MAC_SONIC_IRQ;
+
+ /*
+ * Put the sonic into software reset, then
+ * retrieve and print the ethernet address.
+ */
+
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+
+ /*
+ * We can't trust MacOS to initialise things it seems.
+ */
+
+ if (sonic_debug > 1)
+ printk("SONIC_DCR was %X\n",SONIC_READ(SONIC_DCR));
+
+ SONIC_WRITE(SONIC_DCR,
+ SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | SONIC_DCR_DW);
+
+ /*
+ * We don't want floating spare IRQ's around, not on
+ * level triggered systems!
+ * Strange though - writing to the ISR only clears currently
+ * pending IRQs, but doesn't disable them... Does this make
+ * a difference?? Seems it does ...
+ */
+#if 1
+ SONIC_WRITE(SONIC_ISR,0x7fff);
+ SONIC_WRITE(SONIC_IMR,0);
+#else
+ SONIC_WRITE(SONIC_ISR, SONIC_IMR_DEFAULT);
+#endif
+
+ /* This is how it is done in jazzsonic.c
+ * It doesn't seem to work here though.
+ */
+ if (sonic_debug > 2) {
+ printk("Retreiving CAM entry 0. This should be the HW address.\n");
+
+ SONIC_WRITE(SONIC_CEP, 0);
+ for (i = 0; i < 3; i++)
+ {
+ val = SONIC_READ(SONIC_CAP0 - i);
+ dev->dev_addr[i * 2] = val;
+ dev->dev_addr[i * 2 + 1] = val >> 8;
+ }
+
+ printk("HW Address from CAM 0: ");
+ for (i = 0; i < 6; i++)
+ {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i < 5)
+ printk(":");
+ }
+ printk("\n");
+
+ printk("Retreiving CAM entry 15. Another candidate...\n");
+
+ /*
+ * MacOS seems to use CAM entry 15 ...
+ */
+ SONIC_WRITE(SONIC_CEP, 15);
+ for (i = 0; i < 3; i++)
+ {
+ val = SONIC_READ(SONIC_CAP0 - i);
+ dev->dev_addr[i * 2] = val;
+ dev->dev_addr[i * 2 + 1] = val >> 8;
+ }
+
+ printk("HW Address from CAM 15: ");
+ for (i = 0; i < 6; i++)
+ {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i < 5)
+ printk(":");
+ }
+ printk("\n");
+ }
+
+ /*
+ * if we can read the PROM, we're safe :-)
+ */
+ if (sonic_debug > 1)
+ printk("Retreiving HW address from the PROM: ");
+
+ for(i=0;i<6;i++){
+ dev->dev_addr[i]=SONIC_READ_PROM(i);
+ }
+ if (sonic_debug > 1) {
+ for (i = 0; i < 6; i++)
+ {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i < 5)
+ printk(":");
+ }
+ printk("\n");
+ }
+ /*
+ * If its not one of these we have
+ * screwed up on this Mac model
+ */
+
+ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+ memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+ memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+ {
+ /*
+ * Try bit reversed
+ */
+ for(i=0;i<6;i++){
+ val = SONIC_READ_PROM(i);
+ dev->dev_addr[i]=(nibbletab[val & 0xf] << 4) |
+ nibbletab[(val >> 4) &0xf];
+ }
+ if (sonic_debug > 1) {
+ printk("Trying bit reversed: ");
+ for (i = 0; i < 6; i++)
+ {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i < 5)
+ printk(":");
+ }
+ printk("\n");
+ }
+ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+ memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+ memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+ {
+ /*
+ * Still nonsense ... messed up someplace!
+ */
+ printk("ERROR (INVALID MAC)\n");
+ return -EIO;
+ }
+ }
+
+ printk(" MAC ");
+ for (i = 0; i < 6; i++)
+ {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i < 5)
+ printk(":");
+ }
+
+ printk(" IRQ %d\n", MAC_SONIC_IRQ);
+
+ /* Initialize the device structure. */
+ if (dev->priv == NULL)
+ {
+ if (sonic_debug > 2) {
+ printk("Allocating memory for dev->priv aka lp\n");
+ printk("Memory to allocate: %d\n",sizeof(*lp));
+ }
+ /*
+ * the memory be located in the same 64kb segment
+ */
+ lp = NULL;
+ i = 0;
+ do
+ {
+ lp = (struct sonic_local *) kmalloc(sizeof(*lp), GFP_KERNEL);
+ if ((unsigned long) lp >> 16 != ((unsigned long) lp + sizeof(*lp)) >> 16)
+ {
+ /* FIXME, free the memory later */
+ kfree(lp);
+ lp = NULL;
+ }
+ }
+ while (lp == NULL && i++ < 20);
+
+ if (lp == NULL)
+ {
+ printk("%s: couldn't allocate memory for descriptors\n",
+ dev->name);
+ return -ENOMEM;
+ }
+
+ if (sonic_debug > 2) {
+ printk("Memory allocated after %d tries\n",i);
+ }
+
+ /* XXX sonic_local has the TDA, RRA, RDA, don't cache */
+ kernel_set_cachemode((u32)lp, 8192, IOMAP_NOCACHE_SER);
+ memset(lp, 0, sizeof(struct sonic_local));
+
+ lp->cda_laddr = (u32)lp;
+ if (sonic_debug > 2) {
+ printk("memory allocated for sonic at 0x%x\n",lp);
+ }
+ lp->tda_laddr = lp->cda_laddr + sizeof(lp->cda);
+ lp->rra_laddr = lp->tda_laddr + sizeof(lp->tda);
+ lp->rda_laddr = lp->rra_laddr + sizeof(lp->rra);
+
+ /* allocate receive buffer area */
+ /* FIXME, maybe we should use skbs */
+ if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL)
+ {
+ printk("%s: couldn't allocate receive buffers\n", dev->name);
+ return -ENOMEM;
+ }
+ /* XXX RBA written by Sonic, not cached either */
+ kernel_set_cachemode((u32)lp->rba, 6*8192, IOMAP_NOCACHE_SER);
+ lp->rba_laddr = (u32)lp->rba;
+ flush_cache_all();
+ dev->priv = (struct sonic_local *) lp;
+ }
+ lp = (struct sonic_local *) dev->priv;
+ dev->open = sonic_open;
+ dev->stop = sonic_close;
+ dev->hard_start_xmit = sonic_send_packet;
+ dev->get_stats = sonic_get_stats;
+ dev->set_multicast_list = &sonic_multicast_list;
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+ return 0;
+}
+
+/*
+ * SONIC uses a nubus IRQ
+ */
+
+#define sonic_request_irq(irq, vec, flags, name, dev) \
+ nubus_request_irq(irq, dev, vec)
+#define sonic_free_irq(irq,id) nubus_free_irq(irq)
+
+/*
+ * No funnies on memory mapping.
+ */
+
+#define sonic_chiptomem(x) (x)
+
+/*
+ * No VDMA on a Macintosh. So we need request no such facility.
+ */
+
+#define vdma_alloc(x,y) ((u32)(x))
+#define vdma_free(x)
+#define PHYSADDR(x) (x)
+
+#include "sonic.c"
--- /dev/null
+/* mvme147.c : the Linux/mvme147/lance ethernet driver
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ * Uses the generic 7990.c LANCE code.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/mvme147hw.h>
+
+/* We have 16834 bytes of RAM for the init block and buffers. This places
+ * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
+ * buffers and 2 Tx buffers.
+ */
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+
+#include "7990.h" /* use generic LANCE code */
+
+/* Our private data structure */
+struct m147lance_private {
+ struct lance_private lance;
+ void *base;
+ void *ram;
+};
+
+/* function prototypes... This is easy because all the grot is in the
+ * generic LANCE support. All we have to support is probing for boards,
+ * plus board-specific init, open and close actions.
+ * Oh, and we need to tell the generic code how to read and write LANCE registers...
+ */
+int mvme147lance_probe(struct device *dev);
+static int m147lance_open(struct device *dev);
+static int m147lance_close(struct device *dev);
+static void m147lance_writerap(struct m147lance_private *lp, unsigned short value);
+static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value);
+static unsigned short m147lance_readrdp(struct m147lance_private *lp);
+
+typedef void (*writerap_t)(void *, unsigned short);
+typedef void (*writerdp_t)(void *, unsigned short);
+typedef void (*readrdp_t)(void *);
+
+#ifdef MODULE
+static struct m147lance_private *root_m147lance_dev = NULL;
+#endif
+
+/* Initialise the one and only on-board 7990 */
+__initfunc(int mvme147lance_probe(struct device *dev))
+{
+ static int called = 0;
+ static const char name[] = "MVME147 LANCE";
+ struct m147lance_private *lp;
+ u_long *addr;
+ u_long address;
+
+ if (!MACH_IS_MVME147 || called)
+ return(ENODEV);
+ called++;
+
+ dev->priv = kmalloc(sizeof(struct m147lance_private), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct m147lance_private));
+
+ /* Fill the dev fields */
+ dev->base_addr = (unsigned long)MVME147_LANCE_BASE;
+ dev->open = &m147lance_open;
+ dev->stop = &m147lance_close;
+ dev->hard_start_xmit = &lance_start_xmit;
+ dev->get_stats = &lance_get_stats;
+ dev->set_multicast_list = &lance_set_multicast;
+ dev->dma = 0;
+
+ addr=(u_long *)ETHERNET_ADDRESS;
+ address = *addr;
+ dev->dev_addr[0]=0x08;
+ dev->dev_addr[1]=0x00;
+ dev->dev_addr[2]=0x3e;
+ address=address>>8;
+ dev->dev_addr[5]=address&0xff;
+ address=address>>8;
+ dev->dev_addr[4]=address&0xff;
+ address=address>>8;
+ dev->dev_addr[3]=address&0xff;
+
+ printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, dev->base_addr, MVME147_LANCE_IRQ,
+ dev->dev_addr[0],
+ dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4],
+ dev->dev_addr[5]);
+
+ lp = (struct m147lance_private *)dev->priv;
+ lp->ram = (void *)__get_dma_pages(GFP_ATOMIC, 3); /* 16K */
+ if (!lp->ram)
+ {
+ printk("%s: No memory for LANCE buffers\n", dev->name);
+ return -ENODEV;
+ }
+
+ lp->lance.name = (char*)name; /* discards const, shut up gcc */
+ lp->lance.ll = (struct lance_regs *)(dev->base_addr);
+ lp->lance.init_block = (struct lance_init_block *)(lp->ram); /* CPU addr */
+ lp->lance.lance_init_block = (struct lance_init_block *)(lp->ram); /* LANCE addr of same RAM */
+ lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */
+ lp->lance.irq = MVME147_LANCE_IRQ;
+ lp->lance.writerap = (writerap_t)m147lance_writerap;
+ lp->lance.writerdp = (writerdp_t)m147lance_writerdp;
+ lp->lance.readrdp = (readrdp_t)m147lance_readrdp;
+ lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
+ lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
+ lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
+ lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
+ ether_setup(dev);
+
+#ifdef MODULE
+ dev->ifindex = dev_new_index();
+ lp->next_module = root_m147lance_dev;
+ root_m147lance_dev = lp;
+#endif /* MODULE */
+
+ return 0;
+}
+
+static void m147lance_writerap(struct m147lance_private *lp, unsigned short value)
+{
+ lp->lance.ll->rap = value;
+}
+
+static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value)
+{
+ lp->lance.ll->rdp = value;
+}
+
+static unsigned short m147lance_readrdp(struct m147lance_private *lp)
+{
+ return lp->lance.ll->rdp;
+}
+
+static int m147lance_open(struct device *dev)
+{
+ int status;
+
+ status = lance_open(dev); /* call generic lance open code */
+ if (status)
+ return status;
+ /* enable interrupts at board level. */
+ m147_pcc->lan_cntrl=0; /* clear the interrupts (if any) */
+ m147_pcc->lan_cntrl=0x08 | 0x04; /* Enable irq 4 */
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int m147lance_close(struct device *dev)
+{
+ /* disable interrupts at boardlevel */
+ m147_pcc->lan_cntrl=0x0; /* disable interrupts */
+ lance_close(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ root_lance_dev = NULL;
+ return mvme147lance_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+ /* Walk the chain of devices, unregistering them */
+ struct m147lance_private *lp;
+ while (root_m147lance_dev) {
+ lp = root_m147lance_dev->next_module;
+ unregister_netdev(root_lance_dev->dev);
+ free_pages(lp->ram, 3);
+ kfree(root_lance_dev->dev);
+ root_lance_dev = lp;
+ }
+}
+
+#endif /* MODULE */
-/* $Id: ptifddi.c,v 1.7 1999/06/09 08:19:01 davem Exp $
+/* $Id: ptifddi.c,v 1.8 1999/08/08 01:35:56 davem Exp $
* ptifddi.c: Network driver for Performance Technologies single-attach
* and dual-attach FDDI sbus cards.
*
printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI "
"at 0x%08lx, irq %i, PCI latency %i\n", dev->name,
- pdev->base_address[0], dev->irq, pci_latency);
+ pdev->resource[0].start, dev->irq, pci_latency);
/*
* Remap the regs into kernel space.
*/
rrpriv->regs = (struct rr_regs *)
- ioremap(pdev->base_address[0], 0x1000);
+ ioremap(pdev->resource[0].start, 0x1000);
if (!rrpriv->regs){
printk(KERN_ERR "%s: Unable to map I/O register, "
pdev = pci_find_slot(pci_bus, pci_device_fn);
pci_irq_line = pdev->irq;
- pci_ioaddr = pdev->base_address[0];
+ pci_ioaddr = pdev->resource[0].start;
pcibios_read_config_word(pci_bus, pci_device_fn,
PCI_COMMAND, &pci_command);
* and pad structure members must be exchanged. Also, the structures
* need to be changed accordingly to the bus size.
*
+ * 981229 MSch: did just that for the 68k Mac port (32 bit, big endian),
+ * see CONFIG_MACSONIC branch below.
+ *
*/
#ifndef SONIC_H
#define SONIC_END_OF_LINKS 0x0001
+#ifdef CONFIG_MACSONIC
+/* Big endian like structures on Mac
+ * (680x0)
+ */
+
+typedef struct {
+ u32 rx_bufadr_l; /* receive buffer ptr */
+ u32 rx_bufadr_h;
+
+ u32 rx_bufsize_l; /* no. of words in the receive buffer */
+ u32 rx_bufsize_h;
+} sonic_rr_t;
+
+/*
+ * Sonic receive descriptor. Receive descriptors are
+ * kept in a linked list of these structures.
+ */
+
+typedef struct {
+ SREGS_PAD(pad0);
+ u16 rx_status; /* status after reception of a packet */
+ SREGS_PAD(pad1);
+ u16 rx_pktlen; /* length of the packet incl. CRC */
+
+ /*
+ * Pointers to the location in the receive buffer area (RBA)
+ * where the packet resides. A packet is always received into
+ * a contiguous piece of memory.
+ */
+ SREGS_PAD(pad2);
+ u16 rx_pktptr_l;
+ SREGS_PAD(pad3);
+ u16 rx_pktptr_h;
+
+ SREGS_PAD(pad4);
+ u16 rx_seqno; /* sequence no. */
+
+ SREGS_PAD(pad5);
+ u16 link; /* link to next RDD (end if EOL bit set) */
+
+ /*
+ * Owner of this descriptor, 0= driver, 1=sonic
+ */
+
+ SREGS_PAD(pad6);
+ u16 in_use;
+
+ caddr_t rda_next; /* pointer to next RD */
+} sonic_rd_t;
+
+
+/*
+ * Describes a Transmit Descriptor
+ */
+typedef struct {
+ SREGS_PAD(pad0);
+ u16 tx_status; /* status after transmission of a packet */
+ SREGS_PAD(pad1);
+ u16 tx_config; /* transmit configuration for this packet */
+ SREGS_PAD(pad2);
+ u16 tx_pktsize; /* size of the packet to be transmitted */
+ SREGS_PAD(pad3);
+ u16 tx_frag_count; /* no. of fragments */
+
+ SREGS_PAD(pad4);
+ u16 tx_frag_ptr_l;
+ SREGS_PAD(pad5);
+ u16 tx_frag_ptr_h;
+ SREGS_PAD(pad6);
+ u16 tx_frag_size;
+
+ SREGS_PAD(pad7);
+ u16 link; /* ptr to next descriptor */
+} sonic_td_t;
+
+
+/*
+ * Describes an entry in the CAM Descriptor Area.
+ */
+
+typedef struct {
+ SREGS_PAD(pad0);
+ u16 cam_entry_pointer;
+ SREGS_PAD(pad1);
+ u16 cam_cap0;
+ SREGS_PAD(pad2);
+ u16 cam_cap1;
+ SREGS_PAD(pad3);
+ u16 cam_cap2;
+} sonic_cd_t;
+
+#define CAM_DESCRIPTORS 16
+
+
+typedef struct {
+ sonic_cd_t cam_desc[CAM_DESCRIPTORS];
+ SREGS_PAD(pad);
+ u16 cam_enable;
+} sonic_cda_t;
+
+#else /* original declarations, little endian 32 bit */
+
/*
* structure definitions
*/
u16 cam_enable;
SREGS_PAD(pad);
} sonic_cda_t;
+#endif /* endianness */
/*
* Some tunables for the buffer areas. Power of 2 is required
* the current driver uses one receive buffer for each descriptor.
+ *
+ * MSch: use more buffer space for the slow m68k Macs!
*/
+#ifdef CONFIG_MACSONIC
+#define SONIC_NUM_RRS 32 /* number of receive resources */
+#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */
+#define SONIC_NUM_TDS 32 /* number of transmit descriptors */
+#else
#define SONIC_NUM_RRS 16 /* number of receive resources */
#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */
#define SONIC_NUM_TDS 16 /* number of transmit descriptors */
+#endif
#define SONIC_RBSIZE 1520 /* size of one resource buffer */
#define SONIC_RDS_MASK (SONIC_NUM_RDS-1)
}
hpreg_base = pdev->resource[0].start;
- if((pdev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ if ((pdev->resource[0].flags & IORESOURCE_IOPORT) != 0) {
printk("happymeal(PCI): Cannot find proper PCI device base address.\n");
return ENODEV;
}
- hpreg_base &= PCI_BASE_ADDRESS_MEM_MASK;
if (qfe_slot != -1 && prom_getproplen(node, "local-mac-address") == 6)
prom_getproperty(node, "local-mac-address", dev->dev_addr, 6);
-/* $Id: sunlance.c,v 1.86 1999/07/23 01:52:58 davem Exp $
+/* $Id: sunlance.c,v 1.87 1999/08/08 01:36:14 davem Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
#ifdef DEBUG
#define DPRINTK printk
#else
-static inline int DPRINTK() {return 0;}
+#define DPRINTK(format, args...)
#endif
static struct parport *this_port = NULL;
{
return PARPORT_CONTROL_SELECT |
PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
- /* fake value: select in, no reset,
+ /* fake value: interrupt enable, select in, no reset,
no autolf, no strobe - seems to be closest the wiring diagram */
}
parport_generic_irq(irq, (struct parport *) dev_id, regs);
}
-
static void amiga_init_state(struct pardevice *dev, struct parport_state *s)
{
s->u.amiga.data = 0;
amiga_inc_use_count,
amiga_dec_use_count,
- parport_ieee1284_epp_write_data,
- parport_ieee1284_epp_read_data, /* impossible? */
- parport_ieee1284_epp_write_addr,
- parport_ieee1284_epp_read_addr, /* impossible? */
+ NULL, /* epp_write_data */
+ NULL, /* epp_read_data */
+ NULL, /* epp_write_addr */
+ NULL, /* epp_read_addr */
- parport_ieee1284_ecp_write_data,
- parport_ieee1284_ecp_read_data, /* impossible? */
- parport_ieee1284_ecp_write_addr,
+ NULL, /* ecp_write_data */
+ NULL, /* ecp_read_data */
+ NULL, /* ecp_write_addr */
- parport_ieee1284_write_compat, /* FIXME - need to write amiga one */
- parport_ieee1284_read_nibble,
- parport_ieee1284_read_byte, /* impossible? */
+ NULL, /* compat_write_data */
+ NULL, /* nibble_read_data */
+ NULL, /* byte_read_data */
};
/* ----------- Initialisation code --------------------------------- */
IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
&pp_amiga_ops)))
return 0;
+ if (!request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p)) {
+ parport_unregister_port (p);
+ return 0;
+ }
+
this_port = p;
printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
/* XXX: set operating mode */
parport_proc_register(p);
- if (request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0,
- p->name, p)) {
- parport_unregister_port (p);
- return 0;
- }
- parport_announce_port (p);
+ parport_announce_port(p);
return 1;
void cleanup_module(void)
{
- if (p->irq != PARPORT_IRQ_NONE)
- free_irq(IRQ_AMIGA_CIAA_FLG, p);
+ if (this_port->irq != PARPORT_IRQ_NONE)
+ free_irq(IRQ_MFP_BUSY, this_port);
parport_proc_unregister(this_port);
parport_unregister_port(this_port);
}
}
static void
-parport_atari_init_state(struct parport_state *s)
+parport_atari_init_state(struct pardevice *d, struct parport_state *s)
{
}
parport_atari_inc_use_count,
parport_atari_dec_use_count,
- parport_ieee1284_epp_write_data,
- parport_ieee1284_epp_read_data,
- parport_ieee1284_epp_write_addr,
- parport_ieee1284_epp_read_addr,
+ NULL, /* epp_write_data */
+ NULL, /* epp_read_data */
+ NULL, /* epp_write_addr */
+ NULL, /* epp_read_addr */
- parport_ieee1284_ecp_write_data,
- parport_ieee1284_ecp_read_data,
- parport_ieee1284_ecp_write_addr,
+ NULL, /* ecp_write_data */
+ NULL, /* ecp_read_data */
+ NULL, /* ecp_write_addr */
- parport_ieee1284_write_compat,
- parport_ieee1284_read_nibble,
- parport_ieee1284_read_byte,
+ NULL, /* compat_write_data */
+ NULL, /* nibble_read_data */
+ NULL, /* byte_read_data */
};
void
cleanup_module(void)
{
- if (p->irq != PARPORT_IRQ_NONE)
- free_irq(IRQ_MFP_BUSY, p);
+ if (this_port->irq != PARPORT_IRQ_NONE)
+ free_irq(IRQ_MFP_BUSY, this_port);
parport_proc_unregister(this_port);
parport_unregister_port(this_port);
}
*
* Cleaned up include files - Russell King <linux@arm.uk.linux.org>
* DMA support - Bert De Jonghe <bert@sophis.be>
- * Better EPP probing - Carlos Henrique Bauer <chbauer@acm.org>
*/
/* This driver should work with any hardware that is broadly compatible
* only in register addresses (eg because your registers are on 32-bit
* word boundaries) then you can alter the constants in parport_pc.h to
* accomodate this.
+ *
+ * Note that the ECP registers may not start at offset 0x400 for PCI cards,
+ * but rather will start at port->base_hi.
*/
#include <linux/config.h>
outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
}
-#ifdef CONFIG_PARPORT_1284
+#if defined(CONFIG_PARPORT_1284) || defined(CONFIG_PARPORT_PC_FIFO)
/* Safely change the mode bits in the ECR */
static int change_mode(struct parport *p, int m)
{
return residue;
}
-#endif /* IEEE 1284 support */
+#endif /* IEEE 1284 support or FIFO support */
/*
* Clear TIMEOUT BIT in EPP MODE
}
if (p->dma == PARPORT_DMA_AUTO)
p->dma = PARPORT_DMA_NONE;
- if (p->dma != PARPORT_DMA_NONE)
- printk(", dma %d", p->dma);
#ifdef CONFIG_PARPORT_PC_FIFO
if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
- p->ops->compat_write_data =
- parport_pc_compat_write_block_pio;
+ p->ops->compat_write_data = parport_pc_compat_write_block_pio;
#ifdef CONFIG_PARPORT_1284
- p->ops->ecp_write_data =
- parport_pc_ecp_write_block_pio;
+ p->ops->ecp_write_data = parport_pc_ecp_write_block_pio;
#endif /* IEEE 1284 support */
- if (p->dma != PARPORT_DMA_NONE)
+ if (p->dma != PARPORT_DMA_NONE) {
+ printk(", dma %d", p->dma);
p->modes |= PARPORT_MODE_DMA;
- printk(", using FIFO");
+ }
+ else printk(", using FIFO");
}
+ else
+ /* We can't use the DMA channel after all. */
+ p->dma = PARPORT_DMA_NONE;
#endif /* Allowed to use FIFO/DMA */
printk(" [");
base = res->start;
end = res->end;
flags = res->flags;
- if (!flags)
+ if (!end)
continue;
if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
*
*/
-__initfunc(static int
+static int __init
normal_init (Scsi_Host_Template *tpnt, int board, int chip,
u32 base, int io_port, int irq, int dma, int pci_valid,
- unsigned char pci_bus, unsigned char pci_device_fn, long long options)) {
+ unsigned char pci_bus, unsigned char pci_device_fn, long long options){
struct Scsi_Host *instance;
struct NCR53c7x0_hostdata *hostdata;
char chip_str[80];
*
*/
-__initfunc(static int
+static int __init
ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
- unsigned char bus, unsigned char device_fn, long long options)) {
+ unsigned char bus, unsigned char device_fn, long long options){
unsigned short command;
#ifdef LINUX_1_2
unsigned long
" perhaps you specified an incorrect PCI bus, device, or function.\n", error);
return -1;
}
- io_port = pdev->base_address[0];
- base = pdev->base_address[1];
+ io_port = pdev->resource[0].start;
+ base = pdev->resource[1].start;
irq = pdev->irq;
/* If any one ever clones the NCR chips, this will have to change */
*
*/
-__initfunc(int
-NCR53c7xx_detect(Scsi_Host_Template *tpnt)) {
+int __init
+NCR53c7xx_detect(Scsi_Host_Template *tpnt){
int i;
int current_override;
int count; /* Number of boards detected */
*/
#undef inb
#undef outb
+#undef inw
+#undef outw
+#undef inl
+#undef outl
#define inb(x) 1
#define inw(x) 1
#define inl(x) 1
memset((void *)instance->hostdata[0], 0, 8192);
cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
- kernel_set_cachemode(instance->hostdata[0], 8192, KERNELMAP_NOCACHE_SER);
+ kernel_set_cachemode(instance->hostdata[0], 8192, IOMAP_NOCACHE_SER);
/* FIXME : if we ever support an ISA NCR53c7xx based board, we
need to check if the chip is running in a 16 bit mode, and if so
if (left < 0)
printk("scsi%d: loop detected in ncr reconncect list\n",
host->host_no);
- else if (ncr_search)
+ else if (ncr_search) {
if (found)
printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
host->host_no, c->pid);
/* If we're at the tail end of the issue queue, update that pointer too. */
found = 1;
}
+ }
/*
* Traverse the host running list until we find this command or discover
NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
else
NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
-#if 0
- /* Following disables snooping - run with caches disabled at first */
+ /* Following disables snooping - snooping is not required, as non-
+ * cached pages are used for shared data, and appropriate use is
+ * made of cache_push/cache_clear. Indeed, for 68060
+ * enabling snooping causes disk corruption of ext2fs free block
+ * bitmaps and the like. If you have a 68060 with snooping hardwared
+ * on, then you need to enable CONFIG_060_WRITETHROUGH.
+ */
NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
-#else
- /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating
- * cache lines. */
- NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0);
-#endif
/* Actually burst of eight, according to my 53c710 databook */
NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
static void
my_free_page (void *addr, int dummy)
{
- /* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING, which
+ /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
* XXX may be invalid (CONFIG_060_WRITETHROUGH)
*/
- kernel_set_cachemode((u32)addr, 4096, KERNELMAP_FULL_CACHING);
+ kernel_set_cachemode((u32)addr, 4096, IOMAP_FULL_CACHING);
free_page ((u32)addr);
}
memset((void *)real, 0, 4096);
cache_push(virt_to_phys((void *)real), 4096);
cache_clear(virt_to_phys((void *)real), 4096);
- kernel_set_cachemode(real, 4096, KERNELMAP_NOCACHE_SER);
+ kernel_set_cachemode(real, 4096, IOMAP_NOCACHE_SER);
tmp = ROUNDUP(real, void *);
#ifdef FORCE_DSA_ALIGNMENT
{
case MODE_SELECT:
case WRITE_6:
case WRITE_10:
- case START_STOP: /* also SCAN, which may do DATA OUT */
#if 0
printk("scsi%d : command is ", host->host_no);
print_command(cmd->cmnd);
*/
case TEST_UNIT_READY:
case ALLOW_MEDIUM_REMOVAL:
+ case START_STOP:
datain = dataout = 0;
break;
/*
}
}
}
- if (!(istat & (ISTAT_SIP|ISTAT_DIP)))
+ if (!(istat & (ISTAT_SIP|ISTAT_DIP))) {
if (stage == 0)
++stage;
else if (stage == 3)
break;
+ }
}
hostdata->state = STATE_HALTED;
restore_flags(flags);
if (hostdata->events)
vfree ((void *)hostdata->events);
- /* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING, which
+ /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
* XXX may be invalid (CONFIG_060_WRITETHROUGH)
*/
- kernel_set_cachemode((u32)hostdata, 8192, KERNELMAP_FULL_CACHING);
+ kernel_set_cachemode((u32)hostdata, 8192, IOMAP_FULL_CACHING);
free_pages ((u32)hostdata, 1);
return 1;
}
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sched.h>
*
* Returns : number of host adapters detected
**************************************************************************/
-__initfunc(int AM53C974_detect(Scsi_Host_Template * tpnt))
+int __init AM53C974_detect(Scsi_Host_Template * tpnt)
{
int count = 0; /* number of boards detected */
* set up by the BIOS (as reflected by contents of register CNTLREG1).
* This is the only BIOS assistance we need.
**************************************************************************/
-__initfunc(static int AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev))
+static int __init AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev)
{
AM53C974_local_declare();
int i, j;
instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata));
hostdata = (struct AM53C974_hostdata *) instance->hostdata;
instance->base = NULL;
- instance->io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+ instance->io_port = pdev->resource[0].start;
instance->irq = pdev->irq;
instance->dma_channel = -1;
AM53C974_setio(instance);
#ifdef MODULE
static Scsi_Host_Template driver_template = AM53C974;
+/* You can specify overrides=a,b,c,d in the same format at AM53C974=a,b,c,d
+ on boot up */
+
+MODULE_PARM(overrides, "1-32i");
#include "scsi_module.c"
#endif
static int probe_irq __initdata = 0;
-__initfunc(static void probe_intr(int irq, void *dev_id, struct pt_regs *regs))
+static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs)
{
probe_irq = irq;
}
-__initfunc(static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible))
+static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
{
NCR5380_local_declare();
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
* Inputs : instance, pointer to this instance. Unused.
*/
-__initfunc(static void NCR5380_print_options(struct Scsi_Host *instance))
+static void __init NCR5380_print_options(struct Scsi_Host *instance)
{
printk(" generic options"
#ifdef AUTOPROBE_IRQ
*
*/
-__initfunc(static void NCR5380_init(struct Scsi_Host *instance, int flags))
+static void __init NCR5380_init(struct Scsi_Host *instance, int flags)
{
NCR5380_local_declare();
int i, pass;
}
#endif USE_PIO
-__initfunc(int
-NCR53c406a_detect(Scsi_Host_Template * tpnt)){
+int __init
+NCR53c406a_detect(Scsi_Host_Template * tpnt){
struct Scsi_Host *shpnt;
#ifndef PORT_BASE
int i;
}
/* called from init/main.c */
-__initfunc(void NCR53c406a_setup(char *str, int *ints))
+void __init NCR53c406a_setup(char *str, int *ints)
{
static size_t setup_idx = 0;
size_t i;
outb(SYNC_MODE, SYNCOFF); /* synchronous mode */
}
-__initfunc(void calc_port_addr(void))
+void __init calc_port_addr(void)
{
/* Control Register Set 0 */
TC_LSB = (port_base+0x00);
The driver is currently maintained by Kai M{kisara (email
Kai.Makisara@metla.fi)
-Last modified: Sun Apr 18 13:24:43 1999 by makisara@home
+Last modified: Sat Aug 7 13:52:16 1999 by makisara@kai.makisara.local
BASICS
2^n * (page size). Because of this the actual buffer size may be
larger than the buffer size specified with ST_BUFFER_BLOCKS.
-Allocation of the buffers is done at run-time when they are
-needed. Allocation of the specified number of buffers can be done at
-initialization if ST_RUNTIME_BUFFERS is defined non-zero. The
-advantage of run-time allocation is that memory is not wasted for
-buffers not being used. The disadvantage is that there may not be
-memory available at the time when a buffer is needed for the first
-time (once a buffer is allocated, it is not released).
-
-The maximum number of buffers allocated at initialization is defined by
-ST_MAX_BUFFERS. One buffer is allocated for each drive detected when
-the driver is initialized up to the maximum. The minimum number of
-allocated buffers is ST_EXTRA_DEVS (in hosts.h). This ensures some
-functionality also for the drives found after tape driver
-initialization (a SCSI adapter driver is loaded as a module). The
-default for ST_EXTRA_DEVS is two. The driver tries to allocate new
-buffers at run-time if necessary.
+A small number of buffers are allocated at driver initialisation. The
+maximum number of these buffers is defined by ST_MAX_BUFFERS. The
+maximum can be changed with kernel or module startup options. One
+buffer is allocated for each drive detected when the driver is
+initialized up to the maximum. The minimum number of allocated buffers
+is ST_EXTRA_DEVS (in hosts.h) (unless this number exceeds the defined
+maximum). This ensures some functionality also for the drives found
+after tape driver initialization (a SCSI adapter driver is loaded as a
+module). The default for ST_EXTRA_DEVS is two.
+
+The driver tries to allocate new buffers at run-time if
+necessary. These buffers are freed after use. If the maximum number of
+initial buffers is set to zero, all buffer allocation is done at
+run-time. The advantage of run-time allocation is that memory is not
+wasted for buffers not being used. The disadvantage is that there may
+not be memory available at the time when a buffer is needed for the
+first time (once a buffer is allocated, it is not released). This risk
+should not be big if the tape drive is connected to a PCI adapter that
+supports scatter/gather (the allocation is not limited to "DMA memory"
+and the buffer can be composed of several fragments).
The threshold for triggering asynchronous write in fixed block mode
is defined by ST_WRITE_THRESHOLD. This may be optimized for each
extending the buffer will always fail.
-BOOT TIME CONFIGURATION
+MODULE PARAMETERS
The buffer size, write threshold, and the maximum number of allocated buffers
-are configurable at boot time using, e.g., the LILO command line. The option
-syntax is the following:
+are configurable when the driver is loaded as a module. The keywords are:
+
+buffer_kbs=xxx the buffer size in kilobytes is set to xxx
+write_threshold_kbs=xxx the write threshold in kilobytes set to xxx
+max_buffers=xxx the maximum number of tape buffer set to xxx
+max_sg_segs=xxx the maximum number of scatter/gather
+ segments
+
+Note that if the buffer size is changed but the write threshold is not
+set, the write threshold is set to the new buffer size - 2 kB.
+
+
+BOOT TIME CONFIGURATION
+
+If the driver is compiled into the kernel, the same parameters can be
+also set using, e.g., the LILO command line. The preferred syntax is
+to use the same keywords as when loading the driver as module. If
+several parameters are set, the keyword-value pairs are separated with
+a comma (no spaces allowed). A colon can be used instead of the equal
+mark. The definition is prepended by the string st=. Here is an
+example:
- st=aa[,bb[,cc]]
+ st=buffer_kbs:64,max_buffers:2
+
+The following syntax used by the old kernel versions is also supported:
+
+ st=aa[,bb[,cc[,dd]]]
where
aa is the buffer size in 1024 byte units
bb is the write threshold in 1024 byte units
cc is the maximum number of tape buffers to allocate (the number of
buffers is bounded also by the number of drives detected)
-
-
-MODULE PARAMETERS
-
-The same parameters can be also set when the driver is loaded as a
-module. The keywords are:
-
-buffer_kbs=xxx the buffer size in kilobytes is set to xxx
-write_threshold_kbs=xxx the write threshold in kilobytes set to xxx
-max_buffers=xxx the maximum number of tape buffer set to xxx
-max_sg_segs=xxx the maximum number of scatter/gather
- segments
+ dd is the maximum number of scatter/gather segments
IOCTLS
return FALSE;
}
-__initfunc (static inline int
- get_pci_irq(unsigned long port_base, unsigned char *apic_irq)) {
+static inline int __init
+get_pci_irq(unsigned long port_base, unsigned char *apic_irq){
#if defined(CONFIG_PCI)
return FALSE;
}
-__initfunc (static inline int port_detect \
- (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+static inline int __init port_detect \
+ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt){
unsigned char irq, dma_channel, subversion, i;
unsigned char protocol_rev, apic_irq;
struct eata_info info;
return TRUE;
}
-__initfunc (void eata2x_setup(char *str, int *ints)) {
+void __init eata2x_setup(char *str, int *ints){
int i, argc = ints[0];
char *cur = str, *pc;
return;
}
-__initfunc (static void add_pci_ports(void)) {
+static void __init add_pci_ports(void){
#if defined(CONFIG_PCI)
return;
}
-__initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
+int __init eata2x_detect(Scsi_Host_Template *tpnt){
unsigned int j = 0, k;
IRQ_FLAGS
/* We now have the appropriate device function for the FD board so we
just read the PCI config info from the registers. */
- pci_base = pdev->base_address[0];
+ pci_base = pdev->resource[0].start;
pci_irq = pdev->irq;
/* Now we have the I/O base address and interrupt from the PCI
configuration registers. */
*irq = pci_irq;
- *iobase = (pci_base & PCI_BASE_ADDRESS_IO_MASK);
+ *iobase = pci_base;
#if DEBUG_DETECT
printk( "scsi: <fdomain> TMC-3260 detect:"
*
*/
-__initfunc(static void internal_setup(int board, char *str, int *ints)) {
+static void __init internal_setup(int board, char *str, int *ints){
static int commandline_current = 0;
switch (board) {
case BOARD_NCR5380:
* equal to the number of ints.
*/
-__initfunc(void generic_NCR5380_setup (char *str, int *ints)) {
+void __init generic_NCR5380_setup (char *str, int *ints){
internal_setup (BOARD_NCR5380, str, ints);
}
* equal to the number of ints.
*/
-__initfunc(void generic_NCR53C400_setup (char *str, int *ints)) {
+void __init generic_NCR53C400_setup (char *str, int *ints){
internal_setup (BOARD_NCR53C400, str, ints);
}
*
*/
-__initfunc(int generic_NCR5380_detect(Scsi_Host_Template * tpnt)) {
+int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){
static int current_override = 0;
int count, i;
u_int *ports;
/* controller search and initialization functions */
-__initfunc (static int gdth_search_eisa(ushort eisa_adr))
+static int __init gdth_search_eisa(ushort eisa_adr)
{
ulong32 id;
}
-__initfunc (static int gdth_search_isa(ulong32 bios_adr))
+static int __init gdth_search_isa(ulong32 bios_adr)
{
void *addr;
ulong32 id;
}
-__initfunc (static int gdth_search_pci(gdth_pci_str *pcistr))
+static int __init gdth_search_pci(gdth_pci_str *pcistr)
{
ulong32 base0, base1, base2;
ushort device_id, cnt;
if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 &&
device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP)
continue;
-#if LINUX_VERSION_CODE >= 0x2015C
pdev = NULL;
while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev))
!= NULL) {
pcistr[cnt].bus = pdev->bus->number;
pcistr[cnt].device_fn = pdev->devfn;
pcistr[cnt].irq = pdev->irq;
- base0 = pdev->base_address[0];
- base1 = pdev->base_address[1];
- base2 = pdev->base_address[2];
+ base0 = pdev->resource[0].flags;
+ base1 = pdev->resource[1].flags;
+ base2 = pdev->resource[2].flags;
if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */
device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */
if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
PCI_BASE_ADDRESS_SPACE_MEMORY)
continue;
- pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+ pcistr[cnt].dpmem = pdev->resource[0].start;
} else { /* GDT6110, GDT6120, .. */
if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
PCI_BASE_ADDRESS_SPACE_MEMORY ||
(base1 & PCI_BASE_ADDRESS_SPACE) !=
PCI_BASE_ADDRESS_SPACE_IO)
continue;
- pcistr[cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
- pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
- pcistr[cnt].io = base1 & PCI_BASE_ADDRESS_IO_MASK;
+ pcistr[cnt].dpmem = pdev->resource[2].start;
+ pcistr[cnt].io_mm = pdev->resource[0].start;
+ pcistr[cnt].io = pdev->resource[1].start;
}
TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn),
pcistr[cnt].irq, pcistr[cnt].dpmem));
cnt++;
}
-#else
- idx = 0;
- while (!pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,idx++,
- &pcistr[cnt].bus,&pcistr[cnt].device_fn)) {
- if (cnt >= MAXHA)
- return cnt;
- /* GDT PCI ctr. found, now read resources from config space */
-#if LINUX_VERSION_CODE >= 0x010300
-#define GDTH_BASEP (int *)
-#else
-#define GDTH_BASEP
-#endif
- if ((error = pcibios_read_config_dword(pcistr[cnt].bus,
- pcistr[cnt].device_fn,
- PCI_BASE_ADDRESS_0,
- GDTH_BASEP&base0)) ||
- (error = pcibios_read_config_dword(pcistr[cnt].bus,
- pcistr[cnt].device_fn,
- PCI_BASE_ADDRESS_1,
- GDTH_BASEP&base1)) ||
- (error = pcibios_read_config_dword(pcistr[cnt].bus,
- pcistr[cnt].device_fn,
- PCI_BASE_ADDRESS_2,
- GDTH_BASEP&base2)) ||
- (error = pcibios_read_config_byte(pcistr[cnt].bus,
- pcistr[cnt].device_fn,
- PCI_INTERRUPT_LINE,
- &pcistr[cnt].irq))) {
- printk("GDT-PCI: error %d reading configuration space", error);
- continue;
- }
- pcistr[cnt].device_id = device_id;
- if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */
- device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */
- if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
- PCI_BASE_ADDRESS_SPACE_MEMORY)
- continue;
- pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
- } else { /* GDT6110, GDT6120, .. */
- if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
- PCI_BASE_ADDRESS_SPACE_MEMORY ||
- (base2 & PCI_BASE_ADDRESS_SPACE) !=
- PCI_BASE_ADDRESS_SPACE_MEMORY ||
- (base1 & PCI_BASE_ADDRESS_SPACE) !=
- PCI_BASE_ADDRESS_SPACE_IO)
- continue;
- pcistr[cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
- pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
- pcistr[cnt].io = base1 & PCI_BASE_ADDRESS_IO_MASK;
- }
- TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
- pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn),
- pcistr[cnt].irq, pcistr[cnt].dpmem));
- cnt++;
- }
-#endif
}
return cnt;
}
-__initfunc (static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt))
+static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
{
gdth_pci_str temp;
int i, changed;
}
-__initfunc (static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha))
+static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
{
ulong32 retries,id;
unchar prot_ver,eisacf,i,irq_found;
}
-__initfunc (static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha))
+static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
{
register gdt2_dpram_str *dp2_ptr;
int i;
}
-__initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
+static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
{
register gdt6_dpram_str *dp6_ptr;
register gdt6c_dpram_str *dp6c_ptr;
/* controller protocol functions */
-__initfunc (static void gdth_enable_int(int hanum))
+static void __init gdth_enable_int(int hanum)
{
gdth_ha_str *ha;
ulong flags;
/* search for devices */
-__initfunc (static int gdth_search_drives(int hanum))
+static int __init gdth_search_drives(int hanum)
{
register gdth_ha_str *ha;
ushort cdev_cnt, i;
#endif
-__initfunc (int gdth_detect(Scsi_Host_Template *shtp))
+int __init gdth_detect(Scsi_Host_Template *shtp)
{
struct Scsi_Host *shp;
gdth_ha_str *ha;
/* called from init/main.c */
-__initfunc (void gdth_setup(char *str,int *ints))
+void __init gdth_setup(char *str,int *ints)
{
int i, argc;
char *cur_str, *argv;
shpnt->eh_notify = NULL;
}
-__initfunc(unsigned int scsi_init(void))
+unsigned int __init scsi_init(void)
{
static int called = 0;
int i, pcount;
dRegValue = 0;
wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
if (Addi91u_into_Adapter_table(wBIOS,
- (pDev->base_address[0] & 0xFFFE),
+ (pDev->resource[0].start),
pDev->irq,
pDev->bus->number,
(pDev->devfn >> 3)
#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
bPCIBusNum = pdev->bus->number;
bPCIDeviceNum = pdev->devfn;
- dRegValue = pdev->base_address[0];
+ dRegValue = pdev->resource[0].start;
if (dRegValue == -1) { /* Check return code */
printk("\n\rinia100: orchid read configuration error.\n");
return (0); /* Read configuration space error */
PCI_FUNC (pciDevFun));
/* Read the base port and IRQ from PCI */
-#if LINUX_VERSION_CODE < 0x20100
- pcibios_read_config_dword (pciBus, pciDevFun,
- PCI_BASE_ADDRESS_0,
- (u_int *) & megaBase);
- pcibios_read_config_byte (pciBus, pciDevFun,
- PCI_INTERRUPT_LINE,
- &megaIrq);
-#else
- megaBase = pdev->base_address[0];
+ megaBase = pdev->resource[0].start;
megaIrq = pdev->irq;
-#endif
pciIdx++;
if (flag & BOARD_QUARTZ) {
*
*/
-__initfunc(static void
- enable_board( int board_num, unsigned short port ))
+static void __init
+ enable_board( int board_num, unsigned short port )
{
outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
outb( port >> 2, MASTER_ADDRESS_PTR );
*
*/
-__initfunc (static void
- init_board( unsigned short io_port, int irq, int force_irq ))
+static void __init
+ init_board( unsigned short io_port, int irq, int force_irq )
{
unsigned int tmp;
unsigned int pas_irq_code;
* Returns : 0 if board not found, 1 if found.
*/
-__initfunc(static int
- pas16_hw_detect( unsigned short board_num ))
+static int __init
+ pas16_hw_detect( unsigned short board_num )
{
unsigned char board_rev, tmp;
unsigned short io_port = bases[ board_num ].io_port;
*
*/
-__initfunc(void pas16_setup(char *str, int *ints)) {
+void __init pas16_setup(char *str, int *ints)
+{
static int commandline_current = 0;
int i;
if (ints[0] != 2)
*
*/
-__initfunc(int pas16_detect(Scsi_Host_Template * tpnt)) {
+int __init pas16_detect(Scsi_Host_Template * tpnt)
+{
static int current_override = 0;
static unsigned short current_base = 0;
struct Scsi_Host *instance;
/* do the locking and issue the command */
SCpnt->request.rq_dev = cdi->dev;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
+ /* scsi_do_cmd sets the command length */
SCpnt->cmd_len = 0;
SCpnt->request.sem = &sem;
spin_lock_irqsave(&io_request_lock, flags);
Copyright 1992 - 1999 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Tue May 18 08:32:34 1999 by makisara@home
+ Last modified: Sat Aug 7 13:54:31 1999 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
*/
#include "constants.h"
+static int buffer_kbs = 0;
+static int write_threshold_kbs = 0;
+static int max_buffers = (-1);
+static int max_sg_segs = 0;
#ifdef MODULE
+MODULE_AUTHOR("Kai Makisara");
+MODULE_DESCRIPTION("SCSI Tape Driver");
MODULE_PARM(buffer_kbs, "i");
MODULE_PARM(write_threshold_kbs, "i");
MODULE_PARM(max_buffers, "i");
MODULE_PARM(max_sg_segs, "i");
-static int buffer_kbs = 0;
-static int write_threshold_kbs = 0;
-static int max_buffers = 0;
-static int max_sg_segs = 0;
+#else
+static struct st_dev_parm {
+ char *name;
+ int *val;
+} parms[] __initdata = {
+ {"buffer_kbs", &buffer_kbs},
+ {"write_threshold_kbs", &write_threshold_kbs},
+ {"max_buffers", &max_buffers},
+ {"max_sg_segs", &max_sg_segs}};
#endif
+
/* The default definitions have been moved to st_options.h */
#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_KILOBYTE)
else
printk(KERN_WARNING
"st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
- dev, result, suggestion(result), driver_byte(result),
+ dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
host_byte(result));
}
}
+/* Validate the options from command line or module parameters */
+static void validate_options(void)
+{
+ if (buffer_kbs > 0)
+ st_buffer_size = buffer_kbs * ST_KILOBYTE;
+ if (write_threshold_kbs > 0)
+ st_write_threshold = write_threshold_kbs * ST_KILOBYTE;
+ else if (buffer_kbs > 0)
+ st_write_threshold = st_buffer_size - 2048;
+ if (st_write_threshold > st_buffer_size) {
+ st_write_threshold = st_buffer_size;
+ printk(KERN_WARNING "st: write_threshold limited to %d bytes.\n",
+ st_write_threshold);
+ }
+ if (max_buffers >= 0)
+ st_max_buffers = max_buffers;
+ if (max_sg_segs >= ST_FIRST_SG)
+ st_max_sg_segs = max_sg_segs;
+}
+
#ifndef MODULE
-/* Set the boot options. Syntax: st=xxx,yyy
- where xxx is buffer size in 1024 byte blocks and yyy is write threshold
- in 1024 byte blocks. */
- __initfunc( void
-st_setup(char *str, int *ints))
+/* Set the boot options. Syntax is defined in README.st.
+*/
+static int __init st_setup(char *str)
{
- if (ints[0] > 0 && ints[1] > 0)
- st_buffer_size = ints[1] * ST_KILOBYTE;
- if (ints[0] > 1 && ints[2] > 0) {
- st_write_threshold = ints[2] * ST_KILOBYTE;
- if (st_write_threshold > st_buffer_size)
- st_write_threshold = st_buffer_size;
- }
- if (ints[0] > 2 && ints[3] > 0)
- st_max_buffers = ints[3];
+ int i, len, ints[5];
+ char *stp;
+
+ stp = get_options(str, ARRAY_SIZE(ints), ints);
+
+ if (ints[0] > 0) {
+ for (i=0; i < ints[0] && i < ARRAY_SIZE(parms) ; i++)
+ *parms[i].val = ints[i + 1];
+ }
+ else {
+ while (stp != NULL) {
+ for (i=0; i < ARRAY_SIZE(parms); i++) {
+ len = strlen(parms[i].name);
+ if (!strncmp(stp, parms[i].name, len) &&
+ (*(stp + len) == ':' || *(stp + len) == '=')) {
+ *parms[i].val = simple_strtoul(stp + len + 1, NULL, 0);
+ break;
+ }
+ }
+ if (i >= sizeof(parms) / sizeof(struct st_dev_parm))
+ printk(KERN_WARNING "st: illegal parameter in '%s'\n",
+ stp);
+ stp = strchr(stp, ',');
+ if (stp)
+ stp++;
+ }
+ }
+
+ validate_options();
+
+ return 1;
}
+
+__setup("st=", st_setup);
+
#endif
{
int i;
Scsi_Tape * STp;
-#if !ST_RUNTIME_BUFFERS
int target_nbr;
-#endif
if (st_template.dev_noticed == 0) return 0;
+ printk(KERN_INFO "st: bufsize %d, wrt %d, max init. buffers %d, s/g segs %d.\n",
+ st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+
if(!st_registered) {
if (register_chrdev(SCSI_TAPE_MAJOR,"st",&st_fops)) {
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",MAJOR_NR);
return 1;
}
-#if ST_RUNTIME_BUFFERS
- st_nbr_buffers = 0;
-#else
target_nbr = st_template.dev_noticed;
if (target_nbr < ST_EXTRA_DEVS)
target_nbr = ST_EXTRA_DEVS;
for (i=st_nbr_buffers=0; i < target_nbr; i++) {
if (!new_tape_buffer(TRUE, TRUE)) {
if (i == 0) {
-#if 0
- printk(KERN_ERR "Can't continue without at least one tape buffer.\n");
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- scsi_init_free((char *) st_buffers,
- st_template.dev_max * sizeof(ST_buffer *));
- scsi_init_free((char *) scsi_tapes,
- st_template.dev_max * sizeof(Scsi_Tape));
- return 1;
-#else
printk(KERN_INFO "No tape buffers allocated at initialization.\n");
break;
-#endif
}
printk(KERN_INFO "Number of tape buffers adjusted.\n");
break;
}
}
-#endif
+
return 0;
}
#ifdef MODULE
-int init_module(void) {
+int __init init_module(void) {
int result;
- if (buffer_kbs > 0)
- st_buffer_size = buffer_kbs * ST_KILOBYTE;
- if (write_threshold_kbs > 0)
- st_write_threshold = write_threshold_kbs * ST_KILOBYTE;
- if (st_write_threshold > st_buffer_size)
- st_write_threshold = st_buffer_size;
- if (max_buffers > 0)
- st_max_buffers = max_buffers;
- if (max_sg_segs >= ST_FIRST_SG)
- st_max_sg_segs = max_sg_segs;
- printk(KERN_INFO "st: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n",
- st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+ validate_options();
st_template.module = &__this_module;
result = scsi_register_module(MODULE_SCSI_DEV, &st_template);
/*
The compile-time configurable defaults for the Linux SCSI tape driver.
- Copyright 1995 Kai Makisara.
+ Copyright 1995-1999 Kai Makisara.
- Last modified: Wed Sep 2 21:24:07 1998 by root@home
+ Last modified: Sat Aug 7 13:42:21 1999 by makisara@kai.makisara.local
*/
#ifndef _ST_OPTIONS_H
#define _ST_OPTIONS_H
-/* The driver allocates the tape buffers when needed if ST_RUNTIME_BUFFERS
- is nonzero. Otherwise a number of buffers are allocated at initialization.
- The drawback of runtime allocation is that allocation may fail. In any
- case the driver tries to allocate a new tape buffer when none is free. */
-#define ST_RUNTIME_BUFFERS 0
-
/* The minimum limit for the number of SCSI tape devices is determined by
ST_MAX_TAPES. If the number of tape devices and the "slack" defined by
ST_EXTRA_DEVS exceeds ST_MAX_TAPES, the large number is used. */
below. */
#define ST_WRITE_THRESHOLD_BLOCKS 30
-/* The maximum number of tape buffers the driver allocates. The number
- is also constrained by the number of drives detected. Determines the
- maximum number of concurrently active tape drives. */
+/* The maximum number of tape buffers the driver tries to allocate at
+ driver initialisation. The number is also constrained by the number
+ of drives detected. If more buffers are needed, they are allocated
+ at run time and freed after use. */
#define ST_MAX_BUFFERS (2 + ST_EXTRA_DEVS)
/* Maximum number of scatter/gather segments */
*
*/
-__initfunc(void t128_setup(char *str, int *ints)) {
+void __init t128_setup(char *str, int *ints){
static int commandline_current = 0;
int i;
if (ints[0] != 2)
*
*/
-__initfunc(int t128_detect(Scsi_Host_Template * tpnt)) {
+int __init t128_detect(Scsi_Host_Template * tpnt){
static int current_override = 0, current_base = 0;
struct Scsi_Host *instance;
unsigned char *base;
# define PCI_PRESENT pci_present ()
# define PCI_SET_MASTER pci_set_master (pdev)
# define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev))
-# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq
+# define PCI_GET_IO_AND_IRQ io_port = pdev->resource[0].start; irq = pdev->irq
#else
# include <linux/bios32.h>
# define PDEV pbus, pdevfn
return FALSE;
}
-__initfunc (static inline int port_detect \
- (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+static inline int __init port_detect \
+ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) {
unsigned char irq, dma_channel, subversion, i;
unsigned char in_byte;
char *bus_type, dma_name[16];
return TRUE;
}
-__initfunc (void u14_34f_setup(char *str, int *ints)) {
+void __init u14_34f_setup(char *str, int *ints)
+{
int i, argc = ints[0];
char *cur = str, *pc;
return;
}
-__initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
+int __init u14_34f_detect(Scsi_Host_Template *tpnt)
+{
unsigned int j = 0, k;
IRQ_FLAGS
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/version.h>
+#include <linux/init.h>
#include <asm/irq.h>
#if LINUX_VERSION_CODE >= 0x010300
static inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
{
regp->SASR = reg_num;
+ mb();
return(regp->SCMD);
}
static inline void write_wd33c93(wd33c93_regs *regp,uchar reg_num, uchar value)
{
regp->SASR = reg_num;
+ mb();
regp->SCMD = value;
+ mb();
}
static inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd)
{
regp->SASR = WD_COMMAND;
+ mb();
regp->SCMD = cmd;
+ mb();
}
static void write_wd33c93_count(wd33c93_regs *regp,unsigned long value)
{
regp->SASR = WD_TRANSFER_COUNT_MSB;
+ mb();
regp->SCMD = value >> 16;
regp->SCMD = value >> 8;
regp->SCMD = value;
+ mb();
}
unsigned long value;
regp->SASR = WD_TRANSFER_COUNT_MSB;
+ mb();
value = regp->SCMD << 16;
value |= regp->SCMD << 8;
value |= regp->SCMD;
+ mb();
return value;
}
static char setup_used[MAX_SETUP_ARGS];
static int done_setup = 0;
-void wd33c93_setup (char *str, int *ints)
+int wd33c93_setup (char *str)
{
-int i,x;
-char *p1,*p2;
+ int i;
+ char *p1,*p2;
/* The kernel does some processing of the command-line before calling
* this function: If it begins with any decimal or hex number arguments,
p1 = setup_buffer;
*p1 = '\0';
+#if 0
+/*
+ * Old style command line arguments are now dead
+ */
if (ints[0]) {
for (i=0; i<ints[0]; i++) {
x = vsprintf(p1,"nosync:0x%02x,",&(ints[i+1]));
p1 += x;
}
}
+#endif
if (str)
strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
for (i=0; i<MAX_SETUP_ARGS; i++)
setup_used[i] = 0;
done_setup = 1;
+
+ return 0;
}
+__setup("wd33c93", wd33c93_setup);
+
/* check_setup_args() returns index if key found, 0 if not
*/
char buf[32];
if (!done_setup && setup_strings)
- wd33c93_setup(setup_strings,0);
+ wd33c93_setup(setup_strings);
hostdata = (struct WD33C93_hostdata *)instance->hostdata;
uchar clock_freq;
uchar chip; /* what kind of wd33c93? */
uchar microcode; /* microcode rev */
+ uchar dma_buffer_pool; /* FEF: buffer from chip_ram? */
int dma_dir; /* data transfer dir. */
dma_setup_t dma_setup;
dma_stop_t dma_stop;
unsigned int dma_xfer_mask;
uchar *dma_bounce_buffer;
unsigned int dma_bounce_len;
- uchar dma_buffer_pool; /* FEF: buffer from chip_ram? */
volatile uchar busy[8]; /* index = target, bit = lun */
volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */
volatile Scsi_Cmnd *selecting; /* trying to select this command */
dep_tristate 'C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND
dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
+dep_tristate 'ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o
-#jnx
+obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
obj-$(CONFIG_SOUND_CMPCI) += cmpci.o
obj-$(CONFIG_SOUND_ES1370) += es1370.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o
-obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
+obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o
# Declare multi-part drivers.
--- /dev/null
+/*****************************************************************************/
+
+/*
+ * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver.
+ *
+ * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * 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.
+ *
+ * Module command line parameters:
+ * none so far
+ *
+ * Supported devices:
+ * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
+ * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
+ * /dev/midi simple MIDI UART interface, no ioctl
+ *
+ * Revision history
+ * 10.11.98 0.1 Initial release (without any hardware)
+ * 22.03.99 0.2 cinfo.blocks should be reset after GETxPTR ioctl.
+ * reported by Johan Maes <joma@telindus.be>
+ * return EAGAIN instead of EBUSY when O_NONBLOCK
+ * read/write cannot be executed
+ * 07.04.99 0.3 implemented the following ioctl's: SOUND_PCM_READ_RATE,
+ * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
+ * Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ * 15.06.99 0.4 Fix bad allocation bug.
+ * Thanks to Deti Fliegl <fliegl@in.tum.de>
+ * 28.06.99 0.5 Add pci_set_master
+ *
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/version.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/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <asm/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+
+#include "dm.h"
+
+/* --------------------------------------------------------------------- */
+
+#ifndef PCI_VENDOR_ID_ESS
+#define PCI_VENDOR_ID_ESS 0x125d
+#endif
+#ifndef PCI_DEVICE_ID_ESS_SOLO1
+#define PCI_DEVICE_ID_ESS_SOLO1 0x1969
+#endif
+
+#define SOLO1_MAGIC ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
+
+#define IOBASE_EXTENT 16
+#define SBBASE_EXTENT 16
+#define VCBASE_EXTENT 16
+#define MPUBASE_EXTENT 4
+#define GPBASE_EXTENT 4
+
+
+/* MIDI buffer sizes */
+
+#define MIDIINBUF 256
+#define MIDIOUTBUF 256
+
+#define FMODE_MIDI_SHIFT 3
+#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
+#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+
+#define FMODE_DMFM 0x10
+
+/* --------------------------------------------------------------------- */
+
+#define DEBUGREC
+
+/* --------------------------------------------------------------------- */
+
+struct solo1_state {
+ /* magic */
+ unsigned int magic;
+
+ /* we keep sb cards in a linked list */
+ struct solo1_state *next;
+
+ /* soundcore stuff */
+ int dev_audio;
+ int dev_mixer;
+ int dev_midi;
+ int dev_dmfm;
+
+ /* hardware resources */
+ unsigned long iobase, sbbase, vcbase, mpubase, gpbase; /* long for SPARC */
+ unsigned int irq;
+
+ /* mixer registers; there is no HW readback */
+ struct {
+ unsigned short vol[10];
+ unsigned int recsrc;
+ unsigned int modcnt;
+ unsigned short micpreamp;
+ } mix;
+
+ /* wave stuff */
+ unsigned fmt;
+ unsigned channels;
+ unsigned rate;
+ unsigned char clkdiv;
+ unsigned ena;
+
+ spinlock_t lock;
+ struct semaphore open_sem;
+ mode_t open_mode;
+ wait_queue_head_t open_wait;
+
+ struct dmabuf {
+ void *rawbuf;
+ unsigned buforder;
+ unsigned numfrag;
+ unsigned fragshift;
+ unsigned hwptr, swptr;
+ unsigned total_bytes;
+ int count;
+ unsigned error; /* over/underrun */
+ wait_queue_head_t wait;
+ /* redundant, but makes calculations easier */
+ unsigned fragsize;
+ unsigned dmasize;
+ unsigned fragsamples;
+ /* OSS stuff */
+ unsigned mapped:1;
+ unsigned ready:1;
+ unsigned endcleared:1;
+ unsigned ossfragshift;
+ int ossmaxfrags;
+ unsigned subdivision;
+ } dma_dac, dma_adc;
+
+ /* midi stuff */
+ struct {
+ unsigned ird, iwr, icnt;
+ unsigned ord, owr, ocnt;
+ wait_queue_head_t iwait;
+ wait_queue_head_t owait;
+ struct timer_list timer;
+ unsigned char ibuf[MIDIINBUF];
+ unsigned char obuf[MIDIOUTBUF];
+ } midi;
+};
+
+/* --------------------------------------------------------------------- */
+
+struct solo1_state *devs = NULL;
+
+/* --------------------------------------------------------------------- */
+
+extern inline void write_seq(struct solo1_state *s, unsigned char data)
+{
+ int i;
+ unsigned long flags;
+
+ /* the __cli stunt is to send the data within the command window */
+ for (i = 0; i < 0xffff; i++) {
+ __save_flags(flags);
+ __cli();
+ if (!(inb(s->sbbase+0xc) & 0x80)) {
+ outb(data, s->sbbase+0xc);
+ __restore_flags(flags);
+ return;
+ }
+ __restore_flags(flags);
+ }
+}
+
+extern inline int read_seq(struct solo1_state *s, unsigned char *data)
+{
+ int i;
+
+ if (!data)
+ return 0;
+ for (i = 0; i < 0xffff; i++)
+ if (inb(s->sbbase+0xe) & 0x80) {
+ *data = inb(s->sbbase+0xa);
+ return 1;
+ }
+ return 0;
+}
+
+static int inline reset_ctrl(struct solo1_state *s)
+{
+ int i;
+
+ outb(3, s->sbbase+6); /* clear sequencer and FIFO */
+ udelay(10);
+ outb(0, s->sbbase+6);
+ for (i = 0; i < 0xffff; i++)
+ if (inb(s->sbbase+0xe) & 0x80)
+ if (inb(s->sbbase+0xa) == 0xaa) {
+ write_seq(s, 0xc6); /* enter enhanced mode */
+ return 1;
+ }
+ return 0;
+}
+
+static void write_ctrl(struct solo1_state *s, unsigned char reg, unsigned char data)
+{
+ write_seq(s, reg);
+ write_seq(s, data);
+}
+
+static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg)
+{
+ unsigned char r;
+
+ write_seq(s, 0xc0);
+ write_seq(s, reg);
+ read_seq(s, &r);
+ return r;
+}
+
+static void write_mixer(struct solo1_state *s, unsigned char reg, unsigned char data)
+{
+ outb(reg, s->sbbase+4);
+ outb(data, s->sbbase+5);
+}
+
+static unsigned char read_mixer(struct solo1_state *s, unsigned char reg)
+{
+ outb(reg, s->sbbase+4);
+ return inb(s->sbbase+5);
+}
+
+/* --------------------------------------------------------------------- */
+
+extern inline unsigned ld2(unsigned int x)
+{
+ unsigned r = 0;
+
+ if (x >= 0x10000) {
+ x >>= 16;
+ r += 16;
+ }
+ if (x >= 0x100) {
+ x >>= 8;
+ r += 8;
+ }
+ if (x >= 0x10) {
+ x >>= 4;
+ r += 4;
+ }
+ if (x >= 4) {
+ x >>= 2;
+ r += 2;
+ }
+ if (x >= 2)
+ r++;
+ return r;
+}
+
+/* --------------------------------------------------------------------- */
+
+extern inline void stop_dac(struct solo1_state *s)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ s->ena &= ~FMODE_WRITE;
+ write_mixer(s, 0x78, 0x10);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void start_dac(struct solo1_state *s)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
+ s->ena |= FMODE_WRITE;
+ write_mixer(s, 0x78, 0x13);
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+extern inline void stop_adc(struct solo1_state *s)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ s->ena &= ~FMODE_READ;
+ write_ctrl(s, 0xb8, 0xe);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void start_adc(struct solo1_state *s)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+ && s->dma_adc.ready) {
+ s->ena |= FMODE_READ;
+ write_ctrl(s, 0xb8, 0xf);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMAbuffer: 0x%08lx\n", (long)s->dma_adc.rawbuf);
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ outb(0, s->vcbase+0xd); /* master reset */
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. clr)\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ outb(1, s->vcbase+0xf); /* mask */
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. mask)\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ outb(0x54/*0x14*/, s->vcbase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. wrmode)\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ outl(virt_to_bus(s->dma_adc.rawbuf), s->vcbase);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. wrbase)\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ outw(s->dma_adc.dmasize-1, s->vcbase+4);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. wrcnt)\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ outb(0, s->vcbase+0xf);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. clrmask)\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x DMAmask: 0x%02x SBstat: 0x%02x\n",
+ read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->vcbase+0xf), inb(s->sbbase+0xc));
+
+ printk(KERN_DEBUG "solo1: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
+ KERN_DEBUG "solo1: B1: 0x%02x B2: 0x%02x B4: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n",
+ read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
+ read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb4), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8),
+ read_ctrl(s, 0xb9));
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
+#define DMABUF_MINORDER 1
+
+extern inline void dealloc_dmabuf(struct dmabuf *db)
+{
+ unsigned long map, mapend;
+
+ if (db->rawbuf) {
+ /* undo marking the pages as reserved */
+ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+ for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+ clear_bit(PG_reserved, &mem_map[map].flags);
+ free_pages((unsigned long)db->rawbuf, db->buforder);
+ }
+ db->rawbuf = NULL;
+ db->mapped = db->ready = 0;
+}
+
+static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, int gfp_mask)
+{
+ int order;
+ unsigned bytespersec;
+ unsigned bufs, sample_shift = 0;
+ unsigned long map, mapend;
+
+ db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+ if (!db->rawbuf) {
+ db->ready = db->mapped = 0;
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+ if ((db->rawbuf = (void *)__get_free_pages(gfp_mask, order)))
+ break;
+ if (!db->rawbuf)
+ return -ENOMEM;
+ db->buforder = order;
+ /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+ for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+ set_bit(PG_reserved, &mem_map[map].flags);
+ }
+ if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ sample_shift++;
+ if (s->channels > 1)
+ sample_shift++;
+ bytespersec = s->rate << sample_shift;
+ bufs = PAGE_SIZE << db->buforder;
+ if (db->ossfragshift) {
+ if ((1000 << db->ossfragshift) < bytespersec)
+ db->fragshift = ld2(bytespersec/1000);
+ else
+ db->fragshift = db->ossfragshift;
+ } else {
+ db->fragshift = ld2(bytespersec/100/(db->subdivision ? db->subdivision : 1));
+ if (db->fragshift < 3)
+ db->fragshift = 3;
+ }
+ db->numfrag = bufs >> db->fragshift;
+ while (db->numfrag < 4 && db->fragshift > 3) {
+ db->fragshift--;
+ db->numfrag = bufs >> db->fragshift;
+ }
+ db->fragsize = 1 << db->fragshift;
+ if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+ db->numfrag = db->ossmaxfrags;
+ db->fragsamples = db->fragsize >> sample_shift;
+ db->dmasize = db->numfrag << db->fragshift;
+ return 0;
+}
+
+extern inline int prog_dmabuf_adc(struct solo1_state *s)
+{
+ unsigned long va;
+ int c;
+
+ stop_adc(s);
+ if ((c = prog_dmabuf(s, &s->dma_adc, GFP_KERNEL | GFP_DMA)))
+ return c;
+ va = virt_to_bus(s->dma_adc.rawbuf);
+ if ((va & ~((1<<24)-1)))
+ panic("solo1: buffer above 16M boundary");
+ outb(0, s->vcbase+0xd); /* clear */
+ outb(1, s->vcbase+0xf); /* mask */
+ //outb(0, s->vcbase+8); /* enable (enable is active low!) */
+ outb(0x54, s->vcbase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
+ outl(va, s->vcbase);
+ outw(s->dma_adc.dmasize-1, s->vcbase+4);
+ c = - s->dma_adc.fragsamples;
+ write_ctrl(s, 0xa4, c);
+ write_ctrl(s, 0xa5, c >> 8);
+ outb(0, s->vcbase+0xf);
+ s->dma_adc.ready = 1;
+ return 0;
+}
+
+extern inline int prog_dmabuf_dac(struct solo1_state *s)
+{
+ unsigned long va;
+ int c;
+
+ stop_dac(s);
+ if ((c = prog_dmabuf(s, &s->dma_dac, GFP_KERNEL)))
+ return c;
+ memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
+ va = virt_to_bus(s->dma_dac.rawbuf);
+ if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1))
+ panic("solo1: buffer crosses 1M boundary");
+ outl(va, s->iobase);
+ /* warning: s->dma_dac.dmasize & 0xffff must not be zero! i.e. this limits us to a 32k buffer */
+ outw(s->dma_dac.dmasize, s->iobase+4);
+ c = - s->dma_dac.fragsamples;
+ write_mixer(s, 0x74, c);
+ write_mixer(s, 0x76, c >> 8);
+ outb(0xa, s->iobase+6);
+ s->dma_dac.ready = 1;
+ return 0;
+}
+
+extern inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
+{
+ if (bptr + len > bsize) {
+ unsigned x = bsize - bptr;
+ memset(((char *)buf) + bptr, c, x);
+ bptr = 0;
+ len -= x;
+ }
+ memset(((char *)buf) + bptr, c, len);
+}
+
+/* call with spinlock held! */
+
+static void solo1_update_ptr(struct solo1_state *s)
+{
+ int diff;
+ unsigned hwptr;
+
+ /* update ADC pointer */
+ if (s->ena & FMODE_READ) {
+ hwptr = (s->dma_adc.dmasize - 1 - inw(s->vcbase+4)) % 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;
+ s->dma_adc.count += diff;
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n",
+ s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count);
+#endif
+ if (s->dma_adc.mapped) {
+ if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+ wake_up(&s->dma_adc.wait);
+ } else {
+ if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+ s->ena &= ~FMODE_READ;
+ write_ctrl(s, 0xb8, 0xe);
+ s->dma_adc.error++;
+ }
+ if (s->dma_adc.count > 0)
+ wake_up(&s->dma_adc.wait);
+ }
+ }
+ /* update DAC pointer */
+ if (s->ena & FMODE_WRITE) {
+ hwptr = (s->dma_dac.dmasize - inw(s->iobase+4)) % 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;
+#if 0
+ printk(KERN_DEBUG "solo1: wr: hwptr %u swptr %u dmasize %u count %u\n",
+ s->dma_dac.hwptr, s->dma_dac.swptr, s->dma_dac.dmasize, s->dma_dac.count);
+#endif
+ if (s->dma_dac.mapped) {
+ s->dma_dac.count += diff;
+ if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+ wake_up(&s->dma_dac.wait);
+ } else {
+ s->dma_dac.count -= diff;
+ if (s->dma_dac.count <= 0) {
+ s->ena &= ~FMODE_WRITE;
+ write_mixer(s, 0x78, 0x12);
+ s->dma_dac.error++;
+ } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+ clear_advance(s->dma_dac.rawbuf, s->dma_dac.dmasize, s->dma_dac.swptr,
+ s->dma_dac.fragsize, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80);
+ s->dma_dac.endcleared = 1;
+ }
+ if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
+ wake_up(&s->dma_dac.wait);
+ }
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void prog_codec(struct solo1_state *s)
+{
+ unsigned long flags;
+ int fdiv, filter;
+ unsigned char c;
+
+ reset_ctrl(s);
+ write_seq(s, 0xd3);
+ /* program sampling rates */
+ filter = s->rate * 9 / 20; /* Set filter roll-off to 90% of rate/2 */
+ fdiv = 256 - 7160000 / (filter * 82);
+ spin_lock_irqsave(&s->lock, flags);
+ write_ctrl(s, 0xa1, s->clkdiv);
+ write_ctrl(s, 0xa2, fdiv);
+ write_mixer(s, 0x70, s->clkdiv);
+ write_mixer(s, 0x72, fdiv);
+ /* program ADC parameters */
+ write_ctrl(s, 0xb8, 0xe);
+ write_ctrl(s, 0xb9, /*0x1*/0);
+ write_ctrl(s, 0xa8, (s->channels > 1) ? 0x11 : 0x12);
+ c = 0xd0;
+ if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ c |= 0x04;
+ if (s->fmt & (AFMT_S16_LE | AFMT_S8))
+ c |= 0x20;
+ if (s->channels > 1)
+ c ^= 0x48;
+ write_ctrl(s, 0xb7, (c & 0x70) | 1);
+ write_ctrl(s, 0xb7, c);
+ write_ctrl(s, 0xb1, 0x50);
+ write_ctrl(s, 0xb2, 0x50);
+ /* program DAC parameters */
+ c = 0x40;
+ if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ c |= 1;
+ if (s->fmt & (AFMT_S16_LE | AFMT_S8))
+ c |= 4;
+ if (s->channels > 1)
+ c |= 2;
+ write_mixer(s, 0x7a, c);
+ write_mixer(s, 0x78, 0x10);
+ s->ena = 0;
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+/* --------------------------------------------------------------------- */
+
+static const char invalid_magic[] = KERN_CRIT "solo1: invalid magic value\n";
+
+#define VALIDATE_STATE(s) \
+({ \
+ if (!(s) || (s)->magic != SOLO1_MAGIC) { \
+ printk(invalid_magic); \
+ return -ENXIO; \
+ } \
+})
+
+/* --------------------------------------------------------------------- */
+
+static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long arg)
+{
+ static const unsigned int mixer_src[8] = {
+ SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME,
+ SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0
+ };
+ static const unsigned char mixtable[SOUND_MIXER_NRDEVICES] = {
+ [SOUND_MIXER_PCM] = 0x7c, /* voice */
+ [SOUND_MIXER_SYNTH] = 0x36, /* FM */
+ [SOUND_MIXER_CD] = 0x38, /* CD */
+ [SOUND_MIXER_LINE] = 0x3e, /* Line */
+ [SOUND_MIXER_LINE1] = 0x3a, /* AUX */
+ [SOUND_MIXER_MIC] = 0x1a, /* Mic */
+ [SOUND_MIXER_LINE2] = 0x6d /* Mono in */
+ };
+ unsigned char l, r, rl, rr;
+ int i, val;
+
+ VALIDATE_STATE(s);
+
+ if (cmd == SOUND_MIXER_PRIVATE1) {
+ /* enable/disable/query mixer preamp */
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != -1) {
+ val = val ? 0xff : 0xf7;
+ write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
+ }
+ val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
+ return put_user(val, (int *)arg);
+ }
+ if (cmd == SOUND_MIXER_PRIVATE1) {
+ /* enable/disable/query mixer preamp */
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != -1) {
+ val = val ? 0xff : 0xf7;
+ write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
+ }
+ val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
+ return put_user(val, (int *)arg);
+ }
+ if (cmd == SOUND_MIXER_PRIVATE2) {
+ /* enable/disable/query spatializer */
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != -1) {
+ val &= 0x3f;
+ write_mixer(s, 0x52, val);
+ write_mixer(s, 0x50, val ? 0x08 : 0);
+ }
+ return put_user(read_mixer(s, 0x52), (int *)arg);
+ }
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ strncpy(info.id, "Solo1", sizeof(info.id));
+ strncpy(info.name, "ESS Solo1", sizeof(info.name));
+ info.modify_counter = s->mix.modcnt;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+ strncpy(info.id, "Solo1", sizeof(info.id));
+ strncpy(info.name, "ESS Solo1", sizeof(info.name));
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
+ if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ return -EINVAL;
+ 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_src[read_mixer(s, 0x1c) & 7], (int *)arg);
+
+ case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
+ SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+ SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV |
+ SOUND_MASK_SPEAKER, (int *)arg);
+
+ case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, (int *)arg);
+
+ case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
+ SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+ SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, (int *)arg);
+
+ case SOUND_MIXER_CAPS:
+ return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
+
+ case SOUND_MIXER_VOLUME:
+ rl = read_mixer(s, 0x60);
+ rr = read_mixer(s, 0x62);
+ l = (rl * 3 + 11) / 2;
+ if (rl & 0x40)
+ l = 0;
+ r = (rr * 3 + 11) / 2;
+ if (rr & 0x40)
+ r = 0;
+ return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+
+ case SOUND_MIXER_SPEAKER:
+ rl = read_mixer(s, 0x3c);
+ l = (rl & 7) * 14 + 2;
+ return put_user(l * 0x101, (int *)arg);
+
+ case SOUND_MIXER_RECLEV:
+ rl = read_ctrl(s, 0xb4);
+ r = ((rl & 0xf) * 13 + 5) / 2;
+ l = (((rl >> 4) & 0xf) * 13 + 5) / 2;
+ return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+
+ default:
+ i = _IOC_NR(cmd);
+ if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i])
+ return -EINVAL;
+ rl = read_mixer(s, mixtable[i]);
+ r = ((rl & 0xf) * 13 + 5) / 2;
+ l = (((rl >> 4) & 0xf) * 13 + 5) / 2;
+ return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+ }
+ }
+ if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
+ return -EINVAL;
+ s->mix.modcnt++;
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+
+ {
+ static const unsigned char regs[] = {
+ 0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c
+ };
+ int i;
+
+ for (i = 0; i < sizeof(regs); i++)
+ printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",
+ regs[i], read_mixer(s, regs[i]));
+ printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",
+ 0xb4, read_ctrl(s, 0xb4));
+ }
+
+ get_user_ret(val, (int *)arg, -EFAULT);
+ i = hweight32(val);
+ if (i == 0)
+ return 0;
+ else if (i > 1)
+ val &= ~mixer_src[read_mixer(s, 0x1c) & 7];
+ for (i = 0; i < 8; i++) {
+ if (mixer_src[i] & val)
+ break;
+ }
+ if (i > 7)
+ return 0;
+ write_mixer(s, 0x1c, i);
+ return 0;
+
+ case SOUND_MIXER_VOLUME:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ l = val & 0xff;
+ if (l > 100)
+ l = 100;
+ r = (val >> 8) & 0xff;
+ if (r > 100)
+ r = 100;
+ if (l < 6) {
+ rl = 0x40;
+ l = 0;
+ } else {
+ rl = (l * 2 - 11) / 3;
+ l = (rl * 3 + 11) / 2;
+ }
+ if (r < 6) {
+ rr = 0x40;
+ r = 0;
+ } else {
+ rr = (r * 2 - 11) / 3;
+ r = (rr * 3 + 11) / 2;
+ }
+ write_mixer(s, 0x60, rl);
+ write_mixer(s, 0x62, rr);
+ return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+
+ case SOUND_MIXER_SPEAKER:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ l = val & 0xff;
+ if (l > 100)
+ l = 100;
+ else if (l < 2)
+ l = 2;
+ rl = (l - 2) / 14;
+ l = rl * 14 + 2;
+ write_mixer(s, 0x3c, rl);
+ return put_user(l * 0x101, (int *)arg);
+
+ case SOUND_MIXER_RECLEV:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ l = (val << 1) & 0x1fe;
+ if (l > 200)
+ l = 200;
+ else if (l < 5)
+ l = 5;
+ r = (val >> 7) & 0x1fe;
+ if (r > 200)
+ r = 200;
+ else if (r < 5)
+ r = 5;
+ rl = (l - 5) / 13;
+ rr = (r - 5) / 13;
+ r = (rl * 13 + 5) / 2;
+ l = (rr * 13 + 5) / 2;
+ write_ctrl(s, 0xb4, (rl << 4) | rr);
+ return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+
+ default:
+ i = _IOC_NR(cmd);
+ if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i])
+ return -EINVAL;
+ get_user_ret(val, (int *)arg, -EFAULT);
+ l = (val << 1) & 0x1fe;
+ if (l > 200)
+ l = 200;
+ else if (l < 5)
+ l = 5;
+ r = (val >> 7) & 0x1fe;
+ if (r > 200)
+ r = 200;
+ else if (r < 5)
+ r = 5;
+ rl = (l - 5) / 13;
+ rr = (r - 5) / 13;
+ r = (rl * 13 + 5) / 2;
+ l = (rr * 13 + 5) / 2;
+ write_mixer(s, mixtable[i], (rl << 4) | rr);
+ return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static loff_t solo1_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int solo1_open_mixdev(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct solo1_state *s = devs;
+
+ while (s && s->dev_mixer != minor)
+ s = s->next;
+ if (!s)
+ return -ENODEV;
+ VALIDATE_STATE(s);
+ file->private_data = s;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int solo1_release_mixdev(struct inode *inode, struct file *file)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+
+ VALIDATE_STATE(s);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg);
+}
+
+static /*const*/ struct file_operations solo1_mixer_fops = {
+ &solo1_llseek,
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ &solo1_ioctl_mixdev,
+ NULL, /* mmap */
+ &solo1_open_mixdev,
+ NULL, /* flush */
+ &solo1_release_mixdev,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+#if 0
+ NULL, /* revalidate */
+ NULL, /* lock */
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+
+static int drain_dac(struct solo1_state *s, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count, tmo;
+
+ if (s->dma_dac.mapped)
+ return 0;
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&s->dma_dac.wait, &wait);
+ for (;;) {
+ spin_lock_irqsave(&s->lock, flags);
+ count = s->dma_dac.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (count <= 0)
+ break;
+ if (signal_pending(current))
+ break;
+ if (nonblock) {
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ tmo = (count * HZ) / s->rate;
+ if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ tmo >>= 1;
+ if (s->channels > 1)
+ tmo >>= 1;
+ if (!schedule_timeout(tmo ? : 1) && tmo)
+ printk(KERN_DEBUG "solo1: dma timed out??\n");
+ }
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned swptr;
+ int cnt;
+
+ VALIDATE_STATE(s);
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (s->dma_adc.mapped)
+ return -ENXIO;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ swptr = s->dma_adc.swptr;
+ cnt = s->dma_adc.dmasize-swptr;
+ if (s->dma_adc.count < cnt)
+ cnt = s->dma_adc.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x cnt: %u\n",
+ read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc), cnt);
+#endif
+ if (cnt <= 0) {
+ start_adc(s);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
+ KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
+ KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"
+ KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
+ read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
+ read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
+ inl(s->vcbase), inw(s->vcbase+4), inb(s->vcbase+8), inb(s->vcbase+15), inb(s->sbbase+0xc), cnt);
+#endif
+ if (inb(s->vcbase+15) & 1) {
+ printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
+ return -EIO;
+ }
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ interruptible_sleep_on(&s->dma_adc.wait);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
+ KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
+ KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"
+ KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
+ read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
+ read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
+ inl(s->vcbase), inw(s->vcbase+4), inb(s->vcbase+8), inb(s->vcbase+15), inb(s->sbbase+0xc), cnt);
+#endif
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
+ return ret ? ret : -EFAULT;
+ swptr = (swptr + cnt) % s->dma_adc.dmasize;
+ 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);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n",
+ read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc));
+#endif
+ }
+ return ret;
+}
+
+static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned swptr;
+ int cnt;
+
+ VALIDATE_STATE(s);
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (s->dma_dac.mapped)
+ return -ENXIO;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+ return ret;
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+#if 0
+ printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x 71: 0x%02x 72: 0x%02x 74: 0x%02x 76: 0x%02x 78: 0x%02x 7A: 0x%02x\n"
+ KERN_DEBUG "solo1_write: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x SBstat: 0x%02x\n",
+ read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76),
+ read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
+ printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x reg 7A: 0x%02x DMAcnt: 0x%04x DMAstat: 0x%02x SBstat: 0x%02x\n",
+ read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
+#endif
+ ret = 0;
+ 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;
+ }
+ 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;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ start_dac(s);
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ interruptible_sleep_on(&s->dma_dac.wait);
+ 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;
+ spin_lock_irqsave(&s->lock, flags);
+ s->dma_dac.swptr = swptr;
+ s->dma_dac.count += cnt;
+ s->dma_dac.endcleared = 0;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ start_dac(s);
+ }
+ return ret;
+}
+
+static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ VALIDATE_STATE(s);
+ if (file->f_mode & FMODE_WRITE)
+ poll_wait(file, &s->dma_dac.wait, wait);
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &s->dma_adc.wait, wait);
+ spin_lock_irqsave(&s->lock, flags);
+ solo1_update_ptr(s);
+ if (file->f_mode & FMODE_READ) {
+ if (s->dma_adc.mapped) {
+ if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+ mask |= POLLIN | POLLRDNORM;
+ } else {
+ if (s->dma_adc.count > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (s->dma_dac.mapped) {
+ if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+ mask |= POLLOUT | POLLWRNORM;
+ } else {
+ if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ return mask;
+}
+
+
+static int solo1_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ struct dmabuf *db;
+ int ret;
+ unsigned long size;
+
+ VALIDATE_STATE(s);
+ if (vma->vm_flags & VM_WRITE) {
+ if ((ret = prog_dmabuf_dac(s)) != 0)
+ return ret;
+ db = &s->dma_dac;
+ } else if (vma->vm_flags & VM_READ) {
+ if ((ret = prog_dmabuf_adc(s)) != 0)
+ return ret;
+ db = &s->dma_adc;
+ } else
+ return -EINVAL;
+ if (vma->vm_offset != 0)
+ return -EINVAL;
+ size = vma->vm_end - vma->vm_start;
+ if (size > (PAGE_SIZE << db->buforder))
+ return -EINVAL;
+ if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+ return -EAGAIN;
+ db->mapped = 1;
+ return 0;
+}
+
+static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ unsigned long flags;
+ audio_buf_info abinfo;
+ count_info cinfo;
+ int val, mapped, ret;
+ int div1, div2;
+ unsigned rate1, rate2;
+
+ VALIDATE_STATE(s);
+ mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+ ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
+ return 0;
+
+ case SNDCTL_DSP_SETDUPLEX:
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (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 (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ synchronize_irq();
+ s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+ }
+ prog_codec(s);
+ return 0;
+
+ case SNDCTL_DSP_SPEED:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val >= 0) {
+ stop_adc(s);
+ stop_dac(s);
+ s->dma_adc.ready = s->dma_dac.ready = 0;
+ /* program sampling rates */
+ if (val > 48000)
+ val = 48000;
+ if (val < 6300)
+ val = 6300;
+ div1 = (768000 + val / 2) / val;
+ rate1 = (768000 + div1 / 2) / div1;
+ div1 = -div1;
+ div2 = (793800 + val / 2) / val;
+ rate2 = (793800 + div2 / 2) / div2;
+ div2 = (-div2) & 0x7f;
+ if (abs(val - rate2) < abs(val - rate1)) {
+ rate1 = rate2;
+ div1 = div2;
+ }
+ s->rate = rate1;
+ s->clkdiv = div1;
+ prog_codec(s);
+ }
+ return put_user(s->rate, (int *)arg);
+
+ case SNDCTL_DSP_STEREO:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ stop_adc(s);
+ stop_dac(s);
+ s->dma_adc.ready = s->dma_dac.ready = 0;
+ /* program channels */
+ s->channels = val ? 2 : 1;
+ prog_codec(s);
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 0) {
+ stop_adc(s);
+ stop_dac(s);
+ s->dma_adc.ready = s->dma_dac.ready = 0;
+ /* program channels */
+ s->channels = val ? 2 : 1;
+ prog_codec(s);
+ }
+ return put_user(s->channels, (int *)arg);
+
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != AFMT_QUERY) {
+ stop_adc(s);
+ stop_dac(s);
+ s->dma_adc.ready = s->dma_dac.ready = 0;
+ /* program format */
+ if (val != AFMT_S16_LE && val != AFMT_U16_LE &&
+ val != AFMT_S8 && val != AFMT_U8)
+ val = AFMT_U8;
+ s->fmt = val;
+ prog_codec(s);
+ }
+ return put_user(s->fmt, (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ return 0;
+
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & s->ena & FMODE_READ)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & s->ena & FMODE_WRITE)
+ val |= PCM_ENABLE_OUTPUT;
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
+ start_adc(s);
+ if (inb(s->vcbase+15) & 1)
+ printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
+ } else
+ stop_adc(s);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+ return ret;
+ start_dac(s);
+ } else
+ stop_dac(s);
+ }
+ return 0;
+
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0)
+ return val;
+ spin_lock_irqsave(&s->lock, flags);
+ solo1_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;
+ 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->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0)
+ return val;
+ spin_lock_irqsave(&s->lock, flags);
+ solo1_update_ptr(s);
+ abinfo.fragsize = s->dma_adc.fragsize;
+ abinfo.bytes = s->dma_adc.count;
+ abinfo.fragstotal = s->dma_adc.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ solo1_update_ptr(s);
+ val = s->dma_dac.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ solo1_update_ptr(s);
+ cinfo.bytes = s->dma_adc.total_bytes;
+ cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ cinfo.ptr = s->dma_adc.hwptr;
+ 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));
+
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ solo1_update_ptr(s);
+ cinfo.bytes = s->dma_dac.total_bytes;
+ cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ cinfo.ptr = s->dma_dac.hwptr;
+ if (s->dma_dac.mapped)
+ s->dma_dac.count &= s->dma_dac.fragsize-1;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (file->f_mode & FMODE_WRITE) {
+ if ((val = prog_dmabuf_dac(s)))
+ return val;
+ return put_user(s->dma_dac.fragsize, (int *)arg);
+ }
+ if ((val = prog_dmabuf_adc(s)))
+ return val;
+ return put_user(s->dma_adc.fragsize, (int *)arg);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ s->dma_adc.ossfragshift = val & 0xffff;
+ s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+ if (s->dma_adc.ossfragshift < 4)
+ s->dma_adc.ossfragshift = 4;
+ if (s->dma_adc.ossfragshift > 15)
+ s->dma_adc.ossfragshift = 15;
+ if (s->dma_adc.ossmaxfrags < 4)
+ s->dma_adc.ossmaxfrags = 4;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ s->dma_dac.ossfragshift = val & 0xffff;
+ s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+ if (s->dma_dac.ossfragshift < 4)
+ s->dma_dac.ossfragshift = 4;
+ if (s->dma_dac.ossfragshift > 15)
+ s->dma_dac.ossfragshift = 15;
+ if (s->dma_dac.ossmaxfrags < 4)
+ s->dma_dac.ossmaxfrags = 4;
+ }
+ return 0;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+ (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+ return -EINVAL;
+ get_user_ret(val, (int *)arg, -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)
+ s->dma_dac.subdivision = val;
+ return 0;
+
+ case SOUND_PCM_READ_RATE:
+ return put_user(s->rate, (int *)arg);
+
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(s->channels, (int *)arg);
+
+ case SOUND_PCM_READ_BITS:
+ return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, (int *)arg);
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+
+ }
+ return mixer_ioctl(s, cmd, arg);
+}
+
+static int solo1_release(struct inode *inode, struct file *file)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+
+ VALIDATE_STATE(s);
+ if (file->f_mode & FMODE_WRITE)
+ drain_dac(s, file->f_flags & O_NONBLOCK);
+ down(&s->open_sem);
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ outb(0, s->iobase+6); /* disable DMA */
+ dealloc_dmabuf(&s->dma_dac);
+ }
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ outb(1, s->vcbase+0xf); /* mask DMA channel */
+ //outb(0, s->vcbase+0xd); /* DMA master clear */
+ dealloc_dmabuf(&s->dma_adc);
+ }
+ s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
+ up(&s->open_sem);
+ wake_up(&s->open_wait);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int solo1_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct solo1_state *s = devs;
+
+ while (s && ((s->dev_audio ^ minor) & ~0xf))
+ s = s->next;
+ if (!s)
+ return -ENODEV;
+ VALIDATE_STATE(s);
+ file->private_data = s;
+ /* wait for device to become free */
+ down(&s->open_sem);
+ while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem);
+ return -EBUSY;
+ }
+ up(&s->open_sem);
+ interruptible_sleep_on(&s->open_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ down(&s->open_sem);
+ }
+ s->fmt = AFMT_U8;
+ s->channels = 1;
+ s->rate = 8000;
+ s->clkdiv = 96 | 0x80;
+ s->ena = 0;
+ s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+ s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+ s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+ up(&s->open_sem);
+ MOD_INC_USE_COUNT;
+ if (prog_dmabuf_dac(s) || prog_dmabuf_adc(s)) {
+ solo1_release(inode, file);
+ return -ENOMEM;
+ }
+ prog_codec(s);
+ return 0;
+}
+
+static /*const*/ struct file_operations solo1_audio_fops = {
+ &solo1_llseek,
+ &solo1_read,
+ &solo1_write,
+ NULL, /* readdir */
+ &solo1_poll,
+ &solo1_ioctl,
+ &solo1_mmap,
+ &solo1_open,
+ NULL, /* flush */
+ &solo1_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+#if 0
+ NULL, /* revalidate */
+ NULL, /* lock */
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+
+/* hold spinlock for the following! */
+static void solo1_handle_midi(struct solo1_state *s)
+{
+ unsigned char ch;
+ int wake;
+
+ if (!(s->mpubase))
+ return;
+ wake = 0;
+ while (inb(s->mpubase+1) & 0x80) {
+ ch = inb(s->mpubase);
+ if (s->midi.icnt < MIDIINBUF) {
+ s->midi.ibuf[s->midi.iwr] = ch;
+ s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
+ s->midi.icnt++;
+ }
+ wake = 1;
+ }
+ if (wake)
+ wake_up(&s->midi.iwait);
+ wake = 0;
+ while ((inb(s->mpubase+1) & 0x40) && s->midi.ocnt > 0) {
+ outb(s->midi.obuf[s->midi.ord], s->mpubase);
+ s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
+ s->midi.ocnt--;
+ if (s->midi.ocnt < MIDIOUTBUF-16)
+ wake = 1;
+ }
+ if (wake)
+ wake_up(&s->midi.owait);
+}
+
+static void solo1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct solo1_state *s = (struct solo1_state *)dev_id;
+ unsigned int intsrc;
+
+ static unsigned lim = 0;
+
+ /* fastpath out, to ease interrupt sharing */
+ intsrc = inb(s->iobase+7); /* get interrupt source(s) */
+ if (!intsrc)
+ return;
+ (void)inb(s->sbbase+0xe); /* clear interrupt */
+#ifdef DEBUGREC
+ if (intsrc & 0x10 && lim < 20) {
+ lim++;
+ printk(KERN_DEBUG "solo1: audio1int reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n",
+ read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc));
+ }
+ //printk(KERN_DEBUG "solo1: interrupt 0x%02x\n", intsrc);
+#endif
+ spin_lock(&s->lock);
+ /* clear audio interrupts first */
+ if (intsrc & 0x20)
+ write_mixer(s, 0x7a, read_mixer(s, 0x7a) & 0x7f);
+ solo1_update_ptr(s);
+ solo1_handle_midi(s);
+ spin_unlock(&s->lock);
+}
+
+static void solo1_midi_timer(unsigned long data)
+{
+ struct solo1_state *s = (struct solo1_state *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ solo1_handle_midi(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+ s->midi.timer.expires = jiffies+1;
+ add_timer(&s->midi.timer);
+}
+
+/* --------------------------------------------------------------------- */
+
+static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned ptr;
+ int cnt;
+
+ VALIDATE_STATE(s);
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ ptr = s->midi.ird;
+ cnt = MIDIINBUF - ptr;
+ if (s->midi.icnt < cnt)
+ cnt = s->midi.icnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ interruptible_sleep_on(&s->midi.iwait);
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
+ return ret ? ret : -EFAULT;
+ ptr = (ptr + cnt) % MIDIINBUF;
+ spin_lock_irqsave(&s->lock, flags);
+ s->midi.ird = ptr;
+ s->midi.icnt -= cnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ }
+ return ret;
+}
+
+static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned ptr;
+ int cnt;
+
+ VALIDATE_STATE(s);
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ ptr = s->midi.owr;
+ cnt = MIDIOUTBUF - ptr;
+ if (s->midi.ocnt + cnt > MIDIOUTBUF)
+ cnt = MIDIOUTBUF - s->midi.ocnt;
+ if (cnt <= 0)
+ solo1_handle_midi(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ interruptible_sleep_on(&s->midi.owait);
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
+ return ret ? ret : -EFAULT;
+ ptr = (ptr + cnt) % MIDIOUTBUF;
+ spin_lock_irqsave(&s->lock, flags);
+ s->midi.owr = ptr;
+ s->midi.ocnt += cnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ spin_lock_irqsave(&s->lock, flags);
+ solo1_handle_midi(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
+ return ret;
+}
+
+static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ VALIDATE_STATE(s);
+ if (file->f_flags & FMODE_WRITE)
+ poll_wait(file, &s->midi.owait, wait);
+ if (file->f_flags & FMODE_READ)
+ poll_wait(file, &s->midi.iwait, wait);
+ spin_lock_irqsave(&s->lock, flags);
+ if (file->f_flags & FMODE_READ) {
+ if (s->midi.icnt > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ if (file->f_flags & FMODE_WRITE) {
+ if (s->midi.ocnt < MIDIOUTBUF)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ return mask;
+}
+
+static int solo1_midi_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct solo1_state *s = devs;
+ unsigned long flags;
+
+ while (s && s->dev_midi != minor)
+ s = s->next;
+ if (!s)
+ return -ENODEV;
+ VALIDATE_STATE(s);
+ file->private_data = s;
+ /* wait for device to become free */
+ down(&s->open_sem);
+ while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem);
+ return -EBUSY;
+ }
+ up(&s->open_sem);
+ interruptible_sleep_on(&s->open_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ down(&s->open_sem);
+ }
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+ s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+ s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+ outb(0xff, s->mpubase+1); /* reset command */
+ outb(0x3f, s->mpubase+1); /* uart command */
+ if (!(inb(s->mpubase+1) & 0x80))
+ inb(s->mpubase);
+ s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+ outb(0xb0, s->iobase + 7); /* enable A1, A2, MPU irq's */
+ init_timer(&s->midi.timer);
+ s->midi.timer.expires = jiffies+1;
+ s->midi.timer.data = (unsigned long)s;
+ s->midi.timer.function = solo1_midi_timer;
+ add_timer(&s->midi.timer);
+ }
+ if (file->f_mode & FMODE_READ) {
+ s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+ }
+ 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 solo1_midi_release(struct inode *inode, struct file *file)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ unsigned count, tmo;
+
+ VALIDATE_STATE(s);
+
+ if (file->f_mode & FMODE_WRITE) {
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&s->midi.owait, &wait);
+ for (;;) {
+ spin_lock_irqsave(&s->lock, flags);
+ count = s->midi.ocnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (count <= 0)
+ break;
+ if (signal_pending(current))
+ break;
+ if (file->f_flags & O_NONBLOCK) {
+ remove_wait_queue(&s->midi.owait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ tmo = (count * HZ) / 3100;
+ if (!schedule_timeout(tmo ? : 1) && tmo)
+ printk(KERN_DEBUG "solo1: midi timed out??\n");
+ }
+ remove_wait_queue(&s->midi.owait, &wait);
+ current->state = TASK_RUNNING;
+ }
+ down(&s->open_sem);
+ s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+ outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */
+ del_timer(&s->midi.timer);
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ up(&s->open_sem);
+ wake_up(&s->open_wait);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static /*const*/ struct file_operations solo1_midi_fops = {
+ &solo1_llseek,
+ &solo1_midi_read,
+ &solo1_midi_write,
+ NULL, /* readdir */
+ &solo1_midi_poll,
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ &solo1_midi_open,
+ NULL, /* flush */
+ &solo1_midi_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+#if 0
+ NULL, /* revalidate */
+ NULL, /* lock */
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+
+static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ static const unsigned char op_offset[18] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
+ };
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ struct dm_fm_voice v;
+ struct dm_fm_note n;
+ struct dm_fm_params p;
+ unsigned int io;
+ unsigned int regb;
+
+ switch (cmd) {
+ case FM_IOCTL_RESET:
+ for (regb = 0xb0; regb < 0xb9; regb++) {
+ outb(regb, s->sbbase);
+ outb(0, s->sbbase+1);
+ outb(regb, s->sbbase+2);
+ outb(0, s->sbbase+3);
+ }
+ return 0;
+
+ case FM_IOCTL_PLAY_NOTE:
+ if (copy_from_user(&n, (void *)arg, sizeof(n)))
+ return -EFAULT;
+ if (n.voice >= 18)
+ return -EINVAL;
+ if (n.voice >= 9) {
+ regb = n.voice - 9;
+ io = s->sbbase+2;
+ } else {
+ regb = n.voice;
+ io = s->sbbase;
+ }
+ outb(0xa0 + regb, io);
+ outb(n.fnum & 0xff, io+1);
+ outb(0xb0 + regb, io);
+ outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
+ return 0;
+
+ case FM_IOCTL_SET_VOICE:
+ if (copy_from_user(&v, (void *)arg, sizeof(v)))
+ return -EFAULT;
+ if (v.voice >= 18)
+ return -EINVAL;
+ regb = op_offset[v.voice];
+ io = s->sbbase + ((v.op & 1) << 1);
+ outb(0x20 + regb, io);
+ outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) |
+ ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
+ outb(0x40 + regb, io);
+ outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
+ outb(0x60 + regb, io);
+ outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
+ outb(0x80 + regb, io);
+ outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
+ outb(0xe0 + regb, io);
+ outb(v.waveform & 0x7, io+1);
+ if (n.voice >= 9) {
+ regb = n.voice - 9;
+ io = s->sbbase+2;
+ } else {
+ regb = n.voice;
+ io = s->sbbase;
+ }
+ outb(0xc0 + regb, io);
+ outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
+ (v.connection & 1), io+1);
+ return 0;
+
+ case FM_IOCTL_SET_PARAMS:
+ if (copy_from_user(&p, (void *)arg, sizeof(p)))
+ return -EFAULT;
+ outb(0x08, s->sbbase);
+ outb((p.kbd_split & 1) << 6, s->sbbase+1);
+ outb(0xbd, s->sbbase);
+ outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
+ ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->sbbase+1);
+ return 0;
+
+ case FM_IOCTL_SET_OPL:
+ outb(4, s->sbbase+2);
+ outb(arg, s->sbbase+3);
+ return 0;
+
+ case FM_IOCTL_SET_MODE:
+ outb(5, s->sbbase+2);
+ outb(arg & 1, s->sbbase+3);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int solo1_dmfm_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct solo1_state *s = devs;
+
+ while (s && s->dev_dmfm != minor)
+ s = s->next;
+ if (!s)
+ return -ENODEV;
+ VALIDATE_STATE(s);
+ file->private_data = s;
+ /* wait for device to become free */
+ down(&s->open_sem);
+ while (s->open_mode & FMODE_DMFM) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem);
+ return -EBUSY;
+ }
+ up(&s->open_sem);
+ interruptible_sleep_on(&s->open_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ down(&s->open_sem);
+ }
+ /* init the stuff */
+ outb(1, s->sbbase);
+ outb(0x20, s->sbbase+1); /* enable waveforms */
+ outb(4, s->sbbase+2);
+ outb(0, s->sbbase+3); /* no 4op enabled */
+ outb(5, s->sbbase+2);
+ outb(1, s->sbbase+3); /* enable OPL3 */
+ s->open_mode |= FMODE_DMFM;
+ up(&s->open_sem);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int solo1_dmfm_release(struct inode *inode, struct file *file)
+{
+ struct solo1_state *s = (struct solo1_state *)file->private_data;
+ unsigned int regb;
+
+ VALIDATE_STATE(s);
+ down(&s->open_sem);
+ s->open_mode &= ~FMODE_DMFM;
+ for (regb = 0xb0; regb < 0xb9; regb++) {
+ outb(regb, s->sbbase);
+ outb(0, s->sbbase+1);
+ outb(regb, s->sbbase+2);
+ outb(0, s->sbbase+3);
+ }
+ up(&s->open_sem);
+ wake_up(&s->open_wait);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static /*const*/ struct file_operations solo1_dmfm_fops = {
+ &solo1_llseek,
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ &solo1_dmfm_ioctl,
+ NULL, /* mmap */
+ &solo1_dmfm_open,
+ NULL, /* flush */
+ &solo1_dmfm_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+#if 0
+ NULL, /* revalidate */
+ NULL, /* lock */
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+
+/* maximum number of devices */
+#define NR_DEVICE 5
+
+/* --------------------------------------------------------------------- */
+
+static struct initvol {
+ int mixch;
+ int vol;
+} initvol[] __initdata = {
+ { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
+ { SOUND_MIXER_WRITE_PCM, 0x4040 },
+ { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
+ { SOUND_MIXER_WRITE_CD, 0x4040 },
+ { SOUND_MIXER_WRITE_LINE, 0x4040 },
+ { SOUND_MIXER_WRITE_LINE1, 0x4040 },
+ { SOUND_MIXER_WRITE_LINE2, 0x4040 },
+ { SOUND_MIXER_WRITE_RECLEV, 0x4040 },
+ { SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
+ { SOUND_MIXER_WRITE_MIC, 0x4040 }
+};
+
+static int __init init_solo1(void)
+{
+ struct solo1_state *s;
+ struct pci_dev *pcidev = NULL;
+ mm_segment_t fs;
+ int i, val, index = 0;
+ u16 ddmabase;
+
+ if (!pci_present()) /* No PCI bus in this machine! */
+ return -ENODEV;
+ printk(KERN_INFO "solo1: version v0.5 time " __TIME__ " " __DATE__ "\n");
+ while (index < NR_DEVICE &&
+ (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
+ if (pcidev->resource[0].start == 0 ||
+ (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
+ pcidev->resource[1].start == 0 ||
+ (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
+ pcidev->resource[2].start == 0 ||
+ (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
+ pcidev->resource[3].start == 0 ||
+ (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ continue;
+ if (pcidev->irq == 0)
+ continue;
+ if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
+ printk(KERN_WARNING "solo1: out of memory\n");
+ continue;
+ }
+ memset(s, 0, sizeof(struct solo1_state));
+ init_waitqueue_head(&s->dma_adc.wait);
+ init_waitqueue_head(&s->dma_dac.wait);
+ init_waitqueue_head(&s->open_wait);
+ init_waitqueue_head(&s->midi.iwait);
+ init_waitqueue_head(&s->midi.owait);
+ init_MUTEX(&s->open_sem);
+ s->magic = SOLO1_MAGIC;
+ s->iobase = pcidev->resource[0].start;
+ s->sbbase = pcidev->resource[1].start;
+ s->vcbase = pcidev->resource[2].start;
+ s->mpubase = pcidev->resource[3].start;
+ s->gpbase = pcidev->resource[4].start;
+ s->irq = pcidev->irq;
+ if (check_region(s->iobase, IOBASE_EXTENT) ||
+ check_region(s->sbbase, SBBASE_EXTENT) ||
+ check_region(s->vcbase, VCBASE_EXTENT) ||
+ check_region(s->mpubase, MPUBASE_EXTENT)) {
+ printk(KERN_ERR "solo1: io ports in use\n");
+ goto err_region;
+ }
+ request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
+ request_region(s->sbbase, SBBASE_EXTENT, "ESS Solo1");
+ request_region(s->vcbase, VCBASE_EXTENT, "ESS Solo1");
+ request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
+ if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
+ printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
+ goto err_irq;
+ }
+ /* initialize DDMA base address */
+ /* use PCI config reg, and not vcbase, we need the bus view */
+ pci_read_config_word(pcidev, 0x18, &ddmabase);
+ pci_write_config_word(pcidev, 0x60, (ddmabase & (~0xf)) | 1);
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ /* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */
+ pci_write_config_dword(pcidev, 0x50, 0);
+ /* disable legacy audio address decode */
+ pci_write_config_word(pcidev, 0x40, 0x907f);
+
+ printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1);
+
+ /* register devices */
+ if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0)
+ goto err_dev1;
+ if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0)
+ goto err_dev2;
+ if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0)
+ goto err_dev3;
+ if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
+ goto err_dev4;
+ /* initialize the chips */
+ outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
+
+ /* initialize mixer regs */
+ write_mixer(s, 0x7f, 0); /* disable music digital recording */
+ write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */
+ write_mixer(s, 0x64, 0x45); /* volume control */
+ write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */
+ write_mixer(s, 0x50, 0); /* disable spatializer */
+ write_mixer(s, 0x52, 0);
+ write_mixer(s, 0x14, 0); /* DAC1 minimum volume */
+ write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ outb(0, s->vcbase+0xd); /* DMA master clear */
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ outb(1, s->vcbase+0xf); /* mask channel */
+#ifdef DEBUGREC
+ printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
+ inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+ //outb(0, s->vcbase+0x8); /* enable controller (enable is low active!!) */
+
+ pci_set_master(pcidev); /* enable bus mastering */
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ val = SOUND_MASK_LINE;
+ mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+ for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+ val = initvol[i].vol;
+ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+ }
+ set_fs(fs);
+ /* queue it for later freeing */
+ s->next = devs;
+ devs = s;
+ index++;
+ continue;
+
+ err_dev4:
+ unregister_sound_dsp(s->dev_midi);
+ err_dev3:
+ unregister_sound_mixer(s->dev_mixer);
+ err_dev2:
+ unregister_sound_dsp(s->dev_audio);
+ err_dev1:
+ printk(KERN_ERR "solo1: cannot register misc device\n");
+ free_irq(s->irq, s);
+ err_irq:
+ release_region(s->iobase, IOBASE_EXTENT);
+ release_region(s->sbbase, SBBASE_EXTENT);
+ release_region(s->vcbase, VCBASE_EXTENT);
+ release_region(s->mpubase, MPUBASE_EXTENT);
+ err_region:
+ kfree_s(s, sizeof(struct solo1_state));
+ }
+ if (!devs)
+ return -ENODEV;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
+MODULE_DESCRIPTION("ESS Solo1 Driver");
+
+static void __exit cleanup_solo1(void)
+{
+ struct solo1_state *s;
+
+ while ((s = devs)) {
+ devs = devs->next;
+ /* stop DMA controller */
+ outb(0, s->iobase+6);
+ outb(0, s->vcbase+0xd); /* DMA master clear */
+ outb(3, s->sbbase+6); /* reset sequencer and FIFO */
+ synchronize_irq();
+ free_irq(s->irq, s);
+ release_region(s->iobase, IOBASE_EXTENT);
+ release_region(s->sbbase, SBBASE_EXTENT);
+ release_region(s->vcbase, VCBASE_EXTENT);
+ release_region(s->mpubase, MPUBASE_EXTENT);
+ unregister_sound_dsp(s->dev_audio);
+ unregister_sound_mixer(s->dev_mixer);
+ unregister_sound_midi(s->dev_midi);
+ unregister_sound_special(s->dev_dmfm);
+ kfree_s(s, sizeof(struct solo1_state));
+ }
+ printk(KERN_INFO "solo1: unloading\n");
+}
+
+/* --------------------------------------------------------------------- */
+
+module_init(init_solo1);
+module_exit(cleanup_solo1);
+
dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
dep_tristate 'USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
dep_tristate 'USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+ dep_tristate 'USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
dep_tristate 'USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB
if [ "$CONFIG_USB_SCSI" != "n" ]; then
dep_tristate ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
fi
dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
+ dep_tristate 'USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
if [ "$CONFIG_PROC_FS" != "n" ]; then
bool 'Preliminary /proc/bus/usb support' CONFIG_USB_PROC
fi
MIX_OBJS += printer.o
endif
+ifeq ($(CONFIG_USB_CPIA),y)
+ L_OBJS += cpia.o
+endif
+
+ifeq ($(CONFIG_USB_CPIA),m)
+ M_OBJS += cpia.o
+ MIX_OBJS += cpia.o
+endif
+
ifeq ($(CONFIG_USB_KBD),y)
L_OBJS += keyboard.o keymap.o
endif
endif
endif
+ifeq ($(CONFIG_USB_SCSI),m)
+ M_OBJS += usb-scsi.o
+ MIX_OBJS += usb_scsi.o
+ ifeq ($(CONFIG_USB_SCSI_DEBUG),y)
+ MIX_OBJS += usb_scsi_debug.o
+ endif
+endif
+
ifeq ($(CONFIG_USB_EZUSB),y)
L_OBJS += ezusb.o
endif
MIX_OBJS += ezusb.o
endif
+ifeq ($(CONFIG_USB_USS720),y)
+ L_OBJS += uss720.o
+endif
+
+ifeq ($(CONFIG_USB_USS720),m)
+ M_OBJS += uss720.o
+ MIX_OBJS += uss720.o
+endif
+
include $(TOPDIR)/Rules.make
keymap.o: keymap.c
$(LD) $(LD_RFLAG) -r -o $@ keymap-mac.o keyboard.o
endif
+ifeq ($(CONFIG_USB_SCSI_DEBUG),y)
+usb-scsi.o: usb_scsi.o usb_scsi_debug.o
+ $(LD) $(LD_RFLAG) -r -o $@ usb_scsi.o usb_scsi_debug.o
+else
+usb-scsi.o: usb_scsi.o
+ $(LD) $(LD_RFLAG) -r -o $@ usb_scsi.o
+endif
+
usb-uhci.o: uhci.o uhci-debug.o
$(LD) $(LD_RFLAG) -r -o $@ uhci.o uhci-debug.o
static void usb_audio_disconnect(struct usb_device *dev);
static LIST_HEAD(usb_audio_list);
-struct usb_audio
-{
+struct usb_audio {
struct usb_device *dev;
struct list_head list;
};
-static struct usb_driver usb_audio_driver =
-{
+static struct usb_driver usb_audio_driver = {
"audio",
usb_audio_probe,
usb_audio_disconnect,
- {NULL, NULL}
+ { NULL, NULL }
};
static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
{
- struct usb_audio *aud = (struct usb_audio*) dev_id;
+ struct usb_audio *aud = (struct usb_audio *)dev_id;
+
+ printk("irq on %p\n", aud);
+
return 1;
}
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_audio *aud;
-
int i;
int na=0;
interface = &dev->config[0].altsetting[0].interface[0];
- for(i=0;i<dev->config[0].bNumInterfaces;i++)
- {
- int x;
-
+ for (i=0; i<dev->config[0].bNumInterfaces; i++) {
endpoint = &interface->endpoint[i];
if(interface->bInterfaceClass != 1)
printk(KERN_INFO "USB audio device detected.\n");
- switch(interface->bInterfaceSubClass)
- {
+ switch(interface->bInterfaceSubClass) {
case 0x01:
printk(KERN_INFO "audio: Control device.\n");
break;
na++;
}
- if(na==0)
+ if (!na)
return -1;
aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL);
- if(aud)
- {
+ if (aud) {
memset(aud, 0, sizeof(*aud));
aud->dev = dev;
dev->private = aud;
static void usb_audio_disconnect(struct usb_device *dev)
{
struct usb_audio *aud = (struct usb_audio*) dev->private;
- if(aud)
- {
+
+ if (aud) {
dev->private = NULL;
list_del(&aud->list);
kfree(aud);
}
#endif
+
#include <linux/module.h>
#include <asm/spinlock.h>
+#include <asm/uaccess.h>
#include "usb.h"
#include "hub.h"
/* Wakes up khubd */
-static DECLARE_WAIT_QUEUE_HEAD(usb_hub_wait);
static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t hub_list_lock = SPIN_LOCK_UNLOCKED;
-/* List of hubs needing servicing */
-static struct list_head hub_event_list;
+static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
+static LIST_HEAD(hub_list); /* List containing all of the hubs (for cleanup) */
-/* List containing all of the hubs (for cleanup) */
-static struct list_head all_hubs_list;
+static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
+static int khubd_pid = 0; /* PID of khubd */
+static int khubd_running = 0;
-/* PID of khubd */
-static int khubd_pid = 0;
+static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+ devrequest dr;
+
+ dr.requesttype = USB_DIR_IN | USB_RT_HUB;
+ dr.request = USB_REQ_GET_DESCRIPTOR;
+ dr.value = (USB_DT_HUB << 8);
+ dr.index = 0;
+ dr.length = size;
+
+ return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr,
+ data, size);
+}
+
+static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+ devrequest dr;
+
+ dr.requesttype = USB_RT_PORT;
+ dr.request = USB_REQ_CLEAR_FEATURE;
+ dr.value = feature;
+ dr.index = port;
+ dr.length = 0;
+
+ return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr,
+ NULL, 0);
+}
+
+static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+ devrequest dr;
+
+ dr.requesttype = USB_RT_PORT;
+ dr.request = USB_REQ_SET_FEATURE;
+ dr.value = feature;
+ dr.index = port;
+ dr.length = 0;
+
+ return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr,
+ NULL, 0);
+}
+
+static int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+ devrequest dr;
+
+ dr.requesttype = USB_DIR_IN | USB_RT_HUB;
+ dr.request = USB_REQ_GET_STATUS;
+ dr.value = 0;
+ dr.index = 0;
+ dr.length = 4;
+
+ return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr,
+ data, 4);
+}
+
+static int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+ devrequest dr;
+
+ dr.requesttype = USB_DIR_IN | USB_RT_PORT;
+ dr.request = USB_REQ_GET_STATUS;
+ dr.value = 0;
+ dr.index = port;
+ dr.length = 4;
+
+ return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr,
+ data, 4);
+}
/*
* A irq handler returns non-zero to indicate to
struct usb_hub *hub = dev_id;
unsigned long flags;
- if (waitqueue_active(&usb_hub_wait)) {
+ if (waitqueue_active(&khubd_wait)) {
/* Add the hub to the event queue */
spin_lock_irqsave(&hub_event_lock, flags);
if (hub->event_list.next == &hub->event_list) {
list_add(&hub->event_list, &hub_event_list);
/* Wake up khubd */
- wake_up(&usb_hub_wait);
+ wake_up(&khubd_wait);
}
spin_unlock_irqrestore(&hub_event_lock, flags);
}
return;
hub->nports = dev->maxchild = hubdescriptor[2];
- printk("hub: %d-port%s detected\n", hub->nports,
+ printk(KERN_INFO "hub: %d-port%s detected\n", hub->nports,
(hub->nports == 1) ? "" : "s");
charac = (hubdescriptor[4] << 8) + hubdescriptor[3];
switch (charac & HUB_CHAR_LPSM) {
case 0x00:
- printk("hub: ganged power switching\n");
+ printk(KERN_INFO "hub: ganged power switching\n");
break;
case 0x01:
- printk("hub: individual port power switching\n");
+ printk(KERN_INFO "hub: individual port power switching\n");
break;
case 0x02:
case 0x03:
- printk("hub: unknown reserved power switching mode\n");
+ printk(KERN_INFO "hub: unknown reserved power switching mode\n");
break;
}
if (charac & HUB_CHAR_COMPOUND)
- printk("hub: part of a compound device\n");
+ printk(KERN_INFO "hub: part of a compound device\n");
else
- printk("hub: standalone hub\n");
+ printk(KERN_INFO "hub: standalone hub\n");
switch (charac & HUB_CHAR_OCPM) {
case 0x00:
- printk("hub: global over current protection\n");
+ printk(KERN_INFO "hub: global over current protection\n");
break;
case 0x08:
- printk("hub: individual port over current protection\n");
+ printk(KERN_INFO "hub: individual port over current protection\n");
break;
case 0x10:
case 0x18:
- printk("hub: no over current protection\n");
+ printk(KERN_INFO "hub: no over current protection\n");
break;
}
- printk("hub: power on to power good time: %dms\n",
+ printk(KERN_INFO "hub: power on to power good time: %dms\n",
hubdescriptor[5] * 2);
- printk("hub: hub controller current requirement: %dmA\n",
+ printk(KERN_INFO "hub: hub controller current requirement: %dmA\n",
hubdescriptor[6]);
for (i = 0; i < dev->maxchild; i++)
- printk("hub: port %d is%s removable\n", i + 1,
+ printk(KERN_INFO "hub: port %d is%s removable\n", i + 1,
hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8))
? " not" : "");
if (usb_get_hub_status(dev, buf))
return;
- printk("hub: local power source is %s\n",
+ printk(KERN_INFO "hub: local power source is %s\n",
(buf[0] & 1) ? "lost (inactive)" : "good");
- printk("hub: %sover current condition exists\n",
+ printk(KERN_INFO "hub: %sover current condition exists\n",
(buf[0] & 2) ? "" : "no ");
-#if 0
- for (i = 0; i < hub->nports; i++) {
- int portstat, portchange;
- unsigned char portstatus[4];
-
- if (usb_get_port_status(dev, i + 1, portstatus))
- return;
- portstat = (portstatus[1] << 8) + portstatus[0];
- portchange = (portstatus[3] << 8) + portstatus[2];
-
- printk("hub: port %d status\n", i + 1);
- printk("hub: %sdevice present\n", (portstat & 1) ? "" : "no ");
- printk("hub: %s\n", (portstat & 2) ? "enabled" : "disabled");
- printk("hub: %ssuspended\n", (portstat & 4) ? "" : "not ");
- printk("hub: %sover current\n", (portstat & 8) ? "" : "not ");
- printk("hub: has %spower\n", (portstat & 0x100) ? "" : "no ");
- printk("hub: %s speed\n", (portstat & 0x200) ? "low" : "full");
- }
-#endif
-
/* Enable power to the ports */
- printk("enabling power on all ports\n");
+ printk(KERN_INFO "hub: enabling power on all ports\n");
for (i = 0; i < hub->nports; i++)
usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
}
endpoint = &interface->endpoint[0];
/* Output endpoint? Curiousier and curiousier.. */
- if (!(endpoint->bEndpointAddress & 0x80))
+ if (!(endpoint->bEndpointAddress & USB_DIR_IN))
return -1;
/* If it's not an interrupt endpoint, we'd better punt! */
return -1;
/* We found a hub */
- printk("USB hub found\n");
+ printk(KERN_INFO "USB hub found\n");
if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) {
- printk("couldn't kmalloc hub struct\n");
+ printk(KERN_ERR "couldn't kmalloc hub struct\n");
return -1;
}
/* Record the new hub's existence */
spin_lock_irqsave(&hub_list_lock, flags);
INIT_LIST_HEAD(&hub->hub_list);
- list_add(&hub->hub_list, &all_hubs_list);
+ list_add(&hub->hub_list, &hub_list);
spin_unlock_irqrestore(&hub_list_lock, flags);
usb_hub_configure(hub);
- hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
+ hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev,
+ endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
/* Wake up khubd */
- wake_up(&usb_hub_wait);
+ wake_up(&khubd_wait);
return 0;
}
unsigned char buf[4];
unsigned short portstatus, portchange;
+ /* Disconnect anything that may have been there */
usb_disconnect(&hub->children[port]);
+ /* Reset the port */
usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
wait_ms(50); /* FIXME: This is from the *BSD stack, thanks! :) */
+ /* Check status */
if (usb_get_port_status(hub, port + 1, buf)) {
- printk("get_port_status failed\n");
+ printk(KERN_ERR "get_port_status failed\n");
return;
}
portstatus = le16_to_cpup((unsigned short *)buf + 0);
portchange = le16_to_cpup((unsigned short *)buf + 1);
+ /* If it's not in CONNECT and ENABLE state, we're done */
if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
- (!(portstatus & USB_PORT_STAT_ENABLE))) {
+ (!(portstatus & USB_PORT_STAT_ENABLE)))
/* We're done now, we already disconnected the device */
- /* printk("not connected/enabled\n"); */
return;
- }
+ /* Allocate a new device struct for it */
usb = hub->bus->op->allocate(hub);
if (!usb) {
- printk("couldn't allocate usb_device\n");
+ printk(KERN_ERR "couldn't allocate usb_device\n");
return;
}
- usb_connect(usb);
-
usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
hub->children[port] = usb;
- usb_new_device(usb);
+ /* Find a new device ID for it */
+ usb_connect(usb);
+
+ /* Run it through the hoops (find a driver, etc) */
+ if (usb_new_device(usb)) {
+ /* Woops, disable the port */
+ printk(KERN_DEBUG "hub: disabling malfunctioning port %d\n",
+ port + 1);
+ usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
+ usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_POWER);
+ }
}
static void usb_hub_events(void)
for (i = 0; i < hub->nports; i++) {
if (usb_get_port_status(dev, i + 1, buf)) {
- printk("get_port_status failed\n");
+ printk(KERN_ERR "get_port_status failed\n");
continue;
}
portchange = le16_to_cpup((unsigned short *)buf + 1);
if (portchange & USB_PORT_STAT_C_CONNECTION) {
- printk("hub: port %d connection change\n", i + 1);
+ printk(KERN_INFO "hub: port %d connection change\n",
+ i + 1);
usb_clear_port_feature(dev, i + 1,
USB_PORT_FEAT_C_CONNECTION);
}
if (portchange & USB_PORT_STAT_C_ENABLE) {
- printk("hub: port %d enable change\n", i + 1);
+ printk(KERN_INFO "hub: port %d enable change\n",
+ i + 1);
usb_clear_port_feature(dev, i + 1,
USB_PORT_FEAT_C_ENABLE);
}
if (portchange & USB_PORT_STAT_C_SUSPEND)
- printk("hub: port %d suspend change\n", i + 1);
+ printk(KERN_INFO "hub: port %d suspend change\n",
+ i + 1);
if (portchange & USB_PORT_STAT_C_OVERCURRENT)
- printk("hub: port %d over-current change\n", i + 1);
+ printk(KERN_INFO "hub: port %d over-current change\n",
+ i + 1);
if (portchange & USB_PORT_STAT_C_RESET) {
- printk("hub: port %d reset change\n", i + 1);
+ printk(KERN_INFO "hub: port %d reset change\n",
+ i + 1);
usb_clear_port_feature(dev, i + 1,
USB_PORT_FEAT_C_RESET);
}
-#if 0
- if (!portchange)
- continue;
-
- if (usb_get_port_status(dev, i + 1, buf))
- return;
-
- portstatus = (buf[1] << 8) + buf[0];
- portchange = (buf[3] << 8) + buf[2];
-
- printk("hub: port %d status\n", i + 1);
- printk("hub: %sdevice present\n", (portstatus & 1) ? "" : "no ");
- printk("hub: %s\n", (portstatus & 2) ? "enabled" : "disabled");
- printk("hub: %ssuspended\n", (portstatus & 4) ? "" : "not ");
- printk("hub: %sover current\n", (portstatus & 8) ? "" : "not ");
- printk("hub: has %spower\n", (portstatus & 0x100) ? "" : "no ");
- printk("hub: %s speed\n", (portstatus & 0x200) ? "low" : "full");
-#endif
}
tmp = next;
-#if 0
- wait_ms(1000);
-#endif
}
spin_unlock_irqrestore(&hub_event_lock, flags);
static int usb_hub_thread(void *__hub)
{
+/*
MOD_INC_USE_COUNT;
+*/
- printk(KERN_INFO "USB hub driver registered\n");
+ khubd_running = 1;
lock_kernel();
/* Send me a signal to get me die (for debugging) */
do {
- interruptible_sleep_on(&usb_hub_wait);
usb_hub_events();
+ interruptible_sleep_on(&khubd_wait);
} while (!signal_pending(current));
+/*
MOD_DEC_USE_COUNT;
+*/
printk("usb_hub_thread exiting\n");
+ khubd_running = 0;
return 0;
}
{
int pid;
- INIT_LIST_HEAD(&hub_event_list);
- INIT_LIST_HEAD(&all_hubs_list);
-
usb_register(&hub_driver);
- pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ printk(KERN_INFO "USB hub driver registered\n");
+
+ pid = kernel_thread(usb_hub_thread, NULL,
+ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (pid >= 0) {
khubd_pid = pid;
+
return 0;
}
/* Fall through if kernel_thread failed */
usb_deregister(&hub_driver);
- return 0;
+ return 1;
}
void usb_hub_cleanup(void)
{
+ struct list_head *next, *tmp, *head = &hub_list;
+ struct usb_hub *hub;
+ unsigned long flags, flags2;
+ int ret;
+
+ /* Kill the thread */
+ ret = kill_proc(khubd_pid, SIGTERM, 1);
+ if (!ret) {
+ int count = 10;
+
+ while (khubd_running && --count) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+
+ if (!count)
+ printk(KERN_ERR "hub: giving up on killing khubd\n");
+ }
+
/*
* Hub resources are freed for us by usb_deregister. It
* usb_driver_purge on every device which in turn calls that
} /* usb_hub_cleanup() */
#ifdef MODULE
-int init_module(void){
+int init_module(void)
+{
return usb_hub_init();
}
-void cleanup_module(void){
+void cleanup_module(void)
+{
usb_hub_cleanup();
}
#endif
+
#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
-struct uhci_td * uhci_link_to_td(unsigned int link)
+struct uhci_td *uhci_link_to_td(unsigned int link)
{
- if (link & 1)
+ if (link & UHCI_PTR_TERM)
return NULL;
- return bus_to_virt(link & ~15);
+ return bus_to_virt(link & ~UHCI_PTR_BITS);
}
void show_queue(struct uhci_qh *qh)
struct uhci_td *td;
int i = 0;
-#if 0
- printk(" link = %p, element = %p\n", qh->link, qh->element);
-#endif
- if(!(qh->element & ~0xF)) {
- printk(" td 0 = NULL\n");
+ if (qh->element & UHCI_PTR_QH)
+ printk(" Element points to QH?\n");
+
+ if (qh->element & UHCI_PTR_DEPTH)
+ printk(" Depth traverse\n");
+
+ if (qh->element & UHCI_PTR_TERM)
+ printk(" Terminate\n");
+
+ if (!(qh->element & ~UHCI_PTR_BITS)) {
+ printk(" td 0 = NULL\n");
return;
}
for(td = uhci_link_to_td(qh->element); td;
td = uhci_link_to_td(td->link)) {
- printk(" td %d = %p\n", i++, td);
- printk(" ");
+ printk(" td %d = %p\n", i++, td);
+ printk(" ");
show_td(td);
}
}
int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
{
int j;
- struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
- for (j = 0; j < UHCI_MAXQH; j++)
- if (qh == root_hub->qh + j)
+
+ for (j = 0; j < UHCI_NUM_SKELQH; j++)
+ if (qh == uhci->skelqh + j)
return 1;
return 0;
}
-static const char *qh_names[] = {"isochronous", "interrupt2", "interrupt4",
- "interrupt8", "interrupt16", "interrupt32",
- "interrupt64", "interrupt128", "interrupt256",
- "control", "bulk0", "bulk1", "bulk2", "bulk3",
- "unused", "unused"};
+static const char *qh_names[] = {"interrupt2", "interrupt4", "interrupt8",
+ "interrupt16", "interrupt32", "interrupt64",
+ "interrupt128", "interrupt256", "control",
+ "bulk"};
void show_queues(struct uhci *uhci)
{
int i;
struct uhci_qh *qh;
- struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
- for (i = 0; i < UHCI_MAXQH; ++i) {
- printk(" %s:\n", qh_names[i]);
-#if 0
- printk(" qh #%d, %p\n", i, virt_to_bus(root_hub->qh + i));
- show_queue(uhci->root_hub->qh + i);
-#endif
+ for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+ printk(" %s: [%p] (%08X) (%08X)\n", qh_names[i],
+ &uhci->skelqh[i],
+ uhci->skelqh[i].link, uhci->skelqh[i].element);
- qh = uhci_link_to_qh(root_hub->qh[i].link);
+ qh = uhci_link_to_qh(uhci->skelqh[i].link);
for (; qh; qh = uhci_link_to_qh(qh->link)) {
if (is_skeleton_qh(uhci, qh))
break;
+ printk(" [%p] (%08X) (%08x)\n",
+ qh, qh->link, qh->element);
+
show_queue(qh);
}
}
}
+
* Universal Host Controller Interface driver for USB.
*
* (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
static DECLARE_WAIT_QUEUE_HEAD(uhci_configure);
+static kmem_cache_t *uhci_td_cachep;
+static kmem_cache_t *uhci_qh_cachep;
+
+static LIST_HEAD(uhci_list);
+
+#define UHCI_DEBUG
+
/*
* Map status to standard result codes
*/
static int uhci_map_status(int status, int dir_out)
{
- if (!status)
- return USB_ST_NOERROR;
- if (status & 0x02) /* Bitstuff error*/
- return USB_ST_BITSTUFF;
- if (status & 0x04) { /* CRC/Timeout */
- if (dir_out)
- return USB_ST_NORESPONSE;
- else
- return USB_ST_CRC;
- }
- if (status & 0x08) /* NAK */
- return USB_ST_TIMEOUT;
- if (status & 0x10) /* Babble */
- return USB_ST_STALL;
- if (status & 0x20) /* Buffer error */
- return USB_ST_BUFFERUNDERRUN;
- if (status & 0x40) /* Stalled */
- return USB_ST_STALL;
- if (status & 0x80) /* Active */
- return USB_ST_NOERROR;
- return USB_ST_INTERNALERROR;
+ if (!status)
+ return USB_ST_NOERROR;
+ if (status & 0x02) /* Bitstuff error*/
+ return USB_ST_BITSTUFF;
+ if (status & 0x04) { /* CRC/Timeout */
+ if (dir_out)
+ return USB_ST_NORESPONSE;
+ else
+ return USB_ST_CRC;
+ }
+ if (status & 0x08) /* NAK */
+ return USB_ST_TIMEOUT;
+ if (status & 0x10) /* Babble */
+ return USB_ST_STALL;
+ if (status & 0x20) /* Buffer error */
+ return USB_ST_BUFFERUNDERRUN;
+ if (status & 0x40) /* Stalled */
+ return USB_ST_STALL;
+ if (status & 0x80) /* Active */
+ return USB_ST_NOERROR;
+
+ return USB_ST_INTERNALERROR;
}
/*
* Return the result of a TD..
static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval)
{
unsigned int status;
- struct uhci_td *tmp= td->first;
+ struct uhci_td *tmp;
+
+ if (!td->qh)
+ tmp = td;
+ else
+ tmp = uhci_ptr_to_virt(td->qh->element);
- if(rval)
+ if (rval)
*rval = 0;
-
+
/* locate the first failing td, if any */
do {
if (status) {
/* must reset the toggle on first error */
if (uhci_debug) {
- printk("Set toggle from %x rval %ld\n", (unsigned int)tmp, rval ? *rval : 0);
+ printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
+ (unsigned int)tmp, rval ? *rval : 0);
}
- usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), usb_pipeout(tmp->info), (tmp->info >> 19) & 1);
+ usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info),
+ usb_pipeout(tmp->info), (tmp->info >> 19) & 1);
break;
} else {
- if(rval)
+ if (rval)
*rval += (tmp->status & 0x3ff) + 1;
}
- if ((tmp->link & 1) || (tmp->link & 2))
+ if ((tmp->link & UHCI_PTR_TERM) ||
+ (tmp->link & UHCI_PTR_QH))
break;
- tmp = bus_to_virt(tmp->link & ~0xF);
+ tmp = uhci_ptr_to_virt(tmp->link);
} while (1);
if (!status)
return USB_ST_NOERROR;
/* Some debugging code */
- if (uhci_debug /* && (!usb_pipeendpoint(tmp->info) || !(status & 0x08))*/ ) {
- int i = 10;
-
- tmp = td->first;
- printk("uhci_td_result() failed with status %x\n", status);
- //show_status(dev->uhci);
+ if (uhci_debug) {
+ int count = 10;
+
+ if (!td->qh)
+ tmp = td;
+ else
+ tmp = uhci_ptr_to_virt(td->qh->element);
+ printk(KERN_DEBUG "uhci_td_result() failed with status %x\n",
+ status);
do {
show_td(tmp);
- if ((tmp->link & 1) || (tmp->link & 2))
+ if ((tmp->link & UHCI_PTR_TERM) ||
+ (tmp->link & UHCI_PTR_QH))
break;
- tmp = bus_to_virt(tmp->link & ~0xF);
- if (!--i)
- break;
- } while (1);
+ tmp = uhci_ptr_to_virt(tmp->link);
+ } while (--count);
}
if (status & 0x40) {
- /* endpoint has stalled - mark it halted */
-
- usb_endpoint_halt(dev->usb, usb_pipeendpoint(tmp->info));
- return USB_ST_STALL;
-
+ /* endpoint has stalled - mark it halted */
+ usb_endpoint_halt(dev->usb, usb_pipeendpoint(tmp->info));
+ return USB_ST_STALL;
}
if (status == 0x80) {
- /* still active */
- if (!rval)
- return USB_ST_DATAUNDERRUN;
+ /* still active */
+ if (!rval)
+ return USB_ST_DATAUNDERRUN;
}
return uhci_map_status(status, usb_pipeout(tmp->info));
}
static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, struct uhci_td *last)
{
unsigned int link = qh->element;
- unsigned int new = 4 | virt_to_bus(first);
+ unsigned int new = virt_to_bus(first) | UHCI_PTR_DEPTH;
for (;;) {
unsigned char success;
:"m" (qh->element), "1" (link), "r" (new)
:"memory");
if (success) {
- /* Was there a successor entry? Fix it's backpointer.. */
- if ((link & 1) == 0) {
- struct uhci_td *next = bus_to_virt(link & ~15);
+ /* Was there a successor entry? Fix it's backpointer */
+ if ((link & UHCI_PTR_TERM) == 0) {
+ struct uhci_td *next = uhci_ptr_to_virt(link);
next->backptr = &last->link;
}
break;
static void uhci_insert_qh(struct uhci_qh *qh, struct uhci_qh *newqh)
{
newqh->link = qh->link;
- qh->link = virt_to_bus(newqh) | 2;
+ qh->link = virt_to_bus(newqh) | UHCI_PTR_QH;
}
static void uhci_remove_qh(struct uhci_qh *qh, struct uhci_qh *remqh)
{
- unsigned int remphys = virt_to_bus(remqh);
struct uhci_qh *lqh = qh;
- while ((lqh->link & ~0xF) != remphys) {
- if (lqh->link & 1)
+ while (uhci_ptr_to_virt(lqh->link) != remqh) {
+ if (lqh->link & UHCI_PTR_TERM)
break;
- lqh = bus_to_virt(lqh->link & ~0xF);
+ lqh = uhci_ptr_to_virt(lqh->link);
}
- if (lqh->link & 1) {
- printk("couldn't find qh in chain!\n");
+ if (lqh->link & UHCI_PTR_TERM) {
+ printk(KERN_DEBUG "couldn't find qh in chain!\n");
return;
}
* so we can always just look at that and fix up the backpointer
* of any next element..
*/
- if (!(link & 1)) {
- struct uhci_td *next = bus_to_virt(link & ~15);
+ if (!(link & UHCI_PTR_TERM)) {
+ struct uhci_td *next = uhci_ptr_to_virt(link);
next->backptr = backptr;
}
:"memory");
}
-static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev)
+static struct uhci_td *uhci_td_alloc(struct uhci_device *dev)
{
- struct uhci_qh *qh;
- int inuse;
+ struct uhci_td *td;
- qh = dev->qh;
- for (; (inuse = test_and_set_bit(0, &qh->inuse)) != 0 && qh < &dev->qh[UHCI_MAXQH]; qh++)
- ;
+ td = kmem_cache_alloc(uhci_td_cachep, SLAB_KERNEL);
+ if (!td)
+ return NULL;
- if (!inuse)
- return(qh);
+#ifdef UHCI_DEBUG
+ if ((__u32)td & UHCI_PTR_BITS)
+ printk("qh not 16 byte aligned!\n");
+#endif
- printk("ran out of qh's for dev %p\n", dev);
- return(NULL);
-}
+ td->link = UHCI_PTR_TERM;
+ td->buffer = 0;
-static void uhci_qh_deallocate(struct uhci_qh *qh)
-{
-// if (qh->element != 1)
-// printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element);
+ td->backptr = NULL;
+ td->qh = NULL;
+ td->dev_id = NULL;
+ td->dev = dev;
+ td->flags = 0;
+ INIT_LIST_HEAD(&td->irq_list);
+ atomic_set(&td->refcnt, 1);
- qh->element = 1;
- qh->link = 1;
+ return td;
+}
- clear_bit(0, &qh->inuse);
+static void uhci_td_free(struct uhci_td *td)
+{
+ if (atomic_dec_and_test(&td->refcnt))
+ kmem_cache_free(uhci_td_cachep, td);
}
-static struct uhci_td *uhci_td_allocate(struct uhci_device *dev)
+static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev)
{
- struct uhci_td *td;
- int inuse;
+ struct uhci_qh *qh;
- td = dev->td;
- for (; (inuse = test_and_set_bit(0, &td->inuse)) != 0 && td < &dev->td[UHCI_MAXTD]; td++)
- ;
+ qh = kmem_cache_alloc(uhci_qh_cachep, SLAB_KERNEL);
+ if (!qh)
+ return NULL;
- if (!inuse) {
- td->inuse = 1;
- td->dev=uhci_to_usb(dev);
- return(td);
- }
+#ifdef UHCI_DEBUG
+ if ((__u32)qh & UHCI_PTR_BITS)
+ printk("qh not 16 byte aligned!\n");
+#endif
+
+ qh->element = UHCI_PTR_TERM;
+ qh->link = UHCI_PTR_TERM;
- printk("ran out of td's for dev %p\n", dev);
- return(NULL);
+ qh->dev = dev;
+ qh->skel = NULL;
+ init_waitqueue_head(&qh->wakeup);
+ atomic_set(&qh->refcnt, 1);
+
+ return qh;
}
-/*
- * This MUST only be called when it has been removed from a QH already (or
- * the QH has been removed from the skeleton
- */
-static void uhci_td_deallocate(struct uhci_td *td)
+static void uhci_qh_free(struct uhci_qh *qh)
{
- td->link = 1;
- clear_bit(0, &td->inuse);
+ if (atomic_dec_and_test(&qh->refcnt))
+ kmem_cache_free(uhci_qh_cachep, qh);
}
/*
spin_unlock_irqrestore(&irqlist_lock, flags);
}
-
/*
* This function removes and disallcoates all structures set up for an transfer.
* It takes the qh out of the skeleton, removes the tq and the td's.
* It only removes the associated interrupt handler if removeirq ist set.
* The *td argument is any td in the list of td's.
*/
-static void uhci_remove_transfer(struct uhci_td *td, char removeirq) {
- int maxcount = 100;
- struct uhci_td *curtd = td->first;
+static void uhci_remove_transfer(struct uhci_td *td, char removeirq)
+{
+ int maxcount = 1000;
+ struct uhci_td *curtd;
unsigned int nextlink;
-/* Remove it from the skeleton */
+ if (!td->qh)
+ curtd = td;
+ else
+ curtd = uhci_ptr_to_virt(td->qh->element);
+
+ /* Remove it from the skeleton */
uhci_remove_qh(td->qh->skel, td->qh);
- uhci_qh_deallocate(td->qh);
+ uhci_qh_free(td->qh);
do {
nextlink = curtd->link;
- /*IOC? => remove handler*/
- if (removeirq && (td->status & (1 << 24))) {
+
+ /* IOC? => remove handler */
+ if (removeirq && (td->status & TD_CTRL_IOC))
uhci_remove_irq_list(td);
- }
+
uhci_remove_td(curtd);
- uhci_td_deallocate(curtd);
- if (nextlink & 1) /* Tail? */
- break;
+ uhci_td_free(curtd);
+ if (nextlink & UHCI_PTR_TERM) /* Tail? */
+ break;
- curtd = bus_to_virt(nextlink & ~0xF);
+ curtd = bus_to_virt(nextlink & ~UHCI_PTR_BITS);
if (!--maxcount) {
- printk("runaway td's!?\n");
+ printk(KERN_ERR "runaway td's!?\n");
break;
}
} while (1);
* Returns: a "handle pointer" that release_irq can use to stop this
* interrupt. (It's really a pointer to the TD).
*/
-static void* uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+static void *uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
- struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
- struct uhci_td *td = uhci_td_allocate(dev);
- struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev);
-
+ struct uhci_td *td = uhci_td_alloc(dev);
+ struct uhci_qh *qh = uhci_qh_alloc(dev);
unsigned int destination, status;
- /* Destination: pipe destination with INPUT */
- destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+ if (!td || !qh)
+ return NULL;
- /* Status: slow/fast, Interrupt, Active, Short Packet Detect Infinite Errors */
- status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23) | (1 << 29) | (0 << 27);
+ /* Destination: pipe destination with INPUT */
+ destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid(pipe);
- if(interrupt_qh->element != 1)
- printk("interrupt_qh->element = 0x%x\n",
- interrupt_qh->element);
+ /* Infinite errors is 0, so no bits */
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_IOC | TD_CTRL_ACTIVE |
+ TD_CTRL_SPD;
- td->link = 1;
- td->status = status;
+ td->link = UHCI_PTR_TERM; /* Terminate */
+ td->status = status; /* In */
td->info = destination | ((usb_maxpacket(usb_dev, pipe) - 1) << 21) |
- (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19);
+ (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe)) << 19);
td->buffer = virt_to_bus(dev->data);
- td->first = td;
- td->qh = interrupt_qh;
- td->dev = usb_dev;
+ td->qh = qh;
+ td->dev = dev;
/* if period 0, insert into fast q */
-
if (period == 0) {
- td->inuse |= 2;
- interrupt_qh->skel = &root_hub->skel_int2_qh;
+ td->flags |= UHCI_TD_REMOVE;
+ qh->skel = &dev->uhci->skel_int2_qh;
} else
- interrupt_qh->skel = &root_hub->skel_int8_qh;
+ qh->skel = &dev->uhci->skel_int8_qh;
uhci_add_irq_list(dev->uhci, td, handler, dev_id);
- uhci_insert_td_in_qh(interrupt_qh, td);
+ uhci_insert_td_in_qh(qh, td);
/* Add it into the skeleton */
- uhci_insert_qh(interrupt_qh->skel, interrupt_qh);
-
- return (void*)td;
-}
-
-/*
- * Remove running irq td from queues
- *
- * This function is not used anymore.
- */
-#if 0
-static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
-{
- struct uhci_device *dev = usb_to_uhci(usb_dev);
- struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
- struct uhci_td *td;
- struct uhci_qh *interrupt_qh;
- unsigned long flags;
- struct list_head *head = &dev->uhci->interrupt_list;
- struct list_head *tmp;
-
- spin_lock_irqsave(&irqlist_lock, flags);
-
- /* find the TD in the interrupt list */
-
- tmp = head->next;
- while (tmp != head) {
- td = list_entry(tmp, struct uhci_td, irq_list);
- if (td->dev_id == dev_id && td->completed == handler) {
-
- /* found the right one - let's remove it */
+ uhci_insert_qh(qh->skel, qh);
- /* notify removal */
-
- td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
-
- /* this is DANGEROUS - not sure whether this is right */
-
- list_del(&td->irq_list);
- uhci_remove_td(td);
- interrupt_qh = td->qh;
- uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
- uhci_td_deallocate(td);
- uhci_qh_deallocate(interrupt_qh);
- spin_unlock_irqrestore(&irqlist_lock, flags);
- return USB_ST_NOERROR;
- }
- }
- spin_unlock_irqrestore(&irqlist_lock, flags);
- return USB_ST_INTERNALERROR;
+ return (void *)td;
}
-#endif
/*
* Release an interrupt handler previously allocated using
*
* This function can NOT be called from an interrupt.
*/
-int uhci_release_irq(void* handle)
+int uhci_release_irq(void *handle)
{
struct uhci_td *td;
- struct uhci_qh *interrupt_qh;
- unsigned long flags;
+ struct uhci_qh *qh;
#ifdef UHCI_DEBUG
- printk("usb-uhci: Releasing irq handle %p\n", handle);
+ printk(KERN_DEBUG "usb-uhci: releasing irq handle %p\n", handle);
#endif
- td = (struct uhci_td*)handle;
- if (td == NULL)
+ td = (struct uhci_td *)handle;
+ if (!td)
return USB_ST_INTERNALERROR;
/* Remove it from the internal irq_list */
uhci_remove_irq_list(td);
-#if 0
- spin_lock_irqsave(&irqlist_lock, flags);
- list_del(&td->irq_list);
- spin_unlock_irqrestore(&irqlist_lock, flags);
-#endif
/* Remove the interrupt TD and QH */
uhci_remove_td(td);
- interrupt_qh = td->qh;
- uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
+ qh = td->qh;
+ uhci_remove_qh(qh->skel, qh);
if (td->completed != NULL)
td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
/* Free the TD and QH */
- uhci_td_deallocate(td);
- uhci_qh_deallocate(interrupt_qh);
+ uhci_td_free(td);
+ uhci_qh_free(qh);
return USB_ST_NOERROR;
} /* uhci_release_irq() */
-
/*
- * Isochronous thread operations
+ * Isochronous operations
*/
-
static int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc)
{
struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
int i, totlen = 0;
for (i = 0; i < isodesc->num; i++) {
- char *cdata = bus_to_virt(isodesc->td[i].buffer & ~0xF);
- int n = (isodesc->td[i].status + 1) & 0x7FF;
+ struct uhci_td *td = &isodesc->td[i];
+ char *cdata = uhci_ptr_to_virt(td->buffer);
+ int n = (td->status + 1) & 0x7FF;
if ((cdata != data) && (n))
memmove(data, cdata, n);
+#ifdef UHCI_DEBUG
/* Debugging */
- if ((isodesc->td[i].status >> 16) & 0xFF)
- printk("error: %d %X\n", i,
- (isodesc->td[i].status >> 16));
+ if ((td->status >> 16) & 0xFF)
+ printk(KERN_DEBUG "error: %d %X\n", i,
+ (td->status >> 16));
+#endif
data += n;
totlen += n;
struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
int i;
- if ((isodesc->frame < 0) || (isodesc->frame > 1023))
+ if ((isodesc->frame < 0) || (isodesc->frame > 1023)) {
+ printk(KERN_ERR "illegal frame number %d\n", isodesc->frame);
return 1;
+ }
+
+ /* FIXME: Use uhci_remove_td */
/* Remove from previous frames */
for (i = 0; i < isodesc->num; i++) {
+ struct uhci_td *td = &isodesc->td[i];
+
/* Turn off Active and IOC bits */
- isodesc->td[i].status &= ~(3 << 23);
- uhci->fl->frame[(isodesc->frame + i) % 1024] = isodesc->td[i].link;
+ td->status &= ~(3 << 23);
+ td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
+
+ uhci->fl->frame[(isodesc->frame + i) % 1024] = td->link;
}
isodesc->frame = -1;
int frame, i;
if (isodesc->frame != -1) {
- printk("isoc queue not removed\n");
+ printk(KERN_ERR "isoc queue not removed\n");
uhci_unschedule_isochronous(usb_dev, isodesc);
}
if (!pisodesc) {
/* It's not guaranteed to be 1-1024 */
frame = inw(uhci->io_addr + USBFRNUM) % 1024;
+
/* HACK: Start 2 frames from now */
frame = (frame + 2) % 1024;
} else
frame = (pisodesc->endframe + 1) % 1024;
for (i = 0; i < isodesc->num; i++) {
+ struct uhci_td *td = &isodesc->td[i];
+
/* Active */
- isodesc->td[i].status |= (1 << 23);
- isodesc->td[i].backptr = &uhci->fl->frame[(frame + i) % 1024];
- isodesc->td[i].link = uhci->fl->frame[(frame + i) % 1024];
- uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(&isodesc->td[i]);
+ td->status |= TD_CTRL_ACTIVE;
+ td->backptr = &uhci->fl->frame[(frame + i) % 1024];
+ td->link = uhci->fl->frame[(frame + i) % 1024];
+ uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(td);
}
/* IOC on the last TD */
- isodesc->td[i - 1].status |= (1 << 24);
+ isodesc->td[i - 1].status |= TD_CTRL_IOC;
isodesc->frame = frame;
isodesc->endframe = (frame + isodesc->num - 1) % 1024;
isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL);
if (!isodesc) {
- printk("Couldn't allocate isodesc!\n");
+ printk(KERN_ERR "Couldn't allocate isodesc!\n");
return NULL;
}
+
memset(isodesc, 0, sizeof(*isodesc));
/* Carefully work around the non contiguous pages */
isodesc->maxsze = maxsze;
if (!isodesc->td) {
- printk("Couldn't allocate td's\n");
+ printk(KERN_ERR "couldn't allocate td's\n");
kfree(isodesc);
return NULL;
}
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (pipe & PIPE_DEVEP_MASK)
- | usb_packetid (pipe); /* add IN or OUT */
+ | usb_packetid (pipe); /* add IN or OUT */
- /* Status: slow/fast, Active, Isochronous */
- status = (pipe & (1 << 26)) | (1 << 23) | (1 << 25);
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOS;
/*
* Build the TD for the control request
td->status = status;
td->info = destination | ((maxsze - 1) << 21);
td->buffer = virt_to_bus(data);
- td->first = td;
td->backptr = NULL;
i++;
len -= maxsze;
} while (i < isodesc->num);
-#if 0
- /* IOC on the last TD */
- td->status |= (1 << 24);
-#endif
-
uhci_add_irq_list(dev->uhci, td, completed, dev_id);
return isodesc;
* We need to remove the TD from the lists (both interrupt
* list and TD lists) by hand if something bad happens!
*/
-static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
-static int uhci_control_completed(int status, void *buffer, int len, void *dev_id)
+static int uhci_generic_completed(int status, void *buffer, int len, void *dev_id)
{
- wake_up(&control_wakeup);
+ wait_queue_head_t *wakeup = (wait_queue_head_t *)dev_id;
+
+ if (waitqueue_active(wakeup))
+ wake_up(wakeup);
+ else
+ printk("waitqueue empty!\n");
+
return 0; /* Don't re-instate */
}
static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
{
DECLARE_WAITQUEUE(wait, current);
- struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev);
- struct uhci_td *curtd;
- struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
+ struct uhci_qh *qh = uhci_qh_alloc(dev);
+
+ if (!qh)
+ return -1;
+
current->state = TASK_UNINTERRUPTIBLE;
- add_wait_queue(&control_wakeup, &wait);
+ add_wait_queue(&qh->wakeup, &wait);
- uhci_add_irq_list(dev->uhci, last, uhci_control_completed, NULL);
+ uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup);
+#if 0
/* FIXME: This is kinda kludged */
/* Walk the TD list and update the QH pointer */
{
- int maxcount = 100;
+ struct uhci_td *curtd;
+ int count = 100;
curtd = first;
do {
curtd->qh = ctrl_qh;
- if (curtd->link & 1)
+ if (curtd->link & TD_CTRL_TERM)
break;
- curtd = bus_to_virt(curtd->link & ~0xF);
- if (!--maxcount) {
- printk("runaway tds!\n");
- break;
- }
- } while (1);
+ curtd = uhci_ptr_to_virt(curtd->link);
+ } while (--count);
+ if (!count)
+ printk(KERN_DEBUG "runaway tds!\n");
}
+#endif
- uhci_insert_tds_in_qh(ctrl_qh, first, last);
+ uhci_insert_tds_in_qh(qh, first, last);
/* Add it into the skeleton */
- uhci_insert_qh(&root_hub->skel_control_qh, ctrl_qh);
-
-// control should be full here...
-// printk("control\n");
-// show_status(dev->uhci);
-// show_queues(dev->uhci);
-
- schedule_timeout(HZ*5);
+ uhci_insert_qh(&dev->uhci->skel_control_qh, qh);
-// control should be empty here...
-// show_status(dev->uhci);
-// show_queues(dev->uhci);
+ schedule_timeout(HZ * 5); /* 5 seconds */
- remove_wait_queue(&control_wakeup, &wait);
+ remove_wait_queue(&qh->wakeup, &wait);
/* Clean up in case it failed.. */
uhci_remove_irq_list(last);
-#if 0
- printk("Looking for tds [%p, %p]\n", dev->control_td, td);
-#endif
-
/* Remove it from the skeleton */
- uhci_remove_qh(&root_hub->skel_control_qh, ctrl_qh);
+ uhci_remove_qh(&dev->uhci->skel_control_qh, qh);
- uhci_qh_deallocate(ctrl_qh);
+ uhci_qh_free(qh);
return uhci_td_result(dev, last, NULL);
}
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *first, *td, *prevtd;
unsigned long destination, status;
- int ret;
+ int ret, count;
int maxsze = usb_maxpacket(usb_dev, pipe);
+ __u32 nextlink;
-
- if (len > maxsze * 29)
- printk("Warning, too much data for a control packet, crashing\n");
-
- first = td = uhci_td_allocate(dev);
+ first = td = uhci_td_alloc(dev);
+ if (!td)
+ return -ENOMEM;
/* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */
destination = (pipe & PIPE_DEVEP_MASK) | 0x2D;
- /* Status: slow/fast, Active, Short Packet Detect Three Errors */
- status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27);
+ /* 3 errors */
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD | (3 << 27);
/*
* Build the TD for the control request
td->status = status; /* Try forever */
td->info = destination | (7 << 21); /* 8 bytes of data */
td->buffer = virt_to_bus(cmd);
- td->first = td;
/*
* If direction is "send", change the frame from SETUP (0x2D)
destination ^= (0xE1 ^ 0x69); /* IN -> OUT */
prevtd = td;
- td = uhci_td_allocate(dev);
- prevtd->link = 4 | virt_to_bus(td);
+ td = uhci_td_alloc(dev);
+ if (!td)
+ return -ENOMEM;
+
+ prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
/*
* Build the DATA TD's
destination ^= 1 << 19;
td->status = status; /* Status */
- td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */
+ td->info = destination | ((pktsze - 1) << 21); /* pktsze bytes of data */
td->buffer = virt_to_bus(data);
- td->first = first;
td->backptr = &prevtd->link;
data += pktsze;
len -= pktsze;
prevtd = td;
- td = uhci_td_allocate(dev);
- prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */
-
+ td = uhci_td_alloc(dev);
+ if (!td)
+ return -ENOMEM;
+ prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH; /* Update previous TD */
}
/*
destination ^= (0xE1 ^ 0x69); /* OUT -> IN */
destination |= 1 << 19; /* End in Data1 */
- td->backptr = &prevtd->link;
- td->status = (status /* & ~(3 << 27) */) | (1 << 24); /* no limit on final packet */
+ td->status = status | TD_CTRL_IOC; /* no limit on errors on final packet */
td->info = destination | (UHCI_NULL_DATA_SIZE << 21); /* 0 bytes of data */
td->buffer = 0;
- td->first = first;
- td->link = 1; /* Terminate */
+ td->backptr = &prevtd->link;
+ td->link = UHCI_PTR_TERM; /* Terminate */
/* Start it up.. */
ret = uhci_run_control(dev, first, td);
- {
- int maxcount = 100;
- struct uhci_td *curtd = first;
- unsigned int nextlink;
+ count = 100;
+ td = first;
+ do {
+ nextlink = td->link;
+ uhci_remove_td(td);
+ uhci_td_free(td);
- do {
- nextlink = curtd->link;
- uhci_remove_td(curtd);
- uhci_td_deallocate(curtd);
- if (nextlink & 1) /* Tail? */
- break;
+ if (nextlink & UHCI_PTR_TERM) /* Tail? */
+ break;
- curtd = bus_to_virt(nextlink & ~0xF);
- if (!--maxcount) {
- printk("runaway td's!?\n");
- break;
- }
- } while (1);
- }
+ td = uhci_ptr_to_virt(nextlink);
+ } while (--count);
+
+ if (!count)
+ printk(KERN_ERR "runaway td's!?\n");
if (uhci_debug && ret) {
__u8 *p = (__u8 *)cmd;
- printk("Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ printk(KERN_DEBUG "Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
}
return ret;
}
-
/*
* Bulk thread operations: we just mark the last TD
* in a bulk thread as an interrupt TD, and wake up
* We need to remove the TD from the lists (both interrupt
* list and TD lists) by hand if something bad happens!
*/
-static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
-
-static int uhci_bulk_completed(int status, void *buffer, int len, void *dev_id)
-{
- wake_up(&bulk_wakeup);
- return 0; /* Don't re-instate */
-}
/* td points to the last td in the list, which interrupts on completion */
static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, unsigned long *rval)
{
DECLARE_WAITQUEUE(wait, current);
- struct uhci_qh *bulk_qh = uhci_qh_allocate(dev);
- struct uhci_td *curtd;
- struct uhci_device *root_hub = usb_to_uhci(dev->uhci->bus->root_hub);
+ struct uhci_qh *qh = uhci_qh_alloc(dev);
+
+ if (!qh)
+ return -ENOMEM;
current->state = TASK_UNINTERRUPTIBLE;
- add_wait_queue(&bulk_wakeup, &wait);
+ add_wait_queue(&qh->wakeup, &wait);
- uhci_add_irq_list(dev->uhci, last, uhci_bulk_completed, NULL);
+ uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup);
+#if 0
/* FIXME: This is kinda kludged */
/* Walk the TD list and update the QH pointer */
{
- int maxcount = 100;
+ struct uhci_td *curtd;
+ int count = 100;
curtd = first;
do {
curtd->qh = bulk_qh;
- if (curtd->link & 1)
+ if (curtd->link & UHCI_PTR_TERM)
break;
- curtd = bus_to_virt(curtd->link & ~0xF);
- if (!--maxcount) {
- printk("runaway tds!\n");
- break;
- }
- } while (1);
+ curtd = uhci_ptr_to_virt(curtd->link);
+ } while (--count);
+ if (!count)
+ printk(KERN_ERR "runaway tds!\n");
}
+#endif
- uhci_insert_tds_in_qh(bulk_qh, first, last);
+ uhci_insert_tds_in_qh(qh, first, last);
/* Add it into the skeleton */
- uhci_insert_qh(&root_hub->skel_bulk0_qh, bulk_qh);
-
-// now we're in the queue... but don't ask WHAT is in there ;-(
-// printk("bulk\n");
-// show_status(dev->uhci);
-// show_queues(dev->uhci);
+ uhci_insert_qh(&dev->uhci->skel_bulk_qh, qh);
- schedule_timeout(HZ*5);
-// show_status(dev->uhci);
-// show_queues(dev->uhci);
+ schedule_timeout(HZ*5); /* 5 seconds */
- //show_queue(first->qh);
- remove_wait_queue(&bulk_wakeup, &wait);
+ remove_wait_queue(&qh->wakeup, &wait);
/* Clean up in case it failed.. */
uhci_remove_irq_list(last);
-#if 0
- printk("Looking for tds [%p, %p]\n", dev->control_td, td);
-#endif
-
- /* Remove it from the skeleton */
- uhci_remove_qh(&root_hub->skel_bulk0_qh, bulk_qh);
+ uhci_remove_qh(&dev->uhci->skel_bulk_qh, qh);
- uhci_qh_deallocate(bulk_qh);
+ uhci_qh_free(qh);
return uhci_td_result(dev, last, rval);
}
*
* A bulk message is only built up from
* the data phase
- *
- * The data phase can be an arbitrary number of TD's
- * although we currently had better not have more than
- * 31 TD's here.
- *
- * 31 TD's is a minimum of 248 bytes worth of bulk
- * information.
*/
static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval)
{
usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & 0x80)))
return USB_ST_STALL;
- if (len > maxsze * 31)
- printk("Warning, too much data for a bulk packet, crashing (%d/%d)\n", len, maxsze);
-
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
- /* Status: slow/fast, Active, Short Packet Detect Three Errors */
- status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27);
+ /* 3 errors */
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD | (3 << 27);
/*
* Build the TDs for the bulk request
*/
- first = td = uhci_td_allocate(dev);
+ first = td = uhci_td_alloc(dev);
+ if (!td)
+ return -ENOMEM;
+
prevtd = first; //This is fake, but at least it's not NULL
while (len > 0) {
/* Build the TD for control status */
(usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
td->buffer = virt_to_bus(data);
td->backptr = &prevtd->link;
- td->first = first;
data += maxsze;
len -= maxsze;
if (len > 0) {
prevtd = td;
- td = uhci_td_allocate(dev);
- prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */
+ td = uhci_td_alloc(dev);
+ if (!td)
+ return -ENOMEM;
+
+ prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;/* Update previous TD */
}
/* Alternate Data0/1 (start with Data0) */
- usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+ usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
}
+
td->link = 1; /* Terminate */
- td->status |= (1 << 24); /* IOC */
+ td->status |= TD_CTRL_IOC;
/* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */
ret = uhci_run_bulk(dev, first, td, rval);
{
- int maxcount = 100;
+ int count = 100;
struct uhci_td *curtd = first;
unsigned int nextlink;
do {
nextlink = curtd->link;
uhci_remove_td(curtd);
- uhci_td_deallocate(curtd);
- if (nextlink & 1) /* Tail? */
- break;
+ uhci_td_free(curtd);
- curtd = bus_to_virt(nextlink & ~0xF);
- if (!--maxcount) {
- printk("runaway td's!?\n");
+ if (nextlink & UHCI_PTR_TERM) /* Tail? */
break;
- }
- } while (1);
+
+ curtd = uhci_ptr_to_virt(nextlink);
+ } while (--count);
+
+ if (!count)
+ printk(KERN_DEBUG "runaway td's!?\n");
}
+
return ret;
}
static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
- struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
+ struct uhci *uhci = dev->uhci;
struct uhci_td *first, *td, *prevtd;
- struct uhci_qh *bulk_qh = uhci_qh_allocate(dev);
+ struct uhci_qh *bulk_qh = uhci_qh_alloc(dev);
unsigned long destination, status;
int maxsze = usb_maxpacket(usb_dev, pipe);
-
- if (len > maxsze * 31)
- printk("Warning, too much data for a bulk packet, crashing\n");
/* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */
destination = (pipe & 0x0007ff00) | usb_packetid(pipe);
- /* Status: slow/fast, Active, Short Packet Detect Infinite Errors */
- status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (0 << 27);
-
+ /* Infinite errors is 0 */
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD;
- /*
- * Build the TDs for the bulk request
- */
- first = td = uhci_td_allocate(dev);
- prevtd=td;
+ /* Build the TDs for the bulk request */
+ first = td = uhci_td_alloc(dev);
+ prevtd = td;
while (len > 0) {
/* Build the TD for control status */
int pktsze = len;
if (pktsze > maxsze)
pktsze = maxsze;
- td->status = status; /* Status */
+ td->status = status; /* Status */
td->info = destination | ((pktsze-1) << 21) |
- (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
+ (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
td->buffer = virt_to_bus(data);
td->backptr = &prevtd->link;
- td->first = first;
td->qh = bulk_qh;
- td->dev=usb_dev;
-
+ td->dev = dev;
data += pktsze;
len -= pktsze;
if (len > 0) {
prevtd = td;
- td = uhci_td_allocate(dev);
- prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */
+ td = uhci_td_alloc(dev);
+ prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
}
/* Alternate Data0/1 */
usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
}
-
- first->backptr=NULL;
- td->link = 1; /* Terminate */
- td->status = status | (1 << 24); /* IOC */
- td->first = first;
-
+
+ first->backptr = NULL;
+ td->link = 1; /* Terminate */
+ td->status = status | TD_CTRL_IOC; /* IOC */
+
uhci_add_irq_list(dev->uhci, td, handler, dev_id);
uhci_insert_tds_in_qh(bulk_qh, first, td);
- bulk_qh->skel=&root_hub->skel_bulk0_qh;
- uhci_insert_qh(&root_hub->skel_bulk0_qh, bulk_qh);
-
- //Return last td for removal
+ bulk_qh->skel = &uhci->skel_bulk_qh;
+ uhci_insert_qh(&uhci->skel_bulk_qh, bulk_qh);
+
+ /* Return last td for removal */
return td;
}
* There is only one queue using this pipe. (the one we remove)
* Any data that is in the queue is useless for us, we throw it away.
*/
-static int uhci_terminate_bulk(struct usb_device *dev, void * first)
+static int uhci_terminate_bulk(struct usb_device *dev, void * first)
{
- //none found? there is nothing to remove!
- if (!first) return 0;
+ /* none found? there is nothing to remove! */
+ if (!first)
+ return 0;
uhci_remove_transfer(first,1);
- return 1;
+ return 1;
}
-static struct usb_device *uhci_usb_allocate(struct usb_device *parent)
+static struct usb_device *uhci_usb_alloc(struct usb_device *parent)
{
struct usb_device *usb_dev;
struct uhci_device *dev;
- int i;
/* Allocate the USB device */
usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
usb_dev->hcpriv = dev;
dev->usb = usb_dev;
+
usb_dev->parent = parent;
if (parent) {
dev->uhci = usb_to_uhci(parent)->uhci;
}
- /* Reset the QH's and TD's */
- for (i = 0; i < UHCI_MAXQH; i++) {
- dev->qh[i].link = 1;
- dev->qh[i].element = 1;
- dev->qh[i].inuse = 0;
- }
-
- for (i = 0; i < UHCI_MAXTD; i++) {
- dev->td[i].link = 1;
- dev->td[i].inuse = 0;
- }
-
return usb_dev;
}
-static int uhci_usb_deallocate(struct usb_device *usb_dev)
+static int uhci_usb_free(struct usb_device *usb_dev)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
- int i;
-
- /* There are UHCI_MAXTD preallocated tds */
- for (i = 0; i < UHCI_MAXTD; ++i) {
- struct uhci_td *td = dev->td + i;
-
- if (td->inuse & 1) {
- uhci_remove_td(td);
-
- /* And remove it from the irq list, if it's active */
- if (td->status & (1 << 23))
- td->status &= ~(1 << 23);
-#if 0
- uhci_remove_irq_list(td);
-#endif
- }
- }
-
- /* Remove the td from any queues */
- for (i = 0; i < UHCI_MAXQH; ++i) {
- struct uhci_qh *qh = dev->qh + i;
-
- if (qh->inuse & 1)
- uhci_remove_qh(qh->skel, qh);
- }
kfree(dev);
usb_destroy_configuration(usb_dev);
}
struct usb_operations uhci_device_operations = {
- uhci_usb_allocate,
- uhci_usb_deallocate,
+ uhci_usb_alloc,
+ uhci_usb_free,
uhci_control_msg,
uhci_bulk_msg,
uhci_request_irq,
}
-
/*
* This gets called if the connect status on the root
* hub (and the root hub only) changes.
struct usb_device *usb_dev;
struct uhci_device *dev;
unsigned short status;
- struct uhci_device *root_hub=usb_to_uhci(uhci->bus->root_hub);
- printk("uhci_connect_change: called for %d\n", nr);
+ struct uhci_device *root_hub = usb_to_uhci(uhci->bus->root_hub);
+
+#ifdef UHCI_DEBUG
+ printk(KERN_INFO "uhci_connect_change: called for %d\n", nr);
+#endif
/*
* Even if the status says we're connected,
* Ok, we got a new connection. Allocate a device to it,
* and find out what it wants to do..
*/
- usb_dev = uhci_usb_allocate(root_hub->usb);
+ usb_dev = uhci_usb_alloc(root_hub->usb);
if (!usb_dev)
return;
dev = usb_dev->hcpriv;
- dev->uhci = uhci;
+
usb_connect(usb_dev);
root_hub->usb->children[nr] = usb_dev;
* The rest is generic for any new USB attach, regardless of
* hub type.
*/
- usb_new_device(usb_dev);
+ if (usb_new_device(usb_dev)) {
+ unsigned short status = inw(port);
+
+ printk(KERN_INFO "uhci: disabling malfunctioning port %d\n",
+ nr + 1);
+ outw(status | USBPORTSC_PE, port);
+ }
}
/*
*/
static void uhci_check_configuration(struct uhci *uhci)
{
- struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
+ struct uhci_device *root_hub = usb_to_uhci(uhci->bus->root_hub);
unsigned int io_addr = uhci->io_addr + USBPORTSC1;
int maxchild = root_hub->usb->maxchild;
int nr = 0;
static void uhci_interrupt_notify(struct uhci *uhci)
{
- struct list_head *head = &uhci->interrupt_list;
- struct list_head *tmp;
+ struct list_head *tmp, *head = &uhci->interrupt_list;
int status;
spin_lock(&irqlist_lock);
tmp = head->next;
while (tmp != head) {
- struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
- struct list_head *next;
-
- next = tmp->next;
+ struct uhci_td *first, *td = list_entry(tmp,
+ struct uhci_td, irq_list);
- if (!((status = td->status) & (1 << 23)) || /* No longer active? */
- ((td->qh->element & ~15) &&
- !((status = uhci_link_to_td(td->qh->element)->status) & (1 <<23)) &&
- (status & 0x760000) /* is in error state (Stall, db, babble, timeout, bitstuff) */)) {
- unsigned long rval;
- int status;
+ tmp = tmp->next;
- status=uhci_td_result(usb_to_uhci(td->dev),td,&rval);
- /* remove from IRQ list */
- __list_del(tmp->prev, next);
- INIT_LIST_HEAD(tmp);
+ /* We check the TD which had the IOC bit as well as the */
+ /* first TD */
+ /* XXX: Shouldn't we check all of the TD's in the chain? */
+ if ((td->qh) && (td->qh->element & ~UHCI_PTR_BITS))
+ first = uhci_link_to_td(td->qh->element);
+ else
+ first = NULL;
- if (td->completed(status, bus_to_virt(td->buffer), rval, td->dev_id)) {
- list_add(&td->irq_list, &uhci->interrupt_list);
-
- if (!(td->status & (1 << 25))) {
- struct uhci_qh *interrupt_qh = td->qh;
+ /* If any of the error bits are set OR the active is NOT set */
+ /* then we're interested in this TD */
+ status = td->status & 0xF60000;
- usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
- td->info &= ~(1 << 19); /* clear data toggle */
- td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)) << 19; /* toggle between data0 and data1 */
- td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */
-
- /* Remove then readd? Is that necessary */
- uhci_remove_td(td);
- uhci_insert_td_in_qh(interrupt_qh, td);
- }
- } else if (td->inuse & 2) {
- struct uhci_qh *interrupt_qh = td->qh;
- /* marked for removal */
- td->inuse &= ~2;
- usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
- uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
- uhci_qh_deallocate(interrupt_qh);
- uhci_td_deallocate(td);
- }
- /* If completed wants to not reactivate, then it's */
- /* responsible for free'ing the TD's and QH's */
- /* or another function (such as run_control) */
+ if ((!(status ^ TD_CTRL_ACTIVE)) && (first) &&
+ (!(first->status & TD_CTRL_ACTIVE)))
+ status = first->status & 0xF60000;
- }
- tmp = next;
+ if (!(status ^ TD_CTRL_ACTIVE))
+ continue;
+
+
+ /* remove from IRQ list */
+ list_del(&td->irq_list);
+ INIT_LIST_HEAD(&td->irq_list);
+
+ if (td->completed(uhci_map_status(status, 0),
+ bus_to_virt(td->buffer), -1, td->dev_id)) {
+ list_add(&td->irq_list, &uhci->interrupt_list);
+
+ /* Isochronous TD's don't need this */
+ if (!(td->status & TD_CTRL_IOS)) {
+ struct usb_device *usb_dev = td->dev->usb;
+
+ usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
+ td->info &= ~(1 << 19); /* clear data toggle */
+ td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)) << 19; /* toggle between data0 and data1 */
+ td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+ /* The HC removes it, so readd it */
+ uhci_insert_td_in_qh(td->qh, td);
+ }
+ } else if (td->flags & UHCI_TD_REMOVE) {
+ struct usb_device *usb_dev = td->dev->usb;
+
+ /* marked for removal */
+ td->flags &= ~UHCI_TD_REMOVE;
+ usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
+ uhci_remove_qh(td->qh->skel, td->qh);
+ uhci_qh_free(td->qh);
+ uhci_td_free(td);
+ }
+
+ /* If completed does not wants to reactivate, then */
+ /* it's responsible for free'ing the TD's and QH's */
+ /* or another function (such as run_control) */
}
spin_unlock(&irqlist_lock);
}
static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr)
{
if (waitqueue_active(&uhci_configure)) {
- struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
+ struct uhci_device *root_hub = usb_to_uhci(uhci->bus->root_hub);
int ports = root_hub->usb->maxchild;
+
io_addr += USBPORTSC1;
do {
if (inw(io_addr) & USBPORTSC_CSC) {
status = inw(io_addr + USBSTS);
outw(status, io_addr + USBSTS);
-// if ((status & ~0x21) != 0)
-// printk("interrupt: %X\n", status);
-
/* Walk the list of pending TD's to see which ones completed.. */
uhci_interrupt_notify(uhci);
static void uhci_init_ticktd(struct uhci *uhci)
{
struct uhci_device *dev = usb_to_uhci(uhci->bus->root_hub);
- struct uhci_td *td = uhci_td_allocate(dev);
+ struct uhci_td *td = uhci_td_alloc(dev);
+
+ if (!td) {
+ printk(KERN_ERR "unable to allocate ticktd\n");
+ return;
+ }
- td->link = 1;
- td->status = (1 << 24); /* interrupt on completion */
+ /* Don't clobber the frame */
+ td->link = uhci->fl->frame[0];
+ td->status = TD_CTRL_IOC;
td->info = (15 << 21) | 0x7f69; /* (ignored) input packet, 16 bytes, device 127 */
td->buffer = 0;
- td->first = td;
td->qh = NULL;
uhci->fl->frame[0] = virt_to_bus(td);
+
+ uhci->ticktd = td;
}
static void reset_hc(struct uhci *uhci)
unsigned int io_addr = uhci->io_addr;
/* Global reset for 50ms */
- outw(USBCMD_GRESET, io_addr+USBCMD);
+ outw(USBCMD_GRESET, io_addr + USBCMD);
wait_ms(50);
- outw(0, io_addr+USBCMD);
+ outw(0, io_addr + USBCMD);
wait_ms(10);
}
outw(USBCMD_HCRESET, io_addr + USBCMD);
while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
if (!--timeout) {
- printk("USBCMD_HCRESET timed out!\n");
+ printk(KERN_ERR "USBCMD_HCRESET timed out!\n");
break;
}
}
-
+ /* Turn on all interrupts */
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+
+ /* Start at frame 0 */
outw(0, io_addr + USBFRNUM);
outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
* We could certainly have multiple queues of the same
* type, and maybe we should. We could have per-device
* queues, for example. We begin small.
+ *
+ * Queues are dynamically allocated for devices now,
+ * this code only sets up the skeleton queue
*/
static struct uhci *alloc_uhci(unsigned int io_addr)
{
if (!uhci->fl)
goto au_free_uhci;
- bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+ bus = usb_alloc_bus(&uhci_device_operations);
if (!bus)
goto au_free_fl;
- memset(bus, 0, sizeof(*bus));
-
uhci->bus = bus;
bus->hcpriv = uhci;
- bus->op = &uhci_device_operations;
/*
- * We allocate a 8kB area for the UHCI hub. The area
- * is described by the uhci_device structure, and basically
- * contains everything needed for normal operation.
- *
- * The first page is the actual device descriptor for the
- * hub.
- *
- * The second page is used for the frame list.
+ * Allocate the root_hub
*/
- usb = uhci_usb_allocate(NULL);
+ usb = uhci_usb_alloc(NULL);
if (!usb)
goto au_free_bus;
usb->bus = bus;
+
dev = usb_to_uhci(usb);
- uhci->bus->root_hub=uhci_to_usb(dev);
+ dev->uhci = uhci;
+
+ uhci->bus->root_hub = uhci_to_usb(dev);
+
/* Initialize the root hub */
/* UHCI specs says devices must have 2 ports, but goes on to say */
/* they may have more but give no way to determine how many they */
usb->maxchild = 2;
usb_init_root_hub(usb);
- /*
- * Initialize the queues. They all start out empty,
- * linked to each other in the proper order.
- */
- for (i = 1 ; i < 9; i++) {
- dev->qh[i].link = 2 | virt_to_bus(&dev->skel_control_qh);
- dev->qh[i].element = 1;
- }
-
- dev->skel_control_qh.link = 2 | virt_to_bus(&dev->skel_bulk0_qh);
- dev->skel_control_qh.element = 1;
-
- dev->skel_bulk0_qh.link = 2 | virt_to_bus(&dev->skel_bulk1_qh);
- dev->skel_bulk0_qh.element = 1;
+ /* 8 Interrupt queues */
+ for (i = 0; i < 8; i++) {
+ struct uhci_qh *qh = &uhci->skelqh[i];
- dev->skel_bulk1_qh.link = 2 | virt_to_bus(&dev->skel_bulk2_qh);
- dev->skel_bulk1_qh.element = 1;
+ qh->link = virt_to_bus(&uhci->skel_control_qh) | UHCI_PTR_QH;
+ qh->element = UHCI_PTR_TERM;
+ }
- dev->skel_bulk2_qh.link = 2 | virt_to_bus(&dev->skel_bulk3_qh);
- dev->skel_bulk2_qh.element = 1;
+ uhci->skel_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) |
+ UHCI_PTR_QH;
+ uhci->skel_control_qh.element = UHCI_PTR_TERM;
- dev->skel_bulk3_qh.link = 1;
- dev->skel_bulk3_qh.element = 1;
+ uhci->skel_bulk_qh.link = UHCI_PTR_TERM;
+ uhci->skel_bulk_qh.element = UHCI_PTR_TERM;
/*
* Fill the frame list: make all entries point to
* us a reasonable dynamic range for irq latencies.
*/
for (i = 0; i < 1024; i++) {
- struct uhci_qh * irq = &dev->skel_int2_qh;
+ struct uhci_qh *irq = &uhci->skel_int2_qh;
if (i & 1) {
irq++;
if (i & 2) {
}
}
}
- uhci->fl->frame[i] = 2 | virt_to_bus(irq);
+ uhci->fl->frame[i] = virt_to_bus(irq) | UHCI_PTR_QH;
}
return uhci;
*/
au_free_bus:
- kfree (bus);
+ usb_free_bus(bus);
au_free_fl:
- free_page ((unsigned long)uhci->fl);
+ free_page((unsigned long)uhci->fl);
au_free_uhci:
- kfree (uhci);
+ kfree(uhci);
return NULL;
}
-
/*
* De-allocate all resources..
*/
uhci->irq = -1;
}
-#if 0
- if (uhci->bus->root_hub) {
- uhci_usb_deallocate(uhci_to_usb(uhci->bus->root_hub));
- uhci->bus->root_hub = NULL;
+ if (uhci->ticktd) {
+ uhci_td_free(uhci->ticktd);
+ uhci->ticktd = NULL;
}
-#endif
if (uhci->fl) {
free_page((unsigned long)uhci->fl);
uhci->fl = NULL;
}
- kfree(uhci->bus);
+ usb_free_bus(uhci->bus);
kfree(uhci);
}
static int uhci_control_thread(void * __uhci)
{
struct uhci *uhci = (struct uhci *)__uhci;
- struct uhci_device * root_hub =usb_to_uhci(uhci->bus->root_hub);
+
+ uhci->control_running = 1;
lock_kernel();
- request_region(uhci->io_addr, 32, "usb-uhci");
/*
* This thread doesn't need any user-level access,
* so get rid of all our resources..
*/
- printk("uhci_control_thread at %p\n", &uhci_control_thread);
exit_mm(current);
exit_files(current);
- //exit_fs(current);
strcpy(current->comm, "uhci-control");
/*
* Ok, all systems are go..
*/
- start_hc(uhci);
- usb_register_bus(uhci->bus);
- for(;;) {
+ do {
siginfo_t info;
int unsigned long signr;
- interruptible_sleep_on(&uhci_configure);
#ifdef CONFIG_APM
if (apm_resume) {
apm_resume = 0;
#endif
uhci_check_configuration(uhci);
- if(signal_pending(current)) {
+ interruptible_sleep_on(&uhci_configure);
+
+ if (signal_pending(current)) {
/* sending SIGUSR1 makes us print out some info */
spin_lock_irq(¤t->sigmask_lock);
signr = dequeue_signal(¤t->blocked, &info);
spin_unlock_irq(¤t->sigmask_lock);
- if(signr == SIGUSR1) {
- printk("UHCI queue dump:\n");
+ if (signr == SIGUSR1) {
+ printk(KERN_DEBUG "UHCI queue dump:\n");
show_queues(uhci);
} else if (signr == SIGUSR2) {
uhci_debug = !uhci_debug;
- printk("UHCI debug toggle = %x\n", uhci_debug);
- } else {
+ printk(KERN_DEBUG "UHCI debug toggle = %x\n",
+ uhci_debug);
+ } else
break;
- }
}
- }
-
- {
- int i;
- if(root_hub)
- for(i = 0; i < root_hub->usb->maxchild; i++)
- usb_disconnect(root_hub->usb->children + i);
- }
-
- usb_deregister_bus(uhci->bus);
+ } while (uhci->control_continue);
- reset_hc(uhci);
- release_region(uhci->io_addr, 32);
-
- release_uhci(uhci);
+/*
MOD_DEC_USE_COUNT;
+*/
- printk("uhci_control_thread exiting\n");
+ uhci->control_running = 0;
return 0;
}
if (!uhci)
return -ENOMEM;
+ INIT_LIST_HEAD(&uhci->uhci_list);
+ list_add(&uhci->uhci_list, &uhci_list);
+
+ request_region(uhci->io_addr, 32, "usb-uhci");
+
reset_hc(uhci);
+ usb_register_bus(uhci->bus);
+ start_hc(uhci);
+
+ uhci->control_continue = 1;
+
retval = -EBUSY;
- if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) {
+ if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "uhci", uhci) == 0) {
int pid;
- MOD_INC_USE_COUNT;
+
uhci->irq = irq;
pid = kernel_thread(uhci_control_thread, uhci,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
- if (pid >= 0)
- return 0;
+ if (pid >= 0) {
+ uhci->control_pid = pid;
+
+ return(pid);
+ }
- MOD_DEC_USE_COUNT;
retval = pid;
}
+
+ reset_hc(uhci);
+ release_region(uhci->io_addr, 32);
+
release_uhci(uhci);
return retval;
}
/* IO address? */
if (!(dev->resource[i].flags & 1))
continue;
+
+#if 0
+ /* Is it already in use? */
+ if (check_region(io_addr, 32))
+ break;
+#endif
+
return found_uhci(dev->irq, io_addr);
}
return -1;
}
#endif
-
int uhci_init(void)
{
int retval;
struct pci_dev *dev = NULL;
u8 type;
+ char *name;
+
+ /* FIXME: This is lame, but I guess it's better to leak memory than */
+ /* crash */
+ name = kmalloc(10, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ strcpy(name, "uhci_td");
+
+ uhci_td_cachep = kmem_cache_create(name,
+ sizeof(struct uhci_td), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+ if (!uhci_td_cachep)
+ return -ENOMEM;
+
+ name = kmalloc(10, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ strcpy(name, "uhci_qh");
+
+ uhci_qh_cachep = kmem_cache_create(name,
+ sizeof(struct uhci_qh), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+ if (!uhci_qh_cachep)
+ return -ENOMEM;
retval = -ENODEV;
for (;;) {
- dev = pci_find_class(PCI_CLASS_SERIAL_USB<<8, dev);
+ dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev);
if (!dev)
break;
/* Is it UHCI */
return retval;
}
+void uhci_cleanup(void)
+{
+ struct list_head *next, *tmp, *head = &uhci_list;
+ int ret, i;
+
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
+ struct uhci_device *root_hub = usb_to_uhci(uhci->bus->root_hub);
+
+ next = tmp->next;
+
+ list_del(&uhci->uhci_list);
+ INIT_LIST_HEAD(&uhci->uhci_list);
+
+ /* Check if the process is still running */
+ ret = kill_proc(uhci->control_pid, 0, 1);
+ if (!ret) {
+ int count = 10;
+
+ uhci->control_continue = 0;
+ wake_up(&uhci_configure);
+
+ while (uhci->control_running && --count) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+
+ if (!count)
+ printk(KERN_ERR "uhci: giving up on killing uhci-control\n");
+ }
+
+ if (root_hub)
+ for (i = 0; i < root_hub->usb->maxchild; i++)
+ usb_disconnect(root_hub->usb->children + i);
+
+ usb_deregister_bus(uhci->bus);
+
+ reset_hc(uhci);
+ release_region(uhci->io_addr, 32);
+
+ release_uhci(uhci);
+
+ tmp = next;
+ }
+
+ if (kmem_cache_destroy(uhci_qh_cachep))
+ printk(KERN_INFO "uhci: not all QH's were freed\n");
+
+ if (kmem_cache_destroy(uhci_td_cachep))
+ printk(KERN_INFO "uhci: not all TD's were freed\n");
+}
+
#ifdef MODULE
int init_module(void)
{
#ifdef CONFIG_APM
apm_unregister_callback(&handle_apm_event);
#endif
+ uhci_cleanup();
}
#endif //MODULE
+
#define UHCI_NULL_DATA_SIZE 0x7ff /* for UHCI controller TD */
+#define UHCI_PTR_BITS 0x000F
+#define UHCI_PTR_TERM 0x0001
+#define UHCI_PTR_QH 0x0002
+#define UHCI_PTR_DEPTH 0x0004
+
struct uhci_qh {
- unsigned int link; /* Next queue */
- unsigned int element; /* Queue element pointer */
- int inuse; /* Inuse? */
- struct uhci_qh *skel; /* Skeleton head */
+ /* Hardware fields */
+ __u32 link; /* Next queue */
+ __u32 element; /* Queue element pointer */
+
+ /* Software fields */
+ atomic_t refcnt; /* Reference counting */
+ struct uhci_device *dev; /* The owning device */
+ struct uhci_qh *skel; /* Skeleton head */
+
+ wait_queue_head_t wakeup;
} __attribute__((aligned(16)));
struct uhci_framelist {
- unsigned int frame[1024];
+ __u32 frame[1024];
} __attribute__((aligned(4096)));
+#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
+#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
+#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
+#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
+#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */
+#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */
+#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */
+#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */
+#define TD_CTRL_NAK (1 << 19) /* NAK Received */
+#define TD_CTRL_CRCTIME (1 << 18) /* CTC/Time Out Error */
+#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */
+
+#define uhci_ptr_to_virt(x) bus_to_virt(x & ~UHCI_PTR_BITS)
+
+#define UHCI_TD_REMOVE 0x0001 /* Remove when done */
+
/*
* The documentation says "4 words for hardware, 4 words for software".
*
* On 64-bit machines we probably want to take advantage of the fact that
* hw doesn't really care about the size of the sw-only area.
*
- * Alas, not anymore, we have more than 4 words of software, woops
+ * Alas, not anymore, we have more than 4 words for software, woops
*/
struct uhci_td {
/* Hardware fields */
__u32 buffer;
/* Software fields */
+ unsigned int *backptr; /* Where to remove this from.. */
struct list_head irq_list; /* Active interrupt list.. */
+
usb_device_irq completed; /* Completion handler routine */
- unsigned int *backptr; /* Where to remove this from.. */
void *dev_id;
- int inuse; /* Inuse? (b0) Remove (b1)*/
- struct uhci_qh *qh;
- struct uhci_td *first;
- struct usb_device *dev; /* the owning device */
-} __attribute__((aligned(32)));
+
+ atomic_t refcnt; /* Reference counting */
+ struct uhci_device *dev; /* The owning device */
+ struct uhci_qh *qh; /* QH this TD is a part of (ignored for Isochronous) */
+ int flags; /* Remove, etc */
+} __attribute__((aligned(16)));
struct uhci_iso_td {
- int num;
- char *data;
- int maxsze;
+ int num; /* Total number of TD's */
+ char *data; /* Beginning of buffer */
+ int maxsze; /* Maximum size of each data block */
- struct uhci_td *td;
+ struct uhci_td *td; /* Pointer to first TD */
- int frame;
- int endframe;
+ int frame; /* Beginning frame */
+ int endframe; /* End frame */
};
/*
*/
struct uhci;
+#if 0
#define UHCI_MAXTD 64
#define UHCI_MAXQH 16
+#endif
/* The usb device part must be first! */
struct uhci_device {
struct usb_device *usb;
struct uhci *uhci;
+#if 0
struct uhci_qh qh[UHCI_MAXQH]; /* These are the "common" qh's for each device */
struct uhci_td td[UHCI_MAXTD];
+#endif
unsigned long data[16];
};
#define uhci_to_usb(uhci) ((uhci)->usb)
#define usb_to_uhci(usb) ((struct uhci_device *)(usb)->hcpriv)
-/*
- * The root hub pre-allocated QH's and TD's have
- * some special global uses..
- */
-#if 0
-#define control_td td /* Td's 0-30 */
-/* This is only for the root hub's TD list */
-#define tick_td td[31]
-#endif
-
/*
* There are various standard queues. We set up several different
* queues for each of the three basic queue types: interrupt,
* transfers in QH's and all of their pictures don't have that either) but
* other than that, that is what we're doing now
*
- * To keep with Linus' nomenclature, this is called the qh skeleton. These
- * labels (below) are only signficant to the root hub's qh's
+ * And now we don't put Iso transfers in QH's, so we don't waste one on it
+ *
+ * To keep with Linus' nomenclature, this is called the QH skeleton. These
+ * labels (below) are only signficant to the root hub's QH's
*/
-#define skel_iso_qh qh[0]
+#define UHCI_NUM_SKELQH 10
-#define skel_int2_qh qh[1]
-#define skel_int4_qh qh[2]
-#define skel_int8_qh qh[3]
-#define skel_int16_qh qh[4]
-#define skel_int32_qh qh[5]
-#define skel_int64_qh qh[6]
-#define skel_int128_qh qh[7]
-#define skel_int256_qh qh[8]
+#define skel_int2_qh skelqh[0]
+#define skel_int4_qh skelqh[1]
+#define skel_int8_qh skelqh[2]
+#define skel_int16_qh skelqh[3]
+#define skel_int32_qh skelqh[4]
+#define skel_int64_qh skelqh[5]
+#define skel_int128_qh skelqh[6]
+#define skel_int256_qh skelqh[7]
-#define skel_control_qh qh[9]
+#define skel_control_qh skelqh[8]
-#define skel_bulk0_qh qh[10]
-#define skel_bulk1_qh qh[11]
-#define skel_bulk2_qh qh[12]
-#define skel_bulk3_qh qh[13]
-
-/*
- * These are significant to the devices allocation of QH's
- */
-#if 0
-#define iso_qh qh[0]
-#define int_qh qh[1] /* We have 2 "common" interrupt QH's */
-#define control_qh qh[3]
-#define bulk_qh qh[4] /* We have 4 "common" bulk QH's */
-#define extra_qh qh[8] /* The rest, anything goes */
-#endif
+#define skel_bulk_qh skelqh[9]
/*
* This describes the full uhci information.
int irq;
unsigned int io_addr;
+ int control_pid;
+ int control_running;
+ int control_continue;
+
+ struct list_head uhci_list;
+
struct usb_bus *bus;
-#if 0
- /* These are "standard" QH's for the entire bus */
- struct uhci_qh qh[UHCI_MAXQH];
-#endif
+ struct uhci_qh skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
+
struct uhci_framelist *fl; /* Frame list */
struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */
+
+ struct uhci_td *ticktd;
};
/* needed for the debugging code */
int usb_register(struct usb_driver *new_driver)
{
- struct list_head *tmp = usb_bus_list.next;
+ struct list_head *tmp;
+
+ printk("usbcore: Registering new driver %s\n", new_driver->name);
+
/* Add it to the list of known drivers */
list_add(&new_driver->driver_list, &usb_driver_list);
/*
- * We go through all existing devices, and see if any of them would
- * be acceptable to the new driver.. This is done using a depth-first
- * search for devices without a registered driver already, then
+ * We go through all existing devices, and see if any of them would
+ * be acceptable to the new driver.. This is done using a depth-first
+ * search for devices without a registered driver already, then
* running 'probe' with each of the drivers registered on every one
* of these.
*/
- while (tmp!= &usb_bus_list) {
- struct usb_bus * bus = list_entry(tmp,struct
- usb_bus,bus_list);
- tmp=tmp->next;
+ tmp = usb_bus_list.next;
+ while (tmp != &usb_bus_list) {
+ struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
+
+ tmp = tmp->next;
usb_check_support(bus->root_hub);
- }
+ }
return 0;
}
void usb_deregister(struct usb_driver *driver)
{
- struct list_head *tmp = usb_bus_list.next;
- /*first we remove the driver, to be sure it doesn't get used by
- *another thread while we are stepping through removing entries
- */
+ struct list_head *tmp;
+
+ printk("usbcore: Deregistering driver %s\n", driver->name);
+
+ /*
+ * first we remove the driver, to be sure it doesn't get used by
+ * another thread while we are stepping through removing entries
+ */
list_del(&driver->driver_list);
- printk("usbcore: deregistering driver\n");
- while (tmp!= &usb_bus_list) {
- struct usb_bus * bus = list_entry(tmp,struct
- usb_bus,bus_list);
- tmp=tmp->next;
- usb_driver_purge(driver,bus->root_hub);
- }
+
+ tmp = usb_bus_list.next;
+ while (tmp != &usb_bus_list) {
+ struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
+
+ tmp = tmp->next;
+ usb_driver_purge(driver, bus->root_hub);
+ }
}
/* This function is part of a depth-first search down the device tree,
void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev)
{
int i;
- if (dev==NULL){
- printk("null device being passed in!!!\n");
- return;
- }
- for (i=0;i<USB_MAXCHILDREN;i++)
- if (dev->children[i]!=NULL)
- usb_driver_purge(driver,dev->children[i]);
- /*now we check this device*/
- if(dev->driver==driver) {
- /*
- * Note: this is not the correct way to do this, this
- * uninitializes and reinitializes EVERY driver
- */
- printk("disconnecting driverless device\n");
- dev->driver->disconnect(dev);
- dev->driver=NULL;
- /* This will go back through the list looking for a driver
- * that can handle the device
- */
- usb_device_descriptor(dev);
- }
+
+ if (!dev) {
+ printk(KERN_ERR "usbcore: null device being purged!!!\n");
+ return;
+ }
+
+ for (i=0; i<USB_MAXCHILDREN; i++)
+ if (dev->children[i])
+ usb_driver_purge(driver, dev->children[i]);
+
+ /* now we check this device */
+ if (dev->driver == driver) {
+ /*
+ * Note: this is not the correct way to do this, this
+ * uninitializes and reinitializes EVERY driver
+ */
+ printk(KERN_INFO "disconnect driverless device %d\n",
+ dev->devnum);
+ dev->driver->disconnect(dev);
+ dev->driver = NULL;
+
+ /*
+ * This will go back through the list looking for a driver
+ * that can handle the device
+ */
+ usb_find_driver(dev);
+ }
}
/*
* New functions for (de)registering a controller
*/
+struct usb_bus *usb_alloc_bus(struct usb_operations *op)
+{
+ struct usb_bus *bus;
+
+ bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return NULL;
+
+ memset(&bus->devmap, 0, sizeof(struct usb_devmap));
+
+ bus->op = op;
+ bus->root_hub = NULL;
+ bus->hcpriv = NULL;
+
+ INIT_LIST_HEAD(&bus->bus_list);
+
+ return bus;
+}
+
+void usb_free_bus(struct usb_bus *bus)
+{
+ if (!bus)
+ return;
+
+ if (bus->bus_list.next != &bus->bus_list)
+ printk(KERN_ERR "usbcore: freeing non-empty bus\n");
+
+ kfree(bus);
+}
+
void usb_register_bus(struct usb_bus *new_bus)
{
- /* Add it to the list of buses */
- list_add(&new_bus->bus_list, &usb_bus_list);
- printk("New bus registered\n");
+ /* Add it to the list of buses */
+ list_add(&new_bus->bus_list, &usb_bus_list);
+ printk("New USB bus registered\n");
}
void usb_deregister_bus(struct usb_bus *bus)
{
- /* NOTE: make sure that all the devices are removed by the
- * controller code, as well as having it call this when cleaning
+ /*
+ * NOTE: make sure that all the devices are removed by the
+ * controller code, as well as having it call this when cleaning
* itself up
- */
+ */
list_del(&bus->bus_list);
}
*/
void usb_check_support(struct usb_device *dev)
{
- int i;
- if (dev==NULL)
- {
- printk("null device being passed in!!!\n");
- return;
- }
- for (i=0;i<USB_MAXCHILDREN;i++)
- if (dev->children[i]!=NULL)
- usb_check_support(dev->children[i]);
- /*now we check this device*/
- if (dev->driver==NULL)
- usb_device_descriptor(dev);
+ int i;
+
+ if (!dev) {
+ printk(KERN_ERR "usbcore: null device being checked!!!\n");
+ return;
+ }
+
+ for (i=0; i<USB_MAXCHILDREN; i++)
+ if (dev->children[i])
+ usb_check_support(dev->children[i]);
+
+ /* now we check this device */
+ if (!dev->driver && dev->devnum > 0)
+ usb_find_driver(dev);
}
/*
* This entrypoint gets called for each new device.
* looking for one that will accept this device as
* his..
*/
-int usb_device_descriptor(struct usb_device *dev)
+int usb_find_driver(struct usb_device *dev)
{
struct list_head *tmp = usb_driver_list.next;
dev->driver = driver;
return 1;
}
+
/*
* Ok, no driver accepted the device, so show the info
* for debugging..
if (len <= 0)
return -1;
- if (n_len < 2 || n_len > len)
- {
+ if (n_len < 2 || n_len > len) {
int i;
printk("Short descriptor. (%d, %d):\n", len, n_len);
for (i = 0; i < len; ++i)
parsed += ptr[parsed];
len -= parsed;
- while((i = usb_check_descriptor(ptr+parsed, len, 0x25))>=0)
- {
+ while((i = usb_check_descriptor(ptr+parsed, len, 0x25)) >= 0) {
usb_audio_endpoint(endpoint, ptr+parsed+i);
len -= ptr[parsed+i];
parsed += ptr[parsed+i];
len -= ptr[parsed];
parsed += ptr[parsed];
- while((i=usb_check_descriptor(ptr+parsed, len, 0x24))>=0)
- {
+ while((i=usb_check_descriptor(ptr+parsed, len, 0x24)) >= 0) {
usb_audio_interface(interface, ptr+parsed+i);
len -= ptr[parsed+i];
parsed += ptr[parsed+i];
}
- if (interface->bNumEndpoints > USB_MAXENDPOINTS)
- {
+ if (interface->bNumEndpoints > USB_MAXENDPOINTS) {
printk(KERN_WARNING "usb: too many endpoints.\n");
return -1;
}
interface->endpoint = (struct usb_endpoint_descriptor *)
kmalloc(interface->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
- if(interface->endpoint==NULL)
- {
+ if (!interface->endpoint) {
printk(KERN_WARNING "usb: out of memory.\n");
return -1;
}
// len -= 9;
// }
retval = usb_parse_endpoint(dev, interface->endpoint + i, ptr + parsed, len);
- if (retval < 0) return retval;
+ if (retval < 0)
+ return retval;
parsed += retval;
len -= retval;
}
parsed += *ptr;
le16_to_cpus(&config->wTotalLength);
- if (config->bNumInterfaces > USB_MAXINTERFACES)
- {
+ if (config->bNumInterfaces > USB_MAXINTERFACES) {
printk(KERN_WARNING "usb: too many interfaces.\n");
return -1;
config->altsetting = (struct usb_alternate_setting *)
kmalloc(USB_MAXALTSETTING * sizeof(struct usb_alternate_setting), GFP_KERNEL);
- if (config->altsetting == NULL) {
+ if (!config->altsetting) {
printk(KERN_WARNING "usb: out of memory.\n");
return -1;
}
config->altsetting->interface = (struct usb_interface_descriptor *)
kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
- if(config->altsetting->interface==NULL)
- {
+ if (!config->altsetting->interface) {
printk(KERN_WARNING "usb: out of memory.\n");
return -1;
}
// now parse for additional alternate settings
for (j = 1; j < USB_MAXALTSETTING; j++) {
- retval = usb_expect_descriptor(ptr + parsed, len, USB_DT_INTERFACE, 9);
- if (retval)
- break;
- config->num_altsetting++;
- as = config->altsetting + j;
- as->interface = (struct usb_interface_descriptor *)
- kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
- if (as->interface == NULL) {
- printk(KERN_WARNING "usb: out of memory.\n");
- return -1;
- }
- memset(as->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface_descriptor));
- for (i = 0; i < config->bNumInterfaces; i++) {
- retval = usb_parse_interface(dev, as->interface + i,
+ retval = usb_expect_descriptor(ptr + parsed, len, USB_DT_INTERFACE, 9);
+ if (retval)
+ break;
+ config->num_altsetting++;
+ as = config->altsetting + j;
+ as->interface = (struct usb_interface_descriptor *)
+ kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
+ if (!as->interface) {
+ printk(KERN_WARNING "usb: out of memory.\n");
+ return -1;
+ }
+ memset(as->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface_descriptor));
+ for (i = 0; i < config->bNumInterfaces; i++) {
+ retval = usb_parse_interface(dev, as->interface + i,
ptr + parsed, len);
- if (retval < 0)
- return parsed;
- parsed += retval;
- len -= retval;
- }
+ if (retval < 0)
+ return parsed;
+ parsed += retval;
+ len -= retval;
+ }
}
return parsed;
}
int i;
unsigned char *ptr = __buf;
- if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
- {
+ if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
printk(KERN_WARNING "usb: too many configurations.\n");
return -1;
}
dev->config = (struct usb_config_descriptor *)
kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL);
- if(dev->config==NULL)
- {
+ if (!dev->config) {
printk(KERN_WARNING "usb: out of memory.\n");
return -1;
}
struct usb_alternate_setting *as;
struct usb_interface_descriptor *ifp;
- if(dev->config==NULL)
+ if (!dev->config)
return;
- for(c = 0; c < dev->descriptor.bNumConfigurations; c++)
- {
+ for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
cf = &dev->config[c];
- if (cf->altsetting == NULL)
+ if (!cf->altsetting)
break;
- for (a = 0; a < cf->num_altsetting; a++)
- {
+ for (a = 0; a < cf->num_altsetting; a++) {
as = &cf->altsetting[a];
if (as->interface == NULL)
break;
- for(i=0;i<cf->bNumInterfaces;i++)
- {
+ for(i=0;i<cf->bNumInterfaces;i++) {
ifp = &as->interface[i];
if(ifp->endpoint==NULL)
break;
return ret;
}
-int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
-{
- devrequest dr;
-
- dr.requesttype = USB_RT_HUB | 0x80;
- dr.request = USB_REQ_GET_DESCRIPTOR;
- dr.value = (USB_DT_HUB << 8);
- dr.index = 0;
- dr.length = size;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, size);
-}
-
-int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
-{
- devrequest dr;
-
- dr.requesttype = USB_RT_PORT;
- dr.request = USB_REQ_CLEAR_FEATURE;
- dr.value = feature;
- dr.index = port;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
-}
-
-int usb_set_port_feature(struct usb_device *dev, int port, int feature)
-{
- devrequest dr;
-
- dr.requesttype = USB_RT_PORT;
- dr.request = USB_REQ_SET_FEATURE;
- dr.value = feature;
- dr.index = port;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
-}
-
int usb_get_status (struct usb_device *dev, int type, int target, void *data)
{
devrequest dr;
return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2);
}
-int usb_get_hub_status(struct usb_device *dev, void *data)
-{
- devrequest dr;
-
- dr.requesttype = USB_RT_HUB | 0x80;
- dr.request = USB_REQ_GET_STATUS;
- dr.value = 0;
- dr.index = 0;
- dr.length = 4;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
-}
-
-int usb_get_port_status(struct usb_device *dev, int port, void *data)
-{
- devrequest dr;
-
- dr.requesttype = USB_RT_PORT | 0x80;
- dr.request = USB_REQ_GET_STATUS;
- dr.value = 0;
- dr.index = port;
- dr.length = 4;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
-}
-
int usb_get_protocol(struct usb_device *dev)
{
unsigned char buf[8];
struct usb_interface_descriptor *ip = &as->interface[i];
struct usb_endpoint_descriptor *ep = ip->endpoint;
int e;
+
for (e=0; e<ip->bNumEndpoints; e++) {
dev->epmaxpacket[ep[e].bEndpointAddress & 0x0f] =
ep[e].wMaxPacketSize;
result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
/* dont clear if failed */
- if (result) {
+ if (result)
return result;
- }
#if 1 /* lets be really tough */
dr.requesttype = 0x80 | USB_RT_ENDPOINT;
result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2);
- if (result) {
+ if (result)
return result;
- }
- if (status & 1) {
+ if (status & 1)
return 1; /* still halted */
- }
#endif
usb_endpoint_running(dev, endp & 0x0f);
* and is in the default state. We need to identify the thing and
* get the ball rolling..
*/
-void usb_new_device(struct usb_device *dev)
+int usb_new_device(struct usb_device *dev)
{
- int addr, i;
+ int addr;
- printk("USB new device connect, assigned device number %d\n",
+ printk(KERN_INFO "USB new device connect, assigned device number %d\n",
dev->devnum);
dev->maxpacketsize = 0; /* Default to 8 byte max packet size */
dev->epmaxpacket[0] = 8;
+ /* We still haven't set the Address yet */
addr = dev->devnum;
dev->devnum = 0;
-#if 1
/* Slow devices */
- for (i = 0; i < 5; i++) {
- if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8))
- break;
-
- printk("get_descriptor failed, waiting\n");
- wait_ms(200);
- }
- if (i == 5) {
- printk("giving up\n");
- return;
+ if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) {
+ printk(KERN_ERR "USB device not responding, giving up\n");
+ dev->devnum = -1;
+ return 1;
}
-#endif
-
-#if 0
- printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0);
-#endif
dev->epmaxpacket[0] = dev->descriptor.bMaxPacketSize0;
switch (dev->descriptor.bMaxPacketSize0) {
case 8: dev->maxpacketsize = 0; break;
case 32: dev->maxpacketsize = 2; break;
case 64: dev->maxpacketsize = 3; break;
}
-#if 0
- printk("dev->mps: %d\n", dev->maxpacketsize);
-#endif
dev->devnum = addr;
-#if 1
if (usb_set_address(dev)) {
- printk("Unable to set address\n");
- /* FIXME: We should disable the port */
- return;
+ printk(KERN_ERR "USB device not accepting new address\n");
+ dev->devnum = -1;
+ return 1;
}
-#else
- usb_set_address(dev);
-#endif
wait_ms(10); /* Let the SET_ADDRESS settle */
if (usb_get_device_descriptor(dev)) {
- printk("Unable to get device descriptor\n");
- return;
+ printk(KERN_ERR "Unable to get device descriptor\n");
+ dev->devnum = -1;
+ return 1;
}
if (usb_get_configuration(dev)) {
- printk("Unable to get configuration\n");
- return;
+ printk(KERN_ERR "Unable to get configuration\n");
+ dev->devnum = -1;
+ return 1;
}
- /* usb_get_stringtable(dev); */
-
dev->actconfig = dev->config;
dev->ifnum = 0;
usb_set_maxpacket(dev);
usb_show_string(dev, "Product", dev->descriptor.iProduct);
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
-#if 0
- printk("Vendor: %X\n", dev->descriptor.idVendor);
- printk("Product: %X\n", dev->descriptor.idProduct);
-#endif
-
- if (usb_device_descriptor(dev)==0)
- {
+ if (!usb_find_driver(dev)) {
/*
* Ok, no driver accepted the device, so show the info for
* debugging
*/
- printk ("Unknown new USB device:\n");
+ printk(KERN_DEBUG "Unknown new USB device:\n");
usb_show_device(dev);
}
+
+ return 0;
}
void* usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
}
-void* usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void * data, int len, void *dev_id)
+void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
{
return dev->bus->op->request_bulk(dev, pipe, handler, data, len, dev_id);
}
-int usb_terminate_bulk(struct usb_device *dev, void* first)
+int usb_terminate_bulk(struct usb_device *dev, void *first)
{
return dev->bus->op->terminate_bulk(dev, first);
}
-
void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
{
return usb_dev->bus->op->alloc_isoc (usb_dev, pipe, data, len, maxsze, completed, dev_id);
int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *);
void* (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
int (*release_irq)(void* handle);
- void* (*request_bulk)(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *);
- int (*terminate_bulk)(struct usb_device *, void*);
+ void *(*request_bulk)(struct usb_device *, unsigned int, usb_device_irq,
+ void *, int, void *);
+ int (*terminate_bulk)(struct usb_device *, void *);
void *(*alloc_isoc)(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id);
void (*delete_isoc)(struct usb_device *dev, void *_isodesc);
int (*sched_isoc)(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
extern int usb_register(struct usb_driver *);
extern void usb_deregister(struct usb_driver *);
+extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
+extern void usb_free_bus(struct usb_bus *);
extern void usb_register_bus(struct usb_bus *);
extern void usb_deregister_bus(struct usb_bus *);
extern void* usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
extern int usb_release_irq(struct usb_device *dev, void *handle);
-extern void* usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *);
-extern int usb_terminate_bulk(struct usb_device *, void*);
+extern void *usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *);
+extern int usb_terminate_bulk(struct usb_device *, void *);
extern void usb_init_root_hub(struct usb_device *dev);
extern void usb_connect(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **);
-extern int usb_device_descriptor(struct usb_device *dev);
+extern int usb_find_driver(struct usb_device *dev);
void usb_check_support(struct usb_device *);
void usb_driver_purge(struct usb_driver *,struct usb_device *);
extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len);
/*
* Send and receive control messages..
*/
-void usb_new_device(struct usb_device *dev);
+int usb_new_device(struct usb_device *dev);
int usb_set_address(struct usb_device *dev);
int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned
char descindex, void *buf, int size);
int usb_get_device_descriptor(struct usb_device *dev);
-int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size);
-int usb_clear_port_feature(struct usb_device *dev, int port, int feature);
-int usb_set_port_feature(struct usb_device *dev, int port, int feature);
int usb_get_status (struct usb_device *dev, int type, int target, void *data);
-int usb_get_hub_status(struct usb_device *dev, void *data);
-int usb_get_port_status(struct usb_device *dev, int port, void *data);
int usb_get_protocol(struct usb_device *dev);
int usb_set_protocol(struct usb_device *dev, int protocol);
int usb_set_interface(struct usb_device *dev, int interface, int alternate);
--- /dev/null
+/*****************************************************************************/
+
+/*
+ * uss720.c -- USS720 USB Parport Cable.
+ *
+ * Copyright (C) 1999
+ * Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * 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.
+ *
+ * Based on parport_pc.c
+ *
+ * History:
+ * 0.1 04.08.99 Created
+ * 0.2 07.08.99 Some fixes mainly suggested by Tim Waugh
+ * Interrupt handling currently disabled because
+ * usb_request_irq crashes somewhere within ohci.c
+ * for no apparent reason (that is for me, anyway)
+ * ECP currently untested
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/parport.h>
+#include <linux/init.h>
+
+#include "usb.h"
+
+/* --------------------------------------------------------------------- */
+
+struct parport_uss720_private {
+ struct usb_device *usbdev;
+ void *irqhandle;
+ unsigned char reg[7]; /* USB registers */
+};
+
+/* --------------------------------------------------------------------- */
+
+static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ struct usb_device *usbdev = priv->usbdev;
+ static const unsigned char regindex[9] = {
+ 4, 0, 1, 5, 5, 0, 2, 3, 6
+ };
+ devrequest dr;
+ int ret;
+
+ if (!usbdev)
+ return -1;
+ dr.requesttype = 0xc0;
+ dr.request = 3;
+ dr.value = ((unsigned int)reg) << 8;
+ dr.index = 0;
+ dr.length = 7;
+ ret = usbdev->bus->op->control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), &dr, priv->reg, 7);
+ if (ret) {
+ printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x\n",
+ (unsigned int)reg, ret);
+ } else {
+#if 0
+ printk(KERN_DEBUG "uss720: get_1284_register(%d) return %02x %02x %02x %02x %02x %02x %02x\n",
+ (unsigned int)reg, (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
+ (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], (unsigned int)priv->reg[4],
+ (unsigned int)priv->reg[5], (unsigned int)priv->reg[6]);
+#endif
+ /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
+ if (priv->reg[2] & priv->reg[1] & 0x10)
+ parport_generic_irq(0, pp, NULL);
+ }
+ if (val)
+ *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
+ return ret;
+}
+
+static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ struct usb_device *usbdev = priv->usbdev;
+ devrequest dr;
+ int ret;
+
+ if (!usbdev)
+ return -1;
+ dr.requesttype = 0x40;
+ dr.request = 4;
+ dr.value = (((unsigned int)reg) << 8) | val;
+ dr.index = 0;
+ dr.length = 0;
+ ret = usbdev->bus->op->control_msg(usbdev, usb_sndctrlpipe(usbdev,0), &dr, NULL, 0);
+ if (ret) {
+ printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n",
+ (unsigned int)reg, (unsigned int)val, ret);
+ } else {
+#if 0
+ printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x)\n",
+ (unsigned int)reg, (unsigned int)val);
+#endif
+ }
+ return ret;
+}
+
+/* --------------------------------------------------------------------- */
+
+/* ECR modes */
+#define ECR_SPP 00
+#define ECR_PS2 01
+#define ECR_PPF 02
+#define ECR_ECP 03
+#define ECR_EPP 04
+
+/* Safely change the mode bits in the ECR */
+static int change_mode(struct parport *pp, int m)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ int mode;
+
+ if (get_1284_register(pp, 6, NULL))
+ return -EIO;
+ /* Bits <7:5> contain the mode. */
+ mode = (priv->reg[2] >> 5) & 0x7;
+ if (mode == m)
+ return 0;
+ /* We have to go through mode 000 or 001 */
+ if (mode > ECR_PS2 && m > ECR_PS2)
+ if (change_mode(pp, ECR_PS2))
+ return -EIO;
+
+ if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) {
+ /* This mode resets the FIFO, so we may
+ * have to wait for it to drain first. */
+ long expire = jiffies + pp->physport->cad->timeout;
+ switch (mode) {
+ case ECR_PPF: /* Parallel Port FIFO mode */
+ case ECR_ECP: /* ECP Parallel Port mode */
+ /* Poll slowly. */
+ for (;;) {
+ if (get_1284_register(pp, 6, NULL))
+ return -EIO;
+ if (priv->reg[2] & 0x01)
+ break;
+ if (time_after_eq (jiffies, expire))
+ /* The FIFO is stuck. */
+ return -EBUSY;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((HZ + 99) / 100);
+ if (signal_pending (current))
+ break;
+ }
+ }
+ }
+ /* Set the mode. */
+ if (set_1284_register(pp, 6, m << 5))
+ return -EIO;
+ return 0;
+}
+
+/*
+ * Clear TIMEOUT BIT in EPP MODE
+ */
+static int clear_epp_timeout(struct parport *pp)
+{
+ unsigned char stat;
+
+ if (get_1284_register(pp, 1, &stat))
+ return 1;
+ return stat & 1;
+}
+
+/*
+ * Access functions.
+ */
+
+static void parport_uss720_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
+{
+ struct parport *pp = (struct parport *)dev_id;
+ struct parport_uss720_private *priv = pp->private_data;
+
+ if (usbstatus != USB_ST_NOERROR || len < 4 || !buffer)
+ return 1;
+ memcpy(priv->reg, buffer, 4);
+ /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
+ if (priv->reg[2] & priv->reg[1] & 0x10)
+ parport_generic_irq(0, pp, NULL);
+ return 1;
+}
+
+static void parport_uss720_write_data(struct parport *pp, unsigned char d)
+{
+ set_1284_register(pp, 0, d);
+}
+
+static unsigned char parport_uss720_read_data(struct parport *pp)
+{
+ unsigned char ret;
+
+ if (get_1284_register(pp, 0, &ret))
+ return 0;
+ return ret;
+}
+
+static void parport_uss720_write_control(struct parport *pp, unsigned char d)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+
+ d = (d & 0xf) | (priv->reg[1] & 0xf0);
+ if (set_1284_register(pp, 2, d))
+ return;
+ priv->reg[1] = d;
+}
+
+static unsigned char parport_uss720_read_control(struct parport *pp)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ return priv->reg[1] & 0xf; /* Use soft copy */
+}
+
+static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned char mask, unsigned char val)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ unsigned char d;
+
+ mask &= 0x0f;
+ val &= 0x0f;
+ d = (priv->reg[1] & (~mask)) ^ val;
+ if (set_1284_register(pp, 2, d))
+ return 0;
+ priv->reg[1] = d;
+ return d & 0xf;
+}
+
+static unsigned char parport_uss720_read_status(struct parport *pp)
+{
+ unsigned char ret;
+
+ if (get_1284_register(pp, 1, &ret))
+ return 0;
+ return ret & 0xf8;
+}
+
+static void parport_uss720_disable_irq(struct parport *pp)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ unsigned char d;
+
+ d = priv->reg[1] & ~0x10;
+ if (set_1284_register(pp, 2, d))
+ return;
+ priv->reg[1] = d;
+}
+
+static void parport_uss720_enable_irq(struct parport *pp)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ unsigned char d;
+
+ d = priv->reg[1] | 0x10;
+ if (set_1284_register(pp, 2, d))
+ return;
+ priv->reg[1] = d;
+}
+
+static void parport_uss720_data_forward (struct parport *pp)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ unsigned char d;
+
+ d = priv->reg[1] & ~0x20;
+ if (set_1284_register(pp, 2, d))
+ return;
+ priv->reg[1] = d;
+}
+
+static void parport_uss720_data_reverse (struct parport *pp)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ unsigned char d;
+
+ d = priv->reg[1] | 0x20;
+ if (set_1284_register(pp, 2, d))
+ return;
+ priv->reg[1] = d;
+}
+
+static void parport_uss720_init_state(struct pardevice *dev, struct parport_state *s)
+{
+ s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+ s->u.pc.ecr = 0x24;
+}
+
+static void parport_uss720_save_state(struct parport *pp, struct parport_state *s)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+
+ if (get_1284_register(pp, 2, NULL))
+ return;
+ s->u.pc.ctr = priv->reg[1];
+ s->u.pc.ecr = priv->reg[2];
+}
+
+static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s)
+{
+ set_1284_register(pp, 2, s->u.pc.ctr);
+ set_1284_register(pp, 6, s->u.pc.ecr);
+ get_1284_register(pp, 2, NULL);
+}
+
+static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ size_t got = 0;
+
+ if (change_mode(pp, ECR_EPP))
+ return 0;
+ for (; got < length; got++) {
+ if (get_1284_register(pp, 4, (char *)buf))
+ break;
+ ((char*)buf)++;
+ if (priv->reg[0] & 0x01) {
+ clear_epp_timeout(pp);
+ break;
+ }
+ }
+ change_mode(pp, ECR_PS2);
+ return got;
+}
+
+static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, size_t length, int flags)
+{
+#if 0
+ struct parport_uss720_private *priv = pp->private_data;
+ size_t written = 0;
+
+ if (change_mode(pp, ECR_EPP))
+ return 0;
+ for (; written < length; written++) {
+ if (set_1284_register(pp, 4, (char *)buf))
+ break;
+ ((char*)buf)++;
+ if (get_1284_register(pp, 1, NULL))
+ break;
+ if (priv->reg[0] & 0x01) {
+ clear_epp_timeout(pp);
+ break;
+ }
+ }
+ change_mode(pp, ECR_PS2);
+ return written;
+#else
+ struct parport_uss720_private *priv = pp->private_data;
+ struct usb_device *usbdev = priv->usbdev;
+ unsigned long rlen;
+ int i;
+
+ if (!usbdev)
+ return 0;
+ if (change_mode(pp, ECR_EPP))
+ return 0;
+ i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buf, length, &rlen);
+ if (i)
+ printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buf, length, rlen);
+ change_mode(pp, ECR_PS2);
+ return rlen;
+#endif
+}
+
+static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t length, int flags)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ size_t got = 0;
+
+ if (change_mode(pp, ECR_EPP))
+ return 0;
+ for (; got < length; got++) {
+ if (get_1284_register(pp, 3, (char *)buf))
+ break;
+ ((char*)buf)++;
+ if (priv->reg[0] & 0x01) {
+ clear_epp_timeout(pp);
+ break;
+ }
+ }
+ change_mode(pp, ECR_PS2);
+ return got;
+}
+
+static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, size_t length, int flags)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ size_t written = 0;
+
+ if (change_mode(pp, ECR_EPP))
+ return 0;
+ for (; written < length; written++) {
+ if (set_1284_register(pp, 3, *(char *)buf))
+ break;
+ ((char*)buf)++;
+ if (get_1284_register(pp, 1, NULL))
+ break;
+ if (priv->reg[0] & 0x01) {
+ clear_epp_timeout(pp);
+ break;
+ }
+ }
+ change_mode(pp, ECR_PS2);
+ return written;
+}
+
+static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ struct usb_device *usbdev = priv->usbdev;
+ unsigned long rlen;
+ int i;
+
+ if (!usbdev)
+ return 0;
+ if (change_mode(pp, ECR_ECP))
+ return 0;
+ i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen);
+ if (i)
+ printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buffer, len, rlen);
+ change_mode(pp, ECR_PS2);
+ return rlen;
+}
+
+static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, size_t len, int flags)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ struct usb_device *usbdev = priv->usbdev;
+ unsigned long rlen;
+ int i;
+
+ if (!usbdev)
+ return 0;
+ if (change_mode(pp, ECR_ECP))
+ return 0;
+ i = usbdev->bus->op->bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen);
+ if (i)
+ printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %u rlen %lu\n", buffer, len, rlen);
+ change_mode(pp, ECR_PS2);
+ return rlen;
+}
+
+static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+ size_t written = 0;
+
+ if (change_mode(pp, ECR_ECP))
+ return 0;
+ for (; written < len; written++) {
+ if (set_1284_register(pp, 5, *(char *)buffer))
+ break;
+ ((char*)buffer)++;
+ }
+ change_mode(pp, ECR_PS2);
+ return written;
+}
+
+static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+ struct parport_uss720_private *priv = pp->private_data;
+ struct usb_device *usbdev = priv->usbdev;
+ unsigned long rlen;
+ int i;
+
+ if (!usbdev)
+ return 0;
+ if (change_mode(pp, ECR_PPF))
+ return 0;
+ i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen);
+ if (i)
+ printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buffer, len, rlen);
+ change_mode(pp, ECR_PS2);
+ return rlen;
+}
+
+void parport_uss720_inc_use_count(void)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+void parport_uss720_dec_use_count(void)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct parport_operations parport_uss720_ops =
+{
+ parport_uss720_write_data,
+ parport_uss720_read_data,
+
+ parport_uss720_write_control,
+ parport_uss720_read_control,
+ parport_uss720_frob_control,
+
+ parport_uss720_read_status,
+
+ parport_uss720_enable_irq,
+ parport_uss720_disable_irq,
+
+ parport_uss720_data_forward,
+ parport_uss720_data_reverse,
+
+ parport_uss720_init_state,
+ parport_uss720_save_state,
+ parport_uss720_restore_state,
+
+ parport_uss720_inc_use_count,
+ parport_uss720_dec_use_count,
+
+ parport_uss720_epp_write_data,
+ parport_uss720_epp_read_data,
+ parport_uss720_epp_write_addr,
+ parport_uss720_epp_read_addr,
+
+ parport_uss720_ecp_write_data,
+ parport_uss720_ecp_read_data,
+ parport_uss720_ecp_write_addr,
+
+ parport_uss720_write_compat,
+ parport_ieee1284_read_nibble,
+ parport_ieee1284_read_byte,
+};
+
+/* --------------------------------------------------------------------- */
+
+static int uss720_probe(struct usb_device *usbdev)
+{
+ struct usb_interface_descriptor *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct parport_uss720_private *priv;
+ struct parport *pp;
+ int i;
+
+ printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n",
+ usbdev->descriptor.idVendor, usbdev->descriptor.idProduct);
+
+ if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) &&
+ (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001))
+ return -1;
+
+ /* We don't handle multiple configurations */
+ if (usbdev->descriptor.bNumConfigurations != 1)
+ return -1;
+
+ /* We don't handle multiple interfaces */
+ if (usbdev->config[0].bNumInterfaces != 1)
+ return -1;
+
+ /* We don't handle multiple interfaces */
+ if (usbdev->config[0].num_altsetting != 3)
+ return -1;
+
+ printk(KERN_DEBUG "uss720: set configuration\n");
+ usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue);
+
+ i = usb_set_interface(usbdev, 0, 2);
+ printk(KERN_DEBUG "uss720: set inteface result %d\n", i);
+
+ interface = &usbdev->config[0].altsetting[2].interface[0];
+
+ //printk(KERN_DEBUG "uss720: get interface\n");
+ //i = usb_get_interface(usbdev, 0);
+ //printk(KERN_DEBUG "uss720: is in alternate setting %d\n", i);
+
+ /*
+ * Allocate parport interface
+ */
+ printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
+
+ if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL)))
+ return -1;
+ if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
+ kfree(priv);
+ return -1;
+ }
+ pp->private_data = priv;
+ usbdev->private = pp;
+ priv->usbdev = usbdev;
+ pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
+
+ /* set the USS720 control register to manual mode, no ECP compression, enable all ints */
+ set_1284_register(pp, 7, 0x00);
+ set_1284_register(pp, 6, 0x30); /* PS/2 mode */
+ set_1284_register(pp, 2, 0x0c);
+ /* debugging */
+ get_1284_register(pp, 0, NULL);
+ printk("uss720: reg: %02x %02x %02x %02x %02x %02x %02x\n",
+ priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
+
+ endpoint = &interface->endpoint[2];
+ printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->bEndpointAddress, endpoint->bInterval);
+#if 0
+ priv->irqhandle = usb_request_irq(usbdev, usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress),
+ uss720_irq, endpoint->bInterval, pp);
+#endif
+ parport_proc_register(pp);
+ parport_announce_port(pp);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void uss720_disconnect(struct usb_device *usbdev)
+{
+ struct parport *pp = (struct parport *)usbdev->private;
+ struct parport_uss720_private *priv = pp->private_data;
+
+#if 0
+ usb_release_irq(usbdev, priv->irqhandle);
+#endif
+ usbdev->private = NULL;
+ priv->usbdev = NULL;
+ parport_proc_unregister(pp);
+ parport_unregister_port(pp);
+ kfree(priv);
+ MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver uss720_driver = {
+ "uss720",
+ uss720_probe,
+ uss720_disconnect,
+ { NULL, NULL }
+};
+
+/* --------------------------------------------------------------------- */
+
+#define __exit
+#define module_exit(x) void cleanup_module(void) { x(); }
+#define module_init(x) int init_module(void) { return x(); }
+
+/* --------------------------------------------------------------------- */
+
+static int __init uss720_init(void)
+{
+ usb_register(&uss720_driver);
+ printk(KERN_INFO "uss720: USB<->IEEE1284 cable driver v0.2 registered.\n"
+ KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
+ return 0;
+}
+
+static void __exit uss720_cleanup(void)
+{
+ usb_deregister(&uss720_driver);
+}
+
+module_init(uss720_init);
+module_exit(uss720_cleanup);
+
+/* --------------------------------------------------------------------- */
fi
if [ "$CONFIG_ATARI" = "y" ]; then
bool 'Atari native chipset support' CONFIG_FB_ATARI
- bool 'ATI Mach64 display support' CONFIG_FB_ATY
+ tristate 'ATI Mach64 display support' CONFIG_FB_ATY
fi
if [ "$CONFIG_PPC" = "y" ]; then
bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
bool 'Apple "control" display support' CONFIG_FB_CONTROL
bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
- bool 'ATI Mach64 display support' CONFIG_FB_ATY
+ tristate 'ATI Mach64 display support' CONFIG_FB_ATY
bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT
bool 'Chips 65550 display support' CONFIG_FB_CT65550
bool 'S3 Trio display support' CONFIG_FB_S3TRIO
fi
+ tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16
fi
if [ "$CONFIG_MAC" = "y" ]; then
define_bool CONFIG_FB_MAC y
fi
if [ "$ARCH" = "i386" ]; then
bool 'VESA VGA graphics console' CONFIG_FB_VESA
- bool 'VGA 16-color graphics console' CONFIG_FB_VGA16
+ tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16
define_bool CONFIG_VIDEO_SELECT y
fi
if [ "$CONFIG_VISWS" = "y" ]; then
if [ "$CONFIG_FB_MATROX" != "n" ]; then
bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE
- bool ' G100/G200 support' CONFIG_FB_MATROX_G100
+ bool ' G100/G200/G400 support' CONFIG_FB_MATROX_G100
bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD
fi
- bool 'ATI Mach64 display support' CONFIG_FB_ATY
+ tristate 'ATI Mach64 display support' CONFIG_FB_ATY
fi
fi
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
if [ "$CONFIG_PCI" != "n" ]; then
bool 'PCI framebuffers' CONFIG_FB_PCI
if [ "$CONFIG_FB_PCI" != "n" ]; then
- bool ' ATI Mach64 display support' CONFIG_FB_ATY
+ tristate ' ATI Mach64 display support' CONFIG_FB_ATY
fi
fi
fi
tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
# tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
- bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
+ tristate 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA
else
# Guess what we need
fi
if [ "$CONFIG_FB_VGA16" = "y" ]; then
define_bool CONFIG_FBCON_VGA_PLANES y
+ else
+ if [ "$CONFIG_FB_VGA16" = "m" ]; then
+ define_bool CONFIG_FBCON_VGA_PLANES m
+ fi
fi
if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then
define_bool CONFIG_FBCON_VGA y
ifeq ($(CONFIG_FB_ATY),y)
L_OBJS += atyfb.o
+else
+ ifeq ($(CONFIG_FB_ATY),m)
+ M_OBJS += atyfb.o
+ endif
endif
ifeq ($(CONFIG_FB_IGA),y)
ifeq ($(CONFIG_FB_VGA16),y)
L_OBJS += vga16fb.o
+else
+ ifeq ($(CONFIG_FB_VGA16),m)
+ M_OBJS += vga16fb.o
+ endif
endif
ifeq ($(CONFIG_FB_VIRGE),y)
return -EINVAL;
}
-__initfunc(void s3triofb_init(void))
+void __init s3triofb_init(void)
{
#ifdef __powerpc__
/* We don't want to be called like this. */
#endif /* !__powerpc__ */
}
-__initfunc(void s3trio_resetaccel(void)) {
+void __init s3trio_resetaccel(void){
#define EC01_ENH_ENB 0x0005
outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
}
-__initfunc(int s3trio_init(struct device_node *dp)) {
+int __init s3trio_init(struct device_node *dp){
u_char bus, dev;
unsigned int t32;
* We heavily rely on OF for the moment. This needs fixing.
*/
-__initfunc(void s3triofb_init_of(struct device_node *dp))
+void __init s3triofb_init_of(struct device_node *dp)
{
int i, *pp, len;
unsigned long address;
}
};
-__initfunc(static int
-acornfb_lookup_timing(struct fb_var_screeninfo *var))
+static int __init
+acornfb_lookup_timing(struct fb_var_screeninfo *var)
{
const struct modex_params *x;
const struct modey_params *y;
return 0;
}
-__initfunc(static void
-acornfb_init_fbinfo(void))
+static void __init
+acornfb_init_fbinfo(void)
{
static int first = 1;
* size can optionally be followed by 'M' or 'K' for
* MB or KB respectively.
*/
-__initfunc(static void
-acornfb_parse_font(char *opt))
+static void __init
+acornfb_parse_font(char *opt)
{
strcpy(fb_info.fontname, opt);
}
-__initfunc(static void
-acornfb_parse_mon(char *opt))
+static void __init
+acornfb_parse_mon(char *opt)
{
fb_info.monspecs.hfmin = simple_strtoul(opt, &opt, 0);
if (*opt == '-')
init_var.height = simple_strtoul(opt + 1, NULL, 0);
}
-__initfunc(static void
-acornfb_parse_montype(char *opt))
+static void __init
+acornfb_parse_montype(char *opt)
{
current_par.montype = -2;
}
}
-__initfunc(static void
-acornfb_parse_dram(char *opt))
+static void __init
+acornfb_parse_dram(char *opt)
{
unsigned int size;
{ NULL, NULL }
};
-__initfunc(void
-acornfb_setup(char *options, int *ints))
+void __init
+acornfb_setup(char *options, int *ints)
{
struct options *optp;
char *opt;
* Detect type of monitor connected
* For now, we just assume SVGA
*/
-__initfunc(static int
-acornfb_detect_monitortype(void))
+static int __init
+acornfb_detect_monitortype(void)
{
return 4;
}
printk("acornfb: freed %dK memory\n", mb_freed);
}
-__initfunc(void
-acornfb_init(void))
+void __init
+acornfb_init(void)
{
unsigned long size;
u_int h_sync, v_sync;
amifb_pan_display, amifb_ioctl
};
-
-__initfunc(void amifb_setup(char *options, int *ints))
+void __init amifb_setup(char *options, int *ints)
{
char *this_opt;
char mcap_spec[80];
* Initialisation
*/
-__initfunc(void amifb_init(void))
+void __init amifb_init(void)
{
int tag, i;
u_long chipptr;
* Get a Video Mode
*/
-__initfunc(static void get_video_mode(const char *name))
+static void __init get_video_mode(const char *name)
{
int i;
* Probe the Video Modes
*/
-__initfunc(static void check_default_mode(void))
+static void __init check_default_mode(void)
{
struct amifb_par par;
int mode;
* Allocate, Clear and Align a Block of Chip Memory
*/
-__initfunc(static u_long chipalloc(u_long size))
+static u_long __init chipalloc(u_long size)
{
u_long ptr;
* A strtok which returns empty strings, too
*/
-__initfunc(static char *strtoke(char *s,const char *ct))
+static char __init *strtoke(char *s,const char *ct)
{
char *sbegin, *send;
static char *ssave = NULL;
* Initialise the Copper Initialisation List
*/
-__initfunc(static void ami_init_copper(void))
+static void __init ami_init_copper(void)
{
copins *cop = copdisplay.init;
u_long p;
do_install_cmap(currcon, info);
}
-__initfunc(void atafb_init(void))
+void __init atafb_init(void)
{
int pad;
int detected_mode;
/* Map the video memory (physical address given) to somewhere
* in the kernel address space.
*/
- external_addr = ioremap_writethrough(external_addr, external_len);
+ external_addr =
+ ioremap_writethrough((unsigned long)external_addr,
+ external_len);
if (external_vgaiobase)
- external_vgaiobase = ioremap(external_vgaiobase, 0x10000 );
+ external_vgaiobase =
+ (unsigned long)ioremap(external_vgaiobase, 0x10000);
screen_base =
real_screen_base = external_addr;
screen_len = external_len & PAGE_MASK;
return sbegin;
}
-__initfunc(void atafb_setup( char *options, int *ints ))
+void __init atafb_setup( char *options, int *ints )
{
char *this_opt;
int temp;
external_yres = yres;
external_depth = depth;
external_pmode = planes;
- external_addr = addr;
+ external_addr = (void *)addr;
external_len = len;
if (external_card_type == IS_MV300)
#define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 0_2D */
#define MEM_VGA_RP_SEL 0x00B8 /* Dword offset 0_2E */
+#define I2C_CNTL_1 0x00BC /* Dword offset 0_2F */
+
#define DAC_REGS 0x00C0 /* Dword offset 0_30 */
#define DAC_W_INDEX 0x00C0 /* Dword offset 0_30 */
#define DAC_DATA 0x00C1 /* Dword offset 0_30 */
-/* $Id: atyfb.c,v 1.107 1999/06/08 19:59:03 geert Exp $
+/* $Id: atyfb.c,v 1.109 1999/08/08 01:38:05 davem Exp $
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
* Copyright (C) 1997-1998 Geert Uytterhoeven
struct fb_info_aty {
struct fb_info fb_info;
+ struct fb_info_aty *next;
unsigned long ati_regbase_phys;
unsigned long ati_regbase;
unsigned long frame_buffer_phys;
}
}
-__initfunc(static struct aty_cursor *
-aty_init_cursor(struct fb_info_aty *fb))
+static struct fb_info_aty *fb_list = NULL;
+
+static struct aty_cursor * __init
+aty_init_cursor(struct fb_info_aty *fb)
{
struct aty_cursor *cursor;
unsigned long addr;
* Initialisation
*/
-__initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
+static int __init aty_init(struct fb_info_aty *info, const char *name)
{
u32 chip_id;
u32 i;
if (register_framebuffer(&info->fb_info) < 0)
return 0;
+ info->next = fb_list;
+ fb_list = info;
+
printk("fb%d: %s frame buffer device on %s\n",
GET_FB_IDX(info->fb_info.node), atyfb_name, name);
return 1;
}
-__initfunc(void atyfb_init(void))
+void __init atyfb_init(void)
{
#if defined(CONFIG_FB_OF)
/* We don't want to be called like this. */
for (pdev = pci_devices; pdev; pdev = pdev->next) {
if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
(pdev->vendor == PCI_VENDOR_ID_ATI)) {
+ struct resource *rp;
info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
if (!info) {
}
memset(info, 0, sizeof(struct fb_info_aty));
- addr = pdev->base_address[0];
- if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
- addr = pdev->base_address[1];
+ rp = &pdev->resource[0];
+ if (rp->flags & IORESOURCE_IOPORT)
+ rp = &pdev->resource[1];
+ addr = rp->start;
if (!addr)
continue;
- addr &= PCI_BASE_ADDRESS_MEM_MASK;
#ifdef __sparc__
/*
* Figure mmap addresses from PCI config space.
* Split Framebuffer in big- and little-endian halfs.
*/
- for (i = 0; i < 6 && pdev->base_address[i]; i++)
+ for (i = 0; i < 6 && pdev->resource[i].start; i++)
/* nothing */;
j = i + 4;
}
memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
- for (i = 0, j = 2; i < 6 && pdev->base_address[i]; i++) {
+ for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
+ struct resource *rp = &pdev->resource[i];
int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
unsigned long base;
u32 size, pbase;
- base = pdev->base_address[i];
+ base = rp->start;
- io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+ io = (rp->flags & IORESOURCE_IOPORT);
pci_read_config_dword(pdev, breg, &pbase);
pci_write_config_dword(pdev, breg, 0xffffffff);
}
#ifdef CONFIG_FB_OF
-__initfunc(void atyfb_of_init(struct device_node *dp))
+void __init atyfb_of_init(struct device_node *dp)
{
unsigned long addr;
u8 bus, devfn;
0x1000);
if(! info->ati_regbase) {
- printk("atyfb_init: ioremap() returned NULL\n");
+ printk("atyfb_of_init: ioremap() returned NULL\n");
kfree(info);
return;
}
info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
if(! info->frame_buffer) {
- printk("atyfb_init: ioremap() returned NULL\n");
+ printk("atyfb_of_init: ioremap() returned NULL\n");
kfree(info);
return;
}
#endif /* CONFIG_FB_OF */
-__initfunc(void atyfb_setup(char *options, int *ints))
+void __init atyfb_setup(char *options, int *ints)
{
char *this_opt;
}
#ifdef CONFIG_ATARI
-__initfunc(static int store_video_par(char *video_str, unsigned char m64_num))
+static int __init store_video_par(char *video_str, unsigned char m64_num)
{
char *p;
unsigned long vmembase, size, guiregbase;
return -1;
}
-__initfunc(static char *strtoke(char *s, const char *ct))
+static char __init *strtoke(char *s, const char *ct)
{
static char *ssave = NULL;
char *sbegin, *send;
FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
+
+#ifdef MODULE
+int __init init_module(void)
+{
+ atyfb_init();
+ return fb_list ? 0 : -ENXIO;
+}
+
+void cleanup_module(void)
+{
+ while (fb_list) {
+ struct fb_info_aty *info = fb_list;
+ fb_list = info->next;
+
+ unregister_framebuffer(&info->fb_info);
+
+#ifndef __sparc__
+ if (info->ati_regbase)
+ iounmap((void *)info->ati_regbase);
+ if (info->frame_buffer)
+ iounmap((void *)info->frame_buffer);
+#ifdef __BIG_ENDIAN
+ if (info->cursor && info->cursor->ram)
+ iounmap(info->cursor->ram);
+#endif
+#endif
+
+ if (info->cursor) {
+ if (info->cursor->timer)
+ kfree(info->cursor->timer);
+ kfree(info->cursor);
+ }
+#ifdef __sparc__
+ if (info->mmap_map)
+ kfree(info->mmap_map);
+#endif
+ kfree(info);
+ }
+}
+
+#endif
return 0;
}
-__initfunc(static unsigned long get_phys(unsigned long addr))
+static unsigned long __init get_phys(unsigned long addr)
{
return __get_phys(addr);
}
-__initfunc(static int get_iospace(unsigned long addr))
+static int __init get_iospace(unsigned long addr)
{
return __get_iospace(addr);
}
static char idstring[60] __initdata = { 0 };
-__initfunc(char *cgfourteenfb_init(struct fb_info_sbusfb *fb))
+char __init *cgfourteenfb_init(struct fb_info_sbusfb *fb)
{
struct fb_fix_screeninfo *fix = &fb->fix;
struct display *disp = &fb->disp;
static char idstring[70] __initdata = { 0 };
-__initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb))
+char __init *cgsixfb_init(struct fb_info_sbusfb *fb)
{
struct fb_fix_screeninfo *fix = &fb->fix;
struct fb_var_screeninfo *var = &fb->var;
static char idstring[60] __initdata = { 0 };
-__initfunc(char *cgthreefb_init(struct fb_info_sbusfb *fb))
+char __init *cgthreefb_init(struct fb_info_sbusfb *fb)
{
struct fb_fix_screeninfo *fix = &fb->fix;
struct display *disp = &fb->disp;
{ 0xa8, 0x00 }
};
-__initfunc(static void chips_hw_init(struct fb_info_chips *p))
+static void __init chips_hw_init(struct fb_info_chips *p)
{
int i;
write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
}
-__initfunc(static void init_chips(struct fb_info_chips *p))
+static void __init init_chips(struct fb_info_chips *p)
{
int i;
all_chips = p;
}
-__initfunc(void chips_init(void))
+void __init chips_init(void)
{
#ifndef CONFIG_FB_OF
struct device_node *dp;
#endif /* CONFIG_FB_OF */
}
-__initfunc(void chips_of_init(struct device_node *dp))
+void __init chips_of_init(struct device_node *dp)
{
struct fb_info_chips *p;
unsigned long addr;
/********************************************************************/
/* clgenfb_init() - master initialization function */
/********************************************************************/
-__initfunc(void clgenfb_init(void))
+void __init clgenfb_init(void)
{
const struct ConfigDev *cd = NULL;
const struct ConfigDev *cd2 = NULL;
/* arguments to the video= bootstrap parameter. Right now, there */
/* is nothing I do here. */
/*****************************************************************/
-__initfunc(void clgenfb_setup(char *options, int *ints))
+void __init clgenfb_setup(char *options, int *ints)
{
// char *this_opt;
}
-__initfunc(static void init_control(struct fb_info_control *p))
+static void __init init_control(struct fb_info_control *p)
{
struct fb_par_control parstruct;
struct fb_par_control *par = &parstruct;
#endif /* CONFIG_FB_COMPAT_XPMAC */
}
-__initfunc(void control_init(void))
+void __init control_init(void)
{
#ifndef CONFIG_FB_OF
struct device_node *dp;
#endif /* CONFIG_FB_OF */
}
-__initfunc(void control_of_init(struct device_node *dp))
+void __init control_of_init(struct device_node *dp)
{
struct fb_info_control *p;
unsigned long addr, size;
}
/* Parse user speficied options (`video=controlfb:') */
-__initfunc(void control_setup(char *options, int *ints))
+void __init control_setup(char *options, int *ints)
{
char *this_opt;
static char idstring[60] __initdata = { 0 };
-__initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb))
+char __init *creatorfb_init(struct fb_info_sbusfb *fb)
{
struct fb_fix_screeninfo *fix = &fb->fix;
struct fb_var_screeninfo *var = &fb->var;
}
}
-__initfunc(void cyber2000fb_setup(char *options, int *ints))
+void __init cyber2000fb_setup(char *options, int *ints)
{
}
cyber2000fb_ioctl
};
-__initfunc(static void
-cyber2000fb_init_fbinfo(void))
+static void __init
+cyber2000fb_init_fbinfo(void)
{
static int first = 1;
/*
* Initialization
*/
-__initfunc(void cyber2000fb_init(void))
+void __init cyber2000fb_init(void)
{
struct pci_dev *dev;
u_int h_sync, v_sync;
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-#define wb_64(reg,dat) (*((unsigned char volatile *)CyberRegs + reg) = dat)
+#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
+#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
+
+#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
struct cyberfb_par {
struct fb_var_screeninfo var;
/*
-* Switch for Chipset Independency
-*/
-
-static struct fb_hwswitch {
-
-/* Initialisation */
-
-int (*init)(void);
-
-/* Display Control */
-
-int (*encode_fix)(struct fb_fix_screeninfo *fix, struct cyberfb_par *par);
-int (*decode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par);
-int (*encode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par);
-int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
-int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-void (*blank)(int blank);
-} *fbhw;
-
-
-/*
-* Frame Buffer Name
-*/
+ * Frame Buffer Name
+ */
static char cyberfb_name[16] = "Cybervision";
/*
-* Cybervision Graphics Board
-*/
+ * CyberVision Graphics Board
+ */
static unsigned char Cyber_colour_table [256][3];
-static unsigned long CyberMem;
static unsigned long CyberSize;
-static volatile char *CyberRegs;
+static volatile unsigned char *CyberBase;
+static volatile unsigned char *CyberMem;
+static volatile unsigned char *CyberRegs;
static unsigned long CyberMem_phys;
static unsigned long CyberRegs_phys;
-/* From cvision.c for cvision_core.c */
-static unsigned long cv64_mem;
-static unsigned long cv64_fbmem;
-static volatile char *cv64_regs;
-static unsigned long cv64_size;
-#if 0
-static int cvision_custom_mode = 0;
-static int hbs, hbe, hss, hse, ht, vbs, vbe, vss, vse, vt;
-#endif
/*
-* Predefined Video Modes
-*/
+ * Predefined Video Modes
+ */
-static struct fb_videomode cyberfb_predefined[] __initdata = {
+static struct {
+ const char *name;
+ struct fb_var_screeninfo var;
+} cyberfb_predefined[] __initdata = {
{ "640x480-8", { /* Default 8 BPP mode (cyber8) */
640, 480, 640, 480, 0, 0, 8, 0,
{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
static int Cyberfb_inverse = 0;
/*
-* Some default modes
-*/
+ * Some default modes
+ */
#define CYBER8_DEFMODE (0)
#define CYBER16_DEFMODE (1)
static struct fb_var_screeninfo cyberfb_default;
+static int cyberfb_usermode __initdata = 0;
/*
-* Interface used by the world
-*/
+ * Interface used by the world
+ */
void cyberfb_setup(char *options, int *ints);
u_long arg, int con, struct fb_info *info);
/*
-* Interface to the low level console driver
-*/
+ * Interface to the low level console driver
+ */
void cyberfb_init(void);
static int Cyberfb_switch(int con, struct fb_info *info);
static void Cyberfb_blank(int blank, struct fb_info *info);
/*
-* Text console acceleration
-*/
+ * Text console acceleration
+ */
#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_cyber8;
#endif
/*
-* Accelerated Functions used by the low level console driver
-*/
+ * Accelerated Functions used by the low level console driver
+ */
static void Cyber_WaitQueue(u_short fifo);
static void Cyber_WaitBlit(void);
u_short mode);
static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
u_short mode, u_short color);
+#if 0
static void Cyber_MoveCursor(u_short x, u_short y);
+#endif
/*
-* Hardware Specific Routines
-*/
+ * Hardware Specific Routines
+ */
static int Cyber_init(void);
static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
u_int *transp, struct fb_info *info);
static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
-static void Cyber_blank(int blank);
/*
-* Internal routines
-*/
+ * Internal routines
+ */
static void cyberfb_get_par(struct cyberfb_par *par);
static void cyberfb_set_par(struct cyberfb_par *par);
/* For cvision_core.c */
static unsigned short cv64_compute_clock(unsigned long);
-static int cv_has_4mb (volatile caddr_t);
+static int cv_has_4mb (volatile unsigned char *);
static void cv64_board_init (void);
static void cv64_load_video_mode (struct fb_var_screeninfo *);
/*
-* Initialization
-*
-* Set the default video mode for this chipset. If a video mode was
-* specified on the command line, it will override the default mode.
-*/
+ * Initialization
+ *
+ * Set the default video mode for this chipset. If a video mode was
+ * specified on the command line, it will override the default mode.
+ */
static int Cyber_init(void)
{
+ volatile unsigned char *regs = CyberRegs;
+ volatile unsigned long *CursorBase;
int i;
- volatile u_long *CursorBase;
DPRINTK("ENTER\n");
/* Init local cmap as greyscale levels */
}
/* Initialize the board and determine fbmem size */
- cv64_board_init ();
+ cv64_board_init();
#ifdef CYBERFBDEBUG
DPRINTK("Register state after initing board\n");
cv64_dump();
#endif
/* Clear framebuffer memory */
DPRINTK("Clear framebuffer memory\n");
- memset ((char *) cv64_fbmem, 0, cv64_size);
+ memset ((char *)CyberMem, 0, CyberSize);
/* Disable hardware cursor */
DPRINTK("Disable HW cursor\n");
- wb_64(S3_CRTC_ADR, S3_REG_LOCK2);
- wb_64(S3_CRTC_DATA, 0xa0);
- wb_64(S3_CRTC_ADR, S3_HGC_MODE);
- wb_64(S3_CRTC_DATA, 0x00);
- wb_64(S3_CRTC_ADR, S3_HWGC_DX);
- wb_64(S3_CRTC_DATA, 0x00);
- wb_64(S3_CRTC_ADR, S3_HWGC_DY);
- wb_64(S3_CRTC_DATA, 0x00);
-
- CyberSize = cv64_size;
+ wb_64(regs, S3_CRTC_ADR, S3_REG_LOCK2);
+ wb_64(regs, S3_CRTC_DATA, 0xa0);
+ wb_64(regs, S3_CRTC_ADR, S3_HGC_MODE);
+ wb_64(regs, S3_CRTC_DATA, 0x00);
+ wb_64(regs, S3_CRTC_ADR, S3_HWGC_DX);
+ wb_64(regs, S3_CRTC_DATA, 0x00);
+ wb_64(regs, S3_CRTC_ADR, S3_HWGC_DY);
+ wb_64(regs, S3_CRTC_DATA, 0x00);
/* Initialize hardware cursor */
DPRINTK("Init HW cursor\n");
/*
-* This function should fill in the `fix' structure based on the
-* values in the `par' structure.
-*/
+ * This function should fill in the `fix' structure based on the
+ * values in the `par' structure.
+ */
static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
struct cyberfb_par *par)
/*
-* Set a single color register. Return != 0 for invalid regno.
-*/
+ * Set a single color register. Return != 0 for invalid regno.
+ */
static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
+ volatile unsigned char *regs = CyberRegs;
+
/*DPRINTK("ENTER\n");*/
if (regno > 255) {
DPRINTK("EXIT - Register # > 255\n");
return (1);
}
- wb_64(0x3c8, (unsigned char) regno);
+ wb_64(regs, 0x3c8, (unsigned char) regno);
red >>= 10;
green >>= 10;
Cyber_colour_table [regno][1] = green;
Cyber_colour_table [regno][2] = blue;
- wb_64(0x3c9, red);
- wb_64(0x3c9, green);
- wb_64(0x3c9, blue);
+ wb_64(regs, 0x3c9, red);
+ wb_64(regs, 0x3c9, green);
+ wb_64(regs, 0x3c9, blue);
/*DPRINTK("EXIT\n");*/
return (0);
* 0 = restore fb cmap from local cmap
*/
-void Cyber_blank(int blank)
+void Cyberfb_blank(int blank, struct fb_info *info)
{
+ volatile unsigned char *regs = CyberRegs;
int i;
DPRINTK("ENTER\n");
#if 0
/* Blank by turning gfx off */
- gfx_on_off (1, cv64_regs);
+ gfx_on_off (1, regs);
#else
if (blank) {
for (i = 0; i < 256; i++) {
- wb_64(0x3c8, (unsigned char) i);
+ wb_64(regs, 0x3c8, (unsigned char) i);
/* ARB Pale red to detect this blanking method */
- wb_64(0x3c9, 48);
- wb_64(0x3c9, 0);
- wb_64(0x3c9, 0);
+ wb_64(regs, 0x3c9, 48);
+ wb_64(regs, 0x3c9, 0);
+ wb_64(regs, 0x3c9, 0);
}
} else {
for (i = 0; i < 256; i++) {
- wb_64(0x3c8, (unsigned char) i);
- wb_64(0x3c9, Cyber_colour_table[i][0]);
- wb_64(0x3c9, Cyber_colour_table[i][1]);
- wb_64(0x3c9, Cyber_colour_table[i][2]);
+ wb_64(regs, 0x3c8, (unsigned char) i);
+ wb_64(regs, 0x3c9, Cyber_colour_table[i][0]);
+ wb_64(regs, 0x3c9, Cyber_colour_table[i][1]);
+ wb_64(regs, 0x3c9, Cyber_colour_table[i][2]);
}
}
#endif
*/
static void Cyber_WaitQueue (u_short fifo)
{
- u_short status;
+ unsigned short status;
DPRINTK("ENTER\n");
do {
status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
- }
- while (status & fifo);
+ } while (status & fifo);
DPRINTK("EXIT\n");
}
*/
static void Cyber_WaitBlit (void)
{
- u_short status;
+ unsigned short status;
DPRINTK("ENTER\n");
do {
status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
- }
- while (status & S3_HDW_BUSY);
+ } while (status & S3_HDW_BUSY);
DPRINTK("EXIT\n");
}
u_short desty, u_short width, u_short height,
u_short mode)
{
+ volatile unsigned char *regs = CyberRegs;
u_short blitcmd = S3_BITBLT;
DPRINTK("ENTER\n");
Cyber_WaitQueue (0x8000);
- *((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000;
- *((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0060 | mode);
+ *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
+ *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode);
- *((u_short volatile *)(CyberRegs + S3_CUR_X)) = curx;
- *((u_short volatile *)(CyberRegs + S3_CUR_Y)) = cury;
+ *((u_short volatile *)(regs + S3_CUR_X)) = curx;
+ *((u_short volatile *)(regs + S3_CUR_Y)) = cury;
- *((u_short volatile *)(CyberRegs + S3_DESTX_DIASTP)) = destx;
- *((u_short volatile *)(CyberRegs + S3_DESTY_AXSTP)) = desty;
+ *((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx;
+ *((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty;
- *((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1;
- *((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width - 1;
+ *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
+ *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1;
- *((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
+ *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
DPRINTK("EXIT\n");
}
static void Cyber_RectFill (u_short x, u_short y, u_short width,
u_short height, u_short mode, u_short color)
{
+ volatile unsigned char *regs = CyberRegs;
u_short blitcmd = S3_FILLEDRECT;
DPRINTK("ENTER\n");
Cyber_WaitQueue (0x8000);
- *((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000;
- *((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0020 | mode);
+ *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
+ *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode);
- *((u_short volatile *)(CyberRegs + S3_MULT_MISC)) = 0xe000;
- *((u_short volatile *)(CyberRegs + S3_FRGD_COLOR)) = color;
+ *((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000;
+ *((u_short volatile *)(regs + S3_FRGD_COLOR)) = color;
- *((u_short volatile *)(CyberRegs + S3_CUR_X)) = x;
- *((u_short volatile *)(CyberRegs + S3_CUR_Y)) = y;
+ *((u_short volatile *)(regs + S3_CUR_X)) = x;
+ *((u_short volatile *)(regs + S3_CUR_Y)) = y;
- *((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1;
- *((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width - 1;
+ *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
+ *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1;
- *((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
+ *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
DPRINTK("EXIT\n");
}
+
+#if 0
/**************************************************************
* Move cursor to x, y
*/
static void Cyber_MoveCursor (u_short x, u_short y)
{
+ volatile unsigned char *regs = CyberRegs;
DPRINTK("ENTER\n");
- *(CyberRegs + S3_CRTC_ADR) = 0x39;
- *(CyberRegs + S3_CRTC_DATA) = 0xa0;
-
- *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGX_H;
- *(CyberRegs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
- *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGX_L;
- *(CyberRegs + S3_CRTC_DATA) = (char)(x & 0x00ff);
-
- *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGY_H;
- *(CyberRegs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
- *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGY_L;
- *(CyberRegs + S3_CRTC_DATA) = (char)(y & 0x00ff);
+ *(regs + S3_CRTC_ADR) = 0x39;
+ *(regs + S3_CRTC_DATA) = 0xa0;
+
+ *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_H;
+ *(regs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
+ *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_L;
+ *(regs + S3_CRTC_DATA) = (char)(x & 0x00ff);
+
+ *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_H;
+ *(regs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
+ *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_L;
+ *(regs + S3_CRTC_DATA) = (char)(y & 0x00ff);
DPRINTK("EXIT\n");
}
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch Cyber_switch = {
- Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var,
- Cyber_getcolreg, Cyber_setcolreg, Cyber_blank
-};
+#endif
/* -------------------- Generic routines ---------------------------------- */
if (current_par_valid) {
*par = current_par;
} else {
- fbhw->decode_var(&cyberfb_default, par);
+ Cyber_decode_var(&cyberfb_default, par);
}
DPRINTK("EXIT\n");
}
struct cyberfb_par par;
DPRINTK("ENTER\n");
- if ((err = fbhw->decode_var(var, &par))) {
+ if ((err = Cyber_decode_var(var, &par))) {
DPRINTK("EXIT - decode_var failed\n");
return(err);
}
activate = var->activate;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
cyberfb_set_par(&par);
- fbhw->encode_var(var, &par);
+ Cyber_encode_var(var, &par);
var->activate = activate;
cyber_set_video(var);
}
if (fb_display[con].cmap.len) {
DPRINTK("Use console cmap\n");
- fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info);
+ fb_set_cmap(&fb_display[con].cmap, 1, Cyber_setcolreg, info);
} else {
DPRINTK("Use default cmap\n");
fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- 1, fbhw->setcolreg, info);
+ 1, Cyber_setcolreg, info);
}
DPRINTK("EXIT\n");
}
if (con == -1) {
cyberfb_get_par(&par);
} else {
- error = fbhw->decode_var(&fb_display[con].var, &par);
+ error = Cyber_decode_var(&fb_display[con].var, &par);
}
DPRINTK("EXIT\n");
- return(error ? error : fbhw->encode_fix(fix, &par));
+ return(error ? error : Cyber_encode_fix(fix, &par));
}
DPRINTK("ENTER\n");
if (con == -1) {
cyberfb_get_par(&par);
- error = fbhw->encode_var(var, &par);
+ error = Cyber_encode_var(var, &par);
disp.var = *var; /* ++Andre: don't know if this is the right place */
} else {
*var = fb_display[con].var;
cyberfb_get_fix(&fix, con, info);
if (con == -1)
con = 0;
- display->screen_base = phys_to_virt ((unsigned long) fix.smem_start);
+ display->screen_base = (unsigned char *)CyberMem;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
DPRINTK("ENTER\n");
if (con == currcon) { /* current console? */
DPRINTK("EXIT - console is current console\n");
- return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info));
+ return(fb_get_cmap(cmap, kspc, Cyber_getcolreg, info));
} else if (fb_display[con].cmap.len) { /* non default colormap? */
DPRINTK("Use console cmap\n");
fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
}
if (con == currcon) { /* current console? */
DPRINTK("EXIT - Current console\n");
- return(fb_set_cmap(cmap, kspc, fbhw->setcolreg, info));
+ return(fb_set_cmap(cmap, kspc, Cyber_setcolreg, info));
} else {
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
}
static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
- return(-EINVAL);
+ return -EINVAL;
}
static int cyberfb_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg, int con, struct fb_info *info)
{
- return(-EINVAL);
+ return -EINVAL;
}
};
-__initfunc(void cyberfb_setup(char *options, int *ints))
+void __init cyberfb_setup(char *options, int *ints)
{
char *this_opt;
DPRINTK("ENTER\n");
strcpy(fb_info.fontname, this_opt+5);
} else if (!strcmp (this_opt, "cyber8")) {
cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+ cyberfb_usermode = 1;
} else if (!strcmp (this_opt, "cyber16")) {
cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var;
+ cyberfb_usermode = 1;
} else get_video_mode(this_opt);
}
* Initialization
*/
-__initfunc(void cyberfb_init(void))
+void __init cyberfb_init(void)
{
struct cyberfb_par par;
unsigned long board_addr;
DPRINTK("board_addr=%08lx\n", board_addr);
DPRINTK("board_size=%08lx\n", board_size);
- cv64_mem = ioremap(board_addr, board_size);
- cv64_regs = (volatile char *)(cv64_mem + 0x02000000);
- cv64_fbmem = cv64_mem + 0x01400000;
- DPRINTK("cv64_mem=%08lx cv64_regs=%08lx cv64_fbmem=%08lx\n",
- cv64_mem, (long unsigned int)cv64_regs, cv64_fbmem);
+ CyberBase = ioremap(board_addr, board_size);
+ CyberRegs = CyberBase + 0x02000000;
+ CyberMem = CyberBase + 0x01400000;
+ DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
+ CyberBase, (long unsigned int)CyberRegs, CyberMem);
- CyberMem = cv64_fbmem;
- CyberRegs = cv64_regs;
CyberMem_phys = board_addr + 0x01400000;
CyberRegs_phys = CyberMem_phys + 0x00c00000;
DPRINTK("CyberMem=%08lx CyberRegs=%08lx\n", CyberMem,
cv64_dump();
#endif
- fbhw = &Cyber_switch;
-
strcpy(fb_info.modename, cyberfb_name);
fb_info.changevar = NULL;
fb_info.node = -1;
fb_info.updatevar = &Cyberfb_updatevar;
fb_info.blank = &Cyberfb_blank;
- fbhw->init();
- fbhw->decode_var(&cyberfb_default, &par);
- fbhw->encode_var(&cyberfb_default, &par);
+ Cyber_init();
+ /* ++Andre: set cyberfb default mode */
+ if (!cyberfb_usermode) {
+ cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+ DPRINTK("Use default cyber8 mode\n");
+ }
+ Cyber_decode_var(&cyberfb_default, &par);
+ Cyber_encode_var(&cyberfb_default, &par);
do_fb_set_var(&cyberfb_default, 1);
cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
DPRINTK("ENTER\n");
/* Do we have to save the colormap? */
if (fb_display[currcon].cmap.len) {
- fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg,
+ fb_get_cmap(&fb_display[currcon].cmap, 1, Cyber_getcolreg,
info);
}
}
-/*
- * Blank the display.
- */
-
-static void Cyberfb_blank(int blank, struct fb_info *info)
-{
- DPRINTK("Enter\n");
- fbhw->blank(blank);
- DPRINTK("Exit\n");
-}
-
-
/*
* Get a Video Mode
*/
-__initfunc(static int get_video_mode(const char *name))
+static int __init get_video_mode(const char *name)
{
int i;
for (i = 0; i < NUM_TOTAL_MODES; i++) {
if (!strcmp(name, cyberfb_predefined[i].name)) {
cyberfb_default = cyberfb_predefined[i].var;
+ cyberfb_usermode = 1;
DPRINTK("EXIT - Matched predefined mode\n");
return(i);
}
}
- /* ++Andre: set cyberfb default mode */
- cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
- DPRINTK("EXIT - Use default cyber8 mode\n");
return(0);
}
};
/* -------------------- Hardware specific routines ------------------------- */
-#if 0
-/* ARB Generates 100 usec delay */
-inline void __cv_delay (unsigned long usecs)
-{
- int k;
-
- for (k = 0; k < 1000; k++) {
- asm volatile ("nop");
- }
-}
-#endif
-
-/* Wait while Graphics Engine is busy */
-inline void GfxBusyWait (volatile caddr_t board)
-{
- int test;
- DPRINTK("ENTER\n");
-
- do {
- test = vgar16 (board, ECR_GP_STAT);
- asm volatile ("nop");
- } while (test & (1 << 9));
- DPRINTK("EXIT\n");
-}
-
-/* Wait for any of the 8 Trio32 FIFOs to be free */
-inline void GfxFifoWait (volatile caddr_t board)
-{
- int test;
- DPRINTK("ENTER\n");
-
- do {
- test = vgar16 (board, ECR_GP_STAT);
- } while (test & 0x0f);
- DPRINTK("EXIT\n");
-}
/* Read Attribute Controller Register=idx */
-inline unsigned char RAttr (volatile caddr_t board, short idx)
+inline unsigned char RAttr (volatile unsigned char *regs, short idx)
{
- vgaw (board, ACT_ADDRESS_W, idx);
+ wb_64 (regs, ACT_ADDRESS_W, idx);
+ mb();
udelay(100);
- /* __cv_delay (0); */
- return (vgar (board, ACT_ADDRESS_R));
+ return (rb_64(regs, ACT_ADDRESS_R));
}
/* Read Sequencer Register=idx */
-inline unsigned char RSeq (volatile caddr_t board, short idx)
+inline unsigned char RSeq (volatile unsigned char *regs, short idx)
{
- vgaw (board, SEQ_ADDRESS, idx);
- return (vgar (board, SEQ_ADDRESS_R));
+ wb_64 (regs, SEQ_ADDRESS, idx);
+ mb();
+ return (rb_64(regs, SEQ_ADDRESS_R));
}
/* Read CRT Controller Register=idx */
-inline unsigned char RCrt (volatile caddr_t board, short idx)
+inline unsigned char RCrt (volatile unsigned char *regs, short idx)
{
- vgaw (board, CRT_ADDRESS, idx);
- return (vgar (board, CRT_ADDRESS_R));
+ wb_64 (regs, CRT_ADDRESS, idx);
+ mb();
+ return (rb_64(regs, CRT_ADDRESS_R));
}
/* Read Graphics Controller Register=idx */
-inline unsigned char RGfx (volatile caddr_t board, short idx)
+inline unsigned char RGfx (volatile unsigned char *regs, short idx)
{
- vgaw (board, GCT_ADDRESS, idx);
- return (vgar (board, GCT_ADDRESS_R));
+ wb_64 (regs, GCT_ADDRESS, idx);
+ mb();
+ return (rb_64(regs, GCT_ADDRESS_R));
}
/*
*/
inline void cv64_write_port (unsigned short bits,
- volatile unsigned char *board)
+ volatile unsigned char *base)
{
volatile unsigned char *addr;
static unsigned char cvportbits = 0; /* Mirror port bits here */
DPRINTK("ENTER\n");
- addr = board + 0x40001;
+ addr = base + 0x40001;
if (bits & 0x8000) {
cvportbits |= bits & 0xff; /* Set bits */
DPRINTK("Set bits: %04x\n", bits);
cvportbits &= bits; /* Clear bits */
DPRINTK("Clear bits: %04x\n", bits);
}
-
+
*addr = cvportbits;
DPRINTK("EXIT\n");
}
/* Control screen display */
/* toggle: 0 = on, 1 = off */
/* board = registerbase */
-inline void gfx_on_off (int toggle, volatile unsigned char *board)
+inline void gfx_on_off(int toggle, volatile unsigned char *regs)
{
int r;
DPRINTK("ENTER\n");
toggle = toggle << 5;
DPRINTK("Turn display %s\n", (toggle ? "off" : "on"));
- r = (int) RSeq ((volatile caddr_t) board, SEQ_ID_CLOCKING_MODE);
+ r = (int) RSeq(regs, SEQ_ID_CLOCKING_MODE);
r &= 0xdf; /* Set bit 5 to 0 */
- WSeq (board, SEQ_ID_CLOCKING_MODE, r | toggle);
+ WSeq (regs, SEQ_ID_CLOCKING_MODE, r | toggle);
DPRINTK("EXIT\n");
}
return (erg);
}
-static int cv_has_4mb (volatile caddr_t fb)
+static int cv_has_4mb (volatile unsigned char *fb)
{
volatile unsigned long *tr, *tw;
DPRINTK("ENTER\n");
-
+
/* write patterns in memory and test if they can be read */
tw = (volatile unsigned long *) fb;
tr = (volatile unsigned long *) (fb + 0x02000000);
DPRINTK("EXIT - <4MB\n");
return (0);
}
-
+
/* upper memory region */
tw = (volatile unsigned long *) (fb + 0x00200000);
tr = (volatile unsigned long *) (fb + 0x02200000);
-
+
*tw = 0x87654321;
-
+
if (*tr != 0x87654321) {
DPRINTK("EXIT - <4MB\n");
return (0);
}
-
+
*tw = 0xAAAAAAAA;
-
+
if (*tr != 0xAAAAAAAA) {
DPRINTK("EXIT - <4MB\n");
return (0);
}
-
+
*tw = 0x55555555;
-
+
if (*tr != 0x55555555) {
DPRINTK("EXIT - <4MB\n");
return (0);
}
-
+
DPRINTK("EXIT\n");
return (1);
}
static void cv64_board_init (void)
{
+ volatile unsigned char *regs = CyberRegs;
int i;
- unsigned char test;
unsigned int clockpar;
+ unsigned char test;
DPRINTK("ENTER\n");
*/
/* Reset board */
for (i = 0; i < 6; i++) {
- cv64_write_port (0xff, (volatile unsigned char *) cv64_mem);
+ cv64_write_port (0xff, CyberBase);
}
/* Return to operational mode */
- cv64_write_port (0x8004, (volatile unsigned char *) cv64_mem);
+ cv64_write_port (0x8004, CyberBase);
- /*
- * Generic (?) S3 chip wakeup
- */
- /* Disable I/O & memory decoders, video in setup mode */
- vgaw (cv64_regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
- /* Video responds to cmds, addrs & data */
- vgaw (cv64_regs, SREG_OPTION_SELECT, 0x1);
- /* Enable I/O & memory decoders, video in operational mode */
- vgaw (cv64_regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
- /* VGA color emulation, enable cpu access to display mem */
- vgaw (cv64_regs, GREG_MISC_OUTPUT_W, 0x03);
- /* Unlock S3 VGA regs */
- WCrt (cv64_regs, CRT_ID_REGISTER_LOCK_1, 0x48);
- /* Unlock system control & extension registers */
- WCrt (cv64_regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
+ /*
+ * Generic (?) S3 chip wakeup
+ */
+ /* Disable I/O & memory decoders, video in setup mode */
+ wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
+ /* Video responds to cmds, addrs & data */
+ wb_64 (regs, SREG_OPTION_SELECT, 0x1);
+ /* Enable I/O & memory decoders, video in operational mode */
+ wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
+ /* VGA color emulation, enable cpu access to display mem */
+ wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03);
+ /* Unlock S3 VGA regs */
+ WCrt (regs, CRT_ID_REGISTER_LOCK_1, 0x48);
+ /* Unlock system control & extension registers */
+ WCrt (regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
/* GRF - Enable interrupts */
- /* Enable enhanced regs access, Ready cntl 0 wait states */
- test = RCrt (cv64_regs, CRT_ID_SYSTEM_CONFIG);
- test = test | 0x01; /* enable enhaced register access */
- test = test & 0xEF; /* clear bit 4, 0 wait state */
- WCrt (cv64_regs, CRT_ID_SYSTEM_CONFIG, test);
- /*
- * bit 0=1: Enable enhaced mode functions
- * bit 2=0: Enhanced mode 8+ bits/pixel
- * bit 4=1: Enable linear addressing
- * bit 5=1: Enable MMIO
- */
- vgaw (cv64_regs, ECR_ADV_FUNC_CNTL, 0x31);
- /*
- * bit 0=1: Color emulation
- * bit 1=1: Enable CPU access to display memory
- * bit 5=1: Select high 64K memory page
- */
+ /* Enable enhanced regs access, Ready cntl 0 wait states */
+ test = RCrt (regs, CRT_ID_SYSTEM_CONFIG);
+ test = test | 0x01; /* enable enhanced register access */
+ test = test & 0xEF; /* clear bit 4, 0 wait state */
+ WCrt (regs, CRT_ID_SYSTEM_CONFIG, test);
+ /*
+ * bit 0=1: Enable enhaced mode functions
+ * bit 2=0: Enhanced mode 8+ bits/pixel
+ * bit 4=1: Enable linear addressing
+ * bit 5=1: Enable MMIO
+ */
+ wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31);
+ /*
+ * bit 0=1: Color emulation
+ * bit 1=1: Enable CPU access to display memory
+ * bit 5=1: Select high 64K memory page
+ */
/* GRF - 0xE3 */
- vgaw (cv64_regs, GREG_MISC_OUTPUT_W, 0x23);
-
- /* Cpu base addr */
- WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
-
- /* Reset. This does nothing on Trio, but standard VGA practice */
- /* WSeq (cv64_regs, SEQ_ID_RESET, 0x03); */
- /* Character clocks 8 dots wide */
- WSeq (cv64_regs, SEQ_ID_CLOCKING_MODE, 0x01);
- /* Enable cpu write to all color planes */
- WSeq (cv64_regs, SEQ_ID_MAP_MASK, 0x0F);
- /* Font table in 1st 8k of plane 2, font A=B disables swtich */
- WSeq (cv64_regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
- /* Allow mem access to 256kb */
- WSeq (cv64_regs, SEQ_ID_MEMORY_MODE, 0x2);
- /* Unlock S3 extensions to VGA Sequencer regs */
- WSeq (cv64_regs, SEQ_ID_UNLOCK_EXT, 0x6);
-
- /* Enable 4MB fast page mode */
- test = RSeq (cv64_regs, SEQ_ID_BUS_REQ_CNTL);
- test = test | 1 << 6;
- WSeq (cv64_regs, SEQ_ID_BUS_REQ_CNTL, test);
-
- /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
- WSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
-
- /* Clear immediate clock load bit */
- test = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2);
- test = test & 0xDF;
- /* If > 55MHz, enable 2 cycle memory write */
- if (cv64_memclk >= 55000000) {
- test |= 0x80;
- }
- WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, test);
-
- /* Set MCLK value */
- clockpar = cv64_compute_clock (cv64_memclk);
- test = (clockpar & 0xFF00) >> 8;
- WSeq (cv64_regs, SEQ_ID_MCLK_HI, test);
- test = clockpar & 0xFF;
- WSeq (cv64_regs, SEQ_ID_MCLK_LO, test);
-
- /* Chip rev specific: Not in my Trio manual!!! */
- if (RCrt (cv64_regs, CRT_ID_REVISION) == 0x10)
- WSeq (cv64_regs, SEQ_ID_MORE_MAGIC, test);
-
- /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
-
- /* Set DCLK value */
- WSeq (cv64_regs, SEQ_ID_DCLK_HI, 0x13);
- WSeq (cv64_regs, SEQ_ID_DCLK_LO, 0x41);
-
- /* Load DCLK (and MCLK?) immediately */
- test = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2);
- test = test | 0x22;
- WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, test);
-
- /* Enable loading of DCLK */
- test = vgar (cv64_regs, GREG_MISC_OUTPUT_R);
- test = test | 0x0C;
- vgaw (cv64_regs, GREG_MISC_OUTPUT_W, test);
-
- /* Turn off immediate xCLK load */
- WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
-
- /* Horizontal character clock counts */
- /* 8 LSB of 9 bits = total line - 5 */
- WCrt (cv64_regs, CRT_ID_HOR_TOTAL, 0x5F);
- /* Active display line */
- WCrt (cv64_regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
- /* Blank assertion start */
- WCrt (cv64_regs, CRT_ID_START_HOR_BLANK, 0x50);
- /* Blank assertion end */
- WCrt (cv64_regs, CRT_ID_END_HOR_BLANK, 0x82);
- /* HSYNC assertion start */
- WCrt (cv64_regs, CRT_ID_START_HOR_RETR, 0x54);
- /* HSYNC assertion end */
- WCrt (cv64_regs, CRT_ID_END_HOR_RETR, 0x80);
- WCrt (cv64_regs, CRT_ID_VER_TOTAL, 0xBF);
- WCrt (cv64_regs, CRT_ID_OVERFLOW, 0x1F);
- WCrt (cv64_regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
- WCrt (cv64_regs, CRT_ID_MAX_SCAN_LINE, 0x40);
- WCrt (cv64_regs, CRT_ID_CURSOR_START, 0x00);
- WCrt (cv64_regs, CRT_ID_CURSOR_END, 0x00);
- WCrt (cv64_regs, CRT_ID_START_ADDR_HIGH, 0x00);
- WCrt (cv64_regs, CRT_ID_START_ADDR_LOW, 0x00);
- WCrt (cv64_regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
- WCrt (cv64_regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
- WCrt (cv64_regs, CRT_ID_START_VER_RETR, 0x9C);
- WCrt (cv64_regs, CRT_ID_END_VER_RETR, 0x0E);
- WCrt (cv64_regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
- WCrt (cv64_regs, CRT_ID_SCREEN_OFFSET, 0x50);
- WCrt (cv64_regs, CRT_ID_UNDERLINE_LOC, 0x00);
- WCrt (cv64_regs, CRT_ID_START_VER_BLANK, 0x96);
- WCrt (cv64_regs, CRT_ID_END_VER_BLANK, 0xB9);
- WCrt (cv64_regs, CRT_ID_MODE_CONTROL, 0xE3);
- WCrt (cv64_regs, CRT_ID_LINE_COMPARE, 0xFF);
- WCrt (cv64_regs, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
- WCrt (cv64_regs, CRT_ID_MISC_1, 0x35);
- WCrt (cv64_regs, CRT_ID_DISPLAY_FIFO, 0x5A);
- WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
- WCrt (cv64_regs, CRT_ID_LAW_POS_LO, 0x40);
- WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
-
- WGfx (cv64_regs, GCT_ID_SET_RESET, 0x0);
- WGfx (cv64_regs, GCT_ID_ENABLE_SET_RESET, 0x0);
- WGfx (cv64_regs, GCT_ID_COLOR_COMPARE, 0x0);
- WGfx (cv64_regs, GCT_ID_DATA_ROTATE, 0x0);
- WGfx (cv64_regs, GCT_ID_READ_MAP_SELECT, 0x0);
- WGfx (cv64_regs, GCT_ID_GRAPHICS_MODE, 0x40);
- WGfx (cv64_regs, GCT_ID_MISC, 0x01);
- WGfx (cv64_regs, GCT_ID_COLOR_XCARE, 0x0F);
- WGfx (cv64_regs, GCT_ID_BITMASK, 0xFF);
-
- /* Colors for text mode */
- for (i = 0; i < 0xf; i++)
- WAttr (cv64_regs, i, i);
-
- WAttr (cv64_regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
- WAttr (cv64_regs, ACT_ID_OVERSCAN_COLOR, 0x01);
- WAttr (cv64_regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
- WAttr (cv64_regs, ACT_ID_HOR_PEL_PANNING, 0x0);
- WAttr (cv64_regs, ACT_ID_COLOR_SELECT, 0x0);
-
- vgaw (cv64_regs, VDAC_MASK, 0xFF);
-
- *((unsigned long *) (cv64_regs + ECR_FRGD_COLOR)) = 0xFF;
- *((unsigned long *) (cv64_regs + ECR_BKGD_COLOR)) = 0;
-
- /* Colors initially set to grayscale */
-
- vgaw (cv64_regs, VDAC_ADDRESS_W, 0);
- for (i = 255; i >= 0; i--) {
- vgaw (cv64_regs, VDAC_DATA, i);
- vgaw (cv64_regs, VDAC_DATA, i);
- vgaw (cv64_regs, VDAC_DATA, i);
- }
+ wb_64 (regs, GREG_MISC_OUTPUT_W, 0x23);
+
+ /* Cpu base addr */
+ WCrt (regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
+
+ /* Reset. This does nothing on Trio, but standard VGA practice */
+ /* WSeq (CyberRegs, SEQ_ID_RESET, 0x03); */
+ /* Character clocks 8 dots wide */
+ WSeq (regs, SEQ_ID_CLOCKING_MODE, 0x01);
+ /* Enable cpu write to all color planes */
+ WSeq (regs, SEQ_ID_MAP_MASK, 0x0F);
+ /* Font table in 1st 8k of plane 2, font A=B disables swtich */
+ WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
+ /* Allow mem access to 256kb */
+ WSeq (regs, SEQ_ID_MEMORY_MODE, 0x2);
+ /* Unlock S3 extensions to VGA Sequencer regs */
+ WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6);
+
+ /* Enable 4MB fast page mode */
+ test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
+ test = test | 1 << 6;
+ WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
+
+ /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
+ WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
+
+ /* Clear immediate clock load bit */
+ test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
+ test = test & 0xDF;
+ /* If > 55MHz, enable 2 cycle memory write */
+ if (cv64_memclk >= 55000000) {
+ test |= 0x80;
+ }
+ WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
+
+ /* Set MCLK value */
+ clockpar = cv64_compute_clock (cv64_memclk);
+ test = (clockpar & 0xFF00) >> 8;
+ WSeq (regs, SEQ_ID_MCLK_HI, test);
+ test = clockpar & 0xFF;
+ WSeq (regs, SEQ_ID_MCLK_LO, test);
+
+ /* Chip rev specific: Not in my Trio manual!!! */
+ if (RCrt (regs, CRT_ID_REVISION) == 0x10)
+ WSeq (regs, SEQ_ID_MORE_MAGIC, test);
+
+ /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
+
+ /* Set DCLK value */
+ WSeq (regs, SEQ_ID_DCLK_HI, 0x13);
+ WSeq (regs, SEQ_ID_DCLK_LO, 0x41);
+
+ /* Load DCLK (and MCLK?) immediately */
+ test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
+ test = test | 0x22;
+ WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
+
+ /* Enable loading of DCLK */
+ test = rb_64(regs, GREG_MISC_OUTPUT_R);
+ test = test | 0x0C;
+ wb_64 (regs, GREG_MISC_OUTPUT_W, test);
+
+ /* Turn off immediate xCLK load */
+ WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
+
+ /* Horizontal character clock counts */
+ /* 8 LSB of 9 bits = total line - 5 */
+ WCrt (regs, CRT_ID_HOR_TOTAL, 0x5F);
+ /* Active display line */
+ WCrt (regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
+ /* Blank assertion start */
+ WCrt (regs, CRT_ID_START_HOR_BLANK, 0x50);
+ /* Blank assertion end */
+ WCrt (regs, CRT_ID_END_HOR_BLANK, 0x82);
+ /* HSYNC assertion start */
+ WCrt (regs, CRT_ID_START_HOR_RETR, 0x54);
+ /* HSYNC assertion end */
+ WCrt (regs, CRT_ID_END_HOR_RETR, 0x80);
+ WCrt (regs, CRT_ID_VER_TOTAL, 0xBF);
+ WCrt (regs, CRT_ID_OVERFLOW, 0x1F);
+ WCrt (regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
+ WCrt (regs, CRT_ID_MAX_SCAN_LINE, 0x40);
+ WCrt (regs, CRT_ID_CURSOR_START, 0x00);
+ WCrt (regs, CRT_ID_CURSOR_END, 0x00);
+ WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
+ WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
+ WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
+ WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
+ WCrt (regs, CRT_ID_START_VER_RETR, 0x9C);
+ WCrt (regs, CRT_ID_END_VER_RETR, 0x0E);
+ WCrt (regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
+ WCrt (regs, CRT_ID_SCREEN_OFFSET, 0x50);
+ WCrt (regs, CRT_ID_UNDERLINE_LOC, 0x00);
+ WCrt (regs, CRT_ID_START_VER_BLANK, 0x96);
+ WCrt (regs, CRT_ID_END_VER_BLANK, 0xB9);
+ WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
+ WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
+ WCrt (regs, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
+ WCrt (regs, CRT_ID_MISC_1, 0x35);
+ WCrt (regs, CRT_ID_DISPLAY_FIFO, 0x5A);
+ WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
+ WCrt (regs, CRT_ID_LAW_POS_LO, 0x40);
+ WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
+
+ WGfx (regs, GCT_ID_SET_RESET, 0x0);
+ WGfx (regs, GCT_ID_ENABLE_SET_RESET, 0x0);
+ WGfx (regs, GCT_ID_COLOR_COMPARE, 0x0);
+ WGfx (regs, GCT_ID_DATA_ROTATE, 0x0);
+ WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x0);
+ WGfx (regs, GCT_ID_GRAPHICS_MODE, 0x40);
+ WGfx (regs, GCT_ID_MISC, 0x01);
+ WGfx (regs, GCT_ID_COLOR_XCARE, 0x0F);
+ WGfx (regs, GCT_ID_BITMASK, 0xFF);
+
+ /* Colors for text mode */
+ for (i = 0; i < 0xf; i++)
+ WAttr (regs, i, i);
+
+ WAttr (regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
+ WAttr (regs, ACT_ID_OVERSCAN_COLOR, 0x01);
+ WAttr (regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
+ WAttr (regs, ACT_ID_HOR_PEL_PANNING, 0x0);
+ WAttr (regs, ACT_ID_COLOR_SELECT, 0x0);
+
+ wb_64 (regs, VDAC_MASK, 0xFF);
+
+ *((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF;
+ *((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0;
+
+ /* Colors initially set to grayscale */
+
+ wb_64 (regs, VDAC_ADDRESS_W, 0);
+ for (i = 255; i >= 0; i--) {
+ wb_64(regs, VDAC_DATA, i);
+ wb_64(regs, VDAC_DATA, i);
+ wb_64(regs, VDAC_DATA, i);
+ }
- /* GFx hardware cursor off */
- WCrt (cv64_regs, CRT_ID_HWGC_MODE, 0x00);
+ /* GFx hardware cursor off */
+ WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
- /* Set first to 4MB, so test will work */
- WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x13);
- /* Find "correct" size of fbmem of Z3 board */
- if (cv_has_4mb ((volatile caddr_t) cv64_fbmem)) {
- cv64_size = 1024 * 1024 * 4;
- WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x13);
- DPRINTK("4MB board\n");
- } else {
- cv64_size = 1024 * 1024 * 2;
- WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x12);
- DPRINTK("2MB board\n");
- }
-
- /* Initialize graphics engine */
- Cyber_WaitBlit();
- /* GfxBusyWait (cv64_regs); */
- vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x27);
- vgaw16 (cv64_regs, ECR_BKGD_MIX, 0x07);
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x1000);
- udelay(200);
- /* __cv_delay (200000); */
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x2000);
- Cyber_WaitBlit();
- /* GfxBusyWait (cv64_regs); */
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x3FFF);
- Cyber_WaitBlit();
- /* GfxBusyWait (cv64_regs); */
- udelay(200);
- /* __cv_delay (200000); */
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x4FFF);
- Cyber_WaitBlit();
- /* GfxBusyWait (cv64_regs); */
- vgaw16 (cv64_regs, ECR_BITPLANE_WRITE_MASK, ~0);
- Cyber_WaitBlit();
- /* GfxBusyWait (cv64_regs); */
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xE000);
- vgaw16 (cv64_regs, ECR_CURRENT_Y_POS2, 0x00);
- vgaw16 (cv64_regs, ECR_CURRENT_X_POS2, 0x00);
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000);
- vgaw16 (cv64_regs, ECR_DEST_Y__AX_STEP, 0x00);
- vgaw16 (cv64_regs, ECR_DEST_Y2__AX_STEP2, 0x00);
- vgaw16 (cv64_regs, ECR_DEST_X__DIA_STEP, 0x00);
- vgaw16 (cv64_regs, ECR_DEST_X2__DIA_STEP2, 0x00);
- vgaw16 (cv64_regs, ECR_SHORT_STROKE, 0x00);
- vgaw16 (cv64_regs, ECR_DRAW_CMD, 0x01);
-
- Cyber_WaitBlit();
- /* GfxBusyWait (cv64_regs); */
-
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x4FFF);
- vgaw16 (cv64_regs, ECR_BKGD_COLOR, 0x01);
- vgaw16 (cv64_regs, ECR_FRGD_COLOR, 0x00);
-
-
- /* Enable video display (set bit 5) */
+ /* Set first to 4MB, so test will work */
+ WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
+ /* Find "correct" size of fbmem of Z3 board */
+ if (cv_has_4mb (CyberMem)) {
+ CyberSize = 1024 * 1024 * 4;
+ WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
+ DPRINTK("4MB board\n");
+ } else {
+ CyberSize = 1024 * 1024 * 2;
+ WCrt (regs, CRT_ID_LAW_CNTL, 0x12);
+ DPRINTK("2MB board\n");
+ }
+
+ /* Initialize graphics engine */
+ Cyber_WaitBlit();
+ vgaw16 (regs, ECR_FRGD_MIX, 0x27);
+ vgaw16 (regs, ECR_BKGD_MIX, 0x07);
+ vgaw16 (regs, ECR_READ_REG_DATA, 0x1000);
+ udelay(200);
+ vgaw16 (regs, ECR_READ_REG_DATA, 0x2000);
+ Cyber_WaitBlit();
+ vgaw16 (regs, ECR_READ_REG_DATA, 0x3FFF);
+ Cyber_WaitBlit();
+ udelay(200);
+ vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
+ Cyber_WaitBlit();
+ vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, ~0);
+ Cyber_WaitBlit();
+ vgaw16 (regs, ECR_READ_REG_DATA, 0xE000);
+ vgaw16 (regs, ECR_CURRENT_Y_POS2, 0x00);
+ vgaw16 (regs, ECR_CURRENT_X_POS2, 0x00);
+ vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+ vgaw16 (regs, ECR_DEST_Y__AX_STEP, 0x00);
+ vgaw16 (regs, ECR_DEST_Y2__AX_STEP2, 0x00);
+ vgaw16 (regs, ECR_DEST_X__DIA_STEP, 0x00);
+ vgaw16 (regs, ECR_DEST_X2__DIA_STEP2, 0x00);
+ vgaw16 (regs, ECR_SHORT_STROKE, 0x00);
+ vgaw16 (regs, ECR_DRAW_CMD, 0x01);
+
+ Cyber_WaitBlit();
+
+ vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
+ vgaw16 (regs, ECR_BKGD_COLOR, 0x01);
+ vgaw16 (regs, ECR_FRGD_COLOR, 0x00);
+
+
+ /* Enable video display (set bit 5) */
/* ARB - Would also seem to write to AR13.
* May want to use parts of WAttr to set JUST bit 5
*/
- WAttr (cv64_regs, 0x33, 0);
+ WAttr (regs, 0x33, 0);
/* GRF - function code ended here */
- /* Turn gfx on again */
- gfx_on_off (0, cv64_regs);
-
- /* Pass-through */
- cvscreen (0, (volatile unsigned char *) cv64_mem);
+ /* Turn gfx on again */
+ gfx_on_off (0, regs);
- DPRINTK("EXIT\n");
+ /* Pass-through */
+ cvscreen (0, CyberBase);
+
+ DPRINTK("EXIT\n");
}
static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode)
{
+ volatile unsigned char *regs = CyberRegs;
int fx, fy;
unsigned short mnr;
unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT;
/* GRF - Disable interrupts */
- gfx_on_off (1, cv64_regs);
+ gfx_on_off (1, regs);
switch (video_mode->bits_per_pixel) {
case 15:
VT = yres + vfront + vsync + vback - 2;
}
- vgaw (cv64_regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
+ wb_64 (regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
if (TEXT)
HDE = ((video_mode->xres + fx - 1) / fx) - 1;
VDE = video_mode->yres - 1;
- WCrt (cv64_regs, CRT_ID_HWGC_MODE, 0x00);
- WCrt (cv64_regs, CRT_ID_EXT_DAC_CNTL, 0x00);
+ WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
+ WCrt (regs, CRT_ID_EXT_DAC_CNTL, 0x00);
- WSeq (cv64_regs, SEQ_ID_MEMORY_MODE,
+ WSeq (regs, SEQ_ID_MEMORY_MODE,
(TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e);
- WGfx (cv64_regs, GCT_ID_READ_MAP_SELECT, 0x00);
- WSeq (cv64_regs, SEQ_ID_MAP_MASK,
+ WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x00);
+ WSeq (regs, SEQ_ID_MAP_MASK,
(video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF);
- WSeq (cv64_regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
+ WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
/* cv64_compute_clock accepts arguments in Hz */
/* pixclock is in ps ... convert to Hz */
#endif
mnr = cv64_compute_clock (freq);
- WSeq (cv64_regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
- WSeq (cv64_regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
+ WSeq (regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
+ WSeq (regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
/* Load display parameters into board */
- WCrt (cv64_regs, CRT_ID_EXT_HOR_OVF,
+ WCrt (regs, CRT_ID_EXT_HOR_OVF,
((HT & 0x100) ? 0x01 : 0x00) |
((HDE & 0x100) ? 0x02 : 0x00) |
((HBS & 0x100) ? 0x04 : 0x00) |
(((HT-5) & 0x100) ? 0x40 : 0x00)
);
- WCrt (cv64_regs, CRT_ID_EXT_VER_OVF,
+ WCrt (regs, CRT_ID_EXT_VER_OVF,
0x40 |
((VT & 0x400) ? 0x01 : 0x00) |
((VDE & 0x400) ? 0x02 : 0x00) |
((VSS & 0x400) ? 0x10 : 0x00)
);
- WCrt (cv64_regs, CRT_ID_HOR_TOTAL, HT);
- WCrt (cv64_regs, CRT_ID_DISPLAY_FIFO, HT - 5);
- WCrt (cv64_regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
- WCrt (cv64_regs, CRT_ID_START_HOR_BLANK, HBS);
- WCrt (cv64_regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
- WCrt (cv64_regs, CRT_ID_START_HOR_RETR, HSS);
- WCrt (cv64_regs, CRT_ID_END_HOR_RETR,
+ WCrt (regs, CRT_ID_HOR_TOTAL, HT);
+ WCrt (regs, CRT_ID_DISPLAY_FIFO, HT - 5);
+ WCrt (regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
+ WCrt (regs, CRT_ID_START_HOR_BLANK, HBS);
+ WCrt (regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
+ WCrt (regs, CRT_ID_START_HOR_RETR, HSS);
+ WCrt (regs, CRT_ID_END_HOR_RETR,
(HSE & 0x1F) |
((HBE & 0x20) ? 0x80 : 0x00)
);
- WCrt (cv64_regs, CRT_ID_VER_TOTAL, VT);
- WCrt (cv64_regs, CRT_ID_OVERFLOW,
+ WCrt (regs, CRT_ID_VER_TOTAL, VT);
+ WCrt (regs, CRT_ID_OVERFLOW,
0x10 |
((VT & 0x100) ? 0x01 : 0x00) |
((VDE & 0x100) ? 0x02 : 0x00) |
((VDE & 0x200) ? 0x40 : 0x00) |
((VSS & 0x200) ? 0x80 : 0x00)
);
- WCrt (cv64_regs, CRT_ID_MAX_SCAN_LINE,
+ WCrt (regs, CRT_ID_MAX_SCAN_LINE,
0x40 |
(DBLSCAN ? 0x80 : 0x00) |
((VBS & 0x200) ? 0x20 : 0x00) |
(TEXT ? ((fy - 1) & 0x1F) : 0x00)
);
- WCrt (cv64_regs, CRT_ID_MODE_CONTROL, 0xE3);
+ WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
/* Text cursor */
if (TEXT) {
#if 1
- WCrt (cv64_regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
- WCrt (cv64_regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
+ WCrt (regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
+ WCrt (regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
#else
- WCrt (cv64_regs, CRT_ID_CURSOR_START, 0x00);
- WCrt (cv64_regs, CRT_ID_CURSOR_END, fy & 0x1F);
+ WCrt (regs, CRT_ID_CURSOR_START, 0x00);
+ WCrt (regs, CRT_ID_CURSOR_END, fy & 0x1F);
#endif
- WCrt (cv64_regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
- WCrt (cv64_regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
- WCrt (cv64_regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
+ WCrt (regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
+ WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
+ WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
}
- WCrt (cv64_regs, CRT_ID_START_ADDR_HIGH, 0x00);
- WCrt (cv64_regs, CRT_ID_START_ADDR_LOW, 0x00);
- WCrt (cv64_regs, CRT_ID_START_VER_RETR, VSS);
- WCrt (cv64_regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
- WCrt (cv64_regs, CRT_ID_VER_DISP_ENA_END, VDE);
- WCrt (cv64_regs, CRT_ID_START_VER_BLANK, VBS);
- WCrt (cv64_regs, CRT_ID_END_VER_BLANK, VBE);
- WCrt (cv64_regs, CRT_ID_LINE_COMPARE, 0xFF);
- WCrt (cv64_regs, CRT_ID_LACE_RETR_START, HT / 2);
- WCrt (cv64_regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
- WGfx (cv64_regs, GCT_ID_GRAPHICS_MODE,
+ WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
+ WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
+ WCrt (regs, CRT_ID_START_VER_RETR, VSS);
+ WCrt (regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
+ WCrt (regs, CRT_ID_VER_DISP_ENA_END, VDE);
+ WCrt (regs, CRT_ID_START_VER_BLANK, VBS);
+ WCrt (regs, CRT_ID_END_VER_BLANK, VBE);
+ WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
+ WCrt (regs, CRT_ID_LACE_RETR_START, HT / 2);
+ WCrt (regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
+ WGfx (regs, GCT_ID_GRAPHICS_MODE,
((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40));
- WGfx (cv64_regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
- WSeq (cv64_regs, SEQ_ID_MEMORY_MODE,
+ WGfx (regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
+ WSeq (regs, SEQ_ID_MEMORY_MODE,
((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02));
- vgaw (cv64_regs, VDAC_MASK, 0xFF);
+ wb_64 (regs, VDAC_MASK, 0xFF);
/* Blank border */
- test = RCrt (cv64_regs, CRT_ID_BACKWAD_COMP_2);
- WCrt (cv64_regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
+ test = RCrt (regs, CRT_ID_BACKWAD_COMP_2);
+ WCrt (regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
- sr15 = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2);
+ sr15 = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
sr15 &= 0xEF;
- sr18 = RSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL);
+ sr18 = RSeq (regs, SEQ_ID_RAMDAC_CNTL);
sr18 &= 0x7F;
clock_mode = 0x00;
cr50 = 0x00;
- test = RCrt (cv64_regs, CRT_ID_EXT_MISC_CNTL_2);
+ test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2);
test &= 0xD;
/* Clear roxxler byte-swapping... */
- cv64_write_port (0x0040, (volatile unsigned char *) cv64_mem);
- cv64_write_port (0x0020, (volatile unsigned char *) cv64_mem);
+ cv64_write_port (0x0040, CyberBase);
+ cv64_write_port (0x0020, CyberBase);
switch (video_mode->bits_per_pixel) {
case 1:
break;
case 15:
- cv64_write_port (0x8020, (volatile unsigned char *) cv64_mem);
+ cv64_write_port (0x8020, CyberBase);
clock_mode = 0x30;
HDE = video_mode->xres / 4;
cr50 |= 0x10;
break;
case 16:
- cv64_write_port (0x8020, (volatile unsigned char *) cv64_mem);
+ cv64_write_port (0x8020, CyberBase);
clock_mode = 0x50;
HDE = video_mode->xres / 4;
cr50 |= 0x10;
case 24:
case 32:
- cv64_write_port (0x8040, (volatile unsigned char *) cv64_mem);
+ cv64_write_port (0x8040, CyberBase);
clock_mode = 0xD0;
HDE = video_mode->xres / 2;
cr50 |= 0x30;
break;
}
-
- WCrt (cv64_regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
- WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
- WSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL, sr18);
- WCrt (cv64_regs, CRT_ID_SCREEN_OFFSET, HDE);
- WCrt (cv64_regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
+ WCrt (regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
+ WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
+ WSeq (regs, SEQ_ID_RAMDAC_CNTL, sr18);
+ WCrt (regs, CRT_ID_SCREEN_OFFSET, HDE);
+
+ WCrt (regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
- test = RCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_2);
+ test = RCrt (regs, CRT_ID_EXT_SYS_CNTL_2);
test &= ~0x30;
test |= (HDE >> 4) & 0x30;
- WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_2, test);
+ WCrt (regs, CRT_ID_EXT_SYS_CNTL_2, test);
/* Set up graphics engine */
switch (video_mode->xres) {
break;
}
- WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
+ WCrt (regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
udelay(100);
- /* __cv_delay (100000); */
- WAttr (cv64_regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
+ WAttr (regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
udelay(100);
- /* __cv_delay (100000); */
- WAttr (cv64_regs, ACT_ID_COLOR_PLANE_ENA,
+ WAttr (regs, ACT_ID_COLOR_PLANE_ENA,
(video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F);
udelay(100);
- /* __cv_delay (100000); */
tfillm = (96 * (cv64_memclk / 1000)) / 240000;
m = 0x18;
n = 0xFF;
- WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_2, m);
- WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_3, n);
+ WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, m);
+ WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, n);
udelay(10);
- /* __cv_delay (10000); */
/* Text initialization */
if (CONSOLE) {
int i;
- vgaw (cv64_regs, VDAC_ADDRESS_W, 0);
+ wb_64 (regs, VDAC_ADDRESS_W, 0);
for (i = 0; i < 4; i++) {
- vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][0]);
- vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][1]);
- vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][2]);
+ wb_64 (regs, VDAC_DATA, cvconscolors [i][0]);
+ wb_64 (regs, VDAC_DATA, cvconscolors [i][1]);
+ wb_64 (regs, VDAC_DATA, cvconscolors [i][2]);
}
}
- WAttr (cv64_regs, 0x33, 0);
+ WAttr (regs, 0x33, 0);
/* Turn gfx on again */
- gfx_on_off (0, (volatile unsigned char *) cv64_regs);
+ gfx_on_off (0, (volatile unsigned char *) regs);
/* Pass-through */
- cvscreen (0, (volatile unsigned char *) cv64_mem);
+ cvscreen (0, CyberBase);
DPRINTK("EXIT\n");
}
void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy,
u_short w, u_short h)
{
+ volatile unsigned char *regs = CyberRegs;
unsigned short drawdir = 0;
DPRINTK("ENTER\n");
}
Cyber_WaitBlit();
- /* GfxBusyWait (cv64_regs); */
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000);
- vgaw16 (cv64_regs, ECR_BKGD_MIX, 0x7);
- vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x67);
- vgaw16 (cv64_regs, ECR_BKGD_COLOR, 0x0);
- vgaw16 (cv64_regs, ECR_FRGD_COLOR, 0x1);
- vgaw16 (cv64_regs, ECR_BITPLANE_READ_MASK, 0x1);
- vgaw16 (cv64_regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
- vgaw16 (cv64_regs, ECR_CURRENT_Y_POS, sy);
- vgaw16 (cv64_regs, ECR_CURRENT_X_POS, sx);
- vgaw16 (cv64_regs, ECR_DEST_Y__AX_STEP, dy);
- vgaw16 (cv64_regs, ECR_DEST_X__DIA_STEP, dx);
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, h - 1);
- vgaw16 (cv64_regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
- vgaw16 (cv64_regs, ECR_DRAW_CMD, 0xC051 | drawdir);
+ vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+ vgaw16 (regs, ECR_BKGD_MIX, 0x7);
+ vgaw16 (regs, ECR_FRGD_MIX, 0x67);
+ vgaw16 (regs, ECR_BKGD_COLOR, 0x0);
+ vgaw16 (regs, ECR_FRGD_COLOR, 0x1);
+ vgaw16 (regs, ECR_BITPLANE_READ_MASK, 0x1);
+ vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
+ vgaw16 (regs, ECR_CURRENT_Y_POS, sy);
+ vgaw16 (regs, ECR_CURRENT_X_POS, sx);
+ vgaw16 (regs, ECR_DEST_Y__AX_STEP, dy);
+ vgaw16 (regs, ECR_DEST_X__DIA_STEP, dx);
+ vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
+ vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
+ vgaw16 (regs, ECR_DRAW_CMD, 0xC051 | drawdir);
DPRINTK("EXIT\n");
}
void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg)
{
+ volatile unsigned char *regs = CyberRegs;
DPRINTK("ENTER\n");
Cyber_WaitBlit();
- /* GfxBusyWait (cv64_regs); */
- vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x0027);
- vgaw16 (cv64_regs, ECR_FRGD_COLOR, bg);
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000);
- vgaw16 (cv64_regs, ECR_CURRENT_Y_POS, dy);
- vgaw16 (cv64_regs, ECR_CURRENT_X_POS, dx);
- vgaw16 (cv64_regs, ECR_READ_REG_DATA, h - 1);
- vgaw16 (cv64_regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
- vgaw16 (cv64_regs, ECR_DRAW_CMD, 0x40B1);
+ vgaw16 (regs, ECR_FRGD_MIX, 0x0027);
+ vgaw16 (regs, ECR_FRGD_COLOR, bg);
+ vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+ vgaw16 (regs, ECR_CURRENT_Y_POS, dy);
+ vgaw16 (regs, ECR_CURRENT_X_POS, dx);
+ vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
+ vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
+ vgaw16 (regs, ECR_DRAW_CMD, 0x40B1);
DPRINTK("EXIT\n");
}
*/
static void cv64_dump (void)
{
+ volatile unsigned char *regs = CyberRegs;
DPRINTK("ENTER\n");
/* Dump the VGA setup values */
- *(CyberRegs + S3_CRTC_ADR) = 0x00;
- DPRINTK("CR00 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x01;
- DPRINTK("CR01 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x02;
- DPRINTK("CR02 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x03;
- DPRINTK("CR03 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x04;
- DPRINTK("CR04 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x05;
- DPRINTK("CR05 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x06;
- DPRINTK("CR06 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x07;
- DPRINTK("CR07 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x08;
- DPRINTK("CR08 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x09;
- DPRINTK("CR09 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x10;
- DPRINTK("CR10 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x11;
- DPRINTK("CR11 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x12;
- DPRINTK("CR12 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x13;
- DPRINTK("CR13 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x15;
- DPRINTK("CR15 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x16;
- DPRINTK("CR16 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x36;
- DPRINTK("CR36 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x37;
- DPRINTK("CR37 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x42;
- DPRINTK("CR42 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x43;
- DPRINTK("CR43 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x50;
- DPRINTK("CR50 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x51;
- DPRINTK("CR51 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x53;
- DPRINTK("CR53 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x58;
- DPRINTK("CR58 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x59;
- DPRINTK("CR59 = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x5A;
- DPRINTK("CR5A = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x5D;
- DPRINTK("CR5D = %x\n", *(CyberRegs + S3_CRTC_DATA));
- *(CyberRegs + S3_CRTC_ADR) = 0x5E;
- DPRINTK("CR5E = %x\n", *(CyberRegs + S3_CRTC_DATA));
- DPRINTK("MISC = %x\n", *(CyberRegs + GREG_MISC_OUTPUT_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x01;
- DPRINTK("SR01 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x02;
- DPRINTK("SR02 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x03;
- DPRINTK("SR03 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x09;
- DPRINTK("SR09 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x10;
- DPRINTK("SR10 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x11;
- DPRINTK("SR11 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x12;
- DPRINTK("SR12 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x13;
- DPRINTK("SR13 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
- *(CyberRegs + SEQ_ADDRESS) = 0x15;
- DPRINTK("SR15 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
+ *(regs + S3_CRTC_ADR) = 0x00;
+ DPRINTK("CR00 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x01;
+ DPRINTK("CR01 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x02;
+ DPRINTK("CR02 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x03;
+ DPRINTK("CR03 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x04;
+ DPRINTK("CR04 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x05;
+ DPRINTK("CR05 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x06;
+ DPRINTK("CR06 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x07;
+ DPRINTK("CR07 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x08;
+ DPRINTK("CR08 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x09;
+ DPRINTK("CR09 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x10;
+ DPRINTK("CR10 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x11;
+ DPRINTK("CR11 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x12;
+ DPRINTK("CR12 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x13;
+ DPRINTK("CR13 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x15;
+ DPRINTK("CR15 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x16;
+ DPRINTK("CR16 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x36;
+ DPRINTK("CR36 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x37;
+ DPRINTK("CR37 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x42;
+ DPRINTK("CR42 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x43;
+ DPRINTK("CR43 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x50;
+ DPRINTK("CR50 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x51;
+ DPRINTK("CR51 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x53;
+ DPRINTK("CR53 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x58;
+ DPRINTK("CR58 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x59;
+ DPRINTK("CR59 = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x5A;
+ DPRINTK("CR5A = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x5D;
+ DPRINTK("CR5D = %x\n", *(regs + S3_CRTC_DATA));
+ *(regs + S3_CRTC_ADR) = 0x5E;
+ DPRINTK("CR5E = %x\n", *(regs + S3_CRTC_DATA));
+ DPRINTK("MISC = %x\n", *(regs + GREG_MISC_OUTPUT_R));
+ *(regs + SEQ_ADDRESS) = 0x01;
+ DPRINTK("SR01 = %x\n", *(regs + SEQ_ADDRESS_R));
+ *(regs + SEQ_ADDRESS) = 0x02;
+ DPRINTK("SR02 = %x\n", *(regs + SEQ_ADDRESS_R));
+ *(regs + SEQ_ADDRESS) = 0x03;
+ DPRINTK("SR03 = %x\n", *(regs + SEQ_ADDRESS_R));
+ *(regs + SEQ_ADDRESS) = 0x09;
+ DPRINTK("SR09 = %x\n", *(regs + SEQ_ADDRESS_R));
+ *(regs + SEQ_ADDRESS) = 0x10;
+ DPRINTK("SR10 = %x\n", *(regs + SEQ_ADDRESS_R));
+ *(regs + SEQ_ADDRESS) = 0x11;
+ DPRINTK("SR11 = %x\n", *(regs + SEQ_ADDRESS_R));
+ *(regs + SEQ_ADDRESS) = 0x12;
+ DPRINTK("SR12 = %x\n", *(regs + SEQ_ADDRESS_R));
+ *(regs + SEQ_ADDRESS) = 0x13;
+ DPRINTK("SR13 = %x\n", *(regs + SEQ_ADDRESS_R));
+ *(regs + SEQ_ADDRESS) = 0x15;
+ DPRINTK("SR15 = %x\n", *(regs + SEQ_ADDRESS_R));
return;
}
#define GRFBBOPset 0xf /* 1 */
-/* Read VGA register */
-#define vgar(ba, reg) (*(((volatile caddr_t)ba)+reg))
-
-/* Write VGA register */
-#define vgaw(ba, reg, val) \
-*(((volatile caddr_t)ba)+reg) = ((val) & 0xff)
-
-/* Read 16 Bit VGA register */
-#define vgar16(ba, reg) ( *((unsigned short *) (((volatile caddr_t)ba)+reg)) )
-
/* Write 16 Bit VGA register */
#define vgaw16(ba, reg, val) \
-*((unsigned short *) (((volatile caddr_t)ba)+reg)) = val
-
-/* Read 32 Bit VGA register */
-#define vgar32(ba, reg) ( *((unsigned long *) (((volatile caddr_t)ba)+reg)) )
-
-/* Write 32 Bit VGA register */
-#define vgaw32(ba, reg, val) \
- *((unsigned long *) (((volatile caddr_t)ba)+reg)) = val
+*((unsigned short *) (((volatile unsigned char *)ba)+reg)) = val
/*
* Defines for the used register addresses (mw)
#define WGfx(ba, idx, val) \
-do { vgaw(ba, GCT_ADDRESS, idx); vgaw(ba, GCT_ADDRESS_W , val); } while (0)
+do { wb_64(ba, GCT_ADDRESS, idx); wb_64(ba, GCT_ADDRESS_W , val); } while (0)
#define WSeq(ba, idx, val) \
-do { vgaw(ba, SEQ_ADDRESS, idx); vgaw(ba, SEQ_ADDRESS_W , val); } while (0)
+do { wb_64(ba, SEQ_ADDRESS, idx); wb_64(ba, SEQ_ADDRESS_W , val); } while (0)
#define WCrt(ba, idx, val) \
-do { vgaw(ba, CRT_ADDRESS, idx); vgaw(ba, CRT_ADDRESS_W , val); } while (0)
+do { wb_64(ba, CRT_ADDRESS, idx); wb_64(ba, CRT_ADDRESS_W , val); } while (0)
#define WAttr(ba, idx, val) \
do { \
unsigned char tmp;\
- tmp = vgar(ba, ACT_ADDRESS_RESET);\
- vgaw(ba, ACT_ADDRESS_W, idx);\
- vgaw(ba, ACT_ADDRESS_W, val);\
+ tmp = rb_64(ba, ACT_ADDRESS_RESET);\
+ wb_64(ba, ACT_ADDRESS_W, idx);\
+ wb_64(ba, ACT_ADDRESS_W, val);\
} while (0)
#define SetTextPlane(ba, m) \
/* prototypes */
/* --------------------------------- */
-/* in cvision_core.c */
-inline void __cv_delay(unsigned long usecs);
-inline void GfxBusyWait(volatile caddr_t board);
-inline void GfxFifoWait(volatile caddr_t board);
-inline unsigned char RAttr(volatile caddr_t board, short idx);
-inline unsigned char RSeq(volatile caddr_t board, short idx);
-inline unsigned char RCrt(volatile caddr_t board, short idx);
-inline unsigned char RGfx(volatile caddr_t board, short idx);
+inline unsigned char RAttr(volatile unsigned char * board, short idx);
+inline unsigned char RSeq(volatile unsigned char * board, short idx);
+inline unsigned char RCrt(volatile unsigned char * board, short idx);
+inline unsigned char RGfx(volatile unsigned char * board, short idx);
inline void cv64_write_port(unsigned short bits,
volatile unsigned char *board);
inline void cvscreen(int toggle, volatile unsigned char *board);
inline void gfx_on_off(int toggle, volatile unsigned char *board);
#if 0
unsigned short cv64_compute_clock(unsigned long freq);
-int cv_has_4mb(volatile caddr_t fb);
+int cv_has_4mb(volatile unsigned char * fb);
void cv64_board_init(void);
void cv64_load_video_mode(struct fb_var_screeninfo *video_mode);
#endif
#define DUMMY_ROWS 25
#endif
-__initfunc(static const char *dummycon_startup(void))
+static const char __init *dummycon_startup(void)
{
return "dummy device";
}
p->dispsw->clear_margins(conp, p, 0);
if (logo_shown == -2) {
logo_shown = fg_console;
- fbcon_clear(conp, 0, 0, LOGO_H, p->var.xres-LOGO_W);
fbcon_show_logo(); /* This is protected above by initmem_freed */
update_region(fg_console,
conp->vc_origin + conp->vc_size_row * conp->vc_top,
return n<0 ? d>>-n : d<<n;
}
-__initfunc(static int fbcon_show_logo( void ))
+static int __init fbcon_show_logo( void )
{
struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
int depth = p->var.bits_per_pixel;
static struct proc_dir_entry *proc_fbmem;
-__initfunc(void
-fbmem_init(void))
+void __init
+fbmem_init(void)
{
int i;
* Command line options
*/
-__initfunc(void video_setup(char *options, int *ints))
+void __init video_setup(char *options, int *ints)
{
int i, j;
* Initialisation
*/
-__initfunc(void fm2fb_init(void))
+void __init fm2fb_init(void)
{
int key, is_fm;
const struct ConfigDev *cd = NULL;
fb_fix.id);
}
-__initfunc(void fm2fb_setup(char *options, int *ints))
+void __init fm2fb_setup(char *options, int *ints)
{
char *this_opt;
/*
* Initialisation
*/
-__initfunc(void g364fb_init(void))
+void __init g364fb_init(void)
{
int i,j;
volatile unsigned int *pal_ptr = (volatile unsigned int *) CLR_PAL_REG;
#define TOPCAT_FBOMSB 0x5d
#define TOPCAT_FBOLSB 0x5f
-__initfunc(int hpfb_init_one(unsigned long base))
+int __init hpfb_init_one(unsigned long base)
{
unsigned long fboff;
* Initialise the framebuffer
*/
-__initfunc(unsigned long hpfb_init(unsigned long mem_start))
+unsigned long __init hpfb_init(unsigned long mem_start)
{
unsigned int sid;
return mem_start;
}
-__initfunc(void hpfb_setup(char *options, int *ints))
+void __init hpfb_setup(char *options, int *ints)
{
}
}
-__initfunc(static int iga_init(struct fb_info_iga *info))
+static int __init iga_init(struct fb_info_iga *info)
{
char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL)
& MEM_SIZE_ALIAS;
}
-__initfunc(void igafb_init(void))
+void __init igafb_init(void)
{
struct pci_dev *pdev;
struct fb_info_iga *info;
#endif /* __sparc__ */
}
-__initfunc(void igafb_setup(char *options, int *ints))
+void __init igafb_setup(char *options, int *ints)
{
char *this_opt;
add_timer(&c->timer);
}
-__initfunc(static void
-imstt_cursor_init (struct fb_info_imstt *p))
+static void __init
+imstt_cursor_init (struct fb_info_imstt *p)
{
struct imstt_cursor *c = &p->cursor;
out_le32(&p->dc_regs[STGCTL], ctrl);
}
-__initfunc(static void
-init_imstt(struct fb_info_imstt *p))
+static void __init
+init_imstt(struct fb_info_imstt *p)
{
__u32 i, tmp;
__u32 *ip, *end;
}
#if defined(CONFIG_FB_OF) && !defined(MODULE)
-__initfunc(void
-imsttfb_of_init(struct device_node *dp))
+void __init
+imsttfb_of_init(struct device_node *dp)
{
struct fb_info_imstt *p;
int i;
}
#endif
-__initfunc(void
-imsttfb_init(void))
+void __init
+imsttfb_init(void)
{
#if defined(CONFIG_FB_OF) && !defined(MODULE)
/* We don't want to be called like this. */
}
#ifndef MODULE
-__initfunc(void
-imsttfb_setup(char *options, int *ints))
+void __init
+imsttfb_setup(char *options, int *ints)
{
char *this_opt;
NULL
};
-__initfunc(void macfb_init(void))
+void __init macfb_init(void)
{
/* nubus_remap the video .. */
/*
*
- * Hardware accelerated Matrox Millennium I, II, Mystique and G200
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
*
* (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
*
- * Version: 1.15 1999/04/19
+ * Version: 1.19 1999/08/05
*
* MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
*
* "Kurt Garloff" <garloff@kg1.ping.de>
* Betatesting, fixes, ideas, videomodes, videomodes timmings
*
- * "Tom Rini" <tmrini@ntplx.net>
- * MTRR stuff, betatesting, fixes, ideas
+ * "Tom Rini" <trini@disparity.net>
+ * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
*
* "Bibek Sahu" <scorpio@dodds.net>
* Access device through readb|w|l and write b|w|l
* "Cort Dougan" <cort@cs.nmt.edu>
* CHRP fixes and PReP cleanup
*
+ * "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ * G400 support
+ *
* (following author is not in any relation with this code, but his code
* is included in this driver)
*
/* Debug register calls, too? */
#undef MATROXFB_DEBUG_REG
+/* Log reentrancy attempts - you must have printstate() patch applied */
+#undef MATROXFB_DEBUG_REENTER
+/* you must define DEBUG_REENTER to get debugged CONSOLEBH... */
+#undef MATROXFB_DEBUG_CONSOLEBH
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <video/macmodes.h>
#endif
+/* always compile support for 32MB... It cost almost nothing */
+#define CONFIG_FB_MATROX_32MB
+
#define FBCON_HAS_VGATEXT
#ifdef MATROXFB_DEBUG
#define DEBUG
-#define DBG(x) printk("matroxfb: %s\n", (x));
+#define DBG(x) printk(KERN_DEBUG "matroxfb: %s\n", (x));
#ifdef MATROXFB_DEBUG_HEAVY
#define DBG_HEAVY(x) DBG(x)
#ifndef PCI_DEVICE_ID_MATROX_G100_AGP
#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
#endif
+#ifndef PCI_DEVICE_ID_MATROX_G400_AGP
+#define PCI_DEVICE_ID_MATROX_G400_AGP 0x0525
+#endif
#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
#define PCI_SS_ID_MATROX_GENERIC 0xFF00
unsigned char MiscOutReg;
unsigned char DACpal[768];
unsigned char CRTC[25];
- unsigned char CRTCEXT[6];
+ unsigned char CRTCEXT[9];
unsigned char SEQ[5];
/* unused for MGA mode, but who knows... */
unsigned char GCTL[9];
}
#define PMXINFO(p) mxinfo(p),
-#define MINFO_FROM_DISP(x) struct matrox_fb_info* minfo = mxinfo(x)
+#define MINFO_FROM(x) struct matrox_fb_info* minfo = x
+#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
#else
#endif
#define PMXINFO(p)
+#define MINFO_FROM(x)
#define MINFO_FROM_DISP(x)
#endif
int hwcursor;
int blink;
int sgram;
+#ifdef CONFIG_FB_MATROX_32MB
+ int support32MB;
+#endif
int accelerator;
int text_type_aux;
#if defined(CONFIG_FB_OF)
unsigned char nvram_read_byte(int);
int matrox_of_init(struct device_node *dp);
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
#endif
#define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels)
#define M_RESET 0x1E40
+#define M_AGP2PLL 0x1E4C
+
#define M_OPMODE 0x1E54
#define M_OPMODE_DMA_GEN_WRITE 0x00
#define M_OPMODE_DMA_BLIT 0x04
#define M_EXTVGA_INDEX 0x1FDE
#define M_EXTVGA_DATA 0x1FDF
+/* G200 only */
+#define M_SRCORG 0x2CB4
+
#define M_RAMDAC_BASE 0x3C00
/* fortunately, same on TVP3026 and MGA1064 */
#define M_X_INDEX 0x00
#define M_X_DATAREG 0x0A
+#define DAC_XGENIOCTRL 0x2A
+#define DAC_XGENIODATA 0x2B
+
#ifdef CONFIG_FB_MATROX_MILLENIUM
#define TVP3026_INDEX 0x00
#define TVP3026_PALWRADD 0x00
#define isMilleniumII(x) (0)
#endif
+#ifdef MATROXFB_DEBUG_REENTER
+static atomic_t guard_counter = ATOMIC_INIT(1);
+static atomic_t guard_printing = ATOMIC_INIT(1);
+static void guard_start(void) {
+ if (atomic_dec_and_test(&guard_counter)) { /* first level */
+ if (!(bh_mask & (1 << CONSOLE_BH))) /* and CONSOLE_BH disabled */
+ return; /* is OK */
+ /* otherwise it is first level with CONSOLE_BH enabled -
+ - if we are __sti or SMP, reentering from console_bh possible */
+ atomic_dec(&guard_printing); /* disable reentrancy warning */
+ printk(KERN_DEBUG "matroxfb entered without CONSOLE_BH disabled\n");
+#ifdef printstate
+ printstate();
+#endif
+ atomic_inc(&guard_printing);
+ return;
+ }
+ /* real reentering... You should be already warned by code above */
+ if (atomic_dec_and_test(&guard_printing)) {
+#ifdef printstate
+ printstate();
+#endif
+ }
+ atomic_inc(&guard_printing);
+}
+
+static inline void guard_end(void) {
+ atomic_inc(&guard_counter);
+}
+
+#define CRITBEGIN guard_start();
+#define CRITEND guard_end();
+
+#else
+
+#define CRITBEGIN
+#define CRITEND
+
+#endif
+
+#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
+
static void matrox_cfbX_init(WPMINFO struct display* p) {
u_int32_t maccess;
u_int32_t mpitch;
mga_outl(M_OPMODE, mopmode);
mga_outl(M_CXBNDRY, 0xFFFF0000);
mga_outl(M_YTOP, 0);
- mga_outl(M_YBOT, 0x007FFFFF);
+ mga_outl(M_YBOT, 0x01FFFFFF);
mga_outl(M_MACCESS, maccess);
ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
MINFO_FROM_DISP(p);
DBG("matrox_cfbX_bmove")
-
+
+ CRITBEGIN
+
sx *= fontwidth(p);
dx *= fontwidth(p);
width *= fontwidth(p);
mga_outl(M_AR0, end);
mga_outl(M_AR3, start);
mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
- mga_outl(M_YDSTLEN | M_EXEC, ((dy)<<16) | height);
+ mga_ydstlen(dy, height);
WaitTillIdle();
+
+ CRITEND
}
#ifdef FBCON_HAS_CFB4
also odd, that means that we cannot use acceleration */
DBG("matrox_cfb4_bmove")
-
+
+ CRITBEGIN
+
if ((sx | dx | width) & fontwidth(p) & 1) {
fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
return;
mga_outl(M_YDST, dy*pixx >> 5);
mga_outl(M_LEN | M_EXEC, height);
WaitTillIdle();
+
+ CRITEND
}
#endif
int width) {
DBG("matroxfb_accel_clear")
-
- mga_fifo(4);
+
+ CRITBEGIN
+
+ mga_fifo(5);
mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
mga_outl(M_FCOL, color);
mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
- mga_outl(M_YDSTLEN | M_EXEC, (sy << 16) | height);
+ mga_ydstlen(sy, height);
WaitTillIdle();
+
+ CRITEND
}
static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
MINFO_FROM_DISP(p);
DBG("matrox_cfb4_clear")
-
+
+ CRITBEGIN
+
whattodo = 0;
bgx = attr_bgcol_ec(p, conp);
bgx |= bgx << 4;
}
}
}
+
+ CRITEND
}
#endif
charcell = fontwidth(p) * fontheight(p);
yy *= fontheight(p);
xx *= fontwidth(p);
- mga_fifo(7);
+
+ CRITBEGIN
+
+ mga_fifo(8);
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
mga_outl(M_FCOL, fgx);
ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell;
mga_outl(M_AR3, ar3);
mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
- mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+ mga_ydstlen(yy, fontheight(p));
WaitTillIdle();
+
+ CRITEND
}
static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
yy *= fontheight(p);
xx *= fontwidth(p);
+
+ CRITBEGIN
+
#ifdef __BIG_ENDIAN
WaitTillIdle();
mga_outl(M_OPMODE, M_OPMODE_8BPP);
mga_outl(M_BCOL, bgx);
mga_outl(M_AR3, 0);
mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
- mga_outl(M_YDSTLEN | M_EXEC, (yy<<16) | fontheight(p));
+ mga_ydstlen(yy, fontheight(p));
mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell);
} else {
u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
mga_outl(M_AR5, 0);
mga_outl(M_AR3, 0);
mga_outl(M_AR0, ar0);
- mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+ mga_ydstlen(yy, fontheight(p));
switch (step) {
case 1:
#ifdef __BIG_ENDIAN
mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
#endif
+ CRITEND
}
#ifdef FBCON_HAS_CFB8
yy *= fontheight(p);
xx *= fontwidth(p);
charcell = fontwidth(p) * fontheight(p);
+
+ CRITBEGIN
+
mga_fifo(3);
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
mga_outl(M_FCOL, fgx);
mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
mga_outl(M_AR3, ar3);
mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
- mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+ mga_ydstlen(yy, fontheight(p));
xx += fontwidth(p);
}
WaitTillIdle();
+
+ CRITEND
}
static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
step = 4;
charcell = fontheight(p)*step;
xlen = (charcell + 3) & ~3;
- ydstlen = (yy<<16) | fontheight(p);
+ ydstlen = (yy << 16) | fontheight(p);
if (fontwidth(p) == step << 3) {
ar0 = fontheight(p)*fontwidth(p) - 1;
easy = 1;
ar0 = fontwidth(p) - 1;
easy = 0;
}
+
+ CRITBEGIN
+
#ifdef __BIG_ENDIAN
WaitTillIdle();
mga_outl(M_OPMODE, M_OPMODE_8BPP);
while (count--) {
u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell;
- mga_fifo(5);
+ mga_fifo(6);
mga_writel(mmio, M_FXBNDRY, fxbndry);
mga_writel(mmio, M_AR0, ar0);
mga_writel(mmio, M_AR3, 0);
#ifdef __BIG_ENDIAN
mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
#endif
+ CRITEND
}
#ifdef FBCON_HAS_CFB8
xx |= (xx + fontwidth(p)) << 16;
xx >>= 1;
+ CRITBEGIN
+
mga_fifo(5);
mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
mga_outl(M_FCOL, 0xFFFFFFFF);
mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
mga_outl(M_LEN | M_EXEC, fontheight(p));
WaitTillIdle();
+
+ CRITEND
}
#endif
yy *= fontheight(p);
xx *= fontwidth(p);
+ CRITBEGIN
+
mga_fifo(4);
mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
mga_outl(M_FCOL, 0x0F0F0F0F);
mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
- mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+ mga_ydstlen(yy, fontheight(p));
WaitTillIdle();
+
+ CRITEND
}
#endif
yy *= fontheight(p);
xx *= fontwidth(p);
+ CRITBEGIN
+
mga_fifo(4);
mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
mga_outl(M_FCOL, 0xFFFFFFFF);
mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
- mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+ mga_ydstlen(yy, fontheight(p));
WaitTillIdle();
+
+ CRITEND
}
static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
DBG("matroxfb_ti3026_cursor")
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
if (mode == CM_ERASE) {
if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
cursorbase = ACCESS_FBINFO(video.vbase);
h = ACCESS_FBINFO(features.DAC1064.cursorimage);
+
+ CRITBEGIN
+
#ifdef __BIG_ENDIAN
WaitTillIdle();
mga_outl(M_OPMODE, M_OPMODE_32BPP);
#ifdef __BIG_ENDIAN
mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
#endif
+
+ CRITEND
}
static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
unsigned long flags;
MINFO_FROM_DISP(p);
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
if (mode == CM_ERASE) {
if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p);
if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size))
return 0;
+
+ CRITBEGIN
+
mga_outl(M_OPMODE, M_OPMODE_8BPP);
if (width <= 8) {
if (width == 8)
}
}
mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
+
+ CRITEND
+
return 1;
}
unsigned int step;
MINFO_FROM_DISP(p);
+ CRITBEGIN
+
step = ACCESS_FBINFO(devflags.textstep);
srcoff = (sy * p->next_line) + (sx * step);
dstoff = (dy * p->next_line) + (dx * step);
height--;
}
}
+ CRITEND
}
static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx,
step = ACCESS_FBINFO(devflags.textstep);
offs = sy * p->next_line + sx * step;
val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8));
+
+ CRITBEGIN
+
while (height > 0) {
int i;
for (i = width; i > 0; offs += step, i--)
offs += p->next_line - width * step;
height--;
}
+ CRITEND
}
static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
offs = yy * p->next_line + xx * step;
chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8);
if (chr & 0x10000) chr |= 0x08;
+
+ CRITBEGIN
+
mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr));
+
+ CRITEND
}
static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s,
step = ACCESS_FBINFO(devflags.textstep);
offs = yy * p->next_line + xx * step;
attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
+
+ CRITBEGIN
+
while (count-- > 0) {
unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
if (chr & 0x10000) chr ^= 0x10008;
mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr));
offs += step;
}
+
+ CRITEND
}
static void matrox_text_revc(struct display* p, int xx, int yy) {
step = ACCESS_FBINFO(devflags.textstep);
offs = yy * p->next_line + xx * step + 1;
+
+ CRITBEGIN
+
mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77);
+
+ CRITEND
}
static int matrox_text_loadfont(WPMINFO struct display* p) {
dst = ACCESS_FBINFO(video.vbase);
i = 2;
font = (u_int8_t*)p->fontdata;
+
+ CRITBEGIN
+
mga_setr(M_SEQ_INDEX, 0x02, 0x04);
while (fsize--) {
int l;
i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep);
}
mga_setr(M_SEQ_INDEX, 0x02, 0x03);
+
+ CRITEND
+
return 1;
}
return;
matroxfb_createcursorshape(PMINFO p, 0);
+
+ CRITBEGIN
+
mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1);
+
+ CRITEND
}
static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
unsigned int pos;
MINFO_FROM_DISP(p);
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
if (mode == CM_ERASE) {
if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+
+ CRITBEGIN
+
mga_setr(M_CRTC_INDEX, 0x0A, 0x20);
+
+ CRITEND
+
ACCESS_FBINFO(cursor.state) = CM_ERASE;
}
return;
ACCESS_FBINFO(cursor.x) = x;
ACCESS_FBINFO(cursor.y) = y;
pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x;
+
+ CRITBEGIN
+
mga_setr(M_CRTC_INDEX, 0x0F, pos);
mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8);
mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
+
+ CRITEND
+
ACCESS_FBINFO(cursor.state) = CM_DRAW;
}
static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
unsigned int pos;
unsigned short p0, p1, p2;
+#ifdef CONFIG_FB_MATROX_32MB
+ unsigned int p3;
+#endif
struct display *disp;
DBG("matrox_pan_var")
}
p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
- p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+ p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+#ifdef CONFIG_FB_MATROX_32MB
+ p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21;
+#endif
+
+ CRITBEGIN
+
mga_setr(M_CRTC_INDEX, 0x0D, p0);
mga_setr(M_CRTC_INDEX, 0x0C, p1);
+#ifdef CONFIG_FB_MATROX_32MB
+ if (ACCESS_FBINFO(devflags.support32MB))
+ mga_setr(M_EXTVGA_INDEX, 0x08, p3);
+#endif
mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+
+ CRITEND
}
/*
case 0: return xres;
case 4: rounding = 128;
break;
- case 8: rounding = 64;
+ case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */
break;
case 16: rounding = 32;
break;
- case 24: rounding = 64;
+ case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */
break;
default: rounding = 16;
+ /* on G400, 16 really does not work */
+ if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+ rounding = 32;
break;
}
if (isInterleave(MINFO)) {
hw->DACclk[2] = p;
}
-__initfunc(static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem)) {
+static void __init DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){
u_int32_t mx;
DBG("DAC1064_setmclk")
static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
DBG("DAC1064_restore_1")
+
+ CRITBEGIN
outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
}
+
+ CRITEND
}
static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {
unsigned int tmout;
DBG("DAC1064_restore_2")
+
+ CRITBEGIN
for (i = 0; i < 3; i++)
outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
break;
udelay(10);
};
+
+ CRITEND
+
if (!tmout)
printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
var->pixclock = 15000; /* limit for "normal" gclk & mclk */
#endif
}
-
+ /* YDSTLEN contains only signed 16bit value */
+ if (var->yres_virtual > 32767)
+ var->yres_virtual = 32767;
if (var->yres_virtual < var->yres)
var->yres = var->yres_virtual;
if (var->xres_virtual < var->xres)
}
#ifdef CONFIG_FB_MATROX_MILLENIUM
-__initfunc(static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout)) {
+static void __init ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){
unsigned int f_pll;
unsigned int pclk_m, pclk_n, pclk_p;
unsigned int mclk_m, mclk_n, mclk_p;
printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
}
-__initfunc(static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+static void __init ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){
DBG("ti3026_ramdac_init")
}
#endif
-__initfunc(static void matroxfb_fastfont_init(struct matrox_fb_info* minfo)) {
+static void matroxfb_fastfont_init(struct matrox_fb_info* minfo){
unsigned int size;
size = ACCESS_FBINFO(fastfont.size);
}
#ifdef CONFIG_FB_MATROX_MYSTIQUE
-__initfunc(static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){
DBG("MGA1064_ramdac_init");
DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
}
-__initfunc(static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){
static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960,
1024, 1152, 1280, 1600, 1664, 1920,
2048, 0};
return 0;
}
-__initfunc(static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGA1064_reset(WPMINFO struct matrox_hw_state* hw){
DBG("MGA1064_reset");
static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
#endif
-__initfunc(static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p)) {
+static void __init MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){
int reg;
int selClk;
int clk;
outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
}
-__initfunc(static void MGAG100_setPixClock(CPMINFO int flags, int freq)) {
+static void __init MGAG100_setPixClock(CPMINFO int flags, int freq){
unsigned int m, n, p;
DBG("MGAG100_setPixClock")
MGAG100_progPixClock(PMINFO flags, m, n, p);
}
-__initfunc(static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){
static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960,
1024, 1152, 1280, 1600, 1664, 1920,
2048, 0};
return 0;
}
-__initfunc(static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGAG100_reset(WPMINFO struct matrox_hw_state* hw){
u_int8_t b;
DBG("MGAG100_reset")
dprintk("%02X:", hw->ATTR[i]);
dprintk("\n");
+ CRITBEGIN
+
mga_inb(M_ATTR_RESET);
mga_outb(M_ATTR_INDEX, 0);
mga_outb(M_MISC_REG, hw->MiscOutReg);
mga_outb(M_DAC_VAL, hw->DACpal[i]);
mga_inb(M_ATTR_RESET);
mga_outb(M_ATTR_INDEX, 0x20);
+
+ CRITEND
}
static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
int i;
DBG("MGA1064_restore")
+
+ CRITBEGIN
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
mga_outb(M_IEN, 0x00);
mga_outb(M_CACHEFLUSH, 0x00);
+
+ CRITEND
+
DAC1064_restore_1(PMINFO hw, oldhw);
vgaHWrestore(PMINFO hw, oldhw);
for (i = 0; i < 6; i++)
int i;
DBG("MGAG100_restore")
-
+
+ CRITBEGIN
+
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ CRITEND
+
DAC1064_restore_1(PMINFO hw, oldhw);
vgaHWrestore(PMINFO hw, oldhw);
+#ifdef CONFIG_FB_MATROX_32MB
+ if (ACCESS_FBINFO(devflags.support32MB))
+ mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
+#endif
for (i = 0; i < 6; i++)
mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
DAC1064_restore_2(PMINFO hw, oldhw, p);
dprintk("%02X:", hw->CRTCEXT[i]);
dprintk("\n");
+ CRITBEGIN
+
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ CRITEND
+
vgaHWrestore(PMINFO hw, oldhw);
+
+ CRITBEGIN
+
for (i = 0; i < 6; i++)
mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
}
+ CRITEND
if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
/* agrhh... setting up PLL is very slow on Millenium... */
/* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
/* Maybe even we should call schedule() ? */
+ CRITBEGIN
outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
break;
udelay(10);
}
+
+ CRITEND
+
if (!tmout)
printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
else
dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+ CRITBEGIN
}
outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
for (i = 3; i < 6; i++)
outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+ CRITEND
if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
int tmout;
+ CRITBEGIN
outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
for (tmout = 500000; tmout; --tmout) {
if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40)
break;
udelay(10);
}
+ CRITEND
if (!tmout)
printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
else
strcpy(fix->id,"MATROX");
fix->smem_start = (void*)ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
- fix->smem_len = ACCESS_FBINFO(video.len) - ACCESS_FBINFO(curr.ydstorg.bytes);
+ fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
fix->type = p->type;
fix->type_aux = p->type_aux;
fix->visual = p->visual;
hw->CRTC[0x0D] = pos & 0xFF;
hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
- hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+ hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+ hw->CRTCEXT[8] = pos >> 21;
ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
ACCESS_FBINFO(cursor.redraw) = 1;
ACCESS_FBINFO(currenthw) = hw;
case 4: seq = 0x20; crtc = 0x30; break;
default: seq = 0x00; crtc = 0x00; break;
}
+
+ CRITBEGIN
+
mga_outb(M_SEQ_INDEX, 1);
mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
mga_outb(M_EXTVGA_INDEX, 1);
mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+ CRITEND
+
#undef minfo
}
#define RS1056x344 12 /* 132 x 43 text */
#define RS1056x400 13 /* 132 x 50 text */
#define RS1056x480 14 /* 132 x 60 text */
-/* 0F-FF */
+#define RSNoxNo 15
+/* 10-FF */
static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
{ 640, 400, 48, 16, 39, 8, 96, 2, 70 },
{ 640, 480, 48, 16, 33, 10, 96, 2, 60 },
{ 640, 350, 48, 16, 39, 8, 96, 2, 70 },
{ 1056, 344, 96, 24, 59, 44, 160, 2, 70 },
{ 1056, 400, 96, 24, 39, 8, 160, 2, 70 },
- { 1056, 480, 96, 24, 36, 12, 160, 3, 60 }
+ { 1056, 480, 96, 24, 36, 12, 160, 3, 60 },
+ { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 }
};
#define RSDepth(X) (((X) >> 8) & 0x0F)
{ { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 },
{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 },
{ { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */
- { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 } /* textmode hardwired to VGA8x8 */
+ { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */
};
#define RSCreate(X,Y) ((X) | ((Y) << 8))
static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
/* default must be first */
#ifdef FBCON_HAS_CFB8
+ { ~0, RSCreate(RSNoxNo, RS8bpp ) },
{ 0x101, RSCreate(RS640x480, RS8bpp ) },
{ 0x100, RSCreate(RS640x400, RS8bpp ) },
{ 0x180, RSCreate(RS768x576, RS8bpp ) },
{ 0x198, RSCreate(RS1408x1056, RS8bpp ) },
{ 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
#endif
-#ifdef FBCON_HAS_CFB4
- { 0x010, RSCreate(RS640x350, RS4bpp ) },
- { 0x012, RSCreate(RS640x480, RS4bpp ) },
- { 0x102, RSCreate(RS800x600, RS4bpp ) },
- { 0x104, RSCreate(RS1024x768, RS4bpp ) },
- { 0x106, RSCreate(RS1280x1024, RS4bpp ) },
-#endif
#ifdef FBCON_HAS_CFB16
+ { ~0, RSCreate(RSNoxNo, RS15bpp) },
{ 0x110, RSCreate(RS640x480, RS15bpp) },
{ 0x181, RSCreate(RS768x576, RS15bpp) },
{ 0x113, RSCreate(RS800x600, RS15bpp) },
{ 0x11E, RSCreate(RS1600x1200, RS16bpp) },
#endif
#ifdef FBCON_HAS_CFB24
+ { ~0, RSCreate(RSNoxNo, RS24bpp) },
{ 0x1B2, RSCreate(RS640x480, RS24bpp) },
{ 0x184, RSCreate(RS768x576, RS24bpp) },
{ 0x1B5, RSCreate(RS800x600, RS24bpp) },
{ 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
#endif
#ifdef FBCON_HAS_CFB32
+ { ~0, RSCreate(RSNoxNo, RS32bpp) },
{ 0x112, RSCreate(RS640x480, RS32bpp) },
{ 0x183, RSCreate(RS768x576, RS32bpp) },
{ 0x115, RSCreate(RS800x600, RS32bpp) },
{ 0x11F, RSCreate(RS1600x1200, RS32bpp) },
#endif
#ifdef FBCON_HAS_VGATEXT
+ { ~0, RSCreate(RSNoxNo, RSText) },
{ 0x002, RSCreate(RS640x400, RSText) }, /* 80x25 */
{ 0x003, RSCreate(RS640x400, RSText) }, /* 80x25 */
{ 0x007, RSCreate(RS640x400, RSText) }, /* 80x25 */
{ 0x10A, RSCreate(RS1056x344, RSText8) }, /* 132x43 */
{ 0x10B, RSCreate(RS1056x400, RSText8) }, /* 132x50 */
{ 0x10C, RSCreate(RS1056x480, RSText8) }, /* 132x60 */
+#endif
+#ifdef FBCON_HAS_CFB4
+ { ~0, RSCreate(RSNoxNo, RS4bpp ) },
+ { 0x010, RSCreate(RS640x350, RS4bpp ) },
+ { 0x012, RSCreate(RS640x480, RS4bpp ) },
+ { 0x102, RSCreate(RS800x600, RS4bpp ) },
+ { 0x104, RSCreate(RS1024x768, RS4bpp ) },
+ { 0x106, RSCreate(RS1280x1024, RS4bpp ) },
#endif
{ 0, 0 }};
static int hwcursor = 1; /* "matrox:nohwcursor" */
static int blink = 1; /* "matrox:noblink" */
static int sgram = 0; /* "matrox:sgram" */
+#ifdef CONFIG_MTRR
static int mtrr = 1; /* "matrox:nomtrr" */
+#endif
static int grayscale = 0; /* "matrox:grayscale" */
static unsigned int fastfont = 0; /* "matrox:fastfont:xxxxx" */
static int dev = -1; /* "matrox:dev:xxxxx" */
-static unsigned int vesa = 0x101; /* "matrox:vesa:xxxxx" */
+static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */
static int depth = -1; /* "matrox:depth:xxxxx" */
static unsigned int xres = 0; /* "matrox:xres:xxxxx" */
static unsigned int yres = 0; /* "matrox:yres:xxxxx" */
-static unsigned int upper = 0; /* "matrox:upper:xxxxx" */
-static unsigned int lower = 0; /* "matrox:lower:xxxxx" */
+static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */
+static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */
static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */
-static unsigned int left = 0; /* "matrox:left:xxxxx" */
-static unsigned int right = 0; /* "matrox:right:xxxxx" */
+static unsigned int left = ~0; /* "matrox:left:xxxxx" */
+static unsigned int right = ~0; /* "matrox:right:xxxxx" */
static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */
static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */
static int sync = -1; /* "matrox:sync:xxxxx" */
static char fontname[64]; /* "matrox:font:xxxxx" */
#ifndef MODULE
-__initfunc(void matroxfb_setup(char *options, int *ints)) {
+void __init matroxfb_setup(char *options, int *ints){
char *this_opt;
DBG("matroxfb_setup")
fontname[0] = '\0';
if (!options || !*options)
- return;
+ return 0;
for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
if (!*this_opt) continue;
fv = simple_strtoul(this_opt+3, NULL, 0);
else if (!strncmp(this_opt, "mem:", 4))
mem = simple_strtoul(this_opt+4, NULL, 0);
+ else if (!strncmp(this_opt, "mode:", 5))
+ strcpy(videomode, this_opt+5);
+#ifdef CONFIG_FB_OF
+ else if (!strncmp(this_opt, "vmode:", 6)) {
+ unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+ if (vmode > 0 && vmode <= VMODE_MAX)
+ default_vmode = vmode;
+ } else if (!strncmp(this_opt, "cmode:", 6)) {
+ unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+ switch (cmode) {
+ case 0:
+ case 8:
+ default_cmode = CMODE_8;
+ break;
+ case 15:
+ case 16:
+ default_cmode = CMODE_16;
+ break;
+ case 24:
+ case 32:
+ default_cmode = CMODE_32;
+ break;
+ }
+ }
+#endif
else if (!strncmp(this_opt, "fastfont:", 9))
fastfont = simple_strtoul(this_opt+9, NULL, 0);
else if (!strcmp(this_opt, "nofastfont")) /* fastfont:N and nofastfont (nofastfont = fastfont:0) */
nobios = !value;
else if (!strcmp(this_opt, "init"))
noinit = !value;
+#ifdef CONFIG_MTRR
else if (!strcmp(this_opt, "mtrr"))
mtrr = value;
+#endif
else if (!strcmp(this_opt, "inv24"))
inv24 = value;
else if (!strcmp(this_opt, "cross4MB"))
}
}
}
+ return 0;
}
#endif
-__initfunc(static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize)) {
+static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){
vaddr_t vm;
unsigned int offs;
unsigned int offs2;
unsigned char store;
- unsigned char bytes[16];
+ unsigned char bytes[32];
unsigned char* tmp;
unsigned long cbase;
unsigned long mbase;
maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */
/* at least 2MB */
if (maxSize < 0x0200000) return 0;
- if (maxSize > 0x1000000) maxSize = 0x1000000;
+ if (maxSize > 0x2000000) maxSize = 0x2000000;
mga_outb(M_EXTVGA_INDEX, 0x03);
mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
}
#ifdef CONFIG_FB_MATROX_MILLENIUM
-__initfunc(static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init Ti3026_preinit(WPMINFO struct matrox_hw_state* hw){
static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
1024, 1152, 1280, 1600, 1664, 1920,
2048, 0};
return 0;
}
-__initfunc(static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init Ti3026_reset(WPMINFO struct matrox_hw_state* hw){
DBG("Ti3026_reset")
struct video_board {
int maxvram;
+ int maxdisplayable;
int accelID;
struct matrox_switch* lowlevel;
};
#ifdef CONFIG_FB_MATROX_MILLENIUM
-static struct video_board vbMillenium __initdata = {0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millenium};
-static struct video_board vbMillenium2 __initdata = {0x1000000, FB_ACCEL_MATROX_MGA2164W, &matrox_millenium};
-static struct video_board vbMillenium2A __initdata = {0x1000000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium};
+static struct video_board vbMillenium __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millenium};
+static struct video_board vbMillenium2 __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millenium};
+static struct video_board vbMillenium2A __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium};
#endif /* CONFIG_FB_MATROX_MILLENIUM */
#ifdef CONFIG_FB_MATROX_MYSTIQUE
-static struct video_board vbMystique __initdata = {0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique};
+static struct video_board vbMystique __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique};
#endif /* CONFIG_FB_MATROX_MYSTIQUE */
#ifdef CONFIG_FB_MATROX_G100
-static struct video_board vbG100 __initdata = {0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100};
-static struct video_board vbG200 __initdata = {0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100};
+static struct video_board vbG100 __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100};
+static struct video_board vbG200 __initdata = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100};
+#ifdef CONFIG_FB_MATROX_32MB
+/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
+ whole 32MB */
+static struct video_board vbG400 __initdata = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
+#else
+static struct video_board vbG400 __initdata = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
+#endif
#endif
#define DEVF_VIDEO64BIT 0x01
#define DEVF_MILLENIUM2 0x08
#define DEVF_CROSS4MB 0x10
#define DEVF_TEXT4B 0x20
+#define DEVF_DDC_8_2 0x40
+#define DEVF_DMA 0x80
+#define DEVF_SUPPORT32MB 0x100
+#define DEVF_ANY_VXRES 0x200
+
+#define DEVF_G100 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) /* no doc, no vxres... */
+#define DEVF_G200 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES)
+#define DEVF_G400 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES | DEVF_SUPPORT32MB)
+
static struct board {
unsigned short vendor, device, rev, svid, sid;
unsigned int flags;
#ifdef CONFIG_FB_MATROX_G100
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G100,
230000,
&vbG100,
"MGA-G100 (PCI)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
0, 0,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G100,
230000,
&vbG100,
"unknown G100 (PCI)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G100,
230000,
&vbG100,
"MGA-G100 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_AGP,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G100,
230000,
&vbG100,
"MGA-G100 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G100_AGP,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G100,
230000,
&vbG100,
"MGA-G100 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G100,
230000,
&vbG100,
"Productiva G100 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
0, 0,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G100,
230000,
&vbG100,
"unknown G100 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF,
0, 0,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G200,
250000,
&vbG200,
"unknown G200 (PCI)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G200,
220000,
&vbG200,
"MGA-G200 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G200,
230000,
&vbG200,
"Mystique G200 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G200,
250000,
&vbG200,
"Millennium G200 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G200,
230000,
&vbG200,
"Marvel G200 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G200,
230000,
&vbG200,
"MGA-G200 (AGP)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
0, 0,
- DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+ DEVF_G200,
230000,
&vbG200,
"unknown G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF,
+ 0, 0,
+ DEVF_G400,
+ 360000,
+ &vbG400,
+ "unknown G400 (AGP)"},
#endif
{0, 0, 0xFF,
0, 0,
NULL,
NULL}};
-__initfunc(static int initMatrox2(WPMINFO struct display* d, struct board* b)) {
+static int __init initMatrox2(WPMINFO struct display* d, struct board* b){
unsigned long ctrlptr_phys = 0;
unsigned long video_base_phys = 0;
unsigned int memsize;
ACCESS_FBINFO(devflags.vgastepdisp) = 64;
ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
}
+#ifdef CONFIG_FB_MATROX_32MB
+ ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
+#endif
+ ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
if (ACCESS_FBINFO(capable.cross4MB) < 0)
ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
if (b->flags & DEVF_SWAPS) {
- ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start & ~0x3FFF;
- video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start & ~0x7FFFFF; /* aligned at 8MB (or 16 for Mill 2) */
+ ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
+ video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
} else {
- ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start & ~0x3FFF;
- video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start & ~0x7FFFFF; /* aligned at 8MB */
+ ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
+ video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
}
if (!ctrlptr_phys) {
printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
return -ENOMEM;
}
ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
- if (ACCESS_FBINFO(video.len_usable) > 0x08000000)
- ACCESS_FBINFO(video.len_usable) = 0x08000000;
+ if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
+ ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
#ifdef CONFIG_MTRR
if (mtrr) {
ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
}
#endif /* CONFIG_MTRR */
+ if (!ACCESS_FBINFO(devflags.novga))
+ request_region(0x3C0, 32, "matrox");
+ ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
+
/* validate params, autodetect k, M */
if (fh < 1000) fh *= 1000; /* 1kHz minimum */
if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */
if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */
- vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */
+ if (vesa != ~0)
+ vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */
ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
}
{
int res = RSResolution(RSptr->info)-1;
- if (!left)
+ if (left == ~0)
left = timmings[res].left;
if (!xres)
xres = timmings[res].xres;
- if (!right)
+ if (right == ~0)
right = timmings[res].right;
if (!hslen)
hslen = timmings[res].hslen;
- if (!upper)
+ if (upper == ~0)
upper = timmings[res].upper;
if (!yres)
yres = timmings[res].yres;
- if (!lower)
+ if (lower == ~0)
lower = timmings[res].lower;
if (!vslen)
vslen = timmings[res].vslen;
if (depth == -1)
depth = RSDepth(RSptr->info);
}
+#if 0
if (sync == -1) {
sync = 0;
if (yres < 400)
else if (yres < 480)
sync |= FB_SYNC_VERT_HIGH_ACT;
}
- if (xres < 320)
- xres = 320;
- if (xres > 2048)
- xres = 2048;
- if (yres < 200)
- yres = 200;
- if (yres > 2048)
- yres = 2048;
- {
- unsigned int tmp;
-
- if (fv) {
- tmp = fv * (upper + yres + lower + vslen);
- if ((tmp < fh) || (fh == 0)) fh = tmp;
- }
- if (fh) {
- tmp = fh * (left + xres + right + hslen);
- if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
- }
- maxclk = (maxclk + 499) / 500;
- if (maxclk) {
- tmp = (2000000000 + maxclk) / maxclk;
- if (tmp > pixclock) pixclock = tmp;
- }
- }
+#endif
if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) {
strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8");
}
vesafb_defined.green = colors[depth-1].green;
vesafb_defined.blue = colors[depth-1].blue;
vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
- if (pixclock < 2000) /* > 500MHz */
- pixclock = 4000; /* 250MHz */
- if (pixclock > 1000000)
- pixclock = 1000000; /* 1MHz */
- vesafb_defined.xres = xres;
- vesafb_defined.yres = yres;
- vesafb_defined.xoffset = 0;
- vesafb_defined.yoffset = 0;
vesafb_defined.grayscale = grayscale;
- vesafb_defined.pixclock = pixclock;
- vesafb_defined.left_margin = left;
- vesafb_defined.right_margin = right;
- vesafb_defined.hsync_len = hslen;
- vesafb_defined.upper_margin = upper;
- vesafb_defined.lower_margin = lower;
- vesafb_defined.vsync_len = vslen;
- vesafb_defined.sync = sync;
vesafb_defined.vmode = 0;
-
- if (!ACCESS_FBINFO(devflags.novga))
- request_region(0x3C0, 32, "matrox");
if (noaccel)
vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
- ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
+
+#if 0
+ fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
+ NULL, 0, NULL, vesafb_defined.bits_per_pixel);
+#endif
+ /* mode modifiers */
+ if (sync != -1)
+ vesafb_defined.sync = sync;
+ if (hslen)
+ vesafb_defined.hsync_len = hslen;
+ if (vslen)
+ vesafb_defined.vsync_len = vslen;
+ if (left != ~0)
+ vesafb_defined.left_margin = left;
+ if (right != ~0)
+ vesafb_defined.right_margin = right;
+ if (upper != ~0)
+ vesafb_defined.upper_margin = upper;
+ if (lower != ~0)
+ vesafb_defined.lower_margin = lower;
+ if (xres)
+ vesafb_defined.xres = xres;
+ if (yres)
+ vesafb_defined.yres = yres;
+ /* fv, fh, maxclk limits was specified */
+ {
+ unsigned int tmp;
+
+ if (fv) {
+ tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
+ + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+ if ((tmp < fh) || (fh == 0)) fh = tmp;
+ }
+ if (fh) {
+ tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
+ + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+ if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+ }
+ maxclk = (maxclk + 499) / 500;
+ if (maxclk) {
+ tmp = (2000000000 + maxclk) / maxclk;
+ if (tmp > pixclock) pixclock = tmp;
+ }
+ }
+ if (pixclock) {
+ if (pixclock < 2000) /* > 500MHz */
+ pixclock = 4000; /* 250MHz */
+ if (pixclock > 1000000)
+ pixclock = 1000000; /* 1MHz */
+ vesafb_defined.pixclock = pixclock;
+ }
+
+ /* FIXME: Where to move this?! */
#if defined(CONFIG_FB_OF)
#if defined(CONFIG_FB_COMPAT_XPMAC)
strcpy(ACCESS_FBINFO(matrox_name), "MTRX,"); /* OpenFirmware naming convension */
#endif
if ((xres <= 640) && (yres <= 480)) {
struct fb_var_screeninfo var;
- int default_vmode = nvram_read_byte(NV_VMODE);
- int default_cmode = nvram_read_byte(NV_CMODE);
-
- if ((default_vmode <= 0) || (default_vmode > VMODE_MAX))
+ if (default_vmode == VMODE_NVRAM) {
+ default_vmode = nvram_read_byte(NV_VMODE);
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+ default_vmode = VMODE_CHOOSE;
+ }
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_640_480_60;
- if ((default_cmode < CMODE_8) || (default_cmode > CMODE_32))
+ if (default_cmode == CMODE_NVRAM)
+ default_cmode = nvram_read_byte(NV_CMODE);
+ if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
var.accel_flags = vesafb_defined.accel_flags;
var.xoffset = var.yoffset = 0;
vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */
- }
+ }
}
#endif
- {
- int pixel_size = vesafb_defined.bits_per_pixel;
-
- vesafb_defined.xres_virtual = matroxfb_pitch_adjust(PMINFO vesafb_defined.xres, pixel_size);
- if (nopan) {
- vesafb_defined.yres_virtual = vesafb_defined.yres;
- } else {
- vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
- to yres_virtual * xres_virtual < 2^32 */
- }
+ vesafb_defined.xres_virtual = vesafb_defined.xres;
+ if (nopan) {
+ vesafb_defined.yres_virtual = vesafb_defined.yres;
+ } else {
+ vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
+ to yres_virtual * xres_virtual < 2^32 */
}
if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
printk(KERN_ERR "matroxfb: cannot set required parameters\n");
/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
* and we do not want currcon == 0 for subsequent framebuffers */
- if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0)
+ if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
return -EINVAL;
+ }
printk("fb%d: %s frame buffer device\n",
GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
if (ACCESS_FBINFO(currcon) < 0) {
static struct matrox_fb_info* fb_list = NULL;
-__initfunc(static int matrox_init(void)) {
+static int __init matrox_init(void){
struct pci_dev* pdev = NULL;
DBG("matrox_init")
#ifndef MODULE
static int __init initialized = 0;
-__initfunc(void matroxfb_init(void))
+void __init matroxfb_init(void)
{
DBG("matroxfb_init")
initialized = 1;
matrox_init();
}
+ if (!fb_list) return -ENXIO;
+ return 0;
}
#if defined(CONFIG_FB_OF)
-__initfunc(int matrox_of_init(struct device_node *dp)) {
+int __init matrox_of_init(struct device_node *dp){
DBG("matrox_of_init");
if (!initialized) {
#else
-MODULE_AUTHOR("(c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200");
+MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400");
MODULE_PARM(mem, "i");
MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
MODULE_PARM(disabled, "i");
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 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+MODULE_PARM_DESC(sgram, "Indicates that 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");
MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
MODULE_PARM(cross4MB, "i");
MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
+#ifdef CONFIG_FB_OF
+MODULE_PARM(vmode, "i");
+MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
+MODULE_PARM(cmode, "i");
+MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
+#endif
-__initfunc(int init_module(void)) {
+int __init init_module(void){
DBG("init_module")
#ifdef DEBUG
if( disabled )
- return 0;
+ return -ENXIO;
#endif /* DEBUG */
if (depth == 0)
#ifndef MODULE
-__initfunc(void mdacon_setup(char *str, int *ints))
+void __init mdacon_setup(char *str, int *ints)
{
/* command line format: mdacon=<first>,<last> */
#ifdef MODULE
static int mda_detect(void)
#else
-__initfunc(static int mda_detect(void))
+static int __init mda_detect(void)
#endif
{
int count=0;
#ifdef MODULE
static void mda_initialize(void)
#else
-__initfunc(static void mda_initialize(void))
+static void __init mda_initialize(void)
#endif
{
write_mda_b(97, 0x00); /* horizontal total */
#ifdef MODULE
static const char *mdacon_startup(void)
#else
-__initfunc(static const char *mdacon_startup(void))
+static const char __init *mdacon_startup(void)
#endif
{
mda_num_columns = 80;
#ifdef MODULE
void mda_console_init(void)
#else
-__initfunc(void mda_console_init(void))
+void __init mda_console_init(void)
#endif
{
if (mda_first_vc > mda_last_vc)
* Initialisation
*/
-__initfunc(void offb_init(void))
+void __init offb_init(void)
{
struct device_node *dp;
unsigned int dpy;
}
}
-__initfunc(static int offb_init_driver(struct device_node *dp))
+static int __init offb_init_driver(struct device_node *dp)
{
#ifdef CONFIG_FB_ATY
if (!strncmp(dp->name, "ATY", 3)) {
return 0;
}
-__initfunc(static void offb_init_nodriver(struct device_node *dp))
+static void __init offb_init_nodriver(struct device_node *dp)
{
int *pp, i;
unsigned int len;
}
-__initfunc(static void offb_init_fb(const char *name, const char *full_name,
+static void offb_init_fb(const char *name, const char *full_name,
int width, int height, int depth,
- int pitch, unsigned long address))
+ int pitch, unsigned long address)
{
int i;
struct fb_fix_screeninfo *fix;
}
-__initfunc(static int init_platinum(struct fb_info_platinum *info))
+static int __init init_platinum(struct fb_info_platinum *info)
{
struct fb_var_screeninfo var;
struct display *disp;
return 1;
}
-__initfunc(void platinum_init(void))
+void __init platinum_init(void)
{
#ifndef CONFIG_FB_OF
struct device_node *dp;
#define invalidate_cache(addr)
#endif
-__initfunc(void platinum_of_init(struct device_node *dp))
+void __init platinum_of_init(struct device_node *dp)
{
struct fb_info_platinum *info;
unsigned long addr, size;
/*
* Parse user speficied options (`video=platinumfb:')
*/
-__initfunc(void platinum_setup(char *options, int *ints))
+void __init platinum_setup(char *options, int *ints)
{
char *this_opt;
set_memclock(p, p->memclock);
}
-__initfunc(static int pm2fb_conf(struct pm2fb_info* p)) {
+static int __init pm2fb_conf(struct pm2fb_info* p){
for (p->board=0; board_table[p->board].detect &&
!(board_table[p->board].detect(p)); p->board++);
}
static void pm2fb_set_disp(const void* par, struct display* disp,
- struct fb_info_gen* info) {
+ struct fb_info_gen* info) {
struct pm2fb_info* i=(struct pm2fb_info* )info;
- u32 flags;
- u32 depth;
+ unsigned long flags;
+ unsigned long depth;
save_flags(flags);
cli();
- disp->screen_base=i->regions.v_fb;
+ disp->screen_base = i->regions.v_fb;
switch (depth=((struct pm2fb_par* )par)->depth) {
#ifdef FBCON_HAS_CFB8
case 8:
board_table[i->board].cleanup(i);
}
-__initfunc(void pm2fb_init(void)) {
+void __init pm2fb_init(void){
memset(&fb_info, 0, sizeof(fb_info));
if (!pm2fb_conf(&fb_info))
MOD_INC_USE_COUNT;
}
-__initfunc(void pm2fb_mode_setup(char* options)) {
+void __init pm2fb_mode_setup(char* options){
int i;
for (i=0; user_mode[i].name[0] &&
sizeof(pm2fb_options.user_mode));
}
-__initfunc(void pm2fb_font_setup(char* options)) {
+void __init pm2fb_font_setup(char* options){
strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
}
-__initfunc(void pm2fb_setup(char* options, int* ints)) {
+void __init pm2fb_setup(char* options, int* ints){
char* next;
while (options) {
return b - p;
}
-__initfunc(const char *promcon_startup(void))
+const char __init *promcon_startup(void)
{
const char *display_desc = "PROM";
int node;
return display_desc;
}
-__initfunc(static void
-promcon_init_unimap(struct vc_data *conp))
+static void __init
+promcon_init_unimap(struct vc_data *conp)
{
mm_segment_t old_fs = get_fs();
struct unipair *p, *p1;
con_invert_region: NULL,
};
-__initfunc(void prom_con_init(void))
+void __init prom_con_init(void)
{
#ifdef CONFIG_DUMMY_CONSOLE
if (conswitchp == &dummy_con)
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+
+#include <asm/uaccess.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/module.h>
#include <asm/pgtable.h>
+#include <video/fbcon.h>
#include <video/fbcon-cfb16.h>
+#define FBIOSETSCROLLMODE 0x4611
#define Q40_PHYS_SCREEN_ADDR 0xFE800000
static unsigned long q40_screen_addr;
blue>>=10;
if (regno < 16) {
- fbcon_cmap_cfb16[regno] = ((red & 31) <<5) |
+ fbcon_cmap_cfb16[regno] = ((red & 31) <<6) |
((green & 31) << 11) |
(blue & 63);
}
unsigned int cmd, unsigned long arg, int con,
struct fb_info *info)
{
+#if 0
+ unsigned long i;
+ struct display *display;
+
+ if (con>=0)
+ display = &fb_display[con];
+ else
+ display = &disp[0];
+
+ if (cmd == FBIOSETSCROLLMODE)
+ {
+ i = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned long));
+ if (!i)
+ {
+ copy_from_user(&i, (void *)arg, sizeof(unsigned long));
+ display->scrollmode = i;
+ }
+ q40_updatescrollmode(display);
+ return i;
+ }
+#endif
return -EINVAL;
}
display->inverse = 0;
display->line_length = fix.line_length;
+ display->scrollmode = SCROLL_YREDRAW;
+
#ifdef FBCON_HAS_CFB16
display->dispsw = &fbcon_cfb16;
disp->dispsw_data = fbcon_cmap_cfb16;
void q40fb_init(void)
{
+
+ if ( !MACH_IS_Q40)
+ return;
#if 0
q40_screen_addr = kernel_map(Q40_PHYS_SCREEN_ADDR, 1024*1024,
KERNELMAP_NO_COPYBACK, NULL);
unsigned long physregs;
int currcon;
int current_par_valid; /* set to 0 by memset */
+ int blitbusy;
struct display disp;
struct retz3fb_par current_par;
unsigned char color_table [256][3];
"640x480", { /* 640x480, 8 bpp */
640, 480, 640, 480, 0, 0, 8, 0,
{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-#if 1
0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2,
-#else
- 0, 0, -1, -1, FB_ACCELF_TEXT, 38461, 28, 32, 12, 10, 96, 2,
-#endif
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
}
},
* Interface used by the world
*/
-void retz3fb_setup(char *options, int *ints);
+void retz3fb_setup(char *options);
static int retz3fb_open(struct fb_info *info, int user);
static int retz3fb_release(struct fb_info *info, int user);
static int get_video_mode(const char *name);
-/* -------------------- Hardware specific routines -------------------------- */
+/* -------------------- Hardware specific routines ------------------------- */
static unsigned short find_fq(unsigned int freq)
{
}
+static inline void retz3_busy(struct display *p)
+{
+ struct retz3_fb_info *zinfo = retz3info(p->fb_info);
+ volatile unsigned char *acm = zinfo->base + ACM_OFFSET;
+ unsigned char blt_status;
+
+ if (zinfo->blitbusy) {
+ do{
+ blt_status = *((acm) + (ACM_START_STATUS + 2));
+ }while ((blt_status & 1) == 0);
+ zinfo->blitbusy = 0;
+ }
+}
+
+
static void retz3_bitblt (struct display *p,
unsigned short srcx, unsigned short srcy,
unsigned short destx, unsigned short desty,
unsigned short mod;
unsigned long tmp;
unsigned long pat, src, dst;
- unsigned char blt_status;
int i, xres_virtual = var->xres_virtual;
short bpp = (var->bits_per_pixel & 0xff);
tmp = mask | (mask << 16);
-#if 0
- /*
- * Check for blitter finished before we start messing with the
- * pattern.
- */
- do{
- blt_status = *(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2));
- }while ((blt_status & 1) == 0);
-#endif
+ retz3_busy(p);
i = 0;
do{
*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
-
- /*
- * No reason to wait for the blitter to finish, it is better
- * just to check if it has finished before we use it again.
- */
-#if 1
-#if 0
- while ((*(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2)) & 1) == 0);
-#else
- do{
- blt_status = *(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2));
- }
- while ((blt_status & 1) == 0);
-#endif
-#endif
+ zinfo->blitbusy = 1;
}
#if 0
}
-#if 1
static void retz3fb_set_disp(int con, struct fb_info *info)
{
struct fb_fix_screeninfo fix;
break;
}
}
-#endif
/*
};
-__initfunc(void retz3fb_setup(char *options, int *ints))
+void __init retz3fb_setup(char *options, int *ints)
{
char *this_opt;
} else if (!strncmp(this_opt, "font:", 5)) {
strncpy(fontname, this_opt+5, 39);
fontname[39] = '\0';
- }else
+ } else
z3fb_mode = get_video_mode(this_opt);
}
}
* Initialization
*/
-__initfunc(void retz3fb_init(void))
+void __init retz3fb_init(void)
{
unsigned long board_addr, board_size;
unsigned int key;
* Get a Video Mode
*/
-__initfunc(static int get_video_mode(const char *name))
+static int __init get_video_mode(const char *name)
{
short i;
- for (i = 0; i <= NUM_TOTAL_MODES; i++)
+ for (i = 0; i < NUM_TOTAL_MODES; i++)
if (!strcmp(name, retz3fb_predefined[i].name)){
retz3fb_default = retz3fb_predefined[i].var;
return i;
*/
#ifdef FBCON_HAS_CFB8
-static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx,
- int dy, int dx, int height, int width)
+static void retz3_8_bmove(struct display *p, int sy, int sx,
+ int dy, int dx, int height, int width)
{
int fontwidth = fontwidth(p);
0xffff);
}
-static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p,
- int sy, int sx, int height, int width)
+static void retz3_8_clear(struct vc_data *conp, struct display *p,
+ int sy, int sx, int height, int width)
{
unsigned short col;
int fontwidth = fontwidth(p);
col);
}
+
+static void retz3_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+ retz3_busy(p);
+ fbcon_cfb8_putc(conp, p, c, yy, xx);
+}
+
+
+static void retz3_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count,
+ int yy, int xx)
+{
+ retz3_busy(p);
+ fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
+}
+
+
+static void retz3_revc(struct display *p, int xx, int yy)
+{
+ retz3_busy(p);
+ fbcon_cfb8_revc(p, xx, yy);
+}
+
+
+static void retz3_clear_margins(struct vc_data* conp, struct display* p,
+ int bottom_only)
+{
+ retz3_busy(p);
+ fbcon_cfb8_clear_margins(conp, p, bottom_only);
+}
+
+
static struct display_switch fbcon_retz3_8 = {
- fbcon_cfb8_setup, fbcon_retz3_8_bmove, fbcon_retz3_8_clear,
- fbcon_cfb8_putc, fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL,
- fbcon_cfb8_clear_margins, FONTWIDTH(8)
+ fbcon_cfb8_setup, retz3_8_bmove, retz3_8_clear,
+ retz3_putc, retz3_putcs, retz3_revc, NULL, NULL,
+ retz3_clear_margins, FONTWIDTH(8)
};
#endif
* Setup: parse used options
*/
-__initfunc(void sbusfb_setup(char *options, int *ints))
+void __init sbusfb_setup(char *options, int *ints)
{
char *p;
extern void (*prom_palette)(int);
-__initfunc(static void sbusfb_init_fb(int node, int parent, int fbtype,
- struct linux_sbus_device *sbdp))
+static void __init sbusfb_init_fb(int node, int parent, int fbtype,
+ struct linux_sbus_device *sbdp)
{
struct fb_fix_screeninfo *fix;
struct fb_var_screeninfo *var;
return FBTYPE_NOTYPE;
}
-__initfunc(void sbusfb_init(void))
+void __init sbusfb_init(void)
{
int type;
struct linux_sbus_device *sbdp;
return 0;
}
-__initfunc(void sgivwfb_setup(char *options, int *ints))
+void __init sgivwfb_setup(char *options, int *ints)
{
char *this_opt;
/*
* Initialisation
*/
-__initfunc(void sgivwfb_init(void))
+void __init sgivwfb_init(void)
{
printk("sgivwfb: framebuffer at 0x%lx, size %ldk\n",
sgivwfb_mem_phys, sgivwfb_mem_size/1024);
* Initialization
*/
-__initfunc(void xxxfb_init(void))
+void __init xxxfb_init(void)
{
fb_info.gen.fbhw = &xxx_switch;
fb_info.gen.fbhw->detect();
* Setup
*/
-__initfunc(void xxxfb_setup(char *options, int *ints))
+void __init xxxfb_setup(char *options, int *ints)
{
/* Parse user speficied options (`video=xxxfb:') */
}
static char idstring[60] __initdata = { 0 };
-__initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb))
+char __init *tcxfb_init(struct fb_info_sbusfb *fb)
{
struct fb_fix_screeninfo *fix = &fb->fix;
struct display *disp = &fb->disp;
}
}
-__initfunc(static void init_valkyrie(struct fb_info_valkyrie *p))
+static void __init init_valkyrie(struct fb_info_valkyrie *p)
{
struct fb_par_valkyrie *par = &p->par;
struct fb_var_screeninfo var;
#endif /* CONFIG_FB_COMPAT_XPMAC */
}
-__initfunc(void valkyriefb_init(void))
+void __init valkyriefb_init(void)
{
#ifndef CONFIG_FB_OF
struct device_node *dp;
#endif /* CONFIG_FB_OF */
}
-__initfunc(void valkyrie_of_init(struct device_node *dp))
+void __init valkyrie_of_init(struct device_node *dp)
{
struct fb_info_valkyrie *p;
unsigned long addr, size;
/*
* Parse user speficied options (`video=valkyriefb:')
*/
-__initfunc(void valkyriefb_setup(char *options, int *ints))
+void __init valkyriefb_setup(char *options, int *ints)
{
char *this_opt;
static int currcon = 0;
static int pmi_setpal = 0; /* pmi for palette changes ??? */
-static int ypan = 0;
-static int ywrap = 0;
+static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */
static unsigned short *pmi_base = 0;
static void (*pmi_start)(void);
static void (*pmi_pal)(void);
{
int offset;
- if (!ypan && !ywrap)
+ if (!ypan)
return -EINVAL;
if (var->xoffset)
return -EINVAL;
- if (ypan && var->yoffset+var->yres > var->yres_virtual)
+ if (var->yoffset > var->yres_virtual)
return -EINVAL;
- if (ywrap && var->yoffset > var->yres_virtual)
+ if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual)
return -EINVAL;
offset = (var->yoffset * video_linelength + var->xoffset) / 4;
static int vesafb_update_var(int con, struct fb_info *info)
{
- if (con == currcon && (ywrap || ypan)) {
+ if (con == currcon && ypan) {
struct fb_var_screeninfo *var = &fb_display[currcon].var;
return vesafb_pan_display(var,con,info);
}
fix->type = video_type;
fix->visual = video_visual;
fix->xpanstep = 0;
- fix->ypanstep = (ywrap || ypan) ? 1 : 0;
- fix->ywrapstep = ywrap ? 1 : 0;
+ fix->ypanstep = ypan ? 1 : 0;
+ fix->ywrapstep = (ypan>1) ? 1 : 0;
fix->line_length=video_linelength;
return 0;
}
}
memcpy(&vesafb_sw, sw, sizeof(*sw));
display->dispsw = &vesafb_sw;
- if (!ypan && !ywrap) {
+ if (!ypan) {
display->scrollmode = SCROLL_YREDRAW;
vesafb_sw.bmove = fbcon_redraw_bmove;
}
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
return 0;
- if (ypan || ywrap) {
+ if (ypan) {
if (vesafb_defined.yres_virtual != var->yres_virtual) {
vesafb_defined.yres_virtual = var->yres_virtual;
if (con != -1) {
if (! strcmp(this_opt, "inverse"))
inverse=1;
else if (! strcmp(this_opt, "redraw"))
- ywrap=0,ypan=0;
+ ypan=0;
else if (! strcmp(this_opt, "ypan"))
- ywrap=0,ypan=1;
+ ypan=1;
else if (! strcmp(this_opt, "ywrap"))
- ywrap=1,ypan=0;
+ ypan=2;
else if (! strcmp(this_opt, "vgapal"))
pmi_setpal=0;
else if (! strcmp(this_opt, "pmipal"))
/* Not supported */
}
-__initfunc(void vesafb_init(void))
+void __init vesafb_init(void)
{
int i,j;
}
if (screen_info.vesapm_seg < 0xc000)
- ywrap = ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
+ ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
- if (ypan || ywrap || pmi_setpal) {
+ if (ypan || pmi_setpal) {
pmi_base = (unsigned short*)(__PAGE_OFFSET+((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
* memory area and pass it in the ES register to the BIOS function.
*/
printk("vesafb: can't handle memory requests, pmi disabled\n");
- ywrap = ypan = pmi_setpal = 0;
+ ypan = pmi_setpal = 0;
}
}
}
vesafb_defined.yres_virtual=video_size / video_linelength;
vesafb_defined.bits_per_pixel=video_bpp;
- if ((ypan || ywrap) && vesafb_defined.yres_virtual > video_height) {
+ if (ypan && vesafb_defined.yres_virtual > video_height) {
printk("vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n",
- ywrap ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
+ (ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
} else {
printk("vesafb: scrolling: redraw\n");
vesafb_defined.yres_virtual = video_height;
- ypan = ywrap = 0;
+ ypan = 0;
}
video_height_virtual = vesafb_defined.yres_virtual;
}
-__initfunc(void vfb_setup(char *options, int *ints))
+void __init vfb_setup(char *options, int *ints)
{
char *this_opt;
* Initialisation
*/
-__initfunc(void vfb_init(void))
+void __init vfb_init(void)
{
if (!vfb_enable)
return;
}
}
-__initfunc(void vga16fb_init(void))
+void __init vga16_init(void)
{
int i,j;
vga16fb_set_disp(-1, &vga16fb);
if (register_framebuffer(&vga16fb.fb_info)<0)
- return;
+ return -EINVAL;
printk("fb%d: %s frame buffer device\n",
GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
+
+ return 0;
+}
+
+#ifndef MODULE
+__initfunc(void vga16fb_init(void))
+{
+ vga16_init();
}
+#else /* MODULE */
+
+__initfunc(int init_module(void))
+{
+ return vga16_init();
+}
+
+void cleanup_module(void)
+{
+ unregister_framebuffer(&vga16fb.fb_info);
+ release_region(0x3c0, 32);
+ iounmap(vga16fb.video_vbase);
+}
+
+#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
restore_flags(flags);
}
-__initfunc(static const char *vgacon_startup(void))
+static const char __init *vgacon_startup(void)
{
const char *display_desc = NULL;
u16 saved1, saved2;
(*((unsigned word volatile *)(CyberRegs + reg)) = dat)
#define wl_3d(reg,dat) \
(*((unsigned long volatile *)(CyberRegs + reg)) = dat)
-
#define rl_3d(reg) \
(*((unsigned long volatile *)(CyberRegs + reg)))
+#define Select_Zorro2_FrameBuffer(flag) \
+ do { \
+ *((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x08)) = \
+ ((flag * 0x40) & 0xffff); asm volatile ("nop"); \
+ } while (0)
+/*
+ * may be needed when we initialize the board?
+ * 8bit: flag = 2, 16 bit: flag = 1, 24/32bit: flag = 0
+ * _when_ the board is initialized, depth doesnt matter, we allways write
+ * to the same address, aperture seems not to matter on Z2.
+ */
+
struct virgefb_par {
int xres;
int yres;
* Predefined Video Modes
*/
-static struct fb_videomode virgefb_predefined[] __initdata = {
+static struct {
+ const char *name;
+ struct fb_var_screeninfo var;
+} virgefb_predefined[] __initdata = {
{
"640x480-8", { /* Cybervision 8 bpp */
640, 480, 640, 480, 0, 0, 8, 0,
"1024x768-16", { /* Cybervision 16 bpp */
1024, 768, 1024, 768, 0, 0, 16, 0,
{11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ 0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
}
}, {
"1152x886-16", { /* Cybervision 16 bpp */
1152, 886, 1152, 886, 0, 0, 16, 0,
{11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ 0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
}
}, {
"1280x1024-16", { /* Cybervision 16 bpp */
1280, 1024, 1280, 1024, 0, 0, 16, 0,
{11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ 0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
}
}, {
"1600x1200-16", { /* Cybervision 16 bpp */
1600, 1200, 1600, 1200, 0, 0, 16, 0,
{11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ 0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
}
}
static int Cyberfb_inverse = 0;
-#if 0
-static int Cyberfb_Cyber8 = 0; /* Use Cybervision board */
-static int Cyberfb_Cyber16 = 0; /* Use Cybervision board */
-#endif
/*
* Some default modes
} else {
CyberSize = 0x00400000; /* 4 MB */
}
+
memset ((char*)CyberMem, 0, CyberSize);
/* Disable hardware cursor */
* CV3D low-level support
*/
-#define Cyber3D_WaitQueue(v) { do { while ((rl_3d(0x8504) & 0x1f00) < (((v)+2) << 8)); } while (0); }
+#define Cyber3D_WaitQueue(v) \
+{ \
+ do { \
+ while ((rl_3d(0x8504) & 0x1f00) < (((v)+2) << 8)); \
+ } \
+ while (0); \
+}
static inline void Cyber3D_WaitBusy(void)
{
*/
static void Cyber3D_BitBLT(u_short curx, u_short cury, u_short destx,
- u_short desty, u_short width, u_short height)
+ u_short desty, u_short width, u_short height, u_short depth)
{
- unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_DST_8BPP;
+ unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_BLT_COPY;
- blitcmd |= S3V_BLT_COPY;
+ switch (depth) {
+#ifdef FBCON_HAS_CFB8
+ case 8 :
+ blitcmd |= S3V_DST_8BPP;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16 :
+ blitcmd |= S3V_DST_16BPP;
+ break;
+#endif
+ }
/* Set drawing direction */
/* -Y, X maj, -X (default) */
*/
static void Cyber3D_RectFill(u_short x, u_short y, u_short width,
- u_short height, u_short color)
+ u_short height, u_short color, u_short depth)
{
unsigned int tmp;
- unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW | S3V_DST_8BPP |
+ unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW |
S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25);
if (blit_maybe_busy)
Cyber3D_WaitBusy();
blit_maybe_busy = 1;
+ switch (depth) {
+#ifdef FBCON_HAS_CFB8
+ case 8 :
+ blitcmd |= S3V_DST_8BPP;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16 :
+ blitcmd |= S3V_DST_16BPP;
+ break;
+#endif
+ }
+
tmp = color & 0xff;
wl_3d(0xa4f4, tmp);
};
-__initfunc(void virgefb_setup(char *options, int *ints))
+void __init virgefb_setup(char *options, int *ints)
{
char *this_opt;
* Initialization
*/
-__initfunc(void virgefb_init(void))
+void __init virgefb_init(void)
{
struct virgefb_par par;
unsigned long board_addr;
else
{
CyberVGARegs = (unsigned long)ioremap(board_addr +0x0c000000, 0x00010000);
-
CyberRegs_phys = board_addr + 0x05000000;
CyberMem_phys = board_addr + 0x04000000; /* was 0x04800000 */
CyberRegs = ioremap(CyberRegs_phys, 0x00010000);
* Get a Video Mode
*/
-__initfunc(static int get_video_mode(const char *name))
+static int __init get_video_mode(const char *name)
{
int i;
sx *= 8; dx *= 8; width *= 8;
Cyber3D_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
(u_short)(dy*fontheight(p)), (u_short)width,
- (u_short)(height*fontheight(p)));
+ (u_short)(height*fontheight(p)), 8);
}
static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy,
bg = attr_bgcol_ec(p,conp);
Cyber3D_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
(u_short)width, (u_short)(height*fontheight(p)),
- (u_short)bg);
+ (u_short)bg, 8);
}
static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy,
static void fbcon_virge16_bmove(struct display *p, int sy, int sx, int dy,
int dx, int height, int width)
{
- sx *= 16; dx *= 16; width *= 16;
+ sx *= 8; dx *= 8; width *= 8;
Cyber3D_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
(u_short)(dy*fontheight(p)), (u_short)width,
- (u_short)(height*fontheight(p)));
+ (u_short)(height*fontheight(p)), 16);
}
static void fbcon_virge16_clear(struct vc_data *conp, struct display *p, int sy,
{
unsigned char bg;
- sx *= 16; width *= 16;
+ sx *= 8; width *= 8;
bg = attr_bgcol_ec(p,conp);
Cyber3D_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
(u_short)width, (u_short)(height*fontheight(p)),
- (u_short)bg);
+ (u_short)bg, 16);
}
static void fbcon_virge16_putc(struct vc_data *conp, struct display *p, int c, int yy,
* pressures on different devices - thus the (currently unused)
* 'dev' parameter.
*/
-int too_many_dirty_buffers;
+static int too_many_dirty_buffers;
void balance_dirty(kdev_t dev)
{
return err;
}
+/*
+ * For moronic filesystems that do not allow holes in file.
+ * we allow offset==PAGE_SIZE, bytes==0
+ */
+
+int block_write_cont_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ unsigned long block;
+ int err, partial;
+ unsigned long blocksize, start_block, end_block;
+ unsigned long start_offset, start_bytes, end_bytes;
+ unsigned long bbits, blocks, i, len;
+ struct buffer_head *bh, *head;
+ char * target_buf, *target_data;
+ unsigned long data_offset = offset;
+
+ offset = page->offset-inode->i_size;
+ if (offset < 0)
+ offset = 0;
+ else if (offset >= data_offset)
+ offset = data_offset;
+ bytes += data_offset-offset;
+
+ target_buf = (char *)page_address(page) + offset;
+ target_data = (char *)page_address(page) + data_offset;
+
+ if (!PageLocked(page))
+ BUG();
+
+ blocksize = inode->i_sb->s_blocksize;
+ if (!page->buffers)
+ create_empty_buffers(page, inode, blocksize);
+ head = page->buffers;
+
+ bbits = inode->i_sb->s_blocksize_bits;
+ block = page->offset >> bbits;
+ blocks = PAGE_SIZE >> bbits;
+ start_block = offset >> bbits;
+ end_block = (offset + bytes - 1) >> bbits;
+ start_offset = offset & (blocksize - 1);
+ start_bytes = blocksize - start_offset;
+ if (start_bytes > bytes)
+ start_bytes = bytes;
+ end_bytes = (offset+bytes) & (blocksize - 1);
+ if (end_bytes > bytes)
+ end_bytes = bytes;
+
+ if (offset < 0 || offset > PAGE_SIZE)
+ BUG();
+ if (bytes+offset < 0 || bytes+offset > PAGE_SIZE)
+ BUG();
+ if (start_block < 0 || start_block > blocks)
+ BUG();
+ if (end_block < 0 || end_block >= blocks)
+ BUG();
+ // FIXME: currently we assume page alignment.
+ if (page->offset & (PAGE_SIZE-1))
+ BUG();
+
+ i = 0;
+ bh = head;
+ partial = 0;
+ do {
+ if (!bh)
+ BUG();
+
+ if ((i < start_block) || (i > end_block)) {
+ if (!buffer_uptodate(bh))
+ partial = 1;
+ goto skip;
+ }
+
+ /*
+ * If the buffer is not up-to-date, we need to ask the low-level
+ * FS to do something for us (we used to have assumptions about
+ * the meaning of b_blocknr etc, that's bad).
+ *
+ * If "update" is set, that means that the low-level FS should
+ * try to make sure that the block is up-to-date because we're
+ * not going to fill it completely.
+ */
+ bh->b_end_io = end_buffer_io_sync;
+ if (!buffer_mapped(bh)) {
+ err = inode->i_op->get_block(inode, block, bh, 1);
+ if (err)
+ goto out;
+ }
+
+ if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
+ if (buffer_new(bh)) {
+ memset(bh->b_data, 0, bh->b_size);
+ } else {
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ err = -EIO;
+ if (!buffer_uptodate(bh))
+ goto out;
+ }
+ }
+
+ len = blocksize;
+ if (start_offset) {
+ len = start_bytes;
+ start_offset = 0;
+ } else if (end_bytes && (i == end_block)) {
+ len = end_bytes;
+ end_bytes = 0;
+ }
+ err = 0;
+ if (target_buf+len<=target_data)
+ memset(target_buf, 0, len);
+ else if (target_buf<target_data) {
+ memset(target_buf, 0, target_data-target_buf);
+ copy_from_user(target_data, buf,
+ len+target_buf-target_data);
+ } else
+ err = copy_from_user(target_buf, buf, len);
+ target_buf += len;
+ buf += len;
+
+ /*
+ * we dirty buffers only after copying the data into
+ * the page - this way we can dirty the buffer even if
+ * the bh is still doing IO.
+ *
+ * NOTE! This also does a direct dirty balace check,
+ * rather than relying on bdflush just waking up every
+ * once in a while. This is to catch (and slow down)
+ * the processes that write tons of buffer..
+ *
+ * Note how we do NOT want to do this in the full block
+ * case: full pages are flushed not by the people who
+ * dirtied them, but by people who need memory. And we
+ * should not penalize them for somebody else writing
+ * lots of dirty pages.
+ */
+ set_bit(BH_Uptodate, &bh->b_state);
+ if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
+ __mark_dirty(bh, 0);
+ if (too_many_dirty_buffers)
+ balance_dirty(bh->b_dev);
+ }
+
+ if (err) {
+ err = -EFAULT;
+ goto out;
+ }
+
+skip:
+ i++;
+ block++;
+ bh = bh->b_this_page;
+ } while (bh != head);
+
+ /*
+ * is this a partial write that happened to make all buffers
+ * uptodate then we can optimize away a bogus readpage() for
+ * the next read(). Here we 'discover' wether the page went
+ * uptodate as a result of this (potentially partial) write.
+ */
+ if (!partial)
+ SetPageUptodate(page);
+ return bytes;
+out:
+ ClearPageUptodate(page);
+ return err;
+}
+
/*
* IO completion routine for a buffer_head being used for kiobuf IO: we
if (!(page = __get_free_page(GFP_BUFFER)))
return 0;
bh = create_buffers(page, size, 0);
- if (!bh) {
- free_page(page);
- return 0;
- }
+ if (!bh)
+ goto no_buffer_head;
isize = BUFSIZE_INDEX(size);
mem_map[MAP_NR(page)].buffers = bh;
atomic_add(PAGE_SIZE, &buffermem);
return 1;
+
+no_buffer_head:
+ free_page(page);
+ return 0;
}
/*
*/
atomic_inc(&bh->b_count);
spin_unlock(&lru_list_lock);
- if (major == LOOP_MAJOR && written > 1) {
- ll_rw_block(WRITEA, 1, &bh);
- if (buffer_dirty(bh))
- --written;
- } else
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(WRITE, 1, &bh);
atomic_dec(&bh->b_count);
goto repeat;
}
# define PRINTK(x)
#endif
-struct buffer_head *fat_bread (
+struct buffer_head *fat_bread(struct super_block *sb, int block)
+{
+ return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
+}
+struct buffer_head *fat_getblk(struct super_block *sb, int block)
+{
+ return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
+}
+void fat_brelse (struct super_block *sb, struct buffer_head *bh)
+{
+ if (bh)
+ MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
+}
+void fat_mark_buffer_dirty (
struct super_block *sb,
- int block)
+ struct buffer_head *bh,
+ int dirty)
{
- struct buffer_head *ret = NULL;
-
- PRINTK(("fat_bread: block=0x%x\n", block));
- /*
- * Note that the blocksize is 512, 1024 or 2048, but the first read
- * is always of size 1024 (or 2048). Doing readahead may be
- * counterproductive or just plain wrong.
- */
+ MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty);
+}
+void fat_set_uptodate (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int val)
+{
+ MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
+}
+int fat_is_uptodate(struct super_block *sb, struct buffer_head *bh)
+{
+ return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
+}
+void fat_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32])
+{
+ MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
+}
- if(MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_bread)
- return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
+struct buffer_head *default_fat_bread(struct super_block *sb, int block)
+{
+ return bread (sb->s_dev,block,512);
+}
+struct buffer_head *default_fat_getblk(struct super_block *sb, int block)
+{
+ return getblk (sb->s_dev,block,512);
+}
+void default_fat_brelse(struct super_block *sb, struct buffer_head *bh)
+{
+ brelse (bh);
+}
+void default_fat_mark_buffer_dirty (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int dirty)
+{
+ mark_buffer_dirty (bh,dirty);
+}
+void default_fat_set_uptodate (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int val)
+{
+ mark_buffer_uptodate(bh, val);
+}
+int default_fat_is_uptodate (struct super_block *sb, struct buffer_head *bh)
+{
+ return buffer_uptodate(bh);
+}
+void default_fat_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32])
+{
+ ll_rw_block(opr,nbreq,bh);
+}
- if (sb->s_blocksize == 512) {
- ret = bread (sb->s_dev,block,512);
+struct buffer_head *bigblock_fat_bread (
+ struct super_block *sb,
+ int block)
+{
+ struct buffer_head *ret = NULL;
+ struct buffer_head *real;
+ if (sb->s_blocksize == 1024){
+ real = bread (sb->s_dev,block>>1,1024);
} else {
- struct buffer_head *real;
- if (sb->s_blocksize == 1024){
- real = bread (sb->s_dev,block>>1,1024);
- } else {
- real = bread (sb->s_dev,block>>2,2048);
- }
-
- if (real != NULL){
- ret = (struct buffer_head *)
- kmalloc (sizeof(struct buffer_head), GFP_KERNEL);
- if (ret != NULL) {
- /* #Specification: msdos / strategy / special device / dummy blocks
- * Many special device (Scsi optical disk for one) use
- * larger hardware sector size. This allows for higher
- * capacity.
-
- * Most of the time, the MS-DOS filesystem that sits
- * on this device is totally unaligned. It use logically
- * 512 bytes sector size, with logical sector starting
- * in the middle of a hardware block. The bad news is
- * that a hardware sector may hold data own by two
- * different files. This means that the hardware sector
- * must be read, patch and written almost all the time.
-
- * Needless to say that it kills write performance
- * on all OS.
-
- * Internally the linux msdos fs is using 512 bytes
- * logical sector. When accessing such a device, we
- * allocate dummy buffer cache blocks, that we stuff
- * with the information of a real one (1k large).
+ real = bread (sb->s_dev,block>>2,2048);
+ }
- * This strategy is used to hide this difference to
- * the core of the msdos fs. The slowdown is not
- * hidden though!
- */
- /*
- * The memset is there only to catch errors. The msdos
- * fs is only using b_data
- */
- memset (ret,0,sizeof(*ret));
- ret->b_data = real->b_data;
- if (sb->s_blocksize == 2048) {
- if (block & 3) ret->b_data += (block & 3) << 9;
- }else{
- if (block & 1) ret->b_data += 512;
- }
- ret->b_next = real;
+ if (real != NULL) {
+ ret = (struct buffer_head *)
+ kmalloc (sizeof(struct buffer_head), GFP_KERNEL);
+ if (ret != NULL) {
+ /* #Specification: msdos / strategy / special device / dummy blocks
+ * Many special device (Scsi optical disk for one) use
+ * larger hardware sector size. This allows for higher
+ * capacity.
+
+ * Most of the time, the MS-DOS filesystem that sits
+ * on this device is totally unaligned. It use logically
+ * 512 bytes sector size, with logical sector starting
+ * in the middle of a hardware block. The bad news is
+ * that a hardware sector may hold data own by two
+ * different files. This means that the hardware sector
+ * must be read, patch and written almost all the time.
+
+ * Needless to say that it kills write performance
+ * on all OS.
+
+ * Internally the linux msdos fs is using 512 bytes
+ * logical sector. When accessing such a device, we
+ * allocate dummy buffer cache blocks, that we stuff
+ * with the information of a real one (1k large).
+
+ * This strategy is used to hide this difference to
+ * the core of the msdos fs. The slowdown is not
+ * hidden though!
+ */
+ /*
+ * The memset is there only to catch errors. The msdos
+ * fs is only using b_data
+ */
+ memset (ret,0,sizeof(*ret));
+ ret->b_data = real->b_data;
+ if (sb->s_blocksize == 2048) {
+ if (block & 3) ret->b_data += (block & 3) << 9;
}else{
- brelse (real);
+ if (block & 1) ret->b_data += 512;
}
+ ret->b_next = real;
+ }else{
+ brelse (real);
}
}
return ret;
}
-struct buffer_head *fat_getblk(struct super_block *sb, int block)
-{
- struct buffer_head *ret = NULL;
- PRINTK(("fat_getblk: block=0x%x\n", block));
-
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_getblk)
- return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
-
- if (sb->s_blocksize == 512){
- ret = getblk (sb->s_dev,block,512);
- } else {
- /*
- * #Specification: msdos / special device / writing
- * A write is always preceded by a read of the complete block
- * (large hardware sector size). This defeat write performance.
- * There is a possibility to optimize this when writing large
- * chunk by making sure we are filling large block. Volunteer ?
- */
- ret = fat_bread (sb,block);
- }
- return ret;
-}
-
-void fat_brelse (
+void bigblock_fat_brelse (
struct super_block *sb,
struct buffer_head *bh)
{
- if (bh != NULL) {
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_brelse)
- return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
-
- if (sb->s_blocksize == 512){
- brelse (bh);
- }else{
- brelse (bh->b_next);
- /* We can free the dummy because a new one is allocated at
- each fat_getblk() and fat_bread().
- */
- kfree (bh);
- }
- }
+ brelse (bh->b_next);
+ /*
+ * We can free the dummy because a new one is allocated at
+ * each fat_getblk() and fat_bread().
+ */
+ kfree (bh);
}
-
-void fat_mark_buffer_dirty (
+
+void bigblock_fat_mark_buffer_dirty (
struct super_block *sb,
struct buffer_head *bh,
int dirty)
{
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty) {
- MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty);
- return;
- }
-
- if (sb->s_blocksize != 512){
- bh = bh->b_next;
- }
- mark_buffer_dirty (bh,dirty);
+ mark_buffer_dirty (bh->b_next,dirty);
}
-void fat_set_uptodate (
+void bigblock_fat_set_uptodate (
struct super_block *sb,
struct buffer_head *bh,
int val)
{
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_set_uptodate) {
- MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
- return;
- }
-
- if (sb->s_blocksize != 512){
- bh = bh->b_next;
- }
- mark_buffer_uptodate(bh, val);
+ mark_buffer_uptodate(bh->b_next, val);
}
-int fat_is_uptodate (
+
+int bigblock_fat_is_uptodate (
struct super_block *sb,
struct buffer_head *bh)
{
- if(MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_is_uptodate)
- return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
-
- if (sb->s_blocksize != 512){
- bh = bh->b_next;
- }
- return buffer_uptodate(bh);
+ return buffer_uptodate(bh->b_next);
}
-void fat_ll_rw_block (
+void bigblock_fat_ll_rw_block (
struct super_block *sb,
int opr,
int nbreq,
struct buffer_head *bh[32])
{
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block) {
- MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
- return;
- }
-
- if (sb->s_blocksize == 512){
- ll_rw_block(opr,nbreq,bh);
- }else{
- struct buffer_head *tmp[32];
- int i;
- for (i=0; i<nbreq; i++){
- tmp[i] = bh[i]->b_next;
- }
- ll_rw_block(opr,nbreq,tmp);
- }
+ struct buffer_head *tmp[32];
+ int i;
+ for (i=0; i<nbreq; i++)
+ tmp[i] = bh[i]->b_next;
+ ll_rw_block(opr,nbreq,tmp);
}
-
new_value is != -1, that FAT entry is replaced by it. */
int fat_access(struct super_block *sb,int nr,int new_value)
+{
+ return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
+}
+
+int fat_bmap(struct inode *inode,int sector)
+{
+ return MSDOS_SB(inode->i_sb)->cvf_format->cvf_bmap(inode,sector);
+}
+
+int default_fat_access(struct super_block *sb,int nr,int new_value)
{
struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
unsigned char *p_first,*p_last;
int copy,first,last,next,b;
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->fat_access)
- return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
-
if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
return 0;
if (MSDOS_SB(sb)->fat_bits == 32) {
return nr;
}
-int fat_smap(struct inode *inode,int sector)
+int default_fat_bmap(struct inode *inode,int sector)
{
- struct msdos_sb_info *sb;
+ struct msdos_sb_info *sb=MSDOS_SB(inode->i_sb);
int cluster,offset;
- sb = MSDOS_SB(inode->i_sb);
- if (sb->cvf_format && sb->cvf_format->cvf_smap)
- return sb->cvf_format->cvf_smap(inode,sector);
if ((sb->fat_bits != 32) &&
(inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
!MSDOS_I(inode)->i_start))) {
return 0;
return sector+sb->dir_start;
}
+ if (sector >= (MSDOS_I(inode)->i_realsize>>9))
+ return 0;
cluster = sector/sb->cluster_size;
offset = sector % sb->cluster_size;
if (!(cluster = fat_get_cluster(inode,cluster))) return 0;
#define MAX_CVF_FORMATS 3
+struct buffer_head *default_fat_bread(struct super_block *,int);
+struct buffer_head *default_fat_getblk(struct super_block *, int);
+struct buffer_head *bigblock_fat_bread(struct super_block *, int);
+void default_fat_brelse(struct super_block *, struct buffer_head *);
+void bigblock_fat_brelse(struct super_block *, struct buffer_head *);
+void default_fat_mark_buffer_dirty (struct super_block *,
+ struct buffer_head *, int);
+void bigblock_fat_mark_buffer_dirty (struct super_block *,
+ struct buffer_head *, int);
+void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
+void bigblock_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
+int default_fat_is_uptodate(struct super_block *, struct buffer_head *);
+int bigblock_fat_is_uptodate(struct super_block *, struct buffer_head *);
+int default_fat_access(struct super_block *sb,int nr,int new_value);
+void default_fat_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32]);
+void bigblock_fat_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32]);
+int default_fat_bmap(struct inode *inode,int block);
+ssize_t default_fat_file_write(
+ struct file *filp,
+ const char *buf,
+ size_t count,
+ loff_t *ppos);
+
+struct cvf_format default_cvf = {
+ 0, /* version - who cares? */
+ "plain",
+ 0, /* flags - who cares? */
+ NULL,
+ NULL,
+ NULL,
+ default_fat_bread,
+ default_fat_getblk,
+ default_fat_brelse,
+ default_fat_mark_buffer_dirty,
+ default_fat_set_uptodate,
+ default_fat_is_uptodate,
+ default_fat_ll_rw_block,
+ default_fat_access,
+ NULL,
+ default_fat_bmap,
+ generic_file_read,
+ default_fat_file_write,
+ NULL,
+ NULL
+};
+
+struct cvf_format bigblock_cvf = {
+ 0, /* version - who cares? */
+ "big_blocks",
+ 0, /* flags - who cares? */
+ NULL,
+ NULL,
+ NULL,
+ bigblock_fat_bread,
+ bigblock_fat_bread,
+ bigblock_fat_brelse,
+ bigblock_fat_mark_buffer_dirty,
+ bigblock_fat_set_uptodate,
+ bigblock_fat_is_uptodate,
+ bigblock_fat_ll_rw_block,
+ default_fat_access,
+ NULL,
+ default_fat_bmap,
+ NULL,
+ default_fat_file_write,
+ NULL,
+ NULL
+};
+
struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0};
struct super_block *sb = dir->i_sb;
loff_t offset, curr;
int row;
- int res;
+ struct buffer_head *new_bh;
offset = curr = 0;
*bh = NULL;
}
if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
return -ENOSPC;
- if ((res = fat_add_cluster(dir)) < 0) return res;
+ new_bh = fat_extend_dir(dir);
+ if (!new_bh)
+ return -ENOSPC;
+ fat_brelse(sb, new_bh);
do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
return offset;
}
+int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
+{
+ struct super_block *sb = dir->i_sb;
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ __u16 date, time;
+
+ if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
+ /* zeroed out, so... */
+ fat_date_unix2dos(dir->i_mtime,&time,&date);
+ de = (struct msdos_dir_entry*)&bh->b_data[0];
+ memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
+ memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
+ de[0].attr = de[1].attr = ATTR_DIR;
+ de[0].time = de[1].time = CT_LE_W(time);
+ de[0].date = de[1].date = CT_LE_W(date);
+ if (is_vfat) { /* extra timestamps */
+ de[0].ctime = de[1].ctime = CT_LE_W(time);
+ de[0].adate = de[0].cdate =
+ de[1].adate = de[1].cdate = CT_LE_W(date);
+ }
+ de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
+ de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
+ de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
+ de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
+ fat_mark_buffer_dirty(sb, bh, 1);
+ fat_brelse(sb, bh);
+ dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+
+ return 0;
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
extern struct file_operations fat_dir_operations;
-EXPORT_SYMBOL(fat_add_cluster);
-EXPORT_SYMBOL(fat_add_cluster1);
+EXPORT_SYMBOL(fat_new_dir);
EXPORT_SYMBOL(fat_bmap);
+EXPORT_SYMBOL(fat_get_block);
EXPORT_SYMBOL(fat_brelse);
EXPORT_SYMBOL(fat_cache_inval_inode);
EXPORT_SYMBOL(fat_clear_inode);
EXPORT_SYMBOL(fat_search_long);
EXPORT_SYMBOL(fat_readdir);
EXPORT_SYMBOL(fat_scan);
-EXPORT_SYMBOL(fat_smap);
EXPORT_SYMBOL(fat_statfs);
-EXPORT_SYMBOL(fat_truncate);
EXPORT_SYMBOL(fat_uni2esc);
EXPORT_SYMBOL(fat_unlock_creation);
EXPORT_SYMBOL(fat_write_inode);
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- fat_bmap, /* get_block */
+ fat_get_block, /* get_block */
block_read_full_page, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL /* revalidate */
};
-/* #Specification: msdos / special devices / mmap
- Mmapping does work because a special mmap is provide in that case.
- Note that it is much less efficient than the generic_file_mmap normally
- used since it allocate extra buffer. generic_file_mmap is used for
- normal device (512 bytes hardware sectors).
-*/
-static struct file_operations fat_file_operations_1024 = {
- NULL, /* lseek - default */
- fat_file_read, /* read */
- fat_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select v2.0.x/poll v2.1.x - default */
- NULL, /* ioctl - default */
- fat_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-/* #Specification: msdos / special devices / swap file
- Swap file can't work on special devices with a large sector
- size (1024 bytes hard sector). Those devices have a weird
- MS-DOS filesystem layout. Generally a single hardware sector
- may contain 2 unrelated logical sector. This mean that there is
- no easy way to do a mapping between disk sector of a file and virtual
- memory. So swap file is difficult (not available right now)
- on those devices. Off course, Ext2 does not have this problem.
-*/
-struct inode_operations fat_file_inode_operations_1024 = {
- &fat_file_operations_1024, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- fat_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static struct file_operations fat_file_operations_readpage = {
- NULL, /* lseek - default */
- fat_file_read, /* read */
- fat_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select v2.0.x/poll v2.1.x - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-struct inode_operations fat_file_inode_operations_readpage = {
- &fat_file_operations_readpage, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- fat_readpage, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- fat_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-#define MSDOS_PREFETCH 32
-struct fat_pre {
- int file_sector;/* Next sector to read in the prefetch table */
- /* This is relative to the file, not the disk */
- struct buffer_head *bhlist[MSDOS_PREFETCH]; /* All buffers needed */
- int nblist; /* Number of buffers in bhlist */
- int nolist; /* index in bhlist */
-};
-/*
- Order the prefetch of more sectors.
-*/
-static void fat_prefetch (
- struct inode *inode,
- struct fat_pre *pre,
- int nb) /* How many must we prefetch at once */
-{
- struct super_block *sb = inode->i_sb;
- struct buffer_head *bhreq[MSDOS_PREFETCH]; /* Buffers not */
- /* already read */
- int nbreq = 0; /* Number of buffers in bhreq */
- int i;
- for (i=0; i<nb; i++){
- int sector = fat_smap(inode,pre->file_sector);
- if (sector != 0){
- struct buffer_head *bh;
- PRINTK (("fsector2 %d -> %d\n",pre->file_sector-1,sector));
- pre->file_sector++;
- bh = fat_getblk(sb, sector);
- if (bh == NULL) break;
- pre->bhlist[pre->nblist++] = bh;
- if (!fat_is_uptodate(sb,bh))
- bhreq[nbreq++] = bh;
- }else{
- break;
- }
- }
- if (nbreq > 0) fat_ll_rw_block (sb,READ,nbreq,bhreq);
- for (i=pre->nblist; i<MSDOS_PREFETCH; i++) pre->bhlist[i] = NULL;
-}
-
-/*
- Read a file into user space
-*/
-static ssize_t fat_file_read_text(
+ssize_t fat_file_read(
struct file *filp,
char *buf,
size_t count,
loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
- struct super_block *sb = inode->i_sb;
- char *start = buf;
- char *end = buf + count;
- int i;
- int left_in_file;
- struct fat_pre pre;
-
+ return MSDOS_SB(inode->i_sb)->cvf_format
+ ->cvf_file_read(filp,buf,count,ppos);
+}
- if (!inode) {
- printk("fat_file_read: inode = NULL\n");
- return -EINVAL;
+
+int fat_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create) {
+ unsigned long phys;
+ phys = fat_bmap(inode, iblock);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ return 0;
}
- /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
- if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
- printk("fat_file_read: mode = %07o\n",inode->i_mode);
- return -EINVAL;
+ if (!create)
+ return 0;
+ if (iblock<<9 != MSDOS_I(inode)->i_realsize) {
+ BUG();
+ return -EIO;
}
- if (*ppos >= inode->i_size || count == 0) return 0;
- /*
- Tell the buffer cache which block we expect to read in advance
- Since we are limited with the stack, we preread only MSDOS_PREFETCH
- because we have to keep the result into the local
- arrays pre.bhlist and bhreq.
-
- Each time we process one block in bhlist, we replace
- it by a new prefetch block if needed.
- */
- PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,*ppos,inode->i_size,count));
- {
- /*
- We must prefetch complete block, so we must
- take in account the offset in the first block.
- */
- int count_max = (*ppos & (SECTOR_SIZE-1)) + count;
- int to_reada; /* How many block to read all at once */
- pre.file_sector = *ppos >> SECTOR_BITS;
- to_reada = count_max / SECTOR_SIZE;
- if (count_max & (SECTOR_SIZE-1)) to_reada++;
- if (filp->f_reada || !MSDOS_I(inode)->i_binary){
- /* Doing a read ahead on ASCII file make sure we always */
- /* read enough, since we don't know how many blocks */
- /* we really need */
- int ahead = read_ahead[MAJOR(inode->i_dev)];
- PRINTK (("to_reada %d ahead %d\n",to_reada,ahead));
- if (ahead == 0) ahead = 8;
- to_reada += ahead;
- }
- if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;
- pre.nblist = 0;
- fat_prefetch (inode,&pre,to_reada);
+ if (!(iblock % MSDOS_SB(inode->i_sb)->cluster_size)) {
+ if (fat_add_cluster(inode))
+ return -ENOSPC;
}
- pre.nolist = 0;
- PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
- while ((left_in_file = inode->i_size - *ppos) > 0
- && buf < end){
- struct buffer_head *bh = pre.bhlist[pre.nolist];
- char *data;
- int size,offset;
- if (bh == NULL) break;
- pre.bhlist[pre.nolist] = NULL;
- pre.nolist++;
- if (pre.nolist == MSDOS_PREFETCH/2){
- memcpy (pre.bhlist,pre.bhlist+MSDOS_PREFETCH/2
- ,(MSDOS_PREFETCH/2)*sizeof(pre.bhlist[0]));
- pre.nblist -= MSDOS_PREFETCH/2;
- fat_prefetch (inode,&pre,MSDOS_PREFETCH/2);
- pre.nolist = 0;
- }
- PRINTK (("file_read pos %ld nblist %d %d %d\n",*ppos,pre.nblist,pre.fetched,count));
- wait_on_buffer(bh);
- if (!fat_is_uptodate(sb,bh)){
- /* read error ? */
- fat_brelse (sb, bh);
- break;
- }
- offset = *ppos & (SECTOR_SIZE-1);
- data = bh->b_data + offset;
- size = MIN(SECTOR_SIZE-offset,left_in_file);
- if (MSDOS_I(inode)->i_binary) {
- size = MIN(size,end-buf);
- copy_to_user(buf,data,size);
- buf += size;
- *ppos += size;
- }else{
- for (; size && buf < end; size--) {
- char ch = *data++;
- ++*ppos;
- if (ch == 26){
- *ppos = inode->i_size;
- break;
- }else if (ch != '\r'){
- put_user(ch,buf++);
- }
+ MSDOS_I(inode)->i_realsize+=SECTOR_SIZE;
+ phys=fat_bmap(inode, iblock);
+ if (!phys)
+ BUG();
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ bh_result->b_state |= (1UL << BH_New);
+ return 0;
+}
+
+static int fat_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct page *new_page, **hash;
+ unsigned long pgpos;
+ unsigned long page_cache = 0;
+ long status;
+
+ pgpos = inode->i_size & PAGE_CACHE_MASK;
+ while (pgpos < page->offset) {
+ hash = page_hash(inode, pgpos);
+repeat_find: new_page = __find_lock_page(inode, pgpos, hash);
+ if (!new_page) {
+ if (!page_cache) {
+ page_cache = page_cache_alloc();
+ if (page_cache)
+ goto repeat_find;
+ status = -ENOMEM;
+ goto out;
}
+ new_page = page_cache_entry(page_cache);
+ if (add_to_page_cache_unique(new_page,inode,pgpos,hash))
+ goto repeat_find;
+ page_cache = 0;
}
- fat_brelse(sb, bh);
+ status = block_write_cont_page(file, new_page, PAGE_SIZE, 0, NULL);
+ UnlockPage(new_page);
+ page_cache_release(new_page);
+ if (status < 0)
+ goto out;
+ pgpos = MSDOS_I(inode)->i_realsize & PAGE_CACHE_MASK;
}
- PRINTK (("--- %d -> %d\n",count,(int)(buf-start)));
- for (i=0; i<pre.nblist; i++)
- fat_brelse (sb, pre.bhlist[i]);
- if (start == buf)
- return -EIO;
- if (!IS_RDONLY(inode))
- inode->i_atime = CURRENT_TIME;
- filp->f_reada = 1; /* Will be reset if a lseek is done */
- return buf-start;
+ status = block_write_cont_page(file, page, offset, bytes, buf);
+out:
+ if (page_cache)
+ page_cache_free(page_cache);
+ return status;
}
-ssize_t fat_file_read(
+ssize_t fat_file_write(
struct file *filp,
- char *buf,
+ const char *buf,
size_t count,
loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
- if (MSDOS_SB(inode->i_sb)->cvf_format &&
- MSDOS_SB(inode->i_sb)->cvf_format->cvf_file_read)
- return MSDOS_SB(inode->i_sb)->cvf_format
- ->cvf_file_read(filp,buf,count,ppos);
-
- /*
- * MS-DOS filesystems with a blocksize > 512 may have blocks
- * spread over several hardware sectors (unaligned), which
- * is not something the generic routines can (or would want
- * to) handle).
- */
- if (!MSDOS_I(inode)->i_binary || inode->i_sb->s_blocksize > 512)
- return fat_file_read_text(filp, buf, count, ppos);
- return generic_file_read(filp, buf, count, ppos);
+ struct super_block *sb = inode->i_sb;
+ return MSDOS_SB(sb)->cvf_format
+ ->cvf_file_write(filp,buf,count,ppos);
}
-/*
- Write to a file either from user space
-*/
-ssize_t fat_file_write(
+
+ssize_t default_fat_file_write(
struct file *filp,
const char *buf,
size_t count,
loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
- struct super_block *sb = inode->i_sb;
- int sector,offset,size,left,written;
- int error,carry;
- const char *start;
- char *to,ch;
- struct buffer_head *bh;
- int binary_mode = MSDOS_I(inode)->i_binary;
-
- PRINTK(("fat_file_write: dentry=%p, inode=%p, ino=%ld\n",
- filp->f_dentry, inode, inode->i_ino));
- if (!inode) {
- printk("fat_file_write: inode = NULL\n");
- return -EINVAL;
- }
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_file_write)
- return MSDOS_SB(sb)->cvf_format
- ->cvf_file_write(filp,buf,count,ppos);
-
- /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
- if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
- printk("fat_file_write: mode = %07o\n",inode->i_mode);
- return -EINVAL;
- }
- /* system files may be immutable */
- if (IS_IMMUTABLE(inode))
- return -EPERM;
-/*
- * ok, append may not work when many processes are writing at the same time
- * but so what. That way leads to madness anyway.
- */
- if (filp->f_flags & O_APPEND)
- *ppos = inode->i_size;
- if (count == 0)
- return 0;
- if (*ppos + count > 0x7FFFFFFFLL) {
- count = 0x7FFFFFFFLL-*ppos;
- if (!count)
- return -EFBIG;
+ int retval;
+
+ retval = generic_file_write(filp, buf, count, ppos,
+ fat_write_partial_page);
+ if (retval > 0) {
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+ mark_inode_dirty(inode);
}
-
- error = carry = 0;
- for (start = buf; count || carry; count -= size) {
- while (!(sector = fat_smap(inode,*ppos >> SECTOR_BITS)))
- if ((error = fat_add_cluster(inode)) < 0) break;
- if (error) {
- fat_truncate(inode);
- break;
- }
- offset = *ppos & (SECTOR_SIZE-1);
- size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
- if (binary_mode
- && offset == 0
- && (size == SECTOR_SIZE
- || *ppos + size >= inode->i_size)){
- /* No need to read the block first since we will */
- /* completely overwrite it */
- /* or at least write past the end of file */
- if (!(bh = fat_getblk(sb,sector))){
- error = -EIO;
- break;
- }
- } else if (!(bh = fat_bread(sb,sector))) {
- error = -EIO;
- break;
- }
- if (binary_mode) {
- copy_from_user(bh->b_data+offset,buf,written = size);
- buf += size;
- } else {
- written = left = SECTOR_SIZE-offset;
- to = (char *) bh->b_data+(*ppos & (SECTOR_SIZE-1));
- if (carry) {
- *to++ = '\n';
- left--;
- carry = 0;
- }
- for (size = 0; size < count && left; size++) {
- get_user(ch, buf++);
- if (ch == '\n') {
- *to++ = '\r';
- left--;
- }
- if (!left) carry = 1;
- else {
- *to++ = ch;
- left--;
- }
- }
- written -= left;
- }
- update_vm_cache(inode, *ppos, bh->b_data + (*ppos & (SECTOR_SIZE-1)), written);
- *ppos += written;
- if (*ppos > inode->i_size) {
- inode->i_size = *ppos;
- mark_inode_dirty(inode);
- }
- fat_set_uptodate(sb, bh, 1);
- fat_mark_buffer_dirty(sb, bh, 0);
- fat_brelse(sb, bh);
- }
- if (start == buf)
- return error;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
- mark_inode_dirty(inode);
- return buf-start;
+ return retval;
}
void fat_truncate(struct inode *inode)
int cluster;
/* Why no return value? Surely the disk could fail... */
+ if (IS_RDONLY (inode))
+ return /* -EPERM */;
if (IS_IMMUTABLE(inode))
return /* -EPERM */;
- if(inode->i_sb->s_flags&MS_RDONLY) {
- printk("FAT: fat_truncate called though fs is read-only, uhh...\n");
- return /* -EROFS */;
- }
cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
+ MSDOS_I(inode)->i_realsize = ((inode->i_size-1) | (SECTOR_SIZE-1)) + 1;
(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
}
#include <asm/uaccess.h>
#include <asm/unaligned.h>
+extern struct cvf_format default_cvf, bigblock_cvf;
+
/* #define FAT_PARANOIA 1 */
#define DEBUG_LEVEL 0
#ifdef FAT_DEBUG
void fat_put_super(struct super_block *sb)
{
- if (MSDOS_SB(sb)->cvf_format) {
+ if (MSDOS_SB(sb)->cvf_format->cvf_version) {
dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version);
MSDOS_SB(sb)->cvf_format->unmount_cvf(sb);
}
struct super_block *sb = inode->i_sb;
int nr;
- MSDOS_I(inode)->i_binary = 1;
INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
MSDOS_I(inode)->i_fat_inode = inode;
inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
inode->i_blksize*MSDOS_SB(sb)->cluster_size;
MSDOS_I(inode)->i_logstart = 0;
+ MSDOS_I(inode)->i_realsize = inode->i_size;
MSDOS_I(inode)->i_attrs = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
sb->s_blocksize = 1024;
set_blocksize(sb->s_dev, 1024);
}
- bh = fat_bread(sb, 0);
+ bh = bread(sb->s_dev, 0, sb->s_blocksize);
unlock_super(sb);
- if (bh == NULL || !fat_is_uptodate(sb,bh)) {
- fat_brelse (sb, bh);
+ if (bh == NULL || !buffer_uptodate(bh)) {
+ brelse (bh);
goto out_no_bread;
}
MSDOS_MAX_EXTRA || (logical_sector_size & (SECTOR_SIZE-1))
|| !b->secs_track || !b->heads;
}
- fat_brelse(sb, bh);
+ brelse(bh);
set_blocksize(sb->s_dev, blksize);
/*
This must be done after the brelse because the bh is a dummy
i = detect_cvf(sb,cvf_format);
if (i >= 0)
error = cvf_formats[i]->mount_cvf(sb,cvf_options);
+ else if (sb->s_blocksize == 512)
+ MSDOS_SB(sb)->cvf_format = &default_cvf;
+ else
+ MSDOS_SB(sb)->cvf_format = &bigblock_cvf;
if (error || debug) {
/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
-
-int fat_bmap(struct inode *inode,int block)
-{
- struct msdos_sb_info *sb;
- int cluster,offset;
-
- sb = MSDOS_SB(inode->i_sb);
- if (sb->cvf_format &&
- sb->cvf_format->cvf_bmap)
- return sb->cvf_format->cvf_bmap(inode,block);
- if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) {
- return sb->dir_start + block;
- }
- cluster = block/sb->cluster_size;
- offset = block % sb->cluster_size;
- if (!(cluster = fat_get_cluster(inode,cluster))) return 0;
- return (cluster-2)*sb->cluster_size+sb->data_start+offset;
-}
-
static int is_exec(char *extension)
{
char *exe_extensions = "EXECOMBAT", *walk;
struct super_block *sb = inode->i_sb;
int nr;
- MSDOS_I(inode)->i_binary = 1;
INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
MSDOS_I(inode)->i_fat_inode = inode;
break;
}
}
+ MSDOS_I(inode)->i_realsize = inode->i_size;
} else { /* not a directory */
inode->i_mode = MSDOS_MKMODE(de->attr,
((IS_NOEXEC(inode) ||
!is_exec(de->ext)))
? S_IRUGO|S_IWUGO : S_IRWXUGO)
& ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG;
- if (MSDOS_SB(sb)->cvf_format)
- inode->i_op = (MSDOS_SB(sb)->cvf_format->flags & CVF_USE_READPAGE)
- ? &fat_file_inode_operations_readpage
- : &fat_file_inode_operations_1024;
- else
- inode->i_op = (sb->s_blocksize == 1024 || sb->s_blocksize == 2048)
- ? &fat_file_inode_operations_1024
- : &fat_file_inode_operations;
+ inode->i_op = &fat_file_inode_operations;
MSDOS_I(inode)->i_start = CF_LE_W(de->start);
if (MSDOS_SB(sb)->fat_bits == 32) {
MSDOS_I(inode)->i_start |=
MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
inode->i_nlink = 1;
inode->i_size = CF_LE_L(de->size);
+ MSDOS_I(inode)->i_realsize = ((inode->i_size-1)|(SECTOR_SIZE-1))+1;
}
if(de->attr & ATTR_SYS)
if (MSDOS_SB(sb)->options.sys_immutable)
inode->i_flags |= S_IMMUTABLE;
- MSDOS_I(inode)->i_binary =
- fat_is_binary(MSDOS_SB(sb)->options.conversion, de->ext);
MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
/* this is as close to the truth as we can get ... */
inode->i_blksize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
* represented by inode. The cluster is zero-initialized.
*/
-struct buffer_head *fat_add_cluster1(struct inode *inode)
+/* not a directory */
+
+int fat_add_cluster(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ int count,nr,limit,last,curr,file_cluster;
+ int res = -ENOSPC;
+ int cluster_size = MSDOS_SB(sb)->cluster_size;
+
+ if (!MSDOS_SB(sb)->free_clusters) return res;
+ lock_fat(sb);
+ limit = MSDOS_SB(sb)->clusters;
+ nr = limit; /* to keep GCC happy */
+ for (count = 0; count < limit; count++) {
+ nr = ((count+MSDOS_SB(sb)->prev_free) % limit)+2;
+ if (fat_access(sb,nr,-1) == 0) break;
+ }
+ MSDOS_SB(sb)->prev_free = (count+MSDOS_SB(sb)->prev_free+1) % limit;
+ if (count >= limit) {
+ MSDOS_SB(sb)->free_clusters = 0;
+ unlock_fat(sb);
+ return res;
+ }
+ fat_access(sb,nr,EOF_FAT(sb));
+ if (MSDOS_SB(sb)->free_clusters != -1)
+ MSDOS_SB(sb)->free_clusters--;
+ if (MSDOS_SB(sb)->fat_bits == 32)
+ fat_clusters_flush(sb);
+ unlock_fat(sb);
+ last = 0;
+ /* We must locate the last cluster of the file to add this
+ new one (nr) to the end of the link list (the FAT).
+
+ Here file_cluster will be the number of the last cluster of the
+ file (before we add nr).
+
+ last is the corresponding cluster number on the disk. We will
+ use last to plug the nr cluster. We will use file_cluster to
+ update the cache.
+ */
+ file_cluster = 0;
+ if ((curr = MSDOS_I(inode)->i_start) != 0) {
+ fat_cache_lookup(inode,INT_MAX,&last,&curr);
+ file_cluster = last;
+ while (curr && curr != -1){
+ file_cluster++;
+ if (!(curr = fat_access(sb, last = curr,-1))) {
+ fat_fs_panic(sb,"File without EOF");
+ return res;
+ }
+ }
+ }
+ if (last) fat_access(sb,last,nr);
+ else {
+ MSDOS_I(inode)->i_start = nr;
+ MSDOS_I(inode)->i_logstart = nr;
+ mark_inode_dirty(inode);
+ }
+ fat_cache_add(inode,file_cluster,nr);
+ inode->i_blocks += cluster_size;
+ return 0;
+}
+
+struct buffer_head *fat_extend_dir(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
int count,nr,limit,last,curr,sector,last_sector,file_cluster;
fat_cache_add(inode,file_cluster,nr);
}
inode->i_blocks += cluster_size;
- if (S_ISDIR(inode->i_mode)) {
- if (inode->i_size & (SECTOR_SIZE-1)) {
- fat_fs_panic(sb,"Odd directory size");
- inode->i_size = (inode->i_size+SECTOR_SIZE) &
- ~(SECTOR_SIZE-1);
- }
- inode->i_size += SECTOR_SIZE*cluster_size;
-#ifdef DEBUG
-printk("size is %d now (%x)\n",inode->i_size,inode);
-#endif
- mark_inode_dirty(inode);
+ if (inode->i_size & (SECTOR_SIZE-1)) {
+ fat_fs_panic(sb,"Odd directory size");
+ inode->i_size = (inode->i_size+SECTOR_SIZE) &
+ ~(SECTOR_SIZE-1);
}
+ inode->i_size += SECTOR_SIZE*cluster_size;
+ MSDOS_I(inode)->i_realsize += SECTOR_SIZE*cluster_size;
+ mark_inode_dirty(inode);
return res;
}
-int fat_add_cluster(struct inode *inode)
-{
- struct buffer_head *bh = fat_add_cluster1(inode);
- if (!bh)
- return -ENOSPC;
- fat_brelse(inode->i_sb, bh);
- return 0;
-}
-
/* Linear day numbers of the respective 1sts in non-leap years. */
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
if (*bh)
fat_brelse(sb, *bh);
*bh = NULL;
- if ((sector = fat_smap(dir,offset >> SECTOR_BITS)) == -1)
+ if ((sector = fat_bmap(dir,offset >> SECTOR_BITS)) == -1)
return -1;
PRINTK (("get_entry sector %d %p\n",sector,*bh));
PRINTK (("get_entry sector apres brelse\n"));
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
#include <asm/bitops.h>
return(sum);
}
-void minix_free_block(struct super_block * sb, int block)
+void minix_free_block(struct inode * inode, int block)
{
+ struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
unsigned int bit,zone;
if (!minix_clear_bit(bit,bh->b_data))
printk("free_block (%s:%d): bit already cleared\n",
kdevname(sb->s_dev), block);
+ else
+ DQUOT_FREE_BLOCK(sb, inode, 1);
mark_buffer_dirty(bh, 1);
return;
}
-int minix_new_block(struct super_block * sb)
+int minix_new_block(struct inode * inode)
{
+ struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
int i,j;
return 0;
}
repeat:
+ if(DQUOT_ALLOC_BLOCK(sb, inode, 1))
+ return -EDQUOT;
+
j = 8192;
bh = NULL;
for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) {
return 0;
if (minix_set_bit(j,bh->b_data)) {
printk("new_block: bit already set");
+ DQUOT_FREE_BLOCK(sb, inode, 1);
goto repeat;
}
mark_buffer_dirty(bh, 1);
printk("free_inode: nonexistent imap in superblock\n");
return;
}
+
+ DQUOT_FREE_INODE(inode->i_sb, inode);
+ DQUOT_DROP(inode);
+
bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13];
minix_clear_inode(inode);
clear_inode(inode);
mark_buffer_dirty(bh, 1);
}
-struct inode * minix_new_inode(const struct inode * dir)
+struct inode * minix_new_inode(const struct inode * dir, int * error)
{
struct super_block * sb;
struct inode * inode;
inode->i_blocks = inode->i_blksize = 0;
insert_inode_hash(inode);
mark_inode_dirty(inode);
+
+ unlock_super(sb);
+printk("m_n_i: allocated inode ");
+ if(DQUOT_ALLOC_INODE(sb, inode)) {
+printk("fails quota test\n");
+ sb->dq_op->drop(inode);
+ inode->i_nlink = 0;
+ iput(inode);
+ *error = -EDQUOT;
+ return NULL;
+ }
+printk("is within quota\n");
+
+ *error = 0;
return inode;
}
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
+#include <linux/quotaops.h>
#include <asm/uaccess.h>
struct buffer_head * bh;
struct minix_dir_entry * de;
- inode = minix_new_inode(dir);
+ inode = minix_new_inode(dir, &error);
+ if (error)
+ return error;
if (!inode)
return -ENOSPC;
inode->i_op = &minix_file_inode_operations;
struct buffer_head * bh;
struct minix_dir_entry * de;
- inode = minix_new_inode(dir);
+ inode = minix_new_inode(dir, &error);
+ if (error)
+ return error;
if (!inode)
return -ENOSPC;
inode->i_uid = current->fsuid;
info = &dir->i_sb->u.minix_sb;
if (dir->i_nlink >= info->s_link_max)
return -EMLINK;
- inode = minix_new_inode(dir);
+ inode = minix_new_inode(dir, &error);
+ if (error)
+ return error;
if (!inode)
return -ENOSPC;
inode->i_op = &minix_dir_inode_operations;
if (!bh)
goto end_rmdir;
inode = dentry->d_inode;
+ DQUOT_INIT(inode);
if (!empty_dir(inode)) {
retval = -ENOTEMPTY;
retval = -ENOENT;
inode = dentry->d_inode;
+ DQUOT_INIT(inode);
bh = minix_find_entry(dir, dentry->d_name.name,
dentry->d_name.len, &de);
if (!bh || de->inode != inode->i_ino)
int i;
char c;
- if (!(inode = minix_new_inode(dir)))
+ inode = minix_new_inode(dir, &i);
+ if (i)
+ return i;
+ if (!inode)
return -ENOSPC;
inode->i_mode = S_IFLNK | 0777;
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
+ } else {
+ DQUOT_INIT(new_inode);
}
}
if (S_ISDIR(old_inode->i_mode)) {
mark_buffer_clean(bh);
brelse(bh);
}
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
return retry;
}
*ind = 0;
mark_buffer_dirty(ind_bh, 1);
brelse(bh);
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
ind = (unsigned short *) ind_bh->b_data;
for (i = 0; i < 512; i++)
else {
tmp = *p;
*p = 0;
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(ind_bh);
tmp = *p;
*p = 0;
mark_inode_dirty(inode);
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(dind_bh);
mark_buffer_clean(bh);
brelse(bh);
}
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
return retry;
}
*ind = 0;
mark_buffer_dirty(ind_bh, 1);
brelse(bh);
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
ind = (unsigned long *) ind_bh->b_data;
for (i = 0; i < 256; i++)
else {
tmp = *p;
*p = 0;
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(ind_bh);
tmp = *p;
*p = 0;
mark_inode_dirty(inode);
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(dind_bh);
tmp = *p;
*p = 0;
mark_inode_dirty(inode);
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(tind_bh);
fat_brelse(sb, bh);
goto out_unlock;
}
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
res = 0;
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
- if (!(bh1 = fat_add_cluster1(inode))) {
- res = -ENOSPC;
+ res = fat_new_dir(inode, dir, 0);
+ if (res)
goto mkdir_error;
- }
- fat_brelse(sb, bh);
- de1 = (struct msdos_dir_entry *)bh1->b_data;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
- memcpy(de1->name,MSDOS_DOT,MSDOS_NAME);
- de1->attr = ATTR_DIR;
- de1->start = CT_LE_W(MSDOS_I(inode)->i_logstart);
- de1->starthi = CT_LE_W(MSDOS_I(inode)->i_logstart >> 16);
- fat_date_unix2dos(inode->i_mtime,&de1->time,&de1->date);
- de1->size = 0;
- de1->time = CT_LE_W(de1->time);
- de1->date = CT_LE_W(de1->date);
- de1++;
- memcpy(de1->name,MSDOS_DOTDOT,MSDOS_NAME);
- de1->attr = ATTR_DIR;
- de1->start = CT_LE_W(MSDOS_I(dir)->i_logstart);
- de1->starthi = CT_LE_W(MSDOS_I(dir)->i_logstart >> 16);
- fat_date_unix2dos(dir->i_mtime,&de1->time,&de1->date);
- de1->size = 0;
- de1->time = CT_LE_W(de1->time);
- de1->date = CT_LE_W(de1->date);
- fat_mark_buffer_dirty(sb, bh1, 1);
- fat_brelse(sb, bh1);
+ fat_brelse(sb, bh);
d_instantiate(dentry, inode);
res = 0;
struct ncpfs_inode_info finfo;
__u8 __name[dentry->d_name.len + 1];
- if (!dir)
+ if (!dentry->d_inode || !dir)
return 0;
server = NCP_SERVER(dir);
if ((inode->i_size)&&(inode->i_blksize)) {
inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1;
}
+
/* TODO: times? I'm not sure... */
+ inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.modifyTime),
+ le16_to_cpu(nwinfo->i.modifyDate));
+ inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.creationTime),
+ le16_to_cpu(nwinfo->i.creationDate));
+ inode->i_atime = ncp_date_dos2unix(0,
+ le16_to_cpu(nwinfo->i.lastAccessDate));
+
NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
# Note 2: the CFLAGS definitions are now in the main makefile.
O_TARGET := umsdos.o
-O_OBJS := dir.o file.o inode.o ioctl.o mangle.o namei.o \
+O_OBJS := dir.o inode.o ioctl.o mangle.o namei.o \
rdir.o symlink.o emd.o check.o
M_OBJS := $(O_TARGET)
}
printk (" (i_patched=%d)", inode->u.umsdos_i.i_patched);
-
- if (inode->i_op == NULL) {
- printk (" (i_op is NULL)\n");
- } else if (inode->i_op == &umsdos_dir_inode_operations) {
- printk (" (i_op is umsdos_dir_inode_operations)\n");
- } else if (inode->i_op == &umsdos_file_inode_operations) {
- printk (" (i_op is umsdos_file_inode_operations)\n");
- } else if (inode->i_op == &umsdos_file_inode_operations_no_bmap) {
- printk (" (i_op is umsdos_file_inode_operations_no_bmap)\n");
- } else if (inode->i_op == &umsdos_file_inode_operations_readpage) {
- printk (" (i_op is umsdos_file_inode_operations_readpage)\n");
- } else if (inode->i_op == &umsdos_rdir_inode_operations) {
- printk (" (i_op is umsdos_rdir_inode_operations)\n");
- } else if (inode->i_op == &umsdos_symlink_inode_operations) {
- printk (" (i_op is umsdos_symlink_inode_operations)\n");
- } else {
- printk (" (i_op is UNKNOWN: %p)\n", inode->i_op);
- }
+
} else {
printk (KERN_DEBUG "* inode is NULL\n");
}
inode->i_uid = entry->uid;
inode->i_gid = entry->gid;
- MSDOS_I (inode)->i_binary = 1;
/* #Specification: umsdos / i_nlink
* The nlink field of an inode is maintained by the MSDOS file system
* for directory and by UMSDOS for other files. The logic is that
UMSDOS_rename, /* rename */
NULL, /* readlink */
NULL, /* followlink */
- fat_bmap, /* get_block */
- block_read_full_page, /* readpage */
+ NULL, /* get_block */
+ NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
- MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
ret = fat_file_read (filp, buf, count, &filp->f_pos);
set_fs (old_fs);
return ret;
mm_segment_t old_fs = get_fs ();
ssize_t ret;
- /* note: i_binary=2 is for CVF-FAT. We put it here, instead of
- * umsdos_file_write_kmem, since it is also wise not to compress
- * symlinks (in the unlikely event that they are > 512 bytes and
- * can be compressed.
- * FIXME: should we set it when reading symlinks too?
- */
-
- MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
-
set_fs (KERNEL_DS);
ret = fat_file_write (filp, buf, count, &filp->f_pos);
set_fs (old_fs);
+++ /dev/null
-/*
- * linux/fs/umsdos/file.c
- *
- * Written 1993 by Jacques Gelinas
- * inspired from linux/fs/msdos/file.c Werner Almesberger
- *
- * Extended MS-DOS regular file handling primitives
- */
-
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/msdos_fs.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/umsdos_fs.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-/*
- * Read a file into user space memory
- */
-static ssize_t UMSDOS_file_read (
- struct file *filp,
- char *buf,
- size_t count,
- loff_t * ppos
-)
-{
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = dentry->d_inode;
-
- int ret = fat_file_read (filp, buf, count, ppos);
-
- /* We have to set the access time because msdos don't care */
- if (!IS_RDONLY (inode)) {
- inode->i_atime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }
- return ret;
-}
-
-
-/*
- * Write a file from user space memory
- */
-static ssize_t UMSDOS_file_write (
- struct file *filp,
- const char *buf,
- size_t count,
- loff_t * ppos)
-{
- return fat_file_write (filp, buf, count, ppos);
-}
-
-
-/*
- * Truncate a file to 0 length.
- */
-static void UMSDOS_truncate (struct inode *inode)
-{
- Printk (("UMSDOS_truncate\n"));
- if (!IS_RDONLY (inode)) {
- fat_truncate (inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }
-}
-
-/* Function for normal file system (512 bytes hardware sector size) */
-struct file_operations umsdos_file_operations =
-{
- NULL, /* lseek - default */
- UMSDOS_file_read, /* read */
- UMSDOS_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-struct inode_operations umsdos_file_inode_operations =
-{
- &umsdos_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- fat_bmap, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- UMSDOS_truncate, /* truncate */
- NULL, /* permission */
- fat_smap, /* smap */
- NULL /* revalidate */
-};
-
-/* For other with larger and unaligned file system */
-struct file_operations umsdos_file_operations_no_bmap =
-{
- NULL, /* lseek - default */
- UMSDOS_file_read, /* read */
- UMSDOS_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- fat_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-struct inode_operations umsdos_file_inode_operations_no_bmap =
-{
- &umsdos_file_operations_no_bmap, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- UMSDOS_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-/* For other with larger and unaligned file system with readpage */
-struct file_operations umsdos_file_operations_readpage =
-{
- NULL, /* lseek - default */
- UMSDOS_file_read, /* read */
- UMSDOS_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-struct inode_operations umsdos_file_inode_operations_readpage =
-{
- &umsdos_file_operations_readpage, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow link */
- NULL, /* get_block */
- fat_readpage, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- UMSDOS_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
filp->f_reada = 1;
filp->f_flags = O_RDWR;
filp->f_dentry = dentry;
- filp->f_op = &umsdos_file_operations;
+ filp->f_op = dentry->d_inode->i_op->default_file_ops;
}
umsdos_set_dirinfo_new(dentry, f_pos);
if (S_ISREG (inode->i_mode)) {
- if (MSDOS_SB (inode->i_sb)->cvf_format) {
- if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
- inode->i_op = &umsdos_file_inode_operations_readpage;
- } else {
- inode->i_op = &umsdos_file_inode_operations_no_bmap;
- }
- } else {
- if (inode->i_op->bmap != NULL) {
- inode->i_op = &umsdos_file_inode_operations;
- } else {
- inode->i_op = &umsdos_file_inode_operations_no_bmap;
- }
- }
+ /* All set */
} else if (S_ISDIR (inode->i_mode)) {
umsdos_setup_dir(dentry);
} else if (S_ISLNK (inode->i_mode)) {
NULL, /* rename */
UMSDOS_readlink, /* readlink */
UMSDOS_followlink, /* followlink */
- fat_bmap, /* get_block */
+ fat_get_block, /* get_block */
block_read_full_page, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
return 0;
}
-static int vfat_create_dotdirs(struct inode *dir, struct inode *parent)
-{
- struct super_block *sb = dir->i_sb;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
- __u16 date, time;
-
- if ((bh = fat_add_cluster1(dir)) == NULL) return -ENOSPC;
- /* zeroed out, so... */
- fat_date_unix2dos(dir->i_mtime,&time,&date);
- de = (struct msdos_dir_entry*)&bh->b_data[0];
- memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
- memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
- de[0].attr = de[1].attr = ATTR_DIR;
- de[0].ctime = de[0].time = de[1].ctime = de[1].time = CT_LE_W(time);
- de[0].adate = de[0].cdate = de[0].date = de[1].adate =
- de[1].cdate = de[1].date = CT_LE_W(date);
- de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
- de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
- de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
- de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
- fat_mark_buffer_dirty(sb, bh, 1);
- fat_brelse(sb, bh);
- dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- mark_inode_dirty(dir);
-
- return 0;
-}
-
static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
struct buffer_head *bh, struct msdos_dir_entry *de)
{
dir->i_version = event;
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
-
- res = vfat_create_dotdirs(inode, dir);
+ res = fat_new_dir(inode, dir, 1);
if (res < 0)
goto mkdir_failed;
dentry->d_time = dentry->d_parent->d_inode->i_version;
#define SMP_CACHE_BYTES L1_CACHE_BYTES
+#ifdef MODULE
+#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+#else
+#define __cacheline_aligned \
+ __attribute__((__aligned__(L1_CACHE_BYTES), \
+ __section__(".data.cacheline_aligned")))
+#endif
+
#endif
#ifndef __M68K_HARDIRQ_H
#define __M68K_HARDIRQ_H
-#include <linux/tasks.h>
+#include <linux/threads.h>
extern unsigned int local_irq_count[NR_CPUS];
extern void (*enable_irq)(unsigned int);
extern void (*disable_irq)(unsigned int);
+#define disable_irq_nosync disable_irq
+#define enable_irq_nosync enable_irq
+
extern int sys_request_irq(unsigned int,
void (*)(int, void *, struct pt_regs *),
unsigned long, const char *, void *);
-#ifndef __68K_MMU_CONTEXT_H
-#define __68K_MMU_CONTEXT_H
+#ifndef __M68K_MMU_CONTEXT_H
+#define __M68K_MMU_CONTEXT_H
-/*
- * get a new mmu context.. do we need this on the m68k?
- */
-#define get_mmu_context(x) do { } while (0)
+#include <asm/setup.h>
+#include <asm/page.h>
-#define init_new_context(mm) do { } while(0)
-#define destroy_context(mm) do { } while(0)
-#define activate_context(tsk) do { } while(0)
+extern inline void
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ mm->context = virt_to_phys(mm->pgd);
+}
+
+#define destroy_context(mm) do { } while(0)
+
+extern inline void switch_mm_0230(struct mm_struct *mm)
+{
+ unsigned long crp[2] = {
+ 0x80000000 | _PAGE_TABLE, mm->context
+ };
+ unsigned long tmp;
+
+ asm volatile (".chip 68030");
+
+ /* flush MC68030/MC68020 caches (they are virtually addressed) */
+ asm volatile (
+ "movec %%cacr,%0;"
+ "orw %1,%0; "
+ "movec %0,%%cacr"
+ : "=d" (tmp) : "di" (FLUSH_I_AND_D));
+
+ /* Switch the root pointer. For a 030-only kernel,
+ * avoid flushing the whole ATC, we only need to
+ * flush the user entries. The 68851 does this by
+ * itself. Avoid a runtime check here.
+ */
+ asm volatile (
+#ifdef CPU_M68030_ONLY
+ "pmovefd %0,%%crp; "
+ "pflush #0,#4"
+#else
+ "pmove %0,%%crp"
+#endif
+ : : "m" (crp[0]));
+
+ asm volatile (".chip 68k");
+}
+
+extern inline void switch_mm_0460(struct mm_struct *mm)
+{
+ asm volatile (".chip 68040");
+
+ /* flush address translation cache (user entries) */
+ asm volatile ("pflushan");
+
+ /* switch the root pointer */
+ asm volatile ("movec %0,%%urp" : : "r" (mm->context));
+
+ if (CPU_IS_060) {
+ unsigned long tmp;
+
+ /* clear user entries in the branch cache */
+ asm volatile (
+ "movec %%cacr,%0; "
+ "orl %1,%0; "
+ "movec %0,%%cacr"
+ : "=d" (tmp): "di" (0x00200000));
+ }
+
+ asm volatile (".chip 68k");
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
+{
+ if (prev != next) {
+ if (CPU_IS_020_OR_030)
+ switch_mm_0230(next);
+ else
+ switch_mm_0460(next);
+ }
+}
+
+extern inline void activate_mm(struct mm_struct *prev_mm,
+ struct mm_struct *next_mm)
+{
+ next_mm->context = virt_to_phys(next_mm->pgd);
+
+ if (CPU_IS_020_OR_030)
+ switch_mm_0230(next_mm);
+ else
+ switch_mm_0460(next_mm);
+}
#endif
}
#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT)
+#define BUG() do { \
+ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+ asm volatile("illegal"); \
+} while (0)
+
+#define PAGE_BUG(page) do { \
+ BUG(); \
+} while (0)
+
#endif /* __KERNEL__ */
#endif /* _M68K_PAGE_H */
#ifndef __ASSEMBLY__
#include <asm/processor.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
/*
* This file contains the functions and defines necessary to modify and use
#define PTRS_PER_PGD 128
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
-/* the no. of pointers that fit on a page: this will go away */
-#define PTRS_PER_PAGE (PAGE_SIZE/sizeof(void*))
-
-typedef pgd_t pgd_table[PTRS_PER_PGD];
-typedef pmd_t pmd_table[PTRS_PER_PMD];
-typedef pte_t pte_table[PTRS_PER_PTE];
-
-#define PGD_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pgd_table))
-#define PMD_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pmd_table))
-#define PTE_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pte_table))
-
-typedef pgd_table pgd_tablepage[PGD_TABLES_PER_PAGE];
-typedef pmd_table pmd_tablepage[PMD_TABLES_PER_PAGE];
-typedef pte_table pte_tablepage[PTE_TABLES_PER_PAGE];
-
/* Virtual address region for use by kernel_map() */
#define KMAP_START 0xd0000000
#define KMAP_END 0xf0000000
{
int i;
unsigned long ptbl;
- ptbl = virt_to_phys(ptep);
- for (i = 0; i < 16; i++, ptbl += sizeof(pte_table)/16)
- pmdp->pmd[i] = _PAGE_TABLE | _PAGE_ACCESSED | ptbl;
+ ptbl = virt_to_phys(ptep) | _PAGE_TABLE | _PAGE_ACCESSED;
+ for (i = 0; i < 16; i++, ptbl += (sizeof(pte_t)*PTRS_PER_PTE/16))
+ pmdp->pmd[i] = ptbl;
}
extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
}
extern inline pte_t pte_mkcache(pte_t pte) { pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode; return pte; }
-/* to set the page-dir */
-extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
-{
- tsk->tss.crp[0] = 0x80000000 | _PAGE_TABLE;
- tsk->tss.crp[1] = virt_to_phys(pgdir);
- if (tsk == current) {
- if (CPU_IS_040_OR_060)
- __asm__ __volatile__ (".chip 68040\n\t"
- "pflushan\n\t"
- "movec %0,%%urp\n\t"
- ".chip 68k"
- : : "r" (tsk->tss.crp[1]));
- else {
- unsigned long tmp;
- __asm__ __volatile__ ("movec %%cacr,%0\n\t"
- "orw #0x0808,%0\n\t"
- "movec %0,%%cacr"
- : "=d" (tmp));
- /* For a 030-only kernel, avoid flushing the whole
- ATC, we only need to flush the user entries.
- The 68851 does this by itself. Avoid a runtime
- check here. */
- __asm__ __volatile__ (
-#ifdef CPU_M68030_ONLY
- ".chip 68030\n\t"
- "pmovefd %0,%%crp\n\t"
- ".chip 68k\n\t"
- "pflush #0,#4"
-#else
- "pmove %0,%%crp"
-#endif
- : : "m" (tsk->tss.crp[0]));
- }
- }
-}
-
#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
/* to find an entry in a page-table-directory */
#include <asm/segment.h>
#include <asm/fpu.h>
+#include <asm/ptrace.h>
+
+extern inline unsigned long rdusp(void) {
+ unsigned long usp;
+
+ __asm__ __volatile__("move %/usp,%0" : "=a" (usp));
+ return usp;
+}
+
+extern inline void wrusp(unsigned long usp) {
+ __asm__ __volatile__("move %0,%/usp" : : "a" (usp));
+}
/*
* User space process size: 3.75GB. This is hardcoded into a few places,
#define INIT_MMAP { &init_mm, 0, 0x40000000, NULL, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
-#define INIT_TSS { \
+#define INIT_THREAD { \
sizeof(init_stack) + (unsigned long) init_stack, 0, \
PS_S, __KERNEL_DS, \
{0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \
wrusp(usp);
}
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
/* Free all resources held by a thread. */
static inline void release_thread(struct task_struct *dead_task)
{
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-#define copy_segments(nr, tsk, mm) do { } while (0)
+#define copy_segments(tsk, mm) do { } while (0)
#define release_segments(mm) do { } while (0)
#define forget_segments() do { } while (0)
return sw->retpc;
}
+#define THREAD_SIZE (2*PAGE_SIZE)
+
/* Allocation and freeing of basic task resources. */
#define alloc_task_struct() \
((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
{_STK_LIM, LONG_MAX}, \
{ 0, LONG_MAX}, \
{LONG_MAX, LONG_MAX}, \
- {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \
+ {0, 0}, \
{INR_OPEN, INR_OPEN}, \
{LONG_MAX, LONG_MAX}, \
{LONG_MAX, LONG_MAX} \
#define _M68K_SEMAPHORE_H
#include <linux/linkage.h>
+#include <linux/wait.h>
#include <asm/system.h>
#include <asm/atomic.h>
atomic_t count;
atomic_t waking;
wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+ long __magic;
+#endif
};
-#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
-#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+ , (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+ __SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+ __SEMAPHORE_INITIALIZER(name,1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+ struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+extern inline void sema_init (struct semaphore *sem, int val)
+{
+ *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val);
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+ sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+ sema_init(sem, 0);
+}
asmlinkage void __down_failed(void /* special register calling convention */);
asmlinkage int __down_failed_interruptible(void /* params in registers */);
asmlinkage int __down_trylock(struct semaphore * sem);
asmlinkage void __up(struct semaphore * sem);
-#define sema_init(sem, val) atomic_set(&((sem)->count), val)
-
/*
* This is ugly, but we want the default case to fall through.
* "down_failed" is a special asm handler that calls the C
extern inline void down(struct semaphore * sem)
{
register struct semaphore *sem1 __asm__ ("%a1") = sem;
+
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
__asm__ __volatile__(
"| atomic down operation\n\t"
"subql #1,%0@\n\t"
register struct semaphore *sem1 __asm__ ("%a1") = sem;
register int result __asm__ ("%d0");
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
__asm__ __volatile__(
"| atomic interruptible down operation\n\t"
"subql #1,%1@\n\t"
register struct semaphore *sem1 __asm__ ("%a1") = sem;
register int result __asm__ ("%d0");
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
__asm__ __volatile__(
"| atomic down trylock operation\n\t"
"subql #1,%1@\n\t"
extern inline void up(struct semaphore * sem)
{
register struct semaphore *sem1 __asm__ ("%a1") = sem;
+
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
__asm__ __volatile__(
"| atomic up operation\n\t"
"addql #1,%0@\n\t"
extern unsigned int local_bh_count[NR_CPUS];
+#define local_bh_disable() (local_bh_count[smp_processor_id()]++)
+#define local_bh_enable() (local_bh_count[smp_processor_id()]--)
+
extern inline void start_bh_atomic(void)
{
local_bh_count[smp_processor_id()]++;
#endif
#define spin_lock_init(lock) do { } while(0)
-#define spin_lock(lock) do { } while(0)
-#define spin_trylock(lock) do { } while(0)
+#define spin_lock(lock) (void)(lock) /* Not "unused variable". */
+#define spin_trylock(lock) (1)
#define spin_unlock_wait(lock) do { } while(0)
#define spin_unlock(lock) do { } while(0)
#define spin_lock_irq(lock) cli()
#define spin_unlock_irq(lock) sti()
+#define spin_lock_bh(lock) local_bh_disable()
+#define spin_unlock_bh(lock) local_bh_enable()
#define spin_lock_irqsave(lock, flags) \
do { save_flags(flags); cli(); } while (0)
#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
#endif
-#define read_lock(lock) do { } while(0)
+#define read_lock(lock) (void)(lock) /* Not "unused variable". */
#define read_unlock(lock) do { } while(0)
-#define write_lock(lock) do { } while(0)
+#define write_lock(lock) (void)(lock) /* Not "unused variable". */
#define write_unlock(lock) do { } while(0)
#define read_lock_irq(lock) cli()
#define read_unlock_irq(lock) sti()
#define write_lock_irq(lock) cli()
#define write_unlock_irq(lock) sti()
+#define read_lock_bh(lock) local_bh_disable()
+#define read_unlock_bh(lock) local_bh_enable()
+#define write_lock_bh(lock) local_bh_disable()
+#define write_unlock_bh(lock) local_bh_enable()
#define read_lock_irqsave(lock, flags) save_and_cli(flags)
#define read_unlock_irqrestore(lock, flags) restore_flags(flags)
#include <linux/linkage.h>
#include <asm/segment.h>
-extern inline unsigned long rdusp(void) {
- unsigned long usp;
-
- __asm__ __volatile__("move %/usp,%0" : "=a" (usp));
- return usp;
-}
-
-extern inline void wrusp(unsigned long usp) {
- __asm__ __volatile__("move %0,%/usp" : : "a" (usp));
-}
-
#define prepare_to_switch() do { } while(0)
/*
#define __NR_olduname 109
#define __NR_iopl /* 110 */ not supported
#define __NR_vhangup 111
-#define __NR_idle 112
+#define __NR_idle /* 112 */ Obsolete
#define __NR_vm86 /* 113 */ not supported
#define __NR_wait4 114
#define __NR_swapoff 115
* some others too.
*/
#define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
static inline _syscall0(int,pause)
static inline _syscall0(int,sync)
static inline _syscall0(pid_t,setsid)
-/* $Id: ide.h,v 1.14 1999/05/15 05:02:35 davem Exp $
+/* $Id: ide.h,v 1.15 1999/08/08 01:38:18 davem Exp $
* ide.h: Ultra/PCI specific IDE glue.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
-/* $Id: parport.h,v 1.3 1999/08/04 03:20:03 davem Exp $
+/* $Id: parport.h,v 1.4 1999/08/08 01:38:18 davem Exp $
* parport.h: sparc64 specific parport initialization and dma.
*
* Copyright (C) 1999 Eddie C. Dost (ecd@skynet.be)
int (*fat_access) (struct super_block *sb,int nr,int new_value);
int (*cvf_statfs) (struct super_block *sb,struct statfs *buf, int bufsiz);
int (*cvf_bmap) (struct inode *inode,int block);
- int (*cvf_smap) (struct inode *inode,int sector);
ssize_t (*cvf_file_read) ( struct file *, char *, size_t, loff_t *);
ssize_t (*cvf_file_write) ( struct file *, const char *, size_t, loff_t *);
int (*cvf_mmap) (struct file *, struct vm_area_struct *);
#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */
#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */
+#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */
+#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */
+#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */
+
#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */
#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */
#define FB_VISUAL_TRUECOLOR 2 /* True color */
#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */
#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */
#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */
-#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */
-#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */
-#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */
+#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */
+#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */
+#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */
+#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */
+#define FB_ACCEL_NV3 27 /* nVidia RIVA 128 */
+#define FB_ACCEL_NV4 28 /* nVidia RIVA TNT */
+#define FB_ACCEL_NV5 29 /* nVidia RIVA TNT2 */
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
#define READ 0
#define WRITE 1
#define READA 2 /* read-ahead - don't block if no resources */
-#define WRITEA 3 /* write-ahead - don't block if no resources */
+
#define WRITERAW 5 /* raw write - don't play with buffer lists */
#ifndef NULL
extern int block_read_full_page(struct file *, struct page *);
extern int block_write_full_page (struct file *, struct page *);
extern int block_write_partial_page (struct file *, struct page *, unsigned long, unsigned long, const char *);
+extern int block_write_cont_page (struct file *, struct page *, unsigned long, unsigned long, const char *);
extern int block_flushpage(struct inode *, struct page *, unsigned long);
extern int generic_file_mmap(struct file *, struct vm_area_struct *);
+++ /dev/null
-/*****************************************************************************/
-
-/*
- * hfmodem.h -- Linux soundcard HF FSK driver.
- *
- * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- * 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.
- *
- *
- * This is the Linux realtime sound output driver
- */
-
-/*****************************************************************************/
-
-#ifndef _HFMODEM_H
-#define _HFMODEM_H
-/* --------------------------------------------------------------------- */
-
-#include <linux/version.h>
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#if LINUX_VERSION_CODE >= 0x20100
-#include <linux/poll.h>
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#define HFMODEM_MINOR 145
-
-#define HFMODEM_SRATE 8000
-#define HFMODEM_MAXBITS 4800 /* required for GTOR 300 baud mode */
-#define HFMODEM_MINBAUD 40
-#define HFMODEM_MAXBAUD 400
-#define HFMODEM_MAXCORRLEN ((HFMODEM_SRATE+HFMODEM_MINBAUD-1)/HFMODEM_MINBAUD)
-
-/* --------------------------------------------------------------------- */
-
-typedef unsigned long hfmodem_time_t;
-typedef int hfmodem_soft_t;
-typedef unsigned long hfmodem_id_t;
-
-/* --------------------------------------------------------------------- */
-
-struct hfmodem_ioctl_fsk_tx_request {
- hfmodem_time_t tstart;
- hfmodem_time_t tinc;
- int inv;
- hfmodem_id_t id;
- unsigned int nbits;
- unsigned char *data;
- unsigned int freq[2];
-};
-
-struct hfmodem_ioctl_fsk_rx_request {
- hfmodem_time_t tstart;
- hfmodem_time_t tinc;
- unsigned int baud;
- hfmodem_id_t id;
- unsigned int nbits;
- hfmodem_soft_t *data;
- unsigned int freq[2];
-};
-
-struct hfmodem_ioctl_mixer_params {
- int src;
- int igain;
- int ogain;
-};
-
-struct hfmodem_ioctl_sample_params {
- __s16 *data;
- int len;
-};
-
-#define HFMODEM_IOCTL_FSKTXREQUEST _IOW('H', 0, struct hfmodem_ioctl_fsk_tx_request)
-#define HFMODEM_IOCTL_FSKRXREQUEST _IOW('H', 1, struct hfmodem_ioctl_fsk_rx_request)
-#define HFMODEM_IOCTL_CLEARRQ _IO('H', 3)
-#define HFMODEM_IOCTL_GETCURTIME _IOR('H', 4, hfmodem_time_t)
-#define HFMODEM_IOCTL_WAITRQ _IOR('H', 5, hfmodem_id_t)
-#define HFMODEM_IOCTL_MIXERPARAMS _IOW('H', 6, struct hfmodem_ioctl_mixer_params)
-#define HFMODEM_IOCTL_SAMPLESTART _IOW('H', 7, struct hfmodem_ioctl_sample_params)
-#define HFMODEM_IOCTL_SAMPLEFINISHED _IO('H', 8)
-
-/* --------------------------------------------------------------------- */
-#ifdef __KERNEL__
-
-#include <linux/parport.h>
-
-#define DMA_MODE_AUTOINIT 0x10
-
-#define NR_DEVICE 1
-
-#define HFMODEM_FRAGSAMPLES (HFMODEM_SRATE/100)
-#define HFMODEM_FRAGSIZE (HFMODEM_FRAGSAMPLES*2)
-#define HFMODEM_NUMFRAGS 8
-#define HFMODEM_EXCESSFRAGS 3
-
-#define HFMODEM_NUMRXSLOTS 20
-#define HFMODEM_NUMTXSLOTS 4
-
-#define HFMODEM_CORRELATOR_CACHE 8
-
-enum slot_st { ss_unused = 0, ss_ready, ss_oper, ss_retired };
-typedef int hfmodem_conv_t;
-
-struct hfmodem_state {
- const struct hfmodem_scops *scops;
-
- /* io params */
- struct {
- unsigned int base_addr;
- unsigned int dma;
- unsigned int irq;
- } io;
-
- struct {
- unsigned int seriobase;
- unsigned int pariobase;
- unsigned int midiiobase;
- unsigned int flags;
- struct pardevice *pardev;
- } ptt_out;
-
- struct {
- __s16 *buf;
- unsigned int lastfrag;
- unsigned int fragptr;
- unsigned int last_dmaptr;
- int ptt_frames;
- } dma;
-
- struct {
- unsigned int last_tvusec;
- unsigned long long time_cnt;
- hfmodem_time_t lasttime;
-#ifdef __i386__
- unsigned int starttime_lo, starttime_hi;
-#endif /* __i386__ */
- } clk;
-
- int active;
- wait_queue_head_t wait;
-
- struct {
- __s16 *kbuf;
- __s16 *ubuf;
- __s16 *kptr;
- unsigned int size;
- int rem;
- } sbuf;
-
- struct {
- hfmodem_time_t last_time;
- unsigned int tx_phase;
-
- struct hfmodem_l1_rxslot {
- enum slot_st state;
- hfmodem_time_t tstart, tinc;
- hfmodem_soft_t *data;
- hfmodem_soft_t *userdata;
- unsigned int nbits;
- unsigned int cntbits;
- hfmodem_id_t id;
- unsigned int corrlen;
- hfmodem_conv_t scale;
- unsigned int corr_cache;
- } rxslots[HFMODEM_NUMRXSLOTS];
-
- struct hfmodem_l1_txslot {
- enum slot_st state;
- hfmodem_time_t tstart, tinc;
- unsigned char *data;
- unsigned int nbits;
- unsigned int cntbits;
- hfmodem_id_t id;
- unsigned char inv;
- unsigned int phinc;
- unsigned int phase_incs[2];
- } txslots[HFMODEM_NUMTXSLOTS];
- } l1;
-};
-
-struct hfmodem_correlator_cache {
- int refcnt;
- int lru;
- unsigned short phase_incs[2];
- hfmodem_conv_t correlator[2][2][HFMODEM_MAXCORRLEN];
-};
-
-struct hfmodem_scops {
- unsigned int extent;
-
- void (*init)(struct hfmodem_state *dev);
- void (*prepare_input)(struct hfmodem_state *dev);
- void (*trigger_input)(struct hfmodem_state *dev);
- void (*prepare_output)(struct hfmodem_state *dev);
- void (*trigger_output)(struct hfmodem_state *dev);
- void (*stop)(struct hfmodem_state *dev);
- unsigned int (*intack)(struct hfmodem_state *dev);
- void (*mixer)(struct hfmodem_state *dev, int src, int igain, int ogain);
-};
-
-/* --------------------------------------------------------------------- */
-
-extern int hfmodem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-#if LINUX_VERSION_CODE >= 0x20100
-extern unsigned int hfmodem_poll(struct file *file, poll_table *wait);
-#else
-extern int hfmodem_select(struct inode *inode, struct file *file, int sel_type, select_table *wait);
-#endif
-
-extern void hfmodem_clear_rq(struct hfmodem_state *dev);
-extern void hfmodem_input_samples(struct hfmodem_state *dev, hfmodem_time_t tstart,
- hfmodem_time_t tinc, __s16 *samples);
-extern int hfmodem_output_samples(struct hfmodem_state *dev, hfmodem_time_t tstart,
- hfmodem_time_t tinc, __s16 *samples);
-extern long hfmodem_next_tx_event(struct hfmodem_state *dev, hfmodem_time_t curr);
-extern void hfmodem_finish_pending_rx_requests(struct hfmodem_state *dev);
-extern void hfmodem_wakeup(struct hfmodem_state *dev);
-
-
-extern int hfmodem_sbcprobe(struct hfmodem_state *dev);
-extern int hfmodem_wssprobe(struct hfmodem_state *dev);
-
-extern void hfmodem_refclock_probe(void);
-extern void hfmodem_refclock_init(struct hfmodem_state *dev);
-extern hfmodem_time_t hfmodem_refclock_current(struct hfmodem_state *dev, hfmodem_time_t expected, int exp_valid);
-
-/* --------------------------------------------------------------------- */
-
-extern const char hfmodem_drvname[];
-extern const char hfmodem_drvinfo[];
-
-extern struct hfmodem_state hfmodem_state[NR_DEVICE];
-extern struct hfmodem_correlator_cache hfmodem_correlator_cache[HFMODEM_CORRELATOR_CACHE];
-
-/* --------------------------------------------------------------------- */
-#endif /* __KERNEL__ */
-/* --------------------------------------------------------------------- */
-#endif /* _HFMODEM_H */
extern int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev);
extern int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
struct inode * new_dir, struct dentry *new_dentry);
-extern struct inode * minix_new_inode(const struct inode * dir);
+extern struct inode * minix_new_inode(const struct inode * dir, int * error);
extern void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct super_block *sb);
-extern int minix_new_block(struct super_block * sb);
-extern void minix_free_block(struct super_block * sb, int block);
+extern int minix_new_block(struct inode * inode);
+extern void minix_free_block(struct inode * inode, int block);
extern unsigned long minix_count_free_blocks(struct super_block *sb);
extern int minix_bmap(struct inode *,int);
#define PG_Slab 8
#define PG_swap_cache 9
#define PG_skip 10
+#define PG_swap_entry 11
/* bits 21-30 unused */
#define PG_reserved 31
return page;
}
-extern int low_on_memory;
-
/* memory.c & swap.c*/
#define free_page(addr) free_pages((addr),0)
extern void lock_fat(struct super_block *sb);
extern void unlock_fat(struct super_block *sb);
extern int fat_add_cluster(struct inode *inode);
-extern struct buffer_head *fat_add_cluster1(struct inode *inode);
+extern struct buffer_head *fat_extend_dir(struct inode *inode);
extern int date_dos2unix(__u16 time, __u16 date);
extern void fat_fs_panic(struct super_block *s,const char *msg);
extern void fat_lock_creation(void);
/* fat.c */
extern int fat_access(struct super_block *sb,int nr,int new_value);
-extern int fat_smap(struct inode *inode,int sector);
extern int fat_free(struct inode *inode,int skip);
void fat_cache_inval_inode(struct inode *inode);
void fat_cache_inval_dev(kdev_t device);
/* inode.c */
extern void fat_hash_init(void);
extern int fat_bmap(struct inode *inode,int block);
+extern int fat_get_block(struct inode *, long, struct buffer_head *, int);
extern int fat_notify_change(struct dentry *, struct iattr *);
extern void fat_clear_inode(struct inode *inode);
extern void fat_delete_inode(struct inode *inode);
int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
struct msdos_dir_entry **de, int *ino);
int fat_dir_empty(struct inode *dir);
+int fat_new_dir(struct inode *inode, struct inode *parent, int is_vfat);
/* file.c */
extern struct inode_operations fat_file_inode_operations;
int i_logstart; /* logical first cluster */
int i_attrs; /* unused attribute bits */
int i_ctime_ms; /* unused change time in milliseconds */
- int i_busy; /* file is either deleted but still open, or
- inconsistent (mkdir) */
- int i_binary; /* file contains non-text data */
int i_location; /* on-disk position of directory entry or 0 */
struct inode *i_fat_inode; /* struct inode of this one */
struct list_head i_fat_hash; /* hash by i_location */
+ int i_realsize;
};
#endif
extern void inc_parport_count(void);
/* If PC hardware is the only type supported, we can optimise a bit. */
-#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
+#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !defined(CONFIG_PARPORT_OTHER) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE))
#undef PARPORT_NEED_GENERIC_OPS
#include <linux/parport_pc.h>
#define parport_write_data(p,x) parport_pc_write_data(p,x)
extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
void (*)(void *, kmem_cache_t *, unsigned long),
void (*)(void *, kmem_cache_t *, unsigned long));
+extern int kmem_cache_destroy(kmem_cache_t *);
extern int kmem_cache_shrink(kmem_cache_t *);
extern void *kmem_cache_alloc(kmem_cache_t *, int);
extern void kmem_cache_free(kmem_cache_t *, void *);
extern struct page * read_swap_cache_async(unsigned long, int);
#define read_swap_cache(entry) read_swap_cache_async(entry, 1);
extern int FASTCALL(swap_count(unsigned long));
+extern unsigned long acquire_swap_entry(struct page *page);
+
/*
* Make these inline later once they are working properly.
*/
#endif
extern struct inode_operations umsdos_dir_inode_operations;
-extern struct file_operations umsdos_file_operations;
-extern struct inode_operations umsdos_file_inode_operations;
-extern struct inode_operations umsdos_file_inode_operations_no_bmap;
-extern struct inode_operations umsdos_file_inode_operations_readpage;
extern struct inode_operations umsdos_symlink_inode_operations;
extern int init_umsdos_fs (void);
EXPORT_SYMBOL(__free_page);
EXPORT_SYMBOL(kmem_find_general_cachep);
EXPORT_SYMBOL(kmem_cache_create);
+EXPORT_SYMBOL(kmem_cache_destroy);
EXPORT_SYMBOL(kmem_cache_shrink);
EXPORT_SYMBOL(kmem_cache_alloc);
EXPORT_SYMBOL(kmem_cache_free);
EXPORT_SYMBOL(block_read_full_page);
EXPORT_SYMBOL(block_write_full_page);
EXPORT_SYMBOL(block_write_partial_page);
+EXPORT_SYMBOL(block_write_cont_page);
EXPORT_SYMBOL(block_flushpage);
EXPORT_SYMBOL(generic_file_read);
EXPORT_SYMBOL(generic_file_write);
write_lock(&resource_lock);
- while (!(parent->flags & IORESOURCE_BUSY)) {
+ for (;;) {
struct resource *conflict;
conflict = __request_resource(parent, res);
break;
if (conflict != parent) {
parent = conflict;
- continue;
+ if (!(conflict->flags & IORESOURCE_BUSY))
+ continue;
}
/* Uhhuh, that didn't work out.. */
spin_unlock(&pagecache_lock);
}
-extern atomic_t too_many_dirty_buffers;
-
int shrink_mmap(int priority, int gfp_mask)
{
static unsigned long clock = 0;
status = write_one_page(file, page, offset, bytes, buf);
+ if (status >= 0) {
+ written += status;
+ count -= status;
+ pos += status;
+ buf += status;
+ if (pos > inode->i_size)
+ inode->i_size = pos;
+ }
/* Mark it unlocked again and drop the page.. */
UnlockPage(page);
page_cache_release(page);
if (status < 0)
break;
-
- written += status;
- count -= status;
- pos += status;
- buf += status;
}
*ppos = pos;
- if (pos > inode->i_size)
- inode->i_size = pos;
if (page_cache)
page_cache_free(page_cache);
pte = mk_pte(page_address(page), vma->vm_page_prot);
+ set_bit(PG_swap_entry, &page->flags);
if (write_access && !is_page_shared(page)) {
delete_from_swap_cache(page);
pte = pte_mkwrite(pte_mkdirty(pte));
set_page_count(map, 1); \
} while (0)
-int low_on_memory = 0;
-
unsigned long __get_free_pages(int gfp_mask, unsigned long order)
{
unsigned long flags;
*/
if (!(current->flags & PF_MEMALLOC)) {
int freed;
+ static int low_on_memory = 0;
if (nr_free_pages > freepages.min) {
if (!low_on_memory)
} else if (p->swap_file) {
struct inode *swapf = p->swap_file->d_inode;
int i;
- if (swapf->i_op->get_block == NULL
- && swapf->i_op->smap != NULL){
- /*
- With MS-DOS, we use msdos_smap which returns
- a sector number (not a cluster or block number).
- It is a patch to enable the UMSDOS project.
- Other people are working on better solution.
-
- It sounds like ll_rw_swap_file defined
- its operation size (sector size) based on
- PAGE_SIZE and the number of blocks to read.
- So using get_block or smap should work even if
- smap will require more blocks.
- */
- int j;
- unsigned int block = offset << 3;
-
- for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
- if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
- printk("rw_swap_page: bad swap file\n");
- return;
- }
+ int j;
+ unsigned int block = offset
+ << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
+
+ block_size = swapf->i_sb->s_blocksize;
+ for (i=0, j=0; j< PAGE_SIZE ; i++, j += block_size)
+ if (!(zones[i] = bmap(swapf,block++))) {
+ printk("rw_swap_page: bad swap file\n");
+ return;
}
- block_size = 512;
- }else{
- int j;
- unsigned int block = offset
- << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
-
- block_size = swapf->i_sb->s_blocksize;
- for (i=0, j=0; j< PAGE_SIZE ; i++, j += block_size)
- if (!(zones[i] = bmap(swapf,block++))) {
- printk("rw_swap_page: bad swap file\n");
- return;
- }
- zones_used = i;
- dev = swapf->i_dev;
- }
+ zones_used = i;
+ dev = swapf->i_dev;
} else {
printk(KERN_ERR "rw_swap_page: no swap file or device\n");
put_page(page);
* Written by Mark Hemment, 1996/97.
* (markhe@nextd.demon.co.uk)
*
+ * kmem_cache_destroy() + some cleanup - 1999 Andrea Arcangeli
+ *
* 11 April '97. Started multi-threading - markhe
* The global cache-chain is protected by the semaphore 'cache_chain_sem'.
* The sem is only needed when accessing/extending the cache-chain, which
return cachep;
}
+/*
+ * This check if the kmem_cache_t pointer is chained in the cache_cache
+ * list. -arca
+ */
+static int is_chained_kmem_cache(kmem_cache_t * cachep)
+{
+ kmem_cache_t * searchp;
+ int ret = 0;
+
+ /* Find the cache in the chain of caches. */
+ down(&cache_chain_sem);
+ for (searchp = &cache_cache; searchp->c_nextp != &cache_cache;
+ searchp = searchp->c_nextp)
+ {
+ if (searchp->c_nextp != cachep)
+ continue;
+
+ /* Accessing clock_searchp is safe - we hold the mutex. */
+ if (cachep == clock_searchp)
+ clock_searchp = cachep->c_nextp;
+ ret = 1;
+ break;
+ }
+ up(&cache_chain_sem);
+
+ return ret;
+}
+
+/* returns 0 if every slab is been freed -arca */
+static int __kmem_cache_shrink(kmem_cache_t *cachep)
+{
+ kmem_slab_t *slabp;
+ int ret;
+
+ spin_lock_irq(&cachep->c_spinlock);
+
+ /* If the cache is growing, stop shrinking. */
+ while (!cachep->c_growing) {
+ slabp = cachep->c_lastp;
+ if (slabp->s_inuse || slabp == kmem_slab_end(cachep))
+ break;
+ kmem_slab_unlink(slabp);
+ spin_unlock_irq(&cachep->c_spinlock);
+ kmem_slab_destroy(cachep, slabp);
+ spin_lock_irq(&cachep->c_spinlock);
+ }
+ ret = 1;
+ if (cachep->c_lastp == kmem_slab_end(cachep))
+ ret = 0; /* Cache is empty. */
+ spin_unlock_irq(&cachep->c_spinlock);
+ return ret;
+}
+
/* Shrink a cache. Releases as many slabs as possible for a cache.
* It is expected this function will be called by a module when it is
* unloaded. The cache is _not_ removed, this creates too many problems and
int
kmem_cache_shrink(kmem_cache_t *cachep)
{
- kmem_cache_t *searchp;
- kmem_slab_t *slabp;
- int ret;
-
if (!cachep) {
printk(KERN_ERR "kmem_shrink: NULL ptr\n");
return 2;
return 2;
}
+ if (!is_chained_kmem_cache(cachep))
+ {
+ printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n",
+ cachep);
+ return 2;
+ }
+
+ return __kmem_cache_shrink(cachep);
+}
+
+/*
+ * Remove a kmem_cache_t object from the slab cache. When returns 0 it
+ * completed succesfully. -arca
+ */
+int kmem_cache_destroy(kmem_cache_t * cachep)
+{
+ kmem_cache_t * prev;
+ int ret;
+
+ if (!cachep) {
+ printk(KERN_ERR "kmem_destroy: NULL ptr\n");
+ return 1;
+ }
+ if (in_interrupt()) {
+ printk(KERN_ERR "kmem_destroy: Called during int - %s\n",
+ cachep->c_name);
+ return 1;
+ }
+
+ ret = 0;
/* Find the cache in the chain of caches. */
- down(&cache_chain_sem); /* Semaphore is needed. */
- searchp = &cache_cache;
- for (;searchp->c_nextp != &cache_cache; searchp = searchp->c_nextp) {
- if (searchp->c_nextp != cachep)
+ down(&cache_chain_sem);
+ for (prev = &cache_cache; prev->c_nextp != &cache_cache;
+ prev = prev->c_nextp)
+ {
+ if (prev->c_nextp != cachep)
continue;
/* Accessing clock_searchp is safe - we hold the mutex. */
if (cachep == clock_searchp)
clock_searchp = cachep->c_nextp;
- goto found;
+
+ /* remove the cachep from the cache_cache list. -arca */
+ prev->c_nextp = cachep->c_nextp;
+
+ ret = 1;
+ break;
}
up(&cache_chain_sem);
- printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n", cachep);
- return 2;
-found:
- /* Release the semaphore before getting the cache-lock. This could
- * mean multiple engines are shrinking the cache, but so what.
- */
- up(&cache_chain_sem);
- spin_lock_irq(&cachep->c_spinlock);
- /* If the cache is growing, stop shrinking. */
- while (!cachep->c_growing) {
- slabp = cachep->c_lastp;
- if (slabp->s_inuse || slabp == kmem_slab_end(cachep))
- break;
- kmem_slab_unlink(slabp);
- spin_unlock_irq(&cachep->c_spinlock);
- kmem_slab_destroy(cachep, slabp);
- spin_lock_irq(&cachep->c_spinlock);
+ if (!ret)
+ {
+ printk(KERN_ERR "kmem_destroy: Invalid cache addr %p\n",
+ cachep);
+ return 1;
}
- ret = 1;
- if (cachep->c_lastp == kmem_slab_end(cachep))
- ret--; /* Cache is empty. */
- spin_unlock_irq(&cachep->c_spinlock);
- return ret;
+
+ if (__kmem_cache_shrink(cachep))
+ {
+ printk(KERN_ERR "kmem_destroy: Can't free all objects %p\n",
+ cachep);
+ down(&cache_chain_sem);
+ cachep->c_nextp = cache_cache.c_nextp;
+ cache_cache.c_nextp = cachep;
+ up(&cache_chain_sem);
+ return 1;
+ }
+
+ kmem_cache_free(&cache_cache, cachep);
+
+ return 0;
}
/* Get the memory for a slab management obj. */
}
UnlockPage(page);
+ clear_bit(PG_swap_entry, &page->flags);
+
__free_page(page);
}
offset = SWP_OFFSET(entry);
if (offset >= p->max)
goto bad_offset;
- if (offset < p->lowest_bit)
- p->lowest_bit = offset;
- if (offset > p->highest_bit)
- p->highest_bit = offset;
if (!p->swap_map[offset])
goto bad_free;
if (p->swap_map[offset] < SWAP_MAP_MAX) {
if (!--p->swap_map[offset])
+ {
+ if (offset < p->lowest_bit)
+ p->lowest_bit = offset;
+ if (offset > p->highest_bit)
+ p->highest_bit = offset;
nr_swap_pages++;
+ }
}
#ifdef DEBUG_SWAP
printk("DebugVM: swap_free(entry %08lx, count now %d)\n",
goto out;
}
+/* needs the big kernel lock */
+unsigned long acquire_swap_entry(struct page *page)
+{
+ struct swap_info_struct * p;
+ unsigned long offset, type;
+ unsigned long entry;
+
+ if (!test_bit(PG_swap_entry, &page->flags))
+ goto new_swap_entry;
+
+ /* We have the old entry in the page offset still */
+ entry = page->offset;
+ if (!entry)
+ goto new_swap_entry;
+ type = SWP_TYPE(entry);
+ if (type & SHM_SWP_TYPE)
+ goto new_swap_entry;
+ if (type >= nr_swapfiles)
+ goto new_swap_entry;
+ p = type + swap_info;
+ if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK)
+ goto new_swap_entry;
+ offset = SWP_OFFSET(entry);
+ if (offset >= p->max)
+ goto new_swap_entry;
+ /* Has it been re-used for something else? */
+ if (p->swap_map[offset])
+ goto new_swap_entry;
+
+ /* We're cool, we can just use the old one */
+ p->swap_map[offset] = 1;
+ nr_swap_pages--;
+ return entry;
+
+new_swap_entry:
+ return get_swap_page();
+}
+
/*
* The swap entry has been read in advance, and we return 1 to indicate
* that the page has been used or is no longer needed.
static int least_priority = 0;
union swap_header *swap_header = 0;
int swap_header_version;
- int lock_map_size = PAGE_SIZE;
int nr_good_pages = 0;
unsigned long maxpages;
int swapfilesize;
nr_good_pages = swap_header->info.last_page -
swap_header->info.nr_badpages -
1 /* header page */;
- lock_map_size = (p->max + 7) / 8;
if (error)
goto bad_swap;
}
* Dont be too eager to get aging right if
* memory is dangerously low.
*/
- if (!low_on_memory && pte_young(pte)) {
+ if (pte_young(pte)) {
/*
* Transfer the "accessed" bit from the page
* tables to the global page map.
* we have the swap cache set up to associate the
* page with that swap entry.
*/
- entry = get_swap_page();
+ entry = acquire_swap_entry(page);
if (!entry)
goto out_failed_unlock; /* No swap space left */