input/output character sets. Say Y here for the preferred Russian
character set.
+nls koi8-ru
+CONFIG_NLS_KOI8_RU
+ If you want to display filenames with native language characters
+ from the Microsoft fat filesystem family or from JOLIET CDROMs
+ correctly on the screen, you need to include the appropriate
+ input/output character sets. Say Y here for the preferred Russian
+ character set.
+
Virtual terminal
CONFIG_VT
If you say Y here, you will get support for terminal devices with
CONFIG_SOUND_MAESTRO
Say Y or M if you have a sound system driven by ESS's Maestro line
of PCI sound chips. These include the Maestro 1, Maestro 2, and
- Maestro 2E. See Documentation/sound/Maestro for more details.
+ Maestro 2E, but _does not_ include the Maestro 3 and Allegro
+ line of chips. See Documentation/sound/Maestro for more details
+ on the 1/2/2e line.
+
+ESS Maestro3/Allegro sound chipsets
+CONFIG_SOUND_MAESTRO3
+ Say Y or M if you have a sound system driven by ESS's Maestro3 line
+ of PCI sound chips. This includes the Allegro sound chip that is
+ a lighter version of the Maestro3.
Are you using a crosscompiler
CONFIG_CROSSCOMPILE
--- /dev/null
+ An OSS/Lite Driver for the ESS Maestro3 family of sound chips
+
+ Zach Brown, December 2000
+
+Driver Status and Availability
+------------------------------
+
+The most recent version of this driver will hopefully always be available at
+ http://www.zabbo.net/maestro3/
+
+I will try and maintain the most recent stable version of the driver
+in both the stable and development kernel lines.
+
+Historically I've sucked pretty hard at actually doing that, however.
+
+ESS Maestro3 Chip Family
+-----------------------
+
+The 'Maestro3' is much like the Maestro2 chip. The noted improvement
+is the removal of the silicon in the '2' that did PCM mixing. All that
+work is now done through a custom DSP called the ASSP, the Asynchronus
+Specific Signal Processor.
+
+The 'Allegro' is a baby version of the Maestro3. I'm not entirely clear
+on the extent of the differences, but the driver supports them both :)
+
+The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998,
+both under ESS's vendor ID of 0x125D. The Maestro3 can also show up as
+0x199a when hardware strapping is used.
+
+The chip can also act as a multi function device. The modem IDs follow
+the audio multimedia device IDs. (so the modem part of an Allegro shows
+up as 0x1989)
+
+Driver OSS Behavior
+--------------------
+
+This OSS driver exports /dev/mixer and /dev/dsp to applications, which
+mostly adhere to the OSS spec. This driver doesn't register itself
+with /dev/sndstat, so don't expect information to appear there.
+
+The /dev/dsp device exported behaves as expected. Playback is
+supported in all the various lovely formats. 8/16bit stereo/mono from
+8khz to 48khz, with both read()/write(), and mmap().
+
+/dev/mixer is an interface to the AC'97 codec on the Maestro3. It is
+worth noting that there are a variety of AC'97s that can be wired to
+the Maestro3. Which is used is entirely up to the hardware implementor.
+This should only be visible to the user by the presence, or lack, of
+'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them.
+The Allegro has an onchip AC'97.
+
+The driver doesn't support MIDI or FM playback at the moment.
+
+Compiling and Installing
+------------------------
+
+With the drivers inclusion into the kernel, compiling and installing
+is the same as most OSS/Lite modular sound drivers. Compilation
+of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable
+in the config system.
+
+It may be modular or statically linked. If it is modular it should be
+installed with the rest of the modules for the kernel on the system.
+Typically this will be in /lib/modules/ somewhere. 'alias sound-slot-0
+maestro3' should also be added to your module configs (typically
+/etc/modules.conf) if you're using modular OSS/Lite sound and want to
+default to using a maestro3 chip.
+
+There are very few options to the driver. One is 'debug' which will
+tell the driver to print minimal debugging information as it runs. This
+can be collected with 'dmesg' or through the klogd daemon.
+
+The other is 'external_amp', which tells the driver to attempt to enable
+an external amplifier. This defaults to '1', you can tell the driver
+not to bother enabling such an amplifier by setting it to '0'.
+
+Power Management
+----------------
+
+This driver has a minimal understanding of PCI Power Management. It will
+try and power down the chip when the system is suspended, and power
+it up with it is resumed. It will also try and power down the chip
+when the machine is shut down.
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 19
-EXTRAVERSION = pre4
+EXTRAVERSION = pre5
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
__initfunc(void pcibios_init(void))
{
unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET;
+ unsigned int mem_mask;
unsigned long cntl;
- *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000;
+ for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
+ if (mem_mask >= mem_size)
+ break;
+
+ *CSR_SDRAMBASEMASK = (mem_mask - 1) & 0x0ffc0000;
*CSR_SDRAMBASEOFFSET = 0;
*CSR_ROMBASEMASK = 0x80000000;
*CSR_CSRBASEMASK = 0;
*CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET);
*CSR_PCIROMBASE = 0;
*CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK |
+ PCI_COMMAND_MASTER |
PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
(1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
#endif
.macro restore_user_regs
ldr r0, [sp, #S_PSR] @ Get calling cpsr
- msr cpsr_c, #I_BIT | MODE_SVC @ disable IRQs
+ mov r1, #I_BIT | MODE_SVC @ disable IRQs
+ msr cpsr_c, r1
msr spsr, r0 @ save in spsr_svc
ldmia sp, {r0 - lr}^ @ Get calling r0 - lr
mov r0, r0
__arch_types_end:
#ifdef CONFIG_DEBUG_LL
+ .text
/*
* Some debugging routines (useful if you've got MM problems and
* printk isn't working). For DEBUGGING ONLY!!! Do not leave
.endm
#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE)
+
+#include <asm/dec21285.h>
+#include <asm/hardware.h>
+
#ifndef CONFIG_DEBUG_DC21285_PORT
/* For NetWinder debugging */
.macro addruart,rx
pci_read_config_word(dev, PCI_STATUS, &status);
if (status & 0xf900) {
- printk(KERN_DEBUG "PCI: [%04X:%04X] status = %X\n",
+ printk(KERN_DEBUG "PCI: %02x:%02x.%d [%04X:%04X] status = 0x%04X\n",
+ dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
dev->vendor, dev->device, status);
pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
void flush_thread(void)
{
- int i;
-
- for (i = 0; i < NR_DEBUGS; i++)
- current->tss.debug[i] = 0;
+ memset(¤t->tss.debug, 0, sizeof(struct debug_info));
+ memset(¤t->tss.fpstate, 0, sizeof(union fp_state));
current->used_math = 0;
current->flags &= ~PF_USEDFPU;
}
*/
int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
{
- int fpvalid = 0;
-
if (current->used_math)
- memcpy (fp, ¤t->tss.fpstate.soft, sizeof (fp));
+ memcpy (fp, ¤t->tss.fpstate.soft, sizeof (*fp));
- return fpvalid;
+ return current->used_math;
}
/*
*/
void dump_thread(struct pt_regs * regs, struct user * dump)
{
- int i;
-
+ struct task_struct *tsk = current;
dump->magic = CMAGIC;
- dump->start_code = current->mm->start_code;
+ dump->start_code = tsk->mm->start_code;
dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1);
- dump->u_tsize = (current->mm->end_code - current->mm->start_code) >> PAGE_SHIFT;
- dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT;
+ dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
dump->u_ssize = 0;
- for (i = 0; i < NR_DEBUGS; i++)
- dump->u_debugreg[i] = current->tss.debug[i];
+ dump->u_debugreg[0] = tsk->tss.debug.bp[0].address;
+ dump->u_debugreg[1] = tsk->tss.debug.bp[1].address;
+ dump->u_debugreg[2] = tsk->tss.debug.bp[0].insn;
+ dump->u_debugreg[3] = tsk->tss.debug.bp[1].insn;
+ dump->u_debugreg[4] = tsk->tss.debug.nsaved;
if (dump->start_stack < 0x04000000)
dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
pid_t __ret;
__asm__ __volatile__(
- "mov r0, %1 @ kernel_thread sys_clone\n"
+ "orr r0, %1, %2 @ kernel_thread\n"
" mov r1, #0\n"
__syscall(clone)"\n"
-" mov %0, r0"
+" movs %0, r0
+ bne 1f
+ mov fp, r0
+ mov r0, %4
+ mov lr, pc
+ mov pc, %3
+ b sys_exit
+1: "
: "=r" (__ret)
- : "Ir" (flags | CLONE_VM) : "r0", "r1");
- if (__ret == 0)
- sys_exit((fn)(arg));
+ : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg): "r0", "r1", "lr");
return __ret;
}
#include <asm/pgtable.h>
#include <asm/system.h>
+
+#define REG_PC 15
+#define REG_PSR 16
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
* Breakpoint SWI instruction: SWI &9F0001
*/
#define BREAKINST 0xef9f0001
-#define PTRACE_GETREGS 12
-#define PTRACE_SETREGS 13
-#define PTRACE_GETFPREGS 14
-#define PTRACE_SETFPREGS 15
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ */
static inline struct pt_regs *
get_user_regs(struct task_struct *task)
{
return 0;
}
+#define write_tsk_long(chld, addr, val) write_long((chld), (addr), (val))
+#define read_tsk_long(chld, addr, val) read_long((chld), (addr), (val))
+
/*
* Get value of register `rn' (in the instruction)
*/
-static unsigned long ptrace_getrn (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getrn(struct task_struct *child, unsigned long insn)
{
unsigned int reg = (insn >> 16) & 15;
unsigned long val;
+ val = get_stack_long(child, reg);
if (reg == 15)
- val = pc_pointer (get_stack_long (child, reg));
- else
- val = get_stack_long (child, reg);
+ val = pc_pointer(val + 8);
+
-printk ("r%02d=%08lX ", reg, val);
return val;
}
/*
* Get value of operand 2 (in an ALU instruction)
*/
-static unsigned long ptrace_getaluop2 (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getaluop2(struct task_struct *child, unsigned long insn)
{
unsigned long val;
int shift;
int type;
-printk ("op2=");
+
if (insn & 1 << 25) {
val = insn & 255;
shift = (insn >> 8) & 15;
type = 3;
-printk ("(imm)");
+
} else {
val = get_stack_long (child, insn & 15);
shift = (insn >> 7) & 31;
type = (insn >> 5) & 3;
-printk ("(r%02ld)", insn & 15);
+
}
-printk ("sh%dx%d", type, shift);
+
switch (type) {
case 0: val <<= shift; break;
case 1: val >>= shift; break;
val = (((signed long)val) >> shift);
break;
case 3:
- __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift));
+ val = (val >> shift) | (val << (32 - shift));
break;
}
-printk ("=%08lX ", val);
+
return val;
}
/*
* Get value of operand 2 (in a LDR instruction)
*/
-static unsigned long ptrace_getldrop2 (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getldrop2(struct task_struct *child, unsigned long insn)
{
unsigned long val;
int shift;
int type;
- val = get_stack_long (child, insn & 15);
+ val = get_stack_long(child, insn & 15);
shift = (insn >> 7) & 31;
type = (insn >> 5) & 3;
-printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type);
+
switch (type) {
case 0: val <<= shift; break;
case 1: val >>= shift; break;
val = (((signed long)val) >> shift);
break;
case 3:
- __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift));
+ val = (val >> shift) | (val << (32 - shift));
break;
}
-printk ("=%08lX ", val);
+
return val;
}
-#undef pc_pointer
-#define pc_pointer(x) ((x) & 0x03fffffc)
-int ptrace_set_bpt (struct task_struct *child)
-{
- unsigned long insn, pc, alt;
- int i, nsaved = 0, res;
-
- pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/));
- res = read_long (child, pc, &insn);
- if (res < 0)
- return res;
+static unsigned long
+get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
+{
+ unsigned long alt = 0;
- child->tss.debug[nsaved++] = alt = pc + 4;
-printk ("ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc);
- switch (insn & 0x0e100000) {
+ switch (insn & 0x0e000000) {
case 0x00000000:
- case 0x00100000:
- case 0x02000000:
- case 0x02100000: /* data processing */
- printk ("data ");
- switch (insn & 0x01e0f000) {
- case 0x0000f000:
- alt = ptrace_getrn(child, insn) & ptrace_getaluop2(child, insn);
- break;
- case 0x0020f000:
- alt = ptrace_getrn(child, insn) ^ ptrace_getaluop2(child, insn);
- break;
- case 0x0040f000:
- alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn);
- break;
- case 0x0060f000:
- alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn);
- break;
- case 0x0080f000:
- alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn);
- break;
- case 0x00a0f000:
- alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x00c0f000:
- alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x00e0f000:
- alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x0180f000:
- alt = ptrace_getrn(child, insn) | ptrace_getaluop2(child, insn);
- break;
- case 0x01a0f000:
- alt = ptrace_getaluop2(child, insn);
- break;
- case 0x01c0f000:
- alt = ptrace_getrn(child, insn) & ~ptrace_getaluop2(child, insn);
- break;
- case 0x01e0f000:
- alt = ~ptrace_getaluop2(child, insn);
+ case 0x02000000: {
+ /*
+ * data processing
+ */
+ long aluop1, aluop2, ccbit;
+
+ if ((insn & 0xf000) != 0xf000)
break;
+
+
+
+ aluop1 = ptrace_getrn(child, insn);
+ aluop2 = ptrace_getaluop2(child, insn);
+ ccbit = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0;
+
+ switch (insn & 0x01e00000) {
+ case 0x00000000: alt = aluop1 & aluop2; break;
+ case 0x00200000: alt = aluop1 ^ aluop2; break;
+ case 0x00400000: alt = aluop1 - aluop2; break;
+ case 0x00600000: alt = aluop2 - aluop1; break;
+ case 0x00800000: alt = aluop1 + aluop2; break;
+ case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break;
+ case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break;
+ case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break;
+ case 0x01800000: alt = aluop1 | aluop2; break;
+ case 0x01a00000: alt = aluop2; break;
+ case 0x01c00000: alt = aluop1 & ~aluop2; break;
+ case 0x01e00000: alt = ~aluop2; break;
}
break;
+ }
+
+ case 0x04000000:
+ case 0x06000000:
+ /*
+ * ldr
+ */
+ if ((insn & 0x0010f000) == 0x0010f000) {
+ unsigned long base;
- case 0x04100000: /* ldr */
- if ((insn & 0xf000) == 0xf000) {
-printk ("ldr ");
- alt = ptrace_getrn(child, insn);
+ base = ptrace_getrn(child, insn);
if (insn & 1 << 24) {
- if (insn & 1 << 23)
- alt += ptrace_getldrop2 (child, insn);
+ long aluop2;
+
+ if (insn & 0x02000000)
+ aluop2 = ptrace_getldrop2(child, insn);
else
- alt -= ptrace_getldrop2 (child, insn);
- }
- if (read_long (child, alt, &alt) < 0)
- alt = pc + 4; /* not valid */
- else
- alt = pc_pointer (alt);
- }
- break;
+ aluop2 = insn & 0xfff;
- case 0x06100000: /* ldr imm */
- if ((insn & 0xf000) == 0xf000) {
-printk ("ldrimm ");
- alt = ptrace_getrn(child, insn);
- if (insn & 1 << 24) {
if (insn & 1 << 23)
- alt += insn & 0xfff;
+ base += aluop2;
else
- alt -= insn & 0xfff;
+ base -= aluop2;
}
- if (read_long (child, alt, &alt) < 0)
- alt = pc + 4; /* not valid */
- else
- alt = pc_pointer (alt);
+
+ if (read_tsk_long(child, base, &alt) == 0)
+ alt = pc_pointer(alt);
}
break;
- case 0x08100000: /* ldm */
- if (insn & (1 << 15)) {
+ case 0x08000000:
+ /*
+ * ldm
+ */
+ if ((insn & 0x00108000) == 0x00108000) {
unsigned long base;
- int nr_regs;
-printk ("ldm ");
+ unsigned int nr_regs;
+
if (insn & (1 << 23)) {
nr_regs = insn & 65535;
nr_regs = 0;
}
- base = ptrace_getrn (child, insn);
+ base = ptrace_getrn(child, insn);
- if (read_long (child, base + nr_regs, &alt) < 0)
- alt = pc + 4; /* not valid */
- else
- alt = pc_pointer (alt);
+ if (read_tsk_long(child, base + nr_regs, &alt) == 0)
+ alt = pc_pointer(alt);
break;
}
break;
- case 0x0a000000:
- case 0x0a100000: { /* bl or b */
+ case 0x0a000000: {
+ /*
+ * bl or b
+ */
signed long displ;
-printk ("b/bl ");
+
/* It's a branch/branch link: instead of trying to
* figure out whether the branch will be taken or not,
- * we'll put a breakpoint at either location. This is
+ * we'll put a breakpoint at both locations. This is
* simpler, more reliable, and probably not a whole lot
* slower than the alternative approach of emulating the
* branch.
ret = 0;
}
}
- goto out;
+ break;
}
+ /*
+ * Get the child FPU state.
+ */
case PTRACE_GETFPREGS:
- /* Get the child FPU state. */
- ret = 0;
- if (copy_to_user((void *)data, &child->tss.fpstate,
- sizeof(struct user_fp)))
- ret = -EFAULT;
- goto out;
-
- case PTRACE_SETFPREGS:
- /* Set the child FPU state. */
- ret = 0;
- if (copy_from_user(&child->tss.fpstate, (void *)data,
- sizeof(struct user_fp)))
- ret = -EFAULT;
- goto out;
+ ret = -EIO;
+ if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp)))
+ break;
- case PTRACE_DETACH: /* detach a process that was attached. */
+ /* we should check child->used_math here */
+ ret = __copy_to_user((void *)data, &child->tss.fpstate,
+ sizeof(struct user_fp)) ? -EFAULT : 0;
+ break;
+
+ /*
+ * Set the child FPU state.
+ */
+ case PTRACE_SETFPREGS:
ret = -EIO;
- if ((unsigned long) data > _NSIG)
- goto out;
- child->flags &= ~(PF_PTRACED|PF_TRACESYS);
- wake_up_process (child);
- child->exit_code = data;
- REMOVE_LINKS(child);
- child->p_pptr = child->p_opptr;
- SET_LINKS(child);
- /* make sure single-step breakpoint is gone. */
- ptrace_cancel_bpt (child);
- ret = 0;
- goto out;
+ if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp)))
+ break;
+
+ child->used_math = 1;
+ ret = __copy_from_user(&child->tss.fpstate, (void *)data,
+ sizeof(struct user_fp)) ? -EFAULT : 0;
+ break;
default:
ret = -EIO;
+ break;
+ }
+
+ return ret;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+ struct task_struct *child;
+ int ret;
+
+ lock_kernel();
+ ret = -EPERM;
+ if (request == PTRACE_TRACEME) {
+ /* are we already being traced? */
+ if (current->flags & PF_PTRACED)
goto out;
+ /* set the ptrace bit in the process flags. */
+ current->flags |= PF_PTRACED;
+ ret = 0;
+ goto out;
}
+ ret = -ESRCH;
+ if (!(child = find_task_by_pid(pid)))
+ goto out;
+
+ ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out;
+
+ if (request == PTRACE_ATTACH) {
+ if (child == current)
+ goto out;
+ if ((!child->dumpable ||
+ (current->uid != child->euid) ||
+ (current->uid != child->suid) ||
+ (current->uid != child->uid) ||
+ (current->gid != child->egid) ||
+ (current->gid != child->sgid) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+ goto out;
+ /* the same process cannot be attached many times */
+ if (child->flags & PF_PTRACED)
+ goto out;
+ child->flags |= PF_PTRACED;
+
+ if (child->p_pptr != current) {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+
+ send_sig(SIGSTOP, child, 1);
+ ret = 0;
+ goto out;
+ }
+ ret = -ESRCH;
+ if (!(child->flags & PF_PTRACED))
+ goto out;
+ if (child->state != TASK_STOPPED && request != PTRACE_KILL)
+ goto out;
+ if (child->p_pptr != current)
+ goto out;
+
+ ret = do_ptrace(request, child, addr, data);
+
out:
unlock_kernel();
return ret;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
+ single_stepping |= ptrace_cancel_bpt(current);
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
LC0: .word SYMBOL_NAME(loops_per_jiffy)
+/*
+ * 0 <= r0 <= 2000
+ */
ENTRY(udelay)
- mov r2, #0x1000
- orr r2, r2, #0x00c6
+ mov r2, #0x00006800
+ orr r2, r2, #0x000000db
mul r1, r0, r2
ldr r2, LC0
ldr r2, [r2]
mov r1, r1, lsr #11
mov r2, r2, lsr #11
mul r0, r1, r2
- movs r0, r0, lsr #10
+ movs r0, r0, lsr #6
RETINSTR(moveq,pc,lr)
+/*
+ * loops = (r0 * 0x10c6 * 100 * loops_per_jiffie) / 2^32
+ */
+
@ Delay routine
ENTRY(__delay)
subs r0, r0, #1
/*
- * linux/arch/arm/lib/memset.S
+ * linux/arch/arm/lib/memset.S
*
- * Copyright (C) 1995-1999 Russell King
+ * Copyright (C) 1995-2000 Russell King
*
- * ASM optimised string functions
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*
+ * ASM optimised string functions
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
-#include "constants.h"
- .text
- .align 5
-ENTRY(memset)
- mov r3, r0
- cmp r2, #16
- blt 6f
- ands ip, r3, #3
- beq 1f
- cmp ip, #2
- strltb r1, [r3], #1 @ Align destination
- strleb r1, [r3], #1
- strb r1, [r3], #1
- rsb ip, ip, #4
- sub r2, r2, ip
-1: orr r1, r1, r1, lsl #8
- orr r1, r1, r1, lsl #16
- cmp r2, #256
- blt 4f
- stmfd sp!, {r4, r5, lr}
- mov r4, r1
- mov r5, r1
- mov lr, r1
- mov ip, r2, lsr #6
- sub r2, r2, ip, lsl #6
-2: stmia r3!, {r1, r4, r5, lr} @ 64 bytes at a time.
- stmia r3!, {r1, r4, r5, lr}
- stmia r3!, {r1, r4, r5, lr}
- stmia r3!, {r1, r4, r5, lr}
- subs ip, ip, #1
- bne 2b
- teq r2, #0
- LOADREGS(eqfd, sp!, {r4, r5, pc}) @ Now <64 bytes to go.
- tst r2, #32
- stmneia r3!, {r1, r4, r5, lr}
- stmneia r3!, {r1, r4, r5, lr}
- tst r2, #16
- stmneia r3!, {r1, r4, r5, lr}
- ldmia sp!, {r4, r5}
-3: tst r2, #8
- stmneia r3!, {r1, lr}
- tst r2, #4
- strne r1, [r3], #4
- tst r2, #2
- strneb r1, [r3], #1
- strneb r1, [r3], #1
- tst r2, #1
- strneb r1, [r3], #1
- LOADREGS(fd, sp!, {pc})
+ .text
+ .align 5
+ .word 0
-4: movs ip, r2, lsr #3
- beq 3b
- sub r2, r2, ip, lsl #3
- stmfd sp!, {lr}
- mov lr, r1
- subs ip, ip, #4
-5: stmgeia r3!, {r1, lr}
- stmgeia r3!, {r1, lr}
- stmgeia r3!, {r1, lr}
- stmgeia r3!, {r1, lr}
- subges ip, ip, #4
- bge 5b
- tst ip, #2
- stmneia r3!, {r1, lr}
- stmneia r3!, {r1, lr}
- tst ip, #1
- stmneia r3!, {r1, lr}
- teq r2, #0
- LOADREGS(eqfd, sp!, {pc})
- b 3b
+1: subs r2, r2, #4 @ 1 do we have enough
+ blt 5f @ 1 bytes to align with?
+ cmp r3, #2 @ 1
+ strltb r1, [r0], #1 @ 1
+ strleb r1, [r0], #1 @ 1
+ strb r1, [r0], #1 @ 1
+ add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
+/*
+ * The pointer is now aligned and the length is adjusted. Try doing the
+ * memzero again.
+ */
-6: subs r2, r2, #1
- strgeb r1, [r3], #1
- bgt 6b
- RETINSTR(mov, pc, lr)
+ENTRY(memset)
+ ands r3, r0, #3 @ 1 unaligned?
+ bne 1b @ 1
+/*
+ * we know that the pointer in r0 is aligned to a word boundary.
+ */
+ orr r1, r1, r1, lsl #8
+ orr r1, r1, r1, lsl #16
+ mov r3, r1
+ cmp r2, #16
+ blt 4f
+/*
+ * We need an extra register for this loop - save the return address and
+ * use the LR
+ */
+ str lr, [sp, #-4]!
+ mov ip, r1
+ mov lr, r1
+2: subs r2, r2, #64
+ stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
+ stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia r0!, {r1, r3, ip, lr}
+ bgt 2b
+ LOADREGS(eqfd, sp!, {pc}) @ Now <64 bytes to go.
+/*
+ * No need to correct the count; we're only testing bits from now on
+ */
+ tst r2, #32
+ stmneia r0!, {r1, r3, ip, lr}
+ stmneia r0!, {r1, r3, ip, lr}
+ tst r2, #16
+ stmneia r0!, {r1, r3, ip, lr}
+ ldr lr, [sp], #4
+4: tst r2, #8
+ stmneia r0!, {r1, r3}
+ tst r2, #4
+ strne r1, [r0], #4
+/*
+ * When we get here, we've got less than 4 bytes to zero. We
+ * may have an unaligned pointer as well.
+ */
+5: tst r2, #2
+ strneb r1, [r0], #1
+ strneb r1, [r0], #1
+ tst r2, #1
+ strneb r1, [r0], #1
+ RETINSTR(mov,pc,lr)
Scsi_Cmnd *cur_cmd; /* Current queued command */
struct tq_struct ppa_tq; /* Polling interupt stuff */
unsigned long jstart; /* Jiffies at start */
+ unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */
unsigned int failed:1; /* Failure flag */
unsigned int p_busy:1; /* Parport sharing busy flag */
} ppa_struct;
cur_cmd: NULL, \
ppa_tq: {0, 0, ppa_interrupt, NULL}, \
jstart: 0, \
+ recon_tmo: PPA_RECON_TMO, \
failed: 0, \
p_busy: 0 \
}
ppa_hosts[hostno].mode = x;
return length;
}
+ if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) {
+ x = simple_strtoul(buffer + 10, NULL, 0);
+ ppa_hosts[hostno].recon_tmo = x;
+ printk("ppa: recon_tmo set to %ld\n", x);
+ return length;
+ }
printk("ppa /proc: invalid variable\n");
return (-EINVAL);
}
len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
len += sprintf(buffer + len, "Parport : %s\n", ppa_hosts[i].dev->port->name);
len += sprintf(buffer + len, "Mode : %s\n", PPA_MODE_STRING[ppa_hosts[i].mode]);
+#if PPA_DEBUG > 0
+ len += sprintf(buffer + len, "recon_tmo : %lu\n", ppa_hosts[i].recon_tmo);
+#endif
/* Request for beyond end of buffer */
if (offset > length)
unsigned char r;
k = PPA_SPIN_TMO;
- do {
- r = r_str(ppb);
- k--;
- udelay(1);
+ /* Wait for bit 6 and 7 - PJC */
+ for (r = r_str (ppb); ((r & 0xc0)!=0xc0) && (k); k--) {
+ udelay (1);
+ r = r_str (ppb);
}
- while (!(r & 0x80) && (k));
/*
* return some status information.
k = PPA_SELECT_TMO;
do {
k--;
+ udelay(1);
} while ((r_str(ppb) & 0x40) && (k));
if (!k)
return 0;
k = PPA_SELECT_TMO;
do {
k--;
+ udelay(1);
}
while (!(r_str(ppb) & 0x40) && (k));
if (!k)
if (time_after(jiffies, start_jiffies + 1))
return 0;
- if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) {
+ if ((cmd->SCp.this_residual <= 0)) {
ppa_fail(host_no, DID_ERROR);
return -1; /* ERROR_RETURN */
}
- /* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
- ? PPA_BURST_SIZE : 1;
+
+ /* On some hardware we have SCSI disconnected (6th bit low)
+ * for about 100usecs. It is too expensive to wait a
+ * tick on every loop so we busy wait for no more than
+ * 500usecs to give the drive a chance first. We do not
+ * change things for "normal" hardware since generally
+ * the 6th bit is always high.
+ * This makes the CPU load higher on some hardware
+ * but otherwise we can not get more then 50K/secs
+ * on this problem hardware.
+ */
+ if ((r & 0xc0) != 0xc0) {
+ /* Wait for reconnection should be no more than
+ * jiffy/2 = 5ms = 5000 loops
+ */
+ unsigned long k = ppa_hosts[host_no].recon_tmo;
+ for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0; k--)
+ udelay(1);
+
+ if(!k)
+ return 0;
+ }
+
+ /* determine if we should use burst I/O */
+ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
+ ? PPA_BURST_SIZE : 1;
if (r == (unsigned char) 0xc0)
status = ppa_out(host_no, cmd->SCp.ptr, fast);
#ifndef _PPA_H
#define _PPA_H
-#define PPA_VERSION "2.03 (for Linux 2.2.x)"
+#define PPA_VERSION "2.04a (for Linux 2.2.x)"
/*
* this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
* CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16
* added CONFIG_SCSI_IZIP_SLOW_CTR option
* [2.03]
+ *
+ * Use ppa_wait() to check for ready AND connected status bits
+ * Busy wait for connected status bit in ppa_completion()
+ * in order to cope with some hardware that has this bit low
+ * for short periods of time.
+ * Add udelay() to ppa_select()
+ * by Dr. Peter Cherriman and
+ * Oleg Makarenko <omakarenko@cyberplat.ru>
+ * [2.04a]
*/
/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
#define PPA_BURST_SIZE 512 /* data burst size */
#define PPA_SELECT_TMO 5000 /* how long to wait for target ? */
#define PPA_SPIN_TMO 50000 /* ppa_wait loop limiter */
+#define PPA_RECON_TMO 500 /* scsi reconnection loop limiter */
#define PPA_DEBUG 0 /* debuging option */
#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)
fi
dep_tristate 'ESS Maestro' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
+dep_tristate 'ESS Maestro3' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND
dep_tristate 'ESS Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
dep_tristate 'Intel ICH (810, 820, 440MX...)' CONFIG_SOUND_ICH $CONFIG_SOUND
obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o
obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o
obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
+obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o
obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
--- /dev/null
+/*****************************************************************************
+ *
+ * ESS Maestro3/Allegro driver for Linux 2.2.x
+ *
+ * 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.
+ *
+ * (c) Copyright 2000 Zach Brown <zab@zabbo.net>
+ *
+ * I need to thank many people for helping make this driver happen.
+ * As always, Eric Brombaugh was a hacking machine and killed many bugs
+ * that I was too dumb to notice. Howard Kim at ESS provided reference boards
+ * and as much docs as he could. Todd and Mick at Dell tested snapshots on
+ * an army of laptops. msw and deviant at Red Hat also humoured me by hanging
+ * their laptops every few hours in the name of science.
+ *
+ * Shouts go out to Mike "DJ XPCom" Ang.
+ *
+ * History
+ * v0.51 - Dec 31 2000 - Zach Brown <zab@zabbo.net>
+ * fix up incredibly broken open/release resource management
+ * duh. fix record format setting.
+ * add SMP locking and cleanup formatting here and there
+ * v0.50 - Dec 16 2000 - Zach Brown <zab@zabbo.net>
+ * use native ac97_codec
+ * pull out most SILLY_ stuff
+ * align instance allocation so record works
+ * fix up PCI IDs..
+ * v0.02 - Nov 04 2000 - Zach Brown <zab@zabbo.net>
+ * changed clocking setup for m3, slowdown fixed.
+ * codec reset is hopefully reliable now
+ * rudimentary apm/power management makes suspend/resume work
+ * v0.01 - Oct 31 2000 - Zach Brown <zab@zabbo.net>
+ * first release
+ * v0.00 - Sep 09 2000 - Zach Brown <zab@zabbo.net>
+ * first pass derivation from maestro.c
+ *
+ * TODO
+ * no beep on init (mute)
+ * resetup msrc data memory if freq changes?
+ * clean up driver in general, 2.2/2.3 junk, etc.
+ *
+ * ---
+ *
+ * Allow me to ramble a bit about the m3 architecture. The core of the
+ * chip is the 'assp', the custom ESS dsp that runs the show. It has
+ * a small amount of code and data ram. ESS drops binary dsp code images
+ * on our heads, but we don't get to see specs on the dsp.
+ *
+ * The constant piece of code on the dsp is the 'kernel'. It also has a
+ * chunk of the dsp memory that is statically set aside for its control
+ * info. This is the KDATA defines in maestro3.h. Part of its core
+ * data is a list of code addresses that point to the pieces of DSP code
+ * that it should walk through in its loop. These other pieces of code
+ * do the real work. The kernel presumably jumps into each of them in turn.
+ * These code images tend to have their own data area, and one can have
+ * multiple data areas representing different states for each of the 'client
+ * instance' code portions. There is generaly a list in the kernel data
+ * that points to the data instances for a given piece of code.
+ *
+ * We've only been given the binary image for the 'minisrc', mini sample
+ * rate converter. This is rather annoying because it limits the work
+ * we can do on the dsp, but it also greatly simplifies the job of managing
+ * dsp data memory for the code and data for our playing streams :). We
+ * statically allocate the minisrc code into a region we 'know' to be free
+ * based on the map of the binary kernel image we're loading. We also
+ * statically allocate the data areas for the maximum number of pcm streams
+ * we can be dealing with. This max is set by the length of the static list
+ * in the kernel data that records the number of minisrc data regions we
+ * can have. Thats right, all software dsp mixing with static code list
+ * limits. Rock.
+ *
+ * How sound goes in and out is still a relative mystery. It appears
+ * that the dsp has the ability to get input and output through various
+ * 'connections'. To do IO from or to a connection, you put the address
+ * of the minisrc client area in the static kernel data lists for that
+ * input or output. so for pcm -> dsp -> mixer, we put the minisrc data
+ * instance in the DMA list and also in the list for the mixer. I guess
+ * it Just Knows which is in/out, and we give some dma control info that
+ * helps. There are all sorts of cool inputs/outputs that it seems we can't
+ * use without dsp code images that know how to use them.
+ *
+ * So at init time we preload all the memory allocation stuff and set some
+ * system wide parameters. When we really get a sound to play we build
+ * up its minisrc header (stream parameters, buffer addresses, input/output
+ * settings). Then we throw its header on the various lists. We also
+ * tickle some KDATA settings that ask the assp to raise clock interrupts
+ * and do some amount of software mixing before handing data to the ac97.
+ *
+ * Sorry for the vague details. Feel free to ask Eric or myself if you
+ * happen to be trying to use this driver elsewhere. Please accept my
+ * apologies for the quality of the OSS support code, its passed through
+ * too many hands now and desperately wants to be rethought.
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/ctype.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 <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/reboot.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/spinlock.h>
+
+ /*
+ * apologies for old intra-2.2 and
+ * 2.2->2.4 compat cruft.. it will
+ * die someday.
+ */
+#ifndef wait_queue_head_t
+ #define wait_queue_head_t struct wait_queue *
+#endif
+#ifndef DECLARE_WAITQUEUE
+ #define DECLARE_WAITQUEUE(QUEUE,INIT) struct wait_queue QUEUE = {INIT, NULL}
+#endif
+#ifndef init_waitqueue_head
+ #define init_waitqueue_head init_waitqueue
+#endif
+
+#define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)
+#define SILLY_INIT_SEM(SEM) SEM=MUTEX;
+#define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC)
+#define SILLY_OFFSET(VMA) ((VMA)->vm_offset)
+
+#include <linux/ac97_codec.h>
+
+#include "maestro3.h"
+
+#define M_DEBUG 1
+
+#define DRIVER_VERSION "0.51"
+#define PFX "maestro3: "
+
+#ifndef PCI_VENDOR_ESS
+#define PCI_VENDOR_ESS 0x125D
+#endif
+
+#define M3_STATE_MAGIC 0x734d724d
+#define M3_CARD_MAGIC 0x646e6f50
+
+#define ESS_FMT_STEREO 0x01
+#define ESS_FMT_16BIT 0x02
+#define ESS_FMT_MASK 0x03
+#define ESS_DAC_SHIFT 0
+#define ESS_ADC_SHIFT 4
+
+#define DAC_RUNNING 1
+#define ADC_RUNNING 2
+
+#define SND_DEV_DSP16 5
+
+
+#ifdef M_DEBUG
+static int debug=0;
+static int global_dsp_speed = 49;
+#define DPMOD 1 /* per module load */
+#define DPSTR 2 /* per 'stream' */
+#define DPSYS 3 /* per syscall */
+#define DPCRAP 4 /* stuff the user shouldn't see unless they're really debuggin */
+#define DPINT 5 /* per interrupt, LOTS */
+#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);}
+#else
+#define DPRINTK(x)
+#endif
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int m3_apm_callback(apm_event_t ae);
+static int in_suspend=0;
+wait_queue_head_t suspend_queue;
+static void check_suspend(void);
+#else
+#define check_suspend(args...)
+#define in_suspend 0
+#endif
+
+struct m3_list {
+ int curlen;
+ int mem_addr;
+ int max;
+};
+
+int external_amp = 1;
+static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf);
+
+struct notifier_block maestro_nb = {maestro_notifier, NULL, 0};
+
+struct ess_state {
+ unsigned int magic;
+ struct ess_card *card;
+ unsigned char fmt, enable;
+
+ spinlock_t lock;
+
+ int index;
+
+ struct semaphore open_sem;
+ wait_queue_head_t open_wait;
+ mode_t open_mode;
+
+ int dev_audio;
+
+ struct assp_instance {
+ u16 code, data;
+ } dac_inst, adc_inst;
+
+ /* should be in dmabuf */
+ unsigned int rateadc, ratedac;
+
+ 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;
+ /* new in m3 */
+ int mixer_index, dma_index, msrc_index, adc1_index;
+ int in_lists;
+
+ } dma_dac, dma_adc;
+};
+
+struct ess_card {
+ unsigned int magic;
+
+ struct ess_card *next;
+
+ struct ac97_codec *ac97;
+ spinlock_t ac97_lock;
+
+ int card_type;
+
+#define NR_DSPS 1
+#define MAX_DSPS NR_DSPS
+ struct ess_state channels[MAX_DSPS];
+
+ spinlock_t lock;
+
+ /* hardware resources */
+ struct pci_dev *pcidev;
+ u32 iobase;
+ u32 irq;
+
+ int dacs_active;
+
+ int timer_users;
+
+ struct m3_list msrc_list,
+ mixer_list,
+ adc1_list,
+ dma_list;
+
+ /* for storing reset state..*/
+ u8 reset_state;
+
+#ifdef CONFIG_APM
+ u16 *suspend_dsp_mem;
+#endif
+};
+
+/*
+ * an arbitrary volume we set the internal
+ * volume settings to so that the ac97 volume
+ * range is a little less insane. 0x7fff is
+ * max.
+ */
+#define ARB_VOLUME ( 0x6800 )
+
+static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+
+enum {
+ ESS_ALLEGRO,
+ ESS_MAESTRO3,
+ /* hardware strapping */
+ ESS_MAESTRO3HW
+};
+
+static struct card_type {
+ int pci_id;
+ int type;
+ char *name;
+} m3_card_types[] = {
+ {0x1988, ESS_ALLEGRO, "Allegro"},
+ {0x1998, ESS_MAESTRO3, "Maestro3(i)"},
+ {0x199a, ESS_MAESTRO3, "Maestro3(i)hw"},
+};
+#define NUM_CARD_TYPES ( sizeof(m3_card_types) / sizeof(m3_card_types[0]) )
+
+static 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;
+}
+
+static struct ess_card *devs = NULL;
+
+static void m3_outw(struct ess_card *card,
+ u16 value, unsigned long reg)
+{
+ check_suspend();
+ outw(value, card->iobase + reg);
+}
+
+static u16 m3_inw(struct ess_card *card, unsigned long reg)
+{
+ check_suspend();
+ return inw(card->iobase + reg);
+}
+static void m3_outb(struct ess_card *card,
+ u8 value, unsigned long reg)
+{
+ check_suspend();
+ outb(value, card->iobase + reg);
+}
+static u8 m3_inb(struct ess_card *card, unsigned long reg)
+{
+ check_suspend();
+ return inb(card->iobase + reg);
+}
+
+/*
+ * access 16bit words to the code or data regions of the dsp's memory.
+ * index addresses 16bit words.
+ */
+static u16 __m3_assp_read(struct ess_card *card, u16 region, u16 index)
+{
+ m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
+ m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
+ return m3_inw(card, DSP_PORT_MEMORY_DATA);
+}
+static u16 m3_assp_read(struct ess_card *card, u16 region, u16 index)
+{
+ unsigned long flags;
+ u16 ret;
+
+ spin_lock_irqsave(&(card->lock), flags);
+ ret = __m3_assp_read(card, region, index);
+ spin_unlock_irqrestore(&(card->lock), flags);
+
+ return ret;
+}
+static void __m3_assp_write(struct ess_card *card,
+ u16 region, u16 index, u16 data)
+{
+ m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
+ m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
+ m3_outw(card, data, DSP_PORT_MEMORY_DATA);
+}
+
+static void m3_assp_write(struct ess_card *card,
+ u16 region, u16 index, u16 data)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&(card->lock), flags);
+ __m3_assp_write(card, region, index, data);
+ spin_unlock_irqrestore(&(card->lock), flags);
+}
+
+static void m3_assp_halt(struct ess_card *card)
+{
+ card->reset_state = m3_inb(card, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
+ mdelay(10);
+ m3_outb(card, card->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
+}
+
+static void m3_assp_continue(struct ess_card *card)
+{
+ m3_outb(card, card->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
+}
+
+/*
+ * This makes me sad. the maestro3 has lists
+ * internally that must be packed.. 0 terminates,
+ * apparently, or maybe all unused entries have
+ * to be 0, the lists have static lengths set
+ * by the binary code images.
+ */
+
+static int m3_add_list(struct ess_card *card,
+ struct m3_list *list, u16 val)
+{
+ DPRINTK(DPSTR, "adding val 0x%x to list 0x%p at pos %d\n",
+ val, list, list->curlen);
+
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ list->mem_addr + list->curlen,
+ val);
+
+ return list->curlen++;
+
+}
+
+static void m3_remove_list(struct ess_card *card,
+ struct m3_list *list, int index)
+{
+ u16 val;
+ int lastindex = list->curlen - 1;
+
+ DPRINTK(DPSTR, "removing ind %d from list 0x%p\n",
+ index, list);
+
+ if(index != lastindex) {
+ val = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+ list->mem_addr + lastindex);
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ list->mem_addr + index,
+ val);
+ }
+
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ list->mem_addr + lastindex,
+ 0);
+
+ list->curlen--;
+}
+
+static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
+{
+ int tmp;
+
+ s->fmt = (s->fmt & mask) | data;
+
+ tmp = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
+
+ /* write to 'mono' word */
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + SRC3_DIRECTION_OFFSET + 1,
+ (tmp & ESS_FMT_STEREO) ? 0 : 1);
+ /* write to '8bit' word */
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + SRC3_DIRECTION_OFFSET + 2,
+ (tmp & ESS_FMT_16BIT) ? 0 : 1);
+
+ tmp = (s->fmt >> ESS_ADC_SHIFT) & ESS_FMT_MASK;
+
+ /* write to 'mono' word */
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + SRC3_DIRECTION_OFFSET + 1,
+ (tmp & ESS_FMT_STEREO) ? 0 : 1);
+ /* write to '8bit' word */
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + SRC3_DIRECTION_OFFSET + 2,
+ (tmp & ESS_FMT_16BIT) ? 0 : 1);
+}
+
+static void set_dac_rate(struct ess_state *s, unsigned int rate)
+{
+ u32 freq;
+
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 8000)
+ rate = 8000;
+
+ s->ratedac = rate;
+
+ freq = ((rate << 15) + 24000 ) / 48000;
+ if(freq)
+ freq--;
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_FREQUENCY,
+ freq);
+}
+
+static void set_adc_rate(struct ess_state *s, unsigned int rate)
+{
+ u32 freq;
+
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 8000)
+ rate = 8000;
+
+ s->rateadc = rate;
+
+ freq = ((rate << 15) + 24000 ) / 48000;
+ if(freq)
+ freq--;
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_FREQUENCY,
+ freq);
+}
+
+static void inc_timer_users(struct ess_card *card)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ card->timer_users++;
+ DPRINTK(DPSYS, "inc timer users now %d\n",
+ card->timer_users);
+ if(card->timer_users != 1)
+ goto out;
+
+ __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_TIMER_COUNT_RELOAD,
+ 240 ) ;
+
+ __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_TIMER_COUNT_CURRENT,
+ 240 ) ;
+
+ m3_outw(card,
+ m3_inw(card, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE,
+ HOST_INT_CTRL);
+
+out:
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void dec_timer_users(struct ess_card *card)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ card->timer_users--;
+ DPRINTK(DPSYS, "dec timer users now %d\n",
+ card->timer_users);
+ if(card->timer_users > 0 )
+ goto out;
+
+ __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_TIMER_COUNT_RELOAD,
+ 0 ) ;
+
+ __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_TIMER_COUNT_CURRENT,
+ 0 ) ;
+
+ m3_outw(card, m3_inw(card, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE,
+ HOST_INT_CTRL);
+out:
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/*
+ * {start,stop}_{adc,dac} should be called
+ * while holding the 'state' lock and they
+ * will try to grab the 'card' lock..
+ */
+static void stop_adc(struct ess_state *s)
+{
+ if (! (s->enable & ADC_RUNNING))
+ return;
+
+ s->enable &= ~ADC_RUNNING;
+ dec_timer_users(s->card);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_INSTANCE_READY, 0);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ KDATA_ADC1_REQUEST, 0);
+}
+
+static void stop_dac(struct ess_state *s)
+{
+ if (! (s->enable & DAC_RUNNING))
+ return;
+
+ DPRINTK(DPSYS, "stop_dac()\n");
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_INSTANCE_READY, 0);
+
+ s->enable &= ~DAC_RUNNING;
+ s->card->dacs_active--;
+ dec_timer_users(s->card);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ KDATA_MIXER_TASK_NUMBER,
+ s->card->dacs_active ) ;
+}
+
+static void start_dac(struct ess_state *s)
+{
+ if( (!s->dma_dac.mapped && s->dma_dac.count < 1) ||
+ !s->dma_dac.ready ||
+ (s->enable & DAC_RUNNING))
+ return;
+
+ DPRINTK(DPSYS, "start_dac()\n");
+
+ s->enable |= DAC_RUNNING;
+ s->card->dacs_active++;
+ inc_timer_users(s->card);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_INSTANCE_READY, 1);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ KDATA_MIXER_TASK_NUMBER,
+ s->card->dacs_active ) ;
+}
+
+static void start_adc(struct ess_state *s)
+{
+ if ((! s->dma_adc.mapped &&
+ s->dma_adc.count >= (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+ || !s->dma_adc.ready
+ || (s->enable & ADC_RUNNING) )
+ return;
+
+ DPRINTK(DPSYS, "start_adc()\n");
+
+ s->enable |= ADC_RUNNING;
+ inc_timer_users(s->card);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ KDATA_ADC1_REQUEST, 1);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_INSTANCE_READY, 1);
+}
+
+static struct play_vals {
+ u16 addr, val;
+} pv[] = {
+ {CDATA_LEFT_VOLUME, ARB_VOLUME},
+ {CDATA_RIGHT_VOLUME, ARB_VOLUME},
+ {SRC3_DIRECTION_OFFSET, 0} ,
+ /* +1, +2 are stereo/16 bit */
+ {SRC3_DIRECTION_OFFSET + 3, 0X0000}, /* fraction? */
+ {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
+ {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
+ {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
+ {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
+ {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
+ {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
+ {SRC3_DIRECTION_OFFSET + 10, 0X8000}, /* round */
+ {SRC3_DIRECTION_OFFSET + 11, 0XFF00}, /* higher bute mark */
+ {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
+ {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
+ {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
+ {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */
+ {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */
+ {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */
+ {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
+ {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */
+};
+
+static void
+ess_play_setup(struct ess_state *s, int mode, u32 rate, void *buffer, int size)
+{
+ int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
+ int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
+ int dsp_in_buffer = s->dac_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
+ int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
+ struct dmabuf *db = &s->dma_dac;
+ int i;
+
+ DPRINTK(DPSTR, "mode=%d rate=%d buf=%p len=%d.\n",
+ mode, rate, buffer, size);
+
+#define LO(x) ((x) & 0xffff)
+#define HI(x) LO((x) >> 16)
+
+ /* host dma buffer pointers */
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_HOST_SRC_ADDRL,
+ LO(virt_to_bus(buffer)));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_HOST_SRC_ADDRH,
+ HI(virt_to_bus(buffer)));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
+ LO(virt_to_bus(buffer) + size));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
+ HI(virt_to_bus(buffer) + size));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_HOST_SRC_CURRENTL,
+ LO(virt_to_bus(buffer)));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_HOST_SRC_CURRENTH,
+ HI(virt_to_bus(buffer)));
+#undef LO
+#undef HI
+
+ /* dsp buffers */
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_IN_BUF_BEGIN,
+ dsp_in_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_IN_BUF_END_PLUS_1,
+ dsp_in_buffer + (dsp_in_size / 2));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_IN_BUF_HEAD,
+ dsp_in_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_IN_BUF_TAIL,
+ dsp_in_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_OUT_BUF_BEGIN,
+ dsp_out_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_OUT_BUF_END_PLUS_1,
+ dsp_out_buffer + (dsp_out_size / 2));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_OUT_BUF_HEAD,
+ dsp_out_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_OUT_BUF_TAIL,
+ dsp_out_buffer);
+
+ /*
+ * some per client initializers
+ */
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + SRC3_DIRECTION_OFFSET + 12,
+ s->dac_inst.data + 40 + 8);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + SRC3_DIRECTION_OFFSET + 19,
+ s->dac_inst.code + MINISRC_COEF_LOC);
+
+ /* enable or disable low pass filter? */
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + SRC3_DIRECTION_OFFSET + 22,
+ s->ratedac > 45000 ? 0xff : 0 );
+
+ /* tell it which way dma is going? */
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + CDATA_DMA_CONTROL,
+ DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
+
+ /*
+ * set an armload of static initializers
+ */
+ for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++)
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->dac_inst.data + pv[i].addr, pv[i].val);
+
+ /*
+ * put us in the lists if we're not already there
+ */
+
+ if(db->in_lists == 0) {
+
+ db->msrc_index = m3_add_list(s->card, &s->card->msrc_list,
+ s->dac_inst.data >> DP_SHIFT_COUNT);
+
+ db->dma_index = m3_add_list(s->card, &s->card->dma_list,
+ s->dac_inst.data >> DP_SHIFT_COUNT);
+
+ db->mixer_index = m3_add_list(s->card, &s->card->mixer_list,
+ s->dac_inst.data >> DP_SHIFT_COUNT);
+
+ db->in_lists = 1;
+ }
+
+ set_dac_rate(s,rate);
+ start_dac(s);
+}
+
+/*
+ * Native record driver
+ */
+static struct rec_vals {
+ u16 addr, val;
+} rv[] = {
+ {CDATA_LEFT_VOLUME, ARB_VOLUME},
+ {CDATA_RIGHT_VOLUME, ARB_VOLUME},
+ {SRC3_DIRECTION_OFFSET, 1} ,
+ /* +1, +2 are stereo/16 bit */
+ {SRC3_DIRECTION_OFFSET + 3, 0X0000}, /* fraction? */
+ {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
+ {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
+ {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
+ {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
+ {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
+ {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
+ {SRC3_DIRECTION_OFFSET + 10, 0X8000}, /* round */
+ {SRC3_DIRECTION_OFFSET + 11, 0XFF00}, /* higher bute mark */
+ {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
+ {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
+ {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
+ {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */
+ {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */
+ {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */
+ {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */
+ {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
+ {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */
+ {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */
+};
+
+/*
+ * the buffer passed here must be 32bit aligned
+ */
+static void
+ess_rec_setup(struct ess_state *s, int mode, u32 rate, void *buffer, int size)
+{
+ int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
+ int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
+ int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
+ int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
+ struct dmabuf *db = &s->dma_adc;
+ int i;
+
+ DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n",
+ mode, rate, buffer, size);
+
+#define LO(x) ((x) & 0xffff)
+#define HI(x) LO((x) >> 16)
+
+ /* host dma buffer pointers */
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_HOST_SRC_ADDRL,
+ LO(virt_to_bus(buffer)));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_HOST_SRC_ADDRH,
+ HI(virt_to_bus(buffer)));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
+ LO(virt_to_bus(buffer) + size));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
+ HI(virt_to_bus(buffer) + size));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_HOST_SRC_CURRENTL,
+ LO(virt_to_bus(buffer)));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_HOST_SRC_CURRENTH,
+ HI(virt_to_bus(buffer)));
+#undef LO
+#undef HI
+
+ /* dsp buffers */
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_IN_BUF_BEGIN,
+ dsp_in_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1,
+ dsp_in_buffer + (dsp_in_size / 2));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_IN_BUF_HEAD,
+ dsp_in_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_IN_BUF_TAIL,
+ dsp_in_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_OUT_BUF_BEGIN,
+ dsp_out_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1,
+ dsp_out_buffer + (dsp_out_size / 2));
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_OUT_BUF_HEAD,
+ dsp_out_buffer);
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_OUT_BUF_TAIL,
+ dsp_out_buffer);
+
+ /*
+ * some per client initializers
+ */
+
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12,
+ s->adc_inst.data + 40 + 8);
+
+ /* tell it which way dma is going? */
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + CDATA_DMA_CONTROL,
+ DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT +
+ DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
+
+ /*
+ * set an armload of static initializers
+ */
+ for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++)
+ m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+ s->adc_inst.data + rv[i].addr, rv[i].val);
+
+ /*
+ * put us in the lists if we're not already there
+ */
+
+ if(db->in_lists == 0) {
+
+ db->adc1_index = m3_add_list(s->card, &s->card->adc1_list,
+ s->adc_inst.data >> DP_SHIFT_COUNT);
+
+ db->dma_index = m3_add_list(s->card, &s->card->dma_list,
+ s->adc_inst.data >> DP_SHIFT_COUNT);
+
+ db->msrc_index = m3_add_list(s->card, &s->card->msrc_list,
+ s->adc_inst.data >> DP_SHIFT_COUNT);
+
+ db->in_lists = 1;
+ }
+
+ set_fmt(s, ~0, 0);
+ set_adc_rate(s,rate);
+ start_adc(s);
+}
+/* --------------------------------------------------------------------- */
+
+static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count)
+{
+ DPRINTK(DPINT,"set_dmaa??\n");
+}
+
+static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count)
+{
+ DPRINTK(DPINT,"set_dmac??\n");
+}
+
+u32 get_dma_pos(struct ess_card *card,
+ int instance_addr)
+{
+ u16 hi = 0, lo = 0;
+ int retry = 10;
+
+ /*
+ * try and get a valid answer
+ */
+ while(retry--) {
+ hi = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+ instance_addr + CDATA_HOST_SRC_CURRENTH);
+
+ lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+ instance_addr + CDATA_HOST_SRC_CURRENTL);
+
+ if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+ instance_addr + CDATA_HOST_SRC_CURRENTH))
+ break;
+ }
+ return lo | (hi<<16);
+}
+
+u32 get_dmaa(struct ess_state *s)
+{
+ u32 offset;
+
+ offset = get_dma_pos(s->card, s->dac_inst.data) -
+ virt_to_bus(s->dma_dac.rawbuf);
+
+ DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset);
+
+ return offset;
+}
+
+u32 get_dmac(struct ess_state *s)
+{
+ u32 offset;
+
+ offset = get_dma_pos(s->card, s->adc_inst.data) -
+ virt_to_bus(s->dma_adc.rawbuf);
+
+ DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset);
+
+ return offset;
+
+}
+
+static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static int
+prog_dmabuf(struct ess_state *s, unsigned rec)
+{
+ struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
+ unsigned rate = rec ? s->rateadc : s->ratedac;
+ unsigned bytepersec;
+ unsigned bufs;
+ unsigned char fmt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+
+ fmt = s->fmt;
+ if (rec) {
+ stop_adc(s);
+ fmt >>= ESS_ADC_SHIFT;
+ } else {
+ stop_dac(s);
+ fmt >>= ESS_DAC_SHIFT;
+ }
+ fmt &= ESS_FMT_MASK;
+
+ db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+
+ bytepersec = rate << sample_shift[fmt];
+ bufs = PAGE_SIZE << db->buforder;
+ if (db->ossfragshift) {
+ if ((1000 << db->ossfragshift) < bytepersec)
+ db->fragshift = ld2(bytepersec/1000);
+ else
+ db->fragshift = db->ossfragshift;
+ } else {
+ db->fragshift = ld2(bytepersec/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[fmt];
+ db->dmasize = db->numfrag << db->fragshift;
+
+ DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
+
+ memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
+
+ if (rec)
+ ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
+ else
+ ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
+
+ db->ready = 1;
+
+ spin_unlock_irqrestore(&s->lock, flags);
+
+ return 0;
+}
+
+static void clear_advance(struct ess_state *s)
+{
+ unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
+
+ unsigned char *buf = s->dma_dac.rawbuf;
+ unsigned bsize = s->dma_dac.dmasize;
+ unsigned bptr = s->dma_dac.swptr;
+ unsigned len = s->dma_dac.fragsize;
+
+ if (bptr + len > bsize) {
+ unsigned x = bsize - bptr;
+ memset(buf + bptr, c, x);
+ /* account for wrapping? */
+ bptr = 0;
+ len -= x;
+ }
+ memset(buf + bptr, c, len);
+}
+
+static void ess_update_ptr(struct ess_state *s)
+{
+ unsigned hwptr;
+ int diff;
+
+ /* update ADC pointer */
+ if (s->dma_adc.ready) {
+ hwptr = get_dmac(s) % s->dma_adc.dmasize;
+ diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+ s->dma_adc.hwptr = hwptr;
+ s->dma_adc.total_bytes += diff;
+ s->dma_adc.count += diff;
+ if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+ wake_up(&s->dma_adc.wait);
+ if (!s->dma_adc.mapped) {
+ if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+ stop_adc(s);
+ /* brute force everyone back in sync, sigh */
+ s->dma_adc.count = 0;
+ s->dma_adc.swptr = 0;
+ s->dma_adc.hwptr = 0;
+ s->dma_adc.error++;
+ }
+ }
+ }
+ /* update DAC pointer */
+ if (s->dma_dac.ready) {
+ hwptr = get_dmaa(s) % s->dma_dac.dmasize;
+ diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+
+ DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n",
+ hwptr,diff,s->dma_dac.count);
+
+ s->dma_dac.hwptr = hwptr;
+ s->dma_dac.total_bytes += diff;
+
+ 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) {
+ DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n",
+ diff, diff,
+ s->dma_dac.count,
+ s->dma_dac.count,
+ hwptr, hwptr,
+ s->dma_dac.swptr,
+ s->dma_dac.swptr);
+ stop_dac(s);
+ /* brute force everyone back in sync, sigh */
+ s->dma_dac.count = 0;
+ s->dma_dac.swptr = hwptr;
+ s->dma_dac.error++;
+ } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+ clear_advance(s);
+ s->dma_dac.endcleared = 1;
+ }
+ if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
+ wake_up(&s->dma_dac.wait);
+ DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n",
+ s->dma_dac.count, s->dma_dac.swptr, hwptr);
+ }
+ }
+ }
+}
+
+static void
+ess_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ess_card *c = (struct ess_card *)dev_id;
+ struct ess_state *s = &c->channels[0];
+ u8 status;
+
+ status = inb(c->iobase + 0x1A);
+
+ if(status == 0xff)
+ return;
+
+ /* presumably acking the ints? */
+ outw(status, c->iobase + 0x1A);
+
+ if(in_suspend)
+ return;
+
+ /*
+ * ack an assp int if its running
+ * and has an int pending
+ */
+ if( status & ASSP_INT_PENDING) {
+ u8 ctl = inb(c->iobase + ASSP_CONTROL_B);
+ if( !(ctl & STOP_ASSP_CLOCK)) {
+ ctl = inb(c->iobase + ASSP_HOST_INT_STATUS );
+ if(ctl & DSP2HOST_REQ_TIMER) {
+ outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS);
+
+ /* update adc/dac info if it was a timer int */
+ spin_lock(&s->lock);
+ ess_update_ptr(s);
+ spin_unlock(&s->lock);
+ }
+ }
+ }
+
+ /* XXX is this needed? */
+ if(status & 0x40)
+ outb(0x40, c->iobase+0x1A);
+}
+
+
+/* --------------------------------------------------------------------- */
+
+static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n";
+
+#define VALIDATE_MAGIC(FOO,MAG) \
+({ \
+ if (!(FOO) || (FOO)->magic != MAG) { \
+ printk(invalid_magic,__FUNCTION__); \
+ return -ENXIO; \
+ } \
+})
+
+#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC)
+#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC)
+
+/* --------------------------------------------------------------------- */
+
+static loff_t m3_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int drain_dac(struct ess_state *s, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait,current);
+ unsigned long flags;
+ int count;
+ signed long tmo;
+
+ if (s->dma_dac.mapped || !s->dma_dac.ready)
+ return 0;
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&s->dma_dac.wait, &wait);
+ for (;;) {
+ 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->ratedac;
+ tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
+ /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
+ or something. who cares. - zach */
+ if (!schedule_timeout(tmo ? tmo : 1) && tmo)
+ DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies);
+ }
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+static ssize_t
+ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct ess_state *s = (struct ess_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(s, 1)))
+ return ret;
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return -EFAULT;
+ ret = 0;
+
+ spin_lock_irqsave(&s->lock, flags);
+
+ while (count > 0) {
+ int timed_out;
+
+ swptr = s->dma_adc.swptr;
+ cnt = s->dma_adc.dmasize-swptr;
+ if (s->dma_adc.count < cnt)
+ cnt = s->dma_adc.count;
+
+ if (cnt > count)
+ cnt = count;
+
+ if (cnt <= 0) {
+ start_adc(s);
+ if (file->f_flags & O_NONBLOCK) {
+ ret = ret ? ret : -EAGAIN;
+ goto out;
+ }
+
+ spin_unlock_irqrestore(&s->lock, flags);
+
+ timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0;
+
+ spin_lock_irqsave(&s->lock, flags);
+
+ if(timed_out) {
+ printk("read: chip lockup? dmasz %d fragsz %d count %d hwptr %d swptr %d\n",
+ s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
+ s->dma_adc.hwptr, s->dma_adc.swptr);
+ stop_adc(s);
+ set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
+ s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+ }
+
+ if (signal_pending(current)) {
+ ret = ret ? ret : -ERESTARTSYS;
+ goto out;
+ }
+ continue;
+ }
+
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+ ret = ret ? ret : -EFAULT;
+ return ret;
+ }
+ spin_lock_irqsave(&s->lock, flags);
+
+ swptr = (swptr + cnt) % s->dma_adc.dmasize;
+ s->dma_adc.swptr = swptr;
+ s->dma_adc.count -= cnt;
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ start_adc(s);
+ }
+
+out:
+ spin_unlock_irqrestore(&s->lock, flags);
+ return ret;
+}
+
+static ssize_t
+ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ struct ess_state *s = (struct ess_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(s, 0)))
+ return ret;
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+ ret = 0;
+
+ spin_lock_irqsave(&s->lock, flags);
+
+ while (count > 0) {
+ int timed_out;
+
+ 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;
+
+ if (cnt > count)
+ cnt = count;
+
+ if (cnt <= 0) {
+ start_dac(s);
+ if (file->f_flags & O_NONBLOCK) {
+ if(!ret) ret = -EAGAIN;
+ goto out;
+ }
+
+ spin_unlock_irqrestore(&s->lock, flags);
+ timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0;
+ spin_lock_irqsave(&s->lock, flags);
+
+ if(timed_out) {
+ DPRINTK(DPCRAP,"write: chip lockup? dmasz %d fragsz %d count %d hwptr %d swptr %d\n",
+ s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
+ s->dma_dac.hwptr, s->dma_dac.swptr);
+ stop_dac(s);
+ set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
+ s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+ }
+ if (signal_pending(current)) {
+ if (!ret) ret = -ERESTARTSYS;
+ goto out;
+ }
+ continue;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+ if (!ret) ret = -EFAULT;
+ return ret;
+ }
+ spin_lock_irqsave(&s->lock, flags);
+ DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n",
+ cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);
+
+ swptr = (swptr + cnt) % s->dma_dac.dmasize;
+
+ s->dma_dac.swptr = swptr;
+ s->dma_dac.count += cnt;
+ s->dma_dac.endcleared = 0;
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ start_dac(s);
+ }
+out:
+ spin_unlock_irqrestore(&s->lock, flags);
+ return ret;
+}
+
+static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct ess_state *s = (struct ess_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);
+ ess_update_ptr(s);
+
+ if (file->f_mode & FMODE_READ) {
+ if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+ 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 + (signed)s->dma_dac.fragsize)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ }
+
+ spin_unlock_irqrestore(&s->lock, flags);
+ return mask;
+}
+
+static int ess_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct ess_state *s = (struct ess_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(s, 1)) != 0)
+ return ret;
+ db = &s->dma_dac;
+ } else
+ if (vma->vm_flags & VM_READ) {
+ if ((ret = prog_dmabuf(s, 0)) != 0)
+ return ret;
+ db = &s->dma_adc;
+ } else
+ return -EINVAL;
+ if (SILLY_OFFSET(vma) != 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;
+}
+
+/*
+ * god, what an absolute mess..
+ * not all the paths through here are
+ * properly locked.
+ * *sob*
+ */
+static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct ess_state *s = (struct ess_state *)file->private_data;
+ unsigned long flags;
+ audio_buf_info abinfo;
+ count_info cinfo;
+ int val, mapped, ret;
+ unsigned char fmtm, fmtd;
+
+ VALIDATE_STATE(s);
+
+ mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+ ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+
+ DPRINTK(DPSYS,"ess_ioctl: cmd %d\n", cmd);
+
+ 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, file->f_flags & O_NONBLOCK);
+ return 0;
+
+ case SNDCTL_DSP_SETDUPLEX:
+ /* XXX fix */
+ 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:
+ spin_lock_irqsave(&s->lock, flags);
+ 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;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ return 0;
+
+ case SNDCTL_DSP_SPEED:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ spin_lock_irqsave(&s->lock, flags);
+ if (val >= 0) {
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ set_adc_rate(s, val);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ set_dac_rate(s, val);
+ }
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+
+ case SNDCTL_DSP_STEREO:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ spin_lock_irqsave(&s->lock, flags);
+ fmtd = 0;
+ fmtm = ~0;
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ if (val)
+ fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+ else
+ fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val)
+ fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+ else
+ fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+ }
+ set_fmt(s, fmtm, fmtd);
+ spin_unlock_irqrestore(&s->lock, flags);
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ spin_lock_irqsave(&s->lock, flags);
+ if (val != 0) {
+ fmtd = 0;
+ fmtm = ~0;
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ if (val >= 2)
+ fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+ else
+ fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val >= 2)
+ fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+ else
+ fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+ }
+ set_fmt(s, fmtm, fmtd);
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
+ : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+ get_user_ret(val, (int *)arg, -EFAULT);
+ spin_lock_irqsave(&s->lock, flags);
+ if (val != AFMT_QUERY) {
+ fmtd = 0;
+ fmtm = ~0;
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ if (val == AFMT_S16_LE)
+ fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+ else
+ fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val == AFMT_S16_LE)
+ fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+ else
+ fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
+ }
+ set_fmt(s, fmtm, fmtd);
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
+ (ESS_FMT_16BIT << ESS_ADC_SHIFT)
+ : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ?
+ AFMT_S16_LE :
+ AFMT_U8,
+ (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ return 0;
+
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
+ val |= PCM_ENABLE_INPUT;
+ if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING))
+ 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(s, 1)))
+ return ret;
+ start_adc(s);
+ } else
+ stop_adc(s);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ 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->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0)
+ return val;
+ spin_lock_irqsave(&s->lock, flags);
+ ess_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->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0)
+ return val;
+ spin_lock_irqsave(&s->lock, flags);
+ ess_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);
+ ess_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);
+ ess_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);
+ ess_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(s, 0)))
+ return val;
+ return put_user(s->dma_dac.fragsize, (int *)arg);
+ }
+ if ((val = prog_dmabuf(s, 1)))
+ return val;
+ return put_user(s->dma_adc.fragsize, (int *)arg);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ spin_lock_irqsave(&s->lock, flags);
+ 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;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ 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((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
+ : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+
+ case SOUND_PCM_READ_BITS:
+ return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT)
+ : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, (int *)arg);
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+static int
+allocate_dmabuf(struct dmabuf *db)
+{
+ int order;
+ unsigned long mapend,map;
+ void *rawbuf = NULL;
+
+ DPRINTK(DPSTR,"allocating for dmabuf %p\n", db);
+
+ /*
+ * alloc as big a chunk as we can, start with
+ * 64k 'cause we're insane.
+ */
+ for (order = 16-PAGE_SHIFT; order >= 1; order--)
+ /* XXX might be able to get rid of gfp_dma */
+ if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+ break;
+
+ if (!rawbuf)
+ return 1;
+
+ /*
+ * can't cross a 64k boundry..
+ */
+ if( ((virt_to_bus(rawbuf) & 0xffff) + ((PAGE_SIZE << order) - 1)) > ~0xffff) {
+ printk(KERN_ERR PFX "DMA buffer crosses 64k: busaddr 0x%lx size %ld\n",
+ virt_to_bus(rawbuf), PAGE_SIZE << order);
+ kfree(rawbuf);
+ free_pages((unsigned long)db->rawbuf,db->buforder);
+ return 1;
+ }
+
+ DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n",
+ PAGE_SIZE<<order, order, rawbuf);
+
+ /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+ mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
+ for (map = MAP_NR(rawbuf); map <= mapend; map++) {
+ set_bit(PG_reserved, &mem_map[map].flags);
+ }
+
+ db->rawbuf = rawbuf;
+ db->buforder = order;
+ db->ready = 0;
+ db->mapped = 0;
+
+ return 0;
+}
+
+static void
+nuke_lists(struct ess_card *card, struct dmabuf *db)
+{
+ m3_remove_list(card, &(card->dma_list), db->dma_index);
+ m3_remove_list(card, &(card->msrc_list), db->msrc_index);
+ db->in_lists = 0;
+}
+
+static void
+free_dmabuf(struct dmabuf *db)
+{
+ unsigned long map, mapend;
+
+ DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db);
+
+ 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->buforder = 0;
+ db->mapped = 0;
+ db->ready = 0;
+}
+
+static int
+ess_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct ess_card *c;
+ struct ess_state *s = NULL;
+ int i;
+ int ret = 0;
+ unsigned char fmtm = ~0, fmts = 0;
+ unsigned long flags;
+
+ /*
+ * Scan the cards and find the channel. We only
+ * do this at open time so it is ok
+ */
+ for(c = devs ; c != NULL ; c = c->next) {
+
+ for(i=0;i<NR_DSPS;i++) {
+
+ if(c->channels[i].dev_audio < 0)
+ continue;
+ if((c->channels[i].dev_audio ^ minor) & ~0xf)
+ continue;
+
+ s = &c->channels[i];
+ break;
+ }
+ }
+
+ 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) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem);
+ return -EWOULDBLOCK;
+ }
+ 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 (file->f_mode & FMODE_READ) {
+ if(allocate_dmabuf(&(s->dma_adc))) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
+ if ((minor & 0xf) == SND_DEV_DSP16)
+ fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+
+ s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+ set_adc_rate(s, 8000);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if(allocate_dmabuf(&(s->dma_dac))) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
+ if ((minor & 0xf) == SND_DEV_DSP16)
+ fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+
+ s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+ set_dac_rate(s, 8000);
+ }
+ set_fmt(s, fmtm, fmts);
+ s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+
+ MOD_INC_USE_COUNT;
+out:
+ spin_unlock_irqrestore(&s->lock, flags);
+ up(&s->open_sem);
+ return ret;
+}
+
+static int
+ess_release(struct inode *inode, struct file *file)
+{
+ struct ess_state *s = (struct ess_state *)file->private_data;
+ unsigned long flags;
+
+ VALIDATE_STATE(s);
+ if (file->f_mode & FMODE_WRITE)
+ drain_dac(s, file->f_flags & O_NONBLOCK);
+
+ down(&s->open_sem);
+ spin_lock_irqsave(&s->lock, flags);
+
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ if(s->dma_dac.in_lists) {
+ m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index);
+ nuke_lists(s->card, &(s->dma_dac));
+ }
+ free_dmabuf(&(s->dma_dac));
+ }
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ if(s->dma_adc.in_lists) {
+ m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index);
+ nuke_lists(s->card, &(s->dma_adc));
+ }
+ free_dmabuf(&(s->dma_adc));
+ }
+
+ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+
+ spin_unlock_irqrestore(&s->lock, flags);
+ up(&s->open_sem);
+ wake_up(&s->open_wait);
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * Wait for the ac97 serial bus to be free.
+ * return nonzero if the bus is still busy.
+ */
+static int m3_ac97_wait(struct ess_card *card)
+{
+ int i = 10000;
+
+ while( (m3_inb(card, 0x30) & 1) && i--) ;
+
+ return i == 0;
+}
+
+u16 m3_ac97_read(struct ac97_codec *codec, u8 reg)
+{
+ u16 ret = 0;
+ struct ess_card *card = codec->private_data;
+
+ spin_lock(&card->ac97_lock);
+
+ if(m3_ac97_wait(card)) {
+ printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg);
+ goto out;
+ }
+
+ m3_outb(card, 0x80 | (reg & 0x7f), 0x30);
+
+ if(m3_ac97_wait(card)) {
+ printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg);
+ goto out;
+ }
+
+ ret = m3_inw(card, 0x32);
+ DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg);
+
+out:
+ spin_unlock(&card->ac97_lock);
+ return ret;
+}
+
+void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
+{
+ struct ess_card *card = codec->private_data;
+
+ spin_lock(&card->ac97_lock);
+
+ if(m3_ac97_wait(card)) {
+ printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg);
+ goto out;
+ }
+ DPRINTK(DPCRAP,"writing 0x%04x to 0x%02x\n", val, reg);
+
+ m3_outw(card, val, 0x32);
+ m3_outb(card, reg & 0x7f, 0x30);
+out:
+ spin_unlock(&card->ac97_lock);
+}
+/* OSS /dev/mixer file operation methods */
+static int m3_open_mixdev(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct ess_card *card = devs;
+
+ MOD_INC_USE_COUNT;
+ for (card = devs; card != NULL; card = card->next) {
+ if((card->ac97 != NULL) && (card->ac97->dev_mixer == minor))
+ break;
+ }
+
+ if (!card) {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+
+ file->private_data = card->ac97;
+
+ return 0;
+}
+
+static int m3_release_mixdev(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int m3_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static /*const*/ struct file_operations m3_mixer_fops = {
+llseek: m3_llseek,
+ioctl: m3_ioctl_mixdev,
+open: m3_open_mixdev,
+release: m3_release_mixdev,
+};
+
+void remote_codec_config(int io, int isremote)
+{
+ isremote = isremote ? 1 : 0;
+
+ outw( (inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote,
+ io + RING_BUS_CTRL_B);
+ outw( (inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,
+ io + SDO_OUT_DEST_CTRL);
+ outw( (inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,
+ io + SDO_IN_DEST_CTRL);
+}
+
+/*
+ * hack, returns non zero on err
+ */
+static int try_read_vendor(struct ess_card *card)
+{
+ u16 ret;
+
+ if(m3_ac97_wait(card))
+ return 1;
+
+ m3_outb(card, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30);
+
+ if(m3_ac97_wait(card))
+ return 1;
+
+ ret = m3_inw(card, 0x32);
+
+ return (ret == 0) || (ret == 0xffff);
+}
+
+static void m3_codec_reset(struct ess_card *card, int busywait)
+{
+ u16 dir;
+ int delay1 = 0, delay2 = 0, i;
+ int io = card->iobase;
+
+ switch (card->card_type) {
+ /*
+ * the onboard codec on the allegro seems
+ * to want to wait a very long time before
+ * coming back to life
+ */
+ case ESS_ALLEGRO:
+ delay1 = 50;
+ delay2 = 800;
+ break;
+ case ESS_MAESTRO3:
+ delay1 = 20;
+ delay2 = 500;
+ break;
+ }
+
+ for(i = 0; i < 5; i ++) {
+ dir = inw(io + GPIO_DIRECTION);
+ dir |= 0x10; /* assuming pci bus master? */
+
+ remote_codec_config(io, 0);
+
+ outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);
+ udelay(20);
+
+ outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION);
+ outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK);
+ outw(0, io + GPIO_DATA);
+ outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
+
+ if(busywait) {
+ mdelay(delay1);
+ } else {
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout((delay1 * HZ) / 1000);
+ }
+
+ outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
+ udelay(5);
+ /* ok, bring back the ac-link */
+ outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
+ outw(~0, io + GPIO_MASK);
+
+ if(busywait) {
+ mdelay(delay2);
+ } else {
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout((delay2 * HZ) / 1000);
+ }
+ if(! try_read_vendor(card))
+ break;
+
+ delay1 += 10;
+ delay2 += 100;
+
+ DPRINTK(DPMOD, "retrying codec reset with delays of %d and %d ms\n",
+ delay1, delay2);
+ }
+
+#if 0
+ /* more gung-ho reset that doesn't
+ * seem to work anywhere :)
+ */
+ tmp = inw(io + RING_BUS_CTRL_A);
+ outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
+ mdelay(20);
+ outw(tmp, io + RING_BUS_CTRL_A);
+ mdelay(50);
+#endif
+}
+
+static int __init m3_codec_install(struct ess_card *card)
+{
+ struct ac97_codec *codec;
+
+ if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(codec, 0, sizeof(struct ac97_codec));
+
+ codec->private_data = card;
+ codec->codec_read = m3_ac97_read;
+ codec->codec_write = m3_ac97_write;
+
+ if (ac97_probe_codec(codec) == 0) {
+ printk(KERN_ERR PFX "codec probe failed\n");
+ kfree(codec);
+ return -1;
+ }
+
+ if ((codec->dev_mixer = register_sound_mixer(&m3_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR PFX "couldn't register mixer!\n");
+ kfree(codec);
+ return -1;
+ }
+
+ card->ac97 = codec;
+
+ return 0;
+}
+
+
+#define MINISRC_LPF_LEN 10
+static u16 minisrc_lpf[MINISRC_LPF_LEN] = {
+ 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
+ 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
+};
+static void m3_assp_init(struct ess_card *card)
+{
+ int i;
+
+ /* zero kernel data */
+ for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_BASE_ADDR + i, 0);
+
+ /* zero mixer data? */
+ for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_BASE_ADDR2 + i, 0);
+
+ /* init dma pointer */
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_CURRENT_DMA,
+ KDATA_DMA_XFER0);
+
+ /* write kernel into code memory.. */
+ for(i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) {
+ m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+ REV_B_CODE_MEMORY_BEGIN + i,
+ assp_kernel_image[i]);
+ }
+
+ /*
+ * We only have this one client and we know that 0x400
+ * is free in our kernel's mem map, so lets just
+ * drop it there. It seems that the minisrc doesn't
+ * need vectors, so we won't bother with them..
+ */
+ for(i = 0 ; i < sizeof(assp_minisrc_image) / 2; i++) {
+ m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+ 0x400 + i,
+ assp_minisrc_image[i]);
+ }
+
+ /*
+ * write the coefficients for the low pass filter?
+ */
+ for(i = 0; i < MINISRC_LPF_LEN ; i++) {
+ m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+ 0x400 + MINISRC_COEF_LOC + i,
+ minisrc_lpf[i]);
+ }
+
+ m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+ 0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN,
+ 0x8000);
+
+ /*
+ * the minisrc is the only thing on
+ * our task list..
+ */
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_TASK0,
+ 0x400);
+
+ /*
+ * init the mixer number..
+ */
+
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_MIXER_TASK_NUMBER,0);
+
+ /*
+ * EXTREME KERNEL MASTER VOLUME
+ */
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_DAC_LEFT_VOLUME, ARB_VOLUME);
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME);
+
+ card->mixer_list.mem_addr = KDATA_MIXER_XFER0;
+ card->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS;
+ card->adc1_list.mem_addr = KDATA_ADC1_XFER0;
+ card->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS;
+ card->dma_list.mem_addr = KDATA_DMA_XFER0;
+ card->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS;
+ card->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC;
+ card->msrc_list.max = MAX_INSTANCE_MINISRC;
+}
+
+static int setup_msrc(struct ess_card *card,
+ struct assp_instance *inst, int index)
+{
+ int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 +
+ MINISRC_IN_BUFFER_SIZE / 2 +
+ 1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 );
+ int address, i;
+
+ /*
+ * the revb memory map has 0x1100 through 0x1c00
+ * free.
+ */
+
+ /*
+ * align instance mem so that the shifted list
+ * addresses are aligned.
+ */
+ data_bytes = (data_bytes + 255) & ~255;
+ address = 0x1100 + ((data_bytes/2) * index);
+
+ if((address + (data_bytes/2)) >= 0x1c00) {
+ printk(KERN_ERR PFX "no memory for %d bytes at ind %d (addr 0x%x)\n",
+ data_bytes, index, address);
+ return -1;
+ }
+
+ for(i = 0; i < data_bytes/2 ; i++)
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ address + i, 0);
+
+ inst->code = 0x400;
+ inst->data = address;
+
+ return 0;
+}
+
+static int m3_assp_client_init(struct ess_state *s)
+{
+ setup_msrc(s->card, &(s->dac_inst), s->index * 2);
+ setup_msrc(s->card, &(s->adc_inst), (s->index * 2) + 1);
+
+ return 0;
+}
+
+static void
+m3_amp_enable(struct ess_card *card, int enable)
+{
+ /*
+ * this works for the reference board, have to find
+ * out about others
+ *
+ * this needs more magic for 4 speaker, but..
+ */
+ int io = card->iobase;
+ u16 gpo, polarity_port, polarity;
+
+ if(!external_amp)
+ return;
+
+ switch (card->card_type) {
+ case ESS_ALLEGRO:
+ polarity_port = 0x1800;
+ break;
+ default:
+ /* presumably this is for all 'maestro3's.. */
+ polarity_port = 0x1100;
+ break;
+ }
+
+ gpo = (polarity_port >> 8) & 0x0F;
+ polarity = polarity_port >> 12;
+ if ( enable )
+ polarity = !polarity;
+ polarity = polarity << gpo;
+ gpo = 1 << gpo;
+
+ outw(~gpo , io + GPIO_MASK);
+
+ outw( inw(io + GPIO_DIRECTION) | gpo ,
+ io + GPIO_DIRECTION);
+
+ outw( (GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity) ,
+ io + GPIO_DATA);
+
+ outw(0xffff , io + GPIO_MASK);
+}
+
+static int
+maestro_config(struct ess_card *card)
+{
+ struct pci_dev *pcidev = card->pcidev;
+ u32 n;
+ u8 t; /* makes as much sense as 'n', no? */
+
+ pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
+ n &= REDUCED_DEBOUNCE;
+ n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
+ pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
+
+ outb(RESET_ASSP, card->iobase + ASSP_CONTROL_B);
+ pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
+ n &= ~INT_CLK_SELECT;
+ if(card->card_type == ESS_MAESTRO3) {
+ n &= ~INT_CLK_MULT_ENABLE;
+ n |= INT_CLK_SRC_NOT_PCI;
+ }
+ n &= ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 );
+ pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
+
+ if(card->card_type <= ESS_ALLEGRO) {
+ pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n);
+ n |= IN_CLK_12MHZ_SELECT;
+ pci_write_config_dword(pcidev, PCI_USER_CONFIG, n);
+ }
+
+ t = inb(card->iobase + ASSP_CONTROL_A);
+ t &= ~( DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT);
+ switch(global_dsp_speed) {
+ case 33:
+ break;
+ case 36:
+ t |= DSP_CLK_36MHZ_SELECT;
+ break;
+ case 49:
+ t |= ASSP_CLK_49MHZ_SELECT;
+ break;
+ }
+ t |= ASSP_0_WS_ENABLE;
+ outb(t, card->iobase + ASSP_CONTROL_A);
+
+ outb(RUN_ASSP, card->iobase + ASSP_CONTROL_B);
+
+ return 0;
+}
+
+static void
+m3_enable_ints(struct ess_card *card)
+{
+ unsigned long io = card->iobase;
+
+ outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL);
+ outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
+ io + ASSP_CONTROL_C);
+}
+
+static struct file_operations ess_audio_fops = {
+ &m3_llseek,
+ &ess_read,
+ &ess_write,
+ NULL, /* readdir */
+ &ess_poll,
+ &ess_ioctl,
+ &ess_mmap,
+ &ess_open,
+ NULL, /* flush */
+ &ess_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL, /* lock */
+};
+
+#ifdef CONFIG_APM
+int alloc_dsp_savemem(struct ess_card *card)
+{
+ int len = sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
+
+ if( (card->suspend_dsp_mem = vmalloc(len)) == NULL)
+ return 1;
+
+ return 0;
+}
+void free_dsp_savemem(struct ess_card *card)
+{
+ if(card->suspend_dsp_mem)
+ vfree(card->suspend_dsp_mem);
+}
+
+#else
+#define alloc_dsp_savemem(args...) 0
+#define free_dsp_savemem(args...)
+#endif
+
+/*
+ * great day! this function is ugly as hell.
+ */
+static int
+maestro_install(struct pci_dev *pcidev, struct card_type *ct)
+{
+ u32 n;
+ int i;
+ int iobase;
+ struct ess_card *card = NULL;
+ int num = 0;
+
+ /* don't pick up modems */
+ if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
+ return 1;
+
+ DPRINTK(DPMOD, "in maestro_install\n");
+
+ iobase = SILLY_PCI_BASE_ADDRESS(pcidev);
+
+ if(check_region(iobase, 256))
+ {
+ printk(KERN_WARNING PFX "can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
+ return 1;
+ }
+ /* stake our claim on the iospace */
+ request_region(iobase, 256, ct->name);
+
+ /* this was tripping up some machines */
+ if(pcidev->irq == 0)
+ printk(KERN_WARNING PFX "pci subsystem reports irq 0, this might not be correct.\n");
+
+ /* just to be sure */
+ pci_set_master(pcidev);
+
+ card = kmalloc(sizeof(struct ess_card), GFP_KERNEL);
+ if(card == NULL)
+ {
+ printk(KERN_WARNING PFX "out of memory\n");
+ release_region(card->iobase, 256);
+ return 1;
+ }
+
+ memset(card, 0, sizeof(*card));
+ card->pcidev = pcidev;
+
+ if(alloc_dsp_savemem(card)) {
+ printk(KERN_WARNING PFX "couldn't alloc %d bytes for saving dsp state on suspend\n",
+ REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
+ release_region(card->iobase, 256);
+ free_dsp_savemem(card);
+ kfree(card);
+ return 1;
+ }
+
+ if (register_reboot_notifier(&maestro_nb)) {
+ printk(KERN_WARNING PFX "reboot notifier registration failed\n");
+ release_region(card->iobase, 256);
+ free_dsp_savemem(card);
+ kfree(card);
+ return 1;
+ }
+
+ card->iobase = iobase;
+ card->card_type = ct->type;
+ card->irq = pcidev->irq;
+ card->next = devs;
+ card->magic = M3_CARD_MAGIC;
+ spin_lock_init(&card->lock);
+ spin_lock_init(&card->ac97_lock);
+ devs = card;
+
+ printk(KERN_INFO PFX "Configuring %s found at IO 0x%04X IRQ %d\n",
+ ct->name,iobase,card->irq);
+ pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
+ printk(KERN_INFO PFX " subvendor id: 0x%08x\n",n);
+
+ maestro_config(card);
+ m3_assp_halt(card);
+
+ m3_codec_reset(card, 0);
+
+ if(m3_codec_install(card)) {
+ unregister_reboot_notifier(&maestro_nb);
+ release_region(card->iobase, 256);
+ free_dsp_savemem(card);
+ kfree(card);
+ return 1;
+ }
+
+ m3_assp_init(card);
+ m3_amp_enable(card, 1);
+
+ for(i=0;i<NR_DSPS;i++)
+ {
+ struct ess_state *s=&card->channels[i];
+
+ s->index = i;
+
+ s->card = card;
+ init_waitqueue_head(&s->dma_adc.wait);
+ init_waitqueue_head(&s->dma_dac.wait);
+ init_waitqueue_head(&s->open_wait);
+ spin_lock_init(&s->lock);
+ SILLY_INIT_SEM(s->open_sem);
+ s->magic = M3_STATE_MAGIC;
+
+ m3_assp_client_init(s);
+
+ if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
+ printk("maestro: BOTCH!\n");
+ /* register devices */
+ if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0)
+ break;
+ }
+
+ num = i;
+
+ /* clear the rest if we ran out of slots to register */
+ for(;i<NR_DSPS;i++)
+ {
+ struct ess_state *s=&card->channels[i];
+ s->dev_audio = -1;
+ }
+
+
+ if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, ct->name, card))
+ {
+ printk(KERN_ERR PFX "unable to allocate irq %d,\n", card->irq);
+ for(i=0;i<NR_DSPS;i++)
+ {
+ struct ess_state *s = &card->channels[i];
+ if(s->dev_audio != -1)
+ unregister_sound_dsp(s->dev_audio);
+ }
+ unregister_reboot_notifier(&maestro_nb);
+ unregister_sound_mixer(card->ac97->dev_mixer);
+ kfree(card->ac97);
+ release_region(card->iobase, 256);
+ free_dsp_savemem(card);
+ kfree(card);
+ return 1;
+ }
+
+#ifdef CONFIG_APM
+ if (apm_register_callback(m3_apm_callback)) {
+ printk(KERN_WARNING PFX "couldn't register apm callback, suspend/resume might not work.\n");
+ }
+#endif
+
+ m3_enable_ints(card);
+ m3_assp_continue(card);
+
+ printk(KERN_INFO PFX "%d channels configured.\n", num);
+
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+SILLY_MAKE_INIT(int init_maestro3(void))
+#endif
+{
+ struct pci_dev *pcidev = NULL;
+ int found = 0;
+ int i;
+
+ if (!pci_present()) /* No PCI bus in this machine! */
+ return -ENODEV;
+
+ printk(KERN_INFO PFX "version " DRIVER_VERSION " built at " __TIME__ " " __DATE__ "\n");
+
+ switch(global_dsp_speed) {
+ case 33: case 36: case 49:
+ break;
+ default:
+ printk(KERN_INFO PFX "invalid global_dsp_speed: %d, must be 33, 36, or 49.\n",
+ global_dsp_speed);
+ return -EINVAL;
+ break;
+ }
+
+#ifdef CONFIG_APM
+ init_waitqueue_head(&suspend_queue);
+#endif
+
+ for(i = 0; i < NUM_CARD_TYPES; i++) {
+ struct card_type *ct = &m3_card_types[i];
+
+ pcidev = NULL;
+ while( (pcidev = pci_find_device(PCI_VENDOR_ESS, ct->pci_id, pcidev)) != NULL ) {
+ if (! maestro_install(pcidev, ct))
+ found++;
+ }
+ }
+
+ printk(KERN_INFO PFX "%d maestros installed.\n",found);
+
+ if(found == 0 )
+ return -ENODEV;
+
+ return 0;
+}
+
+void nuke_maestros(void)
+{
+ struct ess_card *card;
+
+ unregister_reboot_notifier(&maestro_nb);
+#ifdef CONFIG_APM
+ apm_unregister_callback(m3_apm_callback);
+#endif
+
+ while ((card = devs)) {
+ int i;
+ devs = devs->next;
+
+ free_irq(card->irq, card);
+ unregister_sound_mixer(card->ac97->dev_mixer);
+ kfree(card->ac97);
+
+ for(i=0;i<NR_DSPS;i++)
+ {
+ struct ess_state *ess = &card->channels[i];
+ if(ess->dev_audio != -1)
+ unregister_sound_dsp(ess->dev_audio);
+ }
+
+ release_region(card->iobase, 256);
+ free_dsp_savemem(card);
+ kfree(card);
+ }
+ devs = NULL;
+}
+
+static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
+{
+ /* this notifier is called when the kernel is really shut down. */
+ DPRINTK(DPMOD,"shutting down\n");
+ nuke_maestros();
+ return NOTIFY_OK;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+MODULE_AUTHOR("Zach Brown <zab@zabbo.net>");
+MODULE_DESCRIPTION("ESS Maestro3/Allegro Driver");
+#ifdef M_DEBUG
+MODULE_PARM(debug,"i");
+MODULE_PARM(global_dsp_speed,"i");
+#endif
+MODULE_PARM(external_amp,"i");
+
+void cleanup_module(void) {
+ DPRINTK(DPMOD,"unloading\n");
+ nuke_maestros();
+}
+
+#endif /* MODULE */
+
+#ifdef CONFIG_APM
+void
+check_suspend(void)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ if(!in_suspend)
+ return;
+
+ in_suspend++;
+ add_wait_queue(&suspend_queue, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule();
+ remove_wait_queue(&suspend_queue, &wait);
+ current->state = TASK_RUNNING;
+}
+
+static int
+m3_suspend(void)
+{
+ struct ess_card *card;
+ unsigned long flags;
+ int index;
+
+ save_flags(flags);
+ cli();
+
+ for (card = devs; card ; card = card->next) {
+ int i;
+
+ DPRINTK(DPMOD, "apm in dev %p\n",card);
+
+ for(i=0;i<NR_DSPS;i++) {
+ struct ess_state *s = &card->channels[i];
+
+ if(s->dev_audio == -1)
+ continue;
+
+ DPRINTK(DPMOD, "stop_adc/dac() device %d\n",i);
+ stop_dac(s);
+ stop_adc(s);
+ }
+
+ mdelay(10); /* give the assp a chance to idle.. */
+
+ m3_assp_halt(card);
+
+ index = 0;
+ DPRINTK(DPMOD, "saving code\n");
+ for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
+ card->suspend_dsp_mem[index++] =
+ m3_assp_read(card, MEMTYPE_INTERNAL_CODE, i);
+ DPRINTK(DPMOD, "saving data\n");
+ for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
+ card->suspend_dsp_mem[index++] =
+ m3_assp_read(card, MEMTYPE_INTERNAL_DATA, i);
+
+ DPRINTK(DPMOD, "powering down apci regs\n");
+ m3_outw(card, 0xffff, 0x54);
+ m3_outw(card, 0xffff, 0x56);
+ }
+ in_suspend=1;
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+static int
+m3_resume(void)
+{
+ struct ess_card *card;
+ unsigned long flags;
+ int index;
+
+ save_flags(flags); /* paranoia */
+ cli();
+ in_suspend=0;
+
+ DPRINTK(DPMOD, "resuming\n");
+
+ /* first lets just bring everything back. .*/
+ for (card = devs; card ; card = card->next) {
+ int i;
+
+ DPRINTK(DPMOD, "bringing power back on card 0x%p\n",card);
+ m3_outw(card, 0, 0x54);
+ m3_outw(card, 0, 0x56);
+
+ DPRINTK(DPMOD, "restoring pci configs and reseting codec\n");
+ maestro_config(card);
+ m3_assp_halt(card);
+ m3_codec_reset(card, 1);
+
+ DPRINTK(DPMOD, "restoring dsp code\n");
+ index = 0;
+ for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
+ m3_assp_write(card, MEMTYPE_INTERNAL_CODE, i,
+ card->suspend_dsp_mem[index++]);
+ for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA, i,
+ card->suspend_dsp_mem[index++]);
+
+ /* tell the dma engine to restart itself */
+ m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+ KDATA_DMA_ACTIVE, 0);
+
+ DPRINTK(DPMOD, "resuming dsp\n");
+ m3_assp_continue(card);
+
+ DPRINTK(DPMOD, "enabling ints\n");
+ m3_enable_ints(card);
+
+ /* bring back the old school flavor */
+ for(i = 0; i < SOUND_MIXER_NRDEVICES ; i++) {
+ int state = card->ac97->mixer_state[i];
+ if (!supported_mixer(card->ac97, i))
+ continue;
+
+ card->ac97->write_mixer(card->ac97, i,
+ state & 0xff, (state >> 8) & 0xff);
+ }
+
+ m3_amp_enable(card, 1);
+ }
+
+ /*
+ * now we flip on the music
+ */
+ for (card = devs; card ; card = card->next) {
+ int i;
+
+
+ for(i=0;i<NR_DSPS;i++) {
+ struct ess_state *s = &card->channels[i];
+ if(s->dev_audio == -1)
+ continue;
+ /*
+ * db->ready makes it so these guys can be
+ * called unconditionally..
+ */
+ DPRINTK(DPMOD, "turning on dacs ind %d\n",i);
+ start_dac(s);
+ start_adc(s);
+ }
+ }
+
+ restore_flags(flags);
+
+ /*
+ * all right, we think things are ready,
+ * wake up people who were using the device
+ * when we suspended
+ */
+ wake_up(&suspend_queue);
+
+ return 0;
+}
+
+int
+m3_apm_callback(apm_event_t ae) {
+
+ DPRINTK(DPMOD, "APM event received: 0x%x\n",ae);
+
+ switch(ae) {
+ case APM_SYS_SUSPEND:
+ case APM_CRITICAL_SUSPEND:
+ case APM_USER_SUSPEND:
+
+ m3_suspend();
+ break;
+
+ case APM_NORMAL_RESUME:
+ case APM_CRITICAL_RESUME:
+ case APM_STANDBY_RESUME:
+
+ m3_resume();
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ * ESS Technology allegro audio driver.
+ *
+ * Copyright (C) 1992-2000 Don Kim (don.kim@esstech.com)
+ *
+ * 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.
+ *
+ * Hacked for the maestro3 driver by zab
+ */
+
+// Allegro PCI configuration registers
+#define PCI_LEGACY_AUDIO_CTRL 0x40
+#define SOUND_BLASTER_ENABLE 0x00000001
+#define FM_SYNTHESIS_ENABLE 0x00000002
+#define GAME_PORT_ENABLE 0x00000004
+#define MPU401_IO_ENABLE 0x00000008
+#define MPU401_IRQ_ENABLE 0x00000010
+#define ALIAS_10BIT_IO 0x00000020
+#define SB_DMA_MASK 0x000000C0
+#define SB_DMA_0 0x00000040
+#define SB_DMA_1 0x00000040
+#define SB_DMA_R 0x00000080
+#define SB_DMA_3 0x000000C0
+#define SB_IRQ_MASK 0x00000700
+#define SB_IRQ_5 0x00000000
+#define SB_IRQ_7 0x00000100
+#define SB_IRQ_9 0x00000200
+#define SB_IRQ_10 0x00000300
+#define MIDI_IRQ_MASK 0x00003800
+#define SERIAL_IRQ_ENABLE 0x00004000
+#define DISABLE_LEGACY 0x00008000
+
+#define PCI_ALLEGRO_CONFIG 0x50
+#define SB_ADDR_240 0x00000004
+#define MPU_ADDR_MASK 0x00000018
+#define MPU_ADDR_330 0x00000000
+#define MPU_ADDR_300 0x00000008
+#define MPU_ADDR_320 0x00000010
+#define MPU_ADDR_340 0x00000018
+#define USE_PCI_TIMING 0x00000040
+#define POSTED_WRITE_ENABLE 0x00000080
+#define DMA_POLICY_MASK 0x00000700
+#define DMA_DDMA 0x00000000
+#define DMA_TDMA 0x00000100
+#define DMA_PCPCI 0x00000200
+#define DMA_WBDMA16 0x00000400
+#define DMA_WBDMA4 0x00000500
+#define DMA_WBDMA2 0x00000600
+#define DMA_WBDMA1 0x00000700
+#define DMA_SAFE_GUARD 0x00000800
+#define HI_PERF_GP_ENABLE 0x00001000
+#define PIC_SNOOP_MODE_0 0x00002000
+#define PIC_SNOOP_MODE_1 0x00004000
+#define SOUNDBLASTER_IRQ_MASK 0x00008000
+#define RING_IN_ENABLE 0x00010000
+#define SPDIF_TEST_MODE 0x00020000
+#define CLK_MULT_MODE_SELECT_2 0x00040000
+#define EEPROM_WRITE_ENABLE 0x00080000
+#define CODEC_DIR_IN 0x00100000
+#define HV_BUTTON_FROM_GD 0x00200000
+#define REDUCED_DEBOUNCE 0x00400000
+#define HV_CTRL_ENABLE 0x00800000
+#define SPDIF_ENABLE 0x01000000
+#define CLK_DIV_SELECT 0x06000000
+#define CLK_DIV_BY_48 0x00000000
+#define CLK_DIV_BY_49 0x02000000
+#define CLK_DIV_BY_50 0x04000000
+#define CLK_DIV_RESERVED 0x06000000
+#define PM_CTRL_ENABLE 0x08000000
+#define CLK_MULT_MODE_SELECT 0x30000000
+#define CLK_MULT_MODE_SHIFT 28
+#define CLK_MULT_MODE_0 0x00000000
+#define CLK_MULT_MODE_1 0x10000000
+#define CLK_MULT_MODE_2 0x20000000
+#define CLK_MULT_MODE_3 0x30000000
+#define INT_CLK_SELECT 0x40000000
+#define INT_CLK_MULT_RESET 0x80000000
+
+// M3
+#define INT_CLK_SRC_NOT_PCI 0x00100000
+#define INT_CLK_MULT_ENABLE 0x80000000
+
+#define PCI_ACPI_CONTROL 0x54
+#define PCI_ACPI_D0 0x00000000
+#define PCI_ACPI_D1 0xB4F70000
+#define PCI_ACPI_D2 0xB4F7B4F7
+
+#define PCI_USER_CONFIG 0x58
+#define EXT_PCI_MASTER_ENABLE 0x00000001
+#define SPDIF_OUT_SELECT 0x00000002
+#define TEST_PIN_DIR_CTRL 0x00000004
+#define AC97_CODEC_TEST 0x00000020
+#define TRI_STATE_BUFFER 0x00000080
+#define IN_CLK_12MHZ_SELECT 0x00000100
+#define MULTI_FUNC_DISABLE 0x00000200
+#define EXT_MASTER_PAIR_SEL 0x00000400
+#define PCI_MASTER_SUPPORT 0x00000800
+#define STOP_CLOCK_ENABLE 0x00001000
+#define EAPD_DRIVE_ENABLE 0x00002000
+#define REQ_TRI_STATE_ENABLE 0x00004000
+#define REQ_LOW_ENABLE 0x00008000
+#define MIDI_1_ENABLE 0x00010000
+#define MIDI_2_ENABLE 0x00020000
+#define SB_AUDIO_SYNC 0x00040000
+#define HV_CTRL_TEST 0x00100000
+#define SOUNDBLASTER_TEST 0x00400000
+
+#define PCI_USER_CONFIG_C 0x5C
+
+#define PCI_DDMA_CTRL 0x60
+#define DDMA_ENABLE 0x00000001
+
+
+// Allegro registers
+#define HOST_INT_CTRL 0x18
+#define SB_INT_ENABLE 0x0001
+#define MPU401_INT_ENABLE 0x0002
+#define ASSP_INT_ENABLE 0x0010
+#define RING_INT_ENABLE 0x0020
+#define HV_INT_ENABLE 0x0040
+#define CLKRUN_GEN_ENABLE 0x0100
+#define HV_CTRL_TO_PME 0x0400
+#define SOFTWARE_RESET_ENABLE 0x8000
+
+/*
+ * should be using the above defines, probably.
+ */
+#define REGB_ENABLE_RESET 0x01
+#define REGB_STOP_CLOCK 0x10
+
+#define HOST_INT_STATUS 0x1A
+#define SB_INT_PENDING 0x01
+#define MPU401_INT_PENDING 0x02
+#define ASSP_INT_PENDING 0x10
+#define RING_INT_PENDING 0x20
+#define HV_INT_PENDING 0x40
+
+#define HARDWARE_VOL_CTRL 0x1B
+#define SHADOW_MIX_REG_VOICE 0x1C
+#define HW_VOL_COUNTER_VOICE 0x1D
+#define SHADOW_MIX_REG_MASTER 0x1E
+#define HW_VOL_COUNTER_MASTER 0x1F
+
+#define CODEC_COMMAND 0x30
+#define CODEC_READ_B 0x80
+
+#define CODEC_STATUS 0x30
+#define CODEC_BUSY_B 0x01
+
+#define CODEC_DATA 0x32
+
+#define RING_BUS_CTRL_A 0x36
+#define RAC_PME_ENABLE 0x0100
+#define RAC_SDFS_ENABLE 0x0200
+#define LAC_PME_ENABLE 0x0400
+#define LAC_SDFS_ENABLE 0x0800
+#define SERIAL_AC_LINK_ENABLE 0x1000
+#define IO_SRAM_ENABLE 0x2000
+#define IIS_INPUT_ENABLE 0x8000
+
+#define RING_BUS_CTRL_B 0x38
+#define SECOND_CODEC_ID_MASK 0x0003
+#define SPDIF_FUNC_ENABLE 0x0010
+#define SECOND_AC_ENABLE 0x0020
+#define SB_MODULE_INTF_ENABLE 0x0040
+#define SSPE_ENABLE 0x0040
+#define M3I_DOCK_ENABLE 0x0080
+
+#define SDO_OUT_DEST_CTRL 0x3A
+#define COMMAND_ADDR_OUT 0x0003
+#define PCM_LR_OUT_LOCAL 0x0000
+#define PCM_LR_OUT_REMOTE 0x0004
+#define PCM_LR_OUT_MUTE 0x0008
+#define PCM_LR_OUT_BOTH 0x000C
+#define LINE1_DAC_OUT_LOCAL 0x0000
+#define LINE1_DAC_OUT_REMOTE 0x0010
+#define LINE1_DAC_OUT_MUTE 0x0020
+#define LINE1_DAC_OUT_BOTH 0x0030
+#define PCM_CLS_OUT_LOCAL 0x0000
+#define PCM_CLS_OUT_REMOTE 0x0040
+#define PCM_CLS_OUT_MUTE 0x0080
+#define PCM_CLS_OUT_BOTH 0x00C0
+#define PCM_RLF_OUT_LOCAL 0x0000
+#define PCM_RLF_OUT_REMOTE 0x0100
+#define PCM_RLF_OUT_MUTE 0x0200
+#define PCM_RLF_OUT_BOTH 0x0300
+#define LINE2_DAC_OUT_LOCAL 0x0000
+#define LINE2_DAC_OUT_REMOTE 0x0400
+#define LINE2_DAC_OUT_MUTE 0x0800
+#define LINE2_DAC_OUT_BOTH 0x0C00
+#define HANDSET_OUT_LOCAL 0x0000
+#define HANDSET_OUT_REMOTE 0x1000
+#define HANDSET_OUT_MUTE 0x2000
+#define HANDSET_OUT_BOTH 0x3000
+#define IO_CTRL_OUT_LOCAL 0x0000
+#define IO_CTRL_OUT_REMOTE 0x4000
+#define IO_CTRL_OUT_MUTE 0x8000
+#define IO_CTRL_OUT_BOTH 0xC000
+
+#define SDO_IN_DEST_CTRL 0x3C
+#define STATUS_ADDR_IN 0x0003
+#define PCM_LR_IN_LOCAL 0x0000
+#define PCM_LR_IN_REMOTE 0x0004
+#define PCM_LR_RESERVED 0x0008
+#define PCM_LR_IN_BOTH 0x000C
+#define LINE1_ADC_IN_LOCAL 0x0000
+#define LINE1_ADC_IN_REMOTE 0x0010
+#define LINE1_ADC_IN_MUTE 0x0020
+#define MIC_ADC_IN_LOCAL 0x0000
+#define MIC_ADC_IN_REMOTE 0x0040
+#define MIC_ADC_IN_MUTE 0x0080
+#define LINE2_DAC_IN_LOCAL 0x0000
+#define LINE2_DAC_IN_REMOTE 0x0400
+#define LINE2_DAC_IN_MUTE 0x0800
+#define HANDSET_IN_LOCAL 0x0000
+#define HANDSET_IN_REMOTE 0x1000
+#define HANDSET_IN_MUTE 0x2000
+#define IO_STATUS_IN_LOCAL 0x0000
+#define IO_STATUS_IN_REMOTE 0x4000
+
+#define SPDIF_IN_CTRL 0x3E
+#define SPDIF_IN_ENABLE 0x0001
+
+#define GPIO_DATA 0x60
+#define GPIO_DATA_MASK 0x0FFF
+#define GPIO_HV_STATUS 0x3000
+#define GPIO_PME_STATUS 0x4000
+
+#define GPIO_MASK 0x64
+#define GPIO_DIRECTION 0x68
+#define GPO_PRIMARY_AC97 0x0001
+#define GPI_LINEOUT_SENSE 0x0004
+#define GPO_SECONDARY_AC97 0x0008
+#define GPI_VOL_DOWN 0x0010
+#define GPI_VOL_UP 0x0020
+#define GPI_IIS_CLK 0x0040
+#define GPI_IIS_LRCLK 0x0080
+#define GPI_IIS_DATA 0x0100
+#define GPI_DOCKING_STATUS 0x0100
+#define GPI_HEADPHONE_SENSE 0x0200
+#define GPO_EXT_AMP_SHUTDOWN 0x1000
+
+// M3
+#define GPO_M3_EXT_AMP_SHUTDN 0x0002
+
+#define ASSP_INDEX_PORT 0x80
+#define ASSP_MEMORY_PORT 0x82
+#define ASSP_DATA_PORT 0x84
+
+#define MPU401_DATA_PORT 0x98
+#define MPU401_STATUS_PORT 0x99
+
+#define CLK_MULT_DATA_PORT 0x9C
+
+#define ASSP_CONTROL_A 0xA2
+#define ASSP_0_WS_ENABLE 0x01
+#define ASSP_CTRL_A_RESERVED1 0x02
+#define ASSP_CTRL_A_RESERVED2 0x04
+#define ASSP_CLK_49MHZ_SELECT 0x08
+#define FAST_PLU_ENABLE 0x10
+#define ASSP_CTRL_A_RESERVED3 0x20
+#define DSP_CLK_36MHZ_SELECT 0x40
+
+#define ASSP_CONTROL_B 0xA4
+#define RESET_ASSP 0x00
+#define RUN_ASSP 0x01
+#define ENABLE_ASSP_CLOCK 0x00
+#define STOP_ASSP_CLOCK 0x10
+#define RESET_TOGGLE 0x40
+
+#define ASSP_CONTROL_C 0xA6
+#define ASSP_HOST_INT_ENABLE 0x01
+#define FM_ADDR_REMAP_DISABLE 0x02
+#define HOST_WRITE_PORT_ENABLE 0x08
+
+#define ASSP_HOST_INT_STATUS 0xAC
+#define DSP2HOST_REQ_PIORECORD 0x01
+#define DSP2HOST_REQ_I2SRATE 0x02
+#define DSP2HOST_REQ_TIMER 0x04
+
+// AC97 registers
+// XXX fix this crap up
+/*#define AC97_RESET 0x00*/
+
+#define AC97_VOL_MUTE_B 0x8000
+#define AC97_VOL_M 0x1F
+#define AC97_LEFT_VOL_S 8
+
+#define AC97_MASTER_VOL 0x02
+#define AC97_LINE_LEVEL_VOL 0x04
+#define AC97_MASTER_MONO_VOL 0x06
+#define AC97_PC_BEEP_VOL 0x0A
+#define AC97_PC_BEEP_VOL_M 0x0F
+#define AC97_SROUND_MASTER_VOL 0x38
+#define AC97_PC_BEEP_VOL_S 1
+
+/*#define AC97_PHONE_VOL 0x0C
+#define AC97_MIC_VOL 0x0E*/
+#define AC97_MIC_20DB_ENABLE 0x40
+
+/*#define AC97_LINEIN_VOL 0x10
+#define AC97_CD_VOL 0x12
+#define AC97_VIDEO_VOL 0x14
+#define AC97_AUX_VOL 0x16*/
+#define AC97_PCM_OUT_VOL 0x18
+/*#define AC97_RECORD_SELECT 0x1A*/
+#define AC97_RECORD_MIC 0x00
+#define AC97_RECORD_CD 0x01
+#define AC97_RECORD_VIDEO 0x02
+#define AC97_RECORD_AUX 0x03
+#define AC97_RECORD_MONO_MUX 0x02
+#define AC97_RECORD_DIGITAL 0x03
+#define AC97_RECORD_LINE 0x04
+#define AC97_RECORD_STEREO 0x05
+#define AC97_RECORD_MONO 0x06
+#define AC97_RECORD_PHONE 0x07
+
+/*#define AC97_RECORD_GAIN 0x1C*/
+#define AC97_RECORD_VOL_M 0x0F
+
+/*#define AC97_GENERAL_PURPOSE 0x20*/
+#define AC97_POWER_DOWN_CTRL 0x26
+#define AC97_ADC_READY 0x0001
+#define AC97_DAC_READY 0x0002
+#define AC97_ANALOG_READY 0x0004
+#define AC97_VREF_ON 0x0008
+#define AC97_PR0 0x0100
+#define AC97_PR1 0x0200
+#define AC97_PR2 0x0400
+#define AC97_PR3 0x0800
+#define AC97_PR4 0x1000
+
+#define AC97_RESERVED1 0x28
+
+#define AC97_VENDOR_TEST 0x5A
+
+#define AC97_CLOCK_DELAY 0x5C
+#define AC97_LINEOUT_MUX_SEL 0x0001
+#define AC97_MONO_MUX_SEL 0x0002
+#define AC97_CLOCK_DELAY_SEL 0x1F
+#define AC97_DAC_CDS_SHIFT 6
+#define AC97_ADC_CDS_SHIFT 11
+
+#define AC97_MULTI_CHANNEL_SEL 0x74
+
+/*#define AC97_VENDOR_ID1 0x7C
+#define AC97_VENDOR_ID2 0x7E*/
+
+/*
+ * ASSP control regs
+ */
+#define DSP_PORT_TIMER_COUNT 0x06
+
+#define DSP_PORT_MEMORY_INDEX 0x80
+
+#define DSP_PORT_MEMORY_TYPE 0x82
+#define MEMTYPE_INTERNAL_CODE 0x0002
+#define MEMTYPE_INTERNAL_DATA 0x0003
+#define MEMTYPE_MASK 0x0003
+
+#define DSP_PORT_MEMORY_DATA 0x84
+
+#define DSP_PORT_CONTROL_REG_A 0xA2
+#define DSP_PORT_CONTROL_REG_B 0xA4
+#define DSP_PORT_CONTROL_REG_C 0xA6
+
+#define REV_A_CODE_MEMORY_BEGIN 0x0000
+#define REV_A_CODE_MEMORY_END 0x0FFF
+#define REV_A_CODE_MEMORY_UNIT_LENGTH 0x0040
+#define REV_A_CODE_MEMORY_LENGTH (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1)
+
+#define REV_B_CODE_MEMORY_BEGIN 0x0000
+#define REV_B_CODE_MEMORY_END 0x0BFF
+#define REV_B_CODE_MEMORY_UNIT_LENGTH 0x0040
+#define REV_B_CODE_MEMORY_LENGTH (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1)
+
+#define REV_A_DATA_MEMORY_BEGIN 0x1000
+#define REV_A_DATA_MEMORY_END 0x2FFF
+#define REV_A_DATA_MEMORY_UNIT_LENGTH 0x0080
+#define REV_A_DATA_MEMORY_LENGTH (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1)
+
+#define REV_B_DATA_MEMORY_BEGIN 0x1000
+#define REV_B_DATA_MEMORY_END 0x2BFF
+#define REV_B_DATA_MEMORY_UNIT_LENGTH 0x0080
+#define REV_B_DATA_MEMORY_LENGTH (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1)
+
+
+#define NUM_UNITS_KERNEL_CODE 16
+#define NUM_UNITS_KERNEL_DATA 2
+
+#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
+#define NUM_UNITS_KERNEL_DATA_WITH_HSP 5
+
+/*
+ * Kernel data layout
+ */
+
+#define DP_SHIFT_COUNT 7
+
+#define KDATA_BASE_ADDR 0x1000
+#define KDATA_BASE_ADDR2 0x1080
+
+#define KDATA_TASK0 (KDATA_BASE_ADDR + 0x0000)
+#define KDATA_TASK1 (KDATA_BASE_ADDR + 0x0001)
+#define KDATA_TASK2 (KDATA_BASE_ADDR + 0x0002)
+#define KDATA_TASK3 (KDATA_BASE_ADDR + 0x0003)
+#define KDATA_TASK4 (KDATA_BASE_ADDR + 0x0004)
+#define KDATA_TASK5 (KDATA_BASE_ADDR + 0x0005)
+#define KDATA_TASK6 (KDATA_BASE_ADDR + 0x0006)
+#define KDATA_TASK7 (KDATA_BASE_ADDR + 0x0007)
+#define KDATA_TASK_ENDMARK (KDATA_BASE_ADDR + 0x0008)
+
+#define KDATA_CURRENT_TASK (KDATA_BASE_ADDR + 0x0009)
+#define KDATA_TASK_SWITCH (KDATA_BASE_ADDR + 0x000A)
+
+#define KDATA_INSTANCE0_POS3D (KDATA_BASE_ADDR + 0x000B)
+#define KDATA_INSTANCE1_POS3D (KDATA_BASE_ADDR + 0x000C)
+#define KDATA_INSTANCE2_POS3D (KDATA_BASE_ADDR + 0x000D)
+#define KDATA_INSTANCE3_POS3D (KDATA_BASE_ADDR + 0x000E)
+#define KDATA_INSTANCE4_POS3D (KDATA_BASE_ADDR + 0x000F)
+#define KDATA_INSTANCE5_POS3D (KDATA_BASE_ADDR + 0x0010)
+#define KDATA_INSTANCE6_POS3D (KDATA_BASE_ADDR + 0x0011)
+#define KDATA_INSTANCE7_POS3D (KDATA_BASE_ADDR + 0x0012)
+#define KDATA_INSTANCE8_POS3D (KDATA_BASE_ADDR + 0x0013)
+#define KDATA_INSTANCE_POS3D_ENDMARK (KDATA_BASE_ADDR + 0x0014)
+
+#define KDATA_INSTANCE0_SPKVIRT (KDATA_BASE_ADDR + 0x0015)
+#define KDATA_INSTANCE_SPKVIRT_ENDMARK (KDATA_BASE_ADDR + 0x0016)
+
+#define KDATA_INSTANCE0_SPDIF (KDATA_BASE_ADDR + 0x0017)
+#define KDATA_INSTANCE_SPDIF_ENDMARK (KDATA_BASE_ADDR + 0x0018)
+
+#define KDATA_INSTANCE0_MODEM (KDATA_BASE_ADDR + 0x0019)
+#define KDATA_INSTANCE_MODEM_ENDMARK (KDATA_BASE_ADDR + 0x001A)
+
+#define KDATA_INSTANCE0_SRC (KDATA_BASE_ADDR + 0x001B)
+#define KDATA_INSTANCE1_SRC (KDATA_BASE_ADDR + 0x001C)
+#define KDATA_INSTANCE_SRC_ENDMARK (KDATA_BASE_ADDR + 0x001D)
+
+#define KDATA_INSTANCE0_MINISRC (KDATA_BASE_ADDR + 0x001E)
+#define KDATA_INSTANCE1_MINISRC (KDATA_BASE_ADDR + 0x001F)
+#define KDATA_INSTANCE2_MINISRC (KDATA_BASE_ADDR + 0x0020)
+#define KDATA_INSTANCE3_MINISRC (KDATA_BASE_ADDR + 0x0021)
+#define KDATA_INSTANCE_MINISRC_ENDMARK (KDATA_BASE_ADDR + 0x0022)
+
+#define KDATA_INSTANCE0_CPYTHRU (KDATA_BASE_ADDR + 0x0023)
+#define KDATA_INSTANCE1_CPYTHRU (KDATA_BASE_ADDR + 0x0024)
+#define KDATA_INSTANCE_CPYTHRU_ENDMARK (KDATA_BASE_ADDR + 0x0025)
+
+#define KDATA_CURRENT_DMA (KDATA_BASE_ADDR + 0x0026)
+#define KDATA_DMA_SWITCH (KDATA_BASE_ADDR + 0x0027)
+#define KDATA_DMA_ACTIVE (KDATA_BASE_ADDR + 0x0028)
+
+#define KDATA_DMA_XFER0 (KDATA_BASE_ADDR + 0x0029)
+#define KDATA_DMA_XFER1 (KDATA_BASE_ADDR + 0x002A)
+#define KDATA_DMA_XFER2 (KDATA_BASE_ADDR + 0x002B)
+#define KDATA_DMA_XFER3 (KDATA_BASE_ADDR + 0x002C)
+#define KDATA_DMA_XFER4 (KDATA_BASE_ADDR + 0x002D)
+#define KDATA_DMA_XFER5 (KDATA_BASE_ADDR + 0x002E)
+#define KDATA_DMA_XFER6 (KDATA_BASE_ADDR + 0x002F)
+#define KDATA_DMA_XFER7 (KDATA_BASE_ADDR + 0x0030)
+#define KDATA_DMA_XFER8 (KDATA_BASE_ADDR + 0x0031)
+#define KDATA_DMA_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0032)
+
+#define KDATA_I2S_SAMPLE_COUNT (KDATA_BASE_ADDR + 0x0033)
+#define KDATA_I2S_INT_METER (KDATA_BASE_ADDR + 0x0034)
+#define KDATA_I2S_ACTIVE (KDATA_BASE_ADDR + 0x0035)
+
+#define KDATA_TIMER_COUNT_RELOAD (KDATA_BASE_ADDR + 0x0036)
+#define KDATA_TIMER_COUNT_CURRENT (KDATA_BASE_ADDR + 0x0037)
+
+#define KDATA_HALT_SYNCH_CLIENT (KDATA_BASE_ADDR + 0x0038)
+#define KDATA_HALT_SYNCH_DMA (KDATA_BASE_ADDR + 0x0039)
+#define KDATA_HALT_ACKNOWLEDGE (KDATA_BASE_ADDR + 0x003A)
+
+#define KDATA_ADC1_XFER0 (KDATA_BASE_ADDR + 0x003B)
+#define KDATA_ADC1_XFER_ENDMARK (KDATA_BASE_ADDR + 0x003C)
+#define KDATA_ADC1_LEFT_VOLUME (KDATA_BASE_ADDR + 0x003D)
+#define KDATA_ADC1_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x003E)
+#define KDATA_ADC1_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x003F)
+#define KDATA_ADC1_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0040)
+
+#define KDATA_ADC2_XFER0 (KDATA_BASE_ADDR + 0x0041)
+#define KDATA_ADC2_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0042)
+#define KDATA_ADC2_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0043)
+#define KDATA_ADC2_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x0044)
+#define KDATA_ADC2_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x0045)
+#define KDATA_ADC2_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0046)
+
+#define KDATA_CD_XFER0 (KDATA_BASE_ADDR + 0x0047)
+#define KDATA_CD_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0048)
+#define KDATA_CD_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0049)
+#define KDATA_CD_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x004A)
+#define KDATA_CD_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x004B)
+#define KDATA_CD_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x004C)
+
+#define KDATA_MIC_XFER0 (KDATA_BASE_ADDR + 0x004D)
+#define KDATA_MIC_XFER_ENDMARK (KDATA_BASE_ADDR + 0x004E)
+#define KDATA_MIC_VOLUME (KDATA_BASE_ADDR + 0x004F)
+#define KDATA_MIC_SUR_VOL (KDATA_BASE_ADDR + 0x0050)
+
+#define KDATA_I2S_XFER0 (KDATA_BASE_ADDR + 0x0051)
+#define KDATA_I2S_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0052)
+
+#define KDATA_CHI_XFER0 (KDATA_BASE_ADDR + 0x0053)
+#define KDATA_CHI_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0054)
+
+#define KDATA_SPDIF_XFER (KDATA_BASE_ADDR + 0x0055)
+#define KDATA_SPDIF_CURRENT_FRAME (KDATA_BASE_ADDR + 0x0056)
+#define KDATA_SPDIF_FRAME0 (KDATA_BASE_ADDR + 0x0057)
+#define KDATA_SPDIF_FRAME1 (KDATA_BASE_ADDR + 0x0058)
+#define KDATA_SPDIF_FRAME2 (KDATA_BASE_ADDR + 0x0059)
+
+#define KDATA_SPDIF_REQUEST (KDATA_BASE_ADDR + 0x005A)
+#define KDATA_SPDIF_TEMP (KDATA_BASE_ADDR + 0x005B)
+
+#define KDATA_SPDIFIN_XFER0 (KDATA_BASE_ADDR + 0x005C)
+#define KDATA_SPDIFIN_XFER_ENDMARK (KDATA_BASE_ADDR + 0x005D)
+#define KDATA_SPDIFIN_INT_METER (KDATA_BASE_ADDR + 0x005E)
+
+#define KDATA_DSP_RESET_COUNT (KDATA_BASE_ADDR + 0x005F)
+#define KDATA_DEBUG_OUTPUT (KDATA_BASE_ADDR + 0x0060)
+
+#define KDATA_KERNEL_ISR_LIST (KDATA_BASE_ADDR + 0x0061)
+
+#define KDATA_KERNEL_ISR_CBSR1 (KDATA_BASE_ADDR + 0x0062)
+#define KDATA_KERNEL_ISR_CBER1 (KDATA_BASE_ADDR + 0x0063)
+#define KDATA_KERNEL_ISR_CBCR (KDATA_BASE_ADDR + 0x0064)
+#define KDATA_KERNEL_ISR_AR0 (KDATA_BASE_ADDR + 0x0065)
+#define KDATA_KERNEL_ISR_AR1 (KDATA_BASE_ADDR + 0x0066)
+#define KDATA_KERNEL_ISR_AR2 (KDATA_BASE_ADDR + 0x0067)
+#define KDATA_KERNEL_ISR_AR3 (KDATA_BASE_ADDR + 0x0068)
+#define KDATA_KERNEL_ISR_AR4 (KDATA_BASE_ADDR + 0x0069)
+#define KDATA_KERNEL_ISR_AR5 (KDATA_BASE_ADDR + 0x006A)
+#define KDATA_KERNEL_ISR_BRCR (KDATA_BASE_ADDR + 0x006B)
+#define KDATA_KERNEL_ISR_PASR (KDATA_BASE_ADDR + 0x006C)
+#define KDATA_KERNEL_ISR_PAER (KDATA_BASE_ADDR + 0x006D)
+
+#define KDATA_CLIENT_SCRATCH0 (KDATA_BASE_ADDR + 0x006E)
+#define KDATA_CLIENT_SCRATCH1 (KDATA_BASE_ADDR + 0x006F)
+#define KDATA_KERNEL_SCRATCH (KDATA_BASE_ADDR + 0x0070)
+#define KDATA_KERNEL_ISR_SCRATCH (KDATA_BASE_ADDR + 0x0071)
+
+#define KDATA_OUEUE_LEFT (KDATA_BASE_ADDR + 0x0072)
+#define KDATA_QUEUE_RIGHT (KDATA_BASE_ADDR + 0x0073)
+
+#define KDATA_ADC1_REQUEST (KDATA_BASE_ADDR + 0x0074)
+#define KDATA_ADC2_REQUEST (KDATA_BASE_ADDR + 0x0075)
+#define KDATA_CD_REQUEST (KDATA_BASE_ADDR + 0x0076)
+#define KDATA_MIC_REQUEST (KDATA_BASE_ADDR + 0x0077)
+
+#define KDATA_ADC1_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0078)
+#define KDATA_ADC2_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0079)
+#define KDATA_CD_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007A)
+#define KDATA_MIC_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007B)
+#define KDATA_MIC_SYNC_COUNTER (KDATA_BASE_ADDR + 0x007C)
+
+/*
+ * second 'segment' (?) reserved for mixer
+ * buffers..
+ */
+
+#define KDATA_MIXER_WORD0 (KDATA_BASE_ADDR2 + 0x0000)
+#define KDATA_MIXER_WORD1 (KDATA_BASE_ADDR2 + 0x0001)
+#define KDATA_MIXER_WORD2 (KDATA_BASE_ADDR2 + 0x0002)
+#define KDATA_MIXER_WORD3 (KDATA_BASE_ADDR2 + 0x0003)
+#define KDATA_MIXER_WORD4 (KDATA_BASE_ADDR2 + 0x0004)
+#define KDATA_MIXER_WORD5 (KDATA_BASE_ADDR2 + 0x0005)
+#define KDATA_MIXER_WORD6 (KDATA_BASE_ADDR2 + 0x0006)
+#define KDATA_MIXER_WORD7 (KDATA_BASE_ADDR2 + 0x0007)
+#define KDATA_MIXER_WORD8 (KDATA_BASE_ADDR2 + 0x0008)
+#define KDATA_MIXER_WORD9 (KDATA_BASE_ADDR2 + 0x0009)
+#define KDATA_MIXER_WORDA (KDATA_BASE_ADDR2 + 0x000A)
+#define KDATA_MIXER_WORDB (KDATA_BASE_ADDR2 + 0x000B)
+#define KDATA_MIXER_WORDC (KDATA_BASE_ADDR2 + 0x000C)
+#define KDATA_MIXER_WORDD (KDATA_BASE_ADDR2 + 0x000D)
+#define KDATA_MIXER_WORDE (KDATA_BASE_ADDR2 + 0x000E)
+#define KDATA_MIXER_WORDF (KDATA_BASE_ADDR2 + 0x000F)
+
+#define KDATA_MIXER_XFER0 (KDATA_BASE_ADDR2 + 0x0010)
+#define KDATA_MIXER_XFER1 (KDATA_BASE_ADDR2 + 0x0011)
+#define KDATA_MIXER_XFER2 (KDATA_BASE_ADDR2 + 0x0012)
+#define KDATA_MIXER_XFER3 (KDATA_BASE_ADDR2 + 0x0013)
+#define KDATA_MIXER_XFER4 (KDATA_BASE_ADDR2 + 0x0014)
+#define KDATA_MIXER_XFER5 (KDATA_BASE_ADDR2 + 0x0015)
+#define KDATA_MIXER_XFER6 (KDATA_BASE_ADDR2 + 0x0016)
+#define KDATA_MIXER_XFER7 (KDATA_BASE_ADDR2 + 0x0017)
+#define KDATA_MIXER_XFER8 (KDATA_BASE_ADDR2 + 0x0018)
+#define KDATA_MIXER_XFER9 (KDATA_BASE_ADDR2 + 0x0019)
+#define KDATA_MIXER_XFER_ENDMARK (KDATA_BASE_ADDR2 + 0x001A)
+
+#define KDATA_MIXER_TASK_NUMBER (KDATA_BASE_ADDR2 + 0x001B)
+#define KDATA_CURRENT_MIXER (KDATA_BASE_ADDR2 + 0x001C)
+#define KDATA_MIXER_ACTIVE (KDATA_BASE_ADDR2 + 0x001D)
+#define KDATA_MIXER_BANK_STATUS (KDATA_BASE_ADDR2 + 0x001E)
+#define KDATA_DAC_LEFT_VOLUME (KDATA_BASE_ADDR2 + 0x001F)
+#define KDATA_DAC_RIGHT_VOLUME (KDATA_BASE_ADDR2 + 0x0020)
+
+#define MAX_INSTANCE_MINISRC (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC)
+#define MAX_VIRTUAL_DMA_CHANNELS (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0)
+#define MAX_VIRTUAL_MIXER_CHANNELS (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0)
+#define MAX_VIRTUAL_ADC1_CHANNELS (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0)
+
+/*
+ * client data area offsets
+ */
+#define CDATA_INSTANCE_READY 0x00
+
+#define CDATA_HOST_SRC_ADDRL 0x01
+#define CDATA_HOST_SRC_ADDRH 0x02
+#define CDATA_HOST_SRC_END_PLUS_1L 0x03
+#define CDATA_HOST_SRC_END_PLUS_1H 0x04
+#define CDATA_HOST_SRC_CURRENTL 0x05
+#define CDATA_HOST_SRC_CURRENTH 0x06
+
+#define CDATA_IN_BUF_CONNECT 0x07
+#define CDATA_OUT_BUF_CONNECT 0x08
+
+#define CDATA_IN_BUF_BEGIN 0x09
+#define CDATA_IN_BUF_END_PLUS_1 0x0A
+#define CDATA_IN_BUF_HEAD 0x0B
+#define CDATA_IN_BUF_TAIL 0x0C
+#define CDATA_OUT_BUF_BEGIN 0x0D
+#define CDATA_OUT_BUF_END_PLUS_1 0x0E
+#define CDATA_OUT_BUF_HEAD 0x0F
+#define CDATA_OUT_BUF_TAIL 0x10
+
+#define CDATA_DMA_CONTROL 0x11
+#define CDATA_RESERVED 0x12
+
+#define CDATA_FREQUENCY 0x13
+#define CDATA_LEFT_VOLUME 0x14
+#define CDATA_RIGHT_VOLUME 0x15
+#define CDATA_LEFT_SUR_VOL 0x16
+#define CDATA_RIGHT_SUR_VOL 0x17
+
+#define CDATA_HEADER_LEN 0x18
+
+#define SRC3_DIRECTION_OFFSET CDATA_HEADER_LEN
+#define SRC3_MODE_OFFSET (CDATA_HEADER_LEN + 1)
+#define SRC3_WORD_LENGTH_OFFSET (CDATA_HEADER_LEN + 2)
+#define SRC3_PARAMETER_OFFSET (CDATA_HEADER_LEN + 3)
+#define SRC3_COEFF_ADDR_OFFSET (CDATA_HEADER_LEN + 8)
+#define SRC3_FILTAP_ADDR_OFFSET (CDATA_HEADER_LEN + 10)
+#define SRC3_TEMP_INBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 16)
+#define SRC3_TEMP_OUTBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 17)
+
+#define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 )
+#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
+#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
+#define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
+#define MINISRC_BIQUAD_STAGE 2
+#define MINISRC_COEF_LOC 0X175
+
+#define DMACONTROL_BLOCK_MASK 0x000F
+#define DMAC_BLOCK0_SELECTOR 0x0000
+#define DMAC_BLOCK1_SELECTOR 0x0001
+#define DMAC_BLOCK2_SELECTOR 0x0002
+#define DMAC_BLOCK3_SELECTOR 0x0003
+#define DMAC_BLOCK4_SELECTOR 0x0004
+#define DMAC_BLOCK5_SELECTOR 0x0005
+#define DMAC_BLOCK6_SELECTOR 0x0006
+#define DMAC_BLOCK7_SELECTOR 0x0007
+#define DMAC_BLOCK8_SELECTOR 0x0008
+#define DMAC_BLOCK9_SELECTOR 0x0009
+#define DMAC_BLOCKA_SELECTOR 0x000A
+#define DMAC_BLOCKB_SELECTOR 0x000B
+#define DMAC_BLOCKC_SELECTOR 0x000C
+#define DMAC_BLOCKD_SELECTOR 0x000D
+#define DMAC_BLOCKE_SELECTOR 0x000E
+#define DMAC_BLOCKF_SELECTOR 0x000F
+#define DMACONTROL_PAGE_MASK 0x00F0
+#define DMAC_PAGE0_SELECTOR 0x0030
+#define DMAC_PAGE1_SELECTOR 0x0020
+#define DMAC_PAGE2_SELECTOR 0x0010
+#define DMAC_PAGE3_SELECTOR 0x0000
+#define DMACONTROL_AUTOREPEAT 0x1000
+#define DMACONTROL_STOPPED 0x2000
+#define DMACONTROL_DIRECTION 0x0100
+
+
+/*
+ * DSP Code images
+ */
+
+u16 assp_kernel_image[] = {
+ 0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4,
+ 0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
+ 0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
+ 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980, 0x03B4, 0x7980, 0x03B4,
+ 0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20, 0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08,
+ 0x0053, 0x695A, 0xEB08, 0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909,
+ 0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40, 0x7980, 0x0038, 0xBE41,
+ 0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A, 0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308,
+ 0x005E, 0x903A, 0xEF00, 0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910,
+ 0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00, 0x690E, 0x660D, 0xEF00,
+ 0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939, 0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026,
+ 0x8B88, 0x6980, 0xE388, 0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0,
+ 0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005, 0x100A, 0xBA01, 0x9012,
+ 0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B, 0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A,
+ 0x0C10, 0x4005, 0x100E, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000,
+ 0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012, 0x0C12, 0x4001, 0x0C05,
+ 0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF, 0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26,
+ 0x1028, 0x6970, 0xBFD0, 0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300,
+ 0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801, 0x907F, 0x0056, 0x8B88,
+ 0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200, 0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008,
+ 0x8056, 0x7980, 0x03A1, 0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80,
+ 0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01, 0xE308, 0x010C, 0xAE71,
+ 0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A,
+ 0x0560, 0xF500, 0xBF0A, 0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100,
+ 0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538, 0xBF0D, 0x053C, 0x6900,
+ 0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0, 0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903,
+ 0x8809, 0xBEC6, 0x013E, 0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309,
+ 0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B, 0x0578, 0xF500, 0xBF0B,
+ 0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB, 0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540,
+ 0xF500, 0xAE72, 0x0500, 0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C,
+ 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380, 0x733E, 0x7A80, 0x0380,
+ 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340,
+ 0x7A80, 0x0380, 0x6975, 0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041,
+ 0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA18,
+ 0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40,
+ 0x0814, 0xBA24, 0x8812, 0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9,
+ 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6, 0x697A, 0xE388, 0x01D8,
+ 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A,
+ 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80,
+ 0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40,
+ 0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C, 0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80,
+ 0x034A, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A,
+ 0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03, 0x98A0, 0x1F20, 0x2F1F,
+ 0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933, 0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1,
+ 0x9033, 0xBF00, 0x6951, 0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034,
+ 0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80, 0x5760, 0xBE03, 0x9F7E,
+ 0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980, 0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977,
+ 0xE388, 0x024E, 0xAE61, 0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B,
+ 0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009, 0x0810, 0x660C, 0xE388,
+ 0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80,
+ 0xE100, 0x0266, 0x697C, 0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473,
+ 0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0524, 0x9073, 0x0473,
+ 0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A, 0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880,
+ 0xBC21, 0x7326, 0x548B, 0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80,
+ 0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02B6,
+ 0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909,
+ 0x900B, 0x7980, 0x02A5, 0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED,
+ 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980, 0x02B8, 0xAF0B, 0x4005,
+ 0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388,
+ 0x02E7, 0xBFA0, 0x0800, 0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4,
+ 0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100,
+ 0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10,
+ 0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070,
+ 0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372, 0x7804, 0x9071, 0x0D71,
+ 0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309, 0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A,
+ 0xE344, 0x030F, 0x0009, 0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061,
+ 0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034, 0xBF0A, 0x109E, 0x8B8A,
+ 0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500, 0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6,
+ 0x7980, 0x03A1, 0x7A80, 0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A,
+ 0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x105C, 0x7A80, 0x02F6,
+ 0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88, 0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358,
+ 0x690E, 0x6610, 0x620F, 0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6,
+ 0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD, 0x98A9, 0x6A8C, 0x61A9,
+ 0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04, 0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379,
+ 0x040D, 0x8410, 0xBC21, 0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6,
+ 0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809, 0x906B, 0x080A, 0x906C,
+ 0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063, 0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166,
+ 0x8267, 0x8368, 0x8469, 0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B,
+ 0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267, 0x0368, 0x0469, 0x056A,
+ 0xBE3A,
+};
+
+/*
+ * Mini sample rate converter code image
+ * that is to be loaded at 0x400 on the DSP.
+ */
+u16 assp_minisrc_image[] = {
+
+ 0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412,
+ 0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41,
+ 0x7A80, 0x002A, 0xBE40, 0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907,
+ 0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009, 0x881A, 0x100A, 0xBA01,
+ 0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D, 0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904,
+ 0x9027, 0x6918, 0xE308, 0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D,
+ 0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6, 0x0453, 0x10A9, 0x90AD,
+ 0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460, 0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22,
+ 0x90AD, 0x7980, 0x047C, 0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0,
+ 0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22, 0x90A0, 0x90AD, 0x10A9,
+ 0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308, 0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89,
+ 0x022C, 0x108A, 0x7C04, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0,
+ 0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99AF, 0x7B99, 0x0484,
+ 0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0, 0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80,
+ 0x051A, 0x6927, 0xBA01, 0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624,
+ 0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80, 0x051A, 0x7980, 0x04B4,
+ 0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80, 0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027,
+ 0xE308, 0x04B4, 0x0124, 0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903,
+ 0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901, 0x8818, 0xB907, 0x8809,
+ 0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F, 0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46,
+ 0xBEC6, 0x04FA, 0x17A0, 0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47,
+ 0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7, 0xFF00, 0xBE1E, 0x1EA0,
+ 0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516,
+ 0x0D07, 0x8510, 0xBE59, 0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E,
+ 0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03, 0x9825, 0x1025, 0x201C,
+ 0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880, 0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180,
+ 0x9880, 0x8BA0, 0x101F, 0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E,
+ 0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0,
+ 0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0, 0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0,
+ 0xBEC6, 0x056B, 0xBE59, 0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0,
+ 0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090, 0x8BD0, 0x8BD8, 0xBE1F,
+ 0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
#ifdef CONFIG_SOUND_MAESTRO
init_maestro();
#endif
+#ifdef CONFIG_SOUND_MAESTRO3
+ init_maestro3();
+#endif
#ifdef CONFIG_SOUND_TRIDENT
init_trident();
#endif
u16 w;
unsigned long iobase;
struct trident_card *card;
-
+ unsigned long flags;
iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
if (check_region(iobase, 256)) {
/* reset command */
while (inb(card->iobase + ALI_MPUR1) & 0x40);
+
+ /* After the out the chip goes into irq jammed on
+ mode. We have to keep irqs off until it shuts up
+ again */
+ save_flags(flags);
+ cli();
outb(0xff, card->iobase + ALI_MPUR1);
while (inb(card->iobase + ALI_MPUR1) & 0x80);
while ((inb(card->iobase + ALI_MPUR0) != 0xfe) && (inb(card->iobase+ALI_MPUR1) != 0x10))
while (inb(card->iobase + ALI_MPUR1) & 0x80);
+ restore_flags(flags);
midi->ird = midi->iwr = midi->icnt = 0;
}
retval = search_binary_handler(&bprm,regs);
if(current->dumpable == 2)
- current->dumapble = 0;
+ current->dumpable = 0;
if (retval >= 0)
/* execve success */
tristate 'NLS ISO 8859-14 (Latin 8; Celtic)' CONFIG_NLS_ISO8859_14
tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15
tristate 'NLS KOI8-R (Russian)' CONFIG_NLS_KOI8_R
+ tristate 'NLS KOI8-RU (Belorussia, Ukraine)' CONFIG_NLS_KOI8_RU
endmenu
fi
endif
endif
+ifeq ($(CONFIG_NLS_KOI8_RU),y)
+NLS += nls_koi8-ru.o
+else
+ ifeq ($(CONFIG_NLS_KOI8_RU),m)
+ M_OBJS += nls_koi8-ru.o
+ endif
+endif
+
O_TARGET = nls.o
OX_OBJS = $(NLS)
#endif
#ifdef CONFIG_NLS_KOI8_R
init_nls_koi8_r();
+#endif
+#ifdef CONFIG_NLS_KOI8_RU
+ init_nls_koi8_ru();
#endif
return 0;
}
--- /dev/null
+/*
+ * linux/fs/nls_koi8-r.c
+ *
+ * Charset koi8-r translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+#include <linux/init.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x25}, {0x02, 0x25}, {0x0c, 0x25}, {0x10, 0x25},
+ {0x14, 0x25}, {0x18, 0x25}, {0x1c, 0x25}, {0x24, 0x25},
+ {0x2c, 0x25}, {0x34, 0x25}, {0x3c, 0x25}, {0x80, 0x25},
+ {0x84, 0x25}, {0x88, 0x25}, {0x8c, 0x25}, {0x90, 0x25},
+ /* 0x90*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x20, 0x23},
+ {0xa0, 0x25}, {0x19, 0x22}, {0x1a, 0x22}, {0x48, 0x22},
+ {0x64, 0x22}, {0x65, 0x22}, {0xa0, 0x00}, {0x21, 0x23},
+ {0xb0, 0x00}, {0xb2, 0x00}, {0xb7, 0x00}, {0xf7, 0x00},
+ /* 0xa0*/
+ {0x50, 0x25}, {0x51, 0x25}, {0x52, 0x25}, {0x51, 0x04},
+ {0x54, 0x04}, {0x54, 0x25}, {0x56, 0x04}, {0x57, 0x04},
+ {0x57, 0x25}, {0x58, 0x25}, {0x59, 0x25}, {0x5a, 0x25},
+ {0x5b, 0x25}, {0x91, 0x04}, {0x5e, 0x04}, {0x5e, 0x25},
+ /* 0xb0*/
+ {0x5f, 0x25}, {0x60, 0x25}, {0x61, 0x25}, {0x01, 0x04},
+ {0x04, 0x04}, {0x63, 0x25}, {0x06, 0x04}, {0x07, 0x04},
+ {0x66, 0x25}, {0x67, 0x25}, {0x68, 0x25}, {0x69, 0x25},
+ {0x6a, 0x25}, {0x90, 0x04}, {0x0e, 0x04}, {0xa9, 0x00},
+ /* 0xc0*/
+ {0x4e, 0x04}, {0x30, 0x04}, {0x31, 0x04}, {0x46, 0x04},
+ {0x34, 0x04}, {0x35, 0x04}, {0x44, 0x04}, {0x33, 0x04},
+ {0x45, 0x04}, {0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04},
+ {0x3b, 0x04}, {0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04},
+ /* 0xd0*/
+ {0x3f, 0x04}, {0x4f, 0x04}, {0x40, 0x04}, {0x41, 0x04},
+ {0x42, 0x04}, {0x43, 0x04}, {0x36, 0x04}, {0x32, 0x04},
+ {0x4c, 0x04}, {0x4b, 0x04}, {0x37, 0x04}, {0x48, 0x04},
+ {0x4d, 0x04}, {0x49, 0x04}, {0x47, 0x04}, {0x4a, 0x04},
+ /* 0xe0*/
+ {0x2e, 0x04}, {0x10, 0x04}, {0x11, 0x04}, {0x26, 0x04},
+ {0x14, 0x04}, {0x15, 0x04}, {0x24, 0x04}, {0x13, 0x04},
+ {0x25, 0x04}, {0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04},
+ {0x1b, 0x04}, {0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04},
+ /* 0xf0*/
+ {0x1f, 0x04}, {0x2f, 0x04}, {0x20, 0x04}, {0x21, 0x04},
+ {0x22, 0x04}, {0x23, 0x04}, {0x16, 0x04}, {0x12, 0x04},
+ {0x2c, 0x04}, {0x2b, 0x04}, {0x17, 0x04}, {0x28, 0x04},
+ {0x2d, 0x04}, {0x29, 0x04}, {0x27, 0x04}, {0x2a, 0x04},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+ 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0xb7, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, /* 0x08-0x0f */
+ 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */
+ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */
+ 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */
+ 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */
+ 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */
+ 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa6, 0xa7, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xa0, 0xa1, 0xa2, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, /* 0x50-0x57 */
+ 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */
+ 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, /* 0x60-0x67 */
+ 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, page04, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, page22, page23, NULL, page25, NULL, NULL,
+};
+
+#if 0
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+#endif
+
+static void uni2char(unsigned char ch, unsigned char cl, unsigned char *out, int boundlen, int *outlen)
+{
+ unsigned char *uni2charset;
+
+ if (boundlen <= 0)
+ return;
+
+ uni2charset = page_uni2charset[ch];
+ if (uni2charset && uni2charset[cl])
+ out[0] = uni2charset[cl];
+ else
+ out[0] = '?';
+ *outlen = 1;
+ return;
+}
+
+static void char2uni(const unsigned char *rawstring, int *offset, unsigned char *uni1, unsigned char *uni2)
+{
+ *uni1 = charset2uni[*rawstring].uni1;
+ *uni2 = charset2uni[*rawstring].uni2;
+ *offset = 1;
+ return;
+}
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "koi8-ru",
+ uni2char,
+ char2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int __init init_nls_koi8_ru(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_koi8_ru();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
#define condition_codes(regs) \
((regs)->ARM_pc & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT))
-#define pc_pointer(v) \
- ((v) & 0x03fffffc)
-
-#define instruction_pointer(regs) \
- (pc_pointer((regs)->ARM_pc))
-
/* Are the current registers suitable for user mode?
* (used to maintain security in signal handlers)
*/
#define condition_codes(regs) \
((regs)->ARM_cpsr & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT))
-#define instruction_pointer(regs) ((regs)->ARM_pc)
-#define pc_pointer(v) (v)
-
/* Are the current registers suitable for user mode?
* (used to maintain security in signal handlers)
*/
#include <asm/arch/processor.h>
#include <asm/proc/processor.h>
+struct debug_info {
+ int nsaved;
+ struct {
+ unsigned long address;
+ unsigned long insn;
+ } bp[2];
+};
+
struct thread_struct {
- unsigned long address; /* Address of fault */
- unsigned long trap_no; /* Trap number */
- unsigned long error_code; /* Error code of trap */
- union fp_state fpstate; /* FPE save state */
- unsigned long debug[NR_DEBUGS]; /* Debug/ptrace */
- struct context_save_struct *save; /* context save */
+ /* fault info */
+ unsigned long address;
+ unsigned long trap_no;
+ unsigned long error_code;
+ /* floating point */
+ union fp_state fpstate;
+ /* debugging */
+ struct debug_info debug;
+ /* context info */
+ struct context_save_struct *save;
unsigned long memmap; /* page tables */
EXTRA_THREAD_STRUCT
};
*/
extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t)
{
- return t->save ? t->save->pc & ~PCMASK : 0;
+ return t->save ? pc_pointer(t->save->pc) : 0;
}
extern __inline__ unsigned long get_css_fp(struct thread_struct *t)
#include <asm/proc/ptrace.h>
+#ifndef __ASSEMBLY__
+#define pc_pointer(v) \
+ ((v) & ~PCMASK)
+
+#define instruction_pointer(regs) \
+ (pc_pointer((regs)->ARM_pc))
+
#ifdef __KERNEL__
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+
extern void show_regs(struct pt_regs *);
+
+#define predicate(x) (x & 0xf0000000)
+#define PREDICATE_ALWAYS 0xe0000000
+
#endif
+#endif /* __ASSEMBLY__ */
+
#endif
*/
#define NFS_MAXFHSIZE 64
struct nfs_fh {
- unsigned short size;
+ unsigned int size;
unsigned char data[NFS_MAXFHSIZE];
};
extern int init_nls_cp949(void);
extern int init_nls_cp950(void);
extern int init_nls_koi8_r(void);
+extern int init_nls_koi8_ru(void);
int pdeath_signal; /* The signal sent when the parent dies */
/* ??? */
unsigned long personality;
- int dumpable:2;
+ unsigned int dumpable:2;
int did_exec:1;
pid_t pid;
pid_t pgrp;