diff -u --recursive --new-file v1.3.8/linux/CREDITS linux/CREDITS --- v1.3.8/linux/CREDITS Fri Jul 7 13:42:57 1995 +++ linux/CREDITS Mon Jul 10 17:08:04 1995 @@ -164,6 +164,13 @@ S: Bellevue, Washington 98007 S: USA +N: Hamish Coleman +E: hamish@zot.apana.org.au +D: SEEQ8005 network driver +S: 98 Paxton Street +S: East Malvern, Victoria, 3145 +S: Australia + N: Alan Cox E: A.Cox@swansea.ac.uk E: iiitac@pyr.swan.ac.uk @@ -235,7 +242,7 @@ N: Paal-Kristian Engstad E: engstad@funcom.com -D: Wrote smbfs (to mount WfW, NT and OS/2 network drives.) +D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.) S: Oscars gt. 35 S: N-0258 OSLO S: Norway @@ -473,6 +480,13 @@ S: Mr. v. Boemellaan 39 S: NL-5237 KA 's-Hertogenbosch S: The Netherlands + +N: Volker Lendecke +E: lendecke@namu01.gwdg.de +D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.) +S: Innersteweg 11 +S: 37081 Goettingen +S: Germany N: Kevin Lentin E: kevinl@cs.monash.edu.au diff -u --recursive --new-file v1.3.8/linux/Makefile linux/Makefile --- v1.3.8/linux/Makefile Fri Jul 7 13:42:57 1995 +++ linux/Makefile Tue Jul 11 08:02:20 1995 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 8 +SUBLEVEL = 9 ARCH = i386 @@ -106,8 +106,6 @@ include arch/$(ARCH)/Makefile -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< .s.o: $(AS) -o $*.o $< .c.o: diff -u --recursive --new-file v1.3.8/linux/Rules.make linux/Rules.make --- v1.3.8/linux/Rules.make Thu Jan 1 02:00:00 1970 +++ linux/Rules.make Tue Jul 11 08:02:20 1995 @@ -0,0 +1,21 @@ +# +# This file contains rules which are shared between multiple Makefiles. +# + +# +# Common rules +# +.c.s: + $(CC) $(CFLAGS) -S $< + +# +# A rule to do nothing +# +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff -u --recursive --new-file v1.3.8/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile --- v1.3.8/linux/arch/alpha/boot/Makefile Wed Jan 18 22:52:36 1995 +++ linux/arch/alpha/boot/Makefile Tue Jul 11 08:02:20 1995 @@ -8,8 +8,6 @@ # Copyright (C) 1994 by Linus Torvalds # -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< .s.o: $(AS) -o $*.o $< .c.o: diff -u --recursive --new-file v1.3.8/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v1.3.8/linux/arch/alpha/kernel/Makefile Thu Jun 1 13:22:05 1995 +++ linux/arch/alpha/kernel/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -o $*.o $< .c.o: @@ -35,13 +33,4 @@ dep: $(CPP) -M *.c > .depend -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - - +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v1.3.8/linux/arch/alpha/kernel/entry.S Tue Jun 27 14:11:30 1995 +++ linux/arch/alpha/kernel/entry.S Tue Jul 11 08:14:54 1995 @@ -369,6 +369,8 @@ jsr $26,($27),alpha_fork br $0,undo_switch_stack ldq $0,0($30) + bis $31,2,$19 /* Make sure that the stored user register v0 has */ + stq $19,0($30) /* the syscall # for fork */ ret $31,($26),1 .end sys_fork @@ -406,8 +408,16 @@ beq $1,1f ldq $27,0($2) 1: jsr $26,($27),do_entSys + ldq $1,0($30) /* We have to handle ptrace specially */ + subq $1,26,$1 /* since it returns a pointer value it will*/ + bne $1,3f /* set up a3 and v0 in the return frame */ + ldq $1,72($30) + stq $1,0($30) + stq $0,72($30) bis $31,$31,$1 - bge $0,2f + br $31,ret_from_sys_call +3: bis $31,$31,$1 + bge $0,2f /* the call succeeded */ bis $31,$31,$26 /* tell "ret_from_sys_call" that we can restart */ ldq $19,0($30) /* .. with this syscall nr */ ldq $20,72($30) /* .. and this a3 */ diff -u --recursive --new-file v1.3.8/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v1.3.8/linux/arch/alpha/kernel/ptrace.c Thu Jan 1 02:00:00 1970 +++ linux/arch/alpha/kernel/ptrace.c Tue Jul 11 08:13:58 1995 @@ -0,0 +1,647 @@ +/* ptrace.c */ +/* By Ross Biro 1/23/92 */ +/* edited by Linus Torvalds */ +/* mangled further by Bob Manson (manson@santafe.edu) */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* This was determined via brute force. */ +#define MAGICNUM 496 + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which flags the user has access to. */ +/* 1 = access 0 = no access */ +#define FLAG_MASK 0x00044dd5 + +/* set's the trap flag. */ +#define TRAP_FLAG 0x100 + +/* + * this is the number to subtract from the top of the stack. To find + * the local frame. + */ + +/* A mapping between register number and its offset on the kernel stack. + * You also need to add MAGICNUM to get past the kernel stack frame + * to the actual saved user info. + * The first portion is the switch_stack, then comes the pt_regs. + * 320 is the size of the switch_stack area. + */ + +static int map_reg_to_offset[] = { + 320+0,320+8,320+16,320+24,320+32,320+40,320+48,320+56,320+64, /* 0-8 */ + 0,8,16,24,32,40,48, /* 9-15 */ + 320+184,320+192,320+200, /* 16-18 */ + 320+72,320+80,320+88,320+96,320+104,320+112,320+120, /* 19-25 */ + 320+128,320+136,320+144,320+176,320+160,-1, /* 26-31*/ + + /* fp registers below */ + 64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192, + 200,208,216,224,232,240,248,256,264,272,280,288,296,304,312, + + /* 64 = pc */ + 320+168 +}; + +static int offset_of_register(int reg_num) { + if(reg_num<0 || reg_num>64) { + return -1; + } + return map_reg_to_offset[reg_num]; +} + +static void unset_singlestep(struct task_struct *child) { +} + +static void set_singlestep(struct task_struct *child) { +} + +/* change a pid into a task struct. */ +static inline struct task_struct * get_task(int pid) +{ + int i; + + for (i = 1; i < NR_TASKS; i++) { + if (task[i] != NULL && (task[i]->pid == pid)) + return task[i]; + } + return NULL; +} + +/* + * this routine will get a word off of the processes privileged stack. + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the privileged stacks are in our + * data space. + * MAGICNUM is the amount to skip to get to the actual user regs. It + * was determined by brute force & asking BufElves. + */ +static inline long get_stack_long(struct task_struct *task, unsigned long offset) +{ + unsigned char *stack; + + stack = (unsigned char *)task->tss.ksp; + stack += offset+MAGICNUM; + return (*((long *)stack)); +} + +/* + * this routine will put a word on the processes privileged stack. + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the privileged stacks are in our + * data space. + */ +static inline int put_stack_long(struct task_struct *task, unsigned long offset, + unsigned long data) +{ + unsigned char * stack; + + stack = (unsigned char *) task->tss.ksp; + stack += offset+MAGICNUM; + *(unsigned long *) stack = data; + return 0; +} + +/* + * This routine gets a long from any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + */ +static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr) +{ + pgd_t * pgdir; + pmd_t * pgmiddle; + pte_t * pgtable; + unsigned long page; + +#ifdef DEBUG + printk("Getting long at 0x%lx\n",addr); +#endif +repeat: + pgdir = pgd_offset(vma->vm_task, addr); + if (pgd_none(*pgdir)) { + do_no_page(vma, addr, 0); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return 0; + } + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + do_no_page(vma, addr, 0); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return 0; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + do_no_page(vma, addr, 0); + goto repeat; + } + page = pte_page(*pgtable); +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (page >= high_memory) + return 0; + page += addr & ~PAGE_MASK; + return *(unsigned long *) page; +} + +/* + * This routine puts a long into any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + * + * Now keeps R/W state of page so that a text page stays readonly + * even if a debugger scribbles breakpoints into it. -M.U- + */ +static void put_long(struct vm_area_struct * vma, unsigned long addr, + unsigned long data) +{ + pgd_t *pgdir; + pmd_t *pgmiddle; + pte_t *pgtable; + unsigned long page; + +repeat: + pgdir = pgd_offset(vma->vm_task, addr); + if (!pgd_present(*pgdir)) { + do_no_page(vma, addr, 1); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return; + } + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + do_no_page(vma, addr, 1); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + do_no_page(vma, addr, 1); + goto repeat; + } + page = pte_page(*pgtable); + if (!pte_write(*pgtable)) { + do_wp_page(vma, addr, 1); + goto repeat; + } +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (page < high_memory) { + page += addr & ~PAGE_MASK; + *(unsigned long *) page = data; + } +/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ +/* this should also re-instate whatever read-only mode there was before */ + *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot)); + invalidate(); +} + +static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr) +{ + struct vm_area_struct * vma; + + addr &= PAGE_MASK; + vma = find_vma(tsk,addr); + if (!vma) + return NULL; + if (vma->vm_start <= addr) + return vma; + if (!(vma->vm_flags & VM_GROWSDOWN)) + return NULL; + if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur) + return NULL; + vma->vm_offset -= vma->vm_start - addr; + vma->vm_start = addr; + return vma; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls get_long() to read a long. + */ +static int read_long(struct task_struct * tsk, unsigned long addr, + unsigned long * result) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + +#ifdef DEBUG + printk("in read_long\n"); +#endif + if (!vma) { + printk("Unable to find vma for addr 0x%lx\n",addr); + return -EIO; + } + if ((addr & ~PAGE_MASK) > (PAGE_SIZE-sizeof(long))) { + unsigned long low,high; + struct vm_area_struct * vma_high = vma; + + if (addr + sizeof(long) >= vma->vm_end) { + vma_high = vma->vm_next; + if (!vma_high || vma_high->vm_start != vma->vm_end) + return -EIO; + } + low = get_long(vma, addr & ~(sizeof(long)-1)); + high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 1: + low >>= 8; + low |= high << 56; + break; + case 2: + low >>= 16; + low |= high << 48; + break; + case 3: + low >>= 24; + low |= high << 40; + break; + case 4: + low >>= 32; + low |= high << 32; + break; + case 5: + low >>= 40; + low |= high << 24; + break; + case 6: + low >>= 48; + low |= high << 16; + break; + case 7: + low >>= 56; + low |= high << 8; + break; + } + *result = low; + } else { + long l =get_long(vma, addr); + +#ifdef DEBUG + printk("value is 0x%lx\n",l); +#endif + *result = l; + } + return 0; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls put_long() to write a long. + */ +static int write_long(struct task_struct * tsk, unsigned long addr, + unsigned long data) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + unsigned long low,high; + struct vm_area_struct * vma_high = vma; + + if (addr + sizeof(long) >= vma->vm_end) { + vma_high = vma->vm_next; + if (!vma_high || vma_high->vm_start != vma->vm_end) + return -EIO; + } + low = get_long(vma, addr & ~(sizeof(long)-1)); + high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 0: /* shouldn't happen, but safety first */ + low = data; + break; + case 1: + low &= 0x00000000000000ffL; + low |= data << 8; + high &= ~0x000000000000ffL; + high |= data >> 56; + break; + case 2: + low &= 0x000000000000ffffL; + low |= data << 16; + high &= ~0x0000000000ffffL; + high |= data >> 48; + break; + case 3: + low &= 0x0000000000ffffffL; + low |= data << 24; + high &= ~0x00000000ffffffL; + high |= data >> 40; + break; + case 4: + low &= 0x00000000ffffffffL; + low |= data << 32; + high &= ~0x000000ffffffffL; + high |= data >> 32; + break; + + case 5: + low &= 0x000000ffffffffffL; + low |= data << 40; + high &= ~0x0000ffffffffffL; + high |= data >> 24; + break; + case 6: + low &= 0x0000ffffffffffffL; + low |= data << 48; + high &= ~0x00ffffffffffffL; + high |= data >> 16; + break; + case 7: + low &= 0x00ffffffffffffffL; + low |= data << 56; + high &= ~0xffffffffffffffL; + high |= data >> 8; + break; + } + put_long(vma, addr & ~(sizeof(long)-1),low); + put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); + } else + put_long(vma, addr, data); + return 0; +} + +/* Uh, this does ugly stuff. It stores the specified value in the a3 + * register. entry.S will swap a3 and the returned value from + * sys_ptrace() before returning to the user. + */ + +static inline void set_success(struct pt_regs *regs,long resval) { + regs->r19=resval; +} + +/* This doesn't do diddly, actually--if the value returned from + * sys_ptrace() is != 0, it sets things up properly. + */ + +static inline void set_failure(struct pt_regs *regs,long errcode) { + regs->r19=0; +} + +asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4, int a5, struct pt_regs regs) +{ + struct task_struct *child; + struct user * dummy; + + dummy = NULL; + +#ifdef DEBUG + printk("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",request,pid,addr,data); +#endif + set_success(®s,0); + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->flags & PF_PTRACED) { + set_failure(®s,-EPERM); + return -EPERM; + } + /* set the ptrace bit in the process flags. */ + current->flags |= PF_PTRACED; + return 0; + } + if (pid == 1) { + set_failure(®s,-EPERM); + return -EPERM; + } + if (!(child = get_task(pid))) { + set_failure(®s,-ESRCH); + return -ESRCH; + } + if (request == PTRACE_ATTACH) { + if (child == current) { + set_failure(®s,-EPERM); + return -EPERM; + } + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->gid)) && !suser()) { + set_failure(®s,-EPERM); + return -EPERM; + } + /* the same process cannot be attached many times */ + if (child->flags & PF_PTRACED) { + set_failure(®s,-EPERM); + return -EPERM; + } + child->flags |= PF_PTRACED; + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + send_sig(SIGSTOP, child, 1); + return 0; + } + if (!(child->flags & PF_PTRACED)) { +#ifdef DEBUG + printk("child not traced\n"); +#endif + set_failure(®s,-ESRCH); + return -ESRCH; + } + if (child->state != TASK_STOPPED) { +#ifdef DEBUG + printk("child process not stopped\n"); +#endif + if (request != PTRACE_KILL) { + set_failure(®s,-ESRCH); + return -ESRCH; + } + } + if (child->p_pptr != current) { +#ifdef DEBUG + printk("child not parent of this process\n"); +#endif + set_failure(®s,-ESRCH); + return -ESRCH; + } + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int res; + +#ifdef DEBUG + printk("doing request at addr 0x%lx\n",addr); +#endif + res = read_long(child, addr, &tmp); + if (res < 0) { + set_failure(®s,res); + return res; + } + else { + set_success(®s,tmp); + return 0; + } + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + /* We only allow access to registers. */ + unsigned long tmp; + + tmp = 0; /* Default return condition */ + if(addr==30) { + /* stack pointer */ + tmp=child->tss.usp; + } + else { + int reg=addr; + addr = offset_of_register(addr); + if(addr < 0) { + set_failure(®s,-EIO); + return -EIO; + } + tmp = get_stack_long(child, addr); +#ifdef DEBUG + printk("%d = reg 0x%lx=tmp\n",reg,tmp); +#endif + } + set_success(®s,tmp); + return 0; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: { + long res=write_long(child,addr,data); + if(res) { + set_failure(®s,res); + } + return res; + } + + case PTRACE_POKEUSR: /* write the specified register */ + { + long res; + addr= offset_of_register(addr); + if(addr < 0) { + set_failure(®s,-EIO); + return -EIO; + } + res=put_stack_long(child,addr,data); + if(res) { + set_failure(®s,res); + } + return res; + } + + case PTRACE_SYSCALL: /* continue and stop at next + (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + if ((unsigned long) data > NSIG) { + set_failure(®s,-EIO); + return -EIO; + } + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + child->state = TASK_RUNNING; + unset_singlestep(child); + set_success(®s,data); + return 0; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + child->state = TASK_RUNNING; + child->exit_code = SIGKILL; + unset_singlestep(child); + return 0; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + if ((unsigned long) data > NSIG) { + set_failure(®s,-EIO); + return -EIO; + } + child->flags &= ~PF_TRACESYS; + set_singlestep(child); + child->state = TASK_RUNNING; + child->exit_code = data; + /* give it a chance to run. */ + return 0; + } + + case PTRACE_DETACH: { /* detach a process that was attached. */ + if ((unsigned long) data > NSIG) { + set_failure(®s,-EIO); + return -EIO; + } + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->state = TASK_RUNNING; + child->exit_code = data; + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + /* make sure the single step bit is not set. */ + unset_singlestep(child); + return 0; + } + + default: + { + set_failure(®s,-EIO); + return -EIO; + } + } +} + +asmlinkage void syscall_trace(void) +{ + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) + current->signal |= (1 << (current->exit_code - 1)); + current->exit_code = 0; +} diff -u --recursive --new-file v1.3.8/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile --- v1.3.8/linux/arch/alpha/lib/Makefile Fri Jun 16 22:02:54 1995 +++ linux/arch/alpha/lib/Makefile Tue Jul 11 08:02:20 1995 @@ -2,8 +2,6 @@ # Makefile for alpha-specific library files.. # -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -30,10 +28,4 @@ dep: -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/alpha/lib/checksum.c linux/arch/alpha/lib/checksum.c --- v1.3.8/linux/arch/alpha/lib/checksum.c Fri Jul 7 08:54:43 1995 +++ linux/arch/alpha/lib/checksum.c Mon Jul 10 16:59:58 1995 @@ -24,7 +24,7 @@ /* * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented + * returns a 16-bit checksum, already complemented. */ unsigned short int csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, @@ -32,7 +32,9 @@ unsigned short proto, unsigned int sum) { - return ~from64to16(saddr + daddr + sum + (ntohs(len) << 16) + (proto << 8)); + return ~from64to16(saddr + daddr + sum + + ((unsigned long) ntohs(len) << 16) + + ((unsigned long) proto << 8)); } /* @@ -83,6 +85,7 @@ carry = (w > result); } while (count); result += carry; + result = (result & 0xffffffff) + (result >> 32); } if (len & 4) { result += *(unsigned int *) buff; diff -u --recursive --new-file v1.3.8/linux/arch/alpha/mm/Makefile linux/arch/alpha/mm/Makefile --- v1.3.8/linux/arch/alpha/mm/Makefile Mon Jan 16 07:17:34 1995 +++ linux/arch/alpha/mm/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS = init.o fault.o @@ -24,9 +22,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile --- v1.3.8/linux/arch/i386/boot/compressed/Makefile Thu Jun 29 19:02:39 1995 +++ linux/arch/i386/boot/compressed/Makefile Tue Jul 11 08:02:20 1995 @@ -17,8 +17,6 @@ INPUT_LEN=input_len endif -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -o $*.o $< .c.o: diff -u --recursive --new-file v1.3.8/linux/arch/i386/config.in linux/arch/i386/config.in --- v1.3.8/linux/arch/i386/config.in Fri Jul 7 13:42:57 1995 +++ linux/arch/i386/config.in Mon Jul 10 17:08:04 1995 @@ -166,6 +166,7 @@ bool 'DEPCA support' CONFIG_DEPCA n bool 'EtherWorks 3 support' CONFIG_EWRK3 n if [ "$CONFIG_NET_ALPHA" = "y" ]; then + bool 'SEEQ8005 support' CONFIG_SEEQ8005 n bool 'AT1700 support' CONFIG_AT1700 n bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n bool 'EtherExpress support' CONFIG_EEXPRESS n diff -u --recursive --new-file v1.3.8/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v1.3.8/linux/arch/i386/kernel/Makefile Thu Jun 29 19:02:39 1995 +++ linux/arch/i386/kernel/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -o $*.o $< .c.o: @@ -38,13 +36,4 @@ modules: -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - - +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v1.3.8/linux/arch/i386/lib/Makefile Tue Jun 20 09:10:31 1995 +++ linux/arch/i386/lib/Makefile Tue Jul 11 08:02:20 1995 @@ -2,8 +2,6 @@ # Makefile for i386-specific library files.. # -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -19,10 +17,4 @@ modules: -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/i386/math-emu/Makefile linux/arch/i386/math-emu/Makefile --- v1.3.8/linux/arch/i386/math-emu/Makefile Fri Jun 30 16:22:25 1995 +++ linux/arch/i386/math-emu/Makefile Tue Jul 11 08:02:20 1995 @@ -42,11 +42,4 @@ modules: -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/i386/mm/Makefile linux/arch/i386/mm/Makefile --- v1.3.8/linux/arch/i386/mm/Makefile Mon Jan 16 07:17:35 1995 +++ linux/arch/i386/mm/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS = init.o fault.o @@ -24,9 +22,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/mips/kernel/Makefile linux/arch/mips/kernel/Makefile --- v1.3.8/linux/arch/mips/kernel/Makefile Wed Jan 25 08:54:22 1995 +++ linux/arch/mips/kernel/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) $(ASFLAGS) -o $*.o $< .c.o: @@ -60,11 +58,4 @@ modules: -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile --- v1.3.8/linux/arch/mips/mm/Makefile Wed Jan 25 08:54:22 1995 +++ linux/arch/mips/mm/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS = fault.o init.o @@ -24,9 +22,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile --- v1.3.8/linux/arch/sparc/boot/Makefile Tue Jun 27 14:11:30 1995 +++ linux/arch/sparc/boot/Makefile Tue Jul 11 08:02:20 1995 @@ -5,8 +5,6 @@ OBJS =bare.o init_me.o ../kernel/promops.o ../lib/lib.a BOOTLINKFLAGS = -N -Ttext 0x200000 -e _first_adr_in_text -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< .s.o: $(AS) -o $*.o $< .c.o: @@ -25,11 +23,4 @@ $(CPP) -M *.c > .depend $(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v1.3.8/linux/arch/sparc/kernel/Makefile Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -o $*.o $< .c.o: @@ -36,13 +34,4 @@ $(CPP) -M *.c > .depend $(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - - +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile --- v1.3.8/linux/arch/sparc/lib/Makefile Sun Jan 22 23:02:41 1995 +++ linux/arch/sparc/lib/Makefile Tue Jul 11 08:02:20 1995 @@ -4,8 +4,6 @@ CFLAGS := $(CFLAGS) -ansi -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -40,9 +38,4 @@ dep: -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile --- v1.3.8/linux/arch/sparc/mm/Makefile Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/mm/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS = fault.o vac-flush.o init.o sun4c.o srmmu.o loadmmu.o @@ -24,9 +22,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/arch/sparc/prom/Makefile linux/arch/sparc/prom/Makefile --- v1.3.8/linux/arch/sparc/prom/Makefile Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/Makefile Tue Jul 11 08:02:20 1995 @@ -23,11 +23,4 @@ dep: $(CPP) -M *.c > .depend -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/drivers/Makefile linux/drivers/Makefile --- v1.3.8/linux/drivers/Makefile Wed Jun 7 13:03:54 1995 +++ linux/drivers/Makefile Tue Jul 11 08:02:20 1995 @@ -9,14 +9,13 @@ .S.s: $(CPP) -traditional $< -o $*.s -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: $(CC) $(CFLAGS) -c $< SUBDIRS = block char net #streams +ALL_SUBDIRS = block char net scsi #streams ifdef CONFIG_PCI SUBDIRS := $(SUBDIRS) pci @@ -36,17 +35,9 @@ set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done modules: dummy - set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i modules; done + set -e; for i in $(ALL_SUBDIRS); do $(MAKE) -C $$i modules; done dep: - set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done - -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + set -e; for i in $(ALL_SUBDIRS); do $(MAKE) -C $$i dep; done +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v1.3.8/linux/drivers/block/Makefile Fri Jul 7 08:54:44 1995 +++ linux/drivers/block/Makefile Tue Jul 11 08:02:20 1995 @@ -9,8 +9,6 @@ # parent makefile. # -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -147,11 +145,4 @@ echo $(BLOCK_MODULE_OBJS) > ../../modules/BLOCK_MODULES (cd ../../modules;for i in $(BLOCK_MODULE_OBJS); do ln -sf ../drivers/block/$$i .; done) -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/drivers/block/README.aztcd linux/drivers/block/README.aztcd --- v1.3.8/linux/drivers/block/README.aztcd Wed Apr 5 12:59:50 1995 +++ linux/drivers/block/README.aztcd Mon Jul 10 08:00:56 1995 @@ -1,7 +1,7 @@ Readme-File README.aztcd for Aztech CD-ROM CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 CD-ROM Driver - Version 1.0 and newer + Version 1.2 and newer (for other drives see 6.-8.) NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE @@ -10,20 +10,27 @@ IT WILL DEFINITELY NOT WORK WITH CD-ROM DRIVES WITH *IDE*-INTERFACE, such as the Aztech CDA269-031SE !!! IF YOU'RE USING A CD-ROM DRIVE WITH IDE-INTERFACE, SOMETIMES ALSO CALLED ATAPI-COMPATIBLE, PLEASE - USE THE ide-cd.c DRIVER, WRITTEN BY MARK LORD AND SCOTT SNYDER !!! + USE THE ide-cd.c DRIVER, WRITTEN BY MARK LORD AND SCOTT SNYDER ! + THE STANDARD-KERNEL 1.2.x NOW ALSO SUPPORTS IDE-CDROM-DRIVES, SEE THE + HARDDISK (!) SECTION OF make config, WHEN COMPILING A NEW KERNEL!!! ---------------------------------------------------------------------------- Contents of this file: - 1. NOTE - 2. INSTALLATION - 3. CONFIGURING YOUR KERNEL - 4. RECOMPILING YOUR KERNEL - 5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS - 6. BUG REPORTS - 7. OTHER DRIVES - 8. IF YOU DON'T SUCCEED ... DEBUGGING - 9. TECHNICAL HISTORY OF THE DRIVER - 10. ACKNOWLEDGMENTS - 11. PROGRAMMING ADD ONS: CDPLAY.C + 1. NOTE + 2. INSTALLATION + 3. CONFIGURING YOUR KERNEL + 4. RECOMPILING YOUR KERNEL + 4.1 AZTCD AS A RUN-TIME LOADABLE MODULE + 4.2 CDROM CONNECTED TO A SOUNDCARD + 5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS + 5.1 MULTISESSION SUPPORT + 5.2 STATUS RECOGNITION + 5.3 DOSEMU's CDROM SUPPORT + 6. BUG REPORTS + 7. OTHER DRIVES + 8. IF YOU DON'T SUCCEED ... DEBUGGING + 9. TECHNICAL HISTORY OF THE DRIVER + 10. ACKNOWLEDGMENTS + 11. PROGRAMMING ADD ONS: CDPLAY.C APPENDIX: Source code of cdplay.c ---------------------------------------------------------------------------- @@ -94,7 +101,7 @@ - Edit aztcd.h to set the I/O-address to your I/O-Base address (AZT_BASE_ADDR), the driver does not use interrupts or DMA, so if you are using an AZTECH CD268, an ORCHID CD-3110 or ORCHID/WEARNES CDD110 that's the only item you - have to set up. + have to set up. If you have a soundcard, read chapter 4.2. Users of other drives should read chapter OTHER DRIVES of this file. You also can configure that address by LILO boot parameter aztcd=... - Build a new kernel, configure it for 'Aztech/Orchid/Okano/Wearnes support' @@ -126,8 +133,10 @@ 4.1 AZTCD AS A RUN-TIME LOADABLE MODULE If you do not need aztcd permanently, you can also load and remove the driver during runtime via insmod and rmmod. To build aztcd as a loadable module you -must *not* configure your kernel for AZTECH support. But you need to have -the ISO9660-filesystem included! So rebuild your kernel, if necessary. +must *not* configure your kernel for AZTECH support. Nevertheless, you may +run into problems, if the version of your boot kernel is not the same than +the source kernel version, from which you create the modules. So rebuild your +kernel, if necessary. Now edit the base address of your AZTECH interface card in /usr/src/linux/include/linux/aztcd.h to the appropriate value. Then change @@ -137,20 +146,42 @@ After that you can run-time load the driver via insmod /lib/modules/X.X.X/misc/aztcd.o and remove it via rmmod aztcd. -If you have not configured the correct base address, you can also supply the +If you did not set the correct base address in aztcd.h, you can also supply the base address when loading the driver via insmod /lib/modules/X.X.X/misc/aztcd.o aztcd= -In all commands 'X.X.X' is the current linux kernel version number. For details -see file README.modules in /usr/src/linux. - +If you do not have the iso9660-filesystem in your boot kernel, you also have +to load it before you can mount the CDROM: + insmod /lib/modules/X.X.X/fs/isofs.o +The mount procedure works as described in 4. above. +(In all commands 'X.X.X' is the current linux kernel version number. For details +see file README.modules in /usr/src/linux.) + +4.2 CDROM CONNECTED TO A SOUNDCARD +Most soundcards do have a bus interface to the CDROM-drive. In many cases +this soundcard needs to be configured, before the CDROM can be used. This +configuration procedure consists of writing some kind of initialization +data to the soundcard registers. The AZTECH-CDROM driver in the moment does +only support one type of soundcard (SoundWave32). Users of other soundcards +should try to boot DOS first and let their DOS drivers initialize the +soundcard and CDROM, then warm boot (or use loadlin) their PC to start +Linux. +Support for the CDROM-interface of SoundWave32-soundcards is directly +implemented in the AZTECH driver. Please edit /usr/src/linux/include/aztdc.h, +uncomment line '#define AZT_SW32' and set the appropiate value for +AZT_BASE_ADDR and AZT_SW32_BASE_ADDR. This support was tested with an Orchid +CDS-3110 connected to a SoundWave32. +If you want your soundcard to be supported, find out, how it needs to be +configured and mail me (see 6.) the appropriate information. 5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS +5.1 MULTISESSION SUPPORT The driver does not support applications such as photo CD, multi session CD etc.. I do not plan to include the support for that in the driver, because I do not use such applications. If you are interested in that stuff and would like to extend the drivers capability on your own, please contact me, I'll support you as far as I can. +5.2 STATUS RECOGNITION The drive status recognition does not work correctly in all cases. Changing a disk or having the door open, when a drive is already mounted, is detected by the Aztech driver itself, but nevertheless causes multiple read attempts @@ -170,6 +201,16 @@ and substitute STEN_LOW_WAIT by STEN_LOW. Busy waiting with STEN_LOW is more stable, but also causes CPU overhead. +5.3 DOSEMU's CD-ROM SUPPORT +With release 1.20 aztcd was modified to allow access to CD-ROMS when running +under dosemu-0.60. aztcd-versions before 1.20 are most likely to crash +Linux, when a CD-ROM is accessed under dosemu. This problem has partly been +fixed, but still when accessing a directory for the first time the system +might hang for some 30sec. So be patient, when using dosemu's CD-ROM support +in combination with aztcd :-) ! Unfortunately up to now, I could not locate +the root cause of that problem. It seems to be somewhere in the interaction +of the kernel with dosemu's and aztcd's buffers. I appreciate any help on +this subject ! 6. BUG REPORTS Please send detailed bug reports and bug fixes via EMail to @@ -380,7 +421,7 @@ also to all the guys on the Internet, who collected valuable technical information about CDROMs. -Joe Nardone (nardone@clark.net) was a patient tester even for my first +Joe Nardone (joe@access.digex.net) was a patient tester even for my first trial, which was more than slow, and made suggestions for code improvement. Especially the 'finite state machine' azt_poll() was rewritten by Joe to get clean C code and avoid the ugly 'gotos', which I copied from mcd.c. @@ -390,6 +431,9 @@ Joseph Piskor and Peter Nugent were the first users with the ORCHID CD3110 and also were very patient with the problems which occurred. + +Reinhard Max delivered the information for the CDROM-interface of the +SoundWave32 soundcards. Anybody, who is interested in these items should have a look at 'ftp.gwdg.de', directory 'pub/linux/cdrom' and at 'ftp.cdrom.com', directory 'pub/cdrom'. diff -u --recursive --new-file v1.3.8/linux/drivers/block/README.ide linux/drivers/block/README.ide --- v1.3.8/linux/drivers/block/README.ide Fri Jun 2 13:46:26 1995 +++ linux/drivers/block/README.ide Mon Jul 10 17:08:05 1995 @@ -1,4 +1,4 @@ -README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.2.x) +README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.3.x) ================================================================================ Supported by: mlord@bnr.ca -- disks, interfaces, probing snyder@fnald0.fnal.gov -- cdroms, ATAPI, audio @@ -21,18 +21,16 @@ - support for interrupt unmasking during I/O (better than hd.c) - improved handshaking and error detection/recovery - can co-exist with hd.c to control only the secondary interface -NEW! - support for reliable operation of buggy CMD-640 interfaces + - support for reliable operation of buggy CMD-640 interfaces - use kernel command line option: hda=serialize -NEW! - experimental support for DTC-2278D interfaces + - experimental support for DTC-2278D interfaces - use kernel command line option: hda=dtc2278 -NEW! - run-time selectable 32bit interface support (using hdparm-2.3) + - run-time selectable 32bit interface support (using hdparm-2.3) -Under construction: +NEW! - support for DiskManager 6.0x "Dynamic Disk Overlay" (experimental) +NEW! - support for drives with a stuck WRERR_STAT bit +NEW! - support for removeable devices - - improved CMD support: tech info is supposedly "in the mail" - - support for interface speed selection on jumperless interfaces - - improved detection of non-standard IDE ATAPI cdrom drives - - support for non-standard 3rd/4th drive interface on Promise cards *** @@ -266,13 +264,10 @@ problems with some software". Ignore them for linux partitions. The "some software" refers to DOS, the BIOS, and LILO, as described previously. -Western Digital now ships a "DiskManager 6.03" diskette with all of their big -hard drives. Burn it! That idiotic piece of garbage isn't even universally -compatible with DOS, let alone other operating systems like Linux. Eventually -some kind person will kludge Linux to work with it, but at present the two -are completely incompatible. If you have this version of DiskManager on your -hard disk already, it can be exterminated at the expense of all data on the -drive (back it up elsewhere), by using the "DM" command from the diskette -as follows: DM /Y- +Western Digital ships a "DiskManager 6.03" diskette with all of their big +hard drives. Use BIOS translation instead of this if possible, as it is a +more generally compatible method of achieving the same results (DOS access +to the entire disk). However, if you must use DiskManager, it should now +work with Linux 1.3.x in most cases. Let me know if you still have trouble. mlord@bnr.ca diff -u --recursive --new-file v1.3.8/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c --- v1.3.8/linux/drivers/block/aztcd.c Tue Jun 27 14:11:33 1995 +++ linux/drivers/block/aztcd.c Mon Jul 10 08:00:56 1995 @@ -1,5 +1,5 @@ -#define AZT_VERSION "V1.0" -/* $Id: aztcd.c,v 1.0 1995/03/25 08:27:11 root Exp $ +#define AZT_VERSION "1.30" +/* $Id: aztcd.c,v 1.30 1995/07/04 08:28:06 root Exp $ linux/drivers/block/aztcd.c - AztechCD268 CDROM driver Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de) @@ -104,6 +104,18 @@ Added support for loadable MODULEs, so aztcd can now also be loaded by insmod and removed by rmmod during run time Werner Zimmermann, Mar. 24, 95 + V1.10 Implemented soundcard configuration for Orchid CDS-3110 drives + connected to Soundwave32 cards. Release for LST 2.1. + (still experimental) + Werner Zimmermann, May 8, 95 + V1.20 Implemented limited support for DOSEMU0.60's cdrom.c. Now it works, but + sometimes DOSEMU may hang for 30 seconds or so. A fully functional ver- + sion needs an update of Dosemu0.60's cdrom.c, which will come with the + next revision of Dosemu. + Also Soundwave32 support no works. + Werner Zimmermann, May 22, 95 + V1.30 Auto-eject feature. Inspired by Franc Racis (racis@psu.edu) + Werner Zimmermann, July 4, 95 NOTE: Points marked with ??? are questionable ! */ @@ -135,16 +147,30 @@ #define MAJOR_NR AZTECH_CDROM_MAJOR #include "blk.h" -#ifndef MODULE + +#ifdef MODULE +#else # define MOD_INC_USE_COUNT # define MOD_DEC_USE_COUNT #endif #include +#define SET_TIMER(func, jifs) delay_timer.expires = jifs; \ + delay_timer.function = (void *) func; \ + add_timer(&delay_timer); + +#define CLEAR_TIMER del_timer(&delay_timer); + +#define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\ + return value;} +#define RETURN(message) {printk("aztcd: Warning: %s failed\n",message);\ + return;} + static int aztPresent = 0; #if 0 +#define AZT_TEST #define AZT_TEST1 /* */ #define AZT_TEST2 /* do_aztcd_request */ #define AZT_TEST3 /* AZT_S_state */ @@ -197,6 +223,7 @@ static char azt_cont = 0; static char azt_init_end = 0; +static char azt_auto_eject = AZT_AUTO_EJECT; static int AztTimeout, AztTries; static struct wait_queue *azt_waitq = NULL; @@ -210,7 +237,6 @@ static char aztDiskChanged = 1; static char aztTocUpToDate = 0; - static void azt_transfer(void); static void azt_poll(void); static void azt_invalidate_buffers(void); @@ -234,6 +260,7 @@ static unsigned char aztIndatum; static unsigned long aztTimeOutCount; +static int aztCmd = 0; /* Macros for the drive hardware interface handshake, these macros use busy waiting */ @@ -270,7 +297,7 @@ do { aztIndatum=inb(STATUS_PORT); aztTimeOutCount++; if (aztTimeOutCount>=AZT_TIMEOUT) - { if (azt_init_end) printk("aztcd: Error Wait STEN_LOW\n"); + { if (azt_init_end) printk("aztcd: Error Wait STEN_LOW commands:%x\n",aztCmd); break; } } while (aztIndatum&AFL_STATUS); @@ -297,25 +324,25 @@ void statusAzt(void) { AztTimeout = AZT_STATUS_DELAY; SET_TIMER(aztStatTimer, 1); - sleep_on(&azt_waitq); - if (AztTimeout <= 0) printk("aztcd: Error Wait STEN_LOW_WAIT\n"); + sleep_on(&azt_waitq); + if (AztTimeout <= 0) printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",aztCmd); return; } static void aztStatTimer(void) -{ if (!(inb(STATUS_PORT) & AFL_STATUS)) - { wake_up(&azt_waitq); - return; - } - AztTimeout--; - if (AztTimeout <= 0) - { wake_up(&azt_waitq); - return; - } - SET_TIMER(aztStatTimer, 1); +{ if (!(inb(STATUS_PORT) & AFL_STATUS)) + { wake_up(&azt_waitq); + return; + } + AztTimeout--; + if (AztTimeout <= 0) + { wake_up(&azt_waitq); + printk("aztcd: Error aztStatTimer: Timeout\n"); + return; + } + SET_TIMER(aztStatTimer, 1); } - void aztcd_setup(char *str, int *ints) { if (ints[0] > 0) azt_port = ints[1]; @@ -363,6 +390,7 @@ #ifdef AZT_DEBUG printk("aztcd: Executing command %x\n",cmd); #endif + aztCmd=cmd; outb(POLLED,MODE_PORT); do { if (inb(STATUS_PORT)&AFL_STATUS) break; inb(DATA_PORT); /* if status left from last command, read and */ @@ -386,7 +414,7 @@ { printk("### Error 2 aztcd: aztSendCmd %x \n",cmd); azt_error=0xA5; } - return -1; + RETURNM("aztSendCmd",-1); } /* @@ -423,7 +451,7 @@ { printk("### Error 2 aztcd: sendAztCmd %x\n ",cmd); azt_error=0xA5; } - return -1; + RETURNM("sendAztCmd",-1); } @@ -440,16 +468,17 @@ */ static int aztStatus(void) { int st; - int i; +/* int i; - i = inb(STATUS_PORT) & AFL_STATUS; /* is STEN=0? ???*/ + i = inb(STATUS_PORT) & AFL_STATUS; is STEN=0? ??? if (!i) - { - st = inb(DATA_PORT) & 0xFF; +*/ STEN_LOW; + if (aztTimeOutCountmin >=70) printk("aztcd: Error msf2hsg address Minutes\n"); - if (mp->sec >=60) printk("aztcd: Error msf2hsg address Seconds\n"); - if (mp->frame>=75) printk("aztcd: Error msf2hsg address Frames\n"); -#endif - return azt_bcd2bin(mp -> frame) - + azt_bcd2bin(mp -> sec) * 75 - + azt_bcd2bin(mp -> min) * 4500 - - 150; +{ return azt_bcd2bin(mp -> frame) + azt_bcd2bin(mp -> sec) * 75 + + azt_bcd2bin(mp -> min) * 4500 - 150; } static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) @@ -517,12 +538,12 @@ struct cdrom_volctrl volctrl; #ifdef AZT_DEBUG - printk("aztcd: starting aztcd_ioctl - Command:%x\n",cmd); + printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n",cmd, jiffies); #endif - if (!ip) return -EINVAL; - if (getAztStatus()<0) return -EIO; + if (!ip) RETURNM("aztcd_ioctl 1",-EINVAL); + if (getAztStatus()<0) RETURNM("aztcd_ioctl 2", -EIO); if (!aztTocUpToDate) - { if ((i=aztUpdateToc())<0) return i; /* error reading TOC */ + { if ((i=aztUpdateToc())<0) RETURNM("aztcd_ioctl 3", i); /* error reading TOC */ } switch (cmd) @@ -530,12 +551,12 @@ case CDROMSTART: /* Spin up the drive. Don't know, what to do, at least close the tray */ #ifdef AZT_PRIVATE_IOCTLS - if (aztSendCmd(ACMD_CLOSE)) return -1; + if (aztSendCmd(ACMD_CLOSE)) RETURNM("aztcd_ioctl 4",-1); STEN_LOW_WAIT; #endif break; case CDROMSTOP: /* Spin down the drive */ - if (aztSendCmd(ACMD_STOP)) return -1; + if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 5",-1); STEN_LOW_WAIT; /* should we do anything if it fails? */ aztAudioStatus = CDROM_AUDIO_NO_STATUS; @@ -546,10 +567,11 @@ if (aztGetQChannelInfo(&qInfo) < 0) { /* didn't get q channel info */ aztAudioStatus = CDROM_AUDIO_NO_STATUS; - return 0; + RETURNM("aztcd_ioctl 7",0); } azt_Play.start = qInfo.diskTime; /* remember restart point */ - if (aztSendCmd(ACMD_PAUSE)) return -1; + + if (aztSendCmd(ACMD_PAUSE)) RETURNM("aztcd_ioctl 8",-1); STEN_LOW_WAIT; aztAudioStatus = CDROM_AUDIO_PAUSED; break; @@ -590,7 +612,7 @@ break; case CDROMPLAYMSF: /* Play starting at the given MSF address. */ /* if (aztAudioStatus == CDROM_AUDIO_PLAY) - { if (aztSendCmd(ACMD_STOP)) return -1; + { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1); STEN_LOW; aztAudioStatus = CDROM_AUDIO_NO_STATUS; } @@ -661,13 +683,28 @@ memcpy_tofs((void *) arg, &entry, sizeof entry); break; case CDROMSUBCHNL: /* Get subchannel info */ - st = verify_area(VERIFY_READ, (void *) arg, sizeof subchnl); - if (st) return st; - st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl); - if (st) return st; - memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl); + st = verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl)); + if (st) { +#ifdef AZT_DEBUG + printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd); +#endif + return st; + } + st = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl)); + if (st) { +#ifdef AZT_DEBUG + printk("aztcd: exiting aztcd_ioctl - Error 2 - Command:%x\n",cmd); +#endif + return st; + } + memcpy_fromfs(&subchnl, (void *) arg, sizeof (struct cdrom_subchnl)); if (aztGetQChannelInfo(&qInfo) < 0) - return -EIO; + if (st) { +#ifdef AZT_DEBUG + printk("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",cmd); +#endif + return -EIO; + } subchnl.cdsc_audiostatus = aztAudioStatus; subchnl.cdsc_adr = qInfo.ctrl_addr; subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4; @@ -677,17 +714,16 @@ { subchnl.cdsc_absaddr.lba = azt_msf2hsg(&qInfo.diskTime); subchnl.cdsc_reladdr.lba = azt_msf2hsg(&qInfo.trackTime); } - else if (subchnl.cdsc_format == CDROM_MSF) - { subchnl.cdsc_absaddr.msf.minute = azt_bcd2bin(qInfo.diskTime.min); + else /*default*/ + { subchnl.cdsc_format = CDROM_MSF; + subchnl.cdsc_absaddr.msf.minute = azt_bcd2bin(qInfo.diskTime.min); subchnl.cdsc_absaddr.msf.second = azt_bcd2bin(qInfo.diskTime.sec); - subchnl.cdsc_absaddr.msf.frame = azt_bcd2bin(qInfo.diskTime.frame); + subchnl.cdsc_absaddr.msf.frame = azt_bcd2bin(qInfo.diskTime.frame); subchnl.cdsc_reladdr.msf.minute = azt_bcd2bin(qInfo.trackTime.min); subchnl.cdsc_reladdr.msf.second = azt_bcd2bin(qInfo.trackTime.sec); subchnl.cdsc_reladdr.msf.frame = azt_bcd2bin(qInfo.trackTime.frame); } - else - return -EINVAL; - memcpy_tofs((void *) arg, &subchnl, sizeof subchnl); + memcpy_tofs((void *) arg, &subchnl, sizeof (struct cdrom_subchnl)); break; case CDROMVOLCTRL: /* Volume control * With my Aztech CD268-01A volume control does not work, I can only @@ -709,12 +745,16 @@ aztUnlockDoor(); /* Assume user knows what they're doing */ /* all drives can at least stop! */ if (aztAudioStatus == CDROM_AUDIO_PLAY) - { if (aztSendCmd(ACMD_STOP)) return -1; + { if (aztSendCmd(ACMD_STOP)) RETURNM("azt_ioctl 10",-1); STEN_LOW_WAIT; } - if (aztSendCmd(ACMD_EJECT)) return -1; + if (aztSendCmd(ACMD_EJECT)) RETURNM("azt_ioctl 11",-1); + STEN_LOW_WAIT; /*???*/ aztAudioStatus = CDROM_AUDIO_NO_STATUS; break; + case CDROMEJECT_SW: + azt_auto_eject = (char) arg; + break; case CDROMREADMODE1: /*read data in mode 1 (2048 Bytes)*/ case CDROMREADMODE2: /*read data in mode 2 (2336 Bytes)*/ /*Take care, the following code is not compatible with other CD-ROM drivers, @@ -759,7 +799,7 @@ return -EINVAL; } #ifdef AZT_DEBUG - printk("aztcd: exiting aztcd_ioctl\n"); + printk("aztcd: exiting aztcd_ioctl Command:%x Time:%li\n",cmd,jiffies); #endif return 0; } @@ -772,7 +812,7 @@ static void azt_transfer(void) { #ifdef AZT_TEST - printk("aztcd: executing azt_transfer\n"); + printk("aztcd: executing azt_transfer Time:%li\n",jiffies); #endif if (CURRENT_VALID) { while (CURRENT -> nr_sectors) { @@ -808,7 +848,7 @@ static void do_aztcd_request(void) { #ifdef AZT_TEST - printk(" do_aztcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors); + printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies); #endif azt_transfer_is_active = 1; while (CURRENT_VALID) { @@ -840,7 +880,7 @@ #ifdef AZT_TEST2 printk("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", \ azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]); - printk(" do_aztcd_request ends\n"); + printk(" do_aztcd_request ends Time:%li\n",jiffies); #endif } @@ -852,7 +892,7 @@ int skip = 0; if (azt_error) { /* ???*/ - if (aztSendCmd(ACMD_GET_ERROR)) return; + if (aztSendCmd(ACMD_GET_ERROR)) RETURN("azt_poll 1"); STEN_LOW; azt_error=inb(DATA_PORT)&0xFF; printk("aztcd: I/O error 0x%02x\n", azt_error); @@ -897,8 +937,7 @@ printk("AZT_S_START\n"); } #endif - - if(aztSendCmd(ACMD_GET_STATUS)) return; /*result will be checked by aztStatus() */ + if(aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 2"); /*result will be checked by aztStatus() */ azt_state = azt_mode == 1 ? AZT_S_READ : AZT_S_MODE; AztTimeout = 3000; break; @@ -936,11 +975,12 @@ return; } /*???*/ - if (aztSendCmd(ACMD_SET_MODE)) return; - outb(0x01, DATA_PORT); /*Mode 1*/ +/* if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3"); + outb(0x01, DATA_PORT); PA_OK; STEN_LOW; - if (aztSendCmd(ACMD_GET_STATUS)) return; +*/ if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 4"); + STEN_LOW; /*???*/ azt_mode = 1; azt_state = AZT_S_READ; AztTimeout = 3000; @@ -1148,7 +1188,7 @@ } azt_read_count--; } - if (aztSendCmd(ACMD_GET_STATUS)) return; + if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 5"); azt_state = AZT_S_STOPPING; AztTimeout = 1000; break; @@ -1209,8 +1249,8 @@ if (!AztTimeout--) { printk("aztcd: timeout in state %d\n", azt_state); azt_state = AZT_S_STOP; - if (aztSendCmd(ACMD_STOP)) return; - STEN_LOW_WAIT; + if (aztSendCmd(ACMD_STOP)) RETURN("azt_poll 6"); + STEN_LOW_WAIT; }; SET_TIMER(azt_poll, 1); @@ -1289,6 +1329,8 @@ sync_dev(inode->i_rdev); /*??? isn't it a read only dev?*/ invalidate_buffers(inode -> i_rdev); aztUnlockDoor(); + if (azt_auto_eject) + aztSendCmd(ACMD_EJECT); CLEAR_TIMER; } return; @@ -1345,7 +1387,25 @@ #endif } - /* check for card */ +#ifdef AZT_SW32 /*CDROM connected to Soundwave32 card*/ + if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500) + { printk("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n", + AZT_SW32_BASE_ADDR,AZT_SW32_INIT,AZT_SW32_CONFIG_REG,AZT_SW32_ID_REG); +#ifndef MODULE + return (mem_start); +#else + return -EIO; +#endif + } + else + { printk("aztcd: Soundwave32 card detected at %x Version %x\n", + AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG)); + outw(AZT_SW32_INIT,AZT_SW32_CONFIG_REG); + for (count=0;count<10000;count++); /*delay a bit*/ + } +#endif + + /* check for presence of drive */ outb(POLLED,MODE_PORT); /*???*/ inb(CMD_PORT); inb(CMD_PORT); @@ -1515,13 +1575,12 @@ int st; #ifdef AZT_DEBUG - printk("aztcd: starting aztGetQChannelInfo\n"); + printk("aztcd: starting aztGetQChannelInfo Time:%li\n",jiffies); #endif - if ((st=getAztStatus())==-1) return -1; - if (aztSendCmd(ACMD_GET_Q_CHANNEL)) return -1; - STEN_LOW_WAIT; - if (aztGetValue(¬Used) <0) return -1; /*Nullbyte ein-*/ - /*lesen ???*/ + if ((st=getAztStatus())==-1) RETURNM("aztGetQChannelInfo 1",-1); + if (aztSendCmd(ACMD_GET_Q_CHANNEL)) RETURNM("aztGetQChannelInfo 2",-1); + /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here*/ + if (aztGetValue(¬Used)) RETURNM("aztGetQChannelInfo 3",-1); /*??? Nullbyte einlesen*/ if ((st&AST_MODE_BITS)==AST_INITIAL) { qp->ctrl_addr=0; /* when audio stop ACMD_GET_Q_CHANNEL returns */ qp->track=0; /* only one byte with Aztech drives */ @@ -1535,19 +1594,19 @@ return 0; } else - { if (aztGetValue(&qp -> ctrl_addr) < 0) return -1; - if (aztGetValue(&qp -> track) < 0) return -1; - if (aztGetValue(&qp -> pointIndex) < 0) return -1; - if (aztGetValue(&qp -> trackTime.min) < 0) return -1; - if (aztGetValue(&qp -> trackTime.sec) < 0) return -1; - if (aztGetValue(&qp -> trackTime.frame) < 0) return -1; - if (aztGetValue(¬Used) < 0) return -1; - if (aztGetValue(&qp -> diskTime.min) < 0) return -1; - if (aztGetValue(&qp -> diskTime.sec) < 0) return -1; - if (aztGetValue(&qp -> diskTime.frame) < 0) return -1; + { if (aztGetValue(&qp -> ctrl_addr) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(&qp -> track) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(&qp -> pointIndex) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(&qp -> trackTime.min) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(&qp -> trackTime.sec) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(&qp -> trackTime.frame) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(¬Used) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(&qp -> diskTime.min) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(&qp -> diskTime.sec) < 0) RETURNM("aztGetQChannelInfo 4",-1); + if (aztGetValue(&qp -> diskTime.frame) < 0) RETURNM("aztGetQChannelInfo 4",-1); } #ifdef AZT_DEBUG - printk("aztcd: exiting aztGetQChannelInfo\n"); + printk("aztcd: exiting aztGetQChannelInfo Time:%li\n",jiffies); #endif return 0; } @@ -1558,7 +1617,7 @@ static int aztUpdateToc() { #ifdef AZT_DEBUG - printk("aztcd: starting aztUpdateToc\n"); + printk("aztcd: starting aztUpdateToc Time:%li\n",jiffies); #endif if (aztTocUpToDate) return 0; @@ -1571,7 +1630,7 @@ aztTocUpToDate = 1; #ifdef AZT_DEBUG - printk("aztcd: exiting aztUpdateToc\n"); + printk("aztcd: exiting aztUpdateToc Time:%li\n",jiffies); #endif return 0; } @@ -1586,13 +1645,13 @@ struct azt_Toc qInfo; #ifdef AZT_DEBUG - printk("aztcd: starting aztGetDiskInfo\n"); + printk("aztcd: starting aztGetDiskInfo Time:%li\n",jiffies); #endif - if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) return -1; + if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetDiskInfo 1",-1); STEN_LOW_WAIT; test=0; for (limit=300;limit>0;limit--) - { if (aztGetQChannelInfo(&qInfo)<0) return -1; + { if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetDiskInfo 2",-1); if (qInfo.pointIndex==0xA0) /*Number of FirstTrack*/ { DiskInfo.first=qInfo.diskTime.min; DiskInfo.first = azt_bcd2bin(DiskInfo.first); @@ -1618,7 +1677,7 @@ if (test==0x0F) break; } #ifdef AZT_DEBUG -printk ("aztcd: exiting aztGetDiskInfo\n"); +printk ("aztcd: exiting aztGetDiskInfo Time:%li\n",jiffies); printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n", DiskInfo.first, DiskInfo.last, @@ -1643,7 +1702,7 @@ struct azt_Toc qInfo; #ifdef AZT_DEBUG - printk("aztcd: starting aztGetToc\n"); + printk("aztcd: starting aztGetToc Time:%li\n",jiffies); #endif for (i = 0; i < MAX_TRACKS; i++) Toc[i].pointIndex = 0; @@ -1651,12 +1710,12 @@ i = DiskInfo.last + 3; /* Is there a good reason to stop motor before TOC read? - if (aztSendCmd(ACMD_STOP)) return -1; + if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1); STEN_LOW_WAIT; */ azt_mode = 0x05; - if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) return -1; /*???*/ + if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetToc 2",-1); /*???*/ STEN_LOW_WAIT; for (limit = 300; limit > 0; limit--) @@ -1679,7 +1738,7 @@ Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; #ifdef AZT_DEBUG -printk("aztcd: exiting aztGetToc\n"); +printk("aztcd: exiting aztGetToc Time:%li\n",jiffies); for (i = 1; i <= DiskInfo.last+1; i++) printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n", i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, diff -u --recursive --new-file v1.3.8/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v1.3.8/linux/drivers/block/floppy.c Tue Jun 27 14:11:33 1995 +++ linux/drivers/block/floppy.c Mon Jul 10 07:17:43 1995 @@ -81,7 +81,7 @@ * errors to allow safe writing by specialized programs. */ -/* 1994/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks +/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks * by defining bit 1 of the "stretch" parameter to mean put sectors on the * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's * drives are "upside-down"). diff -u --recursive --new-file v1.3.8/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v1.3.8/linux/drivers/block/genhd.c Fri Jul 7 08:54:44 1995 +++ linux/drivers/block/genhd.c Mon Jul 10 17:08:05 1995 @@ -10,6 +10,11 @@ * in the early extended-partition checks and added DM partitions */ +/* + * Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca) + * with hints from uwe@eas.iis.fhg.de (us3@irz.inf.tu-dresden.de). + */ + #include #include #include @@ -105,21 +110,62 @@ static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) { - int i, minor = current_minor; + int i, minor = current_minor, found_dm6 = 0; struct buffer_head *bh; struct partition *p; int mask = (1 << hd->minor_shift) - 1; + extern void ide_xlate_1024(dev_t); +read_mbr: if (!(bh = bread(dev,0,1024))) { printk("unable to read partition table\n"); return -1; } - if (*(unsigned short *) (bh->b_data+510) != 0xAA55) { + if (*(unsigned short *) (0x1fe + bh->b_data) != 0xAA55) { brelse(bh); return 0; } + p = (struct partition *) (0x1be + bh->b_data); + + /* + * Check for Disk Manager v6.0x "Dynamic Disk Overlay" (DDO) + */ + if (p->sys_ind == DM6_PARTITION && !found_dm6++) + { + printk(" [DM6:DDO]"); + /* + * Everything is offset by one track (p->end_sector sectors), + * and a translated geometry is used to reduce the number + * of apparent cylinders to 1024 or less. + * + * For complete compatibility with linux fdisk, we do: + * 1. tell the driver to offset *everything* by one track, + * 2. reduce the apparent disk capacity by one track, + * 3. adjust the geometry reported by HDIO_GETGEO (for fdisk), + * (does nothing if not an IDE drive, but that's okay). + * 4. invalidate our in-memory copy of block zero, + * 5. restart the partition table hunt from scratch. + */ + first_sector += p->end_sector; + hd->part[MINOR(dev)].start_sect += p->end_sector; + hd->part[MINOR(dev)].nr_sects -= p->end_sector; + ide_xlate_1024(dev); /* harmless if not an IDE drive */ + bh->b_dirt = 0; /* prevent re-use of this block */ + bh->b_uptodate = 0; + bh->b_req = 0; + brelse(bh); + goto read_mbr; + } + + /* + * Check for Disk Manager v6.0x DDO on a secondary drive (?) + */ + if (p->sys_ind == DM6_AUXPARTITION) { + printk(" [DM6]"); + ide_xlate_1024(dev); /* harmless if not an IDE drive */ + } + current_minor += 4; /* first "extra" minor (for extended partitions) */ - p = (struct partition *) (0x1BE + bh->b_data); for (i=1 ; i<=4 ; minor++,i++,p++) { if (!p->nr_sects) continue; @@ -133,10 +179,10 @@ } } /* - * check for Disk Manager partition table + * Check for old-style Disk Manager partition table */ if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { - p = (struct partition *) (0x1BE + bh->b_data); + p = (struct partition *) (0x1be + bh->b_data); for (i = 4 ; i < 16 ; i++, current_minor++) { p--; if ((current_minor & mask) >= mask-2) diff -u --recursive --new-file v1.3.8/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v1.3.8/linux/drivers/block/ide.c Tue Jun 27 14:11:33 1995 +++ linux/drivers/block/ide.c Mon Jul 10 17:08:05 1995 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 3.16 May 30, 1995 + * linux/drivers/block/ide.c Version 4.00 Jul 10, 1995 * * Copyright (C) 1994, 1995 Linus Torvalds & authors (see below) */ @@ -40,47 +40,10 @@ * inspiration from lots of linux users, esp. hamish@zot.apana.org.au * * Version 1.0 ALPHA initial code, primary i/f working okay - * Version 1.1 ALPHA fixes for dual i/f - * Version 1.2 ALPHA first serious attempt at sharing irqs * Version 1.3 BETA dual i/f on shared irq tested & working! * Version 1.4 BETA added auto probing for irq(s) * Version 1.5 BETA added ALPHA (untested) support for IDE cd-roms, - * fixed hd.c coexistence bug, other minor stuff - * Version 1.6 BETA fix link error when cd-rom not configured - * Version 2.0 BETA lots of minor fixes; remove annoying messages; ... - * Version 2.2 BETA fixed reset_drives; major overhaul of autoprobing - * Version 2.3 BETA set DEFAULT_UNMASK_INTR to 0 again; cosmetic changes - * Version 2.4 BETA added debounce on reading of drive status reg, - * added config flags to remove unwanted features - * Version 2.5 BETA fixed problem with leftover phantom IRQ after probe, - * allow "set_geometry" even when in LBA (as per spec(?)), - * assorted miscellaneous tweaks. - * Version 2.6 BETA more config flag stuff, another probing tweak, - * (not released) multmode now defaults to status quo from boot time, - * moved >16heads check to init time, rearranged reset code - * added HDIO_DRIVE_CMD, removed standby/xfermode stuff - * hopefully fixed ATAPI probing code, added hdx=cdrom - * Version 2.7 BETA fixed invocation of cdrom_setup() - * Version 2.8 BETA fixed compile error for DISK_RECOVERY_TIME>0 - * fixed incorrect drive selection in DO_DRIVE_CMD (Bug!) - * Version 2.9 BETA more work on ATAPI CDROM recognition - * (not released) changed init order so partition checks go in sequence - * Version 3.0 BETA included ide-cd.c update from Steve with Mitsumi fixes - * attempt to fix byte-swap problem with Mitsumi id_info - * ensure drives on second i/f get initialized on boot - * preliminary compile-time support for 32bit IDE i/f chips - * added check_region() and snarf_region() to probes - * Version 3.1 BETA ensure drives on *both* i/f get initialized on boot - * fix byte-swap problem with Mitsumi id_info - * changed ide_timermask into ide_timerbit - * get rid of unexpected interrupts after probing - * don't wait for READY_STAT on cdrom drives - * Version 3.2 BETA Ooops.. mistakenly left VLB_32BIT_IDE on by default - * new ide-cd.c from Scott - * Version 3.3 BETA fix compiling with PROBE_FOR_IRQS==0 - * (sent to Linus) tweak in do_probe() to fix Delman's DRDY problem - * Version 3.4 BETA removed "444" debug message - * (sent to Linus) + * ... * Version 3.5 correct the bios_cyl field if it's too small * (linux 1.1.76) (to help fdisk with brain-dead BIOSs) * Version 3.6 cosmetic corrections to comments and stuff @@ -120,12 +83,23 @@ * add boot flag to enable "dtc2278" probe * add probe to avoid EATA (SCSI) interfaces, * courtesy of neuffer@goofy.zdv.uni-mainz.de. + * Version 4.00 tidy up verify_area() calls - heiko@colossus.escape.de + * add flag to ignore WRERR_STAT for some drives + * courtesy of David.H.West@um.cc.umich.edu + * assembly syntax tweak to VLB_SYNC + * removeable drive support from scuba@cs.tu-berlin.de + * add transparent support for DiskManager-6.0x "Dynamic + * Disk Overlay" (DDO), most of this in in genhd.c + * eliminate "multiple mode turned off" message at boot * * To do: - * - improved CMD support: tech info is supposedly "in the mail" + * - add support for alternative IDE port addresses + * - refine the DiskManager-6.0x overlay support (special cases) + * - improved CMD support: tech info is in my hands for 640B chip * - special 32-bit controller-type detection & support * - figure out how to support oddball "intelligent" caching cards * - reverse-engineer 3/4 drive support on fancy "Promise" cards + * - find someone to work on IDE *tape drive* support */ #include @@ -262,7 +236,7 @@ #if SUPPORT_VLB_32BIT #if SUPPORT_VLB_SYNC -#define VLB_SYNC __asm__ __volatile__ ("pusha\n movl $0x01f2,%edx\n inb (%dx),%al\n inb (%dx),%al\n inb (%dx),%al\n popa\n") +#define VLB_SYNC __asm__ __volatile__ ("pusha\n movl $0x01f2,%edx\n inb %dx,%al\n inb %dx,%al\n inb %dx,%al\n popa\n") #endif /* SUPPORT_VLB_SYNC */ #endif /* SUPPORT_VLB_32BIT */ @@ -274,7 +248,7 @@ #define GET_STAT(hwif) IN_BYTE(HD_STATUS,hwif) #define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good)) #define BAD_R_STAT (BUSY_STAT | ERR_STAT) -#define BAD_W_STAT (BUSY_STAT | ERR_STAT | WRERR_STAT) +#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT) #define BAD_STAT (BAD_R_STAT | DRQ_STAT) #define DRIVE_READY (READY_STAT | SEEK_STAT) #define DATA_READY (DRIVE_READY | DRQ_STAT) @@ -333,15 +307,15 @@ byte unmask; /* pretty quick access to this also */ dev_type type : 1; /* disk or cdrom (or tape, floppy..) */ unsigned present : 1; /* drive is physically present */ - unsigned dont_probe : 1; /* from: hdx=noprobe */ + unsigned noprobe : 1; /* from: hdx=noprobe */ unsigned keep_settings : 1; /* restore settings after drive reset */ unsigned busy : 1; /* mutex for ide_open, revalidate_.. */ unsigned vlb_32bit : 1; /* use 32bit in/out for data */ unsigned vlb_sync : 1; /* needed for some 32bit chip sets */ - unsigned reserved0 : 1; /* unused */ + unsigned be_quiet : 1; /* supress "multiple mode" msg at boot */ special_t special; /* special action flags */ select_t select; /* basic drive/head select reg value */ - byte mult_count, chipset, reserved2; + byte mult_count, chipset, bad_wstat; byte usage, mult_req, wpcom, ctl; byte head, sect, bios_head, bios_sect; unsigned short cyl, bios_cyl; @@ -782,7 +756,7 @@ int i; struct request *rq = ide_cur_rq[DEV_HWIF]; - if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,BAD_W_STAT)) { + if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,dev->bad_wstat)) { #ifdef DEBUG printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n", dev->name, rq->sector, (unsigned long) rq->buffer, @@ -849,7 +823,7 @@ int i; struct request *rq = &ide_write_rq[DEV_HWIF]; - if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,BAD_W_STAT)) { + if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,dev->bad_wstat)) { if (stat & DRQ_STAT) { if (rq->nr_sectors) { if (dev->mult_count) @@ -896,13 +870,14 @@ dev->mult_req = dev->mult_count = 0; dev->special.b.recalibrate = 1; (void) dump_status(DEV_HWIF, "set_multmode", stat); - } else { + } else if (!dev->be_quiet) { if ((dev->mult_count = dev->mult_req)) printk (" %s: enabled %d-sector multiple mode\n", dev->name, dev->mult_count); else printk (" %s: multiple mode turned off\n", dev->name); } + dev->be_quiet = 0; DO_REQUEST; } @@ -1078,7 +1053,7 @@ if (rq->cmd == WRITE) { OUT_BYTE(dev->wpcom,HD_PRECOMP); /* for ancient drives */ OUT_BYTE(dev->mult_count ? WIN_MULTWRITE : WIN_WRITE, HD_COMMAND); - WAIT_STAT(dev, DATA_READY, BAD_W_STAT, WAIT_DRQ, "DRQ", error); + WAIT_STAT(dev,DATA_READY,dev->bad_wstat,WAIT_DRQ,"DRQ",error); if (!dev->unmask) cli(); if (dev->mult_count) { @@ -1383,6 +1358,8 @@ sleep_on(&dev->wqueue); dev->usage++; restore_flags(flags); + if (dev->id->config & (1<<7)) /* for removeable disks */ + check_disk_change(inode->i_rdev); #ifdef CONFIG_BLK_DEV_IDECD if (dev->type == cdrom) return cdrom_open (inode, filp, dev); @@ -1416,7 +1393,7 @@ * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */ -static int revalidate_disk(int i_rdev) +static int revalidate_disk(dev_t i_rdev) { unsigned int i, major, start, drive = DEVICE_NR(i_rdev); ide_dev_t *dev; @@ -1584,29 +1561,34 @@ memcpy_tofs((char *)arg, (char *)dev->id, sizeof(*dev->id)); return 0; + case HDIO_GET_NOWERR: + return write_fs_long(arg, dev->bad_wstat == BAD_R_STAT); + case HDIO_SET_KEEPSETTINGS: case HDIO_SET_UNMASKINTR: - if (!suser()) return -EACCES; - if ((arg > 1) || (MINOR(inode->i_rdev) & PARTN_MASK)) - return -EINVAL; - save_flags(flags); - cli(); - if (cmd == HDIO_SET_KEEPSETTINGS) - dev->keep_settings = arg; - else - dev->unmask = arg; - restore_flags(flags); - return 0; - + case HDIO_SET_NOWERR: case HDIO_SET_CHIPSET: if (!suser()) return -EACCES; - if ((arg > 3) || (MINOR(inode->i_rdev) & PARTN_MASK)) + if ((arg > 1) || (MINOR(inode->i_rdev) & PARTN_MASK)) return -EINVAL; save_flags(flags); cli(); - dev->chipset = arg; - dev->vlb_sync = (arg & 2) >> 1; - dev->vlb_32bit = (arg & 1); + switch (cmd) { + case HDIO_SET_KEEPSETTINGS: + dev->keep_settings = arg; + break; + case HDIO_SET_UNMASKINTR: + dev->unmask = arg; + break; + case HDIO_SET_NOWERR: + dev->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; + break; + case HDIO_SET_CHIPSET: + dev->chipset = arg; + dev->vlb_sync = (arg & 2) >> 1; + dev->vlb_32bit = (arg & 1); + break; + } restore_flags(flags); return 0; @@ -1625,14 +1607,12 @@ dev->mult_req = arg; dev->special.b.set_multmode = 1; restore_flags(flags); -#ifdef IDE_DRIVE_CMD +#ifndef IDE_DRIVE_CMD + return 0; +#else do_drive_cmd (inode->i_rdev, NULL); return (dev->mult_count == arg) ? 0 : -EIO; -#else - return 0; -#endif /* IDE_DRIVE_CMD */ -#ifdef IDE_DRIVE_CMD case HDIO_DRIVE_CMD: { unsigned long args; @@ -1640,11 +1620,13 @@ if (NULL == (long *) arg) err = do_drive_cmd(inode->i_rdev,NULL); else { - if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) + if (!(err = verify_area(VERIFY_READ,(long *)arg,sizeof(long)))) { args = get_user((long *)arg); - err = do_drive_cmd(inode->i_rdev,(char *)&args); - put_user(args,(long *)arg); + if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) { + err = do_drive_cmd(inode->i_rdev,(char *)&args); + put_user(args,(long *)arg); + } } } return err; @@ -1662,18 +1644,20 @@ } } -#ifdef CONFIG_BLK_DEV_IDECD static int ide_check_media_change (dev_t full_dev) { ide_dev_t *dev; if ((dev = get_info_ptr(full_dev)) == NULL) return -ENODEV; - if (dev->type != cdrom) - return 0; - return cdrom_check_media_change (dev); -} +#ifdef CONFIG_BLK_DEV_IDECD + if (dev->type == cdrom) + return cdrom_check_media_change (dev); #endif /* CONFIG_BLK_DEV_IDECD */ + if (dev->id->config & (1<<7)) /* for removeable disks */ + return 1; /* always assume it was changed */ + return 0; +} static void fixstring (byte *s, int bytecount, int byteswap) @@ -1850,8 +1834,10 @@ dev->mult_req = INITIAL_MULT_COUNT; if (dev->mult_req > id->max_multsect) dev->mult_req = id->max_multsect; - if (dev->mult_req || ((id->multsect_valid & 1) && id->multsect)) + if (dev->mult_req || ((id->multsect_valid & 1) && id->multsect)) { dev->special.b.set_multmode = 1; + dev->be_quiet = 1; + } printk(", MaxMult=%d", id->max_multsect); } printk("\n"); @@ -1998,7 +1984,7 @@ * 1 device was found (note: dev->present might still be 0) */ { - if (dev->dont_probe) /* skip probing? */ + if (dev->noprobe) /* skip probing? */ return dev->present; if (do_probe(dev, WIN_IDENTIFY) >= 2) { /* if !(success || timed-out) */ #ifdef CONFIG_BLK_DEV_IDECD @@ -2106,7 +2092,7 @@ } #endif /* SUPPORT_DTC2278 */ #if SUPPORT_SERIALIZE - if (!strcmp(str,"serialize") || !strcmp(str,"cmd")) { + if (!strcmp(str,"serialize")) { printk("%s\n",str); single_threaded = 1; /* serialize all drive access */ return; @@ -2114,7 +2100,12 @@ #endif /* SUPPORT_SERIALIZE */ if (!strcmp(str,"noprobe")) { printk("%s\n",str); - dev->dont_probe = 1; /* don't probe for this drive */ + dev->noprobe = 1; /* don't probe for this drive */ + return; + } + if (!strcmp(str,"nowerr")) { + printk("%s\n",str); + dev->bad_wstat = BAD_R_STAT; /* ignore WRERR_STAT */ return; } #ifdef CONFIG_BLK_DEV_IDECD @@ -2168,6 +2159,22 @@ ide_setup (str, ints); } + +void ide_xlate_1024 (dev_t full_dev) +{ + ide_dev_t *dev; + + if ((dev = get_info_ptr(full_dev)) != NULL) { + dev->bios_cyl -= 1; /* keeps fdisk sane */ + while (dev->bios_cyl > 1024) { + if (dev->bios_head > 32) + return; + dev->bios_head *= 2; + dev->bios_cyl /= 2; + } + } +} + #ifndef CONFIG_BLK_DEV_HD /* * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc @@ -2238,6 +2245,8 @@ dev->keep_settings = 0; ide_hd[hwif][drive<name = ide_devname[hwif][drive]; + if (!dev->bad_wstat) + dev->bad_wstat = BAD_W_STAT; } } @@ -2319,11 +2328,9 @@ ide_open, /* open */ ide_release, /* release */ block_fsync /* fsync */ -#ifdef CONFIG_BLK_DEV_IDECD ,NULL, /* fasync */ ide_check_media_change, /* check_media_change */ - NULL /* revalidate */ -#endif CONFIG_BLK_DEV_IDECD + revalidate_disk /* revalidate */ }; diff -u --recursive --new-file v1.3.8/linux/drivers/block/mcdx.c linux/drivers/block/mcdx.c --- v1.3.8/linux/drivers/block/mcdx.c Fri Jul 7 08:54:45 1995 +++ linux/drivers/block/mcdx.c Mon Jul 10 17:08:04 1995 @@ -23,7 +23,7 @@ * Eberhard Moenkeberg (he gave me much support and the initial kick) * Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they * improved the original driver) - * John Tombs, Bjorn Ekwall (module support) + * Jon Tombs, Bjorn Ekwall (module support) * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) * Gerd Knorr (he lent me his PhotoCD) * Nils Faerber and Roger E. Wolff (extensivly tested the LU portion) diff -u --recursive --new-file v1.3.8/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v1.3.8/linux/drivers/char/Makefile Fri Jun 16 22:02:54 1995 +++ linux/drivers/char/Makefile Tue Jul 11 08:02:20 1995 @@ -9,8 +9,6 @@ # parent makes.. # -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -108,17 +106,10 @@ $(CPP) -M -DMODULE $(MODULES:.o=.c) >> .depend endif -dummy: - conmakehash: conmakehash.c $(HOSTCC) -o conmakehash conmakehash.c uni_hash_tbl.h: $(FONTMAPFILE) conmakehash ./conmakehash $(FONTMAPFILE) 641 283 6 > uni_hash_tbl.h -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.3.8/linux/drivers/net/Makefile Thu Jun 29 19:02:41 1995 +++ linux/drivers/net/Makefile Tue Jul 11 08:02:20 1995 @@ -24,6 +24,10 @@ net_init.o: ../../include/linux/autoconf.h +ifdef CONFIG_SEEQ8005 +NETDRV_OBJS := $(NETDRV_OBJS) seeq8005.o +endif + ifdef CONFIG_IBMTR NETDRV_OBJS := $(NETDRV_OBJS) ibmtr.o endif @@ -304,8 +308,4 @@ endif -# include a dependency file if one exists - -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.3.8/linux/drivers/net/Space.c Thu Jun 29 19:02:41 1995 +++ linux/drivers/net/Space.c Mon Jul 10 17:08:04 1995 @@ -66,6 +66,7 @@ extern int ni52_probe(struct device *); extern int ni65_probe(struct device *); extern int SK_init(struct device *); +extern int seeq8005_probe(struct device *); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct device *); @@ -81,6 +82,9 @@ return 1; /* ENXIO */ if (1 +#if defined(CONFIG_SEEQ8005) + && seeq8005_probe(dev) +#endif #if defined(CONFIG_HP100) && hp100_probe(dev) #endif diff -u --recursive --new-file v1.3.8/linux/drivers/net/auto_irq.c linux/drivers/net/auto_irq.c --- v1.3.8/linux/drivers/net/auto_irq.c Mon Jan 16 07:17:36 1995 +++ linux/drivers/net/auto_irq.c Mon Jul 10 08:45:05 1995 @@ -41,14 +41,14 @@ struct device *irq2dev_map[16] = {0, 0, /* ... zeroed */}; -int irqs_busy = 0x2147; /* The set of fixed IRQs (keyboard, timer, etc) */ -int irqs_used = 0x0001; /* The set of fixed IRQs sometimes enabled. */ -int irqs_reserved = 0x0000; /* An advisory "reserved" table. */ -int irqs_shared = 0x0000; /* IRQ lines "shared" among conforming cards.*/ +unsigned long irqs_busy = 0x2147; /* The set of fixed IRQs (keyboard, timer, etc) */ +unsigned long irqs_used = 0x0001; /* The set of fixed IRQs sometimes enabled. */ +unsigned long irqs_reserved = 0x0000; /* An advisory "reserved" table. */ +unsigned long irqs_shared = 0x0000; /* IRQ lines "shared" among conforming cards.*/ -static volatile int irq_number; /* The latest irq number we actually found. */ -static volatile int irq_bitmap; /* The irqs we actually found. */ -static int irq_handled; /* The irq lines we have a handler on. */ +static volatile unsigned long irq_bitmap; /* The irqs we actually found. */ +static unsigned long irq_handled; /* The irq lines we have a handler on. */ +static volatile int irq_number; /* The latest irq number we actually found. */ static void autoirq_probe(int irq, struct pt_regs * regs) { diff -u --recursive --new-file v1.3.8/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v1.3.8/linux/drivers/net/lance.c Fri Jul 7 13:42:57 1995 +++ linux/drivers/net/lance.c Mon Jul 10 17:08:04 1995 @@ -188,12 +188,13 @@ }; struct lance_private { - char *name; - void *pad; - /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ + /* The Tx and Rx ring entries must be aligned on 8-byte boundaries. + This is accomplished by allocating 7 extra bytes for the struct + and adjusting the start of the struct to be 8-byte aligned. */ struct lance_rx_head rx_ring[RX_RING_SIZE]; struct lance_tx_head tx_ring[TX_RING_SIZE]; struct lance_init_block init_block; + char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; long rx_buffs; /* Address of Rx and Tx buffers. */ @@ -206,7 +207,6 @@ unsigned char chip_version; /* See lance_chip_type. */ char tx_full; char lock; - int pad0, pad1; /* Used for 8-byte alignment */ }; #define LANCE_MUST_PAD 0x00000001 @@ -249,6 +249,10 @@ /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ static unsigned char pci_irq_line = 0; +/* Non-zero if lance_probe1() needs to allocate low-memory bounce buffers. + Assume yes until we know the memory size. */ +static unsigned char lance_need_isa_bounce_buffers = 1; + static int lance_open(struct device *dev); static void lance_init_ring(struct device *dev); static int lance_start_xmit(struct sk_buff *skb, struct device *dev); @@ -272,6 +276,9 @@ { int *port; + if (mem_end <= 16*1024*1024) + lance_need_isa_bounce_buffers = 0; + #if defined(CONFIG_PCI) if (pcibios_present()) { int pci_index; @@ -342,7 +349,7 @@ This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com. */ if ( *((unsigned short *) 0x000f0102) == 0x5048) { - short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360}; + static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360}; int hp_port = ( *((unsigned char *) 0x000f00f1) & 1) ? 0x499 : 0x99; /* We can have boards other than the built-in! Verify this is on-board. */ if ((inb(hp_port) & 0xc0) == 0x80 @@ -384,8 +391,12 @@ } } - dev = init_etherdev(0, sizeof(struct lance_private) - + PKT_BUF_SZ*(RX_RING_SIZE + TX_RING_SIZE), + dev = init_etherdev(0, 7 + + ((sizeof(struct lance_private) + 7) & ~7) + + PKT_BUF_SZ*RX_RING_SIZE + + (lance_need_isa_bounce_buffers + ? PKT_BUF_SZ*TX_RING_SIZE + : 0), &mem_start); chipname = chip_table[lance_version].name; @@ -403,18 +414,10 @@ dev->priv = (void *)(((int)dev->priv + 7) & ~7); lp = (struct lance_private *)dev->priv; lp->name = chipname; - lp->rx_buffs = (long)dev->priv + sizeof(struct lance_private); + lp->rx_buffs = (long)lp + ((sizeof(struct lance_private) + 7) & ~7); lp->tx_bounce_buffs = (char (*)[PKT_BUF_SZ]) (lp->rx_buffs + PKT_BUF_SZ*RX_RING_SIZE); -#ifndef final_version - /* This should never happen. */ - if ((int)(lp->rx_ring) & 0x07) { - printk(" **ERROR** LANCE Rx and Tx rings not on even boundary.\n"); - return mem_start; - } -#endif - lp->chip_version = lance_version; lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */ @@ -438,15 +441,15 @@ dev->dma = 4; /* Native bus-master, no DMA channel needed. */ dev->irq = pci_irq_line; } else if (hp_builtin) { - char dma_tbl[4] = {3, 5, 6, 0}; - char irq_tbl[8] = {3, 4, 5, 9}; + static const char dma_tbl[4] = {3, 5, 6, 0}; + static const char irq_tbl[4] = {3, 4, 5, 9}; unsigned char port_val = inb(hp_builtin); dev->dma = dma_tbl[(port_val >> 4) & 3]; dev->irq = irq_tbl[(port_val >> 2) & 3]; printk(" HP Vectra IRQ %d DMA %d.\n", dev->irq, dev->dma); } else if (hpJ2405A) { - char dma_tbl[4] = {3, 5, 6, 7}; - char irq_tbl[8] = {3, 4, 5, 9, 10, 11, 12, 15}; + static const char dma_tbl[4] = {3, 5, 6, 7}; + static const char irq_tbl[8] = {3, 4, 5, 9, 10, 11, 12, 15}; short reset_val = inw(ioaddr+LANCE_RESET); dev->dma = dma_tbl[(reset_val >> 2) & 3]; dev->irq = irq_tbl[(reset_val >> 4) & 7]; @@ -503,10 +506,10 @@ } else printk(", assigned DMA %d.\n", dev->dma); } else { /* OK, we have to auto-DMA. */ - int dmas[] = { 5, 6, 7, 3 }, boguscnt; - for (i = 0; i < 4; i++) { + static const char dmas[] = { 5, 6, 7, 3 }; int dma = dmas[i]; + int boguscnt; /* Don't enable a permanently busy DMA channel, or the machine will hang. */ @@ -1000,7 +1003,8 @@ } skb->dev = dev; skb_reserve(skb,2); /* 16 byte align */ - eth_copy_and_sum(skb_put(skb,pkt_len), + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb, (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), pkt_len,0); skb->protocol=eth_type_trans(skb,dev); diff -u --recursive --new-file v1.3.8/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v1.3.8/linux/drivers/net/seeq8005.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/seeq8005.c Mon Jul 10 17:16:41 1995 @@ -0,0 +1,762 @@ +/* seeq8005.c: A network driver for linux. */ +/* + Based on skeleton.c, + Written 1993-94 by Donald Becker. + See the skeleton.c file for further copyright information. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + The author may be reached as hamish@zot.apana.org.au + + This file is a network device driver for the SEEQ 8005 chipset and + the Linux operating system. + +*/ + +static char *version = + "seeq8005.c:v1.00 8/07/95 Hamish Coleman (hamish@zot.apana.org.au)\n"; + +/* Always include 'config.h' first in case the user wants to turn on + or override something. */ +#include + +/* + Sources: + SEEQ 8005 databook + + Version history: + 1.00 Public release. cosmetic changes (no warnings now) + 0.68 Turning per- packet,interrupt debug messages off - testing for release. + 0.67 timing problems/bad buffer reads seem to be fixed now + 0.63 *!@$ protocol=eth_type_trans -- now packets flow + 0.56 Send working + 0.48 Receive working +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "seeq8005.h" +extern struct device *init_etherdev(struct device *dev, int sizeof_private, + unsigned long *mem_startp); + +/* First, a few definitions that the brave might change. */ +/* A zero-terminated list of I/O addresses to be probed. */ +static unsigned int seeq8005_portlist[] = + { 0x300, 0x320, 0x340, 0x360, 0}; + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 1 +#endif +static unsigned int net_debug = NET_DEBUG; + +/* Information that need to be kept for each board. */ +struct net_local { + struct enet_statistics stats; + unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */ + long open_time; /* Useless example local info. */ +}; + +/* The station (ethernet) address prefix, used for IDing the board. */ +#define SA_ADDR0 0x00 +#define SA_ADDR1 0x80 +#define SA_ADDR2 0x4b + +/* Index to functions, as function prototypes. */ + +extern int seeq8005_probe(struct device *dev); + +static int seeq8005_probe1(struct device *dev, int ioaddr); +static int seeq8005_open(struct device *dev); +static int seeq8005_send_packet(struct sk_buff *skb, struct device *dev); +static void seeq8005_interrupt(int irq, struct pt_regs *regs); +static void seeq8005_rx(struct device *dev); +static int seeq8005_close(struct device *dev); +static struct enet_statistics *seeq8005_get_stats(struct device *dev); +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); + +/* Example routines you must write ;->. */ +#define tx_done(dev) (inw(SEEQ_STATUS) & SEEQSTAT_TX_ON) +extern void hardware_send_packet(struct device *dev, char *buf, int length); +extern void seeq8005_init(struct device *dev, int startp); +inline void wait_for_buffer(struct device *dev); + + +/* Check for a network adaptor of this type, and return '0' iff one exists. + If dev->base_addr == 0, probe all likely locations. + If dev->base_addr == 1, always return failure. + If dev->base_addr == 2, allocate space for the device and return success + (detachable devices only). + */ +#ifdef HAVE_DEVLIST +/* Support for a alternate probe manager, which will eliminate the + boilerplate below. */ +struct netdev_entry seeq8005_drv = +{"seeq8005", seeq8005_probe1, SEEQ8005_IO_EXTENT, seeq8005_portlist}; +#else +int +seeq8005_probe(struct device *dev) +{ + int i; + int base_addr = dev ? dev->base_addr : 0; + + if (base_addr > 0x1ff) /* Check a single specified location. */ + return seeq8005_probe1(dev, base_addr); + else if (base_addr != 0) /* Don't probe at all. */ + return ENXIO; + + for (i = 0; seeq8005_portlist[i]; i++) { + int ioaddr = seeq8005_portlist[i]; + if (check_region(ioaddr, SEEQ8005_IO_EXTENT)) + continue; + if (seeq8005_probe1(dev, ioaddr) == 0) + return 0; + } + + return ENODEV; +} +#endif + +/* This is the real probe routine. Linux has a history of friendly device + probes on the ISA bus. A good device probes avoids doing writes, and + verifies that the correct device exists and functions. */ + +static int seeq8005_probe1(struct device *dev, int ioaddr) +{ + static unsigned version_printed = 0; + int i,j; + unsigned char SA_prom[32]; + int old_cfg1; + int old_cfg2; + int old_stat; + int old_dmaar; + int old_rear; + + if (net_debug>1) + printk("seeq8005: probing at 0x%x\n",ioaddr); + + old_stat = inw(SEEQ_STATUS); /* read status register */ + if (old_stat == 0xffff) + return ENODEV; /* assume that 0xffff == no device */ + if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */ + if (net_debug>1) { + printk("seeq8005: reserved stat bits != 0x1800\n"); + printk(" == 0x%04x\n",old_stat); + } + return ENODEV; + } + + old_rear = inw(SEEQ_REA); + if (old_rear == 0xffff) { + outw(0,SEEQ_REA); + if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */ + return ENODEV; + } + } else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */ + if (net_debug>1) { + printk("seeq8005: unused rear bits != 0xff00\n"); + printk(" == 0x%04x\n",old_rear); + } + return ENODEV; + } + + old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */ + old_cfg1 = inw(SEEQ_CFG1); + old_dmaar = inw(SEEQ_DMAAR); + + if (net_debug>4) { + printk("seeq8005: stat = 0x%04x\n",old_stat); + printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1); + printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2); + printk("seeq8005: raer = 0x%04x\n",old_rear); + printk("seeq8005: dmaar= 0x%04x\n",old_dmaar); + } + + outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */ + outw( 0, SEEQ_DMAAR); /* set starting PROM address */ + outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */ + + + j=0; + for(i=0; i <32; i++) { + j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff; + } + +#if 0 + /* untested because I only have the one card */ + if ( (j&0xff) != 0 ) { /* checksum appears to be 8bit = 0 */ + if (net_debug>1) { /* check this before deciding that we have a card */ + printk("seeq8005: prom sum error\n"); + } + outw( old_stat, SEEQ_STATUS); + outw( old_dmaar, SEEQ_DMAAR); + outw( old_cfg1, SEEQ_CFG1); + return ENODEV; + } +#endif + + outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */ + SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */ + SLOW_DOWN_IO; + SLOW_DOWN_IO; + SLOW_DOWN_IO; + outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD); + + if (net_debug) { + printk("seeq8005: prom sum = 0x%08x\n",j); + for(j=0; j<32; j+=16) { + printk("seeq8005: prom %02x: ",j); + for(i=0;i<16;i++) { + printk("%02x ",SA_prom[j|i]); + } + printk(" "); + for(i=0;i<16;i++) { + if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) { + printk("%c", SA_prom[j|i]); + } else { + printk(" "); + } + } + printk("\n"); + } + } + +#if 0 + /* + * testing the packet buffer memory doesnt work yet + * but all other buffer accesses do + * - fixing is not a priority + */ + if (net_debug>1) { /* test packet buffer memory */ + printk("seeq8005: testing packet buffer ... "); + outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1); + outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); + outw( 0 , SEEQ_DMAAR); + for(i=0;i<32768;i++) { + outw(0x5a5a, SEEQ_BUFFER); + } + j=jiffies+HZ; + while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && jiffies < j ) + mb(); + outw( 0 , SEEQ_DMAAR); + while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && jiffies < j+HZ) + mb(); + if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT) + outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD); + outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); + j=0; + for(i=0;i<32768;i++) { + if (inw(SEEQ_BUFFER) != 0x5a5a) + j++; + } + if (j) { + printk("%i\n",j); + } else { + printk("ok.\n"); + } + } +#endif + + /* Allocate a new 'dev' if needed. */ + if (dev == NULL) + dev = init_etherdev(0, sizeof(struct net_local), 0); + + if (net_debug && version_printed++ == 0) + printk(version); + + printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr); + + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; + + /* Retrieve and print the ethernet address. */ + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = SA_prom[i+6]); + + if (dev->irq == 0xff) + ; /* Do nothing: a user-level program will set it. */ + else if (dev->irq < 2) { /* "Auto-IRQ" */ + autoirq_setup(0); + + outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD ); + + dev->irq = autoirq_report(0); + + if (net_debug >= 2) + printk(" autoirq is %d\n", dev->irq); + } else if (dev->irq == 2) + /* Fixup for users that don't know that IRQ 2 is really IRQ 9, + * or don't know which one to set. + */ + dev->irq = 9; + +#if 0 + { + int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005"); + if (irqval) { + printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, + dev->irq, irqval); + return EAGAIN; + } + } +#endif + + /* Grab the region so we can find another board if autoIRQ fails. */ + request_region(ioaddr, SEEQ8005_IO_EXTENT,"seeq8005"); + + /* Initialize the device structure. */ + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct net_local)); + + dev->open = seeq8005_open; + dev->stop = seeq8005_close; + dev->hard_start_xmit = seeq8005_send_packet; + dev->get_stats = seeq8005_get_stats; + dev->set_multicast_list = &set_multicast_list; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + return 0; +} + + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine should set everything up anew at each open, even + registers that "should" only need to be set once at boot, so that + there is non-reboot way to recover if something goes wrong. + */ +static int +seeq8005_open(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + { + int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005"); + if (irqval) { + printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, + dev->irq, irqval); + return EAGAIN; + } + } + irq2dev_map[dev->irq] = dev; + + /* Reset the hardware here. Don't forget to set the station address. */ + seeq8005_init(dev, 1); + + lp->open_time = jiffies; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + return 0; +} + +static int +seeq8005_send_packet(struct sk_buff *skb, struct device *dev) +{ + int ioaddr = dev->base_addr; + + if (dev->tbusy) { + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk("%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ conflict" : "network cable problem"); + /* Try to restart the adaptor. */ + seeq8005_init(dev, 1); + dev->tbusy=0; + dev->trans_start = jiffies; + } + + /* If some higher layer thinks we've missed an tx-done interrupt + we are passed NULL. Caution: dev_tint() handles the cli()/sti() + itself. */ + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + + hardware_send_packet(dev, buf, length); + dev->trans_start = jiffies; + } + dev_kfree_skb (skb, FREE_WRITE); + + /* You might need to clean up and record Tx statistics here. */ + + return 0; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ +static void +seeq8005_interrupt(int irq, struct pt_regs * regs) +{ + struct device *dev = (struct device *)(irq2dev_map[irq]); + struct net_local *lp; + int ioaddr, status, boguscount = 0; + + if (dev == NULL) { + printk ("net_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + if (dev->interrupt) + printk ("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + ioaddr = dev->base_addr; + lp = (struct net_local *)dev->priv; + + status = inw(SEEQ_STATUS); + do { + if (net_debug >2) { + printk("%s: int, status=0x%04x\n",dev->name,status); + } + + if (status & SEEQSTAT_WINDOW_INT) { + outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); + if (net_debug) { + printk("%s: window int!\n",dev->name); + } + } + if (status & SEEQSTAT_TX_INT) { + outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); + lp->stats.tx_packets++; + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + if (status & SEEQSTAT_RX_INT) { + /* Got a packet(s). */ + seeq8005_rx(dev); + } + status = inw(SEEQ_STATUS); + } while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ; + + if(net_debug>2) { + printk("%s: eoi\n",dev->name); + } + dev->interrupt = 0; + return; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +seeq8005_rx(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int boguscount = 10; + int pkt_hdr; + int ioaddr = dev->base_addr; + + do { + int next_packet; + int pkt_len; + int i; + int status; + + status = inw(SEEQ_STATUS); + outw( lp->receive_ptr, SEEQ_DMAAR); + outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); + wait_for_buffer(dev); + next_packet = ntohs(inw(SEEQ_BUFFER)); + pkt_hdr = inw(SEEQ_BUFFER); + + if (net_debug>2) { + printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr); + } + + if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */ + return; /* Done for now */ + } + + if ((pkt_hdr & SEEQPKTS_DONE)==0) + break; + + if (next_packet < lp->receive_ptr) { + pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4; + } else { + pkt_len = next_packet - lp->receive_ptr - 4; + } + + if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */ + printk("%s: recv packet ring corrupt, resetting board\n",dev->name); + seeq8005_init(dev,1); + return; + } + + lp->receive_ptr = next_packet; + + if (net_debug>2) { + printk("%s: recv len=0x%04x\n",dev->name,pkt_len); + } + + if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */ + lp->stats.rx_errors++; + if (pkt_hdr & SEEQPKTS_SHORT) lp->stats.rx_frame_errors++; + if (pkt_hdr & SEEQPKTS_DRIB) lp->stats.rx_frame_errors++; + if (pkt_hdr & SEEQPKTS_OVERSIZE) lp->stats.rx_over_errors++; + if (pkt_hdr & SEEQPKTS_CRC_ERR) lp->stats.rx_crc_errors++; + /* skip over this packet */ + outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); + outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA); + } else { + /* Malloc up new buffer. */ + struct sk_buff *skb; + unsigned char *buf; + + skb = dev_alloc_skb(pkt_len); + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + break; + } + skb->dev = dev; + skb_reserve(skb, 2); /* align data on 16 byte */ + buf = skb_put(skb,pkt_len); + + insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1); + + if (net_debug>2) { + char * p = buf; + printk("%s: recv ",dev->name); + for(i=0;i<14;i++) { + printk("%02x ",*(p++)&0xff); + } + printk("\n"); + } + + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + } + } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN)); + + /* If any worth-while packets have been received, netif_rx() + has done a mark_bh(NET_BH) for us and will work on them + when we get to the bottom-half routine. */ + return; +} + +/* The inverse routine to net_open(). */ +static int +seeq8005_close(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + + lp->open_time = 0; + + dev->tbusy = 1; + dev->start = 0; + + /* Flush the Tx and disable Rx here. */ + outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD); + + free_irq(dev->irq); + + irq2dev_map[dev->irq] = 0; + + /* Update the statistics here. */ + + return 0; + +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct enet_statistics * +seeq8005_get_stats(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + return &lp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ +static void +set_multicast_list(struct device *dev, int num_addrs, void *addrs) +{ +/* + * I _could_ do upto 6 addresses here, but wont (yet?) + */ + +#if 0 + int ioaddr = dev->base_addr; +/* + * hmm, not even sure if my matching works _anyway_ - seem to be receiving + * _everything_ . . . + */ + + if (num_addrs) { /* Enable promiscuous mode */ + outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1); + } else { /* Disable promiscuous mode, use normal mode */ + outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1); + } +#endif +} + +void seeq8005_init(struct device *dev, int startp) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + int i; + + outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */ + SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */ + SLOW_DOWN_IO; + SLOW_DOWN_IO; + SLOW_DOWN_IO; + + outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); + outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */ +/* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */ + outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1); + + for(i=0;i<6;i++) { /* set Station address */ + outb(dev->dev_addr[i], SEEQ_BUFFER); + SLOW_DOWN_IO; + } + + outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */ + outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */ + + lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */ + outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */ + + outw( 0x00ff, SEEQ_REA); /* Receive Area End */ + + if (net_debug>4) { + printk("%s: SA0 = ",dev->name); + + outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); + outw( 0, SEEQ_DMAAR); + outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1); + + for(i=0;i<6;i++) { + printk("%02x ",inb(SEEQ_BUFFER)); + } + printk("\n"); + } + + outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1); + outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2); + outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD); + + if (net_debug>4) { + int old_cfg1; + old_cfg1 = inw(SEEQ_CFG1); + printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS)); + printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1); + printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2)); + printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA)); + printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR)); + + } +} + + +void hardware_send_packet(struct device * dev, char *buf, int length) +{ + int ioaddr = dev->base_addr; + int status = inw(SEEQ_STATUS); + int transmit_ptr = 0; + int tmp; + + if (net_debug>4) { + printk("%s: send 0x%04x\n",dev->name,length); + } + + /* Set FIFO to writemode and set packet-buffer address */ + outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD); + outw( transmit_ptr, SEEQ_DMAAR); + + /* output SEEQ Packet header barfage */ + outw( htons(length + 4), SEEQ_BUFFER); + outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER ); + + /* blat the buffer */ + outsw( SEEQ_BUFFER, buf, (length +1) >> 1); + /* paranoia !! */ + outw( 0, SEEQ_BUFFER); + outw( 0, SEEQ_BUFFER); + + /* set address of start of transmit chain */ + outw( transmit_ptr, SEEQ_TPR); + + /* drain FIFO */ + tmp = jiffies; + while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && (jiffies < tmp + HZ)) + mb(); + + /* doit ! */ + outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD); + +} + + +/* + * wait_for_buffer + * + * This routine waits for the SEEQ chip to assert that the FIFO is ready + * by checking for a window interrupt, and then clearing it + */ +inline void wait_for_buffer(struct device * dev) +{ + int ioaddr = dev->base_addr; + int tmp; + int status; + + tmp = jiffies + HZ; + while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && jiffies < tmp) + mb(); + + if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT) + outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v1.3.8/linux/drivers/net/seeq8005.h linux/drivers/net/seeq8005.h --- v1.3.8/linux/drivers/net/seeq8005.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/seeq8005.h Mon Jul 10 17:08:04 1995 @@ -0,0 +1,156 @@ +/* + * defines, etc for the seeq8005 + */ + +/* + * This file is distributed under GPL. + * + * This style and layout of this file is also copied + * from many of the other linux network device drivers. + */ + +/* The number of low I/O ports used by the ethercard. */ +#define SEEQ8005_IO_EXTENT 16 + +#define SEEQ_B (ioaddr) + +#define SEEQ_CMD (SEEQ_B) /* Write only */ +#define SEEQ_STATUS (SEEQ_B) /* Read only */ +#define SEEQ_CFG1 (SEEQ_B + 2) +#define SEEQ_CFG2 (SEEQ_B + 4) +#define SEEQ_REA (SEEQ_B + 6) /* Receive End Area Register */ +#define SEEQ_RPR (SEEQ_B + 10) /* Receive Pointer Register */ +#define SEEQ_TPR (SEEQ_B + 12) /* Transmit Pointer Register */ +#define SEEQ_DMAAR (SEEQ_B + 14) /* DMA Address Register */ +#define SEEQ_BUFFER (SEEQ_B + 8) /* Buffer Window Register */ + +#define DEFAULT_TEA (0x3f) + +#define SEEQCMD_DMA_INT_EN (0x0001) /* DMA Interrupt Enable */ +#define SEEQCMD_RX_INT_EN (0x0002) /* Receive Interrupt Enable */ +#define SEEQCMD_TX_INT_EN (0x0004) /* Transmit Interrupt Enable */ +#define SEEQCMD_WINDOW_INT_EN (0x0008) /* What the hell is this for?? */ +#define SEEQCMD_INT_MASK (0x000f) + +#define SEEQCMD_DMA_INT_ACK (0x0010) /* DMA ack */ +#define SEEQCMD_RX_INT_ACK (0x0020) +#define SEEQCMD_TX_INT_ACK (0x0040) +#define SEEQCMD_WINDOW_INT_ACK (0x0080) +#define SEEQCMD_ACK_ALL (0x00f0) + +#define SEEQCMD_SET_DMA_ON (0x0100) /* Enables DMA Request logic */ +#define SEEQCMD_SET_RX_ON (0x0200) /* Enables Packet RX */ +#define SEEQCMD_SET_TX_ON (0x0400) /* Starts TX run */ +#define SEEQCMD_SET_DMA_OFF (0x0800) +#define SEEQCMD_SET_RX_OFF (0x1000) +#define SEEQCMD_SET_TX_OFF (0x2000) +#define SEEQCMD_SET_ALL_OFF (0x3800) /* set all logic off */ + +#define SEEQCMD_FIFO_READ (0x4000) /* Set FIFO to read mode (read from Buffer) */ +#define SEEQCMD_FIFO_WRITE (0x8000) /* Set FIFO to write mode */ + +#define SEEQSTAT_DMA_INT_EN (0x0001) /* Status of interrupt enable */ +#define SEEQSTAT_RX_INT_EN (0x0002) +#define SEEQSTAT_TX_INT_EN (0x0004) +#define SEEQSTAT_WINDOW_INT_EN (0x0008) + +#define SEEQSTAT_DMA_INT (0x0010) /* Interrupt flagged */ +#define SEEQSTAT_RX_INT (0x0020) +#define SEEQSTAT_TX_INT (0x0040) +#define SEEQSTAT_WINDOW_INT (0x0080) +#define SEEQSTAT_ANY_INT (0x00f0) + +#define SEEQSTAT_DMA_ON (0x0100) /* DMA logic on */ +#define SEEQSTAT_RX_ON (0x0200) /* Packet RX on */ +#define SEEQSTAT_TX_ON (0x0400) /* TX running */ + +#define SEEQSTAT_FIFO_FULL (0x2000) +#define SEEQSTAT_FIFO_EMPTY (0x4000) +#define SEEQSTAT_FIFO_DIR (0x8000) /* 1=read, 0=write */ + +#define SEEQCFG1_BUFFER_MASK (0x000f) /* define what mapps into the BUFFER register */ +#define SEEQCFG1_BUFFER_MAC0 (0x0000) /* MAC station addresses 0-5 */ +#define SEEQCFG1_BUFFER_MAC1 (0x0001) +#define SEEQCFG1_BUFFER_MAC2 (0x0002) +#define SEEQCFG1_BUFFER_MAC3 (0x0003) +#define SEEQCFG1_BUFFER_MAC4 (0x0004) +#define SEEQCFG1_BUFFER_MAC5 (0x0005) +#define SEEQCFG1_BUFFER_PROM (0x0006) /* The Address/CFG PROM */ +#define SEEQCFG1_BUFFER_TEA (0x0007) /* Transmit end area */ +#define SEEQCFG1_BUFFER_BUFFER (0x0008) /* Packet buffer memory */ +#define SEEQCFG1_BUFFER_INT_VEC (0x0009) /* Interrupt Vector */ + +#define SEEQCFG1_DMA_INTVL_MASK (0x0030) +#define SEEQCFG1_DMA_CONT (0x0000) +#define SEEQCFG1_DMA_800ns (0x0010) +#define SEEQCFG1_DMA_1600ns (0x0020) +#define SEEQCFG1_DMA_3200ns (0x0030) + +#define SEEQCFG1_DMA_LEN_MASK (0x00c0) +#define SEEQCFG1_DMA_LEN1 (0x0000) +#define SEEQCFG1_DMA_LEN2 (0x0040) +#define SEEQCFG1_DMA_LEN4 (0x0080) +#define SEEQCFG1_DMA_LEN8 (0x00c0) + +#define SEEQCFG1_MAC_MASK (0x3f00) /* Dis/enable bits for MAC addresses */ +#define SEEQCFG1_MAC0_EN (0x0100) +#define SEEQCFG1_MAC1_EN (0x0200) +#define SEEQCFG1_MAC2_EN (0x0400) +#define SEEQCFG1_MAC3_EN (0x0800) +#define SEEQCFG1_MAC4_EN (0x1000) +#define SEEQCFG1_MAC5_EN (0x2000) + +#define SEEQCFG1_MATCH_MASK (0xc000) /* Packet matching logic cfg bits */ +#define SEEQCFG1_MATCH_SPECIFIC (0x0000) /* only matching MAC addresses */ +#define SEEQCFG1_MATCH_BROAD (0x4000) /* matching and broadcast addresses */ +#define SEEQCFG1_MATCH_MULTI (0x8000) /* matching, broadcast and multicast */ +#define SEEQCFG1_MATCH_ALL (0xc000) /* Promiscuous mode */ + +#define SEEQCFG1_DEFAULT (SEEQCFG1_BUFFER_BUFFER | SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD) + +#define SEEQCFG2_BYTE_SWAP (0x0001) /* 0=Intel byte-order */ +#define SEEQCFG2_AUTO_REA (0x0002) /* if set, Receive End Area will be updated when reading from Buffer */ + +#define SEEQCFG2_CRC_ERR_EN (0x0008) /* enables receiving of packets with CRC errors */ +#define SEEQCFG2_DRIBBLE_EN (0x0010) /* enables receiving of non-aligned packets */ +#define SEEQCFG2_SHORT_EN (0x0020) /* enables receiving of short packets */ + +#define SEEQCFG2_SLOTSEL (0x0040) /* 0= standard IEEE802.3, 1= smaller,faster, non-standard */ +#define SEEQCFG2_NO_PREAM (0x0080) /* 1= user supplies Xmit preamble bytes */ +#define SEEQCFG2_ADDR_LEN (0x0100) /* 1= 2byte addresses */ +#define SEEQCFG2_REC_CRC (0x0200) /* 0= recieved packets will have CRC stripped from them */ +#define SEEQCFG2_XMIT_NO_CRC (0x0400) /* dont xmit CRC with each packet (user supplies it) */ +#define SEEQCFG2_LOOPBACK (0x0800) +#define SEEQCFG2_CTRLO (0x1000) +#define SEEQCFG2_RESET (0x8000) /* software Hard-reset bit */ + +struct seeq_pkt_hdr { + unsigned short next; /* address of next packet header */ + unsigned char babble_int:1, /* enable int on >1514 byte packet */ + coll_int:1, /* enable int on collision */ + coll_16_int:1, /* enable int on >15 collision */ + xmit_int:1, /* enable int on success (or xmit with <15 collision) */ + unused:1, + data_follows:1, /* if not set, process this as a header and pointer only */ + chain_cont:1, /* if set, more headers in chain only cmd bit valid in recv header */ + xmit_recv:1; /* if set, a xmit packet, else a recieve packet.*/ + unsigned char status; +}; + +#define SEEQPKTH_BAB_INT_EN (0x01) /* xmit only */ +#define SEEQPKTH_COL_INT_EN (0x02) /* xmit only */ +#define SEEQPKTH_COL16_INT_EN (0x04) /* xmit only */ +#define SEEQPKTH_XMIT_INT_EN (0x08) /* xmit only */ +#define SEEQPKTH_DATA_FOLLOWS (0x20) /* supposedly in xmit only */ +#define SEEQPKTH_CHAIN (0x40) /* more headers follow */ +#define SEEQPKTH_XMIT (0x80) + +#define SEEQPKTS_BABBLE (0x0100) /* xmit only */ +#define SEEQPKTS_OVERSIZE (0x0100) /* recv only */ +#define SEEQPKTS_COLLISION (0x0200) /* xmit only */ +#define SEEQPKTS_CRC_ERR (0x0200) /* recv only */ +#define SEEQPKTS_COLL16 (0x0400) /* xmit only */ +#define SEEQPKTS_DRIB (0x0400) /* recv only */ +#define SEEQPKTS_SHORT (0x0800) /* recv only */ +#define SEEQPKTS_DONE (0x8000) +#define SEEQPKTS_ANY_ERROR (0x0f00) diff -u --recursive --new-file v1.3.8/linux/drivers/pci/Makefile linux/drivers/pci/Makefile --- v1.3.8/linux/drivers/pci/Makefile Wed Jun 7 13:03:54 1995 +++ linux/drivers/pci/Makefile Tue Jul 11 08:02:20 1995 @@ -9,8 +9,6 @@ # parent makefile. # -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -30,11 +28,5 @@ $(CPP) -M $(SRCS) > .depend modules: -dummy: -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v1.3.8/linux/drivers/pci/pci.c Thu Jun 29 19:02:42 1995 +++ linux/drivers/pci/pci.c Mon Jul 10 17:08:03 1995 @@ -74,6 +74,8 @@ DEVICE( INTEL, INTEL_82430, "82430ZX Aries"), DEVICE( INTEL, INTEL_82437, "82437 Triton"), DEVICE( INTEL, INTEL_82371, "82471 Triton"), + DEVICE( INTEL, INTEL_82438, "82438"), + DEVICE( INTEL, INTEL_7116, "SAA7116"), DEVICE( SMC, SMC_37C665, "FDC 37C665"), DEVICE( ATI, ATI_M32, "Mach 32"), DEVICE( ATI, ATI_M64, "Mach 64"), diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v1.3.8/linux/drivers/scsi/Makefile Fri Jul 7 08:54:48 1995 +++ linux/drivers/scsi/Makefile Tue Jul 11 08:02:20 1995 @@ -6,8 +6,6 @@ # unless it's something special (ie not a .c file). # -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -264,13 +262,10 @@ (cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done) dep: $(SCSI_DEP) - $(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend - $(CPP) -M -DMODULE $(patsubst sd_mod.c,sd.c sd_ioctl.c, \ - $(patsubst sr_mod.c,sr.c sr_ioctl.c, $(SCSI_MODULE_OBJS:.o=.c))) >> .depend - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + $(CPP) -M $(AHA152X) constants.c $(SCSI_OBJS:.o=.c) > .depend + $(CPP) -M -DMODULE $(patsubst scsi_mod.c,scsi.c hosts.c scsi_ioctl.c \ + constants.c scsicam.c scsi_proc.c, \ + $(patsubst sd_mod.c,sd.c sd_ioctl.c, \ + $(patsubst sr_mod.c,sr.c sr_ioctl.c, $(SCSI_MODULE_OBJS:.o=.c)))) >> .depend + +include $(TOPDIR)/Rules.make Binary files v1.3.8/linux/drivers/scsi/aic7770 and linux/drivers/scsi/aic7770 differ diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/eata_dma_proc.c linux/drivers/scsi/eata_dma_proc.c --- v1.3.8/linux/drivers/scsi/eata_dma_proc.c Thu Jun 29 19:02:49 1995 +++ linux/drivers/scsi/eata_dma_proc.c Tue Jul 11 07:56:04 1995 @@ -23,12 +23,12 @@ u8 *bp; lp = (u32 *)p; - sp = ((short *)lp) + 1; /* Convert Header */ + sp = ((short *)lp) + 1; /* Convert Header */ h_sp = *sp = ntohs(*sp); lp++; do { - sp = (u16 *)lp; /* Convert SubHeader */ + sp = (u16 *)lp; /* Convert SubHeader */ *sp = ntohs(*sp); bp = (u8 *) lp; y = *(bp + 3); @@ -53,13 +53,17 @@ /* * eata_proc_info - * inout : decides on the direction of the dataflow and the meaning of the variables + * inout : decides on the direction of the dataflow and the meaning of the + * variables * buffer: If inout==FALSE data is beeing written to it else read from it * *start: If inout==FALSE start of the valid data in the buffer - * offset: If inout==FALSE offset from the beginning of the imaginary file from which we start writing into the buffer - * length: If inout==FALSE max number of bytes to be written into the buffer else number of bytes in the buffer + * offset: If inout==FALSE offset from the beginning of the imaginary file + * from which we start writing into the buffer + * length: If inout==FALSE max number of bytes to be written into the buffer + * else number of bytes in the buffer */ -int eata_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +int eata_proc_info(char *buffer, char **start, off_t offset, int length, + int hostno, int inout) { Scsi_Device *scd; @@ -89,7 +93,7 @@ if (HBA_ptr->host_no == hostno) break; HBA_ptr = SD(HBA_ptr)->next; - } + } if(inout == TRUE) /* Has data been writen to the file ? */ return(eata_set_info(buffer, length, HBA_ptr)); @@ -116,35 +120,6 @@ "processed interrupts:%10ld\n", queue_counter, int_counter); len += size; pos = begin + len; - if(SD(HBA_ptr)->bustype == IS_EISA) - goto devices; - - scmd.cmnd[0] = LOG_SENSE; - scmd.cmnd[1] = 0; - scmd.cmnd[2] = 0x33 + (3<<6); - scmd.cmnd[3] = 0; - scmd.cmnd[4] = 0; - scmd.cmnd[5] = 0; - scmd.cmnd[6] = 0; - scmd.cmnd[7] = 0x00; - scmd.cmnd[8] = 0x66; - scmd.cmnd[9] = 0; - scmd.cmd_len = 10; - - scmd.host = HBA_ptr; - scmd.target = HBA_ptr->this_id; - scmd.lun = 0; - scmd.channel = 0; - - scmd.use_sg = 0; - scmd.request_bufflen = 0x66; - scmd.request_buffer = buff + 0x144; - HBA_interpret = TRUE; - - eata_queue(&scmd, (void *) eata_scsi_done); - while (internal_command_finished == FALSE) - barrier(); - size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n", HBA_ptr->host_no, SD(HBA_ptr)->name); len += size; @@ -156,164 +131,208 @@ size = sprintf(buffer + len, "Hardware Configuration:\n"); len += size; pos = begin + len; - size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt, - (cc->intt == TRUE)?"level":"edge"); - len += size; - pos = begin + len; - if (HBA_ptr->dma_channel == 0xff) - size = sprintf(buffer + len, "DMA: BUSMASTER\n"); - else - size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "CPU: MC680%02d %dMHz\n", bt->cpu_type, - bt->cpu_speed); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "Host Bus: %s\n", - (SD(HBA_ptr)->bustype == IS_PCI)?"PCI ": - (SD(HBA_ptr)->bustype == IS_EISA)?"EISA":"ISA "); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "SCSI Bus:%s%s Speed: %sMB/sec. %s\n", - (sb->wide == TRUE)?" WIDE":"", - (sb->dif == TRUE)?" DIFFERENTIAL":"", - (sb->speed == 0)?"5":(sb->speed == 1)?"10":"20", - (sb->ext == TRUE)?"With external cable detection":""); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "SCSI channel expansion Module: %s installed\n", - (bt->sx1 == TRUE)?"SX1 (one channel)": - ((bt->sx2 == TRUE)?"SX2 (two channels)":"not")); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "SmartRAID hardware: %spresent.\n", - (cc->srs == TRUE)?"":"not "); - len += size; - pos = begin + len; - size = sprintf(buffer + len, " Type: %s\n", - ((cc->key == TRUE)?((bt->dmi == TRUE)?"integrated" - :((bt->dm4 == TRUE)?"DM401X" - :(bt->dm4k == TRUE)?"DM4000" - :"-")) - :"-")); - len += size; - pos = begin + len; - - size = sprintf(buffer + len, " Max array groups: %d\n", - (al->code == 0x0e)?al->max_groups:7); - len += size; - pos = begin + len; - size = sprintf(buffer + len, " Max drives per RAID 0 array: %d\n", - (al->code == 0x0e)?al->raid0_drv:7); - len += size; - pos = begin + len; - size = sprintf(buffer + len, " Max drives per RAID 3/5 array: %d\n", - (al->code == 0x0e)?al->raid35_drv:7); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "Cache Module: %sinstalled.\n", - (cc->csh)?"":"not "); - len += size; - pos = begin + len; - size = sprintf(buffer + len, " Type: %s\n", - ((cc->csh == TRUE)?((bt->cmi == TRUE)?"integrated" - :((bt->cm4 == TRUE)?"CM401X" - :((bt->cm4k == TRUE)?"CM4000" - :"-"))) - :"-")); - len += size; - pos = begin + len; - for (x = 0; x <= 3; x++) { - size = sprintf(buffer + len, " Bank%d: %dMB with%s ECC\n",x, - mc->banksize[x] & 0x7f, - (mc->banksize[x] & 0x80)?"":"out"); - len += size; - pos = begin + len; - } - size = sprintf(buffer + len, "Timer Modification: %sinstalled\n", - (cc->tmr == TRUE)?"":"not "); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "NVRAM: %spresent\n", - (cc->nvr == TRUE)?"":"not "); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "SmartROM: %senabled\n", - (bt->srom == TRUE)?"not ":""); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "HBA indicates %salarm.\n", - (bt->alrm == TRUE)?"":"no "); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - - scmd.cmnd[0] = LOG_SENSE; - scmd.cmnd[1] = 0; - scmd.cmnd[2] = 0x32 + (3<<6); - scmd.cmnd[3] = 0; - scmd.cmnd[4] = 0; - scmd.cmnd[5] = 0; - scmd.cmnd[6] = 0; - scmd.cmnd[7] = 0x01; - scmd.cmnd[8] = 0x44; - scmd.cmnd[9] = 0; - scmd.cmd_len = 10; - scmd.host = HBA_ptr; - scmd.target = HBA_ptr->this_id; - scmd.lun = 0; - scmd.channel = 0; - scmd.use_sg = 0; - scmd.request_bufflen = 0x144; - scmd.request_buffer = buff2; - HBA_interpret = TRUE; - - eata_queue(&scmd, (void *) eata_scsi_done); - while (internal_command_finished == FALSE) - barrier(); - - swap_statistics(buff2); - rhcs = (hst_cmd_stat *)(buff2 + 0x2c); - whcs = (hst_cmd_stat *)(buff2 + 0x8c); - - for (x = 0; x <= 11; x++) { - SD(HBA_ptr)->reads[x] += rhcs->sizes[x]; - SD(HBA_ptr)->writes[x] += whcs->sizes[x]; - SD(HBA_ptr)->reads[12] += rhcs->sizes[x]; - SD(HBA_ptr)->writes[12] += whcs->sizes[x]; - } - size = sprintf(buffer + len, "Host Disk Command Statistics:\n" - " Reads: Writes:\n"); - len += size; - pos = begin + len; - for (x = 0; x <= 10; x++) { - size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x, - SD(HBA_ptr)->reads[x], - SD(HBA_ptr)->writes[x]); + if(SD(HBA_ptr)->bustype == IS_EISA) { + if (HBA_ptr->dma_channel == 0xff) + size = sprintf(buffer + len, "DMA: BUSMASTER\n"); + else + size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel); + len += size; + pos = begin + len; + + size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "Host Bus: EISA\n"); + len += size; + pos = begin + len; + } else { + + scmd.cmnd[0] = LOG_SENSE; + scmd.cmnd[1] = 0; + scmd.cmnd[2] = 0x33 + (3<<6); + scmd.cmnd[3] = 0; + scmd.cmnd[4] = 0; + scmd.cmnd[5] = 0; + scmd.cmnd[6] = 0; + scmd.cmnd[7] = 0x00; + scmd.cmnd[8] = 0x66; + scmd.cmnd[9] = 0; + scmd.cmd_len = 10; + + scmd.host = HBA_ptr; + scmd.target = HBA_ptr->this_id; + scmd.lun = 0; + scmd.channel = 0; + + scmd.use_sg = 0; + scmd.request_bufflen = 0x66; + scmd.request_buffer = buff + 0x144; + HBA_interpret = TRUE; + + eata_queue(&scmd, (void *) eata_scsi_done); + while (internal_command_finished == FALSE) + barrier(); + + size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt, + (cc->intt == TRUE)?"level":"edge"); + len += size; + pos = begin + len; + if (HBA_ptr->dma_channel == 0xff) + size = sprintf(buffer + len, "DMA: BUSMASTER\n"); + else + size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "CPU: MC680%02d %dMHz\n", bt->cpu_type, + bt->cpu_speed); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "Host Bus: %s\n", + (SD(HBA_ptr)->bustype == IS_PCI)?"PCI ": + (SD(HBA_ptr)->bustype == IS_EISA)?"EISA":"ISA "); + + len += size; + pos = begin + len; + size = sprintf(buffer + len, "SCSI Bus:%s%s Speed: %sMB/sec. %s\n", + (sb->wide == TRUE)?" WIDE":"", + (sb->dif == TRUE)?" DIFFERENTIAL":"", + (sb->speed == 0)?"5":(sb->speed == 1)?"10":"20", + (sb->ext == TRUE)?"With external cable detection":""); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "SCSI channel expansion Module: %s installed\n", + (bt->sx1 == TRUE)?"SX1 (one channel)": + ((bt->sx2 == TRUE)?"SX2 (two channels)":"not")); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "SmartRAID hardware: %spresent.\n", + (cc->srs == TRUE)?"":"not "); + len += size; + pos = begin + len; + size = sprintf(buffer + len, " Type: %s\n", + ((cc->key == TRUE)?((bt->dmi == TRUE)?"integrated" + :((bt->dm4 == TRUE)?"DM401X" + :(bt->dm4k == TRUE)?"DM4000" + :"-")) + :"-")); + len += size; + pos = begin + len; + + size = sprintf(buffer + len, " Max array groups: %d\n", + (al->code == 0x0e)?al->max_groups:7); + len += size; + pos = begin + len; + size = sprintf(buffer + len, " Max drives per RAID 0 array: %d\n", + (al->code == 0x0e)?al->raid0_drv:7); + len += size; + pos = begin + len; + size = sprintf(buffer + len, " Max drives per RAID 3/5 array: %d\n", + (al->code == 0x0e)?al->raid35_drv:7); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "Cache Module: %sinstalled.\n", + (cc->csh)?"":"not "); + len += size; + pos = begin + len; + size = sprintf(buffer + len, " Type: %s\n", + ((cc->csh == TRUE)?((bt->cmi == TRUE)?"integrated" + :((bt->cm4 == TRUE)?"CM401X" + :((bt->cm4k == TRUE)?"CM4000" + :"-"))) + :"-")); + len += size; + pos = begin + len; + for (x = 0; x <= 3; x++) { + size = sprintf(buffer + len, " Bank%d: %dMB with%s ECC\n",x, + mc->banksize[x] & 0x7f, + (mc->banksize[x] & 0x80)?"":"out"); + len += size; + pos = begin + len; + } + size = sprintf(buffer + len, "Timer Modification: %sinstalled\n", + (cc->tmr == TRUE)?"":"not "); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "NVRAM: %spresent\n", + (cc->nvr == TRUE)?"":"not "); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "SmartROM: %senabled\n", + (bt->srom == TRUE)?"not ":""); + len += size; + pos = begin + len; + size = sprintf(buffer + len, "HBA indicates %salarm.\n", + (bt->alrm == TRUE)?"":"no "); + len += size; + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + + scmd.cmnd[0] = LOG_SENSE; + scmd.cmnd[1] = 0; + scmd.cmnd[2] = 0x32 + (3<<6); + scmd.cmnd[3] = 0; + scmd.cmnd[4] = 0; + scmd.cmnd[5] = 0; + scmd.cmnd[6] = 0; + scmd.cmnd[7] = 0x01; + scmd.cmnd[8] = 0x44; + scmd.cmnd[9] = 0; + scmd.cmd_len = 10; + scmd.host = HBA_ptr; + scmd.target = HBA_ptr->this_id; + scmd.lun = 0; + scmd.channel = 0; + scmd.use_sg = 0; + scmd.request_bufflen = 0x144; + scmd.request_buffer = buff2; + HBA_interpret = TRUE; + + eata_queue(&scmd, (void *) eata_scsi_done); + while (internal_command_finished == FALSE) + barrier(); + + swap_statistics(buff2); + rhcs = (hst_cmd_stat *)(buff2 + 0x2c); + whcs = (hst_cmd_stat *)(buff2 + 0x8c); + + for (x = 0; x <= 11; x++) { + SD(HBA_ptr)->reads[x] += rhcs->sizes[x]; + SD(HBA_ptr)->writes[x] += whcs->sizes[x]; + SD(HBA_ptr)->reads[12] += rhcs->sizes[x]; + SD(HBA_ptr)->writes[12] += whcs->sizes[x]; + } + size = sprintf(buffer + len, "Host Disk Command Statistics:\n" + " Reads: Writes:\n"); + len += size; + pos = begin + len; + for (x = 0; x <= 10; x++) { + size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x, + SD(HBA_ptr)->reads[x], + SD(HBA_ptr)->writes[x]); + len += size; + pos = begin + len; + } + size = sprintf(buffer+len,">1024k:%12u %12u\n", + SD(HBA_ptr)->reads[11], + SD(HBA_ptr)->writes[11]); + len += size; + pos = begin + len; + size = sprintf(buffer+len,"Sum :%12u %12u\n", + SD(HBA_ptr)->reads[12], + SD(HBA_ptr)->writes[12]); len += size; pos = begin + len; } - size = sprintf(buffer+len,">1024k:%12u %12u\n", - SD(HBA_ptr)->reads[11], - SD(HBA_ptr)->writes[11]); - len += size; - pos = begin + len; - size = sprintf(buffer+len,"Sum :%12u %12u\n", - SD(HBA_ptr)->reads[12], - SD(HBA_ptr)->writes[12]); - len += size; - pos = begin + len; if (pos < offset) { len = 0; @@ -322,7 +341,6 @@ if (pos > offset + length) goto stop_output; - devices: scd = scsi_devices; size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none"); @@ -358,8 +376,8 @@ size += sprintf(buffer + len + size, " Type: %s ", scd->type < MAX_SCSI_DEVICE_CODE ? - scsi_dev_types[(int)scd->type] : "Unknown " ); - size += sprintf(buffer + len + size, " ANSI" + scsi_dev_types[(int)scd->type] : "Unknown " ); + size += sprintf(buffer + len + size, " ANSI" " SCSI revision: %02x", (scd->scsi_level < 3)?1:2); if (scd->scsi_level == 2) size += sprintf(buffer + len + size, " CCS\n"); @@ -381,9 +399,9 @@ stop_output: DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len)); *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ + len-=(offset-begin); /* Start slop */ if(len>length) - len = length; /* Ending slop */ + len = length; /* Ending slop */ DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len)); return (len); diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.3.8/linux/drivers/scsi/scsi.c Fri Jul 7 08:54:50 1995 +++ linux/drivers/scsi/scsi.c Tue Jul 11 07:56:04 1995 @@ -51,7 +51,6 @@ #undef USE_STATIC_SCSI_MEMORY - /* static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $"; */ @@ -164,65 +163,94 @@ * lock up. */ -struct blist{ +#define BLIST_NOLUN 0x01 +#define BLIST_FORCELUN 0x02 +#define BLIST_BORKEN 0x04 +#define BLIST_KEY 0x08 +#define BLIST_SINGLELUN 0x10 + +struct dev_info{ char * vendor; char * model; char * revision; /* Latest revision known to be bad. Not used yet */ + unsigned flags; }; -static struct blist blacklist[] = -{ -{"CHINON","CD-ROM CDS-431","H42"}, /* Locks up if polled for lun != 0 */ -{"CHINON","CD-ROM CDS-535","Q14"}, /* Locks up if polled for lun != 0 */ -{"DENON","DRD-25X","V"}, /* Locks up if probed for lun != 0 */ -{"HITACHI","DK312C","CM81"}, /* Responds to all lun - dtg */ -{"HITACHI","DK314C","CR21" }, /* responds to all lun */ -{"IMS", "CDD521/10","2.06"}, /* Locks-up when LUN>0 polled. */ -{"MAXTOR","XT-3280","PR02"}, /* Locks-up when LUN>0 polled. */ -{"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */ -{"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN>0 polled */ -{"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */ -{"MAXTOR","XT-8760S","B7B"}, /* guess what? */ -{"NEC","CD-ROM DRIVE:841","1.0"}, /* Locks-up when LUN>0 polled. */ -{"RODIME","RO3000S","2.33"}, /* Locks up if polled for lun != 0 */ -{"SEAGATE", "ST157N", "\004|j"}, /* causes failed REQUEST SENSE on lun 1 - * for aha152x controller, which causes - * SCSI code to reset bus.*/ -{"SEAGATE", "ST296","921"}, /* Responds to all lun */ -{"SONY","CD-ROM CDU-541","4.3d"}, -{"SONY","CD-ROM CDU-55S","1.0i"}, -{"TANDBERG","TDC 3600","U07"}, /* Locks up if polled for lun != 0 */ -{"TEAC","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1 - * for seagate controller, which causes - * SCSI code to reset bus.*/ -{"TEXEL","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1 - * for seagate controller, which causes - * SCSI code to reset bus.*/ -{"QUANTUM","LPS525S","3110"}, /* Locks sometimes if polled for lun != 0 */ -{"QUANTUM","PD1225S","3110"}, /* Locks sometimes if polled for lun != 0 */ -{"MEDIAVIS","CDR-H93MV","1.31"}, /* Locks up if polled for lun != 0 */ -{"SANKYO", "CP525","6.64"}, /* causes failed REQ SENSE, extra reset */ -{"HP", "C1750A", "3226"}, /* scanjet iic */ -{"HP", "C1790A", ""}, /* scanjet iip */ -{"HP", "C2500A", ""}, /* scanjet iicx */ +/* + * This is what was previously known as the blacklist. The concept + * has been expanded so that we can specify other + * The blacklist is used to determine which devices cannot tolerate a + * lun probe because of buggy firmware. Far too many for my liking, + * which is why the default is now for there to be no lun scan. + */ +static struct dev_info device_list[] = +{ +{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ +{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ +{"DENON","DRD-25X","V", BLIST_NOLUN}, /* Locks up if probed for lun != 0 */ +{"HITACHI","DK312C","CM81", BLIST_NOLUN}, /* Responds to all lun - dtg */ +{"HITACHI","DK314C","CR21" , BLIST_NOLUN}, /* responds to all lun */ +{"IMS", "CDD521/10","2.06", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ +{"MAXTOR","XT-3280","PR02", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ +{"MAXTOR","XT-4380S","B3C", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ +{"MAXTOR","MXT-1240S","I1.2", BLIST_NOLUN}, /* Locks up when LUN>0 polled */ +{"MAXTOR","XT-4170S","B5A", BLIST_NOLUN}, /* Locks-up sometimes when LUN>0 polled. */ +{"MAXTOR","XT-8760S","B7B", BLIST_NOLUN}, /* guess what? */ +{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ +{"RODIME","RO3000S","2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ +{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for aha152x controller, which causes + * SCSI code to reset bus.*/ +{"SEAGATE", "ST296","921", BLIST_NOLUN}, /* Responds to all lun */ +{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN}, +{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN}, +{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN}, +{"TANDBERG","TDC 3600","U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ +{"TEAC","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for seagate controller, which causes + * SCSI code to reset bus.*/ +{"TEXEL","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for seagate controller, which causes + * SCSI code to reset bus.*/ +{"QUANTUM","LPS525S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ +{"QUANTUM","PD1225S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ +{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ +{"SANKYO", "CP525","6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ +{"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ +{"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ +{"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ + +/* + * Other types of devices that have special flags. + */ +{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN}, +{"TEXEL","CD-ROM","1.06", BLIST_BORKEN}, +{"INSITE","Floptical F*8I","*", BLIST_KEY}, +{"INSITE","I325VM","*", BLIST_KEY}, +{"PIONEER","CD-ROMDRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, +{"PIONEER","CD-ROMDRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, +/* + * Must be at end of list... + */ {NULL, NULL, NULL} }; -static int blacklisted(unsigned char * response_data){ +static int get_device_flags(unsigned char * response_data){ int i = 0; unsigned char * pnt; for(i=0; 1; i++){ - if(blacklist[i].vendor == NULL) return 0; + if(device_list[i].vendor == NULL) return 0; pnt = &response_data[8]; while(*pnt && *pnt == ' ') pnt++; - if(memcmp(blacklist[i].vendor, pnt, - strlen(blacklist[i].vendor))) continue; + if(memcmp(device_list[i].vendor, pnt, + strlen(device_list[i].vendor))) continue; pnt = &response_data[16]; while(*pnt && *pnt == ' ') pnt++; - if(memcmp(blacklist[i].model, pnt, - strlen(blacklist[i].model))) continue; - return 1; + if(memcmp(device_list[i].model, pnt, + strlen(device_list[i].model))) continue; + return device_list[i].flags; } + return 0; } /* @@ -323,7 +351,7 @@ /* * Detecting SCSI devices : - * We scan all present host adapter's busses, from ID 0 to ID 6. + * We scan all present host adapter's busses, from ID 0 to ID (max_id). * We use the INQUIRY command, determine device type, and pass the ID / * lun address of all sequential devices to the tape driver, all random * devices to the disk driver. @@ -338,6 +366,8 @@ unsigned char * scsi_result; Scsi_Device * SDpnt, *SDtail; struct Scsi_Device_Template * sdtpnt; + int bflags; + int max_dev_lun = 0; Scsi_Cmnd *SCpnt; ++in_scan_scsis; @@ -364,7 +394,7 @@ channel = hchannel; dev = hid; lun = hlun; - goto crude; + goto crude; /* Anyone remember good ol' BASIC ? :-) */ } for (channel = 0; channel <= shpnt->max_channel; channel++) @@ -374,9 +404,14 @@ /* * We need the for so our continue, etc. work fine. + * We put this in a variable so that we can override + * it during the scan if we detect a device *KNOWN* + * to have multiple logical units. */ - for (lun = 0; lun < (max_scsi_luns < shpnt->max_lun ? - max_scsi_luns : shpnt->max_lun); ++lun) + max_dev_lun = (max_scsi_luns < shpnt->max_lun ? + max_scsi_luns : shpnt->max_lun); + + for (lun = 0; lun < max_dev_lun; ++lun) { crude: memset(SDpnt, 0, sizeof(Scsi_Device)); @@ -531,6 +566,7 @@ SDpnt->changed = 0; SDpnt->access_count = 0; SDpnt->busy = 0; + SDpnt->has_cmdblocks = 0; /* * Currently, all sequential devices are assumed to be * tapes, all random devices disk, with the appropriate @@ -560,6 +596,7 @@ #endif } + SDpnt->single_lun = 0; SDpnt->soft_reset = (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2); SDpnt->random = (type == TYPE_TAPE) ? 0 : 1; @@ -599,6 +636,12 @@ */ SDpnt->disconnect = 0; + + /* + * Get any flags for this device. + */ + bflags = get_device_flags(scsi_result); + /* * Some revisions of the Texel CD ROM drives have @@ -608,38 +651,16 @@ * change it here if it turns out that it isn't * a TEXEL drive. */ - if((strncmp("SONY",(char *) &scsi_result[8], 4)!= 0 - || strncmp("CD-ROM CDU-8001", - (char *) &scsi_result[16], 15) != 0) - && (strncmp("TEXEL", - (char *) &scsi_result[8], 5) != 0 - || strncmp("CD-ROM", - (char *) &scsi_result[16], 6) != 0 - /* - * XXX 1.06 has problems, some one should - * figure out the others too so ALL TEXEL - * drives don't suffer in performance, - * especially when I finish integrating my - * seagate patches which do multiple I_T_L - * nexuses. - */ - -#ifdef notyet - || (strncmp("1.06", - (char *) &scsi_result, 4) != 0) -#endif - )) + if( (bflags & BLIST_BORKEN) == 0 ) + { SDpnt->borken = 0; + } /* These devices need this "key" to unlock the * devices so we can use it */ - if(memcmp("INSITE", &scsi_result[8], 6) == 0 && - (memcmp("Floptical F*8I", - &scsi_result[16], 16) == 0 - || memcmp("I325VM", - &scsi_result[16], 6) == 0)) { + if( (bflags & BLIST_KEY) != 0 ) { printk("Unlocked floptical drive.\n"); SDpnt->lockable = 0; scsi_cmd[0] = MODE_SENSE; @@ -680,7 +701,32 @@ /* Some scsi devices cannot be polled for lun != 0 * due to firmware bugs */ - if(blacklisted(scsi_result)) break; + if(bflags & BLIST_NOLUN) break; + + /* + * If we want to only allow I/O to one of the luns + * attached to this device at a time, then we set this + * flag. + */ + if(bflags & BLIST_SINGLELUN) + { + SDpnt->single_lun = 1; + } + + /* + * If this device is known to support multiple units, override + * the other settings, and scan all of them. + */ + if(bflags & BLIST_FORCELUN) + { + /* + * We probably want to make this a variable, but this + * will do for now. + */ + max_dev_lun = 8; + } + + /* Old drives like the MAXTOR XT-3280 say vers=0 */ if ((scsi_result[2] & 0x07) == 0) break; @@ -692,6 +738,10 @@ } } /* if result == DID_OK ends */ + /* + * This might screw us up with multi-lun devices, but the user can + * scan for them too. + */ if(hardcoded == 1) goto leave; } /* for lun ends */ @@ -778,6 +828,7 @@ { Scsi_Cmnd * SCpnt = NULL; int tablesize; + Scsi_Cmnd * found = NULL; struct buffer_head * bh, *bhp; if (!device) @@ -787,11 +838,44 @@ panic("Invalid device in request_queueable"); SCpnt = device->host->host_queue; - while(SCpnt){ - if(SCpnt->target == device->id && SCpnt->lun == device->lun - && SCpnt->channel == device->channel) - if(SCpnt->request.dev < 0) break; - SCpnt = SCpnt->next; + + /* + * Look for a free command block. If we have been instructed not to queue + * multiple commands to multi-lun devices, then check to see what else is going on + * for this device first. + */ + + SCpnt = device->host->host_queue; + if (!device->single_lun) { + while(SCpnt){ + if(SCpnt->target == device->id && + SCpnt->lun == device->lun) { + if(SCpnt->request.dev < 0) break; + } + SCpnt = SCpnt->next; + } + } else { + while(SCpnt){ + if(SCpnt->target == device->id) { + if (SCpnt->lun == device->lun) { + if(found == NULL + && SCpnt->request.dev < 0) + { + found=SCpnt; + } + } + if(SCpnt->request.dev >= 0) { + /* + * I think that we should really limit things to one + * outstanding command per device - this is what tends to trip + * up buggy firmware. + */ + return NULL; + } + } + SCpnt = SCpnt->next; + } + SCpnt = found; } if (!SCpnt) return NULL; @@ -841,14 +925,14 @@ SCpnt->transfersize = 0; SCpnt->underflow = 0; SCpnt->cmd_len = 0; -#if 1 + /* Since not everyone seems to set the device info correctly * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. */ SCpnt->channel = device->channel; SCpnt->lun = device->lun; SCpnt->target = device->id; -#endif + return SCpnt; } @@ -873,6 +957,7 @@ struct Scsi_Host * host; Scsi_Cmnd * SCpnt = NULL; Scsi_Cmnd * SCwait = NULL; + Scsi_Cmnd * found = NULL; if (!device) panic ("No device passed to allocate_device().\n"); @@ -887,15 +972,40 @@ if (intr_count && SCSI_BLOCK(host)) return NULL; while (1==1){ - SCpnt = host->host_queue; - while(SCpnt){ - if(SCpnt->target == device->id && SCpnt->lun == device->lun - && SCpnt->channel == device->channel) { - SCwait = SCpnt; - if(SCpnt->request.dev < 0) break; - } - SCpnt = SCpnt->next; - } + SCpnt = device->host->host_queue; + if (!device->single_lun) { + while(SCpnt){ + if(SCpnt->target == device->id && + SCpnt->lun == device->lun) { + if(SCpnt->request.dev < 0) break; + } + SCpnt = SCpnt->next; + } + } else { + while(SCpnt){ + if(SCpnt->target == device->id) { + if (SCpnt->lun == device->lun) { + if(found == NULL + && SCpnt->request.dev < 0) + { + found=SCpnt; + } + } + if(SCpnt->request.dev >= 0) { + /* + * I think that we should really limit things to one + * outstanding command per device - this is what tends to trip + * up buggy firmware. + */ + found = NULL; + break; + } + } + SCpnt = SCpnt->next; + } + SCpnt = found; + } + save_flags(flags); cli(); /* See if this request has already been queued by an interrupt routine @@ -964,15 +1074,16 @@ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; /* No default transfer size */ SCpnt->cmd_len = 0; + SCpnt->underflow = 0; /* Do not flag underflow conditions */ -#if 1 -/* Since not everyone seems to set the device info correctly - * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. - */ + + /* Since not everyone seems to set the device info correctly + * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. + */ SCpnt->channel = device->channel; SCpnt->lun = device->lun; SCpnt->target = device->id; -#endif + return SCpnt; } @@ -2139,6 +2250,7 @@ SCpnt->prev = NULL; host->host_queue = SCpnt; } + SDpnt->has_cmdblocks = 1; } /* @@ -2196,6 +2308,7 @@ if(SDpnt->attached) scsi_build_commandblocks(SDpnt); } + if (scsi_devicelist) dma_sectors = 16; /* Base value we use */ @@ -2584,6 +2697,7 @@ scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd)); sdpnt->host->host_queue = SCpnt; if (SCpnt) SCpnt->prev = NULL; + sdpnt->has_cmdblocks = 0; } /* Next free up the Scsi_Device structures for this host */ @@ -2672,7 +2786,6 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt) { Scsi_Device * SDpnt; - int previous_attachment; if (tpnt->next) return 1; @@ -2686,7 +2799,7 @@ /* * If any of the devices would match this driver, then perform the - * init function. + + * init function. */ if(tpnt->init && tpnt->dev_noticed) (*tpnt->init)(); @@ -2695,13 +2808,12 @@ */ for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next) { - previous_attachment = SDpnt->attached; if(tpnt->attach) (*tpnt->attach)(SDpnt); /* * If this driver attached to the device, and we no longer * have anything attached, release the scso command blocks. */ - if(SDpnt->attached && previous_attachment == 0) + if(SDpnt->attached && SDpnt->has_cmdblocks == 0) scsi_build_commandblocks(SDpnt); } @@ -2750,6 +2862,7 @@ scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); } } + SDpnt->has_cmdblocks = 0; } } /* diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v1.3.8/linux/drivers/scsi/scsi.h Fri Jul 7 08:54:50 1995 +++ linux/drivers/scsi/scsi.h Tue Jul 11 07:56:04 1995 @@ -302,6 +302,7 @@ unsigned writeable:1; unsigned removable:1; unsigned random:1; + unsigned has_cmdblocks:1; unsigned changed:1; /* Data invalid due to media change */ unsigned busy:1; /* Used to prevent races */ unsigned lockable:1; /* Able to prevent media removal */ @@ -312,6 +313,8 @@ unsigned disconnect:1; /* can disconnect */ unsigned soft_reset:1; /* Uses soft reset option */ unsigned sync:1; /* Negotiate for sync transfers */ + unsigned single_lun:1; /* Indicates we should only allow I/O to + one of the luns for the device at a time. */ unsigned char current_tag; /* current tag */ unsigned char sync_min_period; /* Not less than this period */ unsigned char sync_max_offset; /* Not greater than this offset */ diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- v1.3.8/linux/drivers/scsi/scsi_debug.c Fri Jul 7 08:54:50 1995 +++ linux/drivers/scsi/scsi_debug.c Tue Jul 11 07:56:04 1995 @@ -122,6 +122,11 @@ static char sense_buffer[128] = {0,}; +/* + * Semaphore used to simulate bus lockups. + */ +static int scsi_debug_lockup = 0; + static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){ int i; #if 0 @@ -229,7 +234,7 @@ scsi_debug_errsts = 0; break; case TEST_UNIT_READY: - printk("Test unit ready.\n"); + printk("Test unit ready(%x %d)\n", buff, bufflen); if (buff) memset(buff, 0, bufflen); scsi_debug_errsts = 0; @@ -288,6 +293,7 @@ /* If this is block 0, then we want to read the partition table for this * device. Let's make one up */ if(block == 0 && target == 0) { + memset(buff, 0, bufflen); *((unsigned short *) (buff+510)) = 0xAA55; p = (struct partition* ) (buff + 0x1be); npart = 0; @@ -412,8 +418,12 @@ printk("scsi_debug_queuecommand: done cant be NULL\n"); #ifdef IMMEDIATE - SCpnt->result = scsi_debug_errsts; - scsi_debug_intr_handle(); /* No timer - do this one right away */ + if( !scsi_debug_lockup ) + { + SCpnt->result = scsi_debug_errsts; + scsi_debug_intr_handle(); /* No timer - do this one right away */ + } + restore_flags(flags); #else timeout[i] = jiffies+DISK_SPEED; @@ -580,19 +590,20 @@ unsigned long flags; void (*my_done)(Scsi_Cmnd *); + scsi_debug_lockup = 0; DEB(printk("scsi_debug_reset called\n")); for(i=0;iresult = DID_ABORT << 16; - my_done = do_done[i]; - my_done(SCint[i]); - save_flags(flags); - cli(); - SCint[i] = NULL; - do_done[i] = NULL; - timeout[i] = 0; - restore_flags(flags); - }; + if (SCint[i] == NULL) continue; + SCint[i]->result = DID_ABORT << 16; + my_done = do_done[i]; + my_done(SCint[i]); + save_flags(flags); + cli(); + SCint[i] = NULL; + do_done[i] = NULL; + timeout[i] = 0; + restore_flags(flags); + } return 0; } @@ -602,7 +613,7 @@ return buffer; } -/* generic_proc_info +/* scsi_debug_proc_info * Used if the driver currently has no own support for /proc/scsi */ int scsi_debug_proc_info(char *buffer, char **start, off_t offset, @@ -611,7 +622,35 @@ int len, pos, begin; if(inout == 1) - return(-ENOSYS); /* This is a no-op */ + { + /* First check for the Signature */ + if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) { + buffer += 11; + length -= 11; + /* + * OK, we are getting some kind of command. Figure out + * what we are supposed to do here. Simulate bus lockups + * to test our reset capability. + */ + if( length == 6 && strncmp(buffer, "lockup", length) == 0 ) + { + scsi_debug_lockup = 1; + return length; + } + + if( length == 6 && strncmp(buffer, "unlock", length) == 0 ) + { + scsi_debug_lockup = 0; + return length; + } + + printk("Unknown command:%s\n", buffer); + } else + printk("Wrong Signature:%10s\n", (char *) ((ulong)buffer-11)); + + return -EINVAL; + + } begin = 0; pos = len = sprintf(buffer, diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v1.3.8/linux/drivers/scsi/scsi_ioctl.c Fri Jul 7 08:54:50 1995 +++ linux/drivers/scsi/scsi_ioctl.c Tue Jul 11 07:56:04 1995 @@ -42,11 +42,14 @@ static int ioctl_probe(struct Scsi_Host * host, void *buffer) { - int temp; + int temp, result; unsigned int len,slen; const char * string; if ((temp = host->hostt->present) && buffer) { + result = verify_area(VERIFY_READ, buffer, sizeof(long)); + if (result) return result; + len = get_user ((unsigned int *) buffer); if(host->hostt->info) string = host->hostt->info(host); @@ -56,7 +59,9 @@ slen = strlen(string); if (len > slen) len = slen + 1; - verify_area(VERIFY_WRITE, buffer, len); + result = verify_area(VERIFY_WRITE, buffer, len); + if (result) return result; + memcpy_tofs (buffer, string, len); } } @@ -139,7 +144,7 @@ break; }; default: /* Fall through for non-removable media */ - printk("SCSI CD error: host %d id %d lun %d return code = %x\n", + printk("SCSI error: host %d id %d lun %d return code = %x\n", dev->host->host_no, dev->id, dev->lun, @@ -157,6 +162,11 @@ return result; } +/* + * This interface is depreciated - users should use the scsi generics + * interface instead, as this is a more flexible approach to performing + * generic SCSI commands on a device. + */ static int ioctl_command(Scsi_Device *dev, void *buffer) { char * buf; @@ -171,11 +181,35 @@ if (!buffer) return -EINVAL; - inlen = get_user((unsigned int *) buffer); - outlen = get_user( ((unsigned int *) buffer) + 1); - - cmd_in = (char *) ( ((int *)buffer) + 2); - opcode = get_user(cmd_in); + + /* + * Verify that we can read at least this much. + */ + result = verify_area(VERIFY_READ, buffer, 2*sizeof(long) + 1); + if (result) return result; + + /* + * The structure that we are passed should look like: + * + * struct sdata{ + * int inlen; + * int outlen; + * char cmd[]; # However many bytes are used for cmd. + * char data[]; + */ + inlen = get_user((unsigned int *) buffer); + outlen = get_user( ((unsigned int *) buffer) + 1); + + /* + * We do not transfer more than MAX_BUF with this interface. + * If the user needs to transfer more data than this, they + * should use scsi_generics instead. + */ + if( inlen > MAX_BUF ) inlen = MAX_BUF; + if( outlen > MAX_BUF ) outlen = MAX_BUF; + + cmd_in = (char *) ( ((int *)buffer) + 2); + opcode = get_user(cmd_in); needed = buf_needed = (inlen > outlen ? inlen : outlen); if(buf_needed){ @@ -187,9 +221,27 @@ } else buf = NULL; - memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode)); - memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen); + /* + * Obtain the command from the user's address space. + */ + cmdlen = COMMAND_SIZE(opcode); + + result = verify_area(VERIFY_READ, cmd_in, + cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen); + if (result) return result; + + memcpy_fromfs ((void *) cmd, cmd_in, cmdlen); + /* + * Obtain the data to be sent to the device (if any). + */ + memcpy_fromfs ((void *) buf, + (void *) (cmd_in + cmdlen), + inlen); + + /* + * Set the lun field to the correct value. + */ cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5); #ifndef DEBUG_NO_CMD @@ -205,22 +257,25 @@ down(&sem); /* Hmm.. Have to ask about this one */ while (SCpnt->request.dev != 0xfffe) schedule(); - }; + } - /* If there was an error condition, pass the info back to the user. */ + /* + * If there was an error condition, pass the info back to the user. + */ if(SCpnt->result) { - result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer)); - if (result) - return result; - memcpy_tofs((void *) cmd_in, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); + result = verify_area(VERIFY_WRITE, + cmd_in, + sizeof(SCpnt->sense_buffer)); + if (result) return result; + memcpy_tofs((void *) cmd_in, + SCpnt->sense_buffer, + sizeof(SCpnt->sense_buffer)); } else { - - result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF : outlen); - if (result) - return result; - memcpy_tofs ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen); - }; + result = verify_area(VERIFY_WRITE, cmd_in, outlen); + if (result) return result; + memcpy_tofs ((void *) cmd_in, buf, outlen); + } result = SCpnt->result; SCpnt->request.dev = -1; /* Mark as not busy */ if (buf) scsi_free(buf, buf_needed); @@ -255,6 +310,7 @@ */ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) { + int result; char scsi_cmd[12]; /* No idea how this happens.... */ @@ -262,7 +318,9 @@ switch (cmd) { case SCSI_IOCTL_GET_IDLUN: - verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (result) return result; + put_user(dev->id + (dev->lun << 8) + (dev->host->host_no << 16) + /* This has been added to support * multichannel HBAs, it might cause diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c --- v1.3.8/linux/drivers/scsi/scsi_proc.c Fri Jul 7 08:54:50 1995 +++ linux/drivers/scsi/scsi_proc.c Tue Jul 11 07:56:04 1995 @@ -7,7 +7,7 @@ * information directly to the lowlevel driver. * * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de - * Version: 0.99.5 last change: 95/06/28 + * Version: 0.99.6 last change: 95/07/04 * * generic command parser provided by: * Andreas Heilwagen @@ -86,8 +86,7 @@ begin = 0; pos = len = sprintf(buffer, "The driver does not yet support the proc-fs\n"); - if(pos < offset) - { + if(pos < offset) { len = 0; begin = pos; } @@ -110,27 +109,23 @@ struct Scsi_Host *hpnt = scsi_hostlist; if(func != 2) { - if(ino == PROC_SCSI_SCSI) { + if(ino == PROC_SCSI_SCSI) { /* - * If there are no hosts, tell the user to go away. + * This is for the scsi core, rather than any specific + * lowlevel driver. */ - if( hpnt == NULL ) { - return (-ENOSYS); - } - - retval = scsi_proc_info(buffer, start, offset, length, - hpnt->host_no, func); - return(retval); + return(scsi_proc_info(buffer, start, offset, length, 0, func)); } while(hpnt) { - if (ino == (hpnt->host_no + PROC_SCSI_FILE)) + if (ino == (hpnt->host_no + PROC_SCSI_FILE)) { if(hpnt->hostt->proc_info == NULL) return generic_proc_info(buffer, start, offset, length, hpnt->host_no, func); else - return(hpnt->hostt->proc_info(buffer, start, offset, length, - hpnt->host_no, func)); + return(hpnt->hostt->proc_info(buffer, start, offset, + length, hpnt->host_no, func)); + } hpnt = hpnt->next; } return(-EBADF); @@ -154,8 +149,13 @@ { Scsi_Host_Template *tpnt = scsi_hosts; struct Scsi_Host *hpnt; - static char names[PROC_SCSI_LAST - PROC_SCSI_FILE][3]; uint x, y; + + /* namespace for 16 HBAs with host_no 0-999 + * I don't think we'll need more. Having more than 2 + * HBAs in one system is already highly unusual + */ + static char names[PROC_SCSI_LAST - PROC_SCSI_FILE][4]; x = y = 0; diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v1.3.8/linux/drivers/scsi/sd.c Fri Jul 7 08:54:51 1995 +++ linux/drivers/scsi/sd.c Tue Jul 11 07:56:04 1995 @@ -58,8 +58,8 @@ * Time out in seconds for disks and Magneto-opticals (which are slower). */ -#define SD_TIMEOUT 700 -#define SD_MOD_TIMEOUT 750 +#define SD_TIMEOUT (7 * HZ) +#define SD_MOD_TIMEOUT (8 * HZ) #define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \ SC->device->type != TYPE_MOD) @@ -904,7 +904,8 @@ /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is * considered a fatal error, and many devices report such an error - * just after a scsi bus reset. */ + * just after a scsi bus reset. + */ SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1); buffer = (unsigned char *) scsi_malloc(512); @@ -1177,7 +1178,7 @@ static void sd_finish() { int i; - + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; sd_gendisk.next = gendisk_head; @@ -1201,11 +1202,10 @@ * a two block (4 sector) read ahead. */ if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize) - read_ahead[MAJOR_NR] = 120; - /* 64 sector read-ahead */ + read_ahead[MAJOR_NR] = 120; /* 120 sector read-ahead */ else read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ - + return; } diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v1.3.8/linux/drivers/scsi/sg.c Fri Jul 7 08:54:51 1995 +++ linux/drivers/scsi/sg.c Tue Jul 11 07:56:04 1995 @@ -70,12 +70,16 @@ static int sg_ioctl(struct inode * inode,struct file * file, unsigned int cmd_in, unsigned long arg) { + int result; int dev = MINOR(inode->i_rdev); if ((dev<0) || (dev>=sg_template.dev_max)) return -ENXIO; switch(cmd_in) { case SG_SET_TIMEOUT: + result = verify_area(VERIFY_READ, arg, sizeof(long)); + if (result) return result; + scsi_generics[dev].timeout=get_user((int *) arg); return 0; case SG_GET_TIMEOUT: @@ -93,6 +97,11 @@ return -ENXIO; if (O_RDWR!=(flags & O_ACCMODE)) return -EACCES; + + /* + * If we want exclusive access, then wait until the device is not + * busy, and then set the flag to prevent anyone else from using it. + */ if (flags & O_EXCL) { while(scsi_generics[dev].users) @@ -106,6 +115,10 @@ scsi_generics[dev].exclude=1; } else + /* + * Wait until nobody has an exclusive open on + * this device. + */ while(scsi_generics[dev].exclude) { if (flags & O_NONBLOCK) @@ -114,7 +127,15 @@ if (current->signal & ~current->blocked) return -ERESTARTSYS; } - if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete) + + /* + * OK, we should have grabbed the device. Mark the thing so + * that other processes know that we have it, and initialize the + * state variables to known values. + */ + if (!scsi_generics[dev].users + && scsi_generics[dev].pending + && scsi_generics[dev].complete) { if (scsi_generics[dev].buff != NULL) sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len); @@ -174,6 +195,11 @@ scsi_free(buff,size); } +/* + * Read back the results of a previous command. We use the pending and + * complete semaphores to tell us whether the buffer is available for us + * and whether the command is actually done. + */ static int sg_read(struct inode *inode,struct file *filp,char *buf,int count) { int dev=MINOR(inode->i_rdev); @@ -181,6 +207,10 @@ struct scsi_generic *device=&scsi_generics[dev]; if ((i=verify_area(VERIFY_WRITE,buf,count))) return i; + + /* + * Wait until the command is actually done. + */ while(!device->pending || !device->complete) { if (filp->f_flags & O_NONBLOCK) @@ -189,6 +219,10 @@ if (current->signal & ~current->blocked) return -ERESTARTSYS; } + + /* + * Now copy the result back to the user buffer. + */ device->header.pack_len=device->header.reply_len; device->header.result=0; if (count>=sizeof(struct sg_header)) @@ -203,6 +237,11 @@ } else count=0; + + /* + * Clean up, and release the device so that we can send another + * command. + */ sg_free(device->buff,device->buff_len); device->buff = NULL; device->pending=0; @@ -210,6 +249,11 @@ return count; } +/* + * This function is called by the interrupt handler when we + * actually have a command that is complete. Change the + * flags to indicate that we have a result. + */ static void sg_command_done(Scsi_Cmnd * SCpnt) { int dev=SCpnt->request.dev; @@ -220,6 +264,11 @@ SCpnt->request.dev=-1; return; } + + /* + * See if the command completed normally, or whether something went + * wrong. + */ memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); if (SCpnt->sense_buffer[0]) { @@ -227,29 +276,44 @@ } else device->header.result=SCpnt->result; + + /* + * Now wake up the process that is waiting for the + * result. + */ device->complete=1; SCpnt->request.dev=-1; wake_up(&scsi_generics[dev].read_wait); } +#define SG_SEND 0 +#define SG_REC 1 + static int sg_write(struct inode *inode,struct file *filp,char *buf,int count) { - int dev=MINOR(inode->i_rdev); - Scsi_Cmnd *SCpnt; - int bsize,size,amt,i; - unsigned char opcode; - unsigned char cmnd[MAX_COMMAND_SIZE]; - struct scsi_generic *device=&scsi_generics[dev]; + int bsize,size,amt,i; + unsigned char cmnd[MAX_COMMAND_SIZE]; + int dev=MINOR(inode->i_rdev); + struct scsi_generic * device=&scsi_generics[dev]; + int direction; + unsigned char opcode; + Scsi_Cmnd * SCpnt; + int sgcnt; if ((i=verify_area(VERIFY_READ,buf,count))) return i; /* - * The minimum scsi command length is 6 bytes. If we get anything less than this, - * it is clearly bogus. + * The minimum scsi command length is 6 bytes. If we get anything + * less than this, it is clearly bogus. */ if (count<(sizeof(struct sg_header) + 6)) return -EIO; - /* make sure we can fit */ + + /* + * If we still have a result pending from a previous command, + * wait until the result has been read by the user before sending + * another command. + */ while(device->pending) { if (filp->f_flags & O_NONBLOCK) @@ -261,27 +325,61 @@ if (current->signal & ~current->blocked) return -ERESTARTSYS; } + + /* + * Mark the device flags for the new state. + */ device->pending=1; device->complete=0; memcpy_fromfs(&device->header,buf,sizeof(struct sg_header)); - /* fix input size */ + + /* + * fix input size, and see if we are sending data. + */ device->header.pack_len=count; buf+=sizeof(struct sg_header); - bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len; + if( device->header.pack_len > device->header.reply_len ) + { + bsize = device->header.pack_len; + direction = SG_SEND; + } else { + bsize = device->header.reply_len; + direction = SG_REC; + } + + /* + * Don't include the command header itself in the size. + */ bsize-=sizeof(struct sg_header); + + /* + * Allocate a buffer that is large enough to hold the data + * that has been requested. Round up to an even number of sectors, + * since scsi_malloc allocates in chunks of 512 bytes. + */ amt=bsize; if (!bsize) bsize++; bsize=(bsize+511) & ~511; + + /* + * If we cannot allocate the buffer, report an error. + */ if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize))) { device->pending=0; wake_up(&device->write_wait); return -ENOMEM; } + #ifdef DEBUG printk("allocating device\n"); #endif + + /* + * Grab a device pointer for the device we want to talk to. If we + * don't want to block, just return with the appropriate message. + */ if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK)))) { device->pending=0; @@ -293,39 +391,72 @@ #ifdef DEBUG printk("device allocated\n"); #endif - /* now issue command */ + + /* + * Now we need to grab the command itself from the user's buffer. + */ SCpnt->request.dev=dev; SCpnt->sense_buffer[0]=0; opcode = get_user(buf); size=COMMAND_SIZE(opcode); if (opcode >= 0xc0 && device->header.twelve_byte) size = 12; SCpnt->cmd_len = size; - amt-=device->header.pack_len>device->header.reply_len ? size : 0; + + /* + * If we are writing data, subtract off the size + * of the command itself, to get the amount of actual data + * that we need to send to the device. + */ + if( direction == SG_SEND ) + amt -= size; + /* * Verify that the user has actually passed enough bytes for this command. */ - if (count<(sizeof(struct sg_header) + size)) + if( count < (sizeof(struct sg_header) + size) ) { device->pending=0; - wake_up(&device->write_wait); - sg_free(device->buff,device->buff_len); + wake_up( &device->write_wait ); + sg_free( device->buff, device->buff_len ); device->buff = NULL; return -EIO; } + /* + * Now copy the SCSI command from the user's address space. + */ memcpy_fromfs(cmnd,buf,size); buf+=size; - memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header)); - cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5); + + /* + * If we are writing data, copy the data we are writing. The pack_len + * field also includes the length of the header and the command, + * so we need to subtract these off. + */ + if( direction == SG_SEND ) memcpy_fromfs(device->buff,buf, amt); + + /* + * Set the LUN field in the command structure. + */ + cmnd[1]= (cmnd[1] & 0x1f) | (device->device->lun<<5); + #ifdef DEBUG printk("do cmd\n"); #endif + + /* + * Now pass the actual command down to the low-level driver. We + * do not do any more here - when the interrupt arrives, we will + * then do the post-processing. + */ scsi_do_cmd (SCpnt,(void *) cmnd, (void *) device->buff,amt, sg_command_done,device->timeout,SG_DEFAULT_RETRIES); + #ifdef DEBUG printk("done cmd\n"); #endif + return count; } diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v1.3.8/linux/drivers/scsi/sr.c Fri Jul 7 08:54:51 1995 +++ linux/drivers/scsi/sr.c Tue Jul 11 07:56:04 1995 @@ -13,6 +13,10 @@ * * Modified by Eric Youngdale eric@aib.com to support loadable * low-level scsi drivers. + * + * Modified by Thomas Quinot thomas@melchior.frmug.fr.net to + * provide auto-eject. + * */ #ifdef MODULE @@ -39,7 +43,7 @@ #include "constants.h" #define MAX_RETRIES 3 -#define SR_TIMEOUT 15000 +#define SR_TIMEOUT (150 * HZ) static void sr_init(void); static void sr_finish(void); @@ -69,9 +73,13 @@ { sync_dev(inode->i_rdev); if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count) - sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); + { + sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); + if (scsi_CDs[MINOR(inode->i_rdev)].auto_eject) + sr_ioctl(inode, NULL, CDROMEJECT, 0); + } if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count) - (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--; + (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--; if(sr_template.usage_count) (*sr_template.usage_count)--; } @@ -302,6 +310,11 @@ * * kraxel@cs.tu-berlin.de (Gerd Knorr) */ +/* + * 19950704 operator@melchior.frmug.fr.net (Thomas Quinot) + * + * - SONY: Same as Nec. + */ static void sr_photocd(struct inode *inode) { @@ -481,7 +494,7 @@ printk ("sr_photocd: multisession CD detected. start: %lu\n",sector); #endif break; - + case SCSI_MAN_NEC_OLDCDR: case SCSI_MAN_UNKNOWN: default: @@ -1057,6 +1070,7 @@ scsi_CDs[i].use = 1; scsi_CDs[i].ten = 1; scsi_CDs[i].remap = 1; + scsi_CDs[i].auto_eject = 0; /* Default is not to eject upon unmount. */ sr_sizes[i] = scsi_CDs[i].capacity; } diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h --- v1.3.8/linux/drivers/scsi/sr.h Mon Feb 20 08:49:05 1995 +++ linux/drivers/scsi/sr.h Tue Jul 11 07:56:04 1995 @@ -32,6 +32,7 @@ unsigned ten:1; /* support ten byte commands */ unsigned remap:1; /* support remapping */ unsigned use:1; /* is this device still supportable */ + unsigned auto_eject:1; /* auto-eject medium on last release. */ } Scsi_CD; extern Scsi_CD * scsi_CDs; diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v1.3.8/linux/drivers/scsi/sr_ioctl.c Fri Jul 7 08:54:51 1995 +++ linux/drivers/scsi/sr_ioctl.c Tue Jul 11 07:56:04 1995 @@ -139,6 +139,10 @@ case CDROMPLAYMSF: { struct cdrom_msf msf; + + err = verify_area (VERIFY_READ, (void *) arg, sizeof (msf)); + if (err) return err; + memcpy_fromfs(&msf, (void *) arg, sizeof(msf)); sr_cmd[0] = SCMD_PLAYAUDIO_MSF; @@ -159,6 +163,10 @@ case CDROMPLAYTRKIND: { struct cdrom_ti ti; + + err = verify_area (VERIFY_READ, (void *) arg, sizeof (ti)); + if (err) return err; + memcpy_fromfs(&ti, (void *) arg, sizeof(ti)); sr_cmd[0] = SCMD_PLAYAUDIO_TI; @@ -213,7 +221,9 @@ struct cdrom_tocentry tocentry; char * buffer; - verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry)); + err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry)); + if (err) return err; + memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry)); sr_cmd[0] = SCMD_READ_TOC; @@ -267,7 +277,10 @@ return result; case CDROMEJECT: - if (scsi_CDs[target].device -> access_count != 1) + /* + * Allow 0 for access count for auto-eject feature. + */ + if (scsi_CDs[target].device -> access_count > 1) return -EBUSY; sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); @@ -281,12 +294,18 @@ return result; + case CDROMEJECT_SW: + scsi_CDs[target].auto_eject = !!arg; + return 0; + case CDROMVOLCTRL: { char * buffer, * mask; struct cdrom_volctrl volctrl; - verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl)); + err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl)); + if (err) return err; + memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl)); /* First we get the current params so we can just twiddle the volume */ diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v1.3.8/linux/drivers/scsi/st.c Fri Jul 7 08:54:51 1995 +++ linux/drivers/scsi/st.c Tue Jul 11 07:56:04 1995 @@ -83,8 +83,8 @@ #define MAX_READY_RETRIES 5 #define NO_TAPE NOT_READY -#define ST_TIMEOUT 90000 -#define ST_LONG_TIMEOUT 200000 +#define ST_TIMEOUT (900 * HZ) +#define ST_LONG_TIMEOUT (2000 * HZ) static int st_nbr_buffers; static ST_buffer **st_buffers; diff -u --recursive --new-file v1.3.8/linux/drivers/sound/.blurb linux/drivers/sound/.blurb --- v1.3.8/linux/drivers/sound/.blurb Tue May 30 13:20:32 1995 +++ linux/drivers/sound/.blurb Fri Jul 7 22:52:28 1995 @@ -1,7 +1,8 @@ - - ********************************************************* - * IF YOU HAVE ANY PROBLEMS WITH THE SOUND DRIVER, * - * PLEASE READ THE SOUND-HOWTO. IT'S AVAILABLE FROM YOUR * - * NEAREST LINUX FTP SITE AND CONTAINS ANSWER TO YOUR * - * PROBLEM. * - ********************************************************* +********************************************************* +* IF YOU HAVE ANY PROBLEMS WITH THE SOUND DRIVER, * +* PLEASE READ THE SOUND-HOWTO. IT'S AVAILABLE FROM YOUR * +* NEAREST LINUX FTP SITE AND CONTAINS ANSWER TO YOUR * +* PROBLEM. * +* Readme.cards (this directory) contains some card * +* specific instructions. * +********************************************************* diff -u --recursive --new-file v1.3.8/linux/drivers/sound/.version linux/drivers/sound/.version --- v1.3.8/linux/drivers/sound/.version Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/.version Mon Jul 10 01:42:01 1995 @@ -0,0 +1 @@ +3.0 diff -u --recursive --new-file v1.3.8/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG --- v1.3.8/linux/drivers/sound/CHANGELOG Mon Mar 6 11:22:09 1995 +++ linux/drivers/sound/CHANGELOG Mon Jul 10 01:10:38 1995 @@ -1,10 +1,39 @@ -Changelog for version 2.90 ------------------------------------- +Changelog for version 3.0 +------------------------- -This is an intermediate release (v3.0 prototype with some experimental -features disabled). See experimental.txt for more info. +Since 3.0-beta2 +- Minor fixes. +- Added Readme.cards + +Since 3.0-beta1 +- Minor fixes to the modules support. +- Eliminated call to sb_free_irq() in ad1848.c +- Rewritten MAD16&Mozart support (not tested with MAD16 Pro). +- Fix to DMA initialization of PSS cards. +- Some fixes to ad1848/cs42xx mixer support (GUS MAX, MSS, etc.) +- Fixed some bugs in the PSS driver which caused I/O errors with + the MSS mode (/dev/dsp). + +Since 3.0-950506 +- Recording with GUS MAX fixed. It works when the driver is configured + to use two DMA channels with GUS MAX (16 bit ones recommended). + +Since 3.0-94xxxx +- Too many changes + +Since 3.0-940818 +- Fixes for Linux 1.1.4x. +- Disables Disney Sound System with SG NX Pro 16 (less noise). + +Since 2.90-2 +- Fixes to soundcard.h +- Non blocking mode to /dev/sequencer +- Experimental detection code for Ensoniq Soundscape. -Since pre-3.0-949712 +Since 2.90 +- Minor and major bug fixes + +Since pre-3.0-940712 - GUS MAX support - Partially working MSS/WSS support (could work with some cards). - Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs @@ -91,7 +120,7 @@ Since 2.1 - Preliminary support for SB16. - - The SB16 mixer is supported in its native mode. + - The SB16 mixer is supported in it's native mode. - Digitized voice capability up to 44.1 kHz/8 bit/mono (16 bit and stereo support coming in the next release). - Fixed some bugs in the digitized voice driver for PAS16. diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v1.3.8/linux/drivers/sound/Makefile Fri Jan 13 17:25:07 1995 +++ linux/drivers/sound/Makefile Tue Jul 11 08:02:20 1995 @@ -5,11 +5,10 @@ # # -VERSION = 2.90-2 +VERSION = `cat .version` TARGET_OS = linux +USRINCDIR = /usr/include -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -20,15 +19,11 @@ pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \ gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o \ sb16_midi.o sound_switch.o midi_synth.o uart6850.o sound_timer.o \ - sys_timer.o ics2101.o ad1848.o pss.o + sys_timer.o ics2101.o ad1848.o pss.o sscape.o trix.o aedsp16.o \ + mad16.o all: local.h sound.a -/usr/include/sys/soundcard.h: - @echo "WARNING! Your /usr/include/sys/soundcard.h not found." - @echo "Please make a new /usr/include/sys/soundcard.h containing" - @echo "just a line #include " - sound.a: $(OBJS) -rm -f sound.a $(AR) rcs sound.a $(OBJS) @@ -36,7 +31,7 @@ clean: rm -f core core.* *.o *.a tmp_make *~ x z *% - rm -f configure sound_stub.c + rm -f configure for i in *.c;do rm -f `basename $$i .c`.s;done indent: @@ -44,38 +39,36 @@ local.h: $(MAKE) clean + $(MAKE) setup-$(TARGET_OS) $(MAKE) config $(MAKE) dep -config: configure /usr/include/sys/soundcard.h - @echo Compiling Sound Driver v $(VERSION) for Linux +config: configure + @$(MAKE) setup-$(TARGET_OS) @./configure > local.h - @echo \#define SOUND_VERSION_STRING \"$(VERSION)\" >> local.h @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h @echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h @echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h - @if [ -x /bin/dnsdomainname ]; then \ - echo \#define SOUND_CONFIG_DOMAIN \"`dnsdomainname`\"; \ - else \ - echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\"; \ - fi >> local.h + @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h clrconf: - rm -f local.h .depend + rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h -configure: configure.c /usr/include/sys/soundcard.h +configure: configure.c $(HOSTCC) -o configure configure.c @cat .blurb dep: - $(MAKE) /usr/include/sys/soundcard.h $(CPP) -M *.c > .depend -modules: +setup-linux: + @echo Compiling Sound Driver v $(VERSION) for Linux + +sound.o: $(OBJS) + -rm -f sound.o + $(LD) -r -o sound.o $(OBJS) + +modules: sound.o + (cd ../../modules; ln -fs ../drivers/sound/sound.o .) -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme linux/drivers/sound/Readme --- v1.3.8/linux/drivers/sound/Readme Thu Feb 9 18:29:53 1995 +++ linux/drivers/sound/Readme Mon Jul 10 19:13:24 1995 @@ -1,28 +1,81 @@ -VoxWare v2.90 release notes --------------------------- +Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux ftp +sites). It contains much more information than this file. +***************************************************************** +* NEW! VoxWare home page is http://personal.eunet.fi/pp/voxware * +* The file Readme.cards contains card specific instructions * +* about configuring various cards. * +***************************************************************** - This version includes some hidden features which - are described in the file experimental.txt - Some of these features are not enabled by default. Look at - experimental.txt for more info. - - I just decided to release this version with some - incompletely implemented features disabled since - there are some new features required by a popular - application. In addition there is also support - for the GUS MAX and the 16 bit sampling option of GUS. - - The MSS/WSS support works now. At least with SG NX Pro 16. - -********* IMPORTANT ***************************************** -Linux 1.0 or later is required to by this driver version. - -Don't distribute binaries which use /dev/sequencer and are -compiled with the soundcard.h of this version. They will -not work with version 2.x of the driver. -************************************************************* +VoxWare v3.0 release notes +-------------------------- +This version is the final v3.0. All features I have planned to +include in v3.0 are there but some of them are completely untested +(see experimental.txt). + +NOTE! This Linux only distribution doesn't contain files required + for other operating systems than Linux. They are distributed + in file VoxWare-3.0.tar.gz which is available from + sunsite.unc.edu:pub/Linux/kernel/sound (or pub/Linux/Incoming). + + Also some utilities for SoundScape, PSS and AudioTriX cards + have been removed. They are available in VoxWare-3.0.tar.gz and + in snd-util-3.0.tar.gz (when I have time to release it). + +*** GUS MAX enhancements ***************************************************** +Recording with GUS MAX works now. The configuration program asks +two DMA channels for GUS MAX. You have to use two different 16 bit +DMA numbers (5, 6 or 7) if you want to record (8 bit DMA channels +may or may not work). It's still possible to use just one DMA channel +with GUS MAX but recording doesn't work in this case (a hardware limitation). +Even the driver has capability to use two DMA channels, simultaneous recording +and playback is not possible with GUS MAX (will not be before v4.0 +of the driver). However it's now possible to play using /dev/dsp and /dev/dsp1 +at the same time (or /dev/dsp and /dev/sequencer as well). +Recording using /dev/dsp1 will not work if GUS MAX is configured to use two +DMA channels. +****************************************************************************** + +There are some additional device files (since v2.90-2 andv3.0-proto-94mmdd +versions). +You will need to create additional device files using the script at the +end of ./linux/Readme. Also recompile all mixer programs since there are +some new channels that are not enabled in mixers compiled with older +soundcard.h. + +There are some programming information (little bit old) in the +Hacker's Guide +(ftp://nic.funet.fi/pub/OS/Linux/ALPHA/sound/snd-sdk-doc-0.1.ps.gz). +Believe me: The file is really there. The directory is just hidden and +you have to cd into it before the file is visible. + +I have got many patches from various persons during last year. Some of +them are still on my mailbox and they should be included in versions +after v3.0 (I will not add aditional features before v3.0 is ready). + + ==================================================== +- THIS VERSION ____REQUIRES____ Linux 1.2.0 OR LATER. + ==================================================== + +- THIS VERSION MAY NOT WORK WITH Linux VERSIONS RELEASED + AFTER end of July 1995. If this version doesn't compile with + your kernel version, please use the sound driver version + included in your kernel. +- Ensoniq SoundScape support is included in this version but it's + somehow incomplete. MIDI recording may not work and you have to + use /dev/dsp1 and /dev/audio1 (/dev/dsp and /dev/audio don't work). + I recommend you recreate the device files used by the driver by + running the script at the end of linux/Readme. Then just + rm /dev/dsp;ln -s /dev/dsp1 /dev/dsp (and the same with /dev/audio). + You will also need the latest version of the soundscape.co[01] file. + The old sndscape.cod will ___NOT___ work (it propably just hangs your + system completely). The latest code file is available from ftp.ensoniq.com + as part of the DOS/Windows driver distribution. See sndscape/ssinit.c + for more info. +- This is Linux only version. It should work in other operating systems + (SCO, UW, FreeBSD and NetBSD) too but may require some fixes before + it compiles. You will need the snd-util-2.5.tar.gz and snd-data-0.1.tar.Z packages to use this driver. They should be in the same @@ -32,55 +85,187 @@ If you are looking for the installation instructions, please look at linux/Readme. +Supported soundcards +-------------------- + +Gravis Ultrasound (GUS) +GUS MAX +GUS with the 16 bit sampling daughtercard +PAS16 +Windows Sound System compatible soundcards +ECHO-PSS (cards based on the PSS architecture by Analog Devices. + Including Orchid SW32, Cardinal DSP16 among others). + (NOTE! WSS mode may not work (DMA channel setup problem)). +MediaTriX AudioTriX Pro (OPL4 and the optional effect daughtercard + require special initialization. There is a program (setfx) in + the audiotrix directory which does it). +Ensoniq SoundScape (works but needs some improvements) +MV Jazz16 based soundcards (ProSonic, 3D etc). +SoundMan Wave (recording may not work, mixer support is limited) +Mozart (OAK OTI-601 interface chip) based soundcards. +MAD16 (an interface chip by OPTi) based soundcards (TB Tropez ???). +(NOTE! The MAD16 looks similar to the Mozart chip. It could be a good +idea to configure MAD16 cards as Mozart ones. The MAD16 driver doesn't set +up MPU401 which the Mozart one does. + +In addition all Sound Blaster models and clones (up to AWE32) work if +you want to use them. + +The Emu synthesizer chip of AWE32 is not and will not be supported. The same is +true with the ASP chip also. Creative Technology will not release detailed +information about them so it's not possible to support them. + +If you want to get support for AWE32 or ASP, please contact Creative Labs. +Ask _politely_ if they are going to support Linux. Maybe they change +their policy if there is enough demand. + +=========================================================================== +If your card is compatible with SB, MPU401 or Windows Sound System, it +may work with the driver even if it's not listed in the above list. In this +case it may require initialization using DOS. Just start DOS and cold +boot to Linux (etc.) by hitting ctrl-alt-del. +=========================================================================== + Compatibility with the earlier versions --------------------------------------- -This version is backward compatible with the version 2.X. All programs -compiled with sys/soundcard.h of v2.X should work without problems. -PROGRAMS COMPILED WITH THE sys/soundcard.h OF THIS VERSION WILL NOT -WORK WITH v2.X DRIVER. BE CAREFUL WHEN DISTRIBUTING BINARIES COMPILED -FOR THIS VERSION. +There have been some changes in soundcard.h after v2.5 of the driver +(v2.90 is compatible with this one). Binaries compiled with this version +of soundcard.h will not work with v2.0 and earlier. Contributors ------------ This driver contains code by several contributors. In addition several other -persons have given useful suggestions. The following is a list of major +persons have given usefull suggestions. The following is a list of major contributors. (I could have forgotten some names.) Craig Metz 1/2 of the PAS16 Mixer and PCM support Rob Hooft Volume computation algorithm for the FM synth. Mika Liljeberg uLaw encoding and decoding routines + Andy Fingerhut New ulaw conversion tables (ulaw.h) + Jeff Tranter Linux SOUND HOWTO document Greg Lee Volume computation algorithm for the GUS and lot's of valuable suggestions. Andy Warner ISC port - Jim Lowe FreeBSD port + Jim Lowe, + Amancio Hasty Jr FreeBSD/NetBSD port Anders Baekgaard Bughunting and valuable suggestions. Joerg Schubert SB16 DSP support. Andrew Robinson Improvements to the GUS driver Megens SA MIDI recording for SB and SB Pro. - Mikael Nordqvist Linear volume support for GUS. - Mikael Nordqvist Linear volume support for GUS. + Mikael Nordqvist Linear volume support for GUS and + nonblocking /dev/sequencer. Ian Hartas SVR4.2 port Markus Aroharju and Risto Kankkunen Major contributions to the mixer support of GUS v3.7. Hunyue Yau Mixer support for SG NX Pro. Marc Hoffman PSS support. + Rainer Vranken Initialization for Jazz16 (ProSonic, MV3D, SM Wave). + Peter Trattler Loadable module support for Linux. + JRA Gibson 16 bit mode for Jazz16 + Davor Jadrijevic MAD16 support + Gregor Hoffleit Mozart support + Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support + +There are propably many other names missing. If you have sent me some +patches and your name is not in the above list, please inform me. + +Sponsors etc. +------------- + +The following companies have greatly helped development of this driver +in form of a free copy of their product: + +Novell Inc, UnixWare personal edition + SDK +Ensoniq Corp, a SoundScape card and extensive amount of assistance +MediaTriX Peripherals Inc, a AudioTriX Pro card + SDK + +In addition the following companies have provided me sufficial amount +of technical information at least some of their products (free or $$$): + +Advanced Gravis Computer Technology Ltd. +Media Vision Inc. +Analog Devices Inc. +Logitech Inc. +Aztech Labs Inc. +Crystal Semiconductor Corporation, +Integrated Circuit Systems Inc. +OAK Technology +OPTi +Ad Lib Inc. ($$) +Music Quest Inc. ($$) +Creative Labs ($$$) + +If you have some problems +========================= + +Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?). + +It's likely that you have some problems when trying to use the sound driver +first time. Soundcards don't have standard configuration so there are no +good default configuration to use. Please try to use same I/O, DMA and IRQ +values for the soundcard than with DOS. + +If you get an error message when trying to use the driver, please look +at /var/adm/messages for more verbose error message. + + +In general the easiest way to diagnoze problems is to do "cat /dev/sndstat". + +If you get an error message, there are some problems with the driver setup: + + - "No such file or directory" tells that the device files for + the sound driver are missing. Use the script at the end of + linux/drivers/sound/Readme.linux to create them. + + - "No such device" telss that the sound driver is not in the kernel. + You have to reconfigure and recompile the kernel to have the sound + driver. Compiling the driver doesn't help alone. You have to boot + with the newly compiled one before the driver becomes active. + The Linux-HOWTO should help in this step. + +The following errors are likely with /dev/dsp and /dev/audio. + + - "No such device or address". This error message should not happen + with /dev/sndstat but it's possible with the other sound devices. + This error indicates that there are no suitable hardware for the + device file or the sound driver has been compiled without support for + this particular device. For example /dev/audio and /dev/dsp will not + work if "digitized voice support" was not enabled during "make config". + + - "Device or resource busy". Propably the IRQ (or DMA) channel + required by the soundcard is in use by some other device/driver. + + - "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict. + Look at the kernel messages in /var/adm/notice for more info. + + - "Invalid argument". The application is calling ioctl() + with impossible parameters. Check that the application is + for sound driver version 2.X or later. + +In general the printout of of /dev/sndstat should tell what is the problem. +It's possible that there are bugs in the sound driver but 99% of the problems +reported to me are caused by somehow incorrect setup during "make config". + +Hannu Regards, Hannu Savolainen hannu@voxware.pp.fi +(or Hannu.Savolainen@cctap.carel.fi in case the above bounces) Snail mail: Hannu Savolainen Hiekkalaiturintie 3 A 8 00980 Helsinki Finland -FAX: +358 0 341 6272 (answers if I have my machine (mgetty) on). -NOTE! I probably don't answer to Snail mail or FAX messages. Sending answer +NOTE! I propably don't answer to Snail mail or FAX messages. Sending answer to each of them is simply too expensive and time consuming. However I - try to reply every email message I get (within a week). If you don't + try to reply every email message I get (within a week). If you don't get response, please check how your address is written in the message header. I can't answer if I don't have a valid reply address. + +VoxWare home page is http://personal.eunet.fi/pp/voxware diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.aedsp16 linux/drivers/sound/Readme.aedsp16 --- v1.3.8/linux/drivers/sound/Readme.aedsp16 Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/Readme.aedsp16 Fri Apr 28 03:54:01 1995 @@ -0,0 +1,6 @@ +Informations about Audio Excel DSP 16 can be found in the source +file aedsp16.c +Please, read the head of the source before using it. It contain useful +informations. + + Riccardo diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards --- v1.3.8/linux/drivers/sound/Readme.cards Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/Readme.cards Mon Jul 10 00:59:31 1995 @@ -0,0 +1,770 @@ +Configuring VoxWare 3.0 (for Linux) with some most common soundcards +==================================================================== + +NOTE! This document may contain some error. Please inform me + if you find any mistakes. + +Read this before trying to configure the driver +----------------------------------------------- + +There are currently many cards that work with VoxWare. Some of the cards +have native support while the others work since they emulate some other +cards (usually SB, MSS/WSS and/or MPU401). The following cards have native +support in VoxWare. Detailed instructions for configuring these cards +will be given later in this document. + +Pro Audio Spectrum 16 (PAS16) and compatibles: + Pro Audio Spectrum 16 + Pro Audio Studio 16 + Logitech Sound Man 16 + NOTE! The original Pro Audio Spectrum as well as the PAS+ are not + and will not be supported by VoxWare. + +Media Vision Jazz16 based cards + Pro Sonic 16 + Logitech SoundMan Wave + (Other Jazz based cards should work but I don't have any reports + about them). + +Sound Blasters + SB 1.0 to 2.0 + SB Pro + SB 16 + NOTE! The ASP chip and the EMU synth of the AWE32 is not supported + since their manufacturer doesn't release information about + the card. However both the AB16ASP and the AWE32 work with + VoxWare just like a SB16. Also see the comment about some + unsupported cards at the end of this file. + SB16 compatible cards by other manufacturers than Creative. + You have been fooled since there are no SB16 compatible + cards in the market (July95). It's likely that your card + is compatible just with SB Pro but there is also a non SB + compatible 16 bit mode. Usually it's MSS/WSS but could also + be a proprietary one like MV Jazz16. + +Gravis Ultrasound (GUS) + GUS + GUS + the 16 bit option + GUS MAX + (GUS ACE ????????????) + +MPU-401 and compatibles + The driver works both with the full (intelligent mode) MPU-401 + cards (such as MPU IPC-T and MQX-32M) and with the UART only + dumb MIDI ports. MPU-401 is currently the most common MIDI + interface. Most soundcards are compatible with it. However + don't enable MPU401 mode blindly. Many cards having native support + in VoxWare have their own MPU401 driver. Enabling the standard one + will cause a conflict with these cards. So look if your card is + in the list of supported cards before enabling MPU401. + +Windows Sound System (MSS/WSS) + Even Microsoft has discontinued their own Sound System card, they + managed to make a standard. MSS compatible cards are based on a + codec chip which is easily available from at least two manufacturers + (AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor). + Currently most soundcards are based on one of the MSS compatible codec + chip. The CS4231 is used in the high quality cards such as GUS MAX, + MediaTriX AudioTriX Pro and TB Tropez. + + Having a AD1848, CS4248 or CS4231 codec chip on the card is a good + sign. Even if the card is not MSS compatible, it could be easy to write + support for it to VoxWare. Note also that most MSS compatible cards + require special boot time initialization which may not be present + in VoxWare. Also some MSS compatible cards have native support in + VoxWare. Enabling the MSS support with these cards is likely to + cause a conflict. So check if your card is listed in this file before + enabling the MSS support. + +6850 UART MIDI + This UART chip is used in the MIDI interface of some (rare) + soundcards. It's supported by VoxWare in case you need it. + +Yamaha FM synthesizers (OPL2, OPL3 and OPL4) + Most soundcards have a FM synthesizer chip. The OPL2 is a 2 + operator chip used in the original AdLib card. Currently it's used + only in the cheapest (8 bit mono) cards. The OPL3 is a 4 operator + FM chip which provides better sound quality and/or more available + voices than the OPL2. The OPL4 is a new chip which has a OPL3 and + a wave table synthesizer packed on the same chip. VoxWare supports + just the OPL3 mode directly. Most cards having a OPL4 (like + SM Wave and AudioTriX Pro) support the OPL4 mode using MPU401 + emulation. Writing a native OPL4 support to VoxWare is difficult + since Yamaha doesn't give information about their sample ROM chip. + + Enable the generic OPL2/OPL3 FM synthesizer support if your + card has a FM chip made by Yamaha. Don't enable it if your card + has a software (TRS) based FM emulator. + +PSS based cards (AD1848 + ADSP-2115 + Echo ESC614 ASIC) + Analog Devices and Echo Speech have together defined a soundcard + architecture based on the above chips. The DSP chip is used + for emulation of SB Pro, FM and General MIDI/MT32. + + There are several cards based on this architecture. The most known + ones are Orchid SW32 and Cardinal DSP16. + + VoxWare supports downloading DSP algorithms to these cards. + +MediaTriX AudioTriX Pro + The ATP card is built around a CS4231 codec and a OPL4 synthesizer + chips. The OPL4 mode is supported by a microcontroller running a + General MIDI emulator. There is also SB 1.5 playback mode. + +Ensoniq SoundScape and compatibles + Ensoniq has designed a soundcard architecture based on the + OTTO synthesizer chip used in their professional MIDI synthesizers. + Several companies (including Ensoniq, Reveal and Spea) are selling + cards based on this architecture. + +MAD16 and Mozart based cards + The Mozart (OAK OTI-601) and MAD16 Pro (OPTi 82C929) interface + chips are used in many different soundcards, including some + cards by Reveal and Turtle Beach (Tropez). Purpose of these + chips is to connect other audio components to the PC bus. The + interface chip performs address decoding for the other chips. + +Audio Excell DSP16 + Support for this card is made by Riccardo Faccetti + (riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info. + +What if your card was not listed above? +--------------------------------------- + +The first thing to do is to look at the major IC chips on the card. +Many of the latest soundcards are based on some standard chips. If you +are lucky, all of them could be supported by VoxWare. The most common ones +are the OPTi MAD16, Mozart, SoundScape (Ensoniq) and the PSS architectures +listed above. Also look at the end of this file for list of unsupported +cards and the ones which could be supported later. + +The last resort is to send _exact_ name and model information of the card +to me together with a list of the major IC chips (manufactured, model) to +me. I could then try to check if your card looks like something familiar. + +There are much more cards in the word than listed above. The first thing to +do with these cards is to check if they emulate some other card/interface +such as SB, MSS and/or MPU401. In this case there is a chance to get the +card to work by booting DOS before starting Linux (boot DOS, hit ctrl-alt-del +and boot Linux without hard resetting the machine). In this method the +DOS based driver initializes the hardware to use a known I/O, IRQ and DMA +settings. If VoxWare is configured to use the same settings, everything should +work OK. + + +Configuring VoxWare (with Linux) +================================ + +VoxWare sound driver is currently a part of Linux kernel distribution. The +driver files are located in directory /usr/src/linux/drivers/sound. + +**************************************************************************** +* VoxWare MUST BE CONFIGURED AND COMPILED WITH THE KERNEL. TRYING * +* TO COMPILE IT ALONE WILL _NOT_ WORK. * +* * +* ALWAYS USE THE SOUND DRIVER VERSION WHICH IS DISTRIBUTED WITH * +* THE KERNEL SOURCE PACKAGE YOU ARE USING. SOME ALPHA AND BETA TEST * +* VERSIONS CAN BE INSTALLED FROM A SEPARATELY DISTRIBUTED PACKAGE * +* BUT CHECK THAT THE PACKAGE IS NOT MUCH OLDER (OR NEWER) THAN THE * +* KERNEL YOU ARE USING. IT'S POSSIBLE THAT THE KERNEL/DRIVER * +* INTERFACE CHANGES BETWEEN KERNEL RELEASES WHICH MAY CAUSE SOME * +* INCOMPATIBILITY PROBLEMS. * +* * +* IN CASE YOU INSTALL A SEPARATELY DISTRIBUTED SOUND DRIVER VERSION, * +* BE SURE TO REMOVE OR RENAME THE OLD SOUND DRIVER DIRECTORY BEFORE * +* INSTALLING THE NEW ONE. LEAVING OLD FILES TO THE SOUND DRIVER * +* DIRECTORY _WILL_ CAUSE PROBLEMS WHEN THE DRIVER IS USED OR * +* COMPILED. * +**************************************************************************** + +To configure the driver, run "make config" in the kernel source directory +(/usr/src/linux). Answer y to the question about Sound card support (after +questions about mouse, CD-ROM, ftape, etc. supports). Sound config options +will then be asked after some additional questions. + +After configuring the kernel and sound driver, run "make dep" and compile +the kernel following instructions in the kernel README. + +The sound driver configuration dialog +------------------------------------- + +All config information of the sound driver is written to file +linux/drivers/sound/local.h. You may save the old version is this file and +use it again in case you want to use the same config later. In this case +just answer n to each question made by the sound config program and put +the original local.h back before running "make dep". +Don't do this if the version number of the sound driver has changed. In this +case you have to enter the configuration information again. + +If you already have the sound driver installed, consult printout of +"cat /dev/sndstat" when configuring the driver again. It gives the I/O, +IRQ and DMA settings you have used earlier. + + +The sound config program (linux/drivers/sound/configure) starts by making +some yes/no questions. Be careful when answering to these questions since +answering y to a question may prevent some later ones from being asked. For +example don't answer y to the first question (PAS16) if you don't really +have a PAS16. Don't enable more cards than you really need since they +just consume memory. Also some drivers (like MPU401) may conflict with your +SCSI controller and prevent kernel from booting. If you card was in the list +of supported cards (above), please look at the card specific config +instructions (later in this file) before starting to configure. Some cards +must be configured in way which is not obvious. + +So here is the beginning of the config dialog. Answer 'y' or 'n' to these +questions. The default answer is shown so that (y/n) means 'y' by default and +(n/y) means 'n'. To use the default value, just hit ENTER. But be careful +since using the default _doesn't_ guarantee anything. + +Note also that all questions may not be asked. The configuration program +may disable some questions dependig on the earlier choices. It may also +select some options automaticly as well. + + "ProAudioSpectrum 16 support", + - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_, + ProAudio Studio 16 or Logitech SoundMan 16 (be sure that + you read the above list correctly). Don't answer 'y' if you + have some other card made by Media Vision or Logitech since they + are not PAS16 compatible. + "SoundBlaster support", + - Answer 'y' if you have an original SB card made by Creative Labs + or a full 100% hardware compatible clone (like Thunderboard or + SM Games). If your card was in the list of supported cards (above), + please look at the card specific instructions later in this file + before answering this question. For an unknown card you may answer + 'y' if the card claims to be SB compatible. + "Generic OPL2/OPL3 FM synthesizer support", + - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). + Answering 'y' is usually a safe and recommended choice. However some + cards may have software (TSR) FM emulation. Enabling FM support + with these cards may cause trouble. However I don't currently know + such cards. + "Gravis Ultrasound support", + - Answer 'y' if you have GUS or GUS MAX. Answer 'n' if you don't + have GUS since the GUS driver consumes much memory. + Currently I don't have experiences with the GUS ACE so I don't + know what to answer with it. + "MPU-401 support (NOT for SB16)", + - Be careful with this question. The MPU401 interface is supported + by almost any soundcard today. However some natively supported cards + have their own driver for MPU401. Enabling the MPU401 option with + these cards wil cause a conflict. Also enabling MPU401 on a system + that doesn't really have a MPU401 could cause some trouble. If your + card was in the list of supported cards (above), please look at + the card specific instructions later in this file. + It's safe to answer 'y' if you have a true MPU401 MIDI interface + card. + "6850 UART Midi support", + - It's safe to answer 'n' to this question in all cases. The 6850 + UART interface is so rarely used. + "PSS (ECHO-ADI2111) support", + - Answer 'y' only if you have Orchid SW32, Cardinal DSP16 or some + other card based on the PSS chipset (AD1848 codec + ADSP-2115 + DSP chip + Echo ESC614 ASIC CHIP). + "16 bit sampling option of GUS (_NOT_ GUS MAX)", + - Answer 'y' if you have installed the 16 bit sampling daughtercard + to your GUS. Answer 'n' if you have GUS MAX. Enabling this option + disables GUS MAX support. + "GUS MAX support", + - Answer 'y' only if you have a GUS MAX. + "Microsoft Sound System support", + - Again think carefully before answering 'y' to this question. It's + safe to answer 'y' in case you have the original Windows Sound + System card made by Microsoft or Aztech SG 16 Pro (or NX16 Pro). + Also you may answer 'y' in case your card was not listed earlier + in this file. For cards having native support in VoxWare, consult + the card specific instructions later in this file. Some drivers + have their own MSS support and enabling this option wil cause a + conflict. + "Ensoniq Soundscape support", + - Answer 'y' if you have a soundcard based on the Ensoniq SoundScape + chipset. Suach cards are being manufactured at least by Ensoniq, + Spea and Reveal (note that Reveal makes other cards also). + "MediaTriX AudioTriX Pro support", + - Answer 'y' if you have the AudioTriX Pro. + "Support for MAD16 and/or Mozart based cards", + - Answer y if your card has a Mozart (OAK OTI-601) or MAD16 + (OPTi 82C928 or 82C929) audio interface chip. These chips are + currently quite common so it's possible that many no-name cards + have one of them. In addition the MAD16 chip is used in some + cards made by known manufacturers such as Turtle Beach (Tropez), + Reveal (some models) and Diamond (latest ones). + "SoundBlaster Pro support", + - Enable this option if your card is SB Pro or SB16. Enable it + also with any SB Pro clones. Answering 'n' saves some amount of + memory but 'y' is the safe alterative. + "SoundBlaster 16 support", + - Enable if you have a SB16 (including the AWE32). + "Audio Excel DSP 16 initialization support", + - Don't know much about this card. Look at aedsp16.c for more info. + +Then the configuration program asks some y/n questions about the higher +level services. It's recommended to answer 'y' to each of these questions. +Answer 'n' only if you know you will not need the option. + + "/dev/dsp and /dev/audio supports (usually required)", + - Answering 'n' disables /dev/dsp and /dev/audio. Answer 'y'. + "MIDI interface support", + - Answering 'n' disables /dev/midi## devices and access to any + MIDI ports using /dev/sequencer and /dev/music. This option + also affects any MPU401 and/or General MIDI compatible devices. + "FM synthesizer (YM3812/OPL-3) support", + - Answer 'y' here. + "/dev/sequencer support", + - Answering 'n' disables /dev/sequencer and /dev/music. + +Entering the I/O, IRQ and DMA config parameters +----------------------------------------------- + +After the above questions the configuration program prompts for the +card specific configuration information. Usually just a set of +I/O address, IRQ and DMA numbers are asked. With some cards the program +asks for some files to be used during initialization of the card. For example +many cards have a DSP chip or microprocessor which must be initialized by +downloading a program (microcode) file to the card. In some cases this file +is written to a .h file by the config program and then included to the driver +during compile. + +Instructions for answering these questions are given in the next section. + + +Card specific information +========================= + +This section gives additional instructions about configuring some cards. +Please refer manual of your card for valid I/O, IRQ and DMA numbers. Using +the same settings with DOS/Windows and VoxWare is recommended. Using +different values could cause some problems when switching between +different operating systems. + +SoundBlasters (the original ones by Creative) +--------------------------------------------- + +It's possible to configure these cards to use different I/O, IRQ and +DMA settings. Since the available settings have changed between various +models, you have to consult manual of your card for the proper ones. It's +a good idea to use the same values than with DOS/Windows. With SB and SB Pro +it's the only choice. SB16 has software selectable IRQ and DMA channels but +using different values with DOS and Linux is likely to cause troubles. The +DOS driver is not able to reset the card properly after warm boot from Linux +if Linux has used different IRQ or DMA values. + +The original (steam) Sound Blaster (versions 1.x and 2.x) use always +DMA1. There is no way to change it. + +The SB16 needs two DMA channels. A 8 bit one (1 or 3) is required for +8 bit operation and a 16 bit one (5, 6 or 7) for the 16 bit mode. In theory +it's possible to use just one (8 bit) DMA channel by answering the 8 bit +one when the configuration program asks for the 16 bit one. This may work +in some systems but is likely to cause terrible noise on some other systems. + +NOTE! Don't enable the SM Games option (asked by the configuration program) + if you are not 101% sure that your card is a Logitech Soundman Games + (not a SM Wave or SM16). + +SB Clones +--------- + +First of all: There are no SB16 clones. There are SB Pro clones with a +16 bit mode which is not SB16 compatible. The most likely alternative is that +the 16 bit mode means MSS/WSS. + +There are just few fully 100% hardware SB or SB Pro compatible cards. +I know just Thunderboard and SM Games. Other cards require some kind of +hardware initialization before they become SB compatible. Check if your card +was listed in the beginning of this file. In this case you should follow +instructions for your card later in this file. + +For other not fully SB clones yoy may try initialization using DOS in +the following way: + + - Boot DOS so that the card specific driver gets run. + - Hit ctrl-alt-del (or use loadlin) to boot Linux. Don't + switch off power or press the reset button. + - If you use the same I/O, IRQ and DMA settings in Linux, the + card should work. + +If your card is both SB and MSS compatible, I recommend using the MSS mode. +Most cards of this kind are not able to work in the SB and the MSS mode +simultaneously. Using the MSS mode provides 16 bit recording and playback. + +ProAudioSpectrum 16 and compatibles +----------------------------------- + +There are nothing special with these cards. Just don't enable any +other cards in case you don't have them also. The PAS16 has +a SB mode so the driver config program will prompt for the SB settings +do. Use I/O 0x220 and DMA1 for the SB mode. Ensure that you assign different +IRQ numbers for the SB and PAS16 modes. + +With PAS16 you can use two audio devices at the same time. /dev/dsp (and +/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and +/dev/audio1) is connected to the SB emulation (8 bit mono only). + +Gravis Ultrasound +----------------- + +There are many different revisions of the Ultrasound card (GUS). The +earliest ones (pre 3.7) don't have a hardware mixer. With these cards +the driver uses a software emulation for synth and pcm playbacks. It's +also possible to switch some of the inputs (line in, mic) off by setting +mixer volume of the channel level below 10%. For recording you have +to select the channel as a recording source and to use volume above 10%. + +GUS 3.7 has a hardware mixer. + +GUS MAX and the 16 bit sampling daughtercard have a CS4231 codec chip which +also contains a mixer. + +Configuring GUS is simple. Just enable the GUS support and GUS MAX or +the 16 bit daughtercard if you have them. Note that enabling the daughter +card disables GUS MAX. + +With just the standard GUS enabled the configuration program prompts +for the I/O, IRQ and DMA numbers for the card. Use the same values than +with DOS. + +With the daughter card option enabled you will be prompted for the I/O, +IRQ and DMA numbers for the daughter card. You have to use different I/O +and DMA values than for the standard GUS. The daughter card permits +simultaneous recording and playback. Use /dev/dsp (the daughtercard) for +recording and /dev/dsp1 (GUS GF1) for playback. + +GUS MAX uses the same I/O address and IRQ settings than the original GUS +(GUS MAX = GUS + a CS4231 codec). In addition an extra DMA channel may be used. +Using two DMA channels permits simultaneous playback using two devices but +simultaneous recording and playback is not possible (not before v4.0). +Also using two DMA channels is required if you want to record in 16 bit modes. +To enable the second DMA channels, give a valid DMA channel when the config +program asks for the GUS MAX DMA (entering 0 disables the second DMA). +Using 16 bit DMA channels (5,6 or 7) is recommended. The drawback of +using two DMA channels with GUS MAX is that recording from /dev/dsp1 +(the 8 bit codec) is disabled. + +It's not guaranteed that recording using GUS MAX works (in 3.0-beta2). + +MPU401 and Windows Sound System +------------------------------- + +Again. Don't enable these options in case your card is listed +somewhere else in this file. + +Configuring these cards is obvious (or it should be). With MSS +you should propably enable the OPL3 synth also since +most MSS compatible cards have it. However check that this is true +before enabling OPL3. + +VoxWare supports more than one MPU401 compatible cards at the same time +but the config program asks config info for just the first of them. +Adding the second or third MPU interfaces must be done manually by +editing sound/local.h (after running the config program). Add defines for +MPU2_BASE & MPU2_IRQ (and MPU3_BASE & MPU3_IRQ) to the file. + +PSS +--- + +Even the PSS cards are compatible with SB, MSS and MPU401, you must not +enable these options when configuring the driver. The configuration +program handles these options itself. (You may use the SB, MPU and MSS options +together with PSS if you have another card on the system). + +The PSS driver enables MSS and MPU401 modes of the card. SB is not enabled +since it doesn't work concurrently with MSS. The driver loads also a +DSP algorithm which is used to for the general MIDI emulation. The +algorithm file (.ld) is read by the config program and written to a +file included when the pss.c is compiled. For this reason the config +program asks if you want to download the file. Use the genmidi.ld file +distributed with the DOS/Windows drivers of the card (don't use the mt32.ld). +With some cards the file is called 'synth.ld'. You must have access to +the file when configuring the driver. The easiest way is to mount the DOS +partition containing the file with Linux. + +It's possible to load your own DSP algorithms and run them with the card. +Look at the directory sound/pss_test for more info (in the VoxWare-3.0.tar.gz) +package. + +AudioTriX Pro +------------- + +You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition +to the native AudioTriX driver. You don't need to enable MSS or MPU drivers. + +Configuring ATP is little bit tricky since it uses so many I/O, IRQ and +DMA numbers. Using the same values than with DOS/Win is a good idea. Don't +attemp to use the same IRQ or DMA channels twice. + +The SB mode of ATP is implemented so the the ATP driver just enables SB +in the proper address. The SB driver handles the rest. Yoy have to configure +both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O +settings. + +Also the ATP has a microcontroller for the General MIDI emulation (OPL4). +For this reason the driver asks for the name of a file containing the +microcode (TRXPRO.HEX). This file is usually located in the directory +where the DOS drivers were installed. You must have access to this file +when configuring the driver. + +IMPORTANT!!!!!!!!!!! + +The OPL4/OPL3 chip and the (optional) effects daughtercard require +initialization after boot. Since information about the effect processor +is not public, the initialization must be done by running a special program +after boot. The setfx program is distributed in Linux binary form (only) +in directory sound/audiotrix (of VoxWare-3.0.tar.gz package). +It's calls ioperm() so it must be run as root. + +Another way to initialize the effects processor (and OPL4) is to boot DOS +before running Linux. + +Ensoniq SoundScape +------------------ + +The SoundScape driver handles initialization of MSS and MPU supports +itself so you don't need to enable other drivers than SoundScape +(enable also the /dev/dsp, /dev/sequencer and MIDI supports). + +SoundScape driver uses the MSS compatible codec of the card. It's important +to note that /dev/dsp0 (/dev/dsp is linked to /dev/dsp0 by default) +doesn't work with SoundScape (yet). The 'ssinit' program needs /dev/dsp0 so +that's the reason why it's there. It's possible that 'primary' pcm channel +becomes supported later. Currently the card's firmware doesn't contain +support for it. + +With 3.0 of VoxWare you have to change your system to use /dev/dsp1 by default +so execute: cd /dev;rm dsp;ln -s dsp1 dsp after you have installed VoxWare +3.0 (first time). + +The configuration program asks two DMA channels and two interrupts. One IRQ +and one DMA is used by the MSS codec. The second IRQ is required for the +MPU401 mode (you have to use different IRQs for both purposes). +The second DMA channel is required for initialization of the microcontroller. + +The SoundScape card has a Motorola microcontroller which must initialized +_after_ boot (the driver doesn't initialize it during boot). +The initialization is done by running the 'ssinit' program which is +distributed in directory sound/sndscape. You have to edit two +defines in the ssinit.c and then compile the program. You may run ssinit +manually (after each boot) or add it to /etc/rc.d/rc.local. + +The ssinit program needs the microcode file that comes with the DOS/Windows +driver of the card. You will need to use version 1.30.00 or later +of the microcode file (sndscape.co0 or sndscape.co1 depending on +your card model). THE OLD sndscape.cod WILL NOT WORK. IT WILL HANG YOUR +MACHINE. The only way to get the new microcode file is to download +and install the DOS/Windows driver from ftp://ftp.ensoniq.com/pub. + +Then you have to select the proper microcode file to use: soundscape.co0 +is the right one for most cards and sndscape.co1 is for few (older) cards +made by Reveal and/or Spea. The driver has capability to detect the card +version during boot. Look at the boot log messages in /var/adm/messages +and locate the sound driver initialization message for the SoundScape +card. If the driver displays string , you have +an old card and you will need to use sndscape.co1. For other cards use +soundscape.co0. + +Check /var/adm/messages after running ssinit. The driver prints +the board version after downloading the microcode file. That version +number must match the number in the name of the microcode file (extension). + +Running ssinit with a wrong version of the sndscape.co? file is not +dangerous as long as you don't try to use a file called sndscape.cod. +If you have initialized the card using a wrong microcode file (sounds +are terrible), just modify ssinit.c to use another microcode file and try +again. It's possible to use an earlier version of sndscape.co[01] but it +may sound wierd. + +Btw, The driver may complain something about "sscapeintr()" after +running ssinit. You should just ignore these messages. + +MAD16 (Pro) and Mozart +---------------------- + +You need to enable just the MAD16 /Mozart support when configuring +the driver. Don't enable SB, MPU401 or MSS. However you will need the +/dev/audio, /dev/sequencer and MIDI supports. + +Mozart and OPTi 82C928 (the original MAD16) chips don't support +MPU401 mode so enter just 0 when the configuration program asks the +MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) has MPU401 mode. + +TB Tropez is based on the 82C929 chip. However it has two MIDI ports. +The one connected to the MAD16 chip is the second one (there is a second +MIDI connector/pins somewhere??). If you have not connected the second MIDI +port, just disable the MIDI port of MAD16. The 'Maui' compatible synth of +Tropez is jumper configurable and not connected to the MAD16 chip. + +There are some other OPTi chips which may be used in soundcards such as +82C930 and MAC32. These chips are not supported by VoxWare yet. Please +contact me if you have a soundcard which uses these chips. + +MV Jazz (ProSonic) +------------------ + +The Jazz16 driver is just a hack made to the SB Pro driver. However it works +fairly well. You have to enable SB, SB Pro (_not_ SB16) and MPU401 supports +when configuring the driver. The configuration program asks later if you +want support for MV Jazz16 based cards (after asking SB base address). Answer +'y' here and the driver asks the second (16 bit) DMA channel. + +The Jazz16 driver uses the MPU401 driver in a way which will cause +problems if you have another MPU401 compatible card. In this case you must +give address of the Jazz16 based MPU401 interface when the config +program prompts for the MPU401 information. Then look at the MPU401 +spesific section for instructions about configuring more than one MPU401 cards. + +Logitech Soundman Wave +---------------------- + +Read the above MV Jazz spesific instructions first. + +The Logitech SoundMan Wave (don't confuse with the SM16 or SM Games) is +a MV Jazz based card which has an additional OPL4 based wave table +synthesizer. The OPL4 chip is handled by an on board microcontroller +which must be initialized during boot. The config program asks if +you have a SM Wave immediately after asking the second DMA channel of jazz16. +If you answer 'y', the config program will ask name of the file containing +code to be loaded to the microcontroller. The file is usually called +MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file +may also be called as TSUNAMI.BIN or something else (older cards?). + +The OPL4 synth will be riunaccessible without loading the microcontroller code. + +NOTE! Don't answer 'y' when the driver asks about SM Games support + (the next question after the MIDI0001.BIN name). However + aneswering 'y' is not dangerous. + +Sound Galaxies +-------------- + +There are many different Sound Galaxy cards made by Aztech. The 8 bit +ones are fully SB or SB Pro compatible and there should be no problems +with them. + +The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have +an EEPROM chip for storing the configuration data. There is a microcontroller +which initializes the card to match the EEPROM settigs when the machine +is powered on. These cards actually behave just like they have jumpers +for all of the settings. Configure VoxWare for MSS, MPU, SB/SB Pro and OPL3 +supports with these cards. + +The config program asks if you want support for the mixer of +SG NX Pro. Answer 'y' to these questions if you have one of the above 8 or +16 bit Aztech cards. + +There are some new Sound Galaxies in the market. I have no experience with +them so read the card's manual carefully. + + +Reveal cards +------------ + +There are several different cards made/marketed by Reveal. Some of them +are compatible with SoundScape and some use the MAD16 chip. You may have +to look at the card and try to identify origin of the card. + +Diamond +------- + +The oldest (Sierra Aria based) soundcards made by Diamond are not supported +(they may work if the card is initialized using DOS). The recent (LX?) +models are based on the MAD16 chip which is supported by VoxWare. + +Audio Excel DSP16 +----------------- + +See aedsp16.c. + +Others? +------- + +Since there are so many different soundcards, it's likely that I have +forgotten to mention many of them. Please inform me if you know yet another +card which works with Linux, please inform me (or is anybody else +willing to maintain a database of supported cards (just like in XF86)?). + +Cards not supported yet +======================= + +First of all. There is an easy way to make most soundcards to work +with Linux. Just use the DOS based driver to initialize the card +to a _known_ state. Then ctrl-alt-del to Linux. If Linux is configured +to use the sama I/O, IRQ and DMA numbers than DOS, the card could work. + +Don't get fooled with SB compatibility. Most cards are compatible with +SB but that may require a TSR which is not possible with Linux. If +the card is compatible with MSS, it's a better choise. Some cards +don't work in the SB and MSS modes at the same time. + +There are some cards which will be supported by VoxWare sooner or later +(currently at least cards based on the ESS chipset). Such cards are +so common that there is some idea in writing the driver. Check the +VoxWare home page (http://personal.eunet.fi/pp/voxware) for latest +information. + +Then there are cards which are no longer manufactured and/or which +are relatively rarely used (such as the 8 bit ProAudioSpectrum +models). It's extremely unlikely that such cards never get supported. +Adding support for a new card requires much work and increases time +required in maintaining the driver (some changes need to be done +to all low level drivers and be tested too, maybe with multiple +operating systems). For this reason I have made a desicion to not support +obsolete cards. It's possible that someone else makes a separately +distributed driver (diffs) for the card. Version v4.0 will be much more +modular so making separately distributed drivers will be easier with it. +(The bad news is that v4.0 will not be available before late -96). + +Writing a driver for a new card is not possible if there are no +programming information available about the card. If you don't +find your new card from this file, look from the home page +(http://personal.eunet.fi/pp/voxware). Then please contact +manufacturer of the card and ask if they have (or are willing to) +released technical details of the card. Do this before contacting me. I +can only answer 'no' if there are no programming information available. + +Some companies don't give low level technical information about their +products to public or at least their require signing a NDA. + +I have also made decicion to not accept code based on reverse engineering +to VoxWare. There are three main reasons: First I don't want to break +relationships to sound card manufacturers. The second reason is that +maintaining and supporting a driver withoun any specs will be a pain. The +third reason is that why shoud we help such companies in selling their +products to Linux users when they don't want to sell to Linux users +at all? + +Unfortunately many of the leading soundcard manufacturers are not willing +to co-operate with Linux/Unix community. For example: Creative Technology +doesn't give information about the ASP chip and the Emu synth chip of AWE32 +and SB32. Turtle Beach don't give information about any of their +products. MediaVision requires NDA before they are willing to +give information about the Jazz16 chip (fortunately Logitech gave +the info about SM Wave). + +So at least the above three companies are out until they are willing to +release documentation about their products (the situation is the +same with many DOS based freeware/shareware games and utilities). If +you want to use Linux/Unix with their cards, please don't try to push +me. It's a better idea to contact the manufacturer and explain that +you want to use your card with Linux/Unix. You could also try to sell +your card to somebody else and then buy a card that is supported by VoxWare. + +However it's possible that things change and a driver gets written +for some of the banned cards. Please, don't send me messages asking if +there is any plans to write a driver for the cards mentioned above. I +will put any news to the VoxWare www home page (see below). + +There are some common audio chipsets that are supported yet. For example +the ESS chips and Sierra Aria. It's likely that these architectures +get some support in future but I can't make any promises. Just look +at the home page for latest info. + +Information about unsupported soundcards and chipsets is welcome as well +as free copies of soundcards, SDKs and operating systems. + +If you have any corrections and/or comments, please contact me. + +Hannu Savolainen +hannu@voxware.pp.fi +VoxWare www home page: http://personal.eunet.fi/pp/voxware + diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux --- v1.3.8/linux/drivers/sound/Readme.linux Fri Aug 19 08:54:07 1994 +++ linux/drivers/sound/Readme.linux Mon Jul 10 01:02:10 1995 @@ -1,11 +1,18 @@ Installation ------------ +IMPORTANT! Read this if you are installing a separately + distributed version of this driver. + Check that your kernel version works with this + release of the driver (see Readme). Also verify + that your current kernel version doesn't have more + recent sound driver version than this one. + - Since you are reading this, you have already installed the files so let's skip this step. To be serious, the sound driver belongs to linux/drivers/sound. -- To build the device files you need to run the enclosed shell script +- To build the device files you need to run the enclosed shell scrip (see below). - If you are installing a separately distributed version, copy the @@ -23,6 +30,20 @@ Boot time configuration (using lilo) ------------------------------------ +NOTE! This information is little bit obsolete since it doesn't cover + some cards recently added to the driver. + +------------------------------------------------------------------- +NOTE2! This method to configure the sound driver is not normally + required. All configuration information is entered when the + kernel/driver is compiled. This method just gives a way + to override some configuration parameters during boot. + + So THE METHOD PRESENTED IN THIS CHAPTER IS NORMALLY COMPLETELY + USELESS. DON'T USE IT UNLESS YOU HAVE A VERY SPECIAL REASON TO + DO THAT. +------------------------------------------------------------------- + This version of the sound driver has capability to accept the configuration parameters from the boot loader (for example lilo). By default the driver is booted using the parameters given before compiling the driver @@ -52,7 +73,7 @@ 6=SB16 (16 bit DMA number) 7=SB16 Midi (MPU-401 emulation) (There are some new ones also but they are currently - not documented). + not documented. The card numbers are in soundcard.h). These are the configuration templates for various soundcards: @@ -68,7 +89,7 @@ sound=0x2220Id,0x138800 (remember to set the IRQ and DMA) or if you have SB16 or SB16ASP, you have to use the following: - (use the same IRQ (the I columns) in all three places. The + (use the same IRQ (the I colums) in all three places. The the D is the 16 bit DMA channel (5 to 7) and the d is the 8 bit one (1 or 3). The X is the 2nd digit of the midi IO address (3 or 0)). @@ -134,7 +155,7 @@ cat /dev/sndstat -and look at the output. It should display some useful info about the +and look at the output. It should display some usefull info about the driver configuration. If there is no /dev/sndstat (/dev/sndstat: No such file or directory), ensure that you have executed the soundinstall script (at the end of this file). The message: @@ -147,7 +168,7 @@ - /dev/???????: No such device. You have not booted with a kernel containing the driver or the I/O address -configuration doesn't match your hardware. +configuration doesn't match your hardaware. - The module player (str) plays just a second and then stops completely. You have incorrect IRQ settings (usual with SB cards). @@ -159,7 +180,7 @@ UltraSound card. (If you already have GUS, you should use gmod and not the str). If the DSP_BUFFSIZE in the sound/local.h is less than (nr_channels* speed_in_Hz * (bits/8))/2, it could explain the pausing problem. Also check -that the turbo switch is on and don't run applications like weather forecasting +that the turbo swich is on and don't run applications like weather forecasting on background. Sometimes (very rarely) an IRQ conflict can cause similar problems with SB cards. If you want to play modules on a 386sx while recompiling the world, buy a GUS. @@ -171,7 +192,7 @@ ----------------- cut here ------------------------------ #!/bin/sh # -# soundinstall +# soudinstall # # # Create the devices @@ -205,51 +226,66 @@ fi mknod -m 666 /dev/patmgr1 c 14 33 -### # Sequencer2 (14, 8) -### # -### if [ -e /dev/sequencer2 ]; then -### rm -f /dev/sequencer2 -### fi -### mknod -m 666 /dev/sequencer2 c 14 8 + # music (14, 8) + # + if [ -e /dev/music ]; then + rm -f /dev/music + fi + + mknod -m 666 /dev/music c 14 8 + if [ -e /dev/sequencer2 ]; then + rm -f /dev/sequencer2 + fi + ln -s /dev/music /dev/sequencer2 # Midi devices # if [ -e /dev/midi ]; then rm -f /dev/midi # Old name. Don't use it fi -### if [ -e /dev/midi00 ]; then -### rm -f /dev/midi00 -### fi -### mknod -m 666 /dev/midi00 c 14 2 -### -### if [ -e /dev/midi01 ]; then -### rm -f /dev/midi01 -### fi -### mknod -m 666 /dev/midi01 c 14 18 -### -### if [ -e /dev/midi02 ]; then -### rm -f /dev/midi02 -### fi -### mknod -m 666 /dev/midi02 c 14 34 -### -### if [ -e /dev/midi03 ]; then -### rm -f /dev/midi03 -### fi -### mknod -m 666 /dev/midi03 c 14 50 + if [ -e /dev/midi00 ]; then + rm -f /dev/midi00 + fi + mknod -m 666 /dev/midi00 c 14 2 + + if [ -e /dev/midi01 ]; then + rm -f /dev/midi01 + fi + mknod -m 666 /dev/midi01 c 14 18 + + if [ -e /dev/midi02 ]; then + rm -f /dev/midi02 + fi + mknod -m 666 /dev/midi02 c 14 34 + + if [ -e /dev/midi03 ]; then + rm -f /dev/midi03 + fi + mknod -m 666 /dev/midi03 c 14 50 # # DSP (14, 3) # if [ -e /dev/dsp ]; then rm -f /dev/dsp fi -mknod -m 666 /dev/dsp c 14 3 +if [ -e /dev/dsp0 ]; then + rm -f /dev/dsp0 +fi +mknod -m 666 /dev/dsp0 c 14 3 +ln -s /dev/dsp0 /dev/dsp + # # SPARC compatible /dev/audio (14, 4) # if [ -e /dev/audio ]; then rm -f /dev/audio fi -mknod -m 666 /dev/audio c 14 4 +if [ -e /dev/audio0 ]; then + rm -f /dev/audio0 +fi +mknod -m 666 /dev/audio0 c 14 4 +ln -s /dev/audio0 /dev/audio + # # DSP1 (14, 19) /dev/dsp for the second soundcard. # Also the SB emulation part of the diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.modules linux/drivers/sound/Readme.modules --- v1.3.8/linux/drivers/sound/Readme.modules Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/Readme.modules Wed Jan 2 02:30:41 1980 @@ -0,0 +1,87 @@ + Linux sound-driver module + (c) Peter Trattler + License: GPL (Gnu Public License) + + +Idea: + +I've modified the sources for the sound driver to allow simply insert and +remove the sound driver from the kernel by calling (only available for Linux) + + insmod /usr/src/linux/modules/sound.o + +and + + rmmod sound + +This may be useful if you are doing one of the following things: + +1) Debugging the sound driver +2) Creating a new device within the sound-driver +3) You do not the sound driver all the time (as it wastes quite a lot of +memory for its buffers) + + +Compilation: + +Go to /usr/src/linux and make the following steps: + +a) configure the sound driver: To do that call "make config" and enable the +sound-driver -- you will be asked different questions about your +sound-hardware (remember not to use a too big DMA-Buffer size; you +should use 16kB, if you have 16Bit devices, otherwise you can use 32kB) + +b) disable the sound driver in the kernel: call make config again but answer +'N' to "Sound card support" + +c) run "make modules"; the sound-driver sound.o should end up in +/usr/src/linux/modules + + +If memory is tight: + +I've allocated at about 70kB for the sound-drivers internal tables. If this +is too much, 'insmod sound.o' will generate the following warning +... +use 'insmod memsize=xxxx' +... +You can only use this command, if you have (I think) at least +modules-1.1.87 or up. You can also switch debugging on by running the command + +insmod sound.o debugmem=1 + + +Files I changed: + +I've only changed the files soundcard.c(most changes) and some changes within +the Makefile, sound_config.h and the Makefile in /usr/src/linux/drivers + + +Bugs: + +a) As the kmalloc (..., GFP_DMA) caused some unexpected errors (I don't know if +it is my fault), I created some code, which is (by default) enabled by + +#define KMALLOC_DMA_BROKEN 1 (within soundcard.c). + +It trys to allocate a large enough region, so that the complete dma-buffer +can be occupied in this space. If it does not fit within this region it +doubles the size of it. But this can cause problems, if the sound-buffer is +too big (as kmalloc can only handle regions at up to circa 100kB). + +So take care to use for 8Bit devices a sound-DMA-buffer of 32kB (maximum) +and for 16Bit devices a maximum of 16kB. Otherwise the allocation scheme +might fail. + +b) Buffers allocated by the different sound devices via calls to kmalloc are +not freed, if the sound driver is removed again (these buffers tend to be +quite small -- so it does not harm a lot) + +c) If there is not enough (kernel-) memory available, the installation of +the sound-driver fails. (This happens quite often, if you did not install the +driver right after booting -- [PS: I've only got 5MB of Ram, so this might +be the source for this problem]) + + +Author: + Peter Trattler (peter@sbox.tu-graz.ac.at) diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.v30 linux/drivers/sound/Readme.v30 --- v1.3.8/linux/drivers/sound/Readme.v30 Mon Mar 6 11:22:09 1995 +++ linux/drivers/sound/Readme.v30 Mon Jul 10 01:00:58 1995 @@ -1,38 +1,24 @@ VoxWare v3.0 ------------ -This is a PROTOTYPE of the VoxWare v3.0 to be released late 94. - -All features of v2.5 should work as earlier. There could be some +All features of v2.90-2 should work as earlier. There could be some omissions but they are unintentional. I started this version thread after v2.3 so all features implemented before it are there. -Even this is a prototype, there should not be any fatal bugs. The -prototype just means that I don't have implemented all features -completely. Mainly in the /dev/sequencer2 driver. -For example recording from /dev/sequencer2 won't work -with other cards than a full features MPU-401 or clones. As well the -way how the MIDI controllers are handled will change. - -IMPORTANT!!!!!!!!!!!!!!!!! - -Don't distribute any binaries compiled with the soundcard.h of this version. -They will not work together with older drivers. - New features ============ There are now two new device interfaces. The /dev/midi## is a raw tty like interface to MIDI ports. There is a device file for each MIDI port on your system. They are named (/dev/midi00 to /dev/midiNN). -The second addition is the /dev/sequencer2 which is higher level interface +The second addition is the /dev/music which is higher level interface than the old /dev/sequencer. It's intended for writing device independent applications like sequencers. /dev/midi## ----------- -This interface should be useful for applications like MIDI sysex librarians. +This interface should be usefull for applications like MIDI sysex librarians. There are (currently) no timing features so making music could be impossible. There are as many /dev/midi## devices as there are MIDI ports in the system. @@ -67,7 +53,7 @@ If this ioctl is called with mode=1, the interface is put to the intelligent (coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called. It could have some strange effects if not called immediately after open. This -call returns EINVAL if the midi port doesn't support the MPU-401 intelligent +vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent mode. ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port @@ -95,15 +81,15 @@ data Buffer for the command arguments and returned data. -Be extremely careful with the nr_args and nr_returns fields. They +Be extremely carefull with the nr_args and nr_returns fields. They must match the command. An incorrect value will put the card and the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further -details. +datails. -/dev/sequencer2 (if you find a better name, please let me know). ---------------- +/dev/music (/dev/sequencer2) +---------------------------- This device file works much like the /dev/sequencer which has been present since the beginning. The main differences are the following: @@ -113,7 +99,7 @@ /dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE() like macros. The voice number parameters of the API macros have been redefined to denote MIDI channels. This means that the driver allocates voices for -the channels automatically (this is a responsibility/right of an application +the channels automaticly (this is a responsibility/right of an application with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has similar effects for a synth channel than on a MIDI port. This kind of solution provides better device independence than the /dev/sequencer. The @@ -130,15 +116,15 @@ - The new interface is used much like the ordinary /dev/sequencer. The event format is new so you have to use the API macros defined in the -sys/soundcard.h. The interface will probably change before the final 3.0 +sys/soundcard.h. The interface is will propably change before the final 3.0 release but using the API macros should ensure compatibility in source level. The new event format is not recognized by version 2.X so don't try to distribute binaries compiled with soundcard.h of v3.X. -- The basic API usage is similar to the current one. There are some new +- The basic API useage is similar to the current one. There are some new macros but the older ones should work as earlier. The most important incompatibility is that the /dev/sequencer2 driver allocates voices itself. -The other one is that the application must send SEQ_START_TIMER() as its +The other one is that the application must send SEQ_START_TIMER() as it's first event. Otherwise the timer is not started and the application waits infinitely. diff -u --recursive --new-file v1.3.8/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v1.3.8/linux/drivers/sound/ad1848.c Mon Mar 6 11:22:09 1995 +++ linux/drivers/sound/ad1848.c Mon Jul 10 01:45:02 1995 @@ -7,7 +7,7 @@ * The CS4231 which is used in the GUS MAX and some other cards is * upwards compatible with AD1848 and this driver is able to drive it. * - * Copyright by Hannu Savolainen 1994 + * Copyright by Hannu Savolainen 1994, 1995 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -29,6 +29,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * Modified: + * Riccardo Facchetti 24 Mar 1995 + * - Added the Audio Excel DSP 16 initialization routine. */ #define DEB(x) @@ -37,6 +40,8 @@ #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848) +#include "ad1848_mixer.h" + #define IMODE_NONE 0 #define IMODE_OUTPUT 1 #define IMODE_INPUT 2 @@ -44,25 +49,33 @@ #define IMODE_MIDI 4 typedef struct -{ - int base; - int irq; - int dma_capture, dma_playback; - unsigned char MCE_bit; - - int speed; - unsigned char speed_bits; - int channels; - int audio_format; - unsigned char format_bits; - - int xfer_count; - int irq_mode; - int intr_active; - int opened; - char *chip_name; - int mode; -} + { + int base; + int irq; + int dma_capture, dma_playback; + int dual_dma; /* 1, when two DMA channels allocated */ + unsigned char MCE_bit; + unsigned char saved_regs[16]; + + int speed; + unsigned char speed_bits; + int channels; + int audio_format; + unsigned char format_bits; + + int xfer_count; + int irq_mode; + int intr_active; + int opened; + char *chip_name; + int mode; + + /* Mixer parameters */ + int recmask; + int supported_devices; + int supported_rec_devices; + unsigned short levels[32]; + } ad1848_info; @@ -71,7 +84,10 @@ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static int ad_format_mask[3 /*devc->mode*/ ] = +static char mixer2codec[MAX_MIXER_DEV] = +{0}; + +static int ad_format_mask[3 /*devc->mode */ ] = { 0, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, @@ -93,12 +109,17 @@ static int ad1848_prepare_for_IO (int dev, int bsize, int bcount); static void ad1848_reset (int dev); static void ad1848_halt (int dev); +void ad1848_interrupt (INT_HANDLER_PARMS (irq, dummy)); static int ad_read (ad1848_info * devc, int reg) { unsigned long flags; int x; + int timeout = 900000; + + while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */ + timeout--; DISABLE_INTR (flags); OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc)); @@ -113,6 +134,10 @@ ad_write (ad1848_info * devc, int reg, int data) { unsigned long flags; + int timeout = 90000; + + while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */ + timeout--; DISABLE_INTR (flags); OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc)); @@ -122,50 +147,331 @@ } static void -ad_set_MCE (ad1848_info * devc, int state) -{ - unsigned long flags; - - DISABLE_INTR (flags); - if (state) - devc->MCE_bit = 0x40; - else - devc->MCE_bit = 0x00; - OUTB (devc->MCE_bit, io_Index_Addr (devc)); - RESTORE_INTR (flags); -} - -static void wait_for_calibration (ad1848_info * devc) { int timeout = 0; /* - * Wait until the auto calibration process has finished. - * - * 1) Wait until the chip becomes ready (reads don't return 0x80). - * 2) Wait until the ACI bit of I11 gets on and then off. - */ + * Wait until the auto calibration process has finished. + * + * 1) Wait until the chip becomes ready (reads don't return 0x80). + * 2) Wait until the ACI bit of I11 gets on and then off. + */ timeout = 100000; - while (timeout > 0 && INB (devc->base) == 0x80) + while (timeout > 0 && INB (devc->base) & 0x80) timeout--; - if (INB (devc->base) == 0x80) + if (INB (devc->base) & 0x80) printk ("ad1848: Auto calibration timed out(1).\n"); - timeout = 100000; + timeout = 100; while (timeout > 0 && !(ad_read (devc, 11) & 0x20)) timeout--; if (!(ad_read (devc, 11) & 0x20)) - printk ("ad1848: Auto calibration timed out(2).\n"); + return; - timeout = 100000; + timeout = 20000; while (timeout > 0 && ad_read (devc, 11) & 0x20) timeout--; if (ad_read (devc, 11) & 0x20) printk ("ad1848: Auto calibration timed out(3).\n"); } +static void +ad_mute (ad1848_info * devc) +{ + int i; + unsigned char prev; + + /* + * Save old register settings and mute output channels + */ + for (i = 6; i < 8; i++) + { + prev = devc->saved_regs[i] = ad_read (devc, i); + ad_write (devc, i, prev | 0x80); + } +} + +static void +ad_unmute (ad1848_info * devc) +{ + int i; + + /* + * Restore back old volume registers (unmute) + */ + for (i = 6; i < 8; i++) + { + ad_write (devc, i, devc->saved_regs[i] & ~0x80); + } +} + +static void +ad_enter_MCE (ad1848_info * devc) +{ + unsigned long flags; + int timeout = 1000; + unsigned short prev; + + while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */ + timeout--; + + DISABLE_INTR (flags); + + devc->MCE_bit = 0x40; + prev = INB (io_Index_Addr (devc)); + if (prev & 0x40) + { + RESTORE_INTR (flags); + return; + } + + OUTB (devc->MCE_bit, io_Index_Addr (devc)); + RESTORE_INTR (flags); +} + +static void +ad_leave_MCE (ad1848_info * devc) +{ + unsigned long flags; + unsigned char prev; + int timeout = 1000; + + while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */ + timeout--; + + DISABLE_INTR (flags); + + devc->MCE_bit = 0x00; + prev = INB (io_Index_Addr (devc)); + OUTB (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */ + + if (prev & 0x40 == 0) /* Not in MCE mode */ + { + RESTORE_INTR (flags); + return; + } + + OUTB (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */ + wait_for_calibration (devc); + RESTORE_INTR (flags); +} + + +static int +ad1848_set_recmask (ad1848_info * devc, int mask) +{ + unsigned char recdev; + int i, n; + + mask &= devc->supported_rec_devices; + + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; + + if (n == 0) + mask = SOUND_MASK_MIC; + else if (n != 1) /* Too many devices selected */ + { + mask &= ~devc->recmask; /* Filter out active settings */ + + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; + + if (n != 1) + mask = SOUND_MASK_MIC; + } + + switch (mask) + { + case SOUND_MASK_MIC: + recdev = 2; + break; + + case SOUND_MASK_LINE: + case SOUND_MASK_LINE3: + recdev = 0; + break; + + case SOUND_MASK_CD: + case SOUND_MASK_LINE1: + recdev = 1; + break; + + default: + mask = SOUND_MASK_MIC; + recdev = 2; + } + + recdev <<= 6; + ad_write (devc, 0, (ad_read (devc, 0) & 0x3f) | recdev); + ad_write (devc, 1, (ad_read (devc, 1) & 0x3f) | recdev); + + devc->recmask = mask; + return mask; +} + +static void +change_bits (unsigned char *regval, int dev, int chn, int newval) +{ + unsigned char mask; + int shift; + + if (mix_devices[dev][chn].polarity == 1) /* Reverse */ + newval = 100 - newval; + + mask = (1 << mix_devices[dev][chn].nbits) - 1; + shift = mix_devices[dev][chn].bitpos; + newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ + + *regval &= ~(mask << shift); /* Clear bits */ + *regval |= (newval & mask) << shift; /* Set new value */ +} + +static int +ad1848_mixer_get (ad1848_info * devc, int dev) +{ + if (!((1 << dev) & devc->supported_devices)) + return RET_ERROR (EINVAL); + + return devc->levels[dev]; +} + +static int +ad1848_mixer_set (ad1848_info * devc, int dev, int value) +{ + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + + int regoffs; + unsigned char val; + + if (left > 100) + left = 100; + if (right > 100) + right = 100; + + if (dev > 31) + return RET_ERROR (EINVAL); + + if (!(devc->supported_devices & (1 << dev))) + return RET_ERROR (EINVAL); + + if (mix_devices[dev][LEFT_CHN].nbits == 0) + return RET_ERROR (EINVAL); + + /* + * Set the left channel + */ + + regoffs = mix_devices[dev][LEFT_CHN].regno; + val = ad_read (devc, regoffs); + change_bits (&val, dev, LEFT_CHN, left); + devc->levels[dev] = left | (left << 8); + ad_write (devc, regoffs, val); + devc->saved_regs[regoffs] = val; + + /* + * Set the left right + */ + + if (mix_devices[dev][RIGHT_CHN].nbits == 0) + return left | (left << 8); /* Was just a mono channel */ + + regoffs = mix_devices[dev][RIGHT_CHN].regno; + val = ad_read (devc, regoffs); + change_bits (&val, dev, RIGHT_CHN, right); + ad_write (devc, regoffs, val); + devc->saved_regs[regoffs] = val; + + devc->levels[dev] = left | (right << 8); + return left | (right << 8); +} + +static void +ad1848_mixer_reset (ad1848_info * devc) +{ + int i; + + devc->recmask = 0; + if (devc->mode == 2) + devc->supported_devices = MODE2_MIXER_DEVICES; + else + devc->supported_devices = MODE1_MIXER_DEVICES; + + devc->supported_rec_devices = MODE1_REC_DEVICES; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + ad1848_mixer_set (devc, i, devc->levels[i] = default_mixer_levels[i]); + ad1848_set_recmask (devc, SOUND_MASK_MIC); +} + +static int +ad1848_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) +{ + ad1848_info *devc; + + int codec_dev = mixer2codec[dev]; + + if (!codec_dev) + return RET_ERROR (ENXIO); + + codec_dev--; + + devc = (ad1848_info *) audio_devs[codec_dev]->devc; + + if (((cmd >> 8) & 0xff) == 'M') + { + if (cmd & IOC_IN) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, ad1848_set_recmask (devc, IOCTL_IN (arg))); + break; + + default: + return IOCTL_OUT (arg, ad1848_mixer_set (devc, cmd & 0xff, IOCTL_IN (arg))); + } + else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, devc->recmask); + break; + + case SOUND_MIXER_DEVMASK: + return IOCTL_OUT (arg, devc->supported_devices); + break; + + case SOUND_MIXER_STEREODEVS: + return IOCTL_OUT (arg, devc->supported_devices & + ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); + break; + + case SOUND_MIXER_RECMASK: + return IOCTL_OUT (arg, devc->supported_rec_devices); + break; + + case SOUND_MIXER_CAPS: + return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT); + break; + + default: + return IOCTL_OUT (arg, ad1848_mixer_get (devc, cmd & 0xff)); + } + } + else + return RET_ERROR (EINVAL); +} + static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] = { { @@ -186,6 +492,12 @@ NULL }}; +static struct mixer_operations ad1848_mixer_operations = +{ + "AD1848/CS4248/CS4231", + ad1848_mixer_ioctl +}; + static int ad1848_open (int dev, int mode) { @@ -209,23 +521,55 @@ } if (devc->irq) /* Not managed by another driver */ - if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt)) < 0) + if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt, + audio_devs[dev]->name)) < 0) { printk ("ad1848: IRQ in use\n"); RESTORE_INTR (flags); return err; } +/* + * Allocate DMA + */ + + if (mode & OPEN_WRITE) + audio_devs[dev]->dmachan = devc->dma_playback; + else + audio_devs[dev]->dmachan = devc->dma_capture; + if (DMAbuf_open_dma (dev) < 0) { RESTORE_INTR (flags); + if (devc->irq) /* Don't leave IRQ reserved */ + snd_release_irq (devc->irq); + printk ("ad1848: DMA in use\n"); return RET_ERROR (EBUSY); } + devc->dual_dma = 0; + + if (devc->dma_capture != devc->dma_playback && mode == OPEN_READWRITE) + { + devc->dual_dma = 1; + + if (ALLOC_DMA_CHN (devc->dma_capture, "Sound System (capture)")) + { + if (devc->irq) /* Don't leave IRQ reserved */ + snd_release_irq (devc->irq); + DMAbuf_close_dma (dev); + return RET_ERROR (EBUSY); + } + } + devc->intr_active = 0; devc->opened = 1; RESTORE_INTR (flags); +/* + * Mute output until the playback really starts. This decreases clicking. + */ + ad_mute (devc); return 0; } @@ -245,8 +589,18 @@ snd_release_irq (devc->irq); ad1848_reset (dev); DMAbuf_close_dma (dev); + + if (devc->dual_dma) /* Release the second DMA channel */ + { + if (audio_devs[dev]->dmachan == devc->dma_playback) + RELEASE_DMA_CHN (devc->dma_capture); + else + RELEASE_DMA_CHN (devc->dma_playback); + } + devc->opened = 0; + ad_unmute (devc); RESTORE_INTR (flags); } @@ -254,18 +608,18 @@ set_speed (ad1848_info * devc, int arg) { /* - * The sampling speed is encoded in the least significant nibble of I8. The - * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other - * three bits select the divisor (indirectly): - * - * The available speeds are in the following table. Keep the speeds in - * the increasing order. - */ + * The sampling speed is encoded in the least significant nible of I8. The + * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other + * three bits select the divisor (indirectly): + * + * The available speeds are in the following table. Keep the speeds in + * the increasing order. + */ typedef struct - { - int speed; - unsigned char bits; - } + { + int speed; + unsigned char bits; + } speed_struct; static speed_struct speed_table[] = @@ -296,7 +650,7 @@ if (arg > speed_table[n - 1].speed) selected = n - 1; - for (i = 1 /*really*/ ; selected == -1 && i < n; i++) + for (i = 1 /*really */ ; selected == -1 && i < n; i++) if (speed_table[i].speed == arg) selected = i; else if (speed_table[i].speed > arg) @@ -338,11 +692,11 @@ { static struct format_tbl - { - int format; - unsigned char bits; - } - format2bits [] = + { + int format; + unsigned char bits; + } + format2bits[] = { { 0, 0 @@ -460,6 +814,8 @@ cnt = count; + audio_devs[dev]->dmachan = devc->dma_playback; + if (devc->audio_format == AFMT_IMA_ADPCM) { cnt /= 4; @@ -487,31 +843,43 @@ if (dma_restart) { - ad1848_halt (dev); + /* ad1848_halt (dev); */ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); } - ad_set_MCE (devc, 1); + ad_enter_MCE (devc); ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - - ad_write (devc, 9, 0x0d); /* + if (devc->dma_playback == devc->dma_capture) + { + ad_write (devc, 9, 0x0d); /* * Playback enable, single DMA channel mode, * auto calibration on. */ + } + else + { + ad_write (devc, 9, 0x09); /* + * Playback enable, dual DMA channel mode. + * auto calibration on. + */ + } - ad_set_MCE (devc, 0); /* + ad_leave_MCE (devc); /* * Starts the calibration process and * enters playback mode after it. */ - wait_for_calibration (devc); + ad_unmute (devc); devc->xfer_count = cnt; devc->irq_mode = IMODE_OUTPUT; devc->intr_active = 1; + INB (io_Status (devc)); + OUTB (0, io_Status (devc)); /* Clear pending interrupts */ RESTORE_INTR (flags); + } static void @@ -520,7 +888,7 @@ unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - /* int count_reg = (devc->mode == 1) ? 14 : 30; */ + audio_devs[dev]->dmachan = devc->dma_capture; cnt = count; if (devc->audio_format == AFMT_IMA_ADPCM) @@ -550,38 +918,45 @@ if (dma_restart) { - ad1848_halt (dev); + /* ad1848_halt (dev); */ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); } - ad_set_MCE (devc, 1); -#if 0 - ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff)); - ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff)); -#else - ad_write (devc, 15, (unsigned char) (cnt & 0xff)); - ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - if (devc->mode == 2) + ad_enter_MCE (devc); + + if (devc->dma_playback == devc->dma_capture) /* Single DMA channel mode */ { - ad_write (devc, 31, (unsigned char) (cnt & 0xff)); - ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff)); - } -#endif + ad_write (devc, 15, (unsigned char) (cnt & 0xff)); + ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - ad_write (devc, 9, 0x0e); /* + ad_write (devc, 9, 0x0e); /* * Capture enable, single DMA channel mode, * auto calibration on. */ + } + else + /* Dual DMA channel mode */ + { + ad_write (devc, 31, (unsigned char) (cnt & 0xff)); + ad_write (devc, 30, (unsigned char) ((cnt >> 8) & 0xff)); - ad_set_MCE (devc, 0); /* + ad_write (devc, 9, 0x0a); /* + * Capture enable, dual DMA channel mode, + * auto calibration on. + */ + } + + ad_leave_MCE (devc); /* * Starts the calibration process and * enters playback mode after it. */ - wait_for_calibration (devc); + ad_unmute (devc); devc->xfer_count = cnt; devc->irq_mode = IMODE_INPUT; devc->intr_active = 1; + INB (io_Status (devc)); + OUTB (0, io_Status (devc)); /* Clear interrupt status */ RESTORE_INTR (flags); } @@ -594,7 +969,7 @@ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; DISABLE_INTR (flags); - ad_set_MCE (devc, 1); /* Enables changes to the format select reg */ + ad_enter_MCE (devc); /* Enables changes to the format select reg */ fs = devc->speed_bits | (devc->format_bits << 5); if (devc->channels > 1) @@ -602,41 +977,32 @@ ad_write (devc, 8, fs); /* - * Write to I8 starts resynchronization. Wait until it completes. + * Write to I8 starts resyncronization. Wait until it completes. */ timeout = 10000; while (timeout > 0 && INB (devc->base) == 0x80) timeout--; - ad_set_MCE (devc, 0); /* - * Starts the calibration process and - * enters playback mode after it. - */ - wait_for_calibration (devc); - RESTORE_INTR (flags); - /* - * If mode == 2 (CS4231), set I28 also. It's the capture format register. - */ + * If mode == 2 (CS4231), set I28 also. It's the capture format register. + */ if (devc->mode == 2) { - ad_set_MCE (devc, 1); ad_write (devc, 28, fs); /* - * Write to I28 starts resynchronization. Wait until it completes. - */ + * Write to I28 starts resyncronization. Wait until it completes. + */ timeout = 10000; while (timeout > 0 && INB (devc->base) == 0x80) timeout--; - ad_set_MCE (devc, 0); /* - * Starts the calibration process and - * enters playback mode after it. - */ - wait_for_calibration (devc); - RESTORE_INTR (flags); } + + ad_leave_MCE (devc); /* + * Starts the calibration process. + */ + RESTORE_INTR (flags); devc->xfer_count = 0; return 0; } @@ -652,23 +1018,44 @@ { ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad_write (devc, 9, 0); /* Clear the PEN and CEN bits (among others) */ + ad_mute (devc); + ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ + OUTB (0, io_Status (devc)); /* Clear interrupt status */ + + ad_enter_MCE (devc); + OUTB (0, io_Status (devc)); /* Clear interrupt status */ + ad_write (devc, 15, 0); /* Clear DMA counter */ + ad_write (devc, 14, 0); /* Clear DMA counter */ + + if (devc->mode == 2) + { + ad_write (devc, 30, 0); /* Clear DMA counter */ + ad_write (devc, 31, 0); /* Clear DMA counter */ + } + + ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ + OUTB (0, io_Status (devc)); /* Clear interrupt status */ + OUTB (0, io_Status (devc)); /* Clear interrupt status */ + ad_leave_MCE (devc); + + DMAbuf_reset_dma (dev); } int ad1848_detect (int io_base) { -#define DDB(x) x - unsigned char tmp; int i; ad1848_info *devc = &dev_info[nr_ad1848_devs]; unsigned char tmp1 = 0xff, tmp2 = 0xff; if (nr_ad1848_devs >= MAX_AUDIO_DEV) - return 0; + { + DDB (printk ("ad1848 detect error - step 0\n")); + return 0; + } devc->base = io_base; devc->MCE_bit = 0x40; @@ -680,33 +1067,33 @@ devc->mode = 1; /* MODE1 = original AD1848 */ /* - * Check that the I/O address is in use. - * - * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed its power on initialization. Just assume - * this has happened before the OS is starting. - * - * If the I/O address is unused, it typically returns 0xff. - */ + * Check that the I/O address is in use. + * + * The bit 0x80 of the base I/O port is known to be 0 after the + * chip has performed it's power on initialization. Just assume + * this has happened before the OS is starting. + * + * If the I/O address is unused, it typically returns 0xff. + */ if ((INB (devc->base) & 0x80) != 0x00) /* Not a AD1884 */ { - DDB (printk ("ad_detect_A\n")); + DDB (printk ("ad1848 detect error - step A\n")); return 0; } /* - * Test if it's possible to change contents of the indirect registers. - * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only - * so try to avoid using it. -*/ + * Test if it's possible to change contents of the indirect registers. + * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only + * so try to avoid using it. + */ ad_write (devc, 0, 0xaa); ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45) { - DDB (printk ("ad_detect_B (%x/%x)\n", tmp1, tmp2)); + DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); return 0; } @@ -715,63 +1102,63 @@ if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa) { - DDB (printk ("ad_detect_C (%x/%x)\n", tmp1, tmp2)); + DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); return 0; } /* - * The indirect register I12 has some read only bits. Lets - * try to change them. - */ + * The indirect register I12 has some read only bits. Lets + * try to change them. + */ tmp = ad_read (devc, 12); ad_write (devc, 12, (~tmp) & 0x0f); if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f)) { - DDB (printk ("ad_detect_D (%x)\n", tmp1)); + DDB (printk ("ad1848 detect error - step D (%x)\n", tmp1)); return 0; } /* - * NOTE! Last 4 bits of the reg I12 tell the chip revision. - * 0x01=RevB and 0x0A=RevC. - */ + * NOTE! Last 4 bits of the reg I12 tell the chip revision. + * 0x01=RevB and 0x0A=RevC. + */ /* - * The original AD1848/CS4248 has just 15 indirect registers. This means - * that I0 and I16 should return the same value (etc.). - * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails - * with CS4231. - */ + * The original AD1848/CS4248 has just 15 indirect registers. This means + * that I0 and I16 should return the same value (etc.). + * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails + * with CS4231. + */ ad_write (devc, 12, 0); /* Mode2=disabled */ for (i = 0; i < 16; i++) if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16))) { - DDB (printk ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2)); + DDB (printk ("ad1848 detect error - step F(%d/%x/%x)\n", i, tmp1, tmp2)); return 0; } /* - * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). - * The bit 0x80 is always 1 in CS4248 and CS4231. - */ + * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). + * The bit 0x80 is always 1 in CS4248 and CS4231. + */ ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */ tmp1 = ad_read (devc, 12); if (tmp1 & 0x80) - devc->chip_name = "CS4248"; + devc->chip_name = "CS4248"; /* Our best knowledge just now */ if ((tmp1 & 0xc0) == (0x80 | 0x40)) { /* - * CS4231 detected - is it? - * - * Verify that setting I0 doesn't change I16. - */ + * CS4231 detected - is it? + * + * Verify that setting I0 doesn't change I16. + */ ad_write (devc, 16, 0); /* Set I16 to known value */ ad_write (devc, 0, 0x45); @@ -781,16 +1168,32 @@ ad_write (devc, 0, 0xaa); if ((tmp1 = ad_read (devc, 16)) == 0xaa) /* Rotten bits? */ { - DDB (printk ("ad_detect_H(%x)\n", tmp1)); + DDB (printk ("ad1848 detect error - step H(%x)\n", tmp1)); return 0; } /* - * It's a CS4231 - So what! - * (Mode2 will be supported later) - */ - devc->chip_name = "CS4231"; - devc->mode = 2; + * Verify that some bits of I25 are read only. + */ + + tmp1 = ad_read (devc, 25); /* Original bits */ + ad_write (devc, 25, ~tmp1); /* Invert all bits */ + if ((ad_read (devc, 25) & 0xe7) == (tmp1 & 0xe7)) + { + /* + * It's a CS4231 + */ + devc->chip_name = "CS4231"; + + +#ifdef MOZART_PORT + if (devc->base != MOZART_PORT + 4) +#endif + devc->mode = 2; + + + } + ad_write (devc, 25, tmp1); /* Restore bits */ } } @@ -801,18 +1204,22 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture) { /* - * NOTE! If irq < 0, there is another driver which has allocated the IRQ - * so that this driver doesn't need to allocate/deallocate it. - * The actually used IRQ is ABS(irq). - */ + * NOTE! If irq < 0, there is another driver which has allocated the IRQ + * so that this driver doesn't need to allocate/deallocate it. + * The actually used IRQ is ABS(irq). + */ /* - * Initial values for the indirect registers of CS4248/AD1848. - */ + * Initial values for the indirect registers of CS4248/AD1848. + */ static int init_values[] = { - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00 + 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x80, 0x80, + 0x00, 0x08, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, + + /* Positions 16 to 31 just for CS4231 */ + 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int i, my_dev; ad1848_info *devc = &dev_info[nr_ad1848_devs]; @@ -821,8 +1228,13 @@ return; devc->irq = (irq > 0) ? irq : 0; - devc->dma_capture = dma_playback; - devc->dma_playback = dma_capture; + devc->dma_playback = dma_playback; + + if (devc->mode == 2) + devc->dma_capture = dma_capture; + else + devc->dma_capture = dma_playback; /* Use just single DMA */ + devc->opened = 0; if (nr_ad1848_devs != 0) @@ -835,15 +1247,26 @@ for (i = 0; i < 16; i++) ad_write (devc, i, init_values[i]); + ad_mute (devc); /* Initialize some variables */ + ad_unmute (devc); /* Leave it unmuted now */ + + if (devc->mode == 2) + { + ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */ + for (i = 16; i < 32; i++) + ad_write (devc, i, init_values[i]); + } + OUTB (0, io_Status (devc)); /* Clear pending interrupts */ -#ifndef SCO - sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, - "%s (%s)", name, devc->chip_name); -#endif + if (name[0] != 0) + sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + "%s (%s)", name, devc->chip_name); + else + sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + "Generic audio codec (%s)", devc->chip_name); - if (irq > 0) - printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name); + printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name); if (num_audiodevs < MAX_AUDIO_DEV) { @@ -859,13 +1282,28 @@ audio_devs[my_dev]->devc = devc; audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode]; nr_ad1848_devs++; + + /* + * Toggle the MCE bit. It completes the initialization phase. + */ + + ad_enter_MCE (devc); /* In case the bit was off */ + ad_leave_MCE (devc); + + if (num_mixers < MAX_MIXER_DEV) + { + mixer2codec[num_mixers] = my_dev + 1; + audio_devs[my_dev]->mixer_dev = num_mixers; + mixer_devs[num_mixers++] = &ad1848_mixer_operations; + ad1848_mixer_reset (devc); + } } else printk ("AD1848: Too many PCM devices available\n"); } void -ad1848_interrupt (int irq, struct pt_regs * regs) +ad1848_interrupt (INT_HANDLER_PARMS (irq, dummy)) { unsigned char status; ad1848_info *devc; @@ -880,6 +1318,9 @@ devc = (ad1848_info *) audio_devs[dev]->devc; status = INB (io_Status (devc)); + if (status == 0x80) + printk ("ad1848_interrupt: Why?\n"); + if (status & 0x01) { if (devc->opened && devc->irq_mode == IMODE_OUTPUT) @@ -892,25 +1333,72 @@ } OUTB (0, io_Status (devc)); /* Clear interrupt status */ + + status = INB (io_Status (devc)); + if (status == 0x80 || status & 0x01) + { + printk ("ad1848: Problems when clearing interrupt, status=%x\n", status); + OUTB (0, io_Status (devc)); /* Try again */ + } } -#endif /* * Some extra code for the MS Sound System */ -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS) int probe_ms_sound (struct address_info *hw_config) { - if ((INB (hw_config->io_base + 3) & 0x04) == 0) - return 0; /* WSS ID test failed */ +#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MSS) + /* + * Initialize Audio Excel DSP 16 to MSS: before any operation + * we must enable MSS I/O ports. + */ + + InitAEDSP16_MSS (hw_config); +#endif + + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTriX Pro for example) + * return 0x00. + */ + + if ((INB (hw_config->io_base + 3) & 0x3f) != 0x04 && + (INB (hw_config->io_base + 3) & 0x3f) != 0x00) + { + DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n", + hw_config->io_base, INB (hw_config->io_base + 3))); + return 0; + } if (hw_config->irq > 11) - return 0; + { + printk ("MSS: Bad IRQ %d\n", hw_config->irq); + return 0; + } if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - return 0; + { + printk ("MSS: Bad DMA %d\n", hw_config->dma); + return 0; + } + + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && INB (hw_config->io_base + 3) & 0x80) + { + printk ("MSS: Can't use DMA0 with a 8 bit card/slot\n"); + return 0; + } + + if (hw_config->irq > 7 && hw_config->irq != 9 && INB (hw_config->io_base + 3) & 0x80) + { + printk ("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); + return 0; + } return ad1848_detect (hw_config->io_base + 4); } @@ -918,11 +1406,16 @@ long attach_ms_sound (long mem_start, struct address_info *hw_config) { - static unsigned char interrupt_bits[12] = - {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20}; + static char interrupt_bits[12] = + { + -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 + }; char bits; - static unsigned char dma_bits[4] = {1, 2, 0, 3}; + static char dma_bits[4] = + { + 1, 2, 0, 3 + }; int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; @@ -930,16 +1423,16 @@ return mem_start; /* - * Set the IRQ and DMA addresses. - */ + * Set the IRQ and DMA addresses. + */ bits = interrupt_bits[hw_config->irq]; if (bits == -1) return mem_start; - OUTB (bits | 0x40, config_port); /* Verify IRQ (I guess) */ + OUTB (bits | 0x40, config_port); if ((INB (version_port) & 0x40) == 0) - printk ("[IRQ?]"); + printk ("[IRQ Conflict?]"); OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */ diff -u --recursive --new-file v1.3.8/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h --- v1.3.8/linux/drivers/sound/ad1848_mixer.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/ad1848_mixer.h Mon Jun 12 12:48:59 1995 @@ -0,0 +1,130 @@ +/* + * sound/ad1848_mixer.h + * + * Definitions for the mixer of AD1848 and compatible codecs. + * + * Copyright by Hannu Savolainen 1994 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * The AD1848 codec has generic input lines called Line, Aux1 and Aux2. + * Soundcard manufacturers have connected actual inputs (CD, synth, line, + * etc) to these inputs in different order. Therefore it's difficult + * to assign mixer channels to to these inputs correctly. The following + * contains two alternative mappings. The first one is for GUS MAX and + * the second is just a generic one (line1, line2 and line3). + * (Actually this is not a mapping but rather some kind of interleaving + * solution). + */ +#ifdef GUSMAX_MIXER +#define MODE1_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD) + +#define MODE1_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_MIC | \ + SOUND_MASK_CD | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM|SOUND_MASK_IMIX) + +#define MODE2_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_SPEAKER | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) +#else /* Generic mapping */ +#define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE1) + +#define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE2 | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) + +#define MODE2_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) +#endif + +struct mixer_def { + unsigned int regno: 7; + unsigned int polarity:1; /* 0=normal, 1=reversed */ + unsigned int bitpos:4; + unsigned int nbits:4; +}; + + +typedef struct mixer_def mixer_ent; + +/* + * Most of the mixer entries work in backwards. Setting the polarity field + * makes them to work correctly. + * + * The channel numbering used by individual soundcards is not fixed. Some + * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs. + * The current version doesn't try to compensate this. + */ + +#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \ + {{reg_l, pola_l, pos_r, len_l}, {reg_r, pola_r, pos_r, len_r}} + +mixer_ent mix_devices[32][2] = { /* As used in GUS MAX */ +MIX_ENT(SOUND_MIXER_VOLUME, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5), +MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6), +MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5), +MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5), +MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4), +MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5), +MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5), +MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5) +}; + +static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] = +{ + 0x5a5a, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x4b4b, /* FM */ + 0x6464, /* PCM */ + 0x4b4b, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x1010, /* Mic */ + 0x4b4b, /* CD */ + 0x0000, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x4b4b, /* Recording level */ + 0x4b4b, /* Input gain */ + 0x4b4b, /* Output gain */ + 0x4b4b, /* Line1 */ + 0x4b4b, /* Line2 */ + 0x4b4b /* Line3 */ +}; + +#define LEFT_CHN 0 +#define RIGHT_CHN 1 diff -u --recursive --new-file v1.3.8/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c --- v1.3.8/linux/drivers/sound/aedsp16.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/aedsp16.c Mon Jul 10 01:45:03 1995 @@ -0,0 +1,867 @@ +/* + sound/aedsp16.c + + Audio Excel DSP 16 software configuration routines + + Copyright (C) 1995 Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. 2. + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ +/* + * Include the main voxware header file. It include all the os/voxware/etc + * headers needed by this source. + */ +#include "sound_config.h" +/* + * all but ioport.h :) + */ +#include + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AEDSP16) +/* + + READ THIS + + This module is intended for Audio Excel DSP 16 Sound Card. + + Audio Excel DSP 16 is an SB pro II, Microsoft Sound System + and MPU-401 compatible card. + It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq), + so before this module, the only way to configure the DSP under linux was + boot the MS-BAU loading the sound.sys device driver (this driver soft- + configure the sound board hardware by massaging someone of its registers), + and then ctrl-alt-del to boot linux with the DSP configured by the DOG + driver. + + This module works configuring your Audio Excel DSP 16's + irq, dma and mpu-401-irq. The voxware probe routines rely on the + fact that if the hardware is there, they can detect it. The problem + with AEDSP16 is that no hardware can be found by the probe routines + if the sound card is not well configured. Sometimes the kernel probe + routines can find an SBPRO even when the card is not configured (this + is the standard setup of the card), but the SBPRO emulation don't work + well if the card is not properly initialized. For this reason + + InitAEDSP16_...() + + routines are called before the voxware probe routines try to detect the + hardware. + + NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS) + + The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS; + the voxware sound driver can be configured for SBPRO and MSS cards + at the same time, but the aedsp16 can't be two cards!! + When we configure it, we have to choose the SBPRO or the MSS emulation + for AEDSP16. We also can install a *REAL* card of the other type + (see [1], not tested but I can't see any reason for it to fail). + + NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO + please let me know if it works. + + The MPU-401 support can be compiled in together with one of the other + two operating modes. + + The board configuration calls, are in the probe_...() routines because + we have to configure the board before probing it for a particular + hardware. After card configuration, we can probe the hardware. + + NOTE: This is something like plug-and-play: we have only to plug + the AEDSP16 board in the socket, and then configure and compile + a kernel that uses the AEDSP16 software configuration capability. + No jumper setting is needed! + + For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3 + you have just to make config the voxware package, configuring + the SBPro sound card with that parameters, then when configure + asks if you have an AEDSP16, answer yes. That's it. + Compile the kernel and run it. + + NOTE: This means that you can choose irq and dma, but not the + I/O addresses. To change I/O addresses you have to set them + with jumpers. + + NOTE: InitAEDSP16_...() routines get as parameter the hw_config, + the hardware configuration of the - to be configured - board. + The InitAEDSP16() routine, configure the board following our + wishes, that are in the hw_config structure. + + You can change the irq/dma/mirq settings WITHOUT THE NEED to open + your computer and massage the jumpers (there are no irq/dma/mirq + jumpers to be configured anyway, only I/O port ones have to be + configured with jumpers) + + For some ununderstandable reason, the card default of irq 7, dma 1, + don't work for me. Seems to be an IRQ or DMA conflict. Under heavy + HDD work, the kernel start to erupt out a lot of messages like: + + 'Sound: DMA timed out - IRQ/DRQ config error?' + + For what I can say, I have NOT any conflict at irq 7 (under linux I'm + using the lp polling driver), and dma line 1 is unused as stated by + /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so + I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows! + Anyway a setting of irq 10, dma 3 works really fine. + + NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know + the emulation mode, all the installed hardware and the hardware + configuration (irq and dma settings of all the hardware). + + This init module should work with SBPRO+MSS, when one of the two is + the AEDSP16 emulation and the other the real card. (see [1]) + For example: + + AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other + AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other + + MPU401 should work. (see [1]) + + [1] Not tested by me for lack of hardware. + + TODO, WISHES AND TECH + + May be there's lot of redundant delays, but for now I want to leave it + this way. + + Should be interesting eventually write down a new ioctl for the + aedsp16, to let the suser() change the irq/dma/mirq on the fly. + The thing is not trivial. + In the real world, there's no need to have such an ioctl because + when we configure the kernel for compile, we can choose the config + parameters. If we change our mind, we can easily re-config the kernel + and re-compile. + Why let the suser() change the config parameters on the fly ? + If anyone have a reasonable answer to this question, I will write down + the code to do it. + + More integration with voxware, using voxware low level routines to + read-write dsp is not possible because you may want to have MSS + support and in that case we can not rely on the functions included + in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my + own I/O functions. + + - About I/O ports allocation - + + The request_region should be done at device probe in every sound card + module. This module is not the best site for requesting regions. + When the request_region code will be added to the main modules such as + sb, adlib, gus, ad1848, etc, the requesting code in this module should + go away. + + I think the request regions should be done this way: + + if (check_region(...)) + return ERR; // I/O region alredy reserved + device_probe(...); + device_attach(...); + request_region(...); // reserve only when we are sure all is okay + + Request the 2x0h region in any case if we are using this card. + + NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region + (see code) does not mean necessarly that we are emulating sbpro. + It mean that the region is the sbpro I/O ports region. We use this + region to access the control registers of the card, and if emulating + sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro + registers are not used, in no way, to emulate an sbpro: they are + used only for configuration pourposes. + + Someone pointed out that should be possible use both the SBPRO and MSS + modes because the sound card have all the two chipsets, supposing that + the card is really two cards. I have tried something to have the two + modes work together, but, for some reason unknown to me, without success. + + I think all the soft-config only cards have an init sequence similar to + this. If you have a card that is not an aedsp16, you can try to start + with this module changing it (mainly in the CMD? I think) to fit your + needs. + + Started Fri Mar 17 16:13:18 MET 1995 + + v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c) + - Initial code. + v0.2 (ALPHA) + - Cleanups. + - Integrated with Linux voxware v 2.90-2 kernel sound driver. + - SoundBlaster Pro mode configuration. + - Microsoft Sound System mode configuration. + - MPU-401 mode configuration. + v0.3 (ALPHA) + - Cleanups. + - Rearranged the code to let InitAEDSP16 be more general. + - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h + inclusion too. We rely on os.h + - Used the INB and OUTB #defined in os.h instead of inb and outb. + - Corrected the code for GetCardName (DSP Copyright) to get a variable + len string (we are not sure about the len of Copyright string). + This works with any SB and compatible. + - Added the code to request_region at device init (should go in + the main body of voxware). + v0.4 (BETA) + - Better configure.c patch for aedsp16 configuration (better + logic of inclusion of AEDSP16 support) + - Modified the conditional compilation to better support more than + one sound card of the emulated type (read the NOTES above) + - Moved the sb init routine from the attach to the very first + probe in sb_card.c + - Rearrangemens and cleanups + - Wiped out some unnecessary code and variables: this is kernel + code so it is better save some TEXT and DATA + - Fixed the request_region code. We must allocate the aedsp16 (sbpro) + I/O ports in any case because they are used to access the DSP + configuration registers and we can not allow anyone to get them. + v0.5 + - cleanups on comments + - prep for diffs against v3.0-proto-950402 + v0.6 + - removed the request_region()s when compiling the MODULE sound.o + because we are not allowed (by the actual voxware structure) to + release_region() + + */ + + +#define VERSION "0.6" /* Version of Audio Excel DSP 16 driver */ + +#undef AEDSP16_DEBUG /* Define this to enable debug code */ +/* Actually no debug code is activated */ + +/* + * Hardware related defaults + */ +#define IRQ 7 /* 5 7(default) 9 10 11 */ +#define MIRQ 0 /* 5 7 9 10 0(default), 0 means disable */ +#define DMA 1 /* 0 1(default) 3 */ + +/* + * Commands of AEDSP16's DSP (SBPRO+special). + * For now they are CMDn, in the future they may change. + */ +#define CMD1 0xe3 /* Get DSP Copyright */ +#define CMD2 0xe1 /* Get DSP Version */ +#define CMD3 0x88 /* */ +#define CMD4 0x5c /* */ +#define CMD5 0x50 /* Set M&I&DRQ mask (the real config) */ +#define CMD6 0x8c /* Enable Microsoft Sound System mode */ + +/* + * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase + * to have the actual I/O port. + * Register permissions are: + * (wo) == Write Only + * (ro) == Read Only + * (w-) == Write + * (r-) == Read + */ +#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */ +#define DSP_READ 0x0a /* offset of DSP READ (ro) */ +#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */ +#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */ +#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */ +#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */ + + +#define RETRY 10 /* Various retry values on I/O opera- */ +#define STATUSRETRY 1000 /* tions. Sometimes we have to */ +#define HARDRETRY 500000 /* wait for previous cmd to complete */ + +/* + * Size of character arrays that store name and version of sound card + */ +#define CARDNAMELEN 15 /* Size of the card's name in chars */ +#define CARDVERLEN 2 /* Size of the card's version in chars */ + +/* + * Bit mapped flags for calling InitAEDSP16(), and saving the current + * emulation mode. + */ +#define INIT_NONE (0 ) +#define INIT_SBPRO (1<<0) +#define INIT_MSS (1<<1) +#define INIT_MPU401 (1<<2) +#define RESET_DSP16 (1<<3) + +/* Base HW Port for Audio Card */ +static int portbase = AEDSP16_BASE; +static int irq = IRQ; /* irq for DSP I/O */ +static int mirq = MIRQ; /* irq for MPU-401 I/O */ +static int dma = DMA; /* dma for DSP I/O */ + +/* Init status of the card */ +static int ae_init = INIT_NONE; /* (bitmapped variable) */ +static int oredparams = 0; /* Will contain or'ed values of params */ +static int gc = 0; /* generic counter (utility counter) */ +struct orVals + { /* Contain the values to be or'ed */ + int val; /* irq|mirq|dma */ + int or; /* oredparams |= TheStruct.or */ + }; + +/* + * Magic values that the DSP will eat when configuring irq/mirq/dma + */ +/* DSP IRQ conversion array */ +static struct orVals orIRQ[] = +{ + {0x05, 0x28}, + {0x07, 0x08}, + {0x09, 0x10}, + {0x0a, 0x18}, + {0x0b, 0x20}, + {0x00, 0x00} +}; + +/* MPU-401 IRQ conversion array */ +static struct orVals orMIRQ[] = +{ + {0x05, 0x04}, + {0x07, 0x44}, + {0x09, 0x84}, + {0x0a, 0xc4}, + {0x00, 0x00} +}; + +/* DMA Channels conversion array */ +static struct orVals orDMA[] = +{ + {0x00, 0x01}, + {0x01, 0x02}, + {0x03, 0x03}, + {0x00, 0x00} +}; + +/* + * Buffers to store audio card informations + */ +static char AudioExcelName[CARDNAMELEN + 1]; +static char AudioExcelVersion[CARDVERLEN + 1]; + +static void +tenmillisec (void) +{ + + for (gc = 0; gc < 1000; gc++) + tenmicrosec (); +} + +static int +WaitForDataAvail (int port) +{ + int loop = STATUSRETRY; + unsigned char ret = 0; + + do + { + ret = INB (port + DSP_DATAVAIL); + /* + * Wait for data available (bit 7 of ret == 1) + */ + } + while (!(ret & 0x80) && loop--); + + if (ret & 0x80) + return 0; + + return -1; +} + +static int +ReadData (int port) +{ + if (WaitForDataAvail (port)) + return -1; + return INB (port + DSP_READ); +} + +static int +CheckDSPOkay (int port) +{ + return ((ReadData (port) == 0xaa) ? 0 : -1); +} + +static int +ResetBoard (int port) +{ + /* + * Reset DSP + */ + OUTB (1, (port + DSP_RESET)); + tenmicrosec (); + OUTB (0, (port + DSP_RESET)); + tenmicrosec (); + tenmicrosec (); + return CheckDSPOkay (port); +} + +static int +WriteDSPCommand (int port, int cmd) +{ + unsigned char ret; + int loop = HARDRETRY; + + do + { + ret = INB (port + DSP_STATUS); + /* + * DSP ready to receive data if bit 7 of ret == 0 + */ + if (!(ret & 0x80)) + { + OUTB (cmd, port + DSP_COMMAND); + return 0; + } + } + while (loop--); + + printk ("[aedsp16] DSP Command (0x%x) timeout.\n", cmd); + return -1; +} + +int +InitMSS (int port) +{ + + tenmillisec (); + + if (WriteDSPCommand (port, CMD6)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD6); + return -1; + } + + tenmillisec (); + + return 0; +} + +static int +SetUpBoard (int port) +{ + int loop = RETRY; + + do + { + if (WriteDSPCommand (portbase, CMD3)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD3); + return -1; + } + + tenmillisec (); + + } + while (WaitForDataAvail (port) && loop--); + +#if defined(THIS_SHOULD_GO_AWAY) + if (CheckDSPOkay (port)) + { + printk ("[aedsp16] CheckDSPOkay: failed\n"); + return -1; + } +#else + if (ReadData (port) == -1) + { + printk ("[aedsp16] ReadData after CMD 0x%x: failed\n", CMD3); + return -1; + } +#endif + + if (WriteDSPCommand (portbase, CMD4)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD4); + return -1; + } + + if (WriteDSPCommand (portbase, CMD5)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD5); + return -1; + } + + if (WriteDSPCommand (portbase, oredparams)) + { + printk ("[aedsp16] Initialization of (M)IRQ and DMA: failed!\n"); + return -1; + } + return 0; +} + +static int +GetCardVersion (int port) +{ + int len = 0; + int ret; + int ver[3]; + + do + { + if ((ret = ReadData (port)) == -1) + return -1; + /* + * We alredy know how many int are stored (2), so we know when the + * string is finished. + */ + ver[len++] = ret; + } + while (len < CARDVERLEN); + sprintf (AudioExcelVersion, "%d.%d", ver[0], ver[1]); + return 0; +} + +static int +GetCardName (int port) +{ + int len = 0; + int ret; + + do + { + if ((ret = ReadData (port)) == -1) + /* + * If no more data availabe, return to the caller, no error if len>0. + * We have no other way to know when the string is finished. + */ + return (len ? 0 : -1); + + AudioExcelName[len++] = ret; + + } + while (len < CARDNAMELEN); + return 0; +} + +static void +InitializeHardParams (void) +{ + + memset (AudioExcelName, 0, CARDNAMELEN + 1); + memset (AudioExcelVersion, 0, CARDVERLEN + 1); + + for (gc = 0; orIRQ[gc].or; gc++) + if (orIRQ[gc].val == irq) + oredparams |= orIRQ[gc].or; + + for (gc = 0; orMIRQ[gc].or; gc++) + if (orMIRQ[gc].or == mirq) + oredparams |= orMIRQ[gc].or; + + for (gc = 0; orDMA[gc].or; gc++) + if (orDMA[gc].val == dma) + oredparams |= orDMA[gc].or; +} + +static int +InitAEDSP16 (int which) +{ + static char *InitName = NULL; + + InitializeHardParams (); + + if (ResetBoard (portbase)) + { + printk ("[aedsp16] ResetBoard: failed!\n"); + return -1; + } + +#if defined(THIS_SHOULD_GO_AWAY) + if (CheckDSPOkay (portbase)) + { + printk ("[aedsp16] CheckDSPOkay: failed!\n"); + return -1; + } +#endif + + if (WriteDSPCommand (portbase, CMD1)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD1); + return -1; + } + + if (GetCardName (portbase)) + { + printk ("[aedsp16] GetCardName: failed!\n"); + return -1; + } + + /* + * My AEDSP16 card return SC-6000 in AudioExcelName, so + * if we have something different, we have to be warned. + */ + if (strcmp ("SC-6000", AudioExcelName)) + printk ("[aedsp16] Warning: non SC-6000 audio card!\n"); + + if (WriteDSPCommand (portbase, CMD2)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD2); + return -1; + } + + if (GetCardVersion (portbase)) + { + printk ("[aedsp16] GetCardVersion: failed!\n"); + return -1; + } + + if (SetUpBoard (portbase)) + { + printk ("[aedsp16] SetUpBoard: failed!\n"); + return -1; + } + + if (which == INIT_MSS) + { + if (InitMSS (portbase)) + { + printk ("[aedsp16] Can't initialize Microsoft Sound System mode.\n"); + return -1; + } + } + + /* + * If we are resetting, do not print any message because we may be + * in playing and we do not want lost too much time. + */ + if (!(which & RESET_DSP16)) + { + if (which & INIT_MPU401) + InitName = "MPU401"; + else if (which & INIT_SBPRO) + InitName = "SBPro"; + else if (which & INIT_MSS) + InitName = "MSS"; + else + InitName = "None"; + + printk ("Audio Excel DSP 16 init v%s (%s %s) [%s]\n", + VERSION, AudioExcelName, + AudioExcelVersion, InitName); + } + + tenmillisec (); + + return 0; +} + +#if defined(AEDSP16_SBPRO) + +int +InitAEDSP16_SBPRO (struct address_info *hw_config) +{ + /* + * If the card is alredy init'ed MSS, we can not init it to SBPRO too + * because the board can not emulate simultaneously MSS and SBPRO. + */ + if (ae_init & INIT_MSS) + return -1; + if (ae_init & INIT_SBPRO) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (!(ae_init & INIT_MPU401)) + { + if (check_region (hw_config->io_base, 0x0f)) + { + printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n"); + return -1; + } + } + + /* + * Set up the internal hardware parameters, to let the driver reach + * the Sound Card. + */ + portbase = hw_config->io_base; + irq = hw_config->irq; + dma = hw_config->dma; + if (InitAEDSP16 (INIT_SBPRO)) + return -1; + +#if !defined(MODULE) + /* + * If we are compiling sound.o (MODULAR version) we can not + * request any region because there is not a uninit routine that + * can allow me to release the requested region. + */ + if (!(ae_init & INIT_MPU401)) + request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)"); +#endif + + ae_init |= INIT_SBPRO; + return 0; +} + +#endif /* AEDSP16_SBPRO */ + +#if defined(AEDSP16_MSS) + +int +InitAEDSP16_MSS (struct address_info *hw_config) +{ + /* + * If the card is alredy init'ed SBPRO, we can not init it to MSS too + * because the board can not emulate simultaneously MSS and SBPRO. + */ + if (ae_init & INIT_SBPRO) + return -1; + if (ae_init & INIT_MSS) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (check_region (hw_config->io_base, 0x08)) + { + printk ("MSS I/O port region is alredy in use.\n"); + return -1; + } + + /* + * We must allocate the AEDSP16 region too because these are the I/O ports + * to access card's control registers. + */ + if (!(ae_init & INIT_MPU401)) + { + if (check_region (AEDSP16_BASE, 0x0f)) + { + printk ("AEDSP16 I/O port region is alredy in use.\n"); + return -1; + } + } + + + /* + * If we are configuring the card for MSS, the portbase for card + * configuration is the default one (0x220 unless you have changed the + * factory default with board switches), so no need to modify the + * portbase variable. + * The default is AEDSP16_BASE, that is the right value. + */ + irq = hw_config->irq; + dma = hw_config->dma; + if (InitAEDSP16 (INIT_MSS)) + return -1; + +#if !defined(MODULE) + /* + * If we are compiling sound.o (MODULAR version) we can not + * request any region because there is not a uninit routine that + * can allow me to release the requested region. So when unloading + * and then reloading it, we are going to have some nice Oops! + */ + request_region (hw_config->io_base, 0x08, "aedsp16 (mss)"); +#endif + + if (!(ae_init & INIT_MPU401)) + request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)"); + + ae_init |= INIT_MSS; + return 0; +} + +#endif /* AEDSP16_MSS */ + +#if defined(AEDSP16_MPU401) + +int +InitAEDSP16_MPU401 (struct address_info *hw_config) +{ + if (ae_init & INIT_MPU401) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (check_region (hw_config->io_base, 0x02)) + { + printk ("SB I/O port region is alredy in use.\n"); + return -1; + } + + /* + * We must allocate the AEDSP16 region too because these are the I/O ports + * to access card's control registers. + */ + if (!(ae_init & (INIT_MSS | INIT_SBPRO))) + { + if (check_region (AEDSP16_BASE, 0x0f)) + { + printk ("AEDSP16 I/O port region is alredy in use.\n"); + return -1; + } + } + + /* + * If mpu401, the irq and dma are not important, do not touch it + * because we may use the default if sbpro is not yet configured, + * we may use the sbpro ones if configured, and nothing wrong + * should happen. + * + * The mirq default is 0, but once set it to non-0 value, we should + * not touch it anymore (unless I write an ioctl to do it, of course). + */ + mirq = hw_config->irq; + if (InitAEDSP16 (INIT_MPU401)) + return -1; + +#if !defined(MODULE) + /* + * If we are compiling sound.o (MODULAR version) we can not + * request any region because there is not a uninit routine that + * can allow me to release the requested region. + */ + request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)"); +#endif + + if (!(ae_init & (INIT_MSS | INIT_SBPRO))) + request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)"); + + ae_init |= INIT_MPU401; + return 0; +} + +#endif /* AEDSP16_MPU401 */ + +#if 0 /* Leave it out for now. We are not using this portion of code. */ + +/* + * Entry point for a reset function. + * May be I will write the infamous ioctl :) + */ +int +ResetAEDSP16 (void) +{ +#if defined(AEDSP16_DEBUG) + printk ("[aedsp16] ResetAEDSP16 called.\n"); +#endif + return InitAEDSP16 (RESET_DSP16); +} + +#endif /* 0 */ + +#endif /* !EXCLUDE_AEDSP16 */ diff -u --recursive --new-file v1.3.8/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v1.3.8/linux/drivers/sound/audio.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/audio.c Mon Jul 10 01:45:04 1995 @@ -33,11 +33,13 @@ #ifndef EXCLUDE_AUDIO #include "ulaw.h" +#include "coproc.h" #define ON 1 #define OFF 0 static int wr_buff_no[MAX_AUDIO_DEV]; /* + * != -1, if there is * a incomplete output * block in the queue. @@ -45,6 +47,7 @@ static int wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV]; static int audio_mode[MAX_AUDIO_DEV]; +static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in noblocking mode */ #define AM_NONE 0 #define AM_WRITE 1 @@ -98,6 +101,16 @@ if ((ret = DMAbuf_open (dev, mode)) < 0) return ret; + if (audio_devs[dev]->coproc) + if ((ret = audio_devs[dev]->coproc-> + open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) + { + audio_release (dev, file); + printk ("Sound: Can't access coprocessor device\n"); + + return ret; + } + local_conversion[dev] = 0; if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits) @@ -115,6 +128,8 @@ wr_buff_no[dev] = -1; audio_mode[dev] = AM_NONE; + wr_buff_size[dev] = wr_buff_ptr[dev] = 0; + dev_nblock[dev] = 0; return ret; } @@ -134,6 +149,8 @@ wr_buff_no[dev] = -1; } + if (audio_devs[dev]->coproc) + audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM); DMAbuf_release (dev, mode); } @@ -155,9 +172,9 @@ "1:\tlodsb\n\t" "xlatb\n\t" "stosb\n\t" - "loop 1b\n\t": - :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff) - :"bx", "cx", "di", "si", "ax"); +"loop 1b\n\t": +: "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff) +: "bx", "cx", "di", "si", "ax"); } #endif @@ -203,8 +220,13 @@ * There is no incomplete buffers */ { - if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0) + if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], + &wr_buff_size[dev], + dev_nblock[dev])) < 0) { + /* Handle nonblocking mode */ + if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EAGAIN)) + return p; /* No more space. Return # of accepted bytes */ return wr_buff_no[dev]; } wr_buff_ptr[dev] = 0; @@ -284,8 +306,16 @@ while (c) { - if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0) - return buff_no; + if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l, + dev_nblock[dev])) < 0) + { + /* Nonblocking mode handling. Return current # of bytes */ + + if (dev_nblock[dev] && buff_no == RET_ERROR (EAGAIN)) + return p; + + return buff_no; + } if (l > c) l = c; @@ -324,56 +354,149 @@ dev = dev >> 4; - switch (cmd) + if (((cmd >> 8) & 0xff) == 'C') { - case SNDCTL_DSP_SYNC: - if (wr_buff_no[dev] >= 0) + if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ + return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0); + else + printk ("/dev/dsp%d: No coprocessor for this device\n", dev); + + return RET_ERROR (EREMOTEIO); + } + else + switch (cmd) + { + case SNDCTL_DSP_SYNC: + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + return DMAbuf_ioctl (dev, cmd, arg, 0); + break; + + case SNDCTL_DSP_POST: + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + return 0; + break; + + case SNDCTL_DSP_RESET: + wr_buff_no[dev] = -1; + return DMAbuf_ioctl (dev, cmd, arg, 0); + break; + + case SNDCTL_DSP_GETFMTS: + return IOCTL_OUT (arg, audio_devs[dev]->format_mask); + break; + + case SNDCTL_DSP_SETFMT: + return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg))); + + case SNDCTL_DSP_GETISPACE: + if (audio_mode[dev] == AM_WRITE) + return RET_ERROR (EBUSY); + { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + audio_buf_info info; - wr_buff_no[dev] = -1; + int err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1); + + if (err < 0) + return err; + + if (wr_buff_no[dev] != -1) + info.bytes += wr_buff_ptr[dev]; + + IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info)); + return 0; } - return DMAbuf_ioctl (dev, cmd, arg, 0); - break; - case SNDCTL_DSP_POST: - if (wr_buff_no[dev] >= 0) + case SNDCTL_DSP_GETOSPACE: + if (audio_mode[dev] == AM_READ) + return RET_ERROR (EBUSY); + { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + audio_buf_info info; - wr_buff_no[dev] = -1; - } - return 0; - break; + int err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1); - case SNDCTL_DSP_RESET: - wr_buff_no[dev] = -1; - return DMAbuf_ioctl (dev, cmd, arg, 0); - break; + if (err < 0) + return err; - case SNDCTL_DSP_GETFMTS: - return IOCTL_OUT (arg, audio_devs[dev]->format_mask); - break; + if (wr_buff_no[dev] != -1) + info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev]; - case SNDCTL_DSP_SETFMT: - return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg))); + IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info)); + return 0; + } - default: - return DMAbuf_ioctl (dev, cmd, arg, 0); - break; - } + case SNDCTL_DSP_NONBLOCK: + dev_nblock[dev] = 1; + return 0; + break; + + default: + return DMAbuf_ioctl (dev, cmd, arg, 0); + } } long audio_init (long mem_start) { /* - * NOTE! This routine could be called several times during boot. - */ + * NOTE! This routine could be called several times during boot. + */ return mem_start; } -#else +#ifdef ALLOW_SELECT +int +audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +{ + int l; + char *dmabuf; + + dev = dev >> 4; + + switch (sel_type) + { + case SEL_IN: + if (audio_mode[dev] != AM_READ) /* Wrong direction */ + return 0; + + if (DMAbuf_getrdbuffer (dev, &dmabuf, &l, + 1 /* Don't block */ ) >= 0) + return 1; /* We have data */ + + return DMAbuf_select (dev, file, sel_type, wait); + break; + + case SEL_OUT: + if (audio_mode[dev] != AM_WRITE) /* Wrong direction */ + return 0; + + if (wr_buff_no[dev] != -1) + return 1; /* There is space in the current buffer */ + + return DMAbuf_select (dev, file, sel_type, wait); + break; + + case SEL_EX: + return 0; + } + + return 0; +} + +#endif /* ALLOW_SELECT */ + +#else /* EXCLUDE_AUDIO */ /* * Stub versions */ diff -u --recursive --new-file v1.3.8/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v1.3.8/linux/drivers/sound/configure.c Wed Jan 18 09:38:59 1995 +++ linux/drivers/sound/configure.c Mon Jul 10 01:45:05 1995 @@ -1,3 +1,4 @@ +#define DISABLED_OPTIONS 0 /* * sound/configure.c - Configuration program for the Linux Sound Driver * @@ -45,26 +46,36 @@ #define OPT_GUS16 7 #define OPT_GUSMAX 8 #define OPT_MSS 9 - -#define OPT_HIGHLEVEL 10 /* This must be same than the next one */ -#define OPT_SBPRO 10 -#define OPT_SB16 11 -#define OPT_AUDIO 12 -#define OPT_MIDI_AUTO 13 -#define OPT_MIDI 14 -#define OPT_YM3812_AUTO 15 -#define OPT_YM3812 16 -#define OPT_SEQUENCER 17 -#define OPT_LAST 17 /* Must be the same than the defined OPT */ +#define OPT_SSCAPE 10 +#define OPT_TRIX 11 +#define OPT_MAD16 12 + +#define OPT_HIGHLEVEL 13 /* This must be same than the next one */ +#define OPT_SBPRO 13 +#define OPT_SB16 14 +#define OPT_AEDSP16 15 +#define OPT_AUDIO 16 +#define OPT_MIDI_AUTO 17 +#define OPT_MIDI 18 +#define OPT_YM3812_AUTO 19 +#define OPT_YM3812 20 +#define OPT_SEQUENCER 21 +#define OPT_LAST 21 /* Last defined OPT number */ #define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \ - B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)|B(OPT_MSS)) + B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)| \ + B(OPT_MSS)|B(OPT_SSCAPE)|B(OPT_UART6850)|B(OPT_TRIX)| \ + B(OPT_MAD16)) +#define AUDIO_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | \ + B (OPT_MSS) | B (OPT_GUS16) | B (OPT_GUSMAX) | B (OPT_TRIX) | \ + B (OPT_SSCAPE)| B(OPT_MAD16)) +#define MIDI_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \ + B (OPT_GUS) | B (OPT_TRIX) | B (OPT_SSCAPE)|B(OPT_MAD16)) /* * Options that have been disabled for some reason (incompletely implemented * and/or tested). Don't remove from this list before looking at file * experimental.txt for further info. */ -#define DISABLED_OPTIONS (B(OPT_PSS)) typedef struct { @@ -109,14 +120,18 @@ {B (OPT_GUS), 0, "GUS16", 1, 0, 0}, {B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0}, {0, 0, "MSS", 1, 0, 0}, + {0, 0, "SSCAPE", 1, 0, 0}, + {0, 0, "TRIX", 1, 0, 0}, + {0, 0, "MAD16", 1, 0, 0}, {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1}, {B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1}, -{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | B (OPT_MSS), 0, "AUDIO", 1, 0, 1}, + {B (OPT_SBPRO) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0}, + {AUDIO_CARDS, 0, "AUDIO", 1, 0, 1}, {B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0}, - {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1}, + {MIDI_CARDS, 0, "MIDI", 1, 0, 1}, {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0}, - {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1}, + {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB) | B (OPT_MSS) | B (OPT_PSS), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1}, {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1} }; @@ -124,7 +139,7 @@ { "ProAudioSpectrum 16 support", "SoundBlaster support", - "AdLib support", + "Generic OPL2/OPL3 FM synthesizer support", "Gravis Ultrasound support", "MPU-401 support (NOT for SB16)", "6850 UART Midi support", @@ -132,24 +147,32 @@ "16 bit sampling option of GUS (_NOT_ GUS MAX)", "GUS MAX support", "Microsoft Sound System support", + "Ensoniq Soundscape support", + "MediaTriX AudioTriX Pro support", + "Support for MAD16 and/or Mozart based cards", "SoundBlaster Pro support", "SoundBlaster 16 support", - "/dev/dsp and /dev/audio support (_recommended_)", + "Audio Excel DSP 16 initialization support", + "/dev/dsp and /dev/audio supports (usually required)", "This should not be asked", "MIDI interface support", "This should not be asked", "FM synthesizer (YM3812/OPL-3) support", "/dev/sequencer support", - "Should I die" + "Is the sky really falling" }; unsigned long selected_options = 0; int sb_dma = 0; +#include "hex2hex.h" +int bin2hex (char *path, char *target, char *varname); + int can_select_option (int nr) { +#if 0 switch (nr) { case 0: @@ -175,6 +198,7 @@ } +#endif if (hw_table[nr].conditions) if (!(hw_table[nr].conditions & selected_options)) @@ -262,15 +286,19 @@ printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n\n"); fprintf (stderr, "\nConfiguring the sound support\n\n"); - +#if 0 + /* + * The full driver appeared to be impossible to compile and boot. + * There are too much supported cards now. + */ fprintf (stderr, "Do you want to include full version of the sound driver (n/y) ? "); if (think_positively (0)) { /* - * Select all but some most dangerous cards. These cards are difficult to - * detect reliably or conflict with some other cards (SCSI, Mitsumi) - */ + * Select all but some most dangerous cards. These cards are difficult to + * detect reliably or conflict with some other cards (SCSI, Mitsumi) + */ selected_options = 0xffffffff & ~(B (OPT_MPU401) | B (OPT_UART6850) | B (OPT_PSS)) & ~DISABLED_OPTIONS; @@ -279,7 +307,9 @@ full_driver = 1; } else +#endif { +#if 0 fprintf (stderr, "Do you want to DISABLE the Sound Driver (n/y) ?"); if (think_positively (0)) { @@ -287,6 +317,7 @@ printf ("#undef KERNEL_SOUNDCARD\n"); exit (0); } +#endif /* * Partial driver */ @@ -324,14 +355,119 @@ if (selected_options & B (OPT_SBPRO)) { - fprintf(stderr, "Do you want support for the mixer of SG NX Pro ? "); + fprintf (stderr, "Do you want support for the mixer of SG NX Pro ? "); + if (think_positively (0)) + printf ("#define __SGNXPRO__\n"); + } + + if (selected_options & B (OPT_SB)) + { + fprintf (stderr, "Do you want support for the MV Jazz16 (ProSonic etc.) ? "); + if (think_positively (0)) + { + printf ("#define JAZZ16\n"); + do + { + fprintf (stderr, "\tValid 16 bit DMA channels for ProSonic/Jazz 16 are\n"); + fprintf (stderr, "\t1, 3, 5 (default), 7\n"); + fprintf (stderr, "\tEnter 16bit DMA channel for Prosonic : "); + num = ask_value ("%d", 5); + } + while (num != 1 && num != 3 && num != 5 && num != 7); + fprintf (stderr, "ProSonic 16 bit DMA set to %d\n", num); + printf ("#define JAZZ_DMA16 %d\n", num); + + fprintf (stderr, "Do you have SoundMan Wave (n/y) ? "); + + if (think_positively (0)) + { + printf ("#define SM_WAVE\n"); + + midi0001_again: + fprintf + (stderr, + "Logitech SoundMan Wave has a microcontroller which must be initialized\n" + "before MIDI emulation works. This is possible only if the microcode\n" + "file is compiled into the driver.\n" + "Do you have access to the MIDI0001.BIN file (y/n) ? "); + if (think_positively (1)) + { + char path[512]; + + fprintf (stderr, + "Enter full name of the MIDI0001.BIN file (pwd is sound): "); + scanf ("%s", path); + fprintf (stderr, "including microcode file %s\n", path); + + if (!bin2hex (path, "smw-midi0001.h", "smw_ucode")) + { + fprintf (stderr, "couldn't open %s file\n", + path); + fprintf (stderr, "try again with correct path? "); + if (think_positively (1)) + goto midi0001_again; + } + else + printf ("#define SMW_MIDI0001_INCLUDED\n"); + } + } + } + } + + if (selected_options & B (OPT_SBPRO)) + { + fprintf (stderr, "\n\nThe Logitech SoundMan Games supports 44 kHz in stereo\n" + "while the standard SB Pro supports just 22 kHz/stereo\n" + "You have an option to enable the SM Games mode.\n" + "However do enable it only if you are _sure_ that your\n" + "card is a SM Games. Enabling this feature with a\n" + "plain old SB Pro _will_ cause troubles with stereo mode.\n" + "\n" + "DANGER! Read the above once again before answering 'y'\n" + "Answer 'n' in case you are unsure what to do!\n"); + fprintf (stderr, "Do you have a Logitech SoundMan Games (n/y) ? "); if (think_positively (0)) - printf("#define __SGNXPRO__\n"); + printf ("#define SM_GAMES\n"); } if (selected_options & B (OPT_SB16)) selected_options |= B (OPT_SBPRO); + if (selected_options & B (OPT_AEDSP16)) + { + int sel1 = 0; + + if (selected_options & B (OPT_SBPRO)) + { + fprintf (stderr, "Do you want support for the Audio Excel SoundBlaster pro mode ? "); + if (think_positively (1)) + { + printf ("#define AEDSP16_SBPRO\n"); + sel1 = 1; + } + } + + if ((selected_options & B (OPT_MSS)) && (sel1 == 0)) + { + fprintf (stderr, "Do you want support for the Audio Excel Microsoft Sound System mode? "); + if (think_positively (1)) + { + printf ("#define AEDSP16_MSS\n"); + sel1 = 1; + } + } + + if (sel1 == 0) + { + printf ("#undef CONFIGURE_SOUNDCARD\n"); + printf ("#undef KERNEL_SOUNDCARD\n"); + fprintf (stderr, "ERROR!!!!!\nYou loose: you must select at least one mode when using Audio Excel!\n"); + exit (-1); + } + if (selected_options & B (OPT_MPU401)) + printf ("#define AEDSP16_MPU401\n"); + } + if (selected_options & B (OPT_PSS)) { genld_again: @@ -339,8 +475,8 @@ (stderr, "if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n" "then you must include the LD in the kernel.\n" - "(do you wish to include a LD) ? "); - if (think_positively (0)) + "Do you wish to include a LD (y/n) ? "); + if (think_positively (1)) { char path[512]; @@ -348,57 +484,55 @@ "Enter the path to your LD file (pwd is sound): "); scanf ("%s", path); fprintf (stderr, "including LD file %s\n", path); - selected_options |= B (OPT_SB) | B (OPT_MPU401) | B (OPT_ADLIB); - /* Gen LD header */ - { - int fd; - int count; - char c; - int i = 0; - - if ((fd = open (path, 0)) > 0) - { - FILE *sf = fopen ("synth-ld.h", "w"); - - fprintf (sf, "/* automatically generated by configure */\n"); - fprintf (sf, "unsigned char pss_synth[] = {\n"); - while (1) - { - count = read (fd, &c, 1); - if (count == 0) - break; - if (i != 0 && (i % 10) == 0) - fprintf (sf, "\n"); - fprintf (sf, "0x%02x,", c & 0xFFL); - i++; - } - fprintf (sf, "};\n" - "#define pss_synthLen %d\n", i); - fclose (sf); - close (fd); - } - else - { - fprintf (stderr, "couldn't open %s as the ld file\n", - path); - fprintf (stderr, "try again with correct path? "); - if (think_positively (1)) - goto genld_again; - } - } + if (!bin2hex (path, "synth-ld.h", "pss_synth")) + { + fprintf (stderr, "couldn't open %s as the ld file\n", + path); + fprintf (stderr, "try again with correct path? "); + if (think_positively (1)) + goto genld_again; + } } else { FILE *sf = fopen ("synth-ld.h", "w"); - fprintf (sf, "/* automatically generated by configure */\n"); + fprintf (sf, "/* automaticaly generated by configure */\n"); fprintf (sf, "unsigned char pss_synth[1];\n" "#define pss_synthLen 0\n"); fclose (sf); } } + if (selected_options & B (OPT_TRIX)) + { + hex2hex_again: + fprintf (stderr, "MediaTriX audioTriX Pro has a onboard microcontroller\n" + "which needs to be initialized by downloading\n" + "the code from file TRXPRO.HEX in the DOS driver\n" + "directory. If you don't have the TRXPRO.HEX handy\n" + "you may skip this step. However SB and MPU-401\n" + "modes of AudioTriX Pro will not work without\n" + "this file!\n" + "\n" + "Do you want to include TRXPRO.HEX in your kernel (y/n) ? "); + + if (think_positively (1)) + { + char path[512]; + + fprintf (stderr, + "Enter the path to your TRXPRO.HEX file (pwd is sound): "); + scanf ("%s", path); + fprintf (stderr, "including HEX file %s\n", path); + + if (!hex2hex (path, "trix_boot.h", "static unsigned char trix_boot")) + goto hex2hex_again; + printf ("#define INCLUDE_TRIX_BOOT\n"); + } + } + if (!(selected_options & ANY_DEVS)) { printf ("#undef CONFIGURE_SOUNDCARD\n"); @@ -423,6 +557,20 @@ printf ("\n"); #if defined(linux) + if (selected_options & B (OPT_AEDSP16)) + { + fprintf (stderr, "\nI/O base for Audio Excel DSP 16 ?\n" + "Warning:\n" + "If you are using Audio Excel SoundBlaster emulation,\n" + "you must use the same I/O base for Audio Excel and SoundBlaster.\n" + "The factory default is 220 (other possible value is 240)\n" + "Enter the Audio Excel DSP 16 I/O base: "); + + num = ask_value ("%x", 0x220); + fprintf (stderr, "Audio Excel DSP 16 I/O base set to %03x\n", num); + printf ("#define AEDSP16_BASE 0x%03x\n", num); + } + if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI))) { fprintf (stderr, "\nI/O base for SB?\n" @@ -450,7 +598,7 @@ printf ("#define SBC_IRQ %d\n", num); - if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_PSS))) + if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS))) { fprintf (stderr, "\nDMA channel for SoundBlaster?\n" "For SB 1.0, 1.5 and 2.0 this MUST be 1\n" @@ -502,6 +650,7 @@ if (selected_options & B (OPT_PAS)) { + if (selected_options & (B (OPT_AUDIO) | B (OPT_MIDI))) { fprintf (stderr, "\nIRQ number for ProAudioSpectrum?\n" @@ -541,6 +690,17 @@ fprintf (stderr, "\nProAudioSpectrum DMA set to %d\n", num); printf ("#define PAS_DMA %d\n", num); } + fprintf (stderr, "\nEnable Joystick port on ProAudioSpectrum (n/y) ? "); + if (think_positively (0)) + printf ("#define PAS_JOYSTICK_ENABLE\n"); + + fprintf (stderr, "PAS16 could be noisy with some mother boards\n" + "There is a command line switch (was it :T?)\n" + "in the DOS driver for PAS16 which solves this.\n" + "Don't enable this feature unless you have problems!\n" + "Do you have to use this switch with DOS (y/n) ?"); + if (think_positively (0)) + printf ("#define BROKEN_BUS_CLOCK\n"); } if (selected_options & B (OPT_GUS)) @@ -602,6 +762,65 @@ } fprintf (stderr, "\nGravis UltraSound DMA set to %d\n", num); printf ("#define GUS_DMA %d\n", num); + + if (selected_options & B (OPT_GUSMAX)) + { + fprintf (stderr, "\nSecond DMA channel for GUS MAX (optional)?\n" + "The default value is 7 (0 disables)\n" + "Enter the value: "); + + num = ask_value ("%d", 7); + if (num > 0) + { + if (num > 7) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 7; + } + + fprintf (stderr, "\nGUSMAX DMA set to %d\n", num); + printf ("#define GUSMAX_DMA %d\n", num); + } + } + + if (selected_options & B (OPT_GUS16)) + { + fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n" + "The factory default is 530\n" + "Other possible values are 604, E80 or F40\n" + "Enter the GUS16 I/O base: "); + + num = ask_value ("%x", 0x530); + fprintf (stderr, "GUS16 I/O base set to %03x\n", num); + printf ("#define GUS16_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for GUS16?\n" + "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n" + "The default value is 7.\n" + "Enter the value: "); + + num = ask_value ("%d", 7); + if (num == 6 || num < 3 || num > 15) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 7; + } + fprintf (stderr, "GUS16 IRQ set to %d\n", num); + printf ("#define GUS16_IRQ %d\n", num); + + fprintf (stderr, "\nDMA number for GUS16?\n" + "The default value is 3\n" + "Enter the value: "); + + num = ask_value ("%d", 3); + if (num < 0 || num > 3) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 3; + } + fprintf (stderr, "\nGUS16 DMA set to %d\n", num); + printf ("#define GUS16_DMA %d\n", num); + } } if (selected_options & B (OPT_MPU401)) @@ -620,9 +839,7 @@ "Enter the value: "); num = ask_value ("%d", 9); - if (num == 6 || num < 3 || num > 15) /* - * Used for floppy - */ + if (num == 6 || num < 3 || num > 15) { fprintf (stderr, "*** Illegal input! ***\n"); @@ -635,15 +852,15 @@ if (selected_options & B (OPT_UART6850)) { fprintf (stderr, "\nI/O base for 6850 UART Midi?\n" - "Be careful. No defaults.\n" + "Be carefull. No defaults.\n" "Enter the 6850 UART I/O base: "); num = ask_value ("%x", 0); if (num == 0) { /* - * Invalid value entered - */ + * Invalid value entered + */ printf ("#define EXCLUDE_UART6850\n"); } else @@ -657,9 +874,7 @@ "Enter the value: "); num = ask_value ("%d", 5); - if (num == 6 || num < 3 || num > 15) /* - * Used for floppy - */ + if (num == 6 || num < 3 || num > 15) { fprintf (stderr, "*** Illegal input! ***\n"); @@ -673,7 +888,7 @@ if (selected_options & B (OPT_PSS)) { fprintf (stderr, "\nI/O base for PSS?\n" - "The factory default is 220\n" + "The factory default is 220 (240 also possible)\n" "Enter the PSS I/O base: "); num = ask_value ("%x", 0x220); @@ -686,7 +901,7 @@ "Enter the value: "); num = ask_value ("%d", 10); - if (num == 6 || num < 3 || num > 15) /* Used for floppy */ + if (num == 6 || num < 3 || num > 15) { fprintf (stderr, "*** Illegal input! ***\n"); num = 7; @@ -695,6 +910,44 @@ printf ("#define PSS_IRQ %d\n", num); fprintf (stderr, "\nDMA number for ECHO-PSS?\n" + "The default value is 5\n" + "Valid values are 5, 6 and 7\n" + "Enter the value: "); + + num = ask_value ("%d", 5); + if (num < 5 || num > 7) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 5; + } + fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num); + printf ("#define PSS_DMA %d\n", num); + + fprintf (stderr, "\nMSS (MS Sound System) I/O base for the PSS card?\n" + "The factory default is 530\n" + "Other possible values are 604, E80 or F40\n" + "Enter the MSS I/O base: "); + + num = ask_value ("%x", 0x530); + fprintf (stderr, "PSS/MSS I/O base set to %03x\n", num); + printf ("#define PSS_MSS_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for the MSS mode of PSS ?\n" + "Valid numbers are: 7, 9(=2), 10 and 11.\n" + "The default value is 11.\n" + "Enter the value: "); + + num = ask_value ("%d", 11); + if (num == 6 || num < 3 || num > 15) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 11; + } + fprintf (stderr, "PSS/MSS IRQ set to %d\n", num); + printf ("#define PSS_MSS_IRQ %d\n", num); + + fprintf (stderr, "\nMSS DMA number for PSS?\n" + "Valid values are 0, 1 and 3.\n" "The default value is 3\n" "Enter the value: "); @@ -704,8 +957,31 @@ fprintf (stderr, "*** Illegal input! ***\n"); num = 3; } - fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num); - printf ("#define PSS_DMA %d\n", num); + fprintf (stderr, "\nPSS/MSS DMA set to %d\n", num); + printf ("#define PSS_MSS_DMA %d\n", num); + + fprintf (stderr, "\nMIDI I/O base for PSS?\n" + "The factory default is 330\n" + "Enter the PSS MIDI I/O base: "); + + num = ask_value ("%x", 0x330); + fprintf (stderr, "PSS/MIDI I/O base set to %03x\n", num); + printf ("#define PSS_MPU_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for PSS MIDI?\n" + "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" + "The default value is 9.\n" + "Enter the value: "); + + num = ask_value ("%d", 9); + if (num == 6 || num < 3 || num > 15) + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 5; + } + fprintf (stderr, "PSS MIDI IRQ set to %d\n", num); + printf ("#define PSS_MPU_IRQ %d\n", num); } if (selected_options & B (OPT_MSS)) @@ -725,7 +1001,7 @@ "Enter the value: "); num = ask_value ("%d", 10); - if (num == 6 || num < 3 || num > 15) /* Used for floppy */ + if (num == 6 || num < 3 || num > 15) { fprintf (stderr, "*** Illegal input! ***\n"); num = 7; @@ -734,7 +1010,7 @@ printf ("#define MSS_IRQ %d\n", num); fprintf (stderr, "\nDMA number for MSS?\n" - "Valid values are 1 and 3 (sometimes 0)" + "Valid values are 0, 1 and 3.\n" "The default value is 3\n" "Enter the value: "); @@ -748,61 +1024,275 @@ printf ("#define MSS_DMA %d\n", num); } - if (selected_options & B (OPT_GUS16)) + if (selected_options & B (OPT_SSCAPE)) { - fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n" + int reveal_spea; + + fprintf (stderr, "\n(MIDI) I/O base for Ensoniq Soundscape?\n" + "The factory default is 330\n" + "Other possible values are 320, 340 or 350\n" + "Enter the Soundscape I/O base: "); + + num = ask_value ("%x", 0x330); + fprintf (stderr, "Soundscape I/O base set to %03x\n", num); + printf ("#define SSCAPE_BASE 0x%03x\n", num); + + fprintf (stderr, "Is your SoundScape card made/marketed by Reveal or Spea? "); + reveal_spea = think_positively (0); + if (reveal_spea) + printf ("#define REVEAL_SPEA\n"); + + fprintf (stderr, "\nIRQ number for Soundscape?\n"); + + if (reveal_spea) + fprintf (stderr, "Check valid interrupts from the manual of your card.\n"); + else + fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 10.\n"); + + fprintf (stderr, "The default value is 9.\n" + "Enter the value: "); + + num = ask_value ("%d", 9); + if (num == 6 || num < 3 || num > 15) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 9; + } + fprintf (stderr, "Soundscape IRQ set to %d\n", num); + printf ("#define SSCAPE_IRQ %d\n", num); + + fprintf (stderr, "\nDMA number for Soundscape?\n" + "Valid values are 1 and 3 (sometimes 0)" + "The default value is 3\n" + "Enter the value: "); + + num = ask_value ("%d", 3); + if (num == 4 || num < 0 || num > 7) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 3; + } + fprintf (stderr, "\nSoundscape DMA set to %d\n", num); + printf ("#define SSCAPE_DMA %d\n", num); + + fprintf (stderr, "\nMSS (MS Sound System) I/O base for the SSCAPE card?\n" + "The factory default is 534\n" + "Other possible values are 608, E84 or F44\n" + "Enter the MSS I/O base: "); + + num = ask_value ("%x", 0x534); + fprintf (stderr, "SSCAPE/MSS I/O base set to %03x\n", num); + printf ("#define SSCAPE_MSS_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for the MSS mode of SSCAPE ?\n"); + if (reveal_spea) + fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 15.\n"); + else + fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 10.\n"); + fprintf (stderr, "The default value is 5.\n" + "Enter the value: "); + + num = ask_value ("%d", 5); + if (num == 6 || num < 3 || num > 15) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 10; + } + fprintf (stderr, "SSCAPE/MSS IRQ set to %d\n", num); + printf ("#define SSCAPE_MSS_IRQ %d\n", num); + + fprintf (stderr, "\nMSS DMA number for SSCAPE?\n" + "Valid values are 0, 1 and 3.\n" + "The default value is 3\n" + "Enter the value: "); + + num = ask_value ("%d", 3); + if (num == 4 || num < 0 || num > 7) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 3; + } + fprintf (stderr, "\nSSCAPE/MSS DMA set to %d\n", num); + printf ("#define SSCAPE_MSS_DMA %d\n", num); + } + if (selected_options & B (OPT_TRIX)) + { + + fprintf (stderr, "\nWindows Sound System I/O base for the AudioTriX card?\n" "The factory default is 530\n" "Other possible values are 604, E80 or F40\n" - "Enter the GUS16 I/O base: "); + "Enter the MSS I/O base: "); num = ask_value ("%x", 0x530); - fprintf (stderr, "GUS16 I/O base set to %03x\n", num); - printf ("#define GUS16_BASE 0x%03x\n", num); + fprintf (stderr, "AudioTriX MSS I/O base set to %03x\n", num); + printf ("#define TRIX_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for the WSS mode of AudioTriX ?\n" + "Valid numbers are: 5, 7, 9(=2), 10 and 11.\n" + "The default value is 11.\n" + "Enter the value: "); + + num = ask_value ("%d", 11); + if (num != 5 && num != 7 && num != 9 && num != 10 && num != 11) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 11; + } + fprintf (stderr, " AudioTriX WSS IRQ set to %d\n", num); + printf ("#define TRIX_IRQ %d\n", num); - fprintf (stderr, "\nIRQ number for GUS16?\n" - "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n" + fprintf (stderr, "\nWSS DMA number for AudioTriX?\n" + "Valid values are 0, 1 and 3.\n" + "The default value is 3\n" + "Enter the value: "); + + num = ask_value ("%d", 3); + if (num != 0 && num != 1 && num != 3) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 3; + } + fprintf (stderr, "\nAudioTriX/WSS DMA set to %d\n", num); + printf ("#define TRIX_DMA %d\n", num); + + fprintf (stderr, "\nSoundBlaster I/O address for the AudioTriX card?\n" + "The factory default is 220\n" + "Other possible values are 200, 210, 230, 240, 250, 260 and 270\n" + "Enter the MSS I/O base: "); + + num = ask_value ("%x", 0x220); + fprintf (stderr, "AudioTriX SB I/O base set to %03x\n", num); + printf ("#define TRIX_SB_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for the SB mode of AudioTriX ?\n" + "Valid numbers are: 3, 4, 5 and 7.\n" "The default value is 7.\n" "Enter the value: "); num = ask_value ("%d", 7); - if (num == 6 || num < 3 || num > 15) /* Used for floppy */ + if (num != 3 && num != 4 && num != 5 && num != 7) { fprintf (stderr, "*** Illegal input! ***\n"); num = 7; } - fprintf (stderr, "GUS16 IRQ set to %d\n", num); - printf ("#define GUS16_IRQ %d\n", num); + fprintf (stderr, " AudioTriX SB IRQ set to %d\n", num); + printf ("#define TRIX_SB_IRQ %d\n", num); + + fprintf (stderr, "\nSB DMA number for AudioTriX?\n" + "Valid values are 1 and 3.\n" + "The default value is 1\n" + "Enter the value: "); + + num = ask_value ("%d", 1); + if (num != 1 && num != 3) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 1; + } + fprintf (stderr, "\nAudioTriX/SB DMA set to %d\n", num); + printf ("#define TRIX_SB_DMA %d\n", num); + + fprintf (stderr, "\nMIDI (MPU-401) I/O address for the AudioTriX card?\n" + "The factory default is 330\n" + "Other possible values are 330, 370, 3B0 and 3F0\n" + "Enter the MPU I/O base: "); + + num = ask_value ("%x", 0x330); + fprintf (stderr, "AudioTriX MIDI I/O base set to %03x\n", num); + printf ("#define TRIX_MPU_BASE 0x%03x\n", num); + + fprintf (stderr, "\nMIDI IRQ number for the AudioTriX ?\n" + "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" + "The default value is 5.\n" + "Enter the value: "); + + num = ask_value ("%d", 5); + if (num != 3 && num != 4 && num != 5 && num != 7 && num != 9) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 5; + } + fprintf (stderr, " AudioTriX MIDI IRQ set to %d\n", num); + printf ("#define TRIX_MPU_IRQ %d\n", num); + } + + if (selected_options & B (OPT_MAD16)) + { + fprintf (stderr, "\n*** Options for the MAD16 and Mozart based cards ***\n\n"); + + fprintf (stderr, "\nWindows Sound System I/O base for the MAD16/Mozart card?\n" + "The factory default is 530\n" + "Other possible values are 604, E80 or F40\n" + "(Check which ones are supported by your card!!!!!!)\n" + "Enter the MSS I/O base: "); + + num = ask_value ("%x", 0x530); + fprintf (stderr, "MAD16 MSS I/O base set to %03x\n", num); + printf ("#define MAD16_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for the WSS mode of MAD16/Mozart ?\n" + "Valid numbers are: 7, 9(=2), 10 and 11.\n" + "The default value is 11.\n" + "Enter the value: "); + + num = ask_value ("%d", 11); + if (num != 7 && num != 9 && num != 10 && num != 11) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 11; + } + fprintf (stderr, " MAD16 WSS IRQ set to %d\n", num); + printf ("#define MAD16_IRQ %d\n", num); - fprintf (stderr, "\nDMA number for GUS16?\n" + fprintf (stderr, "\nWSS DMA number for MAD16/Mozart?\n" + "Valid values are 0, 1 and 3.\n" "The default value is 3\n" "Enter the value: "); num = ask_value ("%d", 3); - if (num < 0 || num > 3) + if (num != 0 && num != 1 && num != 3) { fprintf (stderr, "*** Illegal input! ***\n"); num = 3; } - fprintf (stderr, "\nGUS16 DMA set to %d\n", num); - printf ("#define GUS16_DMA %d\n", num); + fprintf (stderr, "\nMAD16/WSS DMA set to %d\n", num); + printf ("#define MAD16_DMA %d\n", num); + + fprintf (stderr, "\nMIDI (MPU-401) I/O address for the MAD16 card?\n" + "(MPU401 is not supported by Mozart and 82C928)\n" + "(This is the second MIDI port in TB Tropez)\n" + "The factory default is 330 (use 0 to disable)\n" + "Other possible values are 330, 320, 310 and 300\n" + "Enter the MPU I/O base: "); + + num = ask_value ("%x", 0x330); + if (num == 0) + fprintf (stderr, "MAD16/Mozart MIDI port disabled\n"); + else + { + fprintf (stderr, "MAD16 MIDI I/O base set to %03x\n", num); + printf ("#define MAD16_MPU_BASE 0x%03x\n", num); + + fprintf (stderr, "\nMIDI IRQ number for the MAD16 ?\n" + "Valid numbers are: 5, 7, 9(=2) and 10.\n" + "The default value is 5.\n" + "Enter the value: "); + + num = ask_value ("%d", 5); + if (num != 3 && num != 4 && num != 5 && num != 7 && num != 9) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 5; + } + fprintf (stderr, " MAD16 MIDI IRQ set to %d\n", num); + printf ("#define MAD16_MPU_IRQ %d\n", num); + } } #endif if (selected_options & B (OPT_AUDIO)) { - def_size = 16384; - - if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_SB16))) - def_size = 32768; - -#ifndef __386BSD__ - if ((selected_options & (B (OPT_PAS) | B (OPT_PAS) | B (OPT_GUS16) | B (OPT_GUSMAX) | - B (OPT_MSS) | B (OPT_PSS))) && - !full_driver) - def_size = 65536; /* - * PAS16 or SB16 - */ -#endif + def_size = 65536; fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n" "%d is recommended value for this configuration.\n" @@ -827,4 +1317,38 @@ #endif exit (0); +} + +int +bin2hex (char *path, char *target, char *varname) +{ + int fd; + int count; + char c; + int i = 0; + + if ((fd = open (path, 0)) > 0) + { + FILE *sf = fopen (target, "w"); + + fprintf (sf, "/* automaticaly generated by configure */\n"); + fprintf (sf, "static unsigned char %s[] = {\n", varname); + while (1) + { + count = read (fd, &c, 1); + if (count == 0) + break; + if (i != 0 && (i % 10) == 0) + fprintf (sf, "\n"); + fprintf (sf, "0x%02x,", c & 0xFFL); + i++; + } + fprintf (sf, "};\n" + "#define %sLen %d\n", varname, i); + fclose (sf); + close (fd); + return 1; + } + + return 0; } diff -u --recursive --new-file v1.3.8/linux/drivers/sound/coproc.h linux/drivers/sound/coproc.h --- v1.3.8/linux/drivers/sound/coproc.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/coproc.h Fri Mar 3 12:03:07 1995 @@ -0,0 +1,12 @@ +/* + * Definitions for various on board processors on the soundcards. For + * example DSP processors. + */ + +/* + * Coprocessor access types + */ +#define COPR_CUSTOM 0x0001 /* Custom applications */ +#define COPR_MIDI 0x0002 /* MIDI (MPU-401) emulation */ +#define COPR_PCM 0x0004 /* Digitized voice applications */ +#define COPR_SYNTH 0x0008 /* Music synthesis */ diff -u --recursive --new-file v1.3.8/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v1.3.8/linux/drivers/sound/dev_table.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/dev_table.c Mon Jul 10 01:45:05 1995 @@ -52,6 +52,8 @@ int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); int drv; + printk ("Sound initialization started\n"); + for (i = 0; i < (n - 1); i++) if (snd_installed_cards[i].enabled) if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) @@ -77,74 +79,75 @@ snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ + printk ("Sound initialization complete\n"); return mem_start; } int sndtable_probe (int unit, struct address_info *hw_config) - { - int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); +{ + int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); - if (!unit) - return TRUE; + if (!unit) + return TRUE; + + for (i = 0; i < (n - 1); i++) + if (snd_installed_cards[i].enabled) + if (snd_installed_cards[i].card_type == unit) + { + int drv; - for (i = 0; i < (n - 1); i++) - if (snd_installed_cards[i].enabled) - if (snd_installed_cards[i].card_type == unit) - { - int drv; - - snd_installed_cards[i].config.io_base = hw_config->io_base; - snd_installed_cards[i].config.irq = hw_config->irq; - snd_installed_cards[i].config.dma = hw_config->dma; - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) - snd_installed_cards[i].enabled = 0; /* + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; + if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* * Mark as not * detected */ - else if (sound_drivers[drv].probe (hw_config)) - return 1; - snd_installed_cards[i].enabled = 0; /* + else if (sound_drivers[drv].probe (hw_config)) + return 1; + snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ - return 0; - } + return 0; + } - return FALSE; - } + return FALSE; +} int sndtable_init_card (int unit, struct address_info *hw_config) - { - int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); +{ + int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); - if (!unit) + if (!unit) + { + if (sndtable_init (0) != 0) + panic ("snd: Invalid memory allocation\n"); + return TRUE; + } + + for (i = 0; i < (n - 1); i++) + if (snd_installed_cards[i].card_type == unit) { - if (sndtable_init (0) != 0) - panic ("snd: Invalid memory allocation\n"); - return TRUE; - } + int drv; - for (i = 0; i < (n - 1); i++) - if (snd_installed_cards[i].card_type == unit) - { - int drv; + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; - snd_installed_cards[i].config.io_base = hw_config->io_base; - snd_installed_cards[i].config.irq = hw_config->irq; - snd_installed_cards[i].config.dma = hw_config->dma; - - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) - snd_installed_cards[i].enabled = 0; /* + if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ - else if (sound_drivers[drv].attach (0, hw_config) != 0) - panic ("snd#: Invalid memory allocation\n"); - return TRUE; - } + else if (sound_drivers[drv].attach (0, hw_config) != 0) + panic ("snd#: Invalid memory allocation\n"); + return TRUE; + } - return FALSE; - } + return FALSE; +} int sndtable_get_cardcount (void) @@ -159,8 +162,8 @@ int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); /* - * First disable all drivers - */ + * First disable all drivers + */ for (i = 0; i < n; i++) snd_installed_cards[i].enabled = 0; @@ -168,8 +171,8 @@ if (ints[0] == 0 || ints[1] == 0) return; /* - * Then enable them one by time - */ + * Then enable them one by time + */ for (i = 1; i <= ints[0]; i++) { diff -u --recursive --new-file v1.3.8/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v1.3.8/linux/drivers/sound/dev_table.h Wed Jul 20 15:00:29 1994 +++ linux/drivers/sound/dev_table.h Wed Jul 5 22:34:45 1995 @@ -107,6 +107,20 @@ int underrun_count; }; +/* + * Structure for use with various microcontrollers and DSP processors + * in the recent soundcards. + */ +typedef struct coproc_operations { + char name[32]; + int (*open) (void *devc, int sub_device); + void (*close) (void *devc, int sub_device); + int (*ioctl) (void *devc, unsigned int cmd, unsigned int arg, int local); + void (*reset) (void *devc); + + void *devc; /* Driver specific info */ + } coproc_operations; + struct audio_operations { char name[32]; int flags; @@ -133,9 +147,12 @@ long buffsize; int dmachan; struct dma_buffparms *dmap; + struct coproc_operations *coproc; + int mixer_dev; }; struct mixer_operations { + char name[32]; int (*ioctl) (int dev, unsigned int cmd, unsigned int arg); }; @@ -162,14 +179,29 @@ int (*pmgr_interface) (int dev, struct patmgr_info *info); void (*bender) (int dev, int chn, int value); int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc); + void (*setup_voice) (int dev, int voice, int chn); struct voice_alloc_info alloc; struct channel_info chn_info[16]; }; +struct midi_input_info { /* MIDI input scanner variables */ +#define MI_MAX 10 + int m_busy; + unsigned char m_buf[MI_MAX]; + unsigned char m_prev_status; /* For running status */ + int m_ptr; +#define MST_INIT 0 +#define MST_DATA 1 +#define MST_SYSEX 2 + int m_state; + int m_left; + }; + struct midi_operations { struct midi_info info; struct synth_operations *converter; + struct midi_input_info in_info; int (*open) (int dev, int mode, void (*inputintr)(int dev, unsigned char data), void (*outputintr)(int dev) @@ -183,6 +215,7 @@ int (*command) (int dev, unsigned char *data); int (*buffer_status) (int dev); int (*prefix_cmd) (int dev, unsigned char status); + struct coproc_operations *coproc; }; struct sound_timer_operations { @@ -221,6 +254,16 @@ struct driver_info sound_drivers[] = { #ifndef EXCLUDE_PSS {SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss}, +# ifdef PSS_MPU_BASE + {SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu}, +# endif +# ifdef PSS_MSS_BASE + {SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss}, +# endif +#endif +#ifndef EXCLUDE_MAD16 + {SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16}, + {SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)", attach_mad16_mpu, probe_mad16_mpu}, #endif #ifndef EXCLUDE_YM3812 {SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib}, @@ -254,9 +297,19 @@ #ifndef EXCLUDE_GUS {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus}, #endif +#ifndef EXCLUDE_SSCAPE + {SNDCARD_SSCAPE, "Ensoniq Soundscape", attach_sscape, probe_sscape}, + {SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound}, +#endif +#ifndef EXCLUDE_TRIX + {SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro", attach_trix_wss, probe_trix_wss}, + {SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)", attach_trix_sb, probe_trix_sb}, + {SNDCARD_TRXPRO_MPU, "AudioTriX MIDI", attach_trix_mpu, probe_trix_mpu}, +#endif {0, "*?*", NULL, NULL} }; +#ifdef linux /* * List of devices actually configured in the system. * @@ -266,16 +319,33 @@ struct card_info snd_installed_cards[] = { #ifndef EXCLUDE_PSS {SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE}, +# ifdef PSS_MPU_BASE + {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, +# endif +# ifdef PSS_MSS_BASE + {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA}, SND_DEFAULT_ENABLE}, +# endif #endif -#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) - {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, -#ifdef MPU2_BASE - {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, -#endif -#ifdef MPU3_BASE - {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, +#ifndef EXCLUDE_TRIX + {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA}, SND_DEFAULT_ENABLE}, +# ifdef TRIX_SB_BASE + {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA}, SND_DEFAULT_ENABLE}, +# endif +# ifdef TRIX_MPU_BASE + {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, +# endif #endif +#ifndef EXCLUDE_SSCAPE + {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA}, SND_DEFAULT_ENABLE}, + {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA}, SND_DEFAULT_ENABLE}, +#endif +#ifndef EXCLUDE_MAD16 + {SNDCARD_MAD16, {MAD16_BASE, MAD16_IRQ, MAD16_DMA}, SND_DEFAULT_ENABLE}, +# ifdef MAD16_MPU_BASE + {SNDCARD_MAD16_MPU, {MAD16_MPU_BASE, MAD16_MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, +# endif #endif + #ifndef EXCLUDE_MSS {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE}, # ifdef MSS2_BASE @@ -283,18 +353,31 @@ # endif #endif -#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) - {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE}, -#endif - #ifndef EXCLUDE_PAS {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE}, #endif #ifndef EXCLUDE_SB +# ifndef SBC_DMA +# define SBC_DMA 1 +# endif {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE}, #endif +#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) + {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, +#ifdef MPU2_BASE + {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif +#ifdef MPU3_BASE + {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif +#endif + +#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) + {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif + #if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) #ifndef EXCLUDE_AUDIO {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE}, @@ -317,11 +400,15 @@ {0, {0}, 0} }; - int num_sound_drivers = - sizeof(sound_drivers) / sizeof (struct driver_info); int num_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); +#else + int num_sound_cards = 0; +#endif /* linux */ + + int num_sound_drivers = + sizeof(sound_drivers) / sizeof (struct driver_info); #else extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs; diff -u --recursive --new-file v1.3.8/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v1.3.8/linux/drivers/sound/dmabuf.c Mon Mar 6 11:22:09 1995 +++ linux/drivers/sound/dmabuf.c Mon Jul 10 01:45:06 1995 @@ -3,7 +3,7 @@ * * The DMA buffer manager for digitized voice applications * - * Copyright by Hannu Savolainen 1993, 1994 + * Copyright by Hannu Savolainen 1993, 1994, 1995 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -38,11 +38,13 @@ DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]); static struct dma_buffparms dmaps[MAX_AUDIO_DEV] = -{{0}}; /* - * Primitive way to allocate - * such a large array. - * Needs dynamic run-time allocation. - */ +{ + {0}}; /* + + * Primitive way to allocate + * such a large array. + * Needs dynamic run-time alloction. + */ static void reorganize_buffers (int dev) @@ -78,10 +80,10 @@ sz = sr * nc * sz; /* - * Compute a buffer size for time not exceeding 1 second. - * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds - * of sound (using the current speed, sample size and #channels). - */ + * Compute a buffer size for time not exeeding 1 second. + * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds + * of sound (using the current speed, sample size and #channels). + */ bsz = dsp_dev->buffsize; while (bsz > sz) @@ -106,9 +108,9 @@ else { /* - * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or - * the buffer size computation has already been done. - */ + * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or + * the buffer sice computation has already been done. + */ if (dmap->fragment_size > audio_devs[dev]->buffsize) dmap->fragment_size = audio_devs[dev]->buffsize; bsz = dmap->fragment_size; @@ -157,7 +159,6 @@ dmap->flags = DMA_BUSY; /* Other flags off */ dmap->qlen = dmap->qhead = dmap->qtail = 0; - dmap->qlen = dmap->qtail = dmap->qhead = 0; dmap->dma_mode = DMODE_NONE; } @@ -250,7 +251,7 @@ /* * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait util the device has finished playing. + * audio data. We have to wait until the device has finished playing. */ DISABLE_INTR (flags); @@ -295,7 +296,7 @@ } int -DMAbuf_getrdbuffer (int dev, char **buf, int *len) +DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { unsigned long flags; int err = EIO; @@ -342,6 +343,12 @@ dmap->flags |= DMA_ACTIVE | DMA_STARTED; } + if (dontblock) + { + RESTORE_INTR (flags); + return RET_ERROR (EAGAIN); + } + /* Wait for the next block */ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); @@ -425,7 +432,7 @@ } if (dmap->subdivision != 0 || - dmap->fragment_size)/* Too late to change */ + dmap->fragment_size) /* Loo late to change */ return RET_ERROR (EINVAL); if (fact > MAX_REALTIME_FACTOR) @@ -448,7 +455,7 @@ return RET_ERROR (EIO); if (dmap->subdivision != 0 || - dmap->fragment_size)/* Too late to change */ + dmap->fragment_size) /* Loo late to change */ return RET_ERROR (EINVAL); bytes = fact & 0xffff; @@ -478,11 +485,24 @@ } break; + case SNDCTL_DSP_GETISPACE: + case SNDCTL_DSP_GETOSPACE: + if (!local) + return RET_ERROR (EINVAL); + + { + audio_buf_info *info = (audio_buf_info *) arg; + + info->fragments = dmap->qlen; + info->fragsize = dmap->fragment_size; + info->bytes = dmap->qlen * dmap->fragment_size; + } + return 0; + default: return audio_devs[dev]->ioctl (dev, cmd, arg, local); } - return RET_ERROR (EIO); } static int @@ -491,13 +511,13 @@ int len, max, tmp; struct dma_buffparms *dmap = audio_devs[dev]->dmap; - if (dmap->qlen == dmap->nbufs)/* No space at all */ + if (dmap->qlen == dmap->nbufs) /* No space at all */ return 0; /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ + * Verify that there are no more pending buffers than the limit + * defined by the process. + */ max = dmap->max_fragments; len = dmap->qlen; @@ -507,8 +527,8 @@ tmp = audio_devs[dev]->local_qlen (dev); if (tmp & len) tmp--; /* - * This buffer has been counted twice - */ + * This buffer has been counted twice + */ len += tmp; } @@ -518,7 +538,7 @@ } int -DMAbuf_getwrbuffer (int dev, char **buf, int *size) +DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { unsigned long flags; int abort, err = EIO; @@ -551,6 +571,9 @@ } + if (dontblock) + return RET_ERROR (EAGAIN); + DISABLE_INTR (flags); abort = 0; @@ -669,13 +692,24 @@ #ifndef DMAMODE_AUTO printk ("sound: Invalid DMA mode for device %d\n", dev); #endif +#if defined(SVR42) + + /* + ** send full count to snd_dma_prog, it will take care of subtracting + ** one if it is required. + */ + snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use, + dma_mode, TRUE); + +#else /* !SVR42 */ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) #ifdef DMAMODE_AUTO | DMAMODE_AUTO #endif , - dmap->raw_buf_phys[0], dmap->bytes_in_use); + dmap->raw_buf_phys[0], dmap->bytes_in_use - 1); dma_enable (chan); +#endif /* ! SVR42 */ #else #error This routine is not valid for this OS. #endif @@ -703,9 +737,15 @@ #else #if defined(GENERIC_SYSV) +#if defined(SVR42) + + snd_dma_prog (chan, physaddr, count, dma_mode, FALSE); + +#else /* ! SVR42 */ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode), physaddr, count); dma_enable (chan); +#endif /* SVR42 */ #else #error This routine is not valid for this OS. #endif /* GENERIC_SYSV */ @@ -722,9 +762,13 @@ { int dev; +#if defined(SVR42) + snd_dma_init (); +#endif /* SVR42 */ + /* - * NOTE! This routine could be called several times. - */ + * NOTE! This routine could be called several times. + */ for (dev = 0; dev < num_audiodevs; dev++) audio_devs[dev]->dmap = &dmaps[dev]; @@ -735,18 +779,22 @@ DMAbuf_outputintr (int dev, int event_type) { /* - * Event types: - * 0 = DMA transfer done. Device still has more data in the local - * buffer. - * 1 = DMA transfer done. Device doesn't have local buffer or it's - * empty now. - * 2 = No DMA transfer but the device has now more space in its local - * buffer. - */ + * Event types: + * 0 = DMA transfer done. Device still has more data in the local + * buffer. + * 1 = DMA transfer done. Device doesn't have local buffer or it's + * empty now. + * 2 = No DMA transfer but the device has now more space in it's local + * buffer. + */ unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap; +#if defined(SVR42) + snd_dma_intr (audio_devs[dev]->dmachan); +#endif /* SVR42 */ + if (event_type != 2) { if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) @@ -793,6 +841,10 @@ unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap; +#if defined(SVR42) + snd_dma_intr (audio_devs[dev]->dmachan); +#endif /* SVR42 */ + if (dmap->qlen == (dmap->nbufs - 1)) { printk ("Sound: Recording overrun\n"); @@ -832,7 +884,7 @@ unsigned long flags; int chan = audio_devs[dev]->dmachan; - if (ALLOC_DMA_CHN (chan,"audio")) + if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name)) { printk ("Unable to grab DMA%d for the audio driver\n", chan); return RET_ERROR (EBUSY); @@ -853,24 +905,72 @@ { int chan = audio_devs[dev]->dmachan; - DMAbuf_reset_dma (chan); + DMAbuf_reset_dma (dev); RELEASE_DMA_CHN (chan); } void -DMAbuf_reset_dma (int chan) +DMAbuf_reset_dma (int dev) { +#if 0 + int chan = audio_devs[dev]->dmachan; + + disable_dma (chan); +#endif } -/* - * The sound_mem_init() is called by mem_init() immediately after mem_map is - * initialized and before free_page_list is created. - * - * This routine allocates DMA buffers at the end of available physical memory ( - * <16M) and marks pages reserved at mem_map. - */ +#ifdef ALLOW_SELECT +int +DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +{ + struct dma_buffparms *dmap = audio_devs[dev]->dmap; + unsigned long flags; -#else + switch (sel_type) + { + case SEL_IN: + if (dmap->dma_mode != DMODE_INPUT) + return 0; + + if (!dmap->qlen) + { + DISABLE_INTR (flags); + dev_sleep_flag[dev].mode = WK_SLEEP; + select_wait (&dev_sleeper[dev], wait); + RESTORE_INTR (flags); + return 0; + } + return 1; + break; + + case SEL_OUT: + if (dmap->dma_mode == DMODE_INPUT) + return 0; + + if (dmap->dma_mode == DMODE_NONE) + return 1; + + if (!space_in_queue (dev)) + { + DISABLE_INTR (flags); + dev_sleep_flag[dev].mode = WK_SLEEP; + select_wait (&dev_sleeper[dev], wait); + RESTORE_INTR (flags); + return 0; + } + return 1; + break; + + case SEL_EX: + return 0; + } + + return 0; +} + +#endif /* ALLOW_SELECT */ + +#else /* EXCLUDE_AUDIO */ /* * Stub versions if audio services not included */ @@ -888,13 +988,13 @@ } int -DMAbuf_getwrbuffer (int dev, char **buf, int *size) +DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { return RET_ERROR (EIO); } int -DMAbuf_getrdbuffer (int dev, char **buf, int *len) +DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { return RET_ERROR (EIO); } @@ -930,19 +1030,19 @@ } int -DMAbuf_open_dma (int chan) +DMAbuf_open_dma (int dev) { return RET_ERROR (ENXIO); } void -DMAbuf_close_dma (int chan) +DMAbuf_close_dma (int dev) { return; } void -DMAbuf_reset_dma (int chan) +DMAbuf_reset_dma (int dev) { return; } diff -u --recursive --new-file v1.3.8/linux/drivers/sound/experimental.txt linux/drivers/sound/experimental.txt --- v1.3.8/linux/drivers/sound/experimental.txt Mon Mar 6 11:22:09 1995 +++ linux/drivers/sound/experimental.txt Sun Apr 2 13:55:09 1995 @@ -1,12 +1,10 @@ -This version contains some features which is are NOT enabled by default. +This version contains some features which is may NOT be enabled by default. I'm trying to release an official/reliable version soon so that the Linux version of Doom (and other games) becomes possible. For that reason I have disabled some features which are not reliable enough to be released for wide public. If you are interested to try them, please read this file carefully. -There are currently following goodies which I have disabled: - 1) ECHO PSS (Personal Sound System support) This version contains support for soundcards based on the AD20msp614 @@ -21,38 +19,20 @@ You have also to enable the MSS support since I have not integrated the AD1848 driver with the PSS one yet. -2) WSS/MSS (Microsoft Sound System) support - -The MSS standard is based on the AD1848 codec by Analog Devices. -Since I don't know how the software configuration of the MSS works -so it's not supported yet. This driver should work if your card -has jumpers for the I/O base, IRQ and DMA or there is a way to configure -them using DOS. You could try this if you have a soundcard with -AD1848 codec. I have tried to use this with Aztech SG NX Pro 16 without -success. -If you are interested, remove the B(OPT_MSS) from the DISABLED_OPTIONS -(see above). - -3) /dev/sequencer2 +2) /dev/music (/dev/sequencer2) -This version has a new device file called /dev/sequence2. I have not +This version has a new device file called /dev/music. I have not implemented all parts of it but it's there. It's only interesting if you are writing a sequencer program yourself. Enable by creating -the device file /dev/sequencer (minor 8). +the device file /dev/music. Use the script at the end of linux/Readme -4) /dev/midi## +3) /dev/midi## These are tty like raw devices for MIDI ports. Since there is a minor incompatibility between different versions of Linux, I have disabled this feature by default. You just need to create the device files yourself. -IMPORTANT! If you get warning at line 64 of midibuf.c, - don't try to use /dev/midi## files. Otherwise your - system halts. You may also try to fix the - DEFINE_TIMER() macro in os.h (just remove the 2nd NULL). - This could happen with some earlier versions of Linux - (before 1.1.0???). -5) Support for hardware based u-Law/A-Law and ADPCM formats. +4) Support for hardware based u-Law/A-Law and ADPCM formats. The AD1848 (and compatibles) are able to do compression and decompression by hardware. This version has experimental support @@ -95,7 +75,7 @@ 2a) If the fragment gets played before the application writes a new - one, the device will be stopped and restarted which causes a click. + one, the device will be stoppen and restarted which causes a click. When the process calls write next time, it will be processes as in step 1. @@ -121,13 +101,13 @@ the process blocks for at most the time required to play a buffer fragment. -This method synchronizes the process and the audio device together -automatically. The process will block at most the 'fragment_time'. Usually +This method syncronizes the process and the audio device together +automaticly. The process will block at most the 'fragment_time'. Usually less, depending on how much it needs time to do other things. The maximum delay between writing a byte and the time when it finally plays is at most 3 times the 'fragment_time'. -The delay depends on how much time the program needs to do its +The delay depends on how much time the program needs to do it's computations for the next sample (updating screen etc). If it's about 80% of the 'fragment_time' the game will run almost without delays. If it uses more time, there is a risk that the audio buffer gets empty. @@ -142,7 +122,7 @@ ioctl(NDCTL_DSP_SPEED); /* And #channels & #bits if required */ /* - * Query the actual fragment size since the driver may refuse + * Query the actual fragment sice since the driver may refuse * the requested one (unlikely but possible?) */ @@ -157,4 +137,29 @@ I have tested this with a modified version of str.c. The algorithm works as long as the playing program gets enough time to run. Hitting ENTER on another virtual console causes a pause/click (with 2 frags of 64 bytes). + +NOTE! It's important to know that this call may be called just once and +it must be done immediately after open(). The fragment size will remain +in effect until the device is closed. ------------------- cut here --------------------- + +6) Detection and initialization code for Ensoniq Soundscape + +This version is able to initialize SoundScape (almost). However +PCM recording and playback don't work. Also MIDI playback sounds wierd +since the driver is not able to set volume controls properly. +The soundscape support is disabled. You need to enable it by editing +beginning of configure.c. Also read comments in sndscape/README. + +7) select() support for /dev/audio and /dev/dsp. (/dev/midi## and + /dev/sequencer had it already in v2.90). + +There is now select() support in the audio/dsp driver (for Linux only). +However I have not tried this feature yet. +There are also some new ioctl() calls (please look at soundcard.h). + +8) MIDI recording in /dev/music (/dev/sequencer2) + +MIDI recording was earlier implemented only with full MPU-401 devices. +This version has it also for dumb MIDI ports. However I have not tested it +yet. diff -u --recursive --new-file v1.3.8/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v1.3.8/linux/drivers/sound/gus_card.c Fri Jan 20 10:23:41 1995 +++ linux/drivers/sound/gus_card.c Mon Jul 10 01:45:06 1995 @@ -33,7 +33,7 @@ #include "gus_hw.h" -void gusintr (int, struct pt_regs * regs); +void gusintr (INT_HANDLER_PARMS (irq, dummy)); int gus_base, gus_irq, gus_dma; extern int gus_wave_volume; @@ -45,7 +45,7 @@ { int io_addr; - snd_set_irq_handler (hw_config->irq, gusintr); + snd_set_irq_handler (hw_config->irq, gusintr, "Gravis Ultrasound"); if (gus_wave_detect (hw_config->io_base)) /* * Try first the default @@ -118,7 +118,7 @@ } void -gusintr (int irq, struct pt_regs * regs) +gusintr (INT_HANDLER_PARMS (irq, dummy)) { unsigned char src; @@ -128,7 +128,7 @@ #ifndef EXCLUDE_GUSMAX if (have_gus_max) - ad1848_interrupt (irq, regs); + ad1848_interrupt (INT_HANDLER_CALL (irq)); #endif while (1) diff -u --recursive --new-file v1.3.8/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v1.3.8/linux/drivers/sound/gus_midi.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/gus_midi.c Mon Jul 10 01:45:06 1995 @@ -231,6 +231,7 @@ { {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, &std_midi_synth, + {0}, gus_midi_open, gus_midi_close, gus_midi_ioctl, @@ -296,10 +297,12 @@ } } +#if 0 if (stat & MIDI_FRAME_ERR) - printk ("Midi framing error\n"); + printk ("GUS: Midi framing error\n"); if (stat & MIDI_OVERRUN && input_opened) printk ("GUS: Midi input overrun\n"); +#endif RESTORE_INTR (flags); } diff -u --recursive --new-file v1.3.8/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v1.3.8/linux/drivers/sound/gus_wave.c Tue Jan 17 07:49:57 1995 +++ linux/drivers/sound/gus_wave.c Mon Jul 10 19:25:31 1995 @@ -33,7 +33,7 @@ #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) -#define MAX_SAMPLE 128 +#define MAX_SAMPLE 150 #define MAX_PATCH 256 struct voice_info @@ -76,14 +76,18 @@ extern int gus_base; extern int gus_irq, gus_dma; +static int gusmax_dma = -1; +static int dual_dma_mode = 0; static long gus_mem_size = 0; static long free_mem_ptr = 0; static int gus_busy = 0; +static int gus_no_dma = 0; static int nr_voices = 0; static int gus_devnum = 0; static int volume_base, volume_scale, volume_method; static int gus_recmask = SOUND_MASK_MIC; static int recording_active = 0; +static int only_read_access = 0; int gus_wave_volume = 60; int gus_pcm_volume = 80; @@ -474,10 +478,12 @@ DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_volume (0); + gus_voice_off (); gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */ gus_write8 (0x00, 0x03); /* Voice off */ gus_write8 (0x0d, 0x03); /* Ramping off */ voice_alloc->map[voice] = 0; + voice_alloc->alloc_times[voice] = 0; RESTORE_INTR (flags); } @@ -672,7 +678,7 @@ unsigned char dma_image, irq_image, tmp; static unsigned char gus_irq_map[16] = - {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7}; + {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; static unsigned char gus_dma_map[8] = {0, 1, 0, 2, 0, 3, 4, 5}; @@ -716,7 +722,7 @@ OUTB (0x05, gus_base + 0x0f); - mix_image |= 0x02; /* Disable line out */ + mix_image |= 0x02; /* Disable line out (for a moment) */ OUTB (mix_image, u_Mixer); OUTB (0x00, u_IRQDMAControl); @@ -740,11 +746,35 @@ irq_image |= tmp; irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ - tmp = gus_dma_map[gus_dma]; - if (!tmp) - printk ("Warning! GUS DMA not selected\n"); - dma_image |= tmp; + dual_dma_mode = 1; + if (!have_gus_max || gusmax_dma == gus_dma || gusmax_dma == -1) + { + dual_dma_mode = 0; + dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ + + tmp = gus_dma_map[gus_dma]; + if (!tmp) + printk ("Warning! GUS DMA not selected\n"); + + dma_image |= tmp; + } + else + /* Setup dual DMA channel mode for GUS MAX */ + { + dma_image = gus_dma_map[gus_dma]; + if (!dma_image) + printk ("Warning! GUS DMA not selected\n"); + + tmp = gus_dma_map[gusmax_dma] << 3; + if (!tmp) + { + printk ("Warning! Invalid GUS MAX DMA\n"); + tmp = 0x40; /* Combine DMA channels */ + dual_dma_mode = 0; + } + + dma_image |= tmp; + } /* * For some reason the IRQ and DMA addresses must be written twice @@ -781,7 +811,7 @@ gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ - gusintr (0,NULL); /* Serve pending interrupts */ + gusintr (INT_HANDLER_CALL (0)); /* Serve pending interrupts */ RESTORE_INTR (flags); } @@ -888,7 +918,7 @@ if (sample_no < 0) { printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return RET_ERROR (EINVAL);/* Patch not defined */ + return RET_ERROR (EINVAL); /* Patch not defined */ } if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ @@ -909,7 +939,7 @@ unsigned long flags; DISABLE_INTR (flags); - voice_alloc->map[voice] = 0xffff; + /* voice_alloc->map[voice] = 0xffff; */ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { voices[voice].kill_pending = 1; @@ -921,17 +951,17 @@ gus_voice_fade (voice); } + RESTORE_INTR (flags); return 0; } static void guswave_aftertouch (int dev, int voice, int pressure) { +#if 0 short lo_limit, hi_limit; unsigned long flags; - return; /* Procedure currently disabled */ - if (voice < 0 || voice > 31) return; @@ -964,6 +994,7 @@ gus_ramp_rate (3, 8); gus_rampon (0x58); /* Bidirectional, dow, loop */ RESTORE_INTR (flags); +#endif /* 0 */ } static void @@ -1020,8 +1051,8 @@ DISABLE_INTR (flags); /* - * CAUTION! Interrupts disabled. Enable them before returning - */ + * CAUTION! Interrupts disabled. Enable them before returning + */ gus_select_voice (voice); @@ -1230,8 +1261,8 @@ note_freq <= samples[samplep].high_note) sample = samplep; else - samplep = samples[samplep].key; /* - * Follow link + samplep = samples[samplep].key; /* + * Follow link */ } if (sample == -1) @@ -1336,9 +1367,9 @@ } gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, - is16bits);/* Loop start location */ + is16bits); /* Loop start location */ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, - is16bits);/* Loop end location */ + is16bits); /* Loop end location */ } else { @@ -1346,9 +1377,9 @@ voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ voices[voice].loop_irq_parm = 1; gus_write_addr (0x02, sample_ptrs[sample], - is16bits);/* Loop start location */ + is16bits); /* Loop start location */ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, - is16bits);/* Loop end location */ + is16bits); /* Loop end location */ } gus_voice_freq (freq); gus_voice_balance (pan); @@ -1378,7 +1409,6 @@ voices[voice].volume_pending = volume; else { - RESTORE_INTR (flags); ret_val = guswave_start_note2 (dev, voice, note_num, volume); } } @@ -1387,7 +1417,7 @@ gus_select_voice (voice); mode = gus_read8 (0x00); if (mode & 0x20) - gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ + gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ voices[voice].offset_pending = 0; voices[voice].kill_pending = 0; @@ -1396,11 +1426,12 @@ if (voices[voice].sample_pending >= 0) { - RESTORE_INTR (flags); + RESTORE_INTR (flags); /* Run temporarily with interrupts enabled */ guswave_set_instr (voices[voice].dev_pending, voice, voices[voice].sample_pending); voices[voice].sample_pending = -1; DISABLE_INTR (flags); + gus_select_voice (voice); /* Reselect the voice (just to be sure) */ } if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065)) @@ -1416,11 +1447,11 @@ gus_rampoff (); gus_ramp_range (2000, 4065); - gus_ramp_rate (0, 63);/* Fastest possible rate */ + gus_ramp_rate (0, 63); /* Fastest possible rate */ gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ - RESTORE_INTR (flags); } } + RESTORE_INTR (flags); return ret_val; } @@ -1445,9 +1476,12 @@ return RET_ERROR (EBUSY); gus_initialize (); + voice_alloc->timestamp = 0; if ((err = DMAbuf_open_dma (gus_devnum)) < 0) - return err; + gus_no_dma = 1; /* Upload samples using PIO */ + else + gus_no_dma = 0; RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); gus_busy = 1; @@ -1465,7 +1499,8 @@ active_device = 0; gus_reset (); - DMAbuf_close_dma (gus_devnum); + if (!gus_no_dma) + DMAbuf_close_dma (gus_devnum); } static int @@ -1478,7 +1513,7 @@ unsigned long blk_size, blk_end, left, src_offs, target; - sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ if (format != GUS_PATCH) { @@ -1618,85 +1653,85 @@ blk_size = blk_end - target; } -#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA) - /* - * For some reason the DMA is not possible. We have to use PIO. - */ - { - long i; - unsigned char data; + if (gus_no_dma) + { + /* + * For some reason the DMA is not possible. We have to use PIO. + */ + long i; + unsigned char data; - for (i = 0; i < blk_size; i++) - { - GET_BYTE_FROM_USER (data, addr, sizeof_patch + i); - if (patch.mode & WAVE_UNSIGNED) + for (i = 0; i < blk_size; i++) + { + GET_BYTE_FROM_USER (data, addr, sizeof_patch + i); + if (patch.mode & WAVE_UNSIGNED) - if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* Convert to signed */ - gus_poke (target + i, data); - } - } -#else /* GUS_NO_DMA */ - { - unsigned long address, hold_address; - unsigned char dma_command; - unsigned long flags; + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* Convert to signed */ + gus_poke (target + i, data); + } + } + else + { + unsigned long address, hold_address; + unsigned char dma_command; + unsigned long flags; - /* - * OK, move now. First in and then out. - */ + /* + * OK, move now. First in and then out. + */ - COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0], - addr, sizeof_patch + src_offs, - blk_size); - - DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/ - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma (gus_devnum, - audio_devs[gus_devnum]->dmap->raw_buf_phys[0], - blk_size, DMA_MODE_WRITE); + COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0], + addr, sizeof_patch + src_offs, + blk_size); - /* - * Set the DRAM address for the wave data - */ + DISABLE_INTR (flags); +/******** INTERRUPTS DISABLED NOW ********/ + gus_write8 (0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma (gus_devnum, + audio_devs[gus_devnum]->dmap->raw_buf_phys[0], + blk_size, DMA_MODE_WRITE); - address = target; + /* + * Set the DRAM address for the wave data + */ - if (audio_devs[gus_devnum]->dmachan > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } + address = target; - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + if (audio_devs[gus_devnum]->dmachan > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } - /* - * Start the DMA transfer - */ + gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - dma_command = 0x21; /* IRQ enable, DMA start */ - if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ - if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ - if (audio_devs[gus_devnum]->dmachan > 3) - dma_command |= 0x04; /* 16 bit DMA _channel_ */ + /* + * Start the DMA transfer + */ - gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */ + dma_command = 0x21; /* IRQ enable, DMA start */ + if (patch.mode & WAVE_UNSIGNED) + dma_command |= 0x80; /* Invert MSB */ + if (patch.mode & WAVE_16_BITS) + dma_command |= 0x40; /* 16 bit _DATA_ */ + if (audio_devs[gus_devnum]->dmachan > 3) + dma_command |= 0x04; /* 16 bit DMA _channel_ */ - /* - * Sleep here until the DRAM DMA done interrupt is served - */ - active_device = GUS_DEV_WAVE; + gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */ - DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ); - if (TIMED_OUT (dram_sleeper, dram_sleep_flag)) - printk ("GUS: DMA Transfer timed out\n"); - RESTORE_INTR (flags); - } -#endif /* GUS_NO_DMA */ + /* + * Sleep here until the DRAM DMA done interrupt is served + */ + active_device = GUS_DEV_WAVE; + + DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ); + if (TIMED_OUT (dram_sleeper, dram_sleep_flag)) + printk ("GUS: DMA Transfer timed out\n"); + RESTORE_INTR (flags); + } /* * Now the next part @@ -1867,13 +1902,25 @@ static int gus_sampling_set_speed (int speed) { + if (speed <= 0) - return gus_sampling_speed; + speed = gus_sampling_speed; + + if (speed < 4000) + speed = 4000; if (speed > 44100) speed = 44100; gus_sampling_speed = speed; + + if (only_read_access) + { + /* Compute nearest valid recording speed and return it */ + + speed = (9878400 / (gus_sampling_speed + 2)) / 16; + speed = (9878400 / (speed * 16)) - 2; + } return speed; } @@ -1957,8 +2004,6 @@ return IOCTL_OUT (arg, RET_ERROR (EINVAL)); break; - default: - return RET_ERROR (EINVAL); } return RET_ERROR (EINVAL); } @@ -1966,15 +2011,21 @@ static void gus_sampling_reset (int dev) { + if (recording_active) + { + gus_write8 (0x49, 0x00); /* Halt recording */ + set_input_volumes (); + } } static int gus_sampling_open (int dev, int mode) { -#ifdef GUS_NO_DMA - printk ("GUS: DMA mode not enabled. Device not supported\n"); - return RET_ERROR (ENXIO); -#endif + if (mode & OPEN_READ && dual_dma_mode) + { + printk ("GUS: The 8 bit input device is disabled. Use GUS MAX\n"); + return RET_ERROR (ENOTTY); + } if (gus_busy) return RET_ERROR (EBUSY); @@ -1996,6 +2047,7 @@ recording_active = 1; set_input_volumes (); } + only_read_access = !(mode & OPEN_WRITE); return 0; } @@ -2009,7 +2061,10 @@ active_device = 0; if (recording_active) - set_input_volumes (); + { + gus_write8 (0x49, 0x00); /* Halt recording */ + set_input_volumes (); + } recording_active = 0; } @@ -2020,16 +2075,16 @@ unsigned long flags; int voice; - DISABLE_INTR (flags); if (pcm_active && pcm_opened) for (voice = 0; voice < gus_sampling_channels; voice++) { + DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); gus_voice_volume (1530 + (25 * gus_pcm_volume)); gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); + RESTORE_INTR (flags); } - RESTORE_INTR (flags); } static void @@ -2071,7 +2126,7 @@ if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ { mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03;/* Disable rollover bit */ + ramp_mode[chn] = 0x03; /* Disable rollover bit */ } else { @@ -2108,12 +2163,12 @@ gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start */ if (chn != 0) - gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk), + gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, is16bits); /* Loop end location */ } if (chn == 0) - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], + gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1, is16bits); /* Loop end location */ else mode[chn] |= 0x08; /* Enable looping */ @@ -2126,7 +2181,7 @@ if (chn == 0) { mode[chn] &= ~0x08; /* Disable looping */ - mode[chn] |= 0x20;/* Enable IRQ at the end */ + mode[chn] |= 0x20; /* Enable IRQ at the end */ voices[0].loop_irq_mode = LMODE_PCM_STOP; ramp_mode[chn] = 0x03; /* No rollover bit */ } @@ -2231,9 +2286,9 @@ else { /* - * Left channel data. The right channel - * is transferred after DMA interrupt - */ + * Left channel data. The right channel + * is transferred after DMA interrupt + */ active_device = GUS_DEV_PCM_CONTINUE; } @@ -2360,8 +2415,8 @@ } else { - int in_left = useroffs; - int in_right = useroffs + 1; + int in_left = useroffs / 2; + int in_right = useroffs / 2 + 1; short *out_left, *out_right; int i; @@ -2401,6 +2456,23 @@ }; static void +guswave_setup_voice (int dev, int voice, int chn) +{ + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; + + guswave_set_instr (dev, voice, info->pgm_num); + + voices[voice].expression_vol = + info->controllers[CTL_EXPRESSION]; /* Just msb */ + voices[voice].main_vol = + (info->controllers[CTL_MAIN_VOLUME] * 100) / 128; + voices[voice].panning = + (info->controllers[CTL_PAN] * 2) - 128; + voices[voice].bender = info->bender_value; +} + +static void guswave_bender (int dev, int voice, int value) { int freq; @@ -2524,7 +2596,7 @@ if (offs < 0 || offs >= samples[sample].len) return RET_ERROR (EINVAL); /* Invalid offset */ - n = samples[sample].len - offs; /* Num of bytes left */ + n = samples[sample].len - offs; /* Num of bytes left */ if (l > n) l = n; @@ -2538,7 +2610,7 @@ */ offs += sample_ptrs[sample]; /* - * Begin offset + offset to DRAM + * Begin offsess + offset to DRAM */ for (n = 0; n < l; n++) @@ -2567,8 +2639,8 @@ * Invalid offset */ - n = samples[sample].len - offs; /* - * Nr of bytes left + n = samples[sample].len - offs; /* + * Nr of bytes left */ if (l > n) @@ -2583,7 +2655,7 @@ */ offs += sample_ptrs[sample]; /* - * Begin offset + offset to DRAM + * Begin offsess + offset to DRAM */ for (n = 0; n < l; n++) @@ -2603,12 +2675,12 @@ static int guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p; + int i, p, best = -1, best_time = 0x7fffffff; p = alloc->ptr; /* - * First look for a completely stopped voice - */ + * First look for a completely stopped voice + */ for (i = 0; i < alloc->max_voice; i++) { @@ -2617,12 +2689,17 @@ alloc->ptr = p; return p; } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } p = (p + 1) % alloc->max_voice; } /* - * Then look for a releasing voice - */ + * Then look for a releasing voice + */ for (i = 0; i < alloc->max_voice; i++) { @@ -2633,7 +2710,9 @@ } p = (p + 1) % alloc->max_voice; } - printk ("GUS: Out of free voices\n"); + + if (best >= 0) + p = best; alloc->ptr = p; return p; @@ -2660,7 +2739,8 @@ guswave_volume_method, guswave_patchmgr, guswave_bender, - guswave_alloc + guswave_alloc, + guswave_setup_voice }; static void @@ -2669,13 +2749,16 @@ unsigned long flags; unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + if (have_gus_max) /* Don't disturb GUS MAX */ + return; + DISABLE_INTR (flags); /* - * Enable channels having vol > 10% - * Note! bit 0x01 means line in DISABLED while 0x04 means - * mic in ENABLED. - */ + * Enable channels having vol > 10% + * Note! bit 0x01 means the line in DISABLED while 0x04 means + * the mic in ENABLED. + */ if (gus_line_vol > 10) mask &= ~0x01; if (gus_mic_vol > 10) @@ -2684,8 +2767,8 @@ if (recording_active) { /* - * Disable channel, if not selected for recording - */ + * Disable channel, if not selected for recording + */ if (!(gus_recmask & SOUND_MASK_LINE)) mask |= 0x01; if (!(gus_recmask & SOUND_MASK_MIC)) @@ -2829,6 +2912,7 @@ static struct mixer_operations gus_mixer_operations = { + "Gravis Ultrasound", gus_default_mixer_ioctl }; @@ -2841,6 +2925,16 @@ */ mixer_devs[num_mixers++] = &gus_mixer_operations; + if (have_gus_max) + { +/* + * Enable all mixer channels on the GF1 side. Otherwise recording will + * not be possible using GUS MAX. + */ + mix_image &= ~0x07; + mix_image |= 0x04; /* All channels enabled */ + OUTB (mix_image, u_Mixer); + } return mem_start; } @@ -2853,11 +2947,33 @@ int gus_type = 0x24; /* 2.4 */ int mixer_type = 0; + if (irq < 0 || irq > 15) + { + printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); + return mem_start; + } + + if (dma < 0 || dma > 7) + { + printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); + return mem_start; + } + + gus_irq = irq; + gus_dma = dma; +#ifdef GUSMAX_DMA + if (gusmax_dma == -1) /* Not already set */ + gusmax_dma = GUSMAX_DMA; +#else + if (gusmax_dma == -1) + gusmax_dma = dma; +#endif + /* - * Try to identify the GUS model. - * - * Versions < 3.6 don't have the digital ASIC. Try to probe it first. - */ + * Try to identify the GUS model. + * + * Versions < 3.6 don't have the digital ASIC. Try to probe it first. + */ DISABLE_INTR (flags); OUTB (0x20, gus_base + 0x0f); @@ -2867,9 +2983,9 @@ if (val != 0xff && (val & 0x06)) /* Should be 0x02?? */ { /* - * It has the digital ASIC so the card is at least v3.4. - * Next try to detect the true model. - */ + * It has the digital ASIC so the card is at least v3.4. + * Next try to detect the true model. + */ val = INB (u_MixSelect); @@ -2878,9 +2994,7 @@ * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer. * 10 and above is GUS MAX which has the CS4231 codec/mixer. * - * Sorry. No GUS max support yet but it should be available - * soon after the SDK for GUS MAX is available. - */ + */ if (val == 255 || val < 5) { @@ -2902,8 +3016,11 @@ { unsigned char max_config = 0x40; /* Codec enable */ - if (dma > 3) - max_config |= 0x30; /* 16 bit playback and capture DMAs */ + if (gus_dma > 3) + max_config |= 0x10; /* 16 bit capture DMA */ + + if (gusmax_dma > 3) + max_config |= 0x20; /* 16 bit playback DMA */ max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ @@ -2917,45 +3034,28 @@ have_gus_max = 1; ad1848_init ("GUS MAX", gus_base + 0x10c, -irq, - dma, - dma); + gusmax_dma, /* Playback DMA */ + gus_dma); /* Capture DMA */ } else printk ("[Where's the CS4231?]"); +#else + printk ("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n"); #endif } } else { /* - * ASIC not detected so the card must be 2.2 or 2.4. - * There could still be the 16-bit/mixer daughter card. - * It has the same codec/mixer than MAX. - * At this time there is no support for it but it will appear soon. - */ + * ASIC not detected so the card must be 2.2 or 2.4. + * There could still be the 16-bit/mixer daughter card. + */ } printk (" ", model_num, (int) gus_mem_size / 1024); -#ifndef SCO sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); -#endif - - if (irq < 0 || irq > 15) - { - printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); - return mem_start; - } - - if (dma < 0 || dma > 7) - { - printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); - return mem_start; - } - - gus_irq = irq; - gus_dma = dma; if (num_synths >= MAX_SYNTH_DEV) printk ("GUS Error: Too many synthesizers\n"); @@ -2983,8 +3083,8 @@ printk ("GUS: Too many PCM devices available\n"); /* - * Mixer dependent initialization. - */ + * Mixer dependent initialization. + */ switch (mixer_type) { @@ -2998,8 +3098,6 @@ default: return gus_default_mixer_init (mem_start); } - - return mem_start; } static void @@ -3018,6 +3116,9 @@ */ gus_write8 (0x00, tmp); + if (tmp & 0x03) /* Voice stopped */ + voice_alloc->map[voice] = 0; + mode = voices[voice].loop_irq_mode; voices[voice].loop_irq_mode = 0; parm = voices[voice].loop_irq_parm; @@ -3029,9 +3130,9 @@ * Final loop finished, shoot volume down */ - if ((int) (gus_read16 (0x09) >> 4) < 100) /* - * Get current volume - */ + if ((int) (gus_read16 (0x09) >> 4) < 100) /* + * Get current volume + */ { gus_voice_off (); gus_rampoff (); @@ -3056,21 +3157,25 @@ pcm_qlen--; pcm_head = (pcm_head + 1) % pcm_nblk; - if (pcm_qlen) + if (pcm_qlen && pcm_active) { play_next_pcm_block (); } else { /* Underrun. Just stop the voice */ + gus_select_voice (0); /* Left channel */ + gus_voice_off (); + gus_rampoff (); + gus_select_voice (1); /* Right channel */ gus_voice_off (); gus_rampoff (); pcm_active = 0; } -/* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. - */ + /* + * If the queue was full before this interrupt, the DMA transfer was + * suspended. Let it continue now. + */ if (dma_active) { if (pcm_qlen == 0) @@ -3173,9 +3278,9 @@ * Wave IRQ pending */ if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ + * Not done + * yet + */ { wave_ignore |= voice_bit; do_loop_irq (voice); @@ -3185,9 +3290,9 @@ * Volume IRQ pending */ if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ + * Not done + * yet + */ { volume_ignore |= voice_bit; do_volume_irq (voice); diff -u --recursive --new-file v1.3.8/linux/drivers/sound/hex2hex.h linux/drivers/sound/hex2hex.h --- v1.3.8/linux/drivers/sound/hex2hex.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/hex2hex.h Wed Mar 29 13:30:30 1995 @@ -0,0 +1,97 @@ +/* + * This file is a part of configure.c + * + * hex2hex reads an input file in Intel HEX format and produces + * an (unsigned char) array which contains the bytes and writes it to the + * output file using C syntax + */ + +#define MAX_SIZE (256*1024) +#define ABANDON(why) { \ + fprintf(stderr, "%s: " why "\n", source); \ + fclose(inf);fclose(outf);return 0; \ + } + +int hex2hex(char *source, char *target, char *varline) +{ + FILE *inf, *outf; + + int i,l, c; + unsigned char buf[MAX_SIZE]; + + if ((inf=fopen(source, "r"))==NULL) + { + perror(source); + return 0; + } + + if ((outf=fopen(target, "w"))==NULL) + { + perror(target); + fclose(inf); + return 0; + } + + l=0; + + while ((c=getc(inf))!=EOF) + { + if (c == ':') /* Sync with beginning of line */ + { + int n, check; + unsigned char sum; + int addr; + int linetype; + + if (fscanf(inf, "%02x", &n) != 1) + ABANDON("File format error"); + sum = n; + + if (fscanf(inf, "%04x", &addr) != 1) + ABANDON("File format error"); + sum += addr/256; + sum += addr%256; + + if (fscanf(inf, "%02x", &linetype) != 1) + ABANDON("File format error"); + sum += linetype; + + if (linetype != 0) + continue; + + for (i=0;i= MAX_SIZE) + ABANDON("File too large"); + buf[addr++] = c; + if (addr > l) + l = addr; + sum += c; + } + + if (fscanf(inf, "%02x", &check) != 1) + ABANDON("File format error"); + + sum = ~sum + 1; + if (check != sum) + ABANDON("Line checksum error"); + } + } + + fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n"); + fprintf(outf, "%s[] = {\n", varline); + + for (i=0;i +#include "ultrasound.h" #include "gus_hw.h" #define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ @@ -49,10 +49,10 @@ { #if 1 /* - * Experimental volume scaling by Risto Kankkunen. - * This should give smoother volume response than just - * a plain multiplication. - */ + * Experimental volume scaling by Risto Kankkunen. + * This should give smoother volume response than just + * a plain multiplication. + */ int e; if (vol < 0) @@ -224,6 +224,7 @@ static struct mixer_operations ics2101_mixer_operations = { + "ICS2101 Multimedia Mixer", ics2101_mixer_ioctl }; @@ -237,9 +238,9 @@ mixer_devs[num_mixers++] = &ics2101_mixer_operations; /* - * Some GUS v3.7 cards had some channels flipped. Disable - * the flipping feature if the model id is other than 5. - */ + * Some GUS v3.7 cards had some channels flipped. Disable + * the flipping feature if the model id is other than 5. + */ if (INB (u_MixSelect) != 5) { diff -u --recursive --new-file v1.3.8/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v1.3.8/linux/drivers/sound/mad16.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/mad16.c Mon Jul 10 01:45:09 1995 @@ -0,0 +1,403 @@ +/* + * sound/mad16.c + * + * Initialization code for OPTi MAD16 compatible audio chips. Including + * + * OPTi 82C928 MAD16 (replaced by C929) + * OAK OTI-601D Mozart + * OPTi 82C929 MAD16 Pro + * + * These audio interface chips don't prduce sound themselves. They just + * connect some other components (OPL-[234] and a WSS compatible codec) + * to the PC bus and perform I/O, DMA and IRQ address decoding. There is + * also a UART for the MPU-401 mode (not 82C928/Mozart). + * The Mozart chip appears to be compatible with the 82C928 (can anybody + * confirm this?). + * + * NOTE! If you want to set CD-ROM address and/or joystick enable, define + * MAD16_CONF in local.h as combination of the following bits: + * + * 0x01 - joystick disabled + * + * CD-ROM type selection (select just one): + * 0x02 - Sony 31A + * 0x04 - Mitsumi + * 0x06 - Panasonic + * 0x08 - Secondary IDE + * 0x0a - Primary IDE + * + * For example Mitsumi with joystick disabled = 0x04|0x01 = 0x05 + * + * This defaults to CD I/O 0x340, no IRQ and DMA3 + * (DMA5 with Mitsumi or IDE). If you like to change these, define + * MAD16_CDSEL with the following bits: + * + * CD-ROM port: 0x00=340, 0x40=330, 0x80=360 or 0xc0=320 + * OPL4 select: 0x20=OPL4, 0x00=OPL3 + * CD-ROM irq: 0x00=disabled, 0x04=IRQ5, 0x08=IRQ7, 0x0a=IRQ3, 0x10=IRQ9, + * 0x14=IRQ10 and 0x18=IRQ11. + * + * CD-ROM DMA (Sony or Panasonic): 0x00=DMA3, 0x01=DMA2, 0x02=DMA1 or 0x03=disabled + * or + * CD-ROM DMA (Mitsumi or IDE): 0x00=DMA5, 0x01=DMA6, 0x02=DMA7 or 0x03=disabled + * + * Copyright by Hannu Savolainen 1995 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MAD16) + +static int already_initialized = 0; + +#define C928 1 +#define MOZART 2 +#define C929 3 + +/* + * Registers + * + * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations). + * All ports are inactive by default. They can be activated by + * writing 0xE2 or 0xE3 to the password register. The password is valid + * only until the next I/O read or write. + */ + +#define MC1_PORT 0xf8d +#define MC2_PORT 0xf8e +#define MC3_PORT 0xf8f +#define PASSWD_REG 0xf8f +#define MC4_PORT 0xf90 +#define MC5_PORT 0xf91 +#define MC6_PORT 0xf92 +#define MC7_PORT 0xf93 + +static int board_type = C928; + +#ifndef DDB +#define DDB(x) +#endif + +static unsigned char +mad_read (int port) +{ + unsigned long flags; + unsigned char tmp; + + DISABLE_INTR (flags); + + switch (board_type) /* Output password */ + { + case C928: + case MOZART: + OUTB (0xE2, PASSWD_REG); + break; + + case C929: + OUTB (0xE3, PASSWD_REG); + break; + } + + tmp = INB (port); + RESTORE_INTR (flags); + + return tmp; +} + +static void +mad_write (int port, int value) +{ + unsigned long flags; + + DISABLE_INTR (flags); + + switch (board_type) /* Output password */ + { + case C928: + case MOZART: + OUTB (0xE2, PASSWD_REG); + break; + + case C929: + OUTB (0xE3, PASSWD_REG); + break; + } + + OUTB ((unsigned char) (value & 0xff), port); + RESTORE_INTR (flags); +} + +static int +detect_mad16 (void) +{ + unsigned char tmp, tmp2; + +/* + * Check that reading a register doesn't return bus float (0xff) + * when the card is accessed using password. This may fail in case + * the card is in low power mode. Normally at least the power saving mode + * bit should be 0. + */ + if ((tmp = mad_read (MC1_PORT)) == 0xff) + { + DDB (printk ("MC1_PORT returned 0xff\n")); + return 0; + } +/* + * Now check that the gate is closed on first I/O after writing + * the password. (This is how a MAD16 compatible card works). + */ + + if ((tmp2 = INB (MC1_PORT)) == tmp) /* It didn't close */ + { + DDB (printk ("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); + return 0; + } + + mad_write (MC1_PORT, tmp ^ 0x80); /* Togge a bit */ + + if ((tmp2 = mad_read (MC1_PORT)) != (tmp ^ 0x80)) /* Compare the bit */ + { + mad_write (MC1_PORT, tmp); /* Restore */ + DDB (printk ("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); + return 0; + } + + mad_write (MC1_PORT, tmp); /* Restore */ + return 1; /* Bingo */ + +} + +int +probe_mad16 (struct address_info *hw_config) +{ + int i; + static int valid_ports[] = + {0x530, 0xe80, 0xf40, 0x604}; + unsigned char tmp; + + if (already_initialized) + return 0; + +/* + * Check that all ports return 0xff (bus float) when no password + * is written to the password register. + */ + + DDB (printk ("--- Detecting MAD16 / Mozart ---\n")); + +#if 0 + for (i = 0xf8d; i <= 0xf93; i++) + if (INB (i) != 0xff) + { + DDB (printk ("port 0x%03x != 0xff (0x%02x)\n", i, INB (i))); + return 0; + } +#endif + +/* + * Then try to detect with the old password + */ + board_type = C928; + + DDB (printk ("Detect using password = 0xE2\n")); + + if (!detect_mad16 ()) /* No luck. Try different model */ + { + board_type = C929; + + DDB (printk ("Detect using password = 0xE3\n")); + + if (!detect_mad16 ()) + return 0; + + printk ("mad16.c: A 82C929 detected???\n"); + } + else + printk ("mad16.c: A 82C928 or Mozart detected???\n"); + + for (i = 0xf8d; i <= 0xf93; i++) + DDB (printk ("port %03x = %03x\n", i, mad_read (i))); + +/* + * Set the WSS address + */ + + tmp = 0x80; /* Enable WSS, Disable SB */ + + for (i = 0; i < 5; i++) + { + if (i > 3) /* Not a valid port */ + { + printk ("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); + return 0; + } + + if (valid_ports[i] == hw_config->io_base) + { + tmp |= i << 4; /* WSS port select bits */ + break; + } + } + +/* + * Set optional CD-ROM and joystick settings. + */ + +#ifdef MAD16_CONF + tmp |= ((MAD16_CONF) & 0x0f); /* CD-ROM and joystick bits */ +#endif + mad_write (MC1_PORT, tmp); + +#if defined(MAD16_CONF) && defined(MAD16_CDSEL) + tmp = MAD16_CDSEL; +#else + tmp = 0x03; +#endif + +#ifdef MAD16_OPL4 + tmp |= 0x20; /* Enable OPL4 access */ +#endif + + mad_write (MC2_PORT, tmp); + mad_write (MC3_PORT, 0xf0); /* Disable SB */ + + if (board_type == C929) + { + mad_write (MC4_PORT, 0xa2); + mad_write (MC5_PORT, 0x95); /* AD184x mode (0x9f for CS42xx) */ + mad_write (MC6_PORT, 0x03); /* Disable MPU401 */ + } + else + { + mad_write (MC4_PORT, 0x02); + mad_write (MC5_PORT, 0x10); /* AD184x mode (0x12 for CS42xx) */ + } + + for (i = 0xf8d; i <= 0xf93; i++) + DDB (printk ("port %03x after init = %03x\n", i, mad_read (i))); + + return probe_ms_sound (hw_config); +} + +long +attach_mad16 (long mem_start, struct address_info *hw_config) +{ + + already_initialized = 1; + + return attach_ms_sound (mem_start, hw_config); +} + +long +attach_mad16_mpu (long mem_start, struct address_info *hw_config) +{ + +#ifdef EXCLUDE_MIDI + return mem_start; +#else + if (!already_initialized) + return mem_start; + + return attach_mpu401 (mem_start, hw_config); +#endif +} + +int +probe_mad16_mpu (struct address_info *hw_config) +{ +#ifdef EXCLUDE_MIDI + return 0; +#else + static int mpu_attached = 0; + static int valid_ports[] = + {0x330, 0x320, 0x310, 0x300}; + static short valid_irqs[] = + {9, 10, 5, 7}; + unsigned char tmp; + + int i; /* A variable with secret power */ + + if (!already_initialized) /* The MSS port must be initialized first */ + return 0; + + if (mpu_attached) /* Don't let them call this twice */ + return 0; + mpu_attached = 1; + + if (board_type < C929) /* Early chip. No MPU support */ + { + printk ("Mozart and OPTi 82C928 based cards don't support MPU401. Sorry\n"); + return 0; + } + + tmp = 0x80; /* MPU-401 enable */ + +/* + * Set the MPU base bits + */ + + for (i = 0; i < 5; i++) + { + if (i > 3) /* Out of array bounds */ + { + printk ("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base); + return 0; + } + + if (valid_ports[i] == hw_config->io_base) + { + tmp |= i << 5; + break; + } + } + +/* + * Set the MPU IRQ bits + */ + + for (i = 0; i < 5; i++) + { + if (i > 3) /* Out of array bounds */ + { + printk ("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq); + return 0; + } + + if (valid_irqs[i] == hw_config->irq) + { + tmp |= i << 3; + break; + } + + tmp |= 0x03; /* ???????? */ + mad_write (MC6_PORT, tmp); /* Write MPU401 config */ + } + + return probe_mpu401 (hw_config); +#endif +} + +/* That's all folks */ +#endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midi_ctrl.h linux/drivers/sound/midi_ctrl.h --- v1.3.8/linux/drivers/sound/midi_ctrl.h Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/midi_ctrl.h Fri Mar 3 12:03:07 1995 @@ -1,9 +1,9 @@ static unsigned char ctrl_def_values[128] = { - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 0 to 7 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 8 to 15 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 16 to 23 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 24 to 31 */ + 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 0 to 7 */ + 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 8 to 15 */ + 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 16 to 23 */ + 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 24 to 31 */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 32 to 39 */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 40 to 47 */ diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c --- v1.3.8/linux/drivers/sound/midi_synth.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/midi_synth.c Mon Jul 10 01:45:09 1995 @@ -27,6 +27,9 @@ * */ +#define USE_SEQ_MACROS +#define USE_SIMPLE_MACROS + #include "sound_config.h" #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI) @@ -40,6 +43,61 @@ static int midi2synth[MAX_MIDI_DEV]; static unsigned char prev_out_status[MAX_MIDI_DEV]; +#define STORE(cmd) \ +{ \ + int len; \ + unsigned char obuf[8]; \ + cmd; \ + seq_input_event(obuf, len); \ +} +#define _seqbuf obuf +#define _seqbufptr 0 +#define _SEQ_ADVBUF(x) len=x + +void +do_midi_msg (int synthno, unsigned char *msg, int mlen) +{ + switch (msg[0] & 0xf0) + { + case 0x90: + if (msg[2] != 0) + { + STORE (SEQ_START_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + } + msg[2] = 64; + + case 0x80: + STORE (SEQ_STOP_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xA0: + STORE (SEQ_KEY_PRESSURE (synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xB0: + STORE (SEQ_CONTROL (synthno, msg[0] & 0x0f, + msg[1], msg[2])); + break; + + case 0xC0: + STORE (SEQ_SET_PATCH (synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xD0: + STORE (SEQ_CHN_PRESSURE (synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xE0: + STORE (SEQ_BENDER (synthno, msg[0] & 0x0f, + (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); + break; + + default: + /* printk ("MPU: Unknown midi channel message %02x\n", msg[0]); */ + } +} + static void midi_outc (int midi_dev, int data) { @@ -69,25 +127,118 @@ static int prefix_cmd (int midi_dev, unsigned char status) { - if (midi_devs[midi_dev]->prefix_cmd == NULL) + if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) return 1; return midi_devs[midi_dev]->prefix_cmd (midi_dev, status); } static void -midi_synth_input (int dev, unsigned char data) +midi_synth_input (int orig_dev, unsigned char data) { - int orig_dev; + int dev; + struct midi_input_info *inc; + + static unsigned char len_tab[] = /* # of data bytes following a status + */ + { + 2, /* 8x */ + 2, /* 9x */ + 2, /* Ax */ + 2, /* Bx */ + 1, /* Cx */ + 1, /* Dx */ + 2, /* Ex */ + 0 /* Fx */ + }; - if (dev < 0 || dev > num_synths) + if (orig_dev < 0 || orig_dev > num_midis) return; if (data == 0xfe) /* Ignore active sensing */ return; - orig_dev = midi2synth[dev]; + dev = midi2synth[orig_dev]; + inc = &midi_devs[orig_dev]->in_info; + switch (inc->m_state) + { + case MST_INIT: + if (data & 0x80) /* MIDI status byte */ + { + if ((data & 0xf0) == 0xf0) /* Common message */ + { + switch (data) + { + case 0xf0: /* Sysex */ + inc->m_state = MST_SYSEX; + break; /* Sysex */ + + case 0xf1: /* MTC quarter frame */ + case 0xf3: /* Song select */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 1; + inc->m_buf[0] = data; + break; + + case 0xf2: /* Song position pointer */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 2; + inc->m_buf[0] = data; + break; + + default: + inc->m_buf[0] = data; + inc->m_ptr = 1; + do_midi_msg (dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + inc->m_left = 0; + } + } + else + { + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = len_tab[(data >> 4) - 8]; + inc->m_buf[0] = inc->m_prev_status = data; + } + } + else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ + { /* Data byte (use running status) */ + inc->m_state = MST_DATA; + inc->m_ptr = 2; + inc->m_left = len_tab[(data >> 4) - 8] - 1; + inc->m_buf[0] = inc->m_prev_status; + inc->m_buf[1] = data; + } + break; /* MST_INIT */ + + case MST_DATA: + inc->m_buf[inc->m_ptr++] = data; + if (--inc->m_left <= 0) + { + inc->m_state = MST_INIT; + do_midi_msg (dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + } + break; /* MST_DATA */ + + case MST_SYSEX: + if (data == 0xf7) /* Sysex end */ + { + inc->m_state = MST_INIT; + inc->m_left = 0; + inc->m_ptr = 0; + } + break; /* MST_SYSEX */ + + default: + printk ("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, + (int) data); + inc->m_state = MST_INIT; + } } static void @@ -155,9 +306,9 @@ if (msg == 0x90) /* * Running status = Note on */ - midi_outc (orig_dev, 0);/* - * Note on with velocity 0 == note - * off + midi_outc (orig_dev, 0); /* + * Note on with velocity 0 == note + * off */ else midi_outc (orig_dev, velocity); @@ -261,6 +412,8 @@ { int orig_dev = synth_devs[dev]->midi_dev; int err; + unsigned long flags; + struct midi_input_info *inc; if (orig_dev < 0 || orig_dev > num_midis) return RET_ERROR (ENXIO); @@ -272,6 +425,16 @@ midi_synth_input, midi_synth_output)) < 0) return err; + inc = &midi_devs[orig_dev]->in_info; + + DISABLE_INTR (flags); + inc->m_busy = 0; + inc->m_state = MST_INIT; + inc->m_ptr = 0; + inc->m_left = 0; + inc->m_prev_status = 0x00; + RESTORE_INTR (flags); + return 1; } @@ -281,8 +444,8 @@ int orig_dev = synth_devs[dev]->midi_dev; /* - * Shut up the synths by sending just single active sensing message. - */ + * Shut up the synths by sending just single active sensing message. + */ midi_devs[orig_dev]->putc (orig_dev, 0xfe); midi_devs[orig_dev]->close (orig_dev); @@ -303,6 +466,7 @@ int i; unsigned long left, src_offs, eox_seen = 0; int first_byte = 1; + int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; if (!prefix_cmd (orig_dev, 0xf0)) return 0; @@ -313,20 +477,20 @@ return RET_ERROR (EINVAL); } - if (count < sizeof (struct sysex_info)) + if (count < hdr_size) { printk ("MIDI Error: Patch header too short\n"); return RET_ERROR (EINVAL); } - count -= sizeof (struct sysex_info); + count -= hdr_size; /* * Copy the header from user space but ignore the first bytes which have * been transferred already. */ - COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs); + COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, hdr_size - offs); if (count < sysex.len) { @@ -344,21 +508,20 @@ { unsigned char data; - GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i); + GET_BYTE_FROM_USER (data, addr, hdr_size + i); - if (first_byte && data != 0xf0) - midi_outc (orig_dev, 0xf0); /* Sysex start */ + eox_seen = (i > 0 && data & 0x80); /* End of sysex */ - eox_seen = (data == 0xf7);/* - * Last byte was end of sysex - */ + if (eox_seen && data != 0xf7) + data = 0xf7; if (i == 0) { - if (data != 0xf0) /* - * Sysex start - */ - return RET_ERROR (EINVAL); + if (data != 0xf0) + { + printk ("Error: Sysex start missing\n"); + return RET_ERROR (EINVAL); + } } while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) && @@ -406,6 +569,7 @@ } else if (!prefix_cmd (orig_dev, pressure)) return; + midi_outc (orig_dev, pressure); } @@ -458,7 +622,8 @@ prev_chn = prev_out_status[orig_dev] & 0x0f; if (msg != 0xd0 || prev_chn != channel) /* - * * Test for running status */ + * Test for running status + */ { if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f))) return; @@ -469,6 +634,11 @@ midi_outc (orig_dev, value & 0x7f); midi_outc (orig_dev, (value >> 7) & 0x7f); +} + +void +midi_synth_setup_voice (int dev, int voice, int channel) +{ } #endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midi_synth.h linux/drivers/sound/midi_synth.h --- v1.3.8/linux/drivers/sound/midi_synth.h Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/midi_synth.h Fri Mar 3 12:03:07 1995 @@ -14,6 +14,8 @@ void midi_synth_controller (int dev, int channel, int ctrl_num, int value); int midi_synth_patchmgr (int dev, struct patmgr_info *rec); void midi_synth_bender (int dev, int chn, int value); +void midi_synth_setup_voice (int dev, int voice, int chn); +void do_midi_msg (int synthno, unsigned char *msg, int mlen); #ifndef _MIDI_SYNTH_C_ @@ -40,6 +42,8 @@ midi_synth_panning, NULL, midi_synth_patchmgr, - midi_synth_bender + midi_synth_bender, + NULL, /* alloc_voice */ + midi_synth_setup_voice }; #endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v1.3.8/linux/drivers/sound/midibuf.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/midibuf.c Mon Jul 10 01:45:10 1995 @@ -184,8 +184,8 @@ } /* - * Interrupts disabled. Be careful - */ + * Interrupts disabled. Be careful + */ DISABLE_INTR (flags); if ((err = midi_devs[dev]->open (dev, mode, @@ -245,14 +245,14 @@ DISABLE_INTR (flags); /* - * Wait until the queue is empty - */ + * Wait until the queue is empty + */ if (mode != OPEN_READ) { - midi_devs[dev]->putc (dev, 0xfe); /* - * Active sensing to shut the - * devices + midi_devs[dev]->putc (dev, 0xfe); /* + * Active sensing to shut the + * devices */ while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) && @@ -379,22 +379,32 @@ dev = dev >> 4; - switch (cmd) + if (((cmd >> 8) & 0xff) == 'C') { - - case SNDCTL_MIDI_PRETIME: - val = IOCTL_IN (arg); - if (val < 0) - val = 0; - - val = (HZ * val) / 10; - parms[dev].prech_timeout = val; - return IOCTL_OUT (arg, val); - break; - - default: - return midi_devs[dev]->ioctl (dev, cmd, arg); - } + if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ + return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0); + else + printk ("/dev/midi%d: No coprocessor for this device\n", dev); + + return RET_ERROR (EREMOTEIO); + } + else + switch (cmd) + { + + case SNDCTL_MIDI_PRETIME: + val = IOCTL_IN (arg); + if (val < 0) + val = 0; + + val = (HZ * val) / 10; + parms[dev].prech_timeout = val; + return IOCTL_OUT (arg, val); + break; + + default: + return midi_devs[dev]->ioctl (dev, cmd, arg); + } } #ifdef ALLOW_SELECT diff -u --recursive --new-file v1.3.8/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v1.3.8/linux/drivers/sound/mpu401.c Mon Mar 6 11:22:09 1995 +++ linux/drivers/sound/mpu401.c Mon Jul 10 01:45:12 1995 @@ -25,6 +25,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * Modified: + * Riccardo Facchetti 24 Mar 1995 + * - Added the Audio Excel DSP 16 initialization routine. */ #define USE_SEQ_MACROS @@ -34,7 +37,8 @@ #ifdef CONFIGURE_SOUNDCARD -#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) +#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#include "coproc.h" static int init_sequence[20]; /* NOTE! pos 0 = len, start pos 1. */ static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; @@ -75,7 +79,7 @@ int m_left; unsigned char last_status; void (*inputintr) (int dev, unsigned char data); - unsigned short controls[32]; + int shared_irq; }; #define DATAPORT(base) (base) @@ -101,7 +105,9 @@ {0}}; static int n_mpu_devs = 0; -static int irq2dev[16]; +static int irq2dev[16] = +{-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}; static int reset_mpu401 (struct mpu_config *devc); static void set_uart_mode (int dev, struct mpu_config *devc, int arg); @@ -128,7 +134,7 @@ #define ST_SONGSEL 103 /* Song select */ #define ST_SONGPOS 104 /* Song position pointer */ -static unsigned char len_tab[] =/* # of data bytes following a status +static unsigned char len_tab[] = /* # of data bytes following a status */ { 2, /* 8x */ @@ -142,7 +148,6 @@ }; #define STORE(cmd) \ -if (devc->opened & OPEN_READ) \ { \ int len; \ unsigned char obuf[8]; \ @@ -153,73 +158,10 @@ #define _seqbufptr 0 #define _SEQ_ADVBUF(x) len=x -static void -do_midi_msg (struct mpu_config *devc, unsigned char *msg, int mlen) -{ - switch (msg[0] & 0xf0) - { - case 0x90: - if (msg[2] != 0) - { - STORE (SEQ_START_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - } - msg[2] = 64; - - case 0x80: - STORE (SEQ_STOP_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xA0: - STORE (SEQ_KEY_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xB0: - /* - * Fix the controller value (combine MSB and LSB) - */ - if (msg[1] < 64) - { - int ctrl = msg[1]; - - if (ctrl < 32) - { - devc->controls[ctrl] = (msg[2] & 0x7f) << 7; - } - else - { - ctrl -= 32; - devc->controls[ctrl] = - (devc->controls[ctrl] & ~0x7f) | (msg[2] & 0x7f); - } - STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, - msg[1], devc->controls[ctrl])); - } - else - STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xC0: - STORE (SEQ_SET_PATCH (devc->synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xD0: - STORE (SEQ_CHN_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xE0: - STORE (SEQ_BENDER (devc->synthno, msg[0] & 0x0f, - (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); - break; - - default: - printk ("MPU: Unknown midi channel message %02x\n", msg[0]); - } -} - static int mpu_input_scanner (struct mpu_config *devc, unsigned char midic) { + switch (devc->m_state) { case ST_INIT: @@ -277,6 +219,7 @@ int msg = (midic & 0xf0) >> 4; devc->m_state = ST_DATABYTE; + if (msg < 8) /* Data byte */ { /* printk("midi msg (running status) "); */ @@ -291,7 +234,7 @@ if (devc->m_left <= 0) { devc->m_state = ST_INIT; - do_midi_msg (devc, devc->m_buf, devc->m_ptr); + do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); devc->m_ptr = 0; } } @@ -320,7 +263,7 @@ else { devc->last_status = midic; - /* printk("midi msg "); */ + /* printk ("midi msg "); */ msg -= 8; devc->m_left = len_tab[msg]; @@ -330,7 +273,7 @@ if (devc->m_left <= 0) { devc->m_state = ST_INIT; - do_midi_msg (devc, devc->m_buf, devc->m_ptr); + do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); devc->m_ptr = 0; } } @@ -363,8 +306,8 @@ devc->m_state = ST_INIT; /* - * Real time messages - */ + * Real time messages + */ case 0xf8: /* midi clock */ devc->m_state = ST_INIT; @@ -436,7 +379,7 @@ if ((--devc->m_left) <= 0) { devc->m_state = ST_INIT; - do_midi_msg (devc, devc->m_buf, devc->m_ptr); + do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); devc->m_ptr = 0; } break; @@ -454,16 +397,19 @@ { unsigned long flags; int busy; + int n; DISABLE_INTR (flags); busy = devc->m_busy; devc->m_busy = 1; RESTORE_INTR (flags); - if (busy) + if (busy) /* Already inside the scanner */ return; - while (input_avail (devc->base)) + n = 50; + + while (input_avail (devc->base) && n-- > 0) { unsigned char c = read_data (devc->base); @@ -479,7 +425,7 @@ } void -mpuintr (int irq, struct pt_regs * regs) +mpuintr (INT_HANDLER_PARMS (irq, dummy)) { struct mpu_config *devc; int dev; @@ -497,15 +443,20 @@ dev = irq2dev[irq]; if (dev == -1) { - printk ("MPU-401: Interrupt #%d?\n", irq); + /* printk ("MPU-401: Interrupt #%d?\n", irq); */ return; } devc = &dev_conf[dev]; - if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) - if (input_avail (devc->base)) + if (input_avail (devc->base)) + if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) mpu401_input_loop (devc); + else + { + /* Dummy read (just to acknowledge the interrupt) */ + read_data (devc->base); + } } @@ -529,9 +480,40 @@ return RET_ERROR (EBUSY); } + /* + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloadin it's microcode. + */ + + if (!devc->initialized) + { + if (mpu401_status (devc->base) == 0xff) /* Bus float */ + { + printk ("MPU-401: Device not initialized properly\n"); + return RET_ERROR (EIO); + } + reset_mpu401 (devc); + } + irq2dev[devc->irq] = dev; - if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0)) - return err; + if (devc->shared_irq == 0) + if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[dev]->info.name) < 0)) + { + return err; + } + + if (midi_devs[dev]->coproc) + if ((err = midi_devs[dev]->coproc-> + open (midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) + { + if (devc->shared_irq == 0) + snd_release_irq (devc->irq); + printk ("MPU-401: Can't access coprocessor device\n"); + + return err; + } set_uart_mode (dev, devc, 1); devc->mode = MODE_MIDI; @@ -558,9 +540,12 @@ */ devc->mode = 0; - snd_release_irq (devc->irq); + if (devc->shared_irq == 0) + snd_release_irq (devc->irq); devc->inputintr = NULL; - irq2dev[devc->irq] = -1; + + if (midi_devs[dev]->coproc) + midi_devs[dev]->coproc->close (midi_devs[dev]->coproc->devc, COPR_MIDI); devc->opened = 0; } @@ -580,16 +565,16 @@ */ if (input_avail (devc->base)) - mpu401_input_loop (devc); + { + mpu401_input_loop (devc); + } #endif /* * Sometimes it takes about 13000 loops before the output becomes ready * (After reset). Normally it takes just about 10 loops. */ - for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--); /* - * Wait - */ + for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--); DISABLE_INTR (flags); if (!output_ready (devc->base)) @@ -633,34 +618,42 @@ * (After reset). Normally it takes just about 10 loops. */ - for (timeout = 500000; timeout > 0 && !output_ready (devc->base); timeout--); + timeout = 30000; +retry: + if (timeout-- <= 0) + { + printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); + return RET_ERROR (EIO); + } DISABLE_INTR (flags); + if (!output_ready (devc->base)) { - printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); RESTORE_INTR (flags); - return RET_ERROR (EIO); + goto retry; } write_command (devc->base, cmd->cmd); ok = 0; - for (timeout = 500000; timeout > 0 && !ok; timeout--) + for (timeout = 50000; timeout > 0 && !ok; timeout--) if (input_avail (devc->base)) - if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK) - ok = 1; + { + if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK) + ok = 1; + } if (!ok) { RESTORE_INTR (flags); - printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); + /* printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ return RET_ERROR (EIO); } if (cmd->nr_args) for (i = 0; i < cmd->nr_args; i++) { - for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--); + for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--); if (!mpu401_out (dev, cmd->data[i])) { @@ -687,7 +680,7 @@ if (!ok) { RESTORE_INTR (flags); - printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); + /* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ return RET_ERROR (EIO); } } @@ -857,31 +850,64 @@ midi_dev = synth_devs[dev]->midi_dev; if (midi_dev < 0 || midi_dev > num_midis) - return RET_ERROR (ENXIO); + { + return RET_ERROR (ENXIO); + } devc = &dev_conf[midi_dev]; + /* + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloadin it's microcode. + */ + + if (!devc->initialized) + { + if (mpu401_status (devc->base) == 0xff) /* Bus float */ + { + printk ("MPU-401: Device not initialized properly\n"); + return RET_ERROR (EIO); + } + reset_mpu401 (devc); + } + if (devc->opened) { printk ("MPU-401: Midi busy\n"); return RET_ERROR (EBUSY); } - devc->opened = mode; devc->mode = MODE_SYNTH; devc->synthno = dev; devc->inputintr = NULL; irq2dev[devc->irq] = midi_dev; - if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0)) - return err; + if (devc->shared_irq == 0) + if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[midi_dev]->info.name) < 0)) + { + return err; + } + + if (midi_devs[midi_dev]->coproc) + if ((err = midi_devs[midi_dev]->coproc-> + open (midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) + { + if (devc->shared_irq == 0) + snd_release_irq (devc->irq); + printk ("MPU-401: Can't access coprocessor device\n"); + return err; + } + + devc->opened = mode; reset_mpu401 (devc); if (mode & OPEN_READ) { - exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ exec_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */ + exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ } return 0; @@ -899,11 +925,14 @@ exec_cmd (midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ exec_cmd (midi_dev, 0x8a, 0); /* Disable data in stopped mode */ + if (devc->shared_irq == 0) + snd_release_irq (devc->irq); + devc->inputintr = NULL; + + if (midi_devs[midi_dev]->coproc) + midi_devs[midi_dev]->coproc->close (midi_devs[midi_dev]->coproc->devc, COPR_MIDI); devc->opened = 0; devc->mode = 0; - snd_release_irq (devc->irq); - devc->inputintr = NULL; - irq2dev[devc->irq] = -1; } #define MIDI_SYNTH_NAME "MPU-401 UART Midi" @@ -930,7 +959,9 @@ midi_synth_panning, NULL, midi_synth_patchmgr, - midi_synth_bender + midi_synth_bender, + NULL, /* alloc */ + midi_synth_setup_voice }; static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV]; @@ -939,6 +970,7 @@ { {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, NULL, + {0}, mpu401_open, mpu401_close, mpu401_ioctl, @@ -962,25 +994,28 @@ if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0) return; + + if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ + return; + devc->version = tmp; if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0) - return; + { + devc->version = 0; + return; + } devc->revision = tmp; } long attach_mpu401 (long mem_start, struct address_info *hw_config) { - int i; unsigned long flags; char revision_char; struct mpu_config *devc; - for (i = 0; i < 16; i++) - irq2dev[i] = -1; - if (num_midis >= MAX_MIDI_DEV) { printk ("MPU-401: Too many midi devices detected\n"); @@ -1000,18 +1035,20 @@ devc->timer_flag = 0; devc->m_busy = 0; devc->m_state = ST_INIT; + devc->shared_irq = hw_config->always_detect; - for (i = 0; i < 32; i++) - devc->controls[i] = 0x2000; - - if (!reset_mpu401 (devc)) - return mem_start; + if (!hw_config->always_detect) + { + /* Verify the hardware again */ + if (!reset_mpu401 (devc)) + return mem_start; - DISABLE_INTR (flags); - mpu401_chk_version (devc); - if (devc->version == 0) - mpu401_chk_version (devc); - RESTORE_INTR (flags); + DISABLE_INTR (flags); + mpu401_chk_version (devc); + if (devc->version == 0) + mpu401_chk_version (devc); + RESTORE_INTR (flags); + } if (devc->version == 0) { @@ -1051,13 +1088,11 @@ printk (" ", ports, revision_char); -#ifndef SCO sprintf (mpu_synth_info[num_midis].name, "MQX-%d%c MIDI Interface #%d", ports, revision_char, n_mpu_devs); -#endif } else { @@ -1072,20 +1107,16 @@ (devc->version & 0xf0) >> 4, devc->version & 0x0f, revision_char); -#ifndef SCO sprintf (mpu_synth_info[num_midis].name, "MPU-401 %d.%d%c Midi interface #%d", (devc->version & 0xf0) >> 4, devc->version & 0x0f, revision_char, n_mpu_devs); -#endif } -#ifndef SCO strcpy (mpu401_midi_operations[num_midis].info.name, mpu_synth_info[num_midis].name); -#endif mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis; mpu401_synth_operations[devc->devno].info = @@ -1094,6 +1125,7 @@ if (devc->capabilities & MPU_CAP_INTLG) /* Has timer */ mpu_timer_init (num_midis); + irq2dev[devc->irq] = num_midis; midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; return mem_start; } @@ -1154,10 +1186,14 @@ { if (!arg && devc->version == 0) - return; + { + return; + } if ((devc->uart_mode == 0) == (arg == 0)) - return; /* Already set */ + { + return; /* Already set */ + } reset_mpu401 (devc); /* This exits the uart mode */ @@ -1184,6 +1220,19 @@ tmp_devc.irq = hw_config->irq; tmp_devc.initialized = 0; +#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MPU401) + /* + * Initialize Audio Excel DSP 16 to MPU-401, before any operation. + */ + InitAEDSP16_MPU401 (hw_config); +#endif + + if (hw_config->always_detect) + return 1; + + if (INB (hw_config->io_base + 1) == 0xff) + return 0; /* Just bus float? */ + ok = reset_mpu401 (&tmp_devc); return ok; @@ -1207,11 +1256,11 @@ clocks2ticks (unsigned long clocks) { /* - * The MPU-401 supports just a limited set of possible timebase values. - * Since the applications require more choices, the driver has to - * program the HW to do its best and to convert between the HW and - * actual timebases. - */ + * The MPU-401 supports just a limited set of possible timebase values. + * Since the applications require more choices, the driver has to + * program the HW to do it's best and to convert between the HW and + * actual timebases. + */ return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; } @@ -1269,8 +1318,8 @@ { if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) { - exec_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */ - exec_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ + exec_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */ + exec_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ } else if (timer_mode & TMR_MODE_FSK) exec_cmd (midi_dev, 0x81, 0); /* Use FSK sync */ @@ -1481,8 +1530,6 @@ break; case SNDCTL_TMR_START: - if (tmr_running) - return 0; start_timer (midi_dev); return 0; break; diff -u --recursive --new-file v1.3.8/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v1.3.8/linux/drivers/sound/opl3.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/opl3.c Mon Jul 10 01:45:13 1995 @@ -46,6 +46,7 @@ * * OP4 * * begin here */ static int opl3_enabled = 0; +static int opl4_enabled = 0; static int left_address = 0x388, right_address = 0x388, both_address = 0; static int nr_voices = 9; @@ -189,7 +190,7 @@ * Note2! The chip is initialized if detected. */ - unsigned char stat1, stat2; + unsigned char stat1, stat2, signature; int i; if (already_initialized) @@ -202,22 +203,13 @@ if (opl3_enabled) ioaddr = left_address; - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* - * Reset - * timers - * 1 - * and - * 2 - */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* - * Reset the - * IRQ of FM - * * chicp - */ + /* Reset timers 1 and 2 */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - stat1 = INB (ioaddr); /* - * Read status register - */ + /* Reset the IRQ of the FM chip */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); + + signature = stat1 = INB (ioaddr); /* Status register */ if ((stat1 & 0xE0) != 0x00) { @@ -226,23 +218,19 @@ */ } - opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* - * Set timer 1 to - * 0xff - */ + opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER2_MASK | TIMER1_START); /* * Unmask and start timer 1 */ /* - * Now we have to delay at least 80 msec + * Now we have to delay at least 80 usec */ for (i = 0; i < 50; i++) - tenmicrosec (); /* - * To be sure - */ + tenmicrosec (); stat2 = INB (ioaddr); /* * Read status after timers have expired @@ -252,18 +240,10 @@ * Stop the timers */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* - * Reset - * timers - * 1 - * and - * 2 - */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* - * Reset the - * IRQ of FM - * * chicp - */ + /* Reset timers 1 and 2 */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); + /* Reset the IRQ of the FM chip */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); if ((stat2 & 0xE0) != 0xc0) { @@ -273,9 +253,41 @@ } /* - * There is a FM chicp in this address. Now set some default values. + * There is a FM chicp in this address. Detect the type (OPL2 to OPL4) */ + if (signature == 0x06) /* OPL2 */ + { + opl3_enabled = 0; + } + else if (signature == 0x00) /* OPL3 or OPL4 */ + { + unsigned char tmp; + + if (!opl3_enabled) /* Was not already enabled */ + { + left_address = ioaddr; + right_address = ioaddr + 2; + opl3_enabled = 1; + } + + /* + * Detect availability of OPL4 (_experimental_). Works propably + * only after a cold boot. In addition the OPL4 port + * of the chip may not be connected to the PC bus at all. + */ + + opl3_command (right_address, OPL3_MODE_REGISTER, 0x00); + opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); + + if ((tmp = INB (ioaddr)) == 0x02) /* Have a OPL4 */ + { + opl4_enabled = 1; + } + opl3_command (right_address, OPL3_MODE_REGISTER, 0); + + } + for (i = 0; i < 9; i++) opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* * Note off @@ -374,14 +386,14 @@ -11, -11, -10, -10, -10, -9, -9, -8, /* * 24 - 31 */ - -8, -8, -7, -7, -7, -6, -6, -6,/* - * 32 - 39 + -8, -8, -7, -7, -7, -6, -6, -6, /* + * 32 - 39 */ - -5, -5, -5, -5, -4, -4, -4, -4,/* - * 40 - 47 + -5, -5, -5, -5, -4, -4, -4, -4, /* + * 40 - 47 */ - -3, -3, -3, -3, -2, -2, -2, -2,/* - * 48 - 55 + -3, -3, -3, -3, -2, -2, -2, -2, /* + * 48 - 55 */ -2, -1, -1, -1, -1, 0, 0, 0, /* * 56 - 63 @@ -473,13 +485,13 @@ calc_vol (&vol2, volume); } - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* - * Modulator - * volume + opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* + * Modulator + * volume */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* - * Carrier - * volume + opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* + * Carrier + * volume */ } else @@ -526,7 +538,7 @@ default: /* * Why ?? - */ ; + */ ; } opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); @@ -858,12 +870,23 @@ static int opl3_open (int dev, int mode) { + int i; + if (!opl3_ok) return RET_ERROR (ENXIO); if (opl3_busy) return RET_ERROR (EBUSY); opl3_busy = 1; + voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9; + voice_alloc->timestamp = 0; + + for (i = 0; i < 18; i++) + { + voice_alloc->map[i] = 0; + voice_alloc->alloc_times[i] = 0; + } + connection_mask = 0x00; /* * Just 2 OP voices */ @@ -877,6 +900,7 @@ { opl3_busy = 0; voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9; + fm_info.nr_drums = 0; fm_info.perc_mode = 0; @@ -1076,7 +1100,7 @@ static int opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, avail_voices; + int i, p, best, first, avail_voices, best_time = 0x7fffffff; struct sbi_instrument *instr; int is4op; int instr_no; @@ -1097,21 +1121,22 @@ if (is4op) { - p = 0; + first = p = 0; avail_voices = 6; } else { if (nr_voices == 12) /* 4 OP mode. Use the '2 OP only' voices first */ - p = 6; + first = p = 6; else - p = 0; + first = p = 0; avail_voices = nr_voices; } /* - * Now try to find a free voice - */ + * Now try to find a free voice + */ + best = first; for (i = 0; i < avail_voices; i++) { @@ -1119,15 +1144,36 @@ { return p; } - p = (p + 1) % nr_voices; + if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */ + { + best_time = alloc->alloc_times[p]; + best = p; + } + p = (p + 1) % avail_voices; } /* - * Insert some kind of priority mechanism here. - */ + * Insert some kind of priority mechanism here. + */ + + if (best < 0) + best = 0; + if (best > nr_voices) + best -= nr_voices; - printk ("OPL3: Out of free voices\n"); - return 0; /* All voices in use. Select the first one. */ + return best; /* All voices in use. Select the first one. */ +} + +static void +opl3_setup_voice (int dev, int voice, int chn) +{ + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; + + opl3_set_instr (dev, voice, + info->pgm_num); + + voices[voice].bender = info->bender_value; } static struct synth_operations opl3_operations = @@ -1151,7 +1197,8 @@ opl3_volume_method, opl3_patchmgr, opl3_bender, - opl3_alloc_voice + opl3_alloc_voice, + opl3_setup_voice }; long @@ -1175,14 +1222,16 @@ opl3_ok = 1; if (opl3_enabled) { - printk (" "); + if (opl4_enabled) + printk (" "); + else + printk (" "); + fm_model = 2; voice_alloc->max_voice = nr_voices = 18; fm_info.nr_drums = 0; fm_info.capabilities |= SYNTH_CAP_OPL3; -#ifndef SCO strcpy (fm_info.name, "Yamaha OPL-3"); -#endif for (i = 0; i < 18; i++) if (physical_voices[i].ioaddr == USE_LEFT) diff -u --recursive --new-file v1.3.8/linux/drivers/sound/opl3.h linux/drivers/sound/opl3.h --- v1.3.8/linux/drivers/sound/opl3.h Fri Aug 19 08:54:09 1994 +++ linux/drivers/sound/opl3.h Sat Mar 11 20:04:49 1995 @@ -35,7 +35,7 @@ * * The percussive mode is implemented in the left side only. * - * With the above exceptions the both sides can be operated independently. + * With the above exeptions the both sides can be operated independently. * * A 4 OP voice can be created by setting the corresponding * bit at offset 4 of the right side. @@ -80,6 +80,7 @@ #define OPL3_MODE_REGISTER 0x05 /* Right side */ #define OPL3_ENABLE 0x01 +#define OPL4_ENABLE 0x02 #define KBD_SPLIT_REGISTER 0x08 /* Left side */ #define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ diff -u --recursive --new-file v1.3.8/linux/drivers/sound/os.h linux/drivers/sound/os.h --- v1.3.8/linux/drivers/sound/os.h Tue Aug 23 09:48:52 1994 +++ linux/drivers/sound/os.h Mon Jul 10 19:22:42 1995 @@ -28,6 +28,12 @@ #define ALLOW_SELECT +#ifdef MODULE +#include +#include +#include +#endif + #include #include #include @@ -45,7 +51,8 @@ #include #include #include -#include + +#include "linux/soundcard.h" typedef char snd_rw_buf; @@ -93,7 +100,7 @@ #define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP) #define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wake_up(&q);} -#define ALLOC_DMA_CHN(chn,deviceID) request_dma(chn,deviceID) +#define ALLOC_DMA_CHN(chn,deviceID) request_dma(chn, deviceID) #define RELEASE_DMA_CHN(chn) free_dma(chn) #define GET_TIME() jiffies @@ -102,7 +109,7 @@ /* DISABLE_INTR is used to disable interrupts. These macros store the current flags to the (unsigned long) variable given - as a parameter. RESTORE_INTR returns the interrupt enable bit to state + as a parameter. RESTORE_INTR returns the interrupt ebable bit to state before DISABLE_INTR or ENABLE_INTR */ #define DISABLE_INTR(flags) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); @@ -152,10 +159,28 @@ add_timer (&name);} #define INB inb +#define INW inw #define OUTB outb +#define OUTW outw /* * SND_SA_INTERRUPT is required. Otherwise the IRQ number is not passed * the handler. */ #define SND_SA_INTERRUPT + +/* + * The macro DECLARE_FILE() adds an entry to struct fileinfo referencing the + * connected filestructure. + * This entry must be initialized in sound_open() in soundcard.c + * + * ISSET_FILE_FLAG() allows checking of flags like O_NONBLOCK on files + * + */ + +#define DECLARE_FILE() struct file *filp +#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->filp->f_flags & (flag) ? \ + 1 : 0) +#define INT_HANDLER_PROTO() void(*hndlr)(int, struct pt_regs *) +#define INT_HANDLER_PARMS(irq, parms) int irq, struct pt_regs *parms +#define INT_HANDLER_CALL(irq) irq, NULL diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas.h linux/drivers/sound/pas.h --- v1.3.8/linux/drivers/sound/pas.h Fri Aug 19 08:54:09 1994 +++ linux/drivers/sound/pas.h Fri Mar 3 12:03:07 1995 @@ -42,6 +42,8 @@ #define WAIT_STATE 0xBF88 /* R W Control Four-bit bus wait-state count (~140ns ea.) */ #define BOARD_REV_ID 0x2789 /* R Control Extended Board Revision ID */ +#define CHIP_REV 0xFF88 /* R 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */ + #define SYSTEM_CONFIGURATION_1 0x8388 /* R W Control */ #define S_C_1_PCS_ENABLE 0x01 /* R W PC speaker 1=enable, 0=disable PC speaker emulation */ #define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */ @@ -59,6 +61,7 @@ #define IO_CONFIGURATION_1 0xF388 /* R W Control */ #define I_C_1_BOOT_RESET_ENABLE 0x80 /* R W Control 1=reset board on warm boot, 0=don't */ + #define I_C_1_JOYSTICK_ENABLE 0x40 /* R W Control 1=enable joystick port, 0=don't */ #define IO_CONFIGURATION_2 0xF389 /* R W Control */ #define I_C_2_PCM_DMA_DISABLED 0x00 /* R W PCM PCM DMA disabled */ #define IO_CONFIGURATION_3 0xF38A /* R W Control */ @@ -80,7 +83,7 @@ #define OPERATION_MODE_1 0xEF8B /* R Control */ #define O_M_1_CDROM_TYPE 0x03 /* R CD-ROM 3=SCSI, 2=Sony, 0=no CD-ROM interface */ - #define O_M_1_FM_TYPE 0x04 /* R FM 1=stereo, 0=mono FM chip */ + #define O_M_1_FM_TYPE 0x04 /* R FM 1=sterero, 0=mono FM chip */ #define O_M_1_PCM_TYPE 0x08 /* R PCM 1=16-bit Codec, 0=8-bit DAC */ #define OPERATION_MODE_2 0xFF8B /* R Control */ #define O_M_2_PCS_ENABLED 0x02 /* R PC speaker PC speaker emulation 1=enabled, 0=disabled */ diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v1.3.8/linux/drivers/sound/pas2_card.c Tue Jan 17 07:49:57 1995 +++ linux/drivers/sound/pas2_card.c Mon Jul 10 01:45:14 1995 @@ -44,7 +44,7 @@ static int pas_intr_mask = 0; static int pas_irq = 0; -static char pas_model; +char pas_model; static char *pas_model_names[] = {"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"}; @@ -79,13 +79,13 @@ /******************* Begin of the Interrupt Handler ********************/ void -pasintr (int unused, struct pt_regs * regs) +pasintr (INT_HANDLER_PARMS (irq, dummy)) { int status; status = pas_read (INTERRUPT_STATUS); - pas_write (status, INTERRUPT_STATUS); /* - * Clear interrupt + pas_write (status, INTERRUPT_STATUS); /* + * Clear interrupt */ if (status & I_S_PCM_SAMPLE_BUFFER_IRQ) @@ -117,7 +117,7 @@ if (!pas_intr_mask) { - if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0) + if ((err = snd_set_irq_handler (pas_irq, pasintr, "PAS16")) < 0) return err; } pas_intr_mask |= mask; @@ -182,9 +182,13 @@ pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* * | * S_M_OPL3_DUAL_MONO - */ , SERIAL_MIXER); + */ , SERIAL_MIXER); - pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1); + pas_write (I_C_1_BOOT_RESET_ENABLE +#ifdef PAS_JOYSTICK_ENABLE + | I_C_1_JOYSTICK_ENABLE +#endif + ,IO_CONFIGURATION_1); if (pas_irq < 0 || pas_irq > 15) { @@ -219,9 +223,9 @@ } /* - * This fixes the timing problems of the PAS due to the Symphony chipset - * as per Media Vision. Only define this if your PAS doesn't work correctly. - */ + * This fixes the timing problems of the PAS due to the Symphony chipset + * as per Media Vision. Only define this if your PAS doesn't work correctly. + */ #ifdef SYMPHONY_PAS OUTB (0x05, 0xa8); OUTB (0x60, 0xa9); @@ -253,8 +257,8 @@ else pas_write (0, PRESCALE_DIVIDER); - pas_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER); - pas_write (5, PARALLEL_MIXER); + mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER); + mix_write (5, PARALLEL_MIXER); #if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB) @@ -295,6 +299,8 @@ pas_write (irq_dma, EMULATION_CONFIGURATION); } } +#else + pas_write (0x00, COMPATIBILITY_ENABLE); #endif if (!ok) @@ -348,7 +354,7 @@ */ return 0; - pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]; + pas_model = pas_read (CHIP_REV); return pas_model; } @@ -361,7 +367,7 @@ if (detect_pas_hw (hw_config)) { - if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f])) + if (pas_model = pas_read (CHIP_REV)) { printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID)); } diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c --- v1.3.8/linux/drivers/sound/pas2_midi.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/pas2_midi.c Mon Jul 10 01:45:14 1995 @@ -83,8 +83,8 @@ if (mode == OPEN_READ || mode == OPEN_READWRITE) { - ctrl |= M_C_ENA_INPUT_IRQ;/* - * Enable input + ctrl |= M_C_ENA_INPUT_IRQ; /* + * Enable input */ input_opened = 1; } @@ -134,9 +134,9 @@ fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f; - if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* - * Fifo - * full + if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* + * Fifo + * full */ { return 0; /* @@ -239,6 +239,7 @@ { {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, &std_midi_synth, + {0}, pas_midi_open, pas_midi_close, pas_midi_ioctl, @@ -319,8 +320,10 @@ RESTORE_INTR (flags); } +#if 0 if (stat & M_S_FRAMING_ERROR) printk ("MIDI framing error\n"); +#endif if (stat & M_S_OUTPUT_OVERRUN) { @@ -328,8 +331,8 @@ ofifo_bytes = 100; } - pas_write (stat, MIDI_STATUS);/* - * Acknowledge interrupts + pas_write (stat, MIDI_STATUS); /* + * Acknowledge interrupts */ } diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v1.3.8/linux/drivers/sound/pas2_mixer.c Fri Aug 19 08:54:09 1994 +++ linux/drivers/sound/pas2_mixer.c Mon Jul 10 01:45:14 1995 @@ -35,18 +35,12 @@ #include "pas.h" -#define TRACE(what) /* - * * * (what) */ +#define TRACE(what) /* (what) */ extern int translat_code; +extern char pas_model; -static int rec_devices = (SOUND_MASK_MIC); /* - - - * * * * Default * - * recording * source - * - * * */ +static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */ static int mode_control = 0; #define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ @@ -59,60 +53,47 @@ static unsigned short levels[SOUND_MIXER_NRDEVICES] = { - 0x3232, /* - * Master Volume - */ - 0x3232, /* - * Bass - */ - 0x3232, /* - * Treble - */ - 0x5050, /* - * FM - */ - 0x4b4b, /* - * PCM - */ - 0x3232, /* - * PC Speaker - */ - 0x4b4b, /* - * Ext Line - */ - 0x4b4b, /* - * Mic - */ - 0x4b4b, /* - * CD - */ - 0x6464, /* - * Recording monitor - */ - 0x4b4b, /* - * SB PCM - */ - 0x6464}; /* + 0x3232, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x5050, /* FM */ + 0x4b4b, /* PCM */ + 0x3232, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x4b4b, /* Mic */ + 0x4b4b, /* CD */ + 0x6464, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x6464 /* Recording level */ +}; +void +mix_write (unsigned char data, int ioaddr) +{ + /* + * The Revision D cards have a problem with their MVA508 interface. The + * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and + * MSBs out of the output byte and to do a 16-bit out to the mixer port - + * 1. We need to do this because it isn't timing problem but chip access + * sequence problem. + */ - * * * * Recording level */ + if (pas_model == PAS_16D) + { + OUTW (data | (data << 8), (ioaddr ^ translat_code) - 1); + OUTB (0x80, 0); + } + else + pas_write (data, ioaddr); +} static int mixer_output (int right_vol, int left_vol, int div, int bits, - int mixer /* - * Input or output mixer - */ ) + int mixer) /* Input or output mixer */ { int left = left_vol * div / 100; int right = right_vol * div / 100; - /* - * The Revision D cards have a problem with their MVA508 interface. The - * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and - * MSBs out of the output byte and to do a 16-bit out to the mixer port - - * 1. We don't need to do this because the call to pas_write more than - * compensates for the timing problems. - */ if (bits & P_M_MV508_MIXER) { /* @@ -126,16 +107,16 @@ { /* * Bass and treble are mono devices */ - pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER); - pas_write (left, PARALLEL_MIXER); + mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER); + mix_write (left, PARALLEL_MIXER); right_vol = left_vol; } else { - pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER); - pas_write (left, PARALLEL_MIXER); - pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER); - pas_write (right, PARALLEL_MIXER); + mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER); + mix_write (left, PARALLEL_MIXER); + mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER); + mix_write (right, PARALLEL_MIXER); } return (left_vol | (right_vol << 8)); @@ -144,8 +125,8 @@ void set_mode (int new_mode) { - pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER); - pas_write (new_mode, PARALLEL_MIXER); + mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER); + mix_write (new_mode, PARALLEL_MIXER); mode_control = new_mode; } @@ -168,9 +149,7 @@ switch (whichDev) { - case SOUND_MIXER_VOLUME: /* - * Master volume (0-63) - */ + case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0); break; @@ -178,62 +157,39 @@ * Note! Bass and Treble are mono devices. Will use just the left * channel. */ - case SOUND_MIXER_BASS: /* - * Bass (0-12) - */ + case SOUND_MIXER_BASS: /* Bass (0-12) */ levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0); break; - case SOUND_MIXER_TREBLE: /* - * Treble (0-12) - */ + case SOUND_MIXER_TREBLE: /* Treble (0-12) */ levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0); break; - case SOUND_MIXER_SYNTH: /* - * Internal synthesizer (0-31) - */ + case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer); break; - case SOUND_MIXER_PCM: /* - * PAS PCM (0-31) - */ + case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer); break; - case SOUND_MIXER_ALTPCM: /* - * SB PCM (0-31) - */ + case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer); break; - case SOUND_MIXER_SPEAKER: /* - * PC speaker (0-31) - */ + case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer); break; - case SOUND_MIXER_LINE: /* - * External line (0-31) - */ + case SOUND_MIXER_LINE: /* External line (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer); break; - case SOUND_MIXER_CD: /* - * CD (0-31) - */ + case SOUND_MIXER_CD: /* CD (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer); break; - case SOUND_MIXER_MIC: /* - * External microphone (0-31) - */ + case SOUND_MIXER_MIC: /* External microphone (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer); break; - case SOUND_MIXER_IMIX: /* - * Recording monitor (0-31) (Only available * - * on the Output Mixer) - */ + case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER, P_M_MV508_OUTPUTMIX); break; - case SOUND_MIXER_RECLEV: /* - * Recording level (0-15) - */ + case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0); break; @@ -261,9 +217,7 @@ if (level) mode_control |= P_M_MV508_LOUDNESS; set_mode (mode_control); - return !!level; /* - * 0 or 1 - */ + return !!level; /* 0 or 1 */ break; case SOUND_MIXER_RECSRC: @@ -313,7 +267,7 @@ return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg))); else { /* - * Read parameters + * Read parameters */ switch (cmd & 0xff) @@ -336,15 +290,11 @@ break; case SOUND_MIXER_CAPS: - return IOCTL_OUT (arg, 0); /* - * No special capabilities - */ + return IOCTL_OUT (arg, 0); /* No special capabilities */ break; case SOUND_MIXER_MUTE: - return IOCTL_OUT (arg, 0); /* - * No mute yet - */ + return IOCTL_OUT (arg, 0); /* No mute yet */ break; case SOUND_MIXER_ENHANCE: @@ -369,6 +319,7 @@ static struct mixer_operations pas_mixer_operations = { + "Pro Audio Spectrum 16", pas_mixer_ioctl }; diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c --- v1.3.8/linux/drivers/sound/pas2_pcm.c Fri Aug 19 08:54:09 1994 +++ linux/drivers/sound/pas2_pcm.c Mon Jul 10 01:45:15 1995 @@ -79,13 +79,13 @@ tmp = pas_read (FILTER_FREQUENCY); /* - * Set anti-aliasing filters according to sample rate. You really *NEED* - * to enable this feature for all normal recording unless you want to - * experiment with aliasing effects. - * These filters apply to the selected "recording" source. - * I (pfw) don't know the encoding of these 5 bits. The values shown - * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. -*/ + * Set anti-aliasing filters according to sample rate. You reall *NEED* + * to enable this feature for all normal recording unless you want to + * experiment with aliasing effects. + * These filters apply to the selected "recording" source. + * I (pfw) don't know the encoding of these 5 bits. The values shown + * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. + */ #if !defined NO_AUTO_FILTER_SET tmp &= 0xe0; if (pcm_speed >= 2 * 17897) @@ -128,8 +128,8 @@ pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL); pcm_channels = arg; - pcm_set_speed (pcm_speed);/* - * The speed must be reinitialized + pcm_set_speed (pcm_speed); /* + * The speed must be reinitialized */ } diff -u --recursive --new-file v1.3.8/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c --- v1.3.8/linux/drivers/sound/patmgr.c Fri Aug 19 08:54:09 1994 +++ linux/drivers/sound/patmgr.c Mon Jul 10 01:45:15 1995 @@ -1,7 +1,7 @@ /* * sound/patmgr.c * - * The patch manager interface for the /dev/sequencer + * The patch maneger interface for the /dev/sequencer * * Copyright by Hannu Savolainen 1993 * @@ -234,8 +234,12 @@ printk (" PATMGR: Server %d mbox full. Why?\n", dev); else { - mbox[dev] = - (struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info)); + if ((mbox[dev] = + (struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info))) == NULL) + { + printk ("pmgr: Couldn't allocate memory for a message\n"); + return 0; + } mbox[dev]->key = PM_K_EVENT; mbox[dev]->command = event; diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v1.3.8/linux/drivers/sound/pss.c Mon Mar 6 11:22:09 1995 +++ linux/drivers/sound/pss.c Mon Jul 10 01:45:16 1995 @@ -1,664 +1,250 @@ -/* Marc.Hoffman@analog.com +/* + * sound/pss.c + * + * The low level driver for the Personal Sound System (ECHO ESC614). + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ - This is a pss driver. - - it is based on Greg.Yukna@analog.com @file{host} for DOG - - Unfortunately I can't distribute the ld file needed to - make the pss card to emulate the SB stuff. - - I have provided a simple interface to the PSS unlike the - DOG version. to download a new algorithm just cat it to - /dev/pss 14,9. - - You really need to rebuild this with the synth.ld file - - get the .ld from your dos directory maybe - voyetra\dsp001.ld - - ld2inc < synth.ld > synth-ld.h - (make config does the same). - - rebuild - - Okay if you blow things away no problem just - - main(){ioctl(open("/dev/pss"),SNDCTL_PSS_RESET)}; - - and everything will be okay. - - At first I was going to worry about applications that were using - the sound stuff and disallow the use of /dev/pss. But for - now I figured it doesn't matter. - - And if you change algos all the other applications running die off - due to DMA problems. Yeah just pull the plug and watch em die. - - If the registers get hosed - main(){ioctl(open("/dev/pss"),SNDCTL_PSS_SETUP_REGISTERS)}; - - Probably everything else can be done via mmap - - Oh if you want to develop code for the ADSP-21xx or Program the - 1848 just send me mail and I will hook you up. - - marc.hoffman@analog.com - - */ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS) - -#ifndef PSS_MSS_BASE -#define PSS_MSS_BASE 0 -#endif - -#ifndef PSS_MPU_BASE -#define PSS_MPU_BASE 0 -#endif - -#ifndef PSS_MPU_IRQ -#define PSS_MPU_IRQ 0 -#endif - -#undef DEB -#define DEB(x) x - -#include "pss.h" - -static int pss_ok = 0; -static int sb_ok = 0; - -static int pss_base; -static int pss_irq; -static int pss_dma; - -static int gamePort = 0; - -static int sbInt; -static int cdPol; -static int cdAddr = 0; /* 0x340; */ -static int cdInt = 10; - -/* Define these by hand in local.h */ -static int wssAddr = PSS_MSS_BASE; -static int midiAddr = PSS_MPU_BASE; -static int midiInt = PSS_MPU_IRQ; - -static int SoundPortAddress; -static int SoundPortData; -static int speaker = 1; +#if defined (CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS) && !defined(EXCLUDE_AUDIO) +/* + * PSS registers. + */ +#define REG(x) (devc->base+x) +#define PSS_DATA 0 +#define PSS_STATUS 2 +#define PSS_CONTROL 2 +#define PSS_ID 4 +#define PSS_IRQACK 4 +#define PSS_PIO 0x1a + +/* + * Config registers + */ +#define CONF_PSS 0x10 +#define CONF_WSS 0x12 +#define CONF_SB 0x13 +#define CONF_CDROM 0x16 +#define CONF_MIDI 0x18 + +/* + * Status bits. + */ +#define PSS_FLAG3 0x0800 +#define PSS_FLAG2 0x0400 +#define PSS_FLAG1 0x1000 +#define PSS_FLAG0 0x0800 +#define PSS_WRITE_EMPTY 0x8000 +#define PSS_READ_FULL 0x4000 -static struct pss_speaker default_speaker = -{0, 0, 0, PSS_STEREO}; - -DEFINE_WAIT_QUEUE (pss_sleeper, pss_sleep_flag); - +#include "coproc.h" #include "synth-ld.h" -static int pss_download_boot (unsigned char *block, int size); -static int pss_reset_dsp (void); +typedef struct pss_config + { + int base; + int irq; + int dma; + } -static inline void -pss_outpw (unsigned short port, unsigned short value) -{ - __asm__ __volatile__ ("outw %w0, %w1" - : /* no outputs */ - :"a" (value), "d" (port)); -} +pss_config; -static inline unsigned int -pss_inpw (unsigned short port) -{ - unsigned int _v; - __asm__ __volatile__ ("inw %w1,%w0" - :"=a" (_v):"d" (port), "0" (0)); +static pss_config pss_data; +static pss_config *devc = &pss_data; - return _v; -} +static int pss_initialized = 0; +static int nonstandard_microcode = 0; -static void -PSS_write (int data) +int +probe_pss (struct address_info *hw_config) { - int i, limit; + unsigned short id; + int irq, dma; - limit = GET_TIME () + 10; /* The timeout is 0.1 seconds */ - /* - * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 5000000 && GET_TIME () < limit; i++) - { - if (pss_inpw (pss_base + PSS_STATUS) & PSS_WRITE_EMPTY) - { - pss_outpw (pss_base + PSS_DATA, data); - return; - } - } - printk ("PSS: DSP Command (%04x) Timeout.\n", data); - printk ("IRQ conflict???\n"); -} - - -static void -pss_setaddr (int addr, int configAddr) -{ - int val; + devc->base = hw_config->io_base; + irq = devc->irq = hw_config->irq; + dma = devc->dma = hw_config->dma; - val = pss_inpw (configAddr); - val &= ADDR_MASK; - val |= (addr << 4); - pss_outpw (configAddr, val); -} - -/*_____ pss_checkint - This function tests an interrupt number to see if - it is available. It takes the interrupt button - as its argument and returns TRUE if the interrupt - is ok. -*/ -static int -pss_checkint (int intNum) -{ - int val; - int ret; - int i; - - /*_____ Set the interrupt bits */ - switch (intNum) - { - case 3: - val = pss_inpw (pss_base + PSS_CONFIG); - val &= INT_MASK; - val |= INT_3_BITS; - pss_outpw (pss_base + PSS_CONFIG, val); - break; - case 5: - val = pss_inpw (pss_base + PSS_CONFIG); - val &= INT_MASK; - val |= INT_5_BITS; - pss_outpw (pss_base + PSS_CONFIG, val); - break; - case 7: - val = pss_inpw (pss_base + PSS_CONFIG); - val &= INT_MASK; - val |= INT_7_BITS; - pss_outpw (pss_base + PSS_CONFIG, val); - break; - case 9: - val = pss_inpw (pss_base + PSS_CONFIG); - val &= INT_MASK; - val |= INT_9_BITS; - pss_outpw (pss_base + PSS_CONFIG, val); - break; - case 10: - val = pss_inpw (pss_base + PSS_CONFIG); - val &= INT_MASK; - val |= INT_10_BITS; - pss_outpw (pss_base + PSS_CONFIG, val); - break; - case 11: - val = pss_inpw (pss_base + PSS_CONFIG); - val &= INT_MASK; - val |= INT_11_BITS; - pss_outpw (pss_base + PSS_CONFIG, val); - break; - case 12: - val = pss_inpw (pss_base + PSS_CONFIG); - val &= INT_MASK; - val |= INT_12_BITS; - pss_outpw (pss_base + PSS_CONFIG, val); - break; - default: - printk ("unknown interrupt selected. %d\n", intNum); + if (devc->base != 0x220 && devc->base != 0x240) + if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ return 0; - } - - /*_____ Set the interrupt test bit */ - val = pss_inpw (pss_base + PSS_CONFIG); - val |= INT_TEST_BIT; - pss_outpw (pss_base + PSS_CONFIG, val); - /*_____ Check if the interrupt is in use */ - /*_____ Do it a few times in case there is a delay */ - ret = 0; - for (i = 0; i < 5; i++) - { - val = pss_inpw (pss_base + PSS_CONFIG); - if (val & INT_TEST_PASS) - { - ret = 1; - break; - } - } - /*_____ Clear the Test bit and the interrupt bits */ - val = pss_inpw (pss_base + PSS_CONFIG); - val &= INT_TEST_BIT_MASK; - val &= INT_MASK; - pss_outpw (pss_base + PSS_CONFIG, val); - return (ret); -} + if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && + irq != 10 && irq != 11 && irq != 12) + return 0; -/*____ pss_setint - This function sets the correct bits in the - configuration register to - enable the chosen interrupt. -*/ -static void -pss_setint (int intNum, int configAddress) -{ - int val; + if (dma != 5 && dma != 6 && dma != 7) + return 0; - switch (intNum) + id = INW (REG (PSS_ID)); + if ((id >> 8) != 'E') { - case 0: - val = pss_inpw (configAddress); - val &= INT_MASK; - pss_outpw (configAddress, val); - break; - case 3: - val = pss_inpw (configAddress); - val &= INT_MASK; - val |= INT_3_BITS; - pss_outpw (configAddress, val); - break; - case 5: - val = pss_inpw (configAddress); - val &= INT_MASK; - val |= INT_5_BITS; - pss_outpw (configAddress, val); - break; - case 7: - val = pss_inpw (configAddress); - val &= INT_MASK; - val |= INT_7_BITS; - pss_outpw (configAddress, val); - break; - case 9: - val = pss_inpw (configAddress); - val &= INT_MASK; - val |= INT_9_BITS; - pss_outpw (configAddress, val); - break; - case 10: - val = pss_inpw (configAddress); - val &= INT_MASK; - val |= INT_10_BITS; - pss_outpw (configAddress, val); - break; - case 11: - val = pss_inpw (configAddress); - val &= INT_MASK; - val |= INT_11_BITS; - pss_outpw (configAddress, val); - break; - case 12: - val = pss_inpw (configAddress); - val &= INT_MASK; - val |= INT_12_BITS; - pss_outpw (configAddress, val); - break; - default: - printk ("pss_setint unknown int\n"); + printk ("No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); + return 0; } -} - -/*____ pss_setsbint - This function sets the correct bits in the - SoundBlaster configuration PSS register to - enable the chosen interrupt. - It takes a interrupt button as its argument. -*/ -static void -pss_setsbint (int intNum) -{ - int val; - int sbConfigAddress; - - sbConfigAddress = pss_base + SB_CONFIG; - switch (intNum) - { - case 3: - val = pss_inpw (sbConfigAddress); - val &= INT_MASK; - val |= INT_3_BITS; - pss_outpw (sbConfigAddress, val); - break; - case 5: - val = pss_inpw (sbConfigAddress); - val &= INT_MASK; - val |= INT_5_BITS; - pss_outpw (sbConfigAddress, val); - break; - case 7: - val = pss_inpw (sbConfigAddress); - val &= INT_MASK; - val |= INT_7_BITS; - pss_outpw (sbConfigAddress, val); - break; - default: - printk ("pss_setsbint: unknown_int\n"); - } + return 1; } -/*____ pss_setsbdma - This function sets the correct bits in the - SoundBlaster configuration PSS register to - enable the chosen DMA channel. - It takes a DMA button as its argument. -*/ -static void -pss_setsbdma (int dmaNum) +static int +set_irq (pss_config * devc, int dev, int irq) { - int val; - int sbConfigAddress; + static unsigned short irq_bits[16] = + { + 0x0000, 0x0000, 0x0000, 0x0008, + 0x0000, 0x0010, 0x0000, 0x0018, + 0x0000, 0x0020, 0x0028, 0x0030, + 0x0038, 0x0000, 0x0000, 0x0000 + }; - sbConfigAddress = pss_base + SB_CONFIG; + unsigned short tmp, bits; - switch (dmaNum) - { - case 1: - val = pss_inpw (sbConfigAddress); - val &= DMA_MASK; - val |= DMA_1_BITS; - pss_outpw (sbConfigAddress, val); - break; - default: - printk ("Personal Sound System ERROR! pss_setsbdma: unknown_dma\n"); - } -} - -/*____ pss_setwssdma - This function sets the correct bits in the - WSS configuration PSS register to - enable the chosen DMA channel. - It takes a DMA button as its argument. -*/ -static void -pss_setwssdma (int dmaNum) -{ - int val; - int wssConfigAddress; + if (irq < 1 || irq > 15) + return 0; - wssConfigAddress = pss_base + PSS_WSS_CONFIG; + tmp = INW (REG (dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ - switch (dmaNum) + if ((bits = irq_bits[irq]) == 0) { - case 0: - val = pss_inpw (wssConfigAddress); - val &= DMA_MASK; - val |= DMA_0_BITS; - pss_outpw (wssConfigAddress, val); - break; - case 1: - val = pss_inpw (wssConfigAddress); - val &= DMA_MASK; - val |= DMA_1_BITS; - pss_outpw (wssConfigAddress, val); - break; - case 3: - val = pss_inpw (wssConfigAddress); - val &= DMA_MASK; - val |= DMA_3_BITS; - pss_outpw (wssConfigAddress, val); - break; - default: - printk ("Personal Sound System ERROR! pss_setwssdma: unknown_dma\n"); + printk ("PSS: Invalid IRQ %d\n", irq); + return 0; } -} - -/*_____ SetSpeakerOut - This function sets the Volume, Bass, Treble and Mode of - the speaker out channel. - */ -void -pss_setspeaker (struct pss_speaker *spk) -{ - PSS_write (SET_MASTER_COMMAND); - if (spk->volume > PHILLIPS_VOL_MAX) - spk->volume = PHILLIPS_VOL_MAX; - if (spk->volume < PHILLIPS_VOL_MIN) - spk->volume = PHILLIPS_VOL_MIN; - - PSS_write (MASTER_VOLUME_LEFT - | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP)); - PSS_write (SET_MASTER_COMMAND); - PSS_write (MASTER_VOLUME_RIGHT - | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP)); - - if (spk->bass > PHILLIPS_BASS_MAX) - spk->bass = PHILLIPS_BASS_MAX; - if (spk->bass < PHILLIPS_BASS_MIN) - spk->bass = PHILLIPS_BASS_MIN; - PSS_write (SET_MASTER_COMMAND); - PSS_write (MASTER_BASS - | (PHILLIPS_BASS_CONSTANT + spk->bass / PHILLIPS_BASS_STEP)); - - if (spk->treb > PHILLIPS_TREBLE_MAX) - spk->treb = PHILLIPS_TREBLE_MAX; - if (spk->treb < PHILLIPS_TREBLE_MIN) - spk->treb = PHILLIPS_TREBLE_MIN; - PSS_write (SET_MASTER_COMMAND); - PSS_write (MASTER_TREBLE - | (PHILLIPS_TREBLE_CONSTANT + spk->treb / PHILLIPS_TREBLE_STEP)); - - PSS_write (SET_MASTER_COMMAND); - PSS_write (MASTER_SWITCH | spk->mode); + OUTW (tmp | bits, REG (dev)); + return 1; } -static void -pss_init1848 (void) +static int +set_io_base (pss_config * devc, int dev, int base) { - /*_____ Wait for 1848 to init */ - while (INB (SoundPortAddress) & SP_IN_INIT); + unsigned short tmp = INW (REG (dev)) & 0x003f; + unsigned short bits = (base & 0x0ffc) << 4; - /*_____ Wait for 1848 to autocal */ - OUTB (SoundPortAddress, SP_TEST_AND_INIT); - while (INB (SoundPortData) & AUTO_CAL_IN_PROG); + OUTW (bits | tmp, REG (dev)); + + return 1; } static int -pss_configure_registers_to_look_like_sb (void) +set_dma (pss_config * devc, int dev, int dma) { - pss_setaddr (wssAddr, pss_base + PSS_WSS_CONFIG); - - SoundPortAddress = wssAddr + 4; - SoundPortData = wssAddr + 5; - - DEB (printk ("Turning Game Port %s.\n", - gamePort ? "On" : "Off")); - - /*_____ Turn on the Game port */ - if (gamePort) - pss_outpw (pss_base + PSS_STATUS, - pss_inpw (pss_base + PSS_STATUS) | GAME_BIT); - else - pss_outpw (pss_base + PSS_STATUS, - pss_inpw (pss_base + PSS_STATUS) & GAME_BIT_MASK); + static unsigned short dma_bits[8] = + { + 0x0001, 0x0002, 0x0000, 0x0003, + 0x0000, 0x0005, 0x0006, 0x0007 + }; + unsigned short tmp, bits; - DEB (printk ("PSS attaching base %x irq %d dma %d\n", - pss_base, pss_irq, pss_dma)); - - /* Check if sb is enabled if it is check the interrupt */ - pss_outpw (pss_base + SB_CONFIG, 0); - - if (pss_irq != 0) - { - DEB (printk ("PSS Emulating Sound Blaster ADDR %04x\n", pss_base)); - DEB (printk ("PSS SBC: attaching base %x irq %d dma %d\n", - SBC_BASE, SBC_IRQ, SBC_DMA)); - - if (pss_checkint (SBC_IRQ) == 0) - { - printk ("PSS! attach: int_error\n"); - return 0; - } - - pss_setsbint (SBC_IRQ); - pss_setsbdma (SBC_DMA); - sb_ok = 1; - } - else - { - sb_ok = 0; - printk ("PSS: sound blaster error init\n"); - } + if (dma < 0 || dma > 7) + return 0; - /* Check if cd is enabled if it is check the interrupt */ - pss_outpw (pss_base + CD_CONFIG, 0); + tmp = INW (REG (dev)) & ~0x07; /* Load confreg, mask DMA bits out */ - if (cdAddr != 0) + if ((bits = dma_bits[dma]) == 0) { - DEB (printk ("PSS:CD drive %x irq: %d", cdAddr, cdInt)); - if (cdInt != 0) - { - if (pss_checkint (cdInt) == 0) - { - printk ("Can't allocate cdInt %d\n", cdInt); - } - else - { - int val; - - printk ("CD poll "); - pss_setaddr (cdAddr, pss_base + CD_CONFIG); - pss_setint (cdInt, pss_base + CD_CONFIG); - - /* set the correct bit in the - configuration register to - set the irq polarity for the CD-Rom. - NOTE: This bit is in the address config - field, It must be configured after setting - the CD-ROM ADDRESS!!! */ - val = pss_inpw (pss_base + CD_CONFIG); - pss_outpw (pss_base + CD_CONFIG, 0); - val &= CD_POL_MASK; - if (cdPol) - val |= CD_POL_BIT; - pss_outpw (pss_base + CD_CONFIG, val); - } - } + printk ("PSS: Invalid DMA %d\n", dma); + return 0; } - /* Check if midi is enabled if it is check the interrupt */ - pss_outpw (pss_base + MIDI_CONFIG, 0); - if (midiAddr != 0) - { - printk ("midi init %x %d\n", midiAddr, midiInt); - if (pss_checkint (midiInt) == 0) - { - printk ("midi init int error %x %d\n", midiAddr, midiInt); - } - else - { - pss_setaddr (midiAddr, pss_base + MIDI_CONFIG); - pss_setint (midiInt, pss_base + MIDI_CONFIG); - } - } + OUTW (tmp | bits, REG (dev)); return 1; } -long -attach_pss (long mem_start, struct address_info *hw_config) +static int +pss_reset_dsp (pss_config * devc) { - if (pss_ok) - { - if (hw_config) - { - printk (" "); - } - - return mem_start; - } + unsigned long i, limit = GET_TIME () + 10; - pss_ok = 1; + OUTW (0x2000, REG (PSS_CONTROL)); - if (pss_configure_registers_to_look_like_sb () == 0) - return mem_start; + for (i = 0; i < 32768 && GET_TIME () < limit; i++) + INW (REG (PSS_CONTROL)); - if (sb_ok) - if (pss_synthLen - && pss_download_boot (pss_synth, pss_synthLen)) - { - if (speaker) - pss_setspeaker (&default_speaker); - pss_ok = 1; - } - else - pss_reset_dsp (); + OUTW (0x0000, REG (PSS_CONTROL)); - return mem_start; + return 1; } -int -probe_pss (struct address_info *hw_config) +static int +pss_put_dspword (pss_config * devc, unsigned short word) { - pss_base = hw_config->io_base; - pss_irq = hw_config->irq; - pss_dma = hw_config->dma; + int i, val; - if ((pss_inpw (pss_base + 4) & 0xff00) == 0x4500) + for (i = 0; i < 327680; i++) { - attach_pss (0, hw_config); - return 1; + val = INW (REG (PSS_STATUS)); + if (val & PSS_WRITE_EMPTY) + { + OUTW (word, REG (PSS_DATA)); + return 1; + } } - printk (" fail base %x irq %d dma %d\n", pss_base, pss_irq, pss_dma); return 0; } - static int -pss_reattach (void) +pss_get_dspword (pss_config * devc, unsigned short *word) { - pss_ok = 0; - attach_pss (0, 0); - return 1; -} + int i, val; -static int -pss_reset_dsp () -{ - unsigned long i, limit = GET_TIME () + 10; - - pss_outpw (pss_base + PSS_CONTROL, 0x2000); - - for (i = 0; i < 32768 && GET_TIME () < limit; i++) - pss_inpw (pss_base + PSS_CONTROL); - - pss_outpw (pss_base + PSS_CONTROL, 0x0000); + for (i = 0; i < 327680; i++) + { + val = INW (REG (PSS_STATUS)); + if (val & PSS_READ_FULL) + { + *word = INW (REG (PSS_DATA)); + return 1; + } + } - return 1; + return 0; } - static int -pss_download_boot (unsigned char *block, int size) +pss_download_boot (pss_config * devc, unsigned char *block, int size, int flags) { int i, limit, val, count; - printk ("PSS: downloading boot code synth.ld... "); - - /*_____ Warn DSP software that a boot is coming */ - pss_outpw (pss_base + PSS_DATA, 0x00fe); + if (flags & CPF_FIRST) + { +/*_____ Warn DSP software that a boot is coming */ + OUTW (0x00fe, REG (PSS_DATA)); - limit = GET_TIME () + 10; + limit = GET_TIME () + 10; - for (i = 0; i < 32768 && GET_TIME () < limit; i++) - if (pss_inpw (pss_base + PSS_DATA) == 0x5500) - break; + for (i = 0; i < 32768 && GET_TIME () < limit; i++) + if (INW (REG (PSS_DATA)) == 0x5500) + break; - pss_outpw (pss_base + PSS_DATA, *block++); + OUTW (*block++, REG (PSS_DATA)); - pss_reset_dsp (); - printk ("start "); + pss_reset_dsp (devc); + } count = 1; while (1) @@ -667,15 +253,15 @@ for (j = 0; j < 327670; j++) { - /*_____ Wait for BG to appear */ - if (pss_inpw (pss_base + PSS_STATUS) & PSS_FLAG3) +/*_____ Wait for BG to appear */ + if (INW (REG (PSS_STATUS)) & PSS_FLAG3) break; } if (j == 327670) { /* It's ok we timed out when the file was empty */ - if (count >= size) + if (count >= size && flags & CPF_LAST) break; else { @@ -684,241 +270,460 @@ return 0; } } - /*_____ Send the next byte */ - pss_outpw (pss_base + PSS_DATA, *block++); +/*_____ Send the next byte */ + OUTW (*block++, REG (PSS_DATA)); count++; } - /*_____ Why */ - pss_outpw (pss_base + PSS_DATA, 0); + if (flags & CPF_LAST) + { +/*_____ Why */ + OUTW (0, REG (PSS_DATA)); - limit = GET_TIME () + 10; - for (i = 0; i < 32768 && GET_TIME () < limit; i++) - val = pss_inpw (pss_base + PSS_STATUS); + limit = GET_TIME () + 10; + for (i = 0; i < 32768 && GET_TIME () < limit; i++) + val = INW (REG (PSS_STATUS)); - printk ("downloaded\n"); + limit = GET_TIME () + 10; + for (i = 0; i < 32768 && GET_TIME () < limit; i++) + { + val = INW (REG (PSS_STATUS)); + if (val & 0x4000) + break; + } - limit = GET_TIME () + 10; - for (i = 0; i < 32768 && GET_TIME () < limit; i++) - { - val = pss_inpw (pss_base + PSS_STATUS); - if (val & 0x4000) - break; - } + /* now read the version */ + for (i = 0; i < 32000; i++) + { + val = INW (REG (PSS_STATUS)); + if (val & PSS_READ_FULL) + break; + } + if (i == 32000) + return 0; - /* now read the version */ - for (i = 0; i < 32000; i++) - { - val = pss_inpw (pss_base + PSS_STATUS_REG); - if (val & PSS_READ_FULL) - break; + val = INW (REG (PSS_DATA)); + /* printk("", val/16, val % 16); */ } - if (i == 32000) - return 0; - - val = pss_inpw (pss_base + PSS_DATA_REG); return 1; } +long +attach_pss (long mem_start, struct address_info *hw_config) +{ + unsigned short id; -/* The following is a simple device driver for the pss. - All I really care about is communication to and from the pss. + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; - The ability to reinitialize the This will be - default when release is chosen. + if (!probe_pss (hw_config)) + return mem_start; - SNDCTL_PSS_DOWNLOAD: + id = INW (REG (PSS_ID)) & 0x00ff; - Okay we need to creat new minor numbers for the - DOWNLOAD functionality. - - 14,0x19 -- /dev/pssld where a read operation would output the - current ld to user space - where a write operation would effectively - download a new ld. - - 14,0x09 -- /dev/psecho would open up a communication path to the - esc614 asic. Given the ability to send - messages to the asic and receive messages too. - - All messages would get read and written in the - same manner. It would be up to the application - and the ld to maintain a relationship - of what the messages mean. - - for this device we need to implement select. */ -#define CODE_BUFFER_LEN (64*1024) -static char *code_buffer; -static int code_length; + /* + * Disable all emulations. Will be enabled later (if required). + */ + OUTW (0x0000, REG (CONF_PSS)); + OUTW (0x0000, REG (CONF_WSS)); + OUTW (0x0000, REG (CONF_SB)); + OUTW (0x0000, REG (CONF_MIDI)); + OUTW (0x0000, REG (CONF_CDROM)); -static int lock_pss = 0; + if (!set_irq (devc, CONF_PSS, devc->irq)) + { + printk ("PSS: IRQ error\n"); + return mem_start; + } + + if (!set_dma (devc, CONF_PSS, devc->dma)) + { + printk ("PSS: DRQ error\n"); + return mem_start; + } + + pss_initialized = 1; + printk (" ", id); + + return mem_start; +} int -pss_open (int dev, struct fileinfo *file) +probe_pss_mpu (struct address_info *hw_config) { - int mode; + int timeout; + + if (!pss_initialized) + return 0; - DEB (printk ("pss_open\n")); + if (!set_io_base (devc, CONF_MIDI, hw_config->io_base)) + { + printk ("PSS: MIDI base error.\n"); + return 0; + } - if (pss_ok == 0) - return RET_ERROR (EIO); + if (!set_irq (devc, CONF_MIDI, hw_config->irq)) + { + printk ("PSS: MIDI IRQ error.\n"); + return 0; + } - if (lock_pss) - return 0; + if (!pss_synthLen) + { + printk ("PSS: Can't enable MPU. MIDI synth microcode not available.\n"); + return 0; + } + + if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); + return 0; + } - lock_pss = 1; +/* + * Finally wait until the DSP algorithm has initialized itself and + * deactivates receive interrupt. + */ - dev = dev >> 4; - mode = file->mode & O_ACCMODE; - if (mode == O_WRONLY) + for (timeout = 900000; timeout > 0; timeout--) { - printk ("pss-open for WRONLY\n"); - code_length = 0; + if ((INB (hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ + INB (hw_config->io_base); /* Discard it */ + else + break; /* No more input */ } - RESET_WAIT_QUEUE (pss_sleeper, pss_sleep_flag); - return 1; +#ifdef EXCLUDE_MIDI + return 0 +#else + return probe_mpu401 (hw_config); +#endif } -void -pss_release (int dev, struct fileinfo *file) +static int +pss_coproc_open (void *dev_info, int sub_device) { - int mode; + switch (sub_device) + { + case COPR_MIDI: - DEB (printk ("pss_release\n")); - if (pss_ok == 0) - return RET_ERROR (EIO); - - dev = dev >> 4; - mode = file->mode & O_ACCMODE; - if (mode == O_WRONLY && code_length > 0) - { -#ifdef linux - /* This just allows interrupts while the conversion is running */ - __asm__ ("sti"); -#endif - if (!pss_download_boot (code_buffer, code_length)) + if (pss_synthLen == 0) { - pss_reattach (); + printk ("PSS: MIDI synth microcode not available.\n"); + return RET_ERROR (EIO); } + + if (nonstandard_microcode) + if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); + return RET_ERROR (EIO); + } + nonstandard_microcode = 0; + break; + + default:; } - lock_pss = 0; + return 0; } -int -pss_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +static void +pss_coproc_close (void *dev_info, int sub_device) { - int c, p; - - DEB (printk ("pss_read\n")); - if (pss_ok == 0) - return RET_ERROR (EIO); - - dev = dev >> 4; - p = 0; - c = count; + return; +} - return count - c; +static void +pss_coproc_reset (void *dev_info) +{ + if (pss_synthLen) + if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); + } + nonstandard_microcode = 0; } -int -pss_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +static int +download_boot_block (void *dev_info, copr_buffer * buf) { - DEB (printk ("pss_write\n")); - if (pss_ok == 0) - return RET_ERROR (EIO); - dev = dev >> 4; + if (buf->len <= 0 || buf->len > sizeof (buf->data)) + return RET_ERROR (EINVAL); - if (count) /* Flush output */ + if (!pss_download_boot (devc, buf->data, buf->len, buf->flags)) { - COPY_FROM_USER (&code_buffer[code_length], buf, 0, count); - code_length += count; + printk ("PSS: Unable to load microcode block to DSP.\n"); + return RET_ERROR (EIO); } - return count; -} + nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ + return 0; +} -int -pss_ioctl (int dev, struct fileinfo *file, - unsigned int cmd, unsigned int arg) +static int +pss_coproc_ioctl (void *dev_info, unsigned int cmd, unsigned int arg, int local) { - DEB (printk ("pss_ioctl dev=%d cmd=%x\n", dev, cmd)); - if (pss_ok == 0) - return RET_ERROR (EIO); - - dev = dev >> 4; + /* printk("PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ switch (cmd) { - case SNDCTL_PSS_RESET: - pss_reattach (); - return 1; - - case SNDCTL_PSS_SETUP_REGISTERS: - pss_configure_registers_to_look_like_sb (); - return 1; + case SNDCTL_COPR_RESET: + pss_coproc_reset (dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) KERNEL_MALLOC (sizeof (copr_buffer)); + IOCTL_FROM_USER ((char *) buf, (char *) arg, 0, sizeof (*buf)); + err = download_boot_block (dev_info, buf); + KERNEL_FREE (buf); + return err; + } + break; + + case SNDCTL_COPR_RDATA: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + IOCTL_FROM_USER ((char *) &buf, (char *) arg, 0, sizeof (buf)); + + DISABLE_INTR (flags); + if (!pss_put_dspword (devc, 0x00d0)) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + if (!pss_get_dspword (devc, &tmp)) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + buf.parm1 = tmp; + RESTORE_INTR (flags); + + IOCTL_TO_USER ((char *) arg, 0, &buf, sizeof (buf)); + return 0; + } + break; + + case SNDCTL_COPR_WDATA: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + IOCTL_FROM_USER ((char *) &buf, (char *) arg, 0, sizeof (buf)); + + DISABLE_INTR (flags); + if (!pss_put_dspword (devc, 0x00d1)) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + tmp = (unsigned int) buf.parm2 & 0xffff; + if (!pss_put_dspword (devc, tmp)) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } - case SNDCTL_PSS_SPEAKER: + RESTORE_INTR (flags); + return 0; + } + break; + + case SNDCTL_COPR_WCODE: { - struct pss_speaker params; - COPY_FROM_USER (¶ms, (char *) arg, 0, sizeof (struct pss_speaker)); + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + IOCTL_FROM_USER ((char *) &buf, (char *) arg, 0, sizeof (buf)); + + DISABLE_INTR (flags); + if (!pss_put_dspword (devc, 0x00d3)) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; + if (!pss_put_dspword (devc, tmp)) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + tmp = (unsigned int) buf.parm2 & 0x00ff; + if (!pss_put_dspword (devc, tmp)) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } - pss_setspeaker (¶ms); + RESTORE_INTR (flags); return 0; } + break; + + case SNDCTL_COPR_RCODE: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + IOCTL_FROM_USER ((char *) &buf, (char *) arg, 0, sizeof (buf)); + + DISABLE_INTR (flags); + if (!pss_put_dspword (devc, 0x00d2)) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + if (!pss_get_dspword (devc, &tmp)) /* Read msb */ + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + buf.parm1 = tmp << 8; + + if (!pss_get_dspword (devc, &tmp)) /* Read lsb */ + { + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + + buf.parm1 |= tmp & 0x00ff; + + RESTORE_INTR (flags); + + IOCTL_TO_USER ((char *) arg, 0, &buf, sizeof (buf)); + return 0; + } + break; + default: - return RET_ERROR (EIO); + return RET_ERROR (EINVAL); } + + return RET_ERROR (EINVAL); } -/* This is going to be used to implement - waiting on messages sent from the DSP and to the - DSP when communication is used via the pss directly. +static coproc_operations pss_coproc_operations = +{ + "ADSP-2115", + pss_coproc_open, + pss_coproc_close, + pss_coproc_ioctl, + pss_coproc_reset, + &pss_data +}; - We need to find out if the pss can generate a different - interrupt other than the one it has been setup for. +long +attach_pss_mpu (long mem_start, struct address_info *hw_config) +{ + int prev_devs; + long ret; - This way we can carry on a conversation with the pss - on a separate channel. This would be useful for debugging. */ +#ifndef EXCLUDE_MIDI + prev_devs = num_midis; + ret = attach_mpu401 (mem_start, hw_config); -pss_select (int dev, struct fileinfo * file, int sel_type, select_table * wait) + if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ + midi_devs[prev_devs]->coproc = &pss_coproc_operations; +#endif + return ret; +} + +int +probe_pss_mss (struct address_info *hw_config) { - return 0; - if (pss_ok == 0) - return RET_ERROR (EIO); + int timeout; - dev = dev >> 4; + if (!pss_initialized) + return 0; - switch (sel_type) + if (!set_io_base (devc, CONF_WSS, hw_config->io_base)) { - case SEL_IN: - select_wait (&pss_sleeper, wait); + printk ("PSS: WSS base error.\n"); return 0; - break; + } - case SEL_OUT: - select_wait (&pss_sleeper, wait); + if (!set_irq (devc, CONF_WSS, hw_config->irq)) + { + printk ("PSS: WSS IRQ error.\n"); return 0; - break; + } - case SEL_EX: + if (!set_dma (devc, CONF_WSS, hw_config->dma)) + { + printk ("PSS: WSS DRQ error\n"); return 0; } - return 0; + /* + * For some reason the card returns 0xff in the WSS status register + * immediately after boot. Propably MIDI+SB emulation algorithm + * downloaded to the ADSP2115 spends some time initializing the card. + * Let's try to wait until it finishes this task. + */ + for (timeout = 0; + timeout < 100000 && (INB (hw_config->io_base + 3) & 0x3f) != 0x04; + timeout++); + + return probe_ms_sound (hw_config); } long -pss_init (long mem_start) +attach_pss_mss (long mem_start, struct address_info *hw_config) { - DEB (printk ("pss_init\n")); - if (pss_ok) - { - code_buffer = mem_start; - mem_start += CODE_BUFFER_LEN; - } - return mem_start; + int prev_devs; + long ret; + + prev_devs = num_audiodevs; + ret = attach_ms_sound (mem_start, hw_config); + + if (num_audiodevs == (prev_devs + 1)) /* The MSS driver installed itself */ + audio_devs[prev_devs]->coproc = &pss_coproc_operations; + + return ret; } #endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c --- v1.3.8/linux/drivers/sound/sb16_dsp.c Tue Aug 23 09:48:52 1994 +++ linux/drivers/sound/sb16_dsp.c Mon Jul 10 01:45:17 1995 @@ -42,11 +42,11 @@ extern int sbc_base; -static int sb16_dsp_ok = 0;/* +static int sb16_dsp_ok = 0; /* - * * * * Set to 1 after successful * - * * initialization */ + * * * * Set to 1 after successful * + * * initialization */ static int dsp_16bit = 0; static int dsp_stereo = 0; static int dsp_current_speed = 8000; /* @@ -228,7 +228,7 @@ sb_reset_dsp (); - if (ALLOC_DMA_CHN (dma8,"sb16 8bit")) + if (ALLOC_DMA_CHN (dma8, "SB16 (8bit)")) { printk ("SB16: Unable to grab DMA%d\n", dma8); sb_free_irq (); @@ -236,7 +236,7 @@ } if (dma16 != dma8) - if (ALLOC_DMA_CHN (dma16,"sb16 16bit")) + if (ALLOC_DMA_CHN (dma16, "SB16 (16bit)")) { printk ("SB16: Unable to grab DMA%d\n", dma16); sb_free_irq (); @@ -436,6 +436,7 @@ sb_dsp_command01 (0xda); sb_dsp_command01 (0xd0); } + DMAbuf_reset_dma (dev); } static void @@ -472,9 +473,7 @@ if (sbc_major < 4) return mem_start; /* Not a SB16 */ -#ifndef SCO sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); -#endif printk (" <%s>", sb16_dsp_operations.name); @@ -532,8 +531,8 @@ DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma)); /* - * dsp_showmessage(0xe3,99); - */ + * dsp_showmessage(0xe3,99); + */ sb16_dsp_ok = 1; return 1; } diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c --- v1.3.8/linux/drivers/sound/sb16_midi.c Thu Oct 13 13:50:51 1994 +++ linux/drivers/sound/sb16_midi.c Mon Jul 10 01:45:17 1995 @@ -180,6 +180,7 @@ { {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI}, &std_midi_synth, + {0}, sb16midi_open, sb16midi_close, sb16midi_ioctl, diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v1.3.8/linux/drivers/sound/sb_card.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/sb_card.c Mon Jul 10 01:45:17 1995 @@ -25,6 +25,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * Modified: + * Riccardo Facchetti 24 Mar 1995 + * - Added the Audio Excel DSP 16 initialization routine. */ #include "sound_config.h" @@ -46,6 +49,12 @@ int probe_sb (struct address_info *hw_config) { +#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_SBPRO) + /* + * Initialize Audio Excel DSP 16 to SBPRO. + */ + InitAEDSP16_SBPRO (hw_config); +#endif return sb_dsp_detect (hw_config); } diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c --- v1.3.8/linux/drivers/sound/sb_dsp.c Wed Jan 18 09:38:50 1995 +++ linux/drivers/sound/sb_dsp.c Mon Jul 10 01:45:18 1995 @@ -26,9 +26,11 @@ * SUCH DAMAGE. * * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support Sound Galaxy NX Pro + * Hunyue Yau Jan 6 1994 + * Added code to support Sound Galaxy NX Pro * + * JRA Gibson April 1995 + * Code added for MV ProSonic/Jazz 16 in 16 bit mode */ #include "sound_config.h" @@ -42,6 +44,8 @@ int sbc_base = 0; static int sbc_irq = 0; static int open_mode = 0; /* Read, write or both */ +int Jazz16_detected = 0; +int sb_no_recording = 0; /* * The DSP channel can be used either for input or output. Variable @@ -83,6 +87,21 @@ * IMODE_NONE */ static volatile int irq_ok = 0; +#ifdef JAZZ16 +/* 16 bit support + */ + +static int dsp_16bit = 0; +static int dma8 = 1; +static int dma16 = 5; + +static int dsp_set_bits (int arg); +static int initialize_ProSonic16 (void); + +/* end of 16 bit support + */ +#endif + int sb_duplex_midi = 0; static int my_dev = 0; @@ -104,8 +123,8 @@ int i; unsigned long limit; - limit = GET_TIME () + HZ / 10;/* - * The timeout is 0.1 seconds + limit = GET_TIME () + HZ / 10; /* + * The timeout is 0.1 secods */ /* @@ -131,27 +150,22 @@ } void -sbintr (int unit, struct pt_regs *regs) +sbintr (INT_HANDLER_PARMS (irq, dummy)) { int status; #ifndef EXCLUDE_SBPRO if (sb16) { - unsigned char src = sb_getmixer (IRQ_STAT); /* - - - * * * * Interrupt - * source * * - * register */ + unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */ #ifndef EXCLUDE_SB16 if (src & 3) - sb16_dsp_interrupt (unit); + sb16_dsp_interrupt (irq); #ifndef EXCLUDE_MIDI if (src & 4) - sb16midiintr (unit); /* + sb16midiintr (irq); /* * SB MPU401 interrupt */ #endif @@ -160,13 +174,13 @@ if (!(src & 1)) return; /* - * Not a DSP interrupt + * Not a DSP interupt */ } #endif - status = INB (DSP_DATA_AVAIL);/* - * Clear interrupt + status = INB (DSP_DATA_AVAIL); /* + * Clear interrupt */ if (sb_intr_active) @@ -192,7 +206,7 @@ case IMODE_MIDI: #ifndef EXCLUDE_MIDI - sb_midi_interrupt (unit); + sb_midi_interrupt (irq); #endif break; @@ -209,7 +223,7 @@ int ok; if (!sb_irq_usecount) - if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0) + if ((ok = snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster")) < 0) return ok; sb_irq_usecount++; @@ -282,16 +296,16 @@ speed = 4000; /* - * Older SB models don't support higher speeds than 22050. - */ + * Older SB models don't support higher speeds than 22050. + */ if (sbc_major < 2 || (sbc_major == 2 && sbc_minor == 0)) max_speed = 22050; /* - * SB models earlier than SB Pro have low limit for the input speed. - */ + * SB models earlier than SB Pro have low limit for the input speed. + */ if (open_mode != OPEN_WRITE) /* Recording is possible */ if (sbc_major < 3) /* Limited input speed with these cards */ if (sbc_major == 2 && sbc_minor > 0) @@ -304,11 +318,14 @@ * Invalid speed */ - if (dsp_stereo && speed > 22050) - speed = 22050; + /* Logitech SoundMan Games and Jazz16 cards can support 44.1kHz stereo */ +#if !defined (SM_GAMES) /* * Max. stereo speed is 22050 */ + if (dsp_stereo && speed > 22050 && Jazz16_detected == 0) + speed = 22050; +#endif if ((speed > 22050) && sb_midi_busy) { @@ -349,7 +366,7 @@ tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; DISABLE_INTR (flags); - if (sb_dsp_command (0x40))/* + if (sb_dsp_command (0x40)) /* * Set time constant */ sb_dsp_command (tconst); @@ -409,14 +426,14 @@ if (sb_dsp_highspeed) { DISABLE_INTR (flags); - if (sb_dsp_command (0x48))/* - * High speed size + if (sb_dsp_command (0x48)) /* + * High speed size */ { sb_dsp_command ((unsigned char) (count & 0xff)); sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); - sb_dsp_command (0x91);/* - * High speed 8 bit DAC + sb_dsp_command (0x91); /* + * High speed 8 bit DAC */ } else @@ -426,8 +443,8 @@ else { DISABLE_INTR (flags); - if (sb_dsp_command (0x14))/* - * 8-bit DAC (DMA) + if (sb_dsp_command (0x14)) /* + * 8-bit DAC (DMA) */ { sb_dsp_command ((unsigned char) (count & 0xff)); @@ -463,14 +480,14 @@ if (sb_dsp_highspeed) { DISABLE_INTR (flags); - if (sb_dsp_command (0x48))/* - * High speed size + if (sb_dsp_command (0x48)) /* + * High speed size */ { sb_dsp_command ((unsigned char) (count & 0xff)); sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); - sb_dsp_command (0x99);/* - * High speed 8 bit ADC + sb_dsp_command (0x99); /* + * High speed 8 bit ADC */ } else @@ -480,8 +497,8 @@ else { DISABLE_INTR (flags); - if (sb_dsp_command (0x24))/* - * 8-bit ADC (DMA) + if (sb_dsp_command (0x24)) /* + * 8-bit ADC (DMA) */ { sb_dsp_command ((unsigned char) (count & 0xff)); @@ -511,11 +528,23 @@ * SB Pro */ { +#ifdef JAZZ16 + /* Select correct dma channel + * for 16/8 bit acccess + */ + audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8; + if (dsp_stereo) + sb_dsp_command (dsp_16bit ? 0xac : 0xa8); + else + sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); +#else + /* 8 bit only cards use this + */ if (dsp_stereo) sb_dsp_command (0xa8); else sb_dsp_command (0xa0); - +#endif dsp_speed (dsp_current_speed); /* * Speed must be recalculated if * #channels * changes @@ -535,7 +564,19 @@ * SB Pro */ { +#ifdef JAZZ16 + /* 16 bit specific instructions + */ + audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8; + if (Jazz16_detected != 2) /* SM Wave */ + sb_mixer_set_stereo (dsp_stereo); + if (dsp_stereo) + sb_dsp_command (dsp_16bit ? 0xac : 0xa8); + else + sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); +#else sb_mixer_set_stereo (dsp_stereo); +#endif dsp_speed (dsp_current_speed); /* * Speed must be recalculated if * #channels * changes @@ -597,6 +638,12 @@ return RET_ERROR (ENXIO); } + if (sb_no_recording && mode & OPEN_READ) + { + printk ("SB Error: Recording not supported by this device\n"); + return RET_ERROR (ENOTTY); + } + if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI)) { printk ("SB: PCM not possible during MIDI input\n"); @@ -616,12 +663,32 @@ if (retval) return retval; + /* Allocate 8 bit dma + */ +#ifdef JAZZ16 + audio_devs[my_dev]->dmachan = dma8; +#endif + if (DMAbuf_open_dma (dev) < 0) { sb_free_irq (); printk ("SB: DMA Busy\n"); return RET_ERROR (EBUSY); } +#ifdef JAZZ16 + /* Allocate 16 bit dma + */ + if (Jazz16_detected != 0) + if (dma16 != dma8) + { + if (ALLOC_DMA_CHN (dma16, "Jazz16 16 bit")) + { + sb_free_irq (); + DMAbuf_close_dma (dev); + return RET_ERROR (EBUSY); + } + } +#endif sb_irq_mode = IMODE_NONE; @@ -634,6 +701,19 @@ static void sb_dsp_close (int dev) { +#ifdef JAZZ16 + /* Release 16 bit dma channel + */ + if (Jazz16_detected) + { + if (audio_devs[my_dev]->dmachan == dma8) + RELEASE_DMA_CHN (dma16); + else + RELEASE_DMA_CHN (dma8); + + } +#endif + DMAbuf_close_dma (dev); sb_free_irq (); dsp_cleanup (); @@ -643,6 +723,32 @@ open_mode = 0; } +#ifdef JAZZ16 +/* Function dsp_set_bits() only required for 16 bit cards + */ +static int +dsp_set_bits (int arg) +{ + if (arg) + if (Jazz16_detected == 0) + dsp_16bit = 0; + else + switch (arg) + { + case 8: + dsp_16bit = 0; + break; + case 16: + dsp_16bit = 1; + break; + default: + dsp_16bit = 0; + } + return dsp_16bit ? 16 : 8; +} + +#endif /* ifdef JAZZ16 */ + static int sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) { @@ -678,14 +784,31 @@ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg))); break; +#ifdef JAZZ16 + /* Word size specific cases here. + * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS + */ + case SNDCTL_DSP_SETFMT: + if (local) + return dsp_set_bits (arg); + return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg))); + break; + + case SOUND_PCM_READ_BITS: + if (local) + return dsp_16bit ? 16 : 8; + return IOCTL_OUT (arg, dsp_16bit ? 16 : 8); + break; +#else case SOUND_PCM_WRITE_BITS: case SOUND_PCM_READ_BITS: if (local) return 8; - return IOCTL_OUT (arg, 8);/* - * Only 8 bits/sample supported + return IOCTL_OUT (arg, 8); /* + * Only 8 bits/sample supported */ break; +#endif /* ifdef JAZZ16 */ case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: @@ -715,6 +838,232 @@ #endif + +#ifdef JAZZ16 + +/* + * Initialization of a Media Vision ProSonic 16 Soundcard. + * The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets + * the base address, the DMA-channels, interrupts and enables the joystickport. + * + * Also used by Jazz 16 (same card, different name) + * + * written 1994 by Rainer Vranken + * E-Mail: rvranken@polaris.informatik.uni-essen.de + */ + + +#ifndef MPU_BASE /* take default values if not specified */ +#define MPU_BASE 0x330 +#endif +#ifndef MPU_IRQ +#define MPU_IRQ 9 +#endif + +unsigned int +get_sb_byte (void) +{ + int i; + + for (i = 1000; i; i--) + if (INB (DSP_DATA_AVAIL) & 0x80) + { + return INB (DSP_READ); + } + + return 0xffff; +} + +#ifdef SM_WAVE +/* + * Logitech Soundman Wave detection and initialization by Hannu Savolainen. + * + * There is a microcontroller (8031) in the SM Wave card for MIDI emulation. + * it's located at address MPU_BASE+4. MPU_BASE+7 is a SM Wave specific + * control register for MC reset, SCSI, OPL4 and DSP (future expansion) + * address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16 + * based soundcard. + */ + +static void +smw_putmem (int base, int addr, unsigned char val) +{ + unsigned long flags; + + DISABLE_INTR (flags); + + OUTB (addr & 0xff, base + 1); /* Low address bits */ + OUTB (addr >> 8, base + 2); /* High address bits */ + OUTB (val, base); /* Data */ + + RESTORE_INTR (flags); +} + +static unsigned char +smw_getmem (int base, int addr) +{ + unsigned long flags; + unsigned char val; + + DISABLE_INTR (flags); + + OUTB (addr & 0xff, base + 1); /* Low address bits */ + OUTB (addr >> 8, base + 2); /* High address bits */ + val = INB (base); /* Data */ + + RESTORE_INTR (flags); + return val; +} + +static int +initialize_smw (void) +{ +#ifdef SMW_MIDI0001_INCLUDED +#include "smw-midi0001.h" +#else + unsigned char smw_ucode[1]; + int smw_ucodeLen = 0; + +#endif + + int mp_base = MPU_BASE + 4; /* Microcontroller base */ + int i; + unsigned char control; + + /* + * Reset the microcontroller so that the RAM can be accessed + */ + + control = INB (MPU_BASE + 7); + OUTB (control | 3, MPU_BASE + 7); /* Set last two bits to 1 (?) */ + OUTB ((control & 0xfe) | 2, MPU_BASE + 7); /* xxxxxxx0 resets the mc */ + + for (i = 0; i < 300; i++) /* Wait at least 1ms */ + tenmicrosec (); + + OUTB (control & 0xfc, MPU_BASE + 7); /* xxxxxx00 enables RAM */ + + /* + * Detect microcontroller by probing the 8k RAM area + */ + smw_putmem (mp_base, 0, 0x00); + smw_putmem (mp_base, 1, 0xff); + tenmicrosec (); + + if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff) + { + printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", + smw_getmem (mp_base, 0), smw_getmem (mp_base, 1)); + return 0; /* No RAM */ + } + + /* + * There is RAM so assume it's really a SM Wave + */ + +#ifdef SMW_MIDI0001_INCLUDED + if (smw_ucodeLen != 8192) + { + printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); + return 1; + } +#endif + + /* + * Download microcode + */ + + for (i = 0; i < 8192; i++) + smw_putmem (mp_base, i, smw_ucode[i]); + + /* + * Verify microcode + */ + + for (i = 0; i < 8192; i++) + if (smw_getmem (mp_base, i) != smw_ucode[i]) + { + printk ("SM Wave: Microcode verification failed\n"); + return 0; + } + + control = 0; +#ifdef SMW_SCSI_IRQ + /* + * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt + * is disabled by default. + * + * Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10. + */ + { + static unsigned char scsi_irq_bits[] = + {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; + + control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; + } +#endif + +#ifdef SMW_OPL4_ENABLE + /* + * Make the OPL4 chip visible on the PC bus at 0x380. + * + * There is no need to enable this feature since VoxWare + * doesn't support OPL4 yet. Also there is no RAM in SM Wave so + * enabling OPL4 is pretty useless. + */ + control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ + /* control |= 0x20; Uncomment this if you want to use IRQ7 */ +#endif + + OUTB (control | 0x03, MPU_BASE + 7); /* xxxxxx11 restarts */ + return 1; +} + +#endif + +static int +initialize_ProSonic16 (void) +{ + int x; + static unsigned char int_translat[16] = + {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] = + {0, 1, 0, 2, 0, 3, 0, 4}; + + OUTB (0xAF, 0x201); /* ProSonic/Jazz16 wakeup */ + for (x = 0; x < 1000; ++x) /* wait 10 milliseconds */ + tenmicrosec (); + OUTB (0x50, 0x201); + OUTB ((sbc_base & 0x70) | ((MPU_BASE & 0x30) >> 4), 0x201); + + if (sb_reset_dsp ()) + { /* OK. We have at least a SB */ + + /* Check the version number of ProSonic (I guess) */ + + if (!sb_dsp_command (0xFA)) + return 1; + if (get_sb_byte () != 0x12) + return 1; + + if (sb_dsp_command (0xFB) && /* set DMA-channels and Interrupts */ + sb_dsp_command ((dma_translat[JAZZ_DMA16] << 4) | dma_translat[SBC_DMA]) && + sb_dsp_command ((int_translat[MPU_IRQ] << 4) | int_translat[sbc_irq])) + { + Jazz16_detected = 1; +#ifdef SM_WAVE + if (initialize_smw ()) + Jazz16_detected = 2; +#endif + sb_dsp_disable_midi (); + } + + return 1; /* There was at least a SB */ + } + return 0; /* No SB or ProSonic16 detected */ +} + +#endif /* ifdef JAZZ16 */ + int sb_dsp_detect (struct address_info *hw_config) { @@ -725,9 +1074,16 @@ return 0; /* * Already initialized */ +#ifdef JAZZ16 + dma8 = hw_config->dma; + dma16 = JAZZ_DMA16; + if (!initialize_ProSonic16 ()) + return 0; +#else if (!sb_reset_dsp ()) return 0; +#endif return 1; /* * Detected @@ -792,6 +1148,9 @@ #ifndef EXCLUDE_SBPRO if (sbc_major >= 3) mixer_type = sb_mixer_init (sbc_major); +#else + if (sbc_major >= 3) + printk ("\n\n\n\nNOTE! SB Pro support is required with your soundcard!\n\n\n"); #endif #ifndef EXCLUDE_YM3812 @@ -801,31 +1160,42 @@ enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH); #endif +#ifndef EXCLUDE_AUDIO if (sbc_major >= 3) { -#if !defined(SCO) && !defined(EXCLUDE_AUDIO) -# ifdef __SGNXPRO__ + if (Jazz16_detected) + { + if (Jazz16_detected == 2) + sprintf (sb_dsp_operations.name, "SoundMan Wave %d.%d", sbc_major, sbc_minor); + else + sprintf (sb_dsp_operations.name, "MV Jazz16 %d.%d", sbc_major, sbc_minor); + sb_dsp_operations.format_mask |= AFMT_S16_LE; /* Hurrah, 16 bits */ + } + else +#ifdef __SGNXPRO__ if (mixer_type == 2) { sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor); } else -# endif +#endif + + if (sbc_major == 4) + { + sprintf (sb_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); + } + else { sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor); } -#endif } else { -#ifndef SCO sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor); -#endif } printk (" <%s>", sb_dsp_operations.name); -#ifndef EXCLUDE_AUDIO #if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO) if (!sb16) /* * There is a better driver for SB16 @@ -840,6 +1210,8 @@ } else printk ("SB: Too many DSP devices available\n"); +#else + printk (" "); #endif #ifndef EXCLUDE_MIDI diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c --- v1.3.8/linux/drivers/sound/sb_midi.c Fri Aug 19 08:54:09 1994 +++ linux/drivers/sound/sb_midi.c Mon Jul 10 01:45:18 1995 @@ -42,7 +42,7 @@ * future version of this driver. */ -extern int sb_dsp_ok; /* Set to 1 after successful initialization */ +extern int sb_dsp_ok; /* Set to 1 atfer successful initialization */ extern int sbc_base; extern int sb_midi_mode; @@ -217,6 +217,7 @@ { {"SoundBlaster", 0, 0, SNDCARD_SB}, &std_midi_synth, + {0}, sb_midi_open, sb_midi_close, sb_midi_ioctl, diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v1.3.8/linux/drivers/sound/sb_mixer.c Wed Jul 20 15:00:55 1994 +++ linux/drivers/sound/sb_mixer.c Mon Jul 10 01:45:19 1995 @@ -27,8 +27,8 @@ * SUCH DAMAGE. * * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support the Sound Galaxy NX Pro mixer. + * Hunyue Yau Jan 6 1994 + * Added code to support the Sound Galaxy NX Pro mixer. * */ @@ -42,6 +42,7 @@ #undef SB_TEST_IRQ extern int sbc_base; +extern int Jazz16_detected; static int mixer_initialized = 0; @@ -97,9 +98,9 @@ /* * Returns: - * 0 No mixer detected. - * 1 Only a plain Sound Blaster Pro style mixer detected. - * 2 The Sound Galaxy NX Pro mixer detected. + * 0 No mixer detected. + * 1 Only a plain Sound Blaster Pro style mixer detected. + * 2 The Sound Galaxy NX Pro mixer detected. */ static int detect_mixer (void) @@ -109,6 +110,7 @@ #endif int retcode = 1; + extern int sbc_major; /* * Detect the mixer by changing parameters of two volume channels. If the @@ -127,8 +129,8 @@ #ifdef __SGNXPRO__ /* Attempt to detect the SG NX Pro by check for valid bass/treble - * registers. - */ + * registers. + */ oldbass = sb_getmixer (BASS_LVL); oldtreble = sb_getmixer (TREBLE_LVL); @@ -147,6 +149,21 @@ */ sb_setmixer (BASS_LVL, oldbass); sb_setmixer (TREBLE_LVL, oldtreble); + + /* + * If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16. + * In this case it's good idea to disable the Disney Sound Source + * compatibility mode. It's useless and just causes noise every time the + * LPT-port is accessed. + * + * Also place the card into WSS mode. + */ + if (sbc_major == 3) + { + OUTB (0x01, sbc_base + 0x1c); + OUTB (0x00, sbc_base + 0x1a); + } + #endif return retcode; } @@ -181,6 +198,100 @@ return levels[dev]; } +#ifdef JAZZ16 +static char smw_mix_regs[] = /* Left mixer registers */ +{ + 0x0b, /* SOUND_MIXER_VOLUME */ + 0x0d, /* SOUND_MIXER_BASS */ + 0x0d, /* SOUND_MIXER_TREBLE */ + 0x05, /* SOUND_MIXER_SYNTH */ + 0x09, /* SOUND_MIXER_PCM */ + 0x00, /* SOUND_MIXER_SPEAKER */ + 0x03, /* SOUND_MIXER_LINE */ + 0x01, /* SOUND_MIXER_MIC */ + 0x07, /* SOUND_MIXER_CD */ + 0x00, /* SOUND_MIXER_IMIX */ + 0x00, /* SOUND_MIXER_ALTPCM */ + 0x00, /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_IGAIN */ + 0x00, /* SOUND_MIXER_OGAIN */ + 0x00, /* SOUND_MIXER_LINE1 */ + 0x00, /* SOUND_MIXER_LINE2 */ + 0x00 /* SOUND_MIXER_LINE3 */ +}; + +static void +smw_mixer_init (void) +{ + int i; + + sb_setmixer (0x00, 0x18); /* Mute unused (Telephone) line */ + sb_setmixer (0x10, 0x38); /* Config register 2 */ + + supported_devices = 0; + for (i = 0; i < sizeof (smw_mix_regs); i++) + if (smw_mix_regs[i] != 0) + supported_devices |= (1 << i); + + supported_rec_devices = supported_devices & + ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | + SOUND_MASK_VOLUME); +} + +static int +smw_mixer_set (int dev, int value) +{ + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int reg, val; + + if (left > 100) + left = 100; + if (right > 100) + right = 100; + + if (dev > 31) + return RET_ERROR (EINVAL); + + if (!(supported_devices & (1 << dev))) /* Not supported */ + return RET_ERROR (EINVAL); + + switch (dev) + { + case SOUND_MIXER_VOLUME: + sb_setmixer (0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ + sb_setmixer (0x0c, 96 - (96 * right / 100)); + break; + + case SOUND_MIXER_BASS: + case SOUND_MIXER_TREBLE: + levels[dev] = left | (right << 8); + + /* Set left bass and treble values */ + val = ((levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / 100) << 4; + val |= ((levels[SOUND_MIXER_BASS] & 0xff) * 16 / 100) & 0x0f; + sb_setmixer (0x0d, val); + + /* Set right bass and treble values */ + val = (((levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / 100) << 4; + val |= (((levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / 100) & 0x0f; + sb_setmixer (0x0e, val); + break; + + default: + reg = smw_mix_regs[dev]; + if (reg == 0) + return RET_ERROR (EINVAL); + sb_setmixer (reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ + sb_setmixer (reg + 1, (24 - (24 * right / 100)) | 0x40); + } + + levels[dev] = left | (right << 8); + return left | (right << 8); +} + +#endif + static int sb_mixer_set (int dev, int value) { @@ -190,6 +301,11 @@ int regoffs; unsigned char val; +#ifdef JAZZ16 + if (Jazz16_detected == 2) + return smw_mixer_set (dev, value); +#endif + if (left > 100) left = 100; if (right > 100) @@ -233,6 +349,7 @@ } change_bits (&val, dev, RIGHT_CHN, right); + sb_setmixer (regoffs, val); levels[dev] = left | (right << 8); @@ -337,6 +454,7 @@ break; default: + return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg))); } else @@ -354,8 +472,11 @@ break; case SOUND_MIXER_STEREODEVS: - return IOCTL_OUT (arg, supported_devices & - ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + if (Jazz16_detected) + return IOCTL_OUT (arg, supported_devices); + else + return IOCTL_OUT (arg, supported_devices & + ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); break; case SOUND_MIXER_RECMASK: @@ -376,6 +497,7 @@ static struct mixer_operations sb_mixer_operations = { + "SoundBlaster", sb_mixer_ioctl }; @@ -414,6 +536,18 @@ { case 3: mixer_caps = SOUND_CAP_EXCL_INPUT; + +#ifdef JAZZ16 + if (Jazz16_detected == 2) /* SM Wave */ + { + supported_devices = 0; + supported_rec_devices = 0; + iomap = &sbpro_mix; + smw_mixer_init (); + mixer_type = 1; + } + else +#endif #ifdef __SGNXPRO__ if (mixer_type == 2) /* A SGNXPRO was detected */ { diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v1.3.8/linux/drivers/sound/sb_mixer.h Wed Jul 20 15:00:55 1994 +++ linux/drivers/sound/sb_mixer.h Thu Apr 27 22:21:53 1995 @@ -51,7 +51,8 @@ SOUND_MASK_CD) #define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_RECLEV | \ + SOUND_MASK_CD | \ + SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE) /* @@ -144,7 +145,9 @@ MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) +MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) }; #endif @@ -160,23 +163,51 @@ MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5), MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2) +MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */ +MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2), +MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) }; +#ifdef SM_GAMES /* Master volume is lower and PCM & FM volumes + higher than with SB Pro. This improves the + sound quality */ + +static unsigned short levels[SOUND_MIXER_NRDEVICES] = +{ + 0x2020, /* Master Volume */ + 0x4b4b, /* Bass */ + 0x4b4b, /* Treble */ + 0x6464, /* FM */ + 0x6464, /* PCM */ + 0x4b4b, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x0000, /* Mic */ + 0x4b4b, /* CD */ + 0x4b4b, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x4b4b, /* Recording level */ + 0x4b4b, /* Input gain */ + 0x4b4b}; /* Output gain */ + +#else /* If the user selected just plain SB Pro */ + static unsigned short levels[SOUND_MIXER_NRDEVICES] = { 0x5a5a, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ + 0x4b4b, /* Bass */ + 0x4b4b, /* Treble */ 0x4b4b, /* FM */ 0x4b4b, /* PCM */ 0x4b4b, /* PC Speaker */ 0x4b4b, /* Ext Line */ - 0x0000, /* Mic */ + 0x1010, /* Mic */ 0x4b4b, /* CD */ 0x4b4b, /* Recording monitor */ 0x4b4b, /* SB PCM */ - 0x4b4b}; /* Recording level */ + 0x4b4b, /* Recording level */ + 0x4b4b, /* Input gain */ + 0x4b4b}; /* Output gain */ +#endif /* SM_GAMES */ static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = { @@ -191,7 +222,9 @@ 0x04, /* SOUND_MIXER_CD */ 0x00, /* SOUND_MIXER_IMIX */ 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00 /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_IGAIN */ + 0x00 /* SOUND_MIXER_OGAIN */ }; static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = @@ -207,7 +240,9 @@ 0x02, /* SOUND_MIXER_CD */ 0x00, /* SOUND_MIXER_IMIX */ 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00 /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_IGAIN */ + 0x00 /* SOUND_MIXER_OGAIN */ }; /* diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v1.3.8/linux/drivers/sound/sequencer.c Fri Aug 19 08:54:10 1994 +++ linux/drivers/sound/sequencer.c Mon Jul 10 01:45:20 1995 @@ -29,6 +29,7 @@ #define SEQUENCER_C #include "sound_config.h" +#include "midi_ctrl.h" #ifdef CONFIGURE_SOUNDCARD @@ -49,7 +50,7 @@ /* * The seq_mode gives the operating mode of the sequencer: * 1 = level1 (the default) - * 2 = level2 (extended capabilities) + * 2 = level2 (extended capabilites) */ #define SEQ_1 1 @@ -83,7 +84,7 @@ static int pre_event_timeout; static unsigned synth_open_mask; -static int seq_queue (unsigned char *note); +static int seq_queue (unsigned char *note, char nonblock); static void seq_startplay (void); static int seq_sync (void); static void seq_reset (void); @@ -113,6 +114,12 @@ DISABLE_INTR (flags); if (!iqlen) { + if (ISSET_FILE_FLAG (file, O_NONBLOCK)) + { + RESTORE_INTR (flags); + return RET_ERROR (EAGAIN); + } + DO_SLEEP (midi_sleeper, midi_sleep_flag, pre_event_timeout); if (!iqlen) @@ -151,8 +158,8 @@ unsigned long flags; /* - * Verify that the len is valid for the current mode. - */ + * Verify that the len is valid for the current mode. + */ if (len != 4 && len != 8) return; @@ -331,12 +338,17 @@ } - if (!seq_queue (event)) + if (!seq_queue (event, ISSET_FILE_FLAG (file, O_NONBLOCK))) { + int processed = count - c; if (!seq_playing) seq_startplay (); - return count - c; + + if (!processed && ISSET_FILE_FLAG (file, O_NONBLOCK)) + return RET_ERROR (EAGAIN); + else + return processed; } p += ev_size; @@ -346,11 +358,13 @@ if (!seq_playing) seq_startplay (); - return count; + return count; /* This will "eat" chunks shorter than 4 bytes (if written + * alone) Should we really do that ? + */ } static int -seq_queue (unsigned char *note) +seq_queue (unsigned char *note, char nonblock) { /* @@ -363,7 +377,7 @@ * Give chance to drain the queue */ - if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + if (!nonblock && qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { /* * Sleep until there is enough space on the queue @@ -372,10 +386,11 @@ } if (qlen >= SEQ_MAX_QUEUE) - return 0; /* + { + return 0; /* * To be sure */ - + } memcpy (&queue[qtail * EV_SZ], note, EV_SZ); qtail = (qtail + 1) % SEQ_MAX_QUEUE; @@ -462,6 +477,8 @@ voice = synth_devs[dev]->alloc_voice (dev, chn, note, &synth_devs[dev]->alloc); synth_devs[dev]->alloc.map[voice] = key; + synth_devs[dev]->alloc.alloc_times[voice] = + synth_devs[dev]->alloc.timestamp++; return voice; } @@ -485,33 +502,47 @@ if (seq_mode == SEQ_2) { if (synth_devs[dev]->alloc_voice) - voice = find_voice (dev, chn, note); + voice = find_voice (dev, chn, note); if (cmd == MIDI_NOTEON && parm == 0) - { - cmd = MIDI_NOTEOFF; - parm = 64; - } + { + cmd = MIDI_NOTEOFF; + parm = 64; + } } switch (cmd) { case MIDI_NOTEON: - if (note > 127 && note != 255) + if (note > 127 && note != 255) /* Not a seq2 feature */ return; if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) - { + { /* Internal synthesizer (FM, GUS, etc) */ voice = alloc_voice (dev, chn, note); } if (voice == -1) voice = chn; + if (seq_mode == SEQ_2 && dev < num_synths) + { + /* + * The MIDI channel 10 is a percussive channel. Use the note + * number to select the proper patch (128 to 255) to play. + */ + + if (chn == 9) + { + synth_devs[dev]->set_instr (dev, voice, 128 + note); + note = 60; /* Middle C */ + + } + } + if (seq_mode == SEQ_2) { - synth_devs[dev]->set_instr (dev, voice, - synth_devs[dev]->chn_info[chn].pgm_num); + synth_devs[dev]->setup_voice (dev, voice, chn); } synth_devs[dev]->start_note (dev, voice, note, parm); @@ -524,7 +555,9 @@ break; case MIDI_KEY_PRESSURE: - /* To be implemented */ + if (voice == -1) + voice = chn; + synth_devs[dev]->aftertouch (dev, voice, parm); break; default:; @@ -555,33 +588,27 @@ if (seq_mode == SEQ_2) { synth_devs[dev]->chn_info[chn].pgm_num = p1; + if (dev >= num_synths) + synth_devs[dev]->set_instr (dev, chn, p1); } else synth_devs[dev]->set_instr (dev, chn, p1); + break; case MIDI_CTL_CHANGE: - if (p1 == CTRL_MAIN_VOLUME) - { - w14 = (unsigned short) (((int) w14 * 16383) / 100); - p1 = CTL_MAIN_VOLUME; - } - if (p1 == CTRL_EXPRESSION) - { - w14 *= 128; - p1 = CTL_EXPRESSION; - } if (seq_mode == SEQ_2) { if (chn > 15 || p1 > 127) break; - synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0xff; + synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; if (dev < num_synths) { - int val = w14 & 0xff; + int val = w14 & 0x7f; + int i, key; if (p1 < 64) /* Combine MSB and LSB */ { @@ -591,20 +618,42 @@ chn_info[chn].controllers[p1 | 32] & 0x7f); p1 &= ~32; } - else - val = synth_devs[dev]->chn_info[chn].controllers[p1]; - synth_devs[dev]->controller (dev, chn, p1, val); + /* Handle all playing notes on this channel */ + + key = (chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->controller (dev, i, p1, val); } else synth_devs[dev]->controller (dev, chn, p1, w14); } - else + else /* Mode 1 */ synth_devs[dev]->controller (dev, chn, p1, w14); break; case MIDI_PITCH_BEND: - synth_devs[dev]->bender (dev, chn, w14); + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].bender_value = w14; + + if (dev < num_synths) + { /* Handle all playing notes on this channel */ + int i, key; + + key = (chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->bender (dev, i, w14); + } + else + synth_devs[dev]->bender (dev, chn, w14); + } + else /* MODE 1 */ + synth_devs[dev]->bender (dev, chn, w14); break; default:; @@ -644,9 +693,9 @@ parm += prev_event_time; /* - * NOTE! No break here. Execution of TMR_WAIT_REL continues in the - * next case (TMR_WAIT_ABS) - */ + * NOTE! No break here. Execution of TMR_WAIT_REL continues in the + * next case (TMR_WAIT_ABS) + */ case TMR_WAIT_ABS: if (parm > 0) @@ -714,151 +763,170 @@ printk ("seq_local_event() called. WHY????????\n"); } -static void -seq_startplay (void) +static int +play_event (unsigned char *q) { - int this_one; + /* + * NOTE! This routine returns + * 0 = normal event played. + * 1 = Timer armed. Suspend playback until timer callback. + * 2 = MIDI output buffer full. Restore queue and suspend until timer + */ unsigned long *delay; - unsigned char *q; - while (qlen > 0) + switch (q[0]) { + case SEQ_NOTEOFF: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->kill_note (0, q[1], 255, q[3]); + break; - seq_playing = 1; - - qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; - qlen--; - - q = &queue[this_one * EV_SZ]; - - switch (q[0]) - { - case SEQ_NOTEOFF: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->kill_note (0, q[1], 255, q[3]); - break; - - case SEQ_NOTEON: - if (q[4] < 128 || q[4] == 255) - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->start_note (0, q[1], q[2], q[3]); - break; + case SEQ_NOTEON: + if (q[4] < 128 || q[4] == 255) + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->start_note (0, q[1], q[2], q[3]); + break; - case SEQ_WAIT: - delay = (unsigned long *) q; /* + case SEQ_WAIT: + delay = (unsigned long *) q; /* * Bytes 1 to 3 are containing the * * delay in GET_TIME() */ - *delay = (*delay >> 8) & 0xffffff; + *delay = (*delay >> 8) & 0xffffff; - if (*delay > 0) - { - long time; + if (*delay > 0) + { + long time; - seq_playing = 1; - time = *delay; - prev_event_time = time; + seq_playing = 1; + time = *delay; + prev_event_time = time; - request_sound_timer (time); + request_sound_timer (time); - if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) - { - unsigned long flags; + if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + { + unsigned long flags; - DISABLE_INTR (flags); - if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) - { - WAKE_UP (seq_sleeper, seq_sleep_flag); - } - RESTORE_INTR (flags); + DISABLE_INTR (flags); + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + { + WAKE_UP (seq_sleeper, seq_sleep_flag); } - /* - * The timer is now active and will reinvoke this function - * after the timer expires. Return to the caller now. - */ - return; + RESTORE_INTR (flags); } - break; + /* + * The timer is now active and will reinvoke this function + * after the timer expires. Return to the caller now. + */ + return 1; + } + break; + + case SEQ_PGMCHANGE: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->set_instr (0, q[1], q[2]); + break; - case SEQ_PGMCHANGE: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->set_instr (0, q[1], q[2]); - break; - - case SEQ_SYNCTIMER: /* - * Reset timer - */ - seq_time = GET_TIME (); - prev_input_time = 0; - prev_event_time = 0; - break; + case SEQ_SYNCTIMER: /* + * Reset timer + */ + seq_time = GET_TIME (); + prev_input_time = 0; + prev_event_time = 0; + break; - case SEQ_MIDIPUTC: /* + case SEQ_MIDIPUTC: /* * Put a midi character */ - if (midi_opened[q[2]]) - { - int dev; + if (midi_opened[q[2]]) + { + int dev; - dev = q[2]; + dev = q[2]; - if (!midi_devs[dev]->putc (dev, q[1])) - { - /* - * Output FIFO is full. Wait one timer cycle and try again. - */ - - qlen++; - qhead = this_one; /* - * Restore queue - */ - seq_playing = 1; - request_sound_timer (-1); - return; - } - else - midi_written[dev] = 1; + if (!midi_devs[dev]->putc (dev, q[1])) + { + /* + * Output FIFO is full. Wait one timer cycle and try again. + */ + + seq_playing = 1; + request_sound_timer (-1); + return 2; } - break; + else + midi_written[dev] = 1; + } + break; - case SEQ_ECHO: - seq_copy_to_input (q, 4); /* - * Echo back to the process - */ - break; + case SEQ_ECHO: + seq_copy_to_input (q, 4); /* + * Echo back to the process + */ + break; - case SEQ_PRIVATE: - if ((int) q[1] < max_synthdev) - synth_devs[q[1]]->hw_control (q[1], q); - break; - - case SEQ_EXTENDED: - extended_event (q); - break; - - case EV_CHN_VOICE: - seq_chn_voice_event (q); - break; - - case EV_CHN_COMMON: - seq_chn_common_event (q); - break; + case SEQ_PRIVATE: + if ((int) q[1] < max_synthdev) + synth_devs[q[1]]->hw_control (q[1], q); + break; - case EV_TIMING: - if (seq_timing_event (q) == TIMER_ARMED) - { - return; - } - break; + case SEQ_EXTENDED: + extended_event (q); + break; - case EV_SEQ_LOCAL: - seq_local_event (q); - break; + case EV_CHN_VOICE: + seq_chn_voice_event (q); + break; + + case EV_CHN_COMMON: + seq_chn_common_event (q); + break; - default:; + case EV_TIMING: + if (seq_timing_event (q) == TIMER_ARMED) + { + return 1; + } + break; + + case EV_SEQ_LOCAL: + seq_local_event (q); + break; + + default:; + } + + return 0; +} + +static void +seq_startplay (void) +{ + unsigned long flags; + int this_one, action; + + while (qlen > 0) + { + + DISABLE_INTR (flags); + qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; + qlen--; + RESTORE_INTR (flags); + + seq_playing = 1; + + if ((action = play_event (&queue[this_one * EV_SZ]))) + { /* Suspend playback. Next timer routine invokes this routine again */ + if (action == 2) + { + qlen++; + qhead = this_one; + } + return; } } @@ -876,13 +944,11 @@ } RESTORE_INTR (flags); } - } static void reset_controllers (int dev, unsigned char *controller, int update_dev) { -#include "midi_ctrl.h" int i; @@ -914,6 +980,7 @@ reset_controllers (dev, synth_devs[dev]->chn_info[chn].controllers, 0); + synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ } } @@ -998,7 +1065,6 @@ if (level == 2) { - printk ("Using timer #%d\n", tmr_no); if (tmr == NULL) { printk ("sequencer: No timer for level 2\n"); @@ -1035,7 +1101,7 @@ { printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); if (synth_devs[i]->midi_dev) - printk ("(Maps to midi dev #%d\n", synth_devs[i]->midi_dev); + printk ("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); } else { @@ -1091,7 +1157,7 @@ n = 1; - while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n) + while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && n) { n = 0; @@ -1132,10 +1198,10 @@ } /* - * * Wait until the queue is empty + * * Wait until the queue is empty (if we don't have nonblock) */ - if (mode != OPEN_READ) + if (mode != OPEN_READ && !ISSET_FILE_FLAG (file, O_NONBLOCK)) while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen) { seq_sync (); @@ -1180,16 +1246,17 @@ static int seq_sync (void) { + unsigned long flags; + if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag)) seq_startplay (); - if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* - * Queue not - * empty - */ + DISABLE_INTR (flags); + if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); } + RESTORE_INTR (flags); return qlen; } @@ -1202,26 +1269,23 @@ */ int n; + unsigned long flags; /* * This routine sends one byte to the Midi channel. - */ - /* * If the output Fifo is full, it waits until there - */ - /* * is space in the queue */ - n = 300; /* - * Timeout in jiffies - */ + n = 3 * HZ; /* Timeout */ + DISABLE_INTR (flags); while (n && !midi_devs[dev]->putc (dev, data)) { DO_SLEEP (seq_sleeper, seq_sleep_flag, 4); n--; } + RESTORE_INTR (flags); } static void @@ -1232,8 +1296,8 @@ */ int i; - int chn; + unsigned long flags; sound_stop_timer (); seq_time = GET_TIME (); @@ -1250,13 +1314,20 @@ if (seq_mode == SEQ_2) { - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - for (chn = 0; chn < 16; chn++) - synth_devs[i]->controller (i, chn, 0xfe, 0); /* All notes off */ + + for (chn = 0; chn < 16; chn++) + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + { + synth_devs[i]->controller (i, chn, 123, 0); /* All notes off */ + synth_devs[i]->controller (i, chn, 121, 0); /* Reset all ctl */ + synth_devs[i]->bender (i, chn, 1 << 13); /* Bender off */ + } + } else + /* seq_mode == SEQ_1 */ { for (i = 0; i < max_mididev; i++) if (midi_written[i]) /* @@ -1264,25 +1335,18 @@ */ { /* - * Sending just a ACTIVE SENSING message should be enough to stop all - * playing notes. Since there are devices not recognizing the - * active sensing, we have to send some all notes off messages also. - */ + * Sending just a ACTIVE SENSING message should be enough to stop all + * playing notes. Since there are devices not recognizing the + * active sensing, we have to send some all notes off messages also. + */ midi_outc (i, 0xfe); for (chn = 0; chn < 16; chn++) { midi_outc (i, - (unsigned char) (0xb0 + (chn & 0xff))); /* - * Channel - * msg - */ - midi_outc (i, 0x7b); /* - * All notes off - */ - midi_outc (i, 0); /* - * Dummy parameter - */ + (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ + midi_outc (i, 0x7b); /* All notes off */ + midi_outc (i, 0); /* Dummy parameter */ } midi_devs[i]->close (i); @@ -1294,8 +1358,13 @@ seq_playing = 0; + DISABLE_INTR (flags); if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) - printk ("Sequencer Warning: Unexpected sleeping process\n"); + { + /* printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ + WAKE_UP (seq_sleeper, seq_sleep_flag); + } + RESTORE_INTR (flags); } @@ -1303,22 +1372,22 @@ seq_panic (void) { /* - * This routine is called by the application in case the user - * wants to reset the system to the default state. - */ + * This routine is called by the application in case the user + * wants to reset the system to the default state. + */ seq_reset (); /* - * Since some of the devices don't recognize the active sensing and - * all notes off messages, we have to shut all notes manually. - * - * TO BE IMPLEMENTED LATER - */ + * Since some of the devices don't recognize the active sensing and + * all notes off messages, we have to shut all notes manually. + * + * TO BE IMPLEMENTED LATER + */ /* - * Also return the controllers to their default states - */ + * Also return the controllers to their default states + */ } int @@ -1523,6 +1592,21 @@ } break; + case SNDCTL_SEQ_OUTOFBAND: + { + struct seq_event_rec event; + unsigned long flags; + + IOCTL_FROM_USER ((char *) &event, (char *) arg, 0, sizeof (event)); + + DISABLE_INTR (flags); + play_event (event.arr); + RESTORE_INTR (flags); + + return 0; + } + break; + case SNDCTL_MIDI_INFO: { struct midi_info inf; @@ -1544,7 +1628,11 @@ struct patmgr_info *inf; int dev, err; - inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf)); + if ((inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf))) == NULL) + { + printk ("patmgr: Can't allocate memory for a message\n"); + return RET_ERROR (EIO); + } IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf)); dev = inf->device; @@ -1578,7 +1666,11 @@ struct patmgr_info *inf; int dev, err; - inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf)); + if ((inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf))) == NULL) + { + printk ("patmgr: Can't allocate memory for a message\n"); + return RET_ERROR (EIO); + } IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf)); dev = inf->device; @@ -1607,7 +1699,7 @@ } break; - case SNDCTL_SEQ_TRESHOLD: + case SNDCTL_SEQ_THRESHOLD: { int tmp = IOCTL_IN (arg); @@ -1669,26 +1761,30 @@ switch (sel_type) { case SEL_IN: + DISABLE_INTR (flags); if (!iqlen) { - DISABLE_INTR (flags); midi_sleep_flag.mode = WK_SLEEP; select_wait (&midi_sleeper, wait); RESTORE_INTR (flags); return 0; } + midi_sleep_flag.mode &= ~WK_SLEEP; + RESTORE_INTR (flags); return 1; break; case SEL_OUT: + DISABLE_INTR (flags); if (qlen >= SEQ_MAX_QUEUE) { - DISABLE_INTR (flags); seq_sleep_flag.mode = WK_SLEEP; select_wait (&seq_sleeper, wait); RESTORE_INTR (flags); return 0; } + seq_sleep_flag.mode &= ~WK_SLEEP; + RESTORE_INTR (flags); return 1; break; @@ -1852,11 +1948,14 @@ return mem_start; } +#ifdef ALLOW_SELECT int sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) { return RET_ERROR (EIO); } + +#endif #endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v1.3.8/linux/drivers/sound/sound_calls.h Fri Jan 20 10:24:13 1995 +++ linux/drivers/sound/sound_calls.h Mon Jun 12 15:47:27 1995 @@ -4,18 +4,21 @@ int DMAbuf_open(int dev, int mode); int DMAbuf_release(int dev, int mode); -int DMAbuf_getwrbuffer(int dev, char **buf, int *size); -int DMAbuf_getrdbuffer(int dev, char **buf, int *len); +int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock); +int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock); int DMAbuf_rmchars(int dev, int buff_no, int c); int DMAbuf_start_output(int dev, int buff_no, int l); int DMAbuf_ioctl(int dev, unsigned int cmd, unsigned int arg, int local); long DMAbuf_init(long mem_start); int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); -int DMAbuf_open_dma (int chan); -void DMAbuf_close_dma (int chan); -void DMAbuf_reset_dma (int chan); +int DMAbuf_open_dma (int dev); +void DMAbuf_close_dma (int dev); +void DMAbuf_reset_dma (int dev); void DMAbuf_inputintr(int dev); void DMAbuf_outputintr(int dev, int underflow_flag); +#ifdef ALLOW_SELECT +int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +#endif /* * System calls for /dev/dsp and /dev/audio @@ -30,6 +33,10 @@ int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig); long audio_init (long mem_start); +#ifdef ALLOW_SELECT +int audio_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +#endif + /* * System calls for the /dev/sequencer */ @@ -86,21 +93,13 @@ * Misc calls from various sources */ -/* From pro_midi.c */ - -long pro_midi_attach(long mem_start); -int pro_midi_open(int dev, int mode); -void pro_midi_close(int dev); -int pro_midi_write(int dev, snd_rw_buf *uio); -int pro_midi_read(int dev, snd_rw_buf *uio); - /* From soundcard.c */ long soundcard_init(long mem_start); void tenmicrosec(void); void request_sound_timer (int count); void sound_stop_timer(void); int snd_ioctl_return(int *addr, int value); -int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, struct pt_regs *)); +int snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO(), char *name); void snd_release_irq(int vect); void sound_dma_malloc(int dev); void sound_dma_free(int dev); @@ -123,7 +122,7 @@ int sb_reset_dsp (void); /* From sb16_dsp.c */ -void sb16_dsp_interrupt (int unused); +void sb16_dsp_interrupt (int irq); long sb16_dsp_init(long mem_start, struct address_info *hw_config); int sb16_dsp_detect(struct address_info *hw_config); @@ -177,7 +176,7 @@ long attach_gus_card(long mem_start, struct address_info * hw_config); int probe_gus(struct address_info *hw_config); int gus_set_midi_irq(int num); -void gusintr(int, struct pt_regs * regs); +void gusintr(INT_HANDLER_PARMS(irq, dummy)); long attach_gus_db16(long mem_start, struct address_info * hw_config); int probe_gus_db16(struct address_info *hw_config); @@ -198,6 +197,7 @@ /* From mpu401.c */ long attach_mpu401(long mem_start, struct address_info * hw_config); int probe_mpu401(struct address_info *hw_config); +void mpuintr(INT_HANDLER_PARMS(irq, dummy)); /* From uart6850.c */ long attach_uart6850(long mem_start, struct address_info * hw_config); @@ -225,13 +225,23 @@ /* From ad1848.c */ void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture); int ad1848_detect (int io_base); -void ad1848_interrupt (int dev, struct pt_regs *regs); +void ad1848_interrupt (INT_HANDLER_PARMS(irq, dummy)); long attach_ms_sound(long mem_start, struct address_info * hw_config); int probe_ms_sound(struct address_info *hw_config); /* From pss.c */ int probe_pss (struct address_info *hw_config); long attach_pss (long mem_start, struct address_info *hw_config); +int probe_pss_mpu (struct address_info *hw_config); +long attach_pss_mpu (long mem_start, struct address_info *hw_config); +int probe_pss_mss (struct address_info *hw_config); +long attach_pss_mss (long mem_start, struct address_info *hw_config); + +/* From sscape.c */ +int probe_sscape (struct address_info *hw_config); +long attach_sscape (long mem_start, struct address_info *hw_config); +int probe_ss_ms_sound (struct address_info *hw_config); +long attach_ss_ms_sound(long mem_start, struct address_info * hw_config); int pss_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); int pss_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); @@ -241,3 +251,25 @@ unsigned int cmd, unsigned int arg); int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig); long pss_init(long mem_start); + +/* From aedsp16.c */ +int InitAEDSP16_SBPRO(struct address_info *hw_config); +int InitAEDSP16_MSS(struct address_info *hw_config); +int InitAEDSP16_MPU401(struct address_info *hw_config); + +/* From midi_synth.c */ +void do_midi_msg (int synthno, unsigned char *msg, int mlen); + +/* From trix.c */ +long attach_trix_wss (long mem_start, struct address_info *hw_config); +int probe_trix_wss (struct address_info *hw_config); +long attach_trix_sb (long mem_start, struct address_info *hw_config); +int probe_trix_sb (struct address_info *hw_config); +long attach_trix_mpu (long mem_start, struct address_info *hw_config); +int probe_trix_mpu (struct address_info *hw_config); + +/* From mad16.c */ +long attach_mad16 (long mem_start, struct address_info *hw_config); +int probe_mad16 (struct address_info *hw_config); +long attach_mad16_mpu (long mem_start, struct address_info *hw_config); +int probe_mad16_mpu (struct address_info *hw_config); diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v1.3.8/linux/drivers/sound/sound_config.h Fri Aug 19 08:54:10 1994 +++ linux/drivers/sound/sound_config.h Wed Jul 5 22:37:12 1995 @@ -29,6 +29,13 @@ */ #include "local.h" +#include "os.h" +#include "soundvers.h" + +#if !defined(PSS_MPU_BASE) && defined(EXCLUDE_SSCAPE) && \ + defined(EXCLUDE_TRIX) && !defined(MAD16_MPU_BASE) +#define EXCLUDE_MPU_EMU +#endif #if defined(ISC) || defined(SCO) || defined(SVR42) #define GENERIC_SYSV @@ -38,10 +45,16 @@ * Disable the AD1848 driver if there are no other drivers requiring it. */ -#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX) +#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && \ + defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX) && \ + defined(EXCLUDE_SSCAPE) && defined(EXCLUDE_TRIX) && defined(EXCLUDE_MAD16) #define EXCLUDE_AD1848 #endif +#ifdef PSS_MSS_BASE +#undef EXCLUDE_AD1848 +#endif + #undef CONFIGURE_SOUNDCARD #undef DYNAMIC_BUFFER @@ -63,80 +76,6 @@ #ifdef CONFIGURE_SOUNDCARD -/* ****** IO-address, DMA and IRQ settings **** - -If your card has nonstandard I/O address or IRQ number, change defines - for the following settings in your kernel Makefile */ - -#ifndef SBC_BASE -#define SBC_BASE 0x220 /* 0x220 is the factory default. */ -#endif - -#ifndef SBC_IRQ -#define SBC_IRQ 7 /* IQR7 is the factory default. */ -#endif - -#ifndef SBC_DMA -#define SBC_DMA 1 -#endif - -#ifndef SB16_DMA -#define SB16_DMA 6 -#endif - -#ifndef SB16MIDI_BASE -#define SB16MIDI_BASE 0x300 -#endif - -#ifndef PAS_BASE -#define PAS_BASE 0x388 -#endif - -#ifndef PAS_IRQ -#define PAS_IRQ 5 -#endif - -#ifndef PAS_DMA -#define PAS_DMA 3 -#endif - -#ifndef GUS_BASE -#define GUS_BASE 0x220 -#endif - -#ifndef GUS_IRQ -#define GUS_IRQ 15 -#endif - -#ifndef GUS_MIDI_IRQ -#define GUS_MIDI_IRQ GUS_IRQ -#endif - -#ifndef GUS_DMA -#define GUS_DMA 6 -#endif - -#ifndef MPU_BASE -#define MPU_BASE 0x330 -#endif - -#ifndef MPU_IRQ -#define MPU_IRQ 6 -#endif - -/* Echo Personal Sound System */ -#ifndef PSS_BASE -#define PSS_BASE 0x220 /* 0x240 or */ -#endif - -#ifndef PSS_IRQ -#define PSS_IRQ 7 -#endif - -#ifndef PSS_DMA -#define PSS_DMA 1 -#endif - #ifndef MAX_REALTIME_FACTOR #define MAX_REALTIME_FACTOR 4 #endif @@ -190,7 +129,7 @@ #define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ #define SND_DEV_STATUS 6 /* /dev/sndstat */ /* #7 not in use now. Was in 2.4. Free for use after v3.0. */ -#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ +#define SND_DEV_SEQ2 8 /* /dev/sequecer, level 2 interface */ #define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ #define SND_DEV_PSS SND_DEV_SNDPROC @@ -200,19 +139,21 @@ #define OFF 0 #define MAX_AUDIO_DEV 5 -#define MAX_MIXER_DEV 2 +#define MAX_MIXER_DEV 5 #define MAX_SYNTH_DEV 3 #define MAX_MIDI_DEV 6 #define MAX_TIMER_DEV 3 struct fileinfo { - int mode; /* Open mode */ + int mode; /* Open mode */ + DECLARE_FILE(); /* Reference to file-flags. OS-dependent. */ }; struct address_info { int io_base; int irq; int dma; + int always_detect; /* 1=Trust me, it's there */ }; #define SYNTH_MAX_VOICES 32 @@ -222,10 +163,13 @@ int used_voices; int ptr; /* For device specific use */ unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */ + int timestamp; + int alloc_times[SYNTH_MAX_VOICES]; }; struct channel_info { int pgm_num; + int bender_value; unsigned char controllers[128]; }; @@ -242,17 +186,18 @@ #define OPEN_WRITE 2 #define OPEN_READWRITE 3 -#include "os.h" #include "sound_calls.h" #include "dev_table.h" #ifndef DEB #define DEB(x) +#endif + +#ifndef DDB +#define DDB(x) +#endif #define TIMER_ARMED 121234 #define TIMER_NOT_ARMED 1 - -#define FUTURE_VERSION -#endif #endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c --- v1.3.8/linux/drivers/sound/sound_switch.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/sound_switch.c Mon Jul 10 01:45:21 1995 @@ -115,7 +115,7 @@ status_ptr = 0; - put_status ("Sound Driver:" SOUND_VERSION_STRING + put_status ("VoxWare Sound Driver:" SOUND_VERSION_STRING " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" "\n"); @@ -184,7 +184,11 @@ return; } - if (!put_status ("\nPCM devices:\n")) +#ifdef EXCLUDE_AUDIO + if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n")) + return; +#else + if (!put_status ("\nAudio devices:\n")) return; for (i = 0; i < num_audiodevs; i++) @@ -198,7 +202,12 @@ if (!put_status ("\n")) return; } +#endif +#ifdef EXCLUDE_SEQUENCER + if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n")) + return; +#else if (!put_status ("\nSynth devices:\n")) return; @@ -213,7 +222,12 @@ if (!put_status ("\n")) return; } +#endif +#ifdef EXCLUDE_MIDI + if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n")) + return; +#else if (!put_status ("\nMidi devices:\n")) return; @@ -228,8 +242,9 @@ if (!put_status ("\n")) return; } +#endif - if (!put_status ("\nMIDI Timers:\n")) + if (!put_status ("\nTimers:\n")) return; for (i = 0; i < num_sound_timers; i++) @@ -244,12 +259,20 @@ return; } - if (!put_status ("\n")) - return; - if (!put_status_int (num_mixers, 10)) - return; - if (!put_status (" mixer(s) installed\n")) + if (!put_status ("\nMixers:\n")) return; + + for (i = 0; i < num_mixers; i++) + { + if (!put_status_int (i, 10)) + return; + if (!put_status (": ")) + return; + if (!put_status (mixer_devs[i]->name)) + return; + if (!put_status ("\n")) + return; + } } static int @@ -301,11 +324,6 @@ return MIDIbuf_read (dev, file, buf, count); #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - return pss_read (dev, file, buf, count); -#endif - default: printk ("Sound: Undefined minor device %d\n", dev); } @@ -338,11 +356,6 @@ return MIDIbuf_write (dev, file, buf, count); #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - return pss_write (dev, file, buf, count); -#endif - default: return RET_ERROR (EPERM); } @@ -392,13 +405,6 @@ break; #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - if ((retval = pss_open (dev, file)) < 0) - return retval; - break; -#endif - case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -446,12 +452,6 @@ break; #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - pss_release (dev, file); - break; -#endif - case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -472,11 +472,27 @@ { DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); - if ((dev & 0x0f) != SND_DEV_CTL && num_mixers > 0) - if ((cmd >> 8) & 0xff == 'M') /* - * Mixer ioctl - */ - return mixer_devs[0]->ioctl (0, cmd, arg); + if ((cmd >> 8) & 0xff == 'M' && num_mixers > 0) /* Mixer ioctl */ + if ((dev & 0x0f) != SND_DEV_CTL) + { + int dtype = dev & 0x0f; + int mixdev; + + switch (dtype) + { + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + mixdev = audio_devs[dev >> 4]->mixer_dev; + if (mixdev < 0 || mixdev >= num_mixers) + return RET_ERROR (ENXIO); + return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg); + break; + + default: + return mixer_devs[0]->ioctl (0, cmd, arg); + } + } switch (dev & 0x0f) { @@ -508,12 +524,6 @@ #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: return MIDIbuf_ioctl (dev, file, cmd, arg); - break; -#endif - -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - return pss_ioctl (dev, file, cmd, arg); break; #endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v1.3.8/linux/drivers/sound/sound_timer.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/sound_timer.c Mon Jul 10 01:45:21 1995 @@ -87,8 +87,8 @@ tmr2ticks (int tmr_value) { /* - * Convert timer ticks to MIDI ticks - */ + * Convert timer ticks to MIDI ticks + */ unsigned long tmp; unsigned long scale; @@ -110,8 +110,8 @@ usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); /* - * Don't kill the system by setting too high timer rate - */ + * Don't kill the system by setting too high timer rate + */ if (usecs_per_tick < 2000) usecs_per_tick = 2000; diff -u --recursive --new-file v1.3.8/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v1.3.8/linux/drivers/sound/soundcard.c Mon Jan 23 23:04:09 1995 +++ linux/drivers/sound/soundcard.c Mon Jul 10 01:45:22 1995 @@ -26,13 +26,15 @@ * SUCH DAMAGE. * */ +/* + * Created modular version by Peter Trattler (peter@sbox.tu-graz.ac.at) + */ #include "sound_config.h" #ifdef CONFIGURE_SOUNDCARD #include -#include static int soundcards_installed = 0; /* Number of installed @@ -44,15 +46,9 @@ int snd_ioctl_return (int *addr, int value) { - int error; - if (value < 0) return value; - error = verify_area(VERIFY_WRITE, addr, sizeof(int)); - if (error) - return error; - PUT_WORD_TO_USER (addr, 0, value); return 0; } @@ -73,6 +69,11 @@ { int dev; +#ifdef MODULE + int err; + +#endif + dev = inode->i_rdev; dev = MINOR (dev); @@ -88,7 +89,8 @@ static int sound_open (struct inode *inode, struct file *file) { - int dev; + int dev, retval; + struct fileinfo tmp_file; dev = inode->i_rdev; dev = MINOR (dev); @@ -99,16 +101,25 @@ return RET_ERROR (ENXIO); } - files[dev].mode = 0; + tmp_file.mode = 0; + tmp_file.filp = file; if ((file->f_flags & O_ACCMODE) == O_RDWR) - files[dev].mode = OPEN_READWRITE; + tmp_file.mode = OPEN_READWRITE; if ((file->f_flags & O_ACCMODE) == O_RDONLY) - files[dev].mode = OPEN_READ; + tmp_file.mode = OPEN_READ; if ((file->f_flags & O_ACCMODE) == O_WRONLY) - files[dev].mode = OPEN_WRITE; + tmp_file.mode = OPEN_WRITE; - return sound_open_sw (dev, &files[dev]); + if ((retval = sound_open_sw (dev, &tmp_file)) < 0) + return retval; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file)); + return retval; } static void @@ -120,6 +131,9 @@ dev = MINOR (dev); sound_release_sw (dev, &files[dev]); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif } static int @@ -131,6 +145,29 @@ dev = inode->i_rdev; dev = MINOR (dev); + if (cmd & IOC_INOUT) + { + /* + * Have to validate the address given by the process. + */ + int len, err; + + len = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; + + if (cmd & IOC_IN) + { + if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0) + return err; + } + + if (cmd & IOC_OUT) + { + if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0) + return err; + } + + } + return sound_ioctl_sw (dev, &files[dev], cmd, arg); } @@ -148,6 +185,7 @@ { #ifndef EXCLUDE_SEQUENCER case SND_DEV_SEQ: + case SND_DEV_SEQ2: return sequencer_select (dev, &files[dev], sel_type, wait); break; #endif @@ -158,6 +196,14 @@ break; #endif +#ifndef EXCLUDE_AUDIO + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_select (dev, &files[dev], sel_type, wait); + break; +#endif + default: return 0; } @@ -181,7 +227,9 @@ long soundcard_init (long mem_start) { +#ifndef MODULE register_chrdev (SOUND_MAJOR, "sound", &sound_fops); +#endif soundcard_configured = 1; @@ -212,6 +260,89 @@ return mem_start; } +#ifdef MODULE +static unsigned long irqs = 0; +void snd_release_irq (int); +static int module_sound_mem_init (void); +static void module_sound_mem_release (void); + +static void +free_all_irqs (void) +{ + int i; + + for (i = 0; i < 31; i++) + if (irqs & (1ul << i)) + snd_release_irq (i); + irqs = 0; +} + +char kernel_version[] = UTS_RELEASE; + +static long memory_pool = 0; +static int memsize = 70 * 1024; +static int debugmem = 0; /* switched off by default */ + +int +init_module (void) +{ + long lastbyte; + int err; + + printk ("sound: made modular by Peter Trattler (peter@sbox.tu-graz.ac.at)\n"); + err = register_chrdev (SOUND_MAJOR, "sound", &sound_fops); + if (err) + { + printk ("sound: driver already loaded/included in kernel\n"); + return err; + } + memory_pool = (long) kmalloc (memsize, GFP_KERNEL); + if (memory_pool == 0l) + { + unregister_chrdev (SOUND_MAJOR, "sound"); + return -ENOMEM; + } + lastbyte = soundcard_init (memory_pool); + if (lastbyte > memory_pool + memsize) + { + printk ("sound: Not enough memory; use : 'insmod sound.o memsize=%ld'\n", + lastbyte - memory_pool); + kfree ((void *) memory_pool); + unregister_chrdev (SOUND_MAJOR, "sound"); + free_all_irqs (); + return -ENOMEM; + } + err = module_sound_mem_init (); + if (err) + { + module_sound_mem_release (); + kfree ((void *) memory_pool); + unregister_chrdev (SOUND_MAJOR, "sound"); + free_all_irqs (); + return err; + } + if (lastbyte < memory_pool + memsize) + printk ("sound: (Suggestion) too much memory; use : 'insmod sound.o memsize=%ld'\n", + lastbyte - memory_pool); + return 0; +} + +void +cleanup_module (void) +{ + if (MOD_IN_USE) + printk ("sound: module busy -- remove delayed\n"); + else + { + kfree ((void *) memory_pool); + unregister_chrdev (SOUND_MAJOR, "sound"); + free_all_irqs (); + module_sound_mem_release (); + } +} + +#endif + void tenmicrosec (void) { @@ -222,22 +353,19 @@ } int -snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, struct pt_regs *)) +snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO (), char *name) { int retcode; - retcode = request_irq(interrupt_level, hndlr, -#ifdef SND_SA_INTERRUPT - SA_INTERRUPT, -#else - 0, -#endif - "sound"); - + retcode = request_irq (interrupt_level, hndlr, SA_INTERRUPT, name); if (retcode < 0) { printk ("Sound: IRQ%d already in use\n", interrupt_level); } +#ifdef MODULE + else + irqs |= (1ul << interrupt_level); +#endif return retcode; } @@ -245,6 +373,9 @@ void snd_release_irq (int vect) { +#ifdef MODULE + irqs &= ~(1ul << vect); +#endif free_irq (vect); } @@ -286,6 +417,152 @@ return 0; } +#ifdef MODULE + +#ifdef KMALLOC_DMA_BROKEN +#define KMALLOC_MEM_REGIONS 20 + +static char *dma_list[KMALLOC_MEM_REGIONS]; +static int dma_last = 0; +inline void +add_to_dma_list (char *adr) +{ + dma_list[dma_last++] = adr; +} + +#endif + +static int +module_sound_mem_init (void) +{ + int dev, ret = 0; + unsigned long dma_pagesize; + char *start_addr, *end_addr; + struct dma_buffparms *dmap; + + for (dev = 0; dev < num_audiodevs; dev++) + if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0) + { + dmap = audio_devs[dev]->dmap; + if (audio_devs[dev]->flags & DMA_AUTOMODE) + audio_devs[dev]->buffcount = 1; + + if (audio_devs[dev]->dmachan > 3) + dma_pagesize = 131072; /* 16bit dma: 128k */ + else + dma_pagesize = 65536; /* 8bit dma: 64k */ + if (debugmem) + printk ("sound: dma-page-size %lu\n", dma_pagesize); + /* More sanity checks */ + + if (audio_devs[dev]->buffsize > dma_pagesize) + audio_devs[dev]->buffsize = dma_pagesize; + audio_devs[dev]->buffsize &= 0xfffff000; /* Truncate to n*4k */ + if (audio_devs[dev]->buffsize < 4096) + audio_devs[dev]->buffsize = 4096; + if (debugmem) + printk ("sound: buffsize %lu\n", audio_devs[dev]->buffsize); + /* Now allocate the buffers */ + for (dmap->raw_count = 0; dmap->raw_count < audio_devs[dev]->buffcount; + dmap->raw_count++) + { +#ifdef KMALLOC_DMA_BROKEN + start_addr = kmalloc (audio_devs[dev]->buffsize, GFP_KERNEL); + if (start_addr) + { + if (debugmem) + printk ("sound: trying 0x%lx for DMA\n", (long) start_addr); + if (valid_dma_page ((unsigned long) start_addr, + audio_devs[dev]->buffsize, + dma_pagesize)) + add_to_dma_list (start_addr); + else + { + kfree (start_addr); + start_addr = kmalloc (audio_devs[dev]->buffsize * 2, + GFP_KERNEL); /* what a waste :-( */ + if (start_addr) + { + if (debugmem) + printk ("sound: failed; trying 0x%lx aligned to", + (long) start_addr); + add_to_dma_list (start_addr); + /* now align it to the next dma-page boundary */ + start_addr = (char *) (((long) start_addr + + dma_pagesize - 1) + & ~(dma_pagesize - 1)); + if (debugmem) + printk (" 0x%lx\n", (long) start_addr); + } + } + } +#else + start_addr = kmalloc (audio_devs[dev]->buffsize, + GFP_DMA | GFP_KERNEL); +#endif + if (start_addr == NULL) + ret = -ENOMEM; /* Can't stop the loop in this case, because + * ...->raw_buf [...] must be initilized + * to valid values (at least to NULL) + */ + else + { + /* make some checks */ + end_addr = start_addr + audio_devs[dev]->buffsize - 1; + if (debugmem) + printk ("sound: start 0x%lx, end 0x%lx\n", + (long) start_addr, (long) end_addr); + /* now check if it fits into the same dma-pagesize */ + if (((long) start_addr & ~(dma_pagesize - 1)) + != ((long) end_addr & ~(dma_pagesize - 1)) + || end_addr >= (char *) (16 * 1024 * 1024)) + { + printk ( + "sound: kmalloc returned invalid address 0x%lx for %ld Bytes DMA-buffer\n", + (long) start_addr, + audio_devs[dev]->buffsize); + ret = -EFAULT; + } + } + dmap->raw_buf[dmap->raw_count] = start_addr; + dmap->raw_buf_phys[dmap->raw_count] = (unsigned long) start_addr; + } + } + return ret; +} + +static void +module_sound_mem_release (void) +{ +#ifdef KMALLOC_DMA_BROKEN + int i; + + for (i = 0; i < dma_last; i++) + { + if (debugmem) + printk ("sound: freeing 0x%lx\n", (long) dma_list[i]); + kfree (dma_list[i]); + } +#else + int dev, i; + + for (dev = 0; dev < num_audiodevs; dev++) + if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0) + { + for (i = 0; i < audio_devs[dev]->buffcount; i++) + if (audio_devs[dev]->dmap->raw_buf[i]) + { + if (debugmem) + printk ("sound: freeing 0x%lx\n", + (long) (audio_devs[dev]->dmap->raw_buf[i])); + kfree (audio_devs[dev]->dmap->raw_buf[i]); + } + } +#endif +} + +#else /* !MODULE */ + void sound_mem_init (void) { @@ -309,7 +586,7 @@ audio_devs[dev]->buffcount = 1; if (audio_devs[dev]->dmachan > 3 && audio_devs[dev]->buffsize > 65536) - dma_pagesize = 131072;/* 128k */ + dma_pagesize = 131072; /* 128k */ else dma_pagesize = 65536; @@ -347,6 +624,8 @@ } /* for dev */ } +#endif /* !MODULE */ + #endif #else @@ -365,5 +644,14 @@ { /* Dummy version */ } + +#ifdef MODULE +static int +module_sound_mem_init (void) +{ + return 0; /* no error */ +} + +#endif #endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h --- v1.3.8/linux/drivers/sound/soundvers.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/soundvers.h Mon Jul 10 01:45:00 1995 @@ -0,0 +1 @@ +#define SOUND_VERSION_STRING "3.0-950710" diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v1.3.8/linux/drivers/sound/sscape.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/sscape.c Mon Jul 10 01:45:23 1995 @@ -0,0 +1,1134 @@ +/* + * sound/sscape.c + * + * Low level driver for Ensoniq Soundscape + * + * Copyright by Hannu Savolainen 1994 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SSCAPE) + +#include "coproc.h" + +/* + * I/O ports + */ +#define MIDI_DATA 0 +#define MIDI_CTRL 1 +#define HOST_CTRL 2 +#define TX_READY 0x02 +#define RX_READY 0x01 +#define HOST_DATA 3 +#define ODIE_ADDR 4 +#define ODIE_DATA 5 + +/* + * Indirect registers + */ +#define GA_INTSTAT_REG 0 +#define GA_INTENA_REG 1 +#define GA_DMAA_REG 2 +#define GA_DMAB_REG 3 +#define GA_INTCFG_REG 4 +#define GA_DMACFG_REG 5 +#define GA_CDCFG_REG 6 +#define GA_SMCFGA_REG 7 +#define GA_SMCFGB_REG 8 +#define GA_HMCTL_REG 9 + +/* + * DMA channel identifiers (A and B) + */ +#define SSCAPE_DMA_A 0 +#define SSCAPE_DMA_B 1 + +#define PORT(name) (devc->base+name) + +/* + * Host commands recognized by the OBP microcode + */ +#define CMD_GEN_HOST_ACK 0x80 +#define CMD_GEN_MPU_ACK 0x81 +#define CMD_GET_BOARD_TYPE 0x82 +#define CMD_SET_CONTROL 0x88 +#define CMD_GET_CONTROL 0x89 +#define CMD_SET_MT32 0x96 +#define CMD_GET_MT32 0x97 +#define CMD_SET_EXTMIDI 0x9b +#define CMD_GET_EXTMIDI 0x9c + +#define CMD_ACK 0x80 + +typedef struct sscape_info + { + int base, irq, dma; + int ok; /* Properly detected */ + int dma_allocated; + int my_audiodev; + int opened; + } + +sscape_info; +static struct sscape_info dev_info = +{0}; +static struct sscape_info *devc = &dev_info; + +DEFINE_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + +/* Some older cards have assigned interrupt bits differently than new ones */ +static char valid_interrupts_old[] = +{9, 7, 5, 15}; + +static char valid_interrupts_new[] = +{9, 5, 7, 10}; + +static char *valid_interrupts = valid_interrupts_new; + +#ifdef REVEAL_SPEA +static char old_hardware = 1; + +#else +static char old_hardware = 0; + +#endif + +static unsigned char +sscape_read (struct sscape_info *devc, int reg) +{ + unsigned long flags; + unsigned char val; + + DISABLE_INTR (flags); + OUTB (reg, PORT (ODIE_ADDR)); + val = INB (PORT (ODIE_DATA)); + RESTORE_INTR (flags); + return val; +} + +static void +sscape_write (struct sscape_info *devc, int reg, int data) +{ + unsigned long flags; + + DISABLE_INTR (flags); + OUTB (reg, PORT (ODIE_ADDR)); + OUTB (data, PORT (ODIE_DATA)); + RESTORE_INTR (flags); +} + +static void +host_open (struct sscape_info *devc) +{ + OUTB (0x00, PORT (HOST_CTRL)); /* Put the board to the host mode */ +} + +static void +host_close (struct sscape_info *devc) +{ + OUTB (0x03, PORT (HOST_CTRL)); /* Put the board to the MIDI mode */ +} + +static int +host_write (struct sscape_info *devc, unsigned char *data, int count) +{ + unsigned long flags; + int i, timeout; + + DISABLE_INTR (flags); + + /* + * Send the command and data bytes + */ + + for (i = 0; i < count; i++) + { + for (timeout = 10000; timeout > 0; timeout--) + if (INB (PORT (HOST_CTRL)) & TX_READY) + break; + + if (timeout <= 0) + { + RESTORE_INTR (flags); + return 0; + } + + OUTB (data[i], PORT (HOST_DATA)); + } + + + RESTORE_INTR (flags); + + return 1; +} + +static int +host_read (struct sscape_info *devc) +{ + unsigned long flags; + int timeout; + unsigned char data; + + DISABLE_INTR (flags); + + /* + * Read a byte + */ + + for (timeout = 10000; timeout > 0; timeout--) + if (INB (PORT (HOST_CTRL)) & RX_READY) + break; + + if (timeout <= 0) + { + RESTORE_INTR (flags); + return -1; + } + + data = INB (PORT (HOST_DATA)); + + RESTORE_INTR (flags); + + return data; +} + +static int +host_command1 (struct sscape_info *devc, int cmd) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + + return host_write (devc, buf, 1); +} + +static int +host_command2 (struct sscape_info *devc, int cmd, int parm1) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); + + return host_write (devc, buf, 2); +} + +static int +host_command3 (struct sscape_info *devc, int cmd, int parm1, int parm2) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); + buf[2] = (unsigned char) (parm2 & 0xff); + + return host_write (devc, buf, 3); +} + +static void +set_mt32 (struct sscape_info *devc, int value) +{ + host_open (devc); + host_command2 (devc, CMD_SET_MT32, + value ? 1 : 0); + if (host_read (devc) != CMD_ACK) + { + printk ("SNDSCAPE: Setting MT32 mode failed\n"); + } + host_close (devc); +} + +static int +get_board_type (struct sscape_info *devc) +{ + int tmp; + + host_open (devc); + if (!host_command1 (devc, CMD_GET_BOARD_TYPE)) + tmp = -1; + else + tmp = host_read (devc); + host_close (devc); + return tmp; +} + +void +sscapeintr (INT_HANDLER_PARMS (irq, dummy)) +{ + unsigned char bits, tmp; + static int debug = 0; + + printk ("sscapeintr(0x%02x)\n", (bits = sscape_read (devc, GA_INTSTAT_REG))); + if (SOMEONE_WAITING (sscape_sleeper, sscape_sleep_flag)) + { + WAKE_UP (sscape_sleeper, sscape_sleep_flag); + } + + if (bits & 0x02) /* Host interface interrupt */ + { + printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc)); + } + +#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) + if (bits & 0x01) + { + mpuintr (INT_HANDLER_CALL (irq)); + if (debug++ > 10) /* Temporary debugging hack */ + { + sscape_write (devc, GA_INTENA_REG, 0x00); /* Disable all interrupts */ + } + } +#endif + + /* + * Acknowledge interrupts (toggle the interrupt bits) + */ + + tmp = sscape_read (devc, GA_INTENA_REG); + sscape_write (devc, GA_INTENA_REG, (~bits & 0x0e) | (tmp & 0xf1)); + +} + +static void +sscape_enable_intr (struct sscape_info *devc, unsigned intr_bits) +{ + unsigned char temp, orig; + + temp = orig = sscape_read (devc, GA_INTENA_REG); + temp |= intr_bits; + temp |= 0x80; /* Master IRQ enable */ + + if (temp == orig) + return; /* No change */ + + sscape_write (devc, GA_INTENA_REG, temp); +} + +static void +sscape_disable_intr (struct sscape_info *devc, unsigned intr_bits) +{ + unsigned char temp, orig; + + temp = orig = sscape_read (devc, GA_INTENA_REG); + temp &= ~intr_bits; + if ((temp & ~0x80) == 0x00) + temp = 0x00; /* Master IRQ disable */ + if (temp == orig) + return; /* No change */ + + sscape_write (devc, GA_INTENA_REG, temp); +} + +static void +do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) +{ + unsigned char temp; + + if (dma_chan != SSCAPE_DMA_A) + { + printk ("SSCAPE: Tried to use DMA channel != A. Why?\n"); + return; + } + + DMAbuf_start_dma (devc->my_audiodev, + buf, + blk_size, mode); + + temp = devc->dma << 4; /* Setup DMA channel select bits */ + if (devc->dma <= 3) + temp |= 0x80; /* 8 bit DMA channel */ + + temp |= 1; /* Trigger DMA */ + sscape_write (devc, GA_DMAA_REG, temp); + temp &= 0xfe; /* Clear DMA trigger */ + sscape_write (devc, GA_DMAA_REG, temp); +} + +static int +verify_mpu (struct sscape_info *devc) +{ + /* + * The SoundScape board could be in three modes (MPU, 8250 and host). + * If the card is not in the MPU mode, enabling the MPU driver will + * cause infinite loop (the driver believes that there is always some + * received data in the buffer. + * + * Detect this by looking if there are more than 10 received MIDI bytes + * (0x00) in the buffer. + */ + + int i; + + for (i = 0; i < 10; i++) + { + if (INB (devc->base + HOST_CTRL) & 0x80) + return 1; + + if (INB (devc->base) != 0x00) + return 1; + } + + printk ("SoundScape: The device is not in the MPU-401 mode\n"); + return 0; +} + +static int +sscape_coproc_open (void *dev_info, int sub_device) +{ + if (sub_device == COPR_MIDI) + { + set_mt32 (devc, 0); + if (!verify_mpu (devc)) + return RET_ERROR (EIO); + } + + return 0; +} + +static void +sscape_coproc_close (void *dev_info, int sub_device) +{ + struct sscape_info *devc = dev_info; + unsigned long flags; + + DISABLE_INTR (flags); + if (devc->dma_allocated) + { + sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ +#ifndef EXCLUDE_NATIVE_PCM + DMAbuf_close_dma (devc->my_audiodev); +#endif + devc->dma_allocated = 0; + } + RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + RESTORE_INTR (flags); + + return; +} + +static void +sscape_coproc_reset (void *dev_info) +{ +} + +static int +sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, int flag) +{ + unsigned long flags; + unsigned char temp; + int done, timeout; + + if (flag & CPF_FIRST) + { + /* + * First block. Have to allocate DMA and to reset the board + * before continuing. + */ + + DISABLE_INTR (flags); + if (devc->dma_allocated == 0) + { +#ifndef EXCLUDE_NATIVE_PCM + if (DMAbuf_open_dma (devc->my_audiodev) < 0) + { + RESTORE_INTR (flags); + return 0; + } +#endif + + devc->dma_allocated = 1; + } + RESTORE_INTR (flags); + + sscape_write (devc, GA_HMCTL_REG, + (temp = sscape_read (devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ + + for (timeout = 10000; timeout > 0; timeout--) + sscape_read (devc, GA_HMCTL_REG); /* Delay */ + + /* Take board out of reset */ + sscape_write (devc, GA_HMCTL_REG, + (temp = sscape_read (devc, GA_HMCTL_REG)) | 0x80); + } + + /* + * Transfer one code block using DMA + */ + memcpy (audio_devs[devc->my_audiodev]->dmap->raw_buf[0], block, size); + + DISABLE_INTR (flags); +/******** INTERRUPTS DISABLED NOW ********/ + do_dma (devc, SSCAPE_DMA_A, + audio_devs[devc->my_audiodev]->dmap->raw_buf_phys[0], + size, DMA_MODE_WRITE); + + /* + * Wait until transfer completes. + */ + RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + done = 0; + timeout = 100; + while (!done && timeout-- > 0) + { + int resid; + + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + clear_dma_ff (devc->dma); + if ((resid = get_dma_residue (devc->dma)) == 0) + done = 1; + } + + RESTORE_INTR (flags); + if (!done) + return 0; + + if (flag & CPF_LAST) + { + /* + * Take the board out of reset + */ + OUTB (0x00, PORT (HOST_CTRL)); + OUTB (0x00, PORT (MIDI_CTRL)); + + temp = sscape_read (devc, GA_HMCTL_REG); + temp |= 0x40; + sscape_write (devc, GA_HMCTL_REG, temp); /* Kickstart the board */ + + /* + * Wait until the ODB wakes up + */ + + DISABLE_INTR (flags); + done = 0; + timeout = 5 * HZ; + while (!done && timeout-- > 0) + { + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + if (INB (PORT (HOST_DATA)) == 0xff) /* OBP startup acknowledge */ + done = 1; + } + RESTORE_INTR (flags); + if (!done) + { + printk ("SoundScape: The OBP didn't respond after code download\n"); + return 0; + } + + DISABLE_INTR (flags); + done = 0; + timeout = 5 * HZ; + while (!done && timeout-- > 0) + { + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + if (INB (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */ + done = 1; + } + RESTORE_INTR (flags); + if (!done) + { + printk ("SoundScape: OBP Initialization failed.\n"); + return 0; + } + + printk ("SoundScape board of type %d initialized OK\n", + get_board_type (devc)); + +#ifdef SSCAPE_DEBUG3 + /* + * Temporary debugging aid. Print contents of the registers after + * downloading the code. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); + } +#endif + + } + + return 1; +} + +static int +download_boot_block (void *dev_info, copr_buffer * buf) +{ + if (buf->len <= 0 || buf->len > sizeof (buf->data)) + return RET_ERROR (EINVAL); + + if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags)) + { + printk ("SSCAPE: Unable to load microcode block to the OBP.\n"); + return RET_ERROR (EIO); + } + + return 0; +} + +static int +sscape_coproc_ioctl (void *dev_info, unsigned int cmd, unsigned int arg, int local) +{ + + switch (cmd) + { + case SNDCTL_COPR_RESET: + sscape_coproc_reset (dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) KERNEL_MALLOC (sizeof (copr_buffer)); + IOCTL_FROM_USER ((char *) buf, (char *) arg, 0, sizeof (*buf)); + err = download_boot_block (dev_info, buf); + KERNEL_FREE (buf); + return err; + } + break; + + default: + return RET_ERROR (EINVAL); + } + + return RET_ERROR (EINVAL); +} + +static coproc_operations sscape_coproc_operations = +{ + "SoundScape M68K", + sscape_coproc_open, + sscape_coproc_close, + sscape_coproc_ioctl, + sscape_coproc_reset, + &dev_info +}; + +static int +sscape_audio_open (int dev, int mode) +{ + unsigned long flags; + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + DISABLE_INTR (flags); + if (devc->opened) + { + RESTORE_INTR (flags); + return RET_ERROR (EBUSY); + } + + if (devc->dma_allocated == 0) + { + int err; + + if ((err = DMAbuf_open_dma (devc->my_audiodev)) < 0) + { + RESTORE_INTR (flags); + return err; + } + + devc->dma_allocated = 1; + } + + devc->opened = 1; + RESTORE_INTR (flags); +#ifdef SSCAPE_DEBUG4 + /* + * Temporary debugging aid. Print contents of the registers + * when the device is opened. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x\n", i, sscape_read (devc, i)); + } +#endif + + return 0; +} + +static void +sscape_audio_close (int dev) +{ + unsigned long flags; + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + DEB (printk ("sscape_audio_close(void)\n")); + + DISABLE_INTR (flags); + + if (devc->dma_allocated) + { + sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ + DMAbuf_close_dma (dev); + devc->dma_allocated = 0; + } + devc->opened = 0; + + RESTORE_INTR (flags); +} + +static int +set_speed (sscape_info * devc, int arg) +{ + return 8000; +} + +static int +set_channels (sscape_info * devc, int arg) +{ + return 1; +} + +static int +set_format (sscape_info * devc, int arg) +{ + return AFMT_U8; +} + +static int +sscape_audio_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (local) + return set_speed (devc, arg); + return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_RATE: + if (local) + return 8000; + return IOCTL_OUT (arg, 8000); + + case SNDCTL_DSP_STEREO: + if (local) + return set_channels (devc, arg + 1) - 1; + return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1); + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return set_channels (devc, arg); + return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_CHANNELS: + if (local) + return 1; + return IOCTL_OUT (arg, 1); + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return set_format (devc, arg); + return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_BITS: + if (local) + return 8; + return IOCTL_OUT (arg, 8); + + default:; + } + return RET_ERROR (EINVAL); +} + +static void +sscape_audio_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ +} + +static void +sscape_audio_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ +} + +static int +sscape_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + return 0; +} + +static int +sscape_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + return 0; +} + +static void +sscape_audio_halt (int dev) +{ +} + +static void +sscape_audio_reset (int dev) +{ + sscape_audio_halt (dev); +} + +static struct audio_operations sscape_audio_operations = +{ + "Not functional", + 0, + AFMT_U8 | AFMT_S16_LE, + NULL, + sscape_audio_open, + sscape_audio_close, + sscape_audio_output_block, + sscape_audio_start_input, + sscape_audio_ioctl, + sscape_audio_prepare_for_input, + sscape_audio_prepare_for_output, + sscape_audio_reset, + sscape_audio_halt, + NULL, + NULL +}; + +long +attach_sscape (long mem_start, struct address_info *hw_config) +{ + int my_dev; + +#ifndef SSCAPE_REGS + /* + * Config register values for Spea/V7 Media FX and Ensoniq S-2000. + * These values are card + * dependent. If you have another SoundScape based card, you have to + * find the correct values. Do the following: + * - Compile this driver with SSCAPE_DEBUG1 defined. + * - Shut down and power off your machine. + * - Boot with DOS so that the SSINIT.EXE program is run. + * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed + * when detecting the SoundScape. + * - Modify the following list to use the values printed during boot. + * Undefine the SSCAPE_DEBUG1 + */ +#define SSCAPE_REGS { \ +/* I0 */ 0x00, \ + 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ + 0x20, /* Note! Ignored. Set always to 0x20 */ \ + 0x20, /* Note! Ignored. Set always to 0x20 */ \ + 0xf5, /* Ignored */ \ + 0x10, \ + 0x00, \ + 0x2e, /* I7 MEM config A. Likely to vary between models */ \ + 0x00, /* I8 MEM config B. Likely to vary between models */ \ +/* I9 */ 0x40 /* Ignored */ \ + } +#endif + + unsigned long flags; + static unsigned char regs[10] = SSCAPE_REGS; + + int i, irq_bits = 0xff; + + if (!probe_sscape (hw_config)) + return mem_start; + + if (old_hardware) + { + valid_interrupts = valid_interrupts_old; + printk (" "); + } + else + printk (" "); + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + + if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) + { + printk ("Invalid IRQ%d\n", hw_config->irq); + return mem_start; + } + + DISABLE_INTR (flags); + + for (i = 1; i < 10; i++) + switch (i) + { + case 1: /* Host interrupt enable */ + sscape_write (devc, i, 0xf0); /* All interrupts enabled */ + break; + + case 2: /* DMA A status/trigger register */ + case 3: /* DMA B status/trigger register */ + sscape_write (devc, i, 0x20); /* DMA channel disabled */ + break; + + case 4: /* Host interrupt config reg */ + sscape_write (devc, i, 0xf0 | (irq_bits << 2) | irq_bits); + break; + + case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ + sscape_write (devc, i, (regs[i] & 0x3f) | + (sscape_read (devc, i) & 0xc0)); + break; + + case 6: /* CD-ROM config. Don't touch. */ + break; + + case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ + sscape_write (devc, i, + (sscape_read (devc, i) & 0xf0) | 0x00); + break; + + default: + sscape_write (devc, i, regs[i]); + } + + RESTORE_INTR (flags); + +#ifdef SSCAPE_DEBUG2 + /* + * Temporary debugging aid. Print contents of the registers after + * changing them. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); + } +#endif + +#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_MPU_EMU) + hw_config->always_detect = 1; + if (probe_mpu401 (hw_config)) + { + int prev_devs; + + prev_devs = num_midis; + mem_start = attach_mpu401 (mem_start, hw_config); + + if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ + midi_devs[prev_devs]->coproc = &sscape_coproc_operations; + } +#endif + +#ifndef EXCLUDE_NATIVE_PCM + /* Not supported yet */ + +#ifndef EXCLUDE_AUDIO + if (num_audiodevs < MAX_AUDIO_DEV) + { + audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations; + audio_devs[my_dev]->dmachan = hw_config->dma; + audio_devs[my_dev]->buffcount = 1; + audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; + audio_devs[my_dev]->devc = devc; + devc->my_audiodev = my_dev; + devc->opened = 0; + audio_devs[my_dev]->coproc = &sscape_coproc_operations; + if (snd_set_irq_handler (hw_config->irq, sscapeintr, "SoundScape") < 0) + printk ("Error: Can't allocate IRQ for SoundScape\n"); + + sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ + } + else + printk ("SoundScape: More than enough audio devices detected\n"); +#endif +#endif + devc->ok = 1; + return mem_start; +} + +int +probe_sscape (struct address_info *hw_config) +{ + unsigned char save; + + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + + /* + * First check that the address register of "ODIE" is + * there and that it has exactly 4 writeable bits. + * First 4 bits + */ + if ((save = INB (PORT (ODIE_ADDR))) & 0xf0) + return 0; + + OUTB (0x00, PORT (ODIE_ADDR)); + if (INB (PORT (ODIE_ADDR)) != 0x00) + return 0; + + OUTB (0xff, PORT (ODIE_ADDR)); + if (INB (PORT (ODIE_ADDR)) != 0x0f) + return 0; + + OUTB (save, PORT (ODIE_ADDR)); + + /* + * Now verify that some indirect registers return zero on some bits. + * This may break the driver with some future revisions of "ODIE" but... + */ + + if (sscape_read (devc, 0) & 0x0c) + return 0; + + if (sscape_read (devc, 1) & 0x0f) + return 0; + + if (sscape_read (devc, 5) & 0x0f) + return 0; + +#ifdef SSCAPE_DEBUG1 + /* + * Temporary debugging aid. Print contents of the registers before + * changing them. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (old value)\n", i, sscape_read (devc, i)); + } +#endif + + if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ + { + int tmp, status = 0; + int cc; + + if (!((tmp = sscape_read (devc, GA_HMCTL_REG)) & 0xc0)) + { + sscape_write (devc, GA_HMCTL_REG, tmp | 0x80); + for (cc = 0; cc < 200000; ++cc) + INB (devc->base + ODIE_ADDR); + } + else + old_hardware = 0; + } + + + return 1; +} + +int +probe_ss_ms_sound (struct address_info *hw_config) +{ + int i, irq_bits = 0xff; + + if (devc->ok == 0) + { + printk ("SoundScape: Invalid initialization order.\n"); + return 0; + } + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + if (hw_config->irq > 15 || irq_bits == 0xff) + { + printk ("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq); + return 0; + } + + return ad1848_detect (hw_config->io_base); +} + +long +attach_ss_ms_sound (long mem_start, struct address_info *hw_config) +{ + /* + * This routine configures the SoundScape card for use with the + * Win Sound System driver. The AD1848 codec interface uses the CD-ROM + * config registers of the "ODIE". + */ + + int i, irq_bits = 0xff; + +#ifdef EXCLUDE_NATIVE_PCM + int prev_devs = num_audiodevs; + +#endif + + /* + * Setup the DMA polarity. + */ + sscape_write (devc, GA_DMACFG_REG, 0x50); + + /* + * Take the gate-arry off of the DMA channel. + */ + sscape_write (devc, GA_DMAB_REG, 0x20); + + /* + * Init the AD1848 (CD-ROM) config reg. + */ + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + + sscape_write (devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | + (irq_bits << 1)); + + if (hw_config->irq == devc->irq) + printk ("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n"); + + ad1848_init ("SoundScape", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma); + +#ifdef EXCLUDE_NATIVE_PCM + if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ + audio_devs[prev_devs]->coproc = &sscape_coproc_operations; +#endif +#ifdef SSCAPE_DEBUG5 + /* + * Temporary debugging aid. Print contents of the registers + * after the AD1848 device has been initialized. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x\n", i, sscape_read (devc, i)); + } +#endif + + return mem_start; +} + +#endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c --- v1.3.8/linux/drivers/sound/sys_timer.c Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/sys_timer.c Mon Jul 10 01:45:23 1995 @@ -51,17 +51,23 @@ tmr2ticks (int tmr_value) { /* - * Convert system timer ticks (HZ) to MIDI ticks - */ + * Convert system timer ticks (HZ) to MIDI ticks + */ unsigned long tmp; unsigned long scale; - tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */ + tmp = (tmr_value * 1000) / HZ; /* Convert to msecs */ - scale = (60 * 1000) / (curr_tempo * curr_timebase); /* msecs per MIDI tick */ + if (curr_tempo == 0 || curr_timebase == 0) /* Error? */ + scale = 1; + else + scale = (60 * 1000) / (curr_tempo * curr_timebase); /* msecs per MIDI tick */ - return (tmp + (scale / 2)) / scale; + if (scale == 0) /* Error? */ + scale = 1; + + return (tmp + (scale >> 1)) / scale; } static void diff -u --recursive --new-file v1.3.8/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v1.3.8/linux/drivers/sound/trix.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/trix.c Mon Jul 10 01:45:23 1995 @@ -0,0 +1,331 @@ +/* + * sound/trix.c + * + * Low level driver for the MediaTriX AudioTriX Pro + * (MT-0002-PC Control Chip) + * + * Copyright by Hannu Savolainen 1995 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_TRIX) + +#ifdef INCLUDE_TRIX_BOOT +#include "trix_boot.h" +#endif + +static int kilroy_was_here = 0; /* Don't detect twice */ +static int sb_initialized = 0; +static int mpu_initialized = 0; + +static unsigned char +trix_read (int addr) +{ + OUTB ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */ + return INB (0x391); /* MT-0002-PC ASIC data */ +} + +static void +trix_write (int addr, int data) +{ + OUTB ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */ + OUTB ((unsigned char) data, 0x391); /* MT-0002-PC ASIC data */ +} + +static void +download_boot (int base) +{ +#ifdef INCLUDE_TRIX_BOOT + int i = 0, n = sizeof (trix_boot); + + trix_write (0xf8, 0x00); /* ??????? */ + OUTB (0x01, base + 6); /* Clear the internal data pointer */ + OUTB (0x00, base + 6); /* Restart */ + + /* + * Write the boot code to the RAM upload/download register. + * Each write increments the internal data pointer. + */ + OUTB (0x01, base + 6); /* Clear the internal data pointer */ + OUTB (0x1A, 0x390); /* Select RAM download/upload port */ + + for (i = 0; i < n; i++) + OUTB (trix_boot[i], 0x391); + for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ + OUTB (0x00, 0x391); + OUTB (0x00, base + 6); /* Reset */ + OUTB (0x50, 0x390); /* ?????? */ +#endif +} + +static int +trix_set_wss_port (struct address_info *hw_config) +{ + unsigned char addr_bits; + + if (kilroy_was_here) /* Already initialized */ + return 0; + + kilroy_was_here = 1; + + if (trix_read (0x15) != 0x71) /* No asic signature */ + return 0; + + /* + * Disable separate wave playback and recording DMA channels since + * the driver doesn't support duplex mode yet. + */ + + trix_write (0x13, trix_read (0x13) & ~0x80); + trix_write (0x14, trix_read (0x14) & ~0x80); + + /* + * Configure the ASIC to place the codec to the proper I/O location + */ + + switch (hw_config->io_base) + { + case 0x530: + addr_bits = 0; + break; + case 0x604: + addr_bits = 1; + break; + case 0xE80: + addr_bits = 2; + break; + case 0xF40: + addr_bits = 3; + break; + default: + return 0; + } + + trix_write (0x19, (trix_read (0x19) & 0x03) | addr_bits); + return 1; +} + +/* + * Probe and attach routines for the Windows Sound System mode of + * AudioTriX Pro + */ + +int +probe_trix_wss (struct address_info *hw_config) +{ + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTriX Pro for example) + * return 0x00. + */ + if (!trix_set_wss_port (hw_config)) + return 0; + + if ((INB (hw_config->io_base + 3) & 0x3f) != 0x00) + { + DDB (printk ("No MSS signature detected on port 0x%x\n", hw_config->io_base)); + return 0; + } + + if (hw_config->irq > 11) + { + printk ("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq); + return 0; + } + + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk ("AudioTriX: Bad WSS DMA %d\n", hw_config->dma); + return 0; + } + + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && INB (hw_config->io_base + 3) & 0x80) + { + printk ("AudioTriX: Can't use DMA0 with a 8 bit card\n"); + return 0; + } + + if (hw_config->irq > 7 && hw_config->irq != 9 && INB (hw_config->io_base + 3) & 0x80) + { + printk ("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq); + return 0; + } + + return ad1848_detect (hw_config->io_base + 4); +} + +long +attach_trix_wss (long mem_start, struct address_info *hw_config) +{ + static unsigned char interrupt_bits[12] = + {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20}; + char bits; + + static unsigned char dma_bits[4] = + {1, 2, 0, 3}; + + int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + + if (!kilroy_was_here) + return mem_start; + + /* + * Set the IRQ and DMA addresses. + */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == -1) + return mem_start; + + OUTB (bits | 0x40, config_port); + if ((INB (version_port) & 0x40) == 0) + printk ("[IRQ Conflict?]"); + + OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */ + + ad1848_init ("AudioTriX Pro", hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma); + return mem_start; +} + +int +probe_trix_sb (struct address_info *hw_config) +{ + + int tmp; + unsigned char conf; + static char irq_translate[] = + {-1, -1, -1, 0, 1, 2, -1, 3}; + +#ifndef INCLUDE_TRIX_BOOT + return 0; /* No boot code -> no fun */ +#endif + if (!kilroy_was_here) + return 0; /* AudioTriX Pro has not been detected earlier */ + + if (sb_initialized) + return 0; + + if (hw_config->io_base & 0xffffff8f != 0x200) + return 0; + + tmp = hw_config->irq; + if (tmp > 7) + return 0; + if (irq_translate[tmp] == -1) + return 0; + + tmp = hw_config->dma; + if (tmp != 1 && tmp != 3) + return 0; + + conf = 0x84; /* DMA and IRQ enable */ + conf |= hw_config->io_base & 0x70; /* I/O address bits */ + conf |= irq_translate[hw_config->irq]; + if (hw_config->dma == 3) + conf |= 0x08; + trix_write (0x1b, conf); + + download_boot (hw_config->io_base); + sb_initialized = 1; + + return 1; +} + +long +attach_trix_sb (long mem_start, struct address_info *hw_config) +{ +#ifndef EXCLUDE_SB + extern int sb_no_recording; + + sb_dsp_disable_midi (); + sb_no_recording = 1; +#endif + printk (" "); + return mem_start; +} + +long +attach_trix_mpu (long mem_start, struct address_info *hw_config) +{ + return attach_mpu401 (mem_start, hw_config); +} + +int +probe_trix_mpu (struct address_info *hw_config) +{ + unsigned char conf; + static char irq_bits[] = + {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; + + if (!kilroy_was_here) + return 0; /* AudioTriX Pro has not been detected earlier */ + + if (!sb_initialized) + return 0; + + if (mpu_initialized) + return 0; + + if (hw_config->irq > 9) + return 0; + + if (irq_bits[hw_config->irq] == -1) + return 0; + + switch (hw_config->io_base) + { + case 0x330: + conf = 0x00; + break; + case 0x370: + conf = 0x04; + break; + case 0x3b0: + conf = 0x08; + break; + case 0x3f0: + conf = 0x0c; + break; + default: + return 0; /* Invalid port */ + } + + conf |= irq_bits[hw_config->irq] << 4; + + trix_write (0x19, (trix_read (0x19) & 0x83) | conf); + + mpu_initialized = 1; + + return probe_mpu401 (hw_config); +} + +#endif diff -u --recursive --new-file v1.3.8/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v1.3.8/linux/drivers/sound/uart6850.c Tue Jan 17 07:49:57 1995 +++ linux/drivers/sound/uart6850.c Mon Jul 10 01:45:24 1995 @@ -93,9 +93,8 @@ } void -m6850intr (int unit, struct pt_regs * regs) +m6850intr (INTR_HANDLER_PARMS (irq, dummy)) { - printk ("M"); if (input_avail ()) uart6850_input_loop (); } @@ -243,6 +242,7 @@ { {"6850 UART", 0, 0, SNDCARD_UART6850}, &std_midi_synth, + {0}, uart6850_open, uart6850_close, uart6850_ioctl, @@ -309,7 +309,7 @@ uart6850_base = hw_config->io_base; uart6850_irq = hw_config->irq; - if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0) + if (snd_set_irq_handler (uart6850_irq, m6850intr, "MIDI6850") < 0) return 0; ok = reset_uart6850 (); diff -u --recursive --new-file v1.3.8/linux/drivers/sound/ulaw.h linux/drivers/sound/ulaw.h --- v1.3.8/linux/drivers/sound/ulaw.h Mon Jul 18 09:50:55 1994 +++ linux/drivers/sound/ulaw.h Sun Jun 25 17:09:37 1995 @@ -1,69 +1,74 @@ + +/* + * This is a new ulaw.h made by Andy Fingerhut + */ + static unsigned char ulaw_dsp[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, - 5, 9, 13, 17, 21, 25, 29, 33, - 37, 41, 45, 49, 53, 57, 61, 65, - 68, 70, 72, 74, 76, 78, 80, 82, - 84, 86, 88, 90, 92, 94, 96, 98, - 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, - 115, 116, 116, 117, 117, 118, 118, 119, - 119, 120, 120, 121, 121, 122, 122, 123, - 123, 123, 124, 124, 124, 124, 125, 125, - 125, 125, 126, 126, 126, 126, 127, 127, - 127, 127, 127, 127, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 252, 248, 244, 240, 236, 232, 228, 224, - 220, 216, 212, 208, 204, 200, 196, 192, - 189, 187, 185, 183, 181, 179, 177, 175, - 173, 171, 169, 167, 165, 163, 161, 159, - 157, 156, 155, 154, 153, 152, 151, 150, - 149, 148, 147, 146, 145, 144, 143, 142, - 142, 141, 141, 140, 140, 139, 139, 138, - 138, 137, 137, 136, 136, 135, 135, 134, - 134, 134, 133, 133, 133, 133, 132, 132, - 132, 132, 131, 131, 131, 131, 130, 130, - 130, 130, 130, 130, 129, 129, 129, 129, - 129, 129, 129, 129, 128, 128, 128, 128, + 2, 6, 10, 14, 18, 22, 26, 30, + 34, 38, 42, 46, 50, 54, 58, 62, + 65, 67, 69, 71, 73, 75, 77, 79, + 81, 83, 85, 87, 89, 91, 93, 95, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 112, 113, 113, 114, 114, 115, 115, 116, + 116, 117, 117, 118, 118, 119, 119, 120, + 120, 120, 121, 121, 121, 121, 122, 122, + 122, 122, 123, 123, 123, 123, 124, 124, + 124, 124, 124, 124, 125, 125, 125, 125, + 125, 125, 125, 125, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 128, + 253, 249, 245, 241, 237, 233, 229, 225, + 221, 217, 213, 209, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 174, 172, 170, 168, 166, 164, 162, 160, + 158, 157, 156, 155, 154, 153, 152, 151, + 150, 149, 148, 147, 146, 145, 144, 143, + 143, 142, 142, 141, 141, 140, 140, 139, + 139, 138, 138, 137, 137, 136, 136, 135, + 135, 135, 134, 134, 134, 134, 133, 133, + 133, 133, 132, 132, 132, 132, 131, 131, + 131, 131, 131, 131, 130, 130, 130, 130, + 130, 130, 130, 130, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128 }; static unsigned char dsp_ulaw[] = { - 31, 31, 31, 32, 32, 32, 32, 33, - 33, 33, 33, 34, 34, 34, 34, 35, - 35, 35, 35, 36, 36, 36, 36, 37, - 37, 37, 37, 38, 38, 38, 38, 39, - 39, 39, 39, 40, 40, 40, 40, 41, - 41, 41, 41, 42, 42, 42, 42, 43, - 43, 43, 43, 44, 44, 44, 44, 45, - 45, 45, 45, 46, 46, 46, 46, 47, - 47, 47, 47, 48, 48, 49, 49, 50, - 50, 51, 51, 52, 52, 53, 53, 54, - 54, 55, 55, 56, 56, 57, 57, 58, - 58, 59, 59, 60, 60, 61, 61, 62, - 62, 63, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 81, 83, 85, 87, 89, - 91, 93, 95, 99, 103, 107, 111, 119, - 255, 247, 239, 235, 231, 227, 223, 221, - 219, 217, 215, 213, 211, 209, 207, 206, - 205, 204, 203, 202, 201, 200, 199, 198, - 197, 196, 195, 194, 193, 192, 191, 191, - 190, 190, 189, 189, 188, 188, 187, 187, - 186, 186, 185, 185, 184, 184, 183, 183, - 182, 182, 181, 181, 180, 180, 179, 179, - 178, 178, 177, 177, 176, 176, 175, 175, - 175, 175, 174, 174, 174, 174, 173, 173, - 173, 173, 172, 172, 172, 172, 171, 171, - 171, 171, 170, 170, 170, 170, 169, 169, - 169, 169, 168, 168, 168, 168, 167, 167, - 167, 167, 166, 166, 166, 166, 165, 165, - 165, 165, 164, 164, 164, 164, 163, 163, - 163, 163, 162, 162, 162, 162, 161, 161, - 161, 161, 160, 160, 160, 160, 159, 159, + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, + 3, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, + 7, 8, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 10, 11, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, + 13, 14, 14, 14, 14, 15, 15, 15, + 15, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 20, 21, 21, 22, 22, 23, + 23, 24, 24, 25, 25, 26, 26, 27, + 27, 28, 28, 29, 29, 30, 30, 31, + 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 50, 52, 54, 56, 58, 60, + 62, 65, 69, 73, 77, 83, 91, 103, + 255, 231, 219, 211, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 161, 160, + 159, 159, 158, 158, 157, 157, 156, 156, + 155, 155, 154, 154, 153, 153, 152, 152, + 151, 151, 150, 150, 149, 149, 148, 148, + 147, 147, 146, 146, 145, 145, 144, 144, + 143, 143, 143, 143, 142, 142, 142, 142, + 141, 141, 141, 141, 140, 140, 140, 140, + 139, 139, 139, 139, 138, 138, 138, 138, + 137, 137, 137, 137, 136, 136, 136, 136, + 135, 135, 135, 135, 134, 134, 134, 134, + 133, 133, 133, 133, 132, 132, 132, 132, + 131, 131, 131, 131, 130, 130, 130, 130, + 129, 129, 129, 129, 128, 128, 128, 128 }; diff -u --recursive --new-file v1.3.8/linux/fs/Makefile linux/fs/Makefile --- v1.3.8/linux/fs/Makefile Fri Jul 7 08:54:51 1995 +++ linux/fs/Makefile Tue Jul 11 08:29:44 1995 @@ -79,8 +79,6 @@ MODULE_OBJS := $(MODULE_OBJS) binfmt_elf.o endif -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -114,11 +112,4 @@ set -e; for i in $(MODULE_FS_SUBDIRS); do \ test ! -d $$i || $(MAKE) -C $$i CFLAGS="$(CFLAGS) -DMODULE" dep; done -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v1.3.8/linux/fs/binfmt_elf.c Fri Jul 7 13:42:58 1995 +++ linux/fs/binfmt_elf.c Tue Jul 11 07:56:04 1995 @@ -50,6 +50,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_elf_library(int fd); +extern int aout_core_dump(long signr, struct pt_regs * regs); static int elf_core_dump(long signr, struct pt_regs * regs); extern int dump_fpu (elf_fpregset_t *); diff -u --recursive --new-file v1.3.8/linux/fs/ext/Makefile linux/fs/ext/Makefile --- v1.3.8/linux/fs/ext/Makefile Wed Dec 1 14:44:15 1993 +++ linux/fs/ext/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -23,9 +21,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/ext2/CHANGES linux/fs/ext2/CHANGES --- v1.3.8/linux/fs/ext2/CHANGES Wed Apr 5 12:59:50 1995 +++ linux/fs/ext2/CHANGES Mon Jul 10 17:08:03 1995 @@ -1,3 +1,10 @@ +Changes from version 0.5a to version 0.5b +========================================= + - More consistency checks on directories. + - The ext2.diff patch from Tom May has been + integrated. This patch replaces expensive "/" and "%" with + cheap ">>" and "&" where possible. + Changes from version 0.5 to version 0.5a ======================================== - Zero the partial block following the end of the file when a file diff -u --recursive --new-file v1.3.8/linux/fs/ext2/Makefile linux/fs/ext2/Makefile --- v1.3.8/linux/fs/ext2/Makefile Fri Jul 29 14:35:03 1994 +++ linux/fs/ext2/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -23,9 +21,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/ext2/dir.c linux/fs/ext2/dir.c --- v1.3.8/linux/fs/ext2/dir.c Mon Jun 12 12:07:43 1995 +++ linux/fs/ext2/dir.c Mon Jul 10 17:08:03 1995 @@ -88,10 +88,10 @@ error_msg = "inode out of bounds"; if (error_msg != NULL) - ext2_error (dir->i_sb, function, "bad directory entry: %s\n" + ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - " "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", - error_msg, offset, (unsigned long) de->inode, de->rec_len, - de->name_len); + dir->i_ino, error_msg, offset, (unsigned long) de->inode, + de->rec_len, de->name_len); return error_msg == NULL ? 1 : 0; } @@ -118,6 +118,9 @@ blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb); bh = ext2_bread (inode, blk, 0, &err); if (!bh) { + ext2_error (sb, "ext2_readdir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, (unsigned long)filp->f_pos); filp->f_pos += sb->s_blocksize - offset; continue; } diff -u --recursive --new-file v1.3.8/linux/fs/ext2/file.c linux/fs/ext2/file.c --- v1.3.8/linux/fs/ext2/file.c Tue Jun 27 14:11:39 1995 +++ linux/fs/ext2/file.c Mon Jul 10 17:08:03 1995 @@ -114,6 +114,7 @@ read = 0; block = offset >> EXT2_BLOCK_SIZE_BITS(sb); offset &= (sb->s_blocksize - 1); + chars = sb->s_blocksize - offset; size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); bhb = bhe = buflist; @@ -188,12 +189,10 @@ break; } } - if (left < sb->s_blocksize - offset) - chars = left; - else - chars = sb->s_blocksize - offset; - filp->f_pos += chars; left -= chars; + if (left < 0) + chars += left; + filp->f_pos += chars; read += chars; if (*bhe) { memcpy_tofs (buf, offset + (*bhe)->b_data, @@ -205,6 +204,7 @@ put_user (0, buf++); } offset = 0; + chars = sb->s_blocksize; if (++bhe == &buflist[NBUF]) bhe = buflist; } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); @@ -234,9 +234,10 @@ const loff_t two_gb = 2147483647; loff_t pos; off_t pos2; + long block; + int offset; int written, c; struct buffer_head * bh, *bufferlist[NBUF]; - char * p; struct super_block * sb; int err; int i,buffercount,write_error; @@ -272,22 +273,25 @@ */ if (filp->f_flags & O_SYNC) inode->u.ext2_i.i_osync++; + block = pos2 >> EXT2_BLOCK_SIZE_BITS(sb); + offset = pos2 & (sb->s_blocksize - 1); + c = sb->s_blocksize - offset; written = 0; - while (written < count) { + while (count > 0) { if (pos > two_gb) { if (!written) written = -EFBIG; break; } - bh = ext2_getblk (inode, pos2 / sb->s_blocksize, 1, &err); + bh = ext2_getblk (inode, block, 1, &err); if (!bh) { if (!written) written = err; break; } - c = sb->s_blocksize - (pos2 % sb->s_blocksize); - if (c > count-written) - c = count - written; + count -= c; + if (count < 0) + c += count; if (c != sb->s_blocksize && !bh->b_uptodate) { ll_rw_block (READ, 1, &bh); wait_on_buffer (bh); @@ -298,11 +302,10 @@ break; } } - p = (pos2 % sb->s_blocksize) + bh->b_data; pos2 += c; pos += c; written += c; - memcpy_fromfs (p, buf, c); + memcpy_fromfs (bh->b_data + offset, buf, c); buf += c; bh->b_uptodate = 1; mark_buffer_dirty(bh, 0); @@ -322,6 +325,9 @@ } if(write_error) break; + block++; + offset = 0; + c = sb->s_blocksize; } if ( buffercount ){ ll_rw_block(WRITE, buffercount, bufferlist); diff -u --recursive --new-file v1.3.8/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v1.3.8/linux/fs/ext2/inode.c Wed Mar 22 10:33:59 1995 +++ linux/fs/ext2/inode.c Mon Jul 10 17:08:03 1995 @@ -129,14 +129,15 @@ { int i; int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); if (block < 0) { ext2_warning (inode->i_sb, "ext2_bmap", "block < 0"); return 0; } if (block >= EXT2_NDIR_BLOCKS + addr_per_block + - addr_per_block * addr_per_block + - addr_per_block * addr_per_block * addr_per_block) { + (1 << (addr_per_block_bits * 2)) + + ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) { ext2_warning (inode->i_sb, "ext2_bmap", "block > big"); return 0; } @@ -151,29 +152,29 @@ inode->i_sb->s_blocksize), block); } block -= addr_per_block; - if (block < addr_per_block * addr_per_block) { + if (block < (1 << (addr_per_block_bits * 2))) { i = inode_bmap (inode, EXT2_DIND_BLOCK); if (!i) return 0; i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - block / addr_per_block); + block >> addr_per_block_bits); if (!i) return 0; return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), block & (addr_per_block - 1)); } - block -= addr_per_block * addr_per_block; + block -= (1 << (addr_per_block_bits * 2)); i = inode_bmap (inode, EXT2_TIND_BLOCK); if (!i) return 0; i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - block / (addr_per_block * addr_per_block)); + block >> (addr_per_block_bits * 2)); if (!i) return 0; i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - (block / addr_per_block) & (addr_per_block - 1)); + (block >> addr_per_block_bits) & (addr_per_block - 1)); if (!i) return 0; return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), @@ -335,10 +336,11 @@ if(!bh) return 0; - if(nr % (PAGE_SIZE / inode->i_sb->s_blocksize) != 0) goto out; + if((nr & ((PAGE_SIZE >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)) - 1)) != 0) + goto out; if(nr + 3 > EXT2_ADDR_PER_BLOCK(inode->i_sb)) goto out; - for(i=0; i< (PAGE_SIZE / inode->i_sb->s_blocksize); i++) { + for(i=0; i< (PAGE_SIZE >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); i++) { p = (u32 *) bh->b_data + nr + i; /* All blocks in cluster must already be allocated */ @@ -363,15 +365,16 @@ struct buffer_head * bh; unsigned long b; unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); *err = -EIO; if (block < 0) { ext2_warning (inode->i_sb, "ext2_getblk", "block < 0"); return NULL; } - if (block > EXT2_NDIR_BLOCKS + addr_per_block + - addr_per_block * addr_per_block + - addr_per_block * addr_per_block * addr_per_block) { + if (block > EXT2_NDIR_BLOCKS + addr_per_block + + (1 << (addr_per_block_bits * 2)) + + ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) { ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); return NULL; } @@ -401,18 +404,18 @@ inode->i_sb->s_blocksize, b, err); } block -= addr_per_block; - if (block < addr_per_block * addr_per_block) { + if (block < (1 << (addr_per_block_bits * 2))) { bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err); - bh = block_getblk (inode, bh, block / addr_per_block, create, - inode->i_sb->s_blocksize, b, err); + bh = block_getblk (inode, bh, block >> addr_per_block_bits, + create, inode->i_sb->s_blocksize, b, err); return block_getblk (inode, bh, block & (addr_per_block - 1), create, inode->i_sb->s_blocksize, b, err); } - block -= addr_per_block * addr_per_block; + block -= (1 << (addr_per_block_bits * 2)); bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err); - bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block), + bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2), create, inode->i_sb->s_blocksize, b, err); - bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1), + bh = block_getblk (inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1), create, inode->i_sb->s_blocksize, b, err); return block_getblk (inode, bh, block & (addr_per_block - 1), create, inode->i_sb->s_blocksize, b, err); @@ -424,6 +427,7 @@ int err, create; unsigned long b; unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); create = 0; err = -EIO; @@ -431,9 +435,9 @@ ext2_warning (inode->i_sb, "ext2_getblk", "block < 0"); return 0; } - if (block > EXT2_NDIR_BLOCKS + addr_per_block + - addr_per_block * addr_per_block + - addr_per_block * addr_per_block * addr_per_block) { + if (block > EXT2_NDIR_BLOCKS + addr_per_block + + (1 << (addr_per_block_bits * 2)) + + ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) { ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); return 0; } @@ -450,18 +454,18 @@ inode->i_sb->s_blocksize); } block -= addr_per_block; - if (block < addr_per_block * addr_per_block) { + if (block < (1 << (addr_per_block_bits * 2))) { bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, &err); - bh = block_getblk (inode, bh, block / addr_per_block, create, - inode->i_sb->s_blocksize, b, &err); + bh = block_getblk (inode, bh, block >> addr_per_block_bits, + create, inode->i_sb->s_blocksize, b, &err); return block_getcluster (inode, bh, block & (addr_per_block - 1), inode->i_sb->s_blocksize); } - block -= addr_per_block * addr_per_block; + block -= (1 << (addr_per_block_bits * 2)); bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, &err); - bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block), + bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2), create, inode->i_sb->s_blocksize, b, &err); - bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1), + bh = block_getblk (inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1), create, inode->i_sb->s_blocksize, b, &err); return block_getcluster (inode, bh, block & (addr_per_block - 1), inode->i_sb->s_blocksize); @@ -505,8 +509,8 @@ if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) ext2_panic (inode->i_sb, "ext2_read_inode", "group >= groups count"); - group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb); - desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb); + group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb); + desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1); bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc]; if (!bh) ext2_panic (inode->i_sb, "ext2_read_inode", @@ -514,13 +518,13 @@ gdp = (struct ext2_group_desc *) bh->b_data; block = gdp[desc].bg_inode_table + (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) - / EXT2_INODES_PER_BLOCK(inode->i_sb)); + >> EXT2_INODES_PER_BLOCK_BITS(inode->i_sb)); if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) ext2_panic (inode->i_sb, "ext2_read_inode", "unable to read i-node block - " "inode=%lu, block=%lu", inode->i_ino, block); raw_inode = ((struct ext2_inode *) bh->b_data) + - (inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb); + ((inode->i_ino - 1) & (EXT2_INODES_PER_BLOCK(inode->i_sb) - 1)); inode->i_mode = raw_inode->i_mode; inode->i_uid = raw_inode->i_uid; inode->i_gid = raw_inode->i_gid; @@ -596,8 +600,8 @@ if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) ext2_panic (inode->i_sb, "ext2_write_inode", "group >= groups count"); - group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb); - desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb); + group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb); + desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1); bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc]; if (!bh) ext2_panic (inode->i_sb, "ext2_write_inode", @@ -605,7 +609,7 @@ gdp = (struct ext2_group_desc *) bh->b_data; block = gdp[desc].bg_inode_table + (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) - / EXT2_INODES_PER_BLOCK(inode->i_sb)); + >> EXT2_INODES_PER_BLOCK_BITS(inode->i_sb)); if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) ext2_panic (inode->i_sb, "ext2_write_inode", "unable to read i-node block - " diff -u --recursive --new-file v1.3.8/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v1.3.8/linux/fs/ext2/namei.c Fri Jul 7 13:42:58 1995 +++ linux/fs/ext2/namei.c Mon Jul 10 17:08:04 1995 @@ -101,9 +101,7 @@ bh_read[toread++] = bh; } - block = 0; - offset = 0; - while (offset < dir->i_size) { + for (block = 0, offset = 0; offset < dir->i_size; block++) { struct buffer_head * bh; struct ext2_dir_entry * de; char * dlimit; @@ -113,9 +111,13 @@ toread = 0; } bh = bh_use[block % NAMEI_RA_SIZE]; - if (!bh) - ext2_panic (sb, "ext2_find_entry", - "buffer head pointer is NULL"); + if (!bh) { + ext2_error (sb, "ext2_find_entry", + "directory #%lu contains a hole at offset %lu", + dir->i_ino, offset); + offset += sb->s_blocksize; + continue; + } wait_on_buffer (bh); if (!bh->b_uptodate) { /* @@ -149,7 +151,7 @@ bh = NULL; else bh = ext2_getblk (dir, block + NAMEI_RA_SIZE, 0, &err); - bh_use[block++ % NAMEI_RA_SIZE] = bh; + bh_use[block % NAMEI_RA_SIZE] = bh; if (bh && !bh->b_uptodate) bh_read[toread++] = bh; } @@ -558,7 +560,8 @@ if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) || !(bh = ext2_bread (inode, 0, 0, &err))) { ext2_warning (inode->i_sb, "empty_dir", - "bad directory (dir %lu)", inode->i_ino); + "bad directory (dir #%lu) - no data block", + inode->i_ino); return 1; } de = (struct ext2_dir_entry *) bh->b_data; @@ -566,7 +569,8 @@ if (de->inode != inode->i_ino || !de1->inode || strcmp (".", de->name) || strcmp ("..", de1->name)) { ext2_warning (inode->i_sb, "empty_dir", - "bad directory (dir %lu)", inode->i_ino); + "bad directory (dir #%lu) - no `.' or `..'", + inode->i_ino); return 1; } offset = de->rec_len + de1->rec_len; @@ -576,6 +580,9 @@ brelse (bh); bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err); if (!bh) { + ext2_error (sb, "empty_dir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, offset); offset += sb->s_blocksize; continue; } diff -u --recursive --new-file v1.3.8/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v1.3.8/linux/fs/ext2/super.c Mon Jun 12 16:49:40 1995 +++ linux/fs/ext2/super.c Mon Jul 10 17:08:04 1995 @@ -15,6 +15,7 @@ #include +#include #include #include @@ -388,6 +389,8 @@ return 1; } +#define log2(n) ffz(~(n)) + struct super_block * ext2_read_super (struct super_block * sb, void * data, int silent) { @@ -439,8 +442,8 @@ MAJOR(dev), MINOR(dev)); return NULL; } - sb->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size; - sb->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(sb); + sb->s_blocksize_bits = sb->u.ext2_sb.s_es->s_log_block_size + 10; + sb->s_blocksize = 1 << sb->s_blocksize_bits; if (sb->s_blocksize != BLOCK_SIZE && (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || sb->s_blocksize == 4096)) { @@ -480,7 +483,6 @@ sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize / sizeof (struct ext2_group_desc); sb->u.ext2_sb.s_sbh = bh; - sb->u.ext2_sb.s_es = es; if (resuid != EXT2_DEF_RESUID) sb->u.ext2_sb.s_resuid = resuid; else @@ -492,6 +494,12 @@ sb->u.ext2_sb.s_mount_state = es->s_state; sb->u.ext2_sb.s_rename_lock = 0; sb->u.ext2_sb.s_rename_wait = NULL; + sb->u.ext2_sb.s_addr_per_block_bits = + log2 (EXT2_ADDR_PER_BLOCK(sb)); + sb->u.ext2_sb.s_inodes_per_block_bits = + log2 (EXT2_INODES_PER_BLOCK(sb)); + sb->u.ext2_sb.s_desc_per_block_bits = + log2 (EXT2_DESC_PER_BLOCK(sb)); #ifdef EXT2FS_PRE_02B_COMPAT if (sb->s_magic == EXT2_PRE_02B_MAGIC) { if (es->s_blocks_count > 262144) { diff -u --recursive --new-file v1.3.8/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c --- v1.3.8/linux/fs/ext2/truncate.c Wed Apr 5 12:59:50 1995 +++ linux/fs/ext2/truncate.c Mon Jul 10 17:08:04 1995 @@ -354,9 +354,10 @@ * zeroed in case it ever becomes accessible again because of * subsequent file growth. */ - offset = inode->i_size % inode->i_sb->s_blocksize; + offset = inode->i_size & (inode->i_sb->s_blocksize - 1); if (offset) { - bh = ext2_bread (inode, inode->i_size / inode->i_sb->s_blocksize, + bh = ext2_bread (inode, + inode->i_size >> EXT2_BLOCK_SIZE_BITS(inode->i_sb), 0, &err); if (bh) { memset (bh->b_data + offset, 0, diff -u --recursive --new-file v1.3.8/linux/fs/hpfs/Makefile linux/fs/hpfs/Makefile --- v1.3.8/linux/fs/hpfs/Makefile Sun Feb 5 14:44:32 1995 +++ linux/fs/hpfs/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -22,9 +20,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/isofs/Makefile linux/fs/isofs/Makefile --- v1.3.8/linux/fs/isofs/Makefile Tue Jan 10 17:02:17 1995 +++ linux/fs/isofs/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -25,9 +23,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v1.3.8/linux/fs/isofs/inode.c Mon Jun 12 16:49:40 1995 +++ linux/fs/isofs/inode.c Tue Jul 11 07:56:04 1995 @@ -2,6 +2,7 @@ * linux/fs/isofs/inode.c * * (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem. + * 1995 Mark Dobie - patch to allow VideoCD and PhotoCD mounting. * * (C) 1991 Linus Torvalds - minix filesystem */ @@ -425,6 +426,7 @@ void *cpnt = NULL; int high_sierra; int block; + int volume_seq_no ; int i; block = inode->i_ino >> ISOFS_BUFFER_BITS(inode); @@ -563,16 +565,23 @@ inode->i_op = NULL; - /* A volume number of 0 is nonsense. Disable checking if we see - this */ + /* get the volume sequence numner */ + volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ; + + /* + * Disable checking if we see any volume number other than 0 or 1. + * We could use the cruft option, but that has multiple purposes, one + * of which is limiting the file size to 16Mb. Thus we silently allow + * volume numbers of 0 to go through without complaining. + */ if (inode->i_sb->u.isofs_sb.s_cruft == 'n' && - isonum_723 (raw_inode->volume_sequence_number) == 0) { + (volume_seq_no != 0) && (volume_seq_no != 1)) { printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n"); inode->i_sb->u.isofs_sb.s_cruft = 'y'; } if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && - isonum_723 (raw_inode->volume_sequence_number) != 1) { + (volume_seq_no != 0) && (volume_seq_no != 1)) { printk("Multi volume CD somehow got mounted.\n"); } else { if (S_ISREG(inode->i_mode)) diff -u --recursive --new-file v1.3.8/linux/fs/isofs/namei.c linux/fs/isofs/namei.c --- v1.3.8/linux/fs/isofs/namei.c Wed Feb 22 08:15:14 1995 +++ linux/fs/isofs/namei.c Tue Jul 11 07:56:04 1995 @@ -178,8 +178,18 @@ dlen--; } } - match = isofs_match(namelen,name,dpnt,dlen); - if (cpnt) { + /* + * Skip hidden or associated files unless unhide is set + */ + match = 0; + if( !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5) + || dir->i_sb->u.isofs_sb.s_unhide == 'y' ) + { + match = isofs_match(namelen,name,dpnt,dlen); + } + + if (cpnt) + { kfree(cpnt); cpnt = NULL; } diff -u --recursive --new-file v1.3.8/linux/fs/minix/Makefile linux/fs/minix/Makefile --- v1.3.8/linux/fs/minix/Makefile Mon Jan 9 09:23:00 1995 +++ linux/fs/minix/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -25,9 +23,4 @@ modules: minix.o -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/msdos/Makefile linux/fs/msdos/Makefile --- v1.3.8/linux/fs/msdos/Makefile Tue Jan 10 17:02:18 1995 +++ linux/fs/msdos/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -25,9 +23,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/msdos/mmap.c linux/fs/msdos/mmap.c --- v1.3.8/linux/fs/msdos/mmap.c Mon Jan 23 10:38:29 1995 +++ linux/fs/msdos/mmap.c Mon Jul 10 17:08:04 1995 @@ -2,7 +2,7 @@ * fs/msdos/mmap.c * * Written by Jacques Gelinas (jacques@solucorp.qc.ca) - * Inspired by fs/nfs/mmap.c (Jaon Tombs 15 Aug 1993) + * Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993) * * msdos mmap handling */ diff -u --recursive --new-file v1.3.8/linux/fs/nfs/Makefile linux/fs/nfs/Makefile --- v1.3.8/linux/fs/nfs/Makefile Mon Jan 9 09:23:36 1995 +++ linux/fs/nfs/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -25,9 +23,4 @@ modules: nfs.o -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/nfs/mmap.c linux/fs/nfs/mmap.c --- v1.3.8/linux/fs/nfs/mmap.c Mon Jan 23 10:38:29 1995 +++ linux/fs/nfs/mmap.c Mon Jul 10 17:10:41 1995 @@ -73,9 +73,10 @@ #endif tmp = page + PAGE_SIZE; - while (clear--) { - *(char *)--tmp = 0; + if (clear > 0){ + memset ((char*)(tmp-clear),0,clear); } + return page; } diff -u --recursive --new-file v1.3.8/linux/fs/proc/Makefile linux/fs/proc/Makefile --- v1.3.8/linux/fs/proc/Makefile Thu Jun 29 19:02:54 1995 +++ linux/fs/proc/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -22,9 +20,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/proc/scsi.c linux/fs/proc/scsi.c --- v1.3.8/linux/fs/proc/scsi.c Fri Jul 7 08:54:52 1995 +++ linux/fs/proc/scsi.c Tue Jul 11 07:56:04 1995 @@ -8,12 +8,13 @@ * * /proc/scsi directory handling functions * - * last change: 95/06/13 + * last change: 95/07/04 * * Initial version: March '95 - * 95/15/05 Added subdirectories for each driver and show every + * 95/05/15 Added subdirectories for each driver and show every * registered HBA as a single file. - * 95/30/05 Added rudimentary write support for parameter passing + * 95/05/30 Added rudimentary write support for parameter passing + * 95/07/04 Fixed bugs in directory handling * * TODO: Improve support to write to the driver files * Optimize directory handling @@ -96,13 +97,17 @@ (uint) *num = flag = index = 0; - if(dispatch_scsi_info_ptr) - { + if(dispatch_scsi_info_ptr) { if (inode == PROC_SCSI) { dir = scsi_dir; while(dir[(uint)*num].low_ino) (*num)++; } else { + /* Here we do not simply count the entries. Since the array + * contains the directories of all drivers, we need to return + * a pointer to the beginning of the directory information + * and its length. + */ dir = scsi_hba_dir; while(dir[index].low_ino || dir[index].low_ino <= PROC_SCSI_LAST) { if(dir[index].low_ino == inode) @@ -140,8 +145,7 @@ iput(dir); return(-ENOENT); } - if (dispatch_scsi_info_ptr != NULL) - { + if (dispatch_scsi_info_ptr != NULL) { if (dir->i_ino <= PROC_SCSI_SCSI) de = scsi_dir; else { @@ -170,7 +174,7 @@ struct proc_dir_entry * de; uint index, num; - index = num = 0; + num = 0; if (!inode || !S_ISDIR(inode->i_mode)) return(-EBADF); @@ -221,7 +225,6 @@ static int proc_readscsi(struct inode * inode, struct file * file, char * buf, int count) { - uint ino; int length; int bytes = count; int copied = 0; @@ -235,18 +238,14 @@ * end of the file */ if (!(page = (char *) __get_free_page(GFP_KERNEL))) return(-ENOMEM); - ino = inode->i_ino; - - while(bytes > 0 || count == -1) - { - + while(bytes > 0 || count == -1) { thistime = bytes; if(bytes > PROC_BLOCK_SIZE || count == -1) thistime = PROC_BLOCK_SIZE; if(dispatch_scsi_info_ptr) - length = dispatch_scsi_info_ptr(ino, page, &start, + length = dispatch_scsi_info_ptr(inode->i_ino, page, &start, file->f_pos, thistime, 0); else length = get_not_present_info(page, &start, file->f_pos, thistime); diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/Makefile linux/fs/smbfs/Makefile --- v1.3.8/linux/fs/smbfs/Makefile Fri Jul 7 08:54:52 1995 +++ linux/fs/smbfs/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -25,9 +23,4 @@ modules: smbfs.o -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c --- v1.3.8/linux/fs/smbfs/dir.c Fri Jul 7 08:54:52 1995 +++ linux/fs/smbfs/dir.c Mon Jul 10 08:28:00 1995 @@ -554,11 +554,10 @@ } } -int +void smb_init_root(struct smb_server *server) { struct smb_inode_info *root = &(server->root); - int result; root->finfo.path = server->m.root_path; root->finfo.len = strlen(root->finfo.path); @@ -568,6 +567,14 @@ root->nused = 1; root->dir = NULL; root->next = root->prev = root; + return; +} + +int +smb_stat_root(struct smb_server *server) +{ + struct smb_inode_info *root = &(server->root); + int result; if (root->finfo.len == 0) { result = smb_proc_getattr(server, "\\", 1, &(root->finfo)); @@ -776,6 +783,8 @@ entry.attr = 0; entry.ctime = CURRENT_TIME; + entry.atime = CURRENT_TIME; + entry.mtime = CURRENT_TIME; entry.size = 0; error = smb_proc_create(SMB_SERVER(dir), path, len, &entry); diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/file.c linux/fs/smbfs/file.c --- v1.3.8/linux/fs/smbfs/file.c Fri Jul 7 08:54:52 1995 +++ linux/fs/smbfs/file.c Mon Jul 10 08:28:00 1995 @@ -119,6 +119,9 @@ file->f_pos = pos; + if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->path); return already_read; @@ -177,6 +180,9 @@ break; } } + + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; file->f_pos = pos; diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v1.3.8/linux/fs/smbfs/inode.c Fri Jul 7 08:54:52 1995 +++ linux/fs/smbfs/inode.c Mon Jul 10 08:28:00 1995 @@ -250,6 +250,8 @@ server->m.dir_mode = (server->m.dir_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR; + smb_init_root(server); + /* * Make the connection to the server */ @@ -278,19 +280,19 @@ goto fail; } + if ((error = smb_stat_root(server)) < 0) { + sb->s_dev = 0; + printk("smb_read_super: could not get root dir attributes\n"); + smb_kfree_s(server->packet, server->max_xmit); + goto fail; + } + DPRINTK("smb_read_super : %u %u %u %u\n", SMB_SBP(sb)->s_attr.total, SMB_SBP(sb)->s_attr.blocksize, SMB_SBP(sb)->s_attr.allocblocks, SMB_SBP(sb)->s_attr.free); - if (smb_init_root(server) != 0) { - sb->s_dev = 0; - printk("smb_read_super: invalid root directory\n"); - smb_kfree_s(server->packet, server->max_xmit); - goto fail; - } - DPRINTK("smb_read_super: SMB_SBP(sb) = %x\n", (int)SMB_SBP(sb)); if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) { @@ -406,7 +408,7 @@ #ifdef MODULE -static char kernel_version[] = UTS_RELEASE; +char kernel_version[] = UTS_RELEASE; /* looks ugly, taken from gcc-info */ static void *shut_up_gcc = (&shut_up_gcc, kernel_version); diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c --- v1.3.8/linux/fs/smbfs/sock.c Fri Jul 7 08:54:52 1995 +++ linux/fs/smbfs/sock.c Sat Jul 8 09:21:45 1995 @@ -22,7 +22,7 @@ #include #include #include -#include "/usr/src/linux/include/net/ip.h" +#include #include #include diff -u --recursive --new-file v1.3.8/linux/fs/sysv/Makefile linux/fs/sysv/Makefile --- v1.3.8/linux/fs/sysv/Makefile Tue Jan 10 17:02:18 1995 +++ linux/fs/sysv/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -26,9 +24,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/umsdos/Makefile linux/fs/umsdos/Makefile --- v1.3.8/linux/fs/umsdos/Makefile Tue Jan 10 17:02:18 1995 +++ linux/fs/umsdos/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -35,9 +33,4 @@ doc: nadoc -i -p umsdos.doc - /tmp/umsdos.mpg -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/fs/xiafs/Makefile linux/fs/xiafs/Makefile --- v1.3.8/linux/fs/xiafs/Makefile Tue Jan 10 17:02:18 1995 +++ linux/fs/xiafs/Makefile Tue Jul 11 08:02:20 1995 @@ -7,8 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -.c.s: - $(CC) $(CFLAGS) -S $< .c.o: $(CC) $(CFLAGS) -c $< .s.o: @@ -26,9 +24,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/include/asm-alpha/socket.h linux/include/asm-alpha/socket.h --- v1.3.8/linux/include/asm-alpha/socket.h Fri Jul 7 13:42:58 1995 +++ linux/include/asm-alpha/socket.h Mon Jul 10 16:59:58 1995 @@ -1,6 +1,19 @@ #ifndef _ASM_SOCKET_H #define _ASM_SOCKET_H +#include +#include + +/* Socket-level I/O control calls. */ +#define FIOGETOWN _IOR('f', 123, int) +#define FIOSETOWN _IOW('f', 124, int) + +#define SIOCATMARK _IOR('s', 7, int) +#define SIOCSPGRP _IOW('s', 8, pid_t) +#define SIOCGPGRP _IOR('s', 9, pid_t) + +#define SIOCGSTAMP 0x8906 /* Get stamp - linux-specific */ + /* For setsockoptions(2) */ /* * Note: we only bother about making the SOL_SOCKET options diff -u --recursive --new-file v1.3.8/linux/include/asm-i386/socket.h linux/include/asm-i386/socket.h --- v1.3.8/linux/include/asm-i386/socket.h Fri Jul 7 13:42:58 1995 +++ linux/include/asm-i386/socket.h Mon Jul 10 16:59:58 1995 @@ -1,6 +1,14 @@ #ifndef _ASM_SOCKET_H #define _ASM_SOCKET_H +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp */ + /* For setsockoptions(2) */ #define SOL_SOCKET 1 diff -u --recursive --new-file v1.3.8/linux/include/linux/aztcd.h linux/include/linux/aztcd.h --- v1.3.8/linux/include/linux/aztcd.h Sun Mar 26 11:56:23 1995 +++ linux/include/linux/aztcd.h Mon Jul 10 08:00:56 1995 @@ -1,4 +1,4 @@ -/* $Id: aztcd.h,v 1.0 1995/03/25 08:27:19 root Exp $ +/* $Id: aztcd.h,v 1.30 1995/07/04 08:28:17 root Exp $ * Definitions for a AztechCD268 CD-ROM interface * Copyright (C) 1994, 1995 Werner Zimmermann * @@ -22,12 +22,29 @@ * October 1994 Email: zimmerma@rz.fht-esslingen.de */ -/* *** change this to set the I/O port address */ +/* *** change this to set the I/O port address of your CD-ROM drive*/ #define AZT_BASE_ADDR 0x320 -/* Comment this out to prevent tray from locking */ +/* Uncomment this, if your CDROM is connected to a Soundwave32-soundcard + and configure AZT_BASE_ADDR and AZT_SW32_BASE_ADDR */ +/*#define AZT_SW32 1 +*/ + +#ifdef AZT_SW32 +#define AZT_SW32_BASE_ADDR 0x220 /*I/O port base adress of your soundcard*/ +#endif + +/* Set this to 1, if you want your tray to be locked, set to 0 to prevent tray + from locking */ #define AZT_ALLOW_TRAY_LOCK 1 +/*Set this to 1 to allow auto-eject when unmounting a disk, set to 0, if you + don't want the auto-eject feature*/ +#define AZT_AUTO_EJECT 0 + +/*---------------------------------------------------------------------------*/ +/*------------nothing to be configured below this line-----------------------*/ + /* use incompatible ioctls for reading in raw and cooked mode */ #define AZT_PRIVATE_IOCTLS @@ -45,6 +62,11 @@ #define DATA_PORT azt_port #define STATUS_PORT azt_port+1 #define MODE_PORT azt_port+2 +#ifdef AZT_SW32 + #define AZT_SW32_INIT (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16)) + #define AZT_SW32_CONFIG_REG AZT_SW32_BASE_ADDR+0x16 /*Soundwave32 Config. Register*/ + #define AZT_SW32_ID_REG AZT_SW32_BASE_ADDR+0x04 /*Soundwave32 ID Version Register*/ +#endif /* status bits */ #define AST_CMD_CHECK 0x80 /* command error */ @@ -83,13 +105,6 @@ #define ACMD_SET_VOLUME 0x93 /* set audio level */ #define ACMD_GET_VERSION 0xA0 /* get firmware version */ #define ACMD_SET_MODE 0xA1 /* set drive mode */ - -#define SET_TIMER(func, jifs) \ - delay_timer.expires = jifs; \ - delay_timer.function = (void *) func; \ - add_timer(&delay_timer); - -#define CLEAR_TIMER del_timer(&delay_timer) #define MAX_TRACKS 104 diff -u --recursive --new-file v1.3.8/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v1.3.8/linux/include/linux/cdrom.h Fri Jul 7 08:54:53 1995 +++ linux/include/linux/cdrom.h Tue Jul 11 07:56:04 1995 @@ -404,7 +404,7 @@ #define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ /* * preliminary extension for enable (1) / disable (0) auto-ejecting - * currently used by sbpcd.c + * currently used by sbpcd.c and sr.c * (still may change if other drivers will use it, too): */ #define CDROMEJECT_SW 0x530f /* arg: 0 or 1 */ diff -u --recursive --new-file v1.3.8/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h --- v1.3.8/linux/include/linux/etherdevice.h Fri Jun 30 16:22:30 1995 +++ linux/include/linux/etherdevice.h Mon Jul 10 17:08:05 1995 @@ -34,6 +34,8 @@ extern int eth_rebuild_header(void *buff, struct device *dev, unsigned long dst, struct sk_buff *skb); extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev); +extern void eth_copy_and_sum(struct sk_buff *dest, + unsigned char *src, int length, int base); #endif diff -u --recursive --new-file v1.3.8/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v1.3.8/linux/include/linux/ext2_fs.h Mon Jun 12 16:49:41 1995 +++ linux/include/linux/ext2_fs.h Mon Jul 10 17:08:04 1995 @@ -50,8 +50,8 @@ /* * The second extended file system version */ -#define EXT2FS_DATE "95/03/19" -#define EXT2FS_VERSION "0.5a" +#define EXT2FS_DATE "95/07/02" +#define EXT2FS_VERSION "0.5b" /* * Debug code @@ -102,11 +102,15 @@ #define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) #ifdef __KERNEL__ -# define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10) +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) #else # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) #endif #define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode)) +#ifdef __KERNEL__ +#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits) +#define EXT2_INODES_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_inodes_per_block_bits) +#endif /* * Macro-instructions used to manage fragments @@ -175,6 +179,7 @@ # define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group) # define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block) # define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group) +# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits) #else # define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) # define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) diff -u --recursive --new-file v1.3.8/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h --- v1.3.8/linux/include/linux/ext2_fs_sb.h Wed Mar 22 10:33:59 1995 +++ linux/include/linux/ext2_fs_sb.h Mon Jul 10 17:08:04 1995 @@ -53,6 +53,10 @@ unsigned short s_resuid; unsigned short s_resgid; unsigned short s_mount_state; + unsigned short s_pad; + int s_addr_per_block_bits; + int s_inodes_per_block_bits; + int s_desc_per_block_bits; }; #endif /* _LINUX_EXT2_FS_SB */ diff -u --recursive --new-file v1.3.8/linux/include/linux/genhd.h linux/include/linux/genhd.h --- v1.3.8/linux/include/linux/genhd.h Fri Jul 7 08:54:53 1995 +++ linux/include/linux/genhd.h Mon Jul 10 17:08:05 1995 @@ -16,6 +16,9 @@ #endif #define EXTENDED_PARTITION 5 + +#define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */ +#define DM6_AUXPARTITION 0x51 /* no DDO: use xlated geom */ struct partition { unsigned char boot_ind; /* 0x80 - active */ diff -u --recursive --new-file v1.3.8/linux/include/linux/hdreg.h linux/include/linux/hdreg.h --- v1.3.8/linux/include/linux/hdreg.h Thu Jun 1 11:23:04 1995 +++ linux/include/linux/hdreg.h Mon Jul 10 17:08:05 1995 @@ -79,6 +79,7 @@ #define HDIO_GET_IDENTITY 0x307 /* get IDE identification info */ #define HDIO_GET_KEEPSETTINGS 0x308 /* get keep-settings-on-reset flag */ #define HDIO_GET_CHIPSET 0x309 /* get current interface type setting */ +#define HDIO_GET_NOWERR 0x30a /* get ignore-write-error flag */ #define HDIO_DRIVE_CMD 0x31f /* execute a special drive command */ /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x32n/0x33n */ @@ -86,6 +87,7 @@ #define HDIO_SET_UNMASKINTR 0x322 /* permit other irqs during I/O */ #define HDIO_SET_KEEPSETTINGS 0x323 /* keep ioctl settings on reset */ #define HDIO_SET_CHIPSET 0x324 /* optimise driver for interface type */ +#define HDIO_SET_NOWERR 0x325 /* set ignore-write-error flag */ /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */ struct hd_driveid { diff -u --recursive --new-file v1.3.8/linux/include/linux/mcdx.h linux/include/linux/mcdx.h --- v1.3.8/linux/include/linux/mcdx.h Fri Jul 7 08:54:54 1995 +++ linux/include/linux/mcdx.h Mon Jul 10 17:08:04 1995 @@ -23,7 +23,7 @@ * Eberhard Moenkeberg (he gave me much support and the initial kick) * Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they * improved the original driver) - * John Tombs, Bjorn Ekwall (module support) + * Jon Tombs, Bjorn Ekwall (module support) * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) * Gerd Knorr (he lent me his PhotoCD) * Nils Faerber and Roger E. Wolff (extensivly tested the LU portion) diff -u --recursive --new-file v1.3.8/linux/include/linux/pci.h linux/include/linux/pci.h --- v1.3.8/linux/include/linux/pci.h Thu Jun 29 19:02:55 1995 +++ linux/include/linux/pci.h Mon Jul 10 17:08:03 1995 @@ -218,6 +218,8 @@ #define PCI_DEVICE_ID_INTEL_82430 0x0486 #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371 0x122e +#define PCI_DEVICE_ID_INTEL_82438 0x1230 +#define PCI_DEVICE_ID_INTEL_7116 0x1223 #define PCI_VENDOR_ID_SMC 0x1042 #define PCI_DEVICE_ID_SMC_37C665 0x1000 diff -u --recursive --new-file v1.3.8/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h --- v1.3.8/linux/include/linux/smb_fs.h Fri Jul 7 08:54:54 1995 +++ linux/include/linux/smb_fs.h Mon Jul 10 08:28:01 1995 @@ -104,7 +104,8 @@ extern struct inode_operations smb_dir_inode_operations; void smb_free_inode_info(struct smb_inode_info *i); void smb_free_all_inodes(struct smb_server *server); -int smb_init_root(struct smb_server *server); +void smb_init_root(struct smb_server *server); +int smb_stat_root(struct smb_server *server); void smb_init_dir_cache(void); void smb_invalid_dir_cache(unsigned long ino); void smb_invalidate_all_inodes(struct smb_server *server); diff -u --recursive --new-file v1.3.8/linux/include/linux/sockios.h linux/include/linux/sockios.h --- v1.3.8/linux/include/linux/sockios.h Tue Jan 24 15:27:55 1995 +++ linux/include/linux/sockios.h Mon Jul 10 16:59:58 1995 @@ -18,16 +18,6 @@ #ifndef _LINUX_SOCKIOS_H #define _LINUX_SOCKIOS_H -/* This section will go away soon! */ - -/* Socket-level I/O control calls. */ -#define FIOSETOWN 0x8901 -#define SIOCSPGRP 0x8902 -#define FIOGETOWN 0x8903 -#define SIOCGPGRP 0x8904 -#define SIOCATMARK 0x8905 -#define SIOCGSTAMP 0x8906 /* Get stamp */ - /* Routing table calls. */ #define SIOCADDRT 0x890B /* add routing table entry */ #define SIOCDELRT 0x890C /* delete routing table entry */ diff -u --recursive --new-file v1.3.8/linux/include/linux/soundcard.h linux/include/linux/soundcard.h --- v1.3.8/linux/include/linux/soundcard.h Mon Mar 6 11:22:08 1995 +++ linux/include/linux/soundcard.h Tue Jun 27 14:36:53 1995 @@ -35,12 +35,21 @@ * Regards, * Hannu Savolainen * hannu@voxware.pp.fi + * + ********************************************************************** + * PS. The Hacker's Guide to VoxWare available from + * nic.funet.fi:pub/OS/Linux/ALPHA/sound. The file is + * snd-sdk-doc-0.1.ps.gz (gzipped postscript). It contains + * some useful information about programming with VoxWare. + * (NOTE! The pub/OS/Linux/ALPHA/ directories are hidden. You have + * to cd inside them before the files are accessible.) + ********************************************************************** */ -#define SOUND_VERSION 300 +#define SOUND_VERSION 301 #define VOXWARE -#include +#include /* * Supported card ID numbers (Should be somewhere else?) @@ -58,6 +67,14 @@ #define SNDCARD_MSS 10 #define SNDCARD_PSS 11 #define SNDCARD_SSCAPE 12 +#define SNDCARD_PSS_MPU 13 +#define SNDCARD_PSS_MSS 14 +#define SNDCARD_SSCAPE_MSS 15 +#define SNDCARD_TRXPRO 16 +#define SNDCARD_TRXPRO_SB 17 +#define SNDCARD_TRXPRO_MPU 18 +#define SNDCARD_MAD16 19 +#define SNDCARD_MAD16_MPU 20 /*********************************** * IOCTL Commands for /dev/sequencer @@ -99,11 +116,16 @@ #define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int) #define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int) #define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info) -#define SNDCTL_SEQ_TRESHOLD _IOW ('Q',13, int) +#define SNDCTL_SEQ_THRESHOLD _IOW ('Q',13, int) #define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */ #define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */ #define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info) #define SNDCTL_SEQ_PANIC _IO ('Q',17) +#define SNDCTL_SEQ_OUTOFBAND _IOW ('Q',18, struct seq_event_rec) + + struct seq_event_rec { + unsigned char arr[8]; + }; #define SNDCTL_TMR_TIMEBASE _IOWR('T', 1, int) #define SNDCTL_TMR_START _IO ('T', 2) @@ -124,7 +146,7 @@ * Sample loading mechanism for internal synthesizers (/dev/sequencer) * The following patch_info structure has been designed to support * Gravis UltraSound. It tries to be universal format for uploading - * sample based patches but is probably too limited. + * sample based patches but is propably too limited. */ struct patch_info { @@ -211,6 +233,7 @@ struct sysex_info { short key; /* Use GUS_PATCH here */ #define SYSEX_PATCH 0x05fd +#define MAUI_PATCH 0x06fd /* For future use */ short device_no; /* Synthesizer number */ long len; /* Size of the sysex data in bytes */ unsigned char data[1]; /* Sysex data starts here */ @@ -343,14 +366,8 @@ * controllers. * In the MIDI 1.0 these controllers are sent using * two messages. Controller numbers 0 to 31 are used - * to send the LSB and the controller numbers 32 to 63 - * are for the LSB. - * - * This driver uses just the numbers 0 to 31 to store both - * the LSB and MSB. The controller value is a unsigned short - * and its valid range is between 0 and 16383 (0x0000 to 0x3fff). - * The driver sends the controller value using two messages when - * necessary. + * to send the MSB and the controller numbers 32 to 63 + * are for the LSB. Note that just 7 bits are used in MIDI bytes. */ #define CTL_BANK_SELECT 0x00 @@ -557,6 +574,22 @@ # define AFMT_S8 0x00000040 # define AFMT_U16_LE 0x00000080 /* Little endian U16 */ # define AFMT_U16_BE 0x00000100 /* Big endian U16 */ +# define AFMT_MPEG 0x00000200 /* MPEG (2) audio */ + +/* + * Buffer status queries. + */ +typedef struct audio_buf_info { + int fragments; /* # of available fragments (partially usend ones not counted) */ + int fragsize; /* Size of a fragment in bytes */ + + int bytes; /* Available space in bytes (includes partially used fragments) */ + /* Note! 'bytes' could be more than fragments*fragsize */ + } audio_buf_info; + +#define SNDCTL_DSP_GETOSPACE _IOR ('P',12, audio_buf_info) +#define SNDCTL_DSP_GETISPACE _IOR ('P',13, audio_buf_info) +#define SNDCTL_DSP_NONBLOCK _IO ('P',14) #define SOUND_PCM_READ_RATE _IOR ('P', 2, int) #define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int) @@ -573,21 +606,50 @@ #define SOUND_PCM_SETFRAGMENT SNDCTL_DSP_SETFRAGMENT #define SOUND_PCM_GETFMTS SNDCTL_DSP_GETFMTS #define SOUND_PCM_SETFMT SNDCTL_DSP_SETFMT - -/********************************************* - * IOCTL /dev/pss (experimental PSS API by marc.hoffman@analog.com. - * likely to change in near future. - */ -#define SNDCTL_PSS_RESET _IO ('C', 0) -#define SNDCTL_PSS_SETUP_REGISTERS _IO ('C', 1) -#define SNDCTL_PSS_SPEAKER _IOW ('C', 2, struct pss_speaker) - -struct pss_speaker { - int volume; - int bass; - int treb; - int mode; -}; +#define SOUND_PCM_GETOSPACE SNDCTL_DSP_GETOSPACE +#define SOUND_PCM_GETISPACE SNDCTL_DSP_GETISPACE +#define SOUND_PCM_NONBLOCK SNDCTL_DSP_NONBLOCK + +/* + * ioctl calls to be used in communication with coprocessors and + * DSP chips. + */ + +typedef struct copr_buffer { + int command; /* Set to 0 if not used */ + int flags; +#define CPF_NONE 0x0000 +#define CPF_FIRST 0x0001 /* First block */ +#define CPF_LAST 0x0002 /* Last block */ + int len; + int offs; /* If required by the device (0 if not used) */ + + unsigned char data[4000]; /* NOTE! 4000 is not 4k */ + } copr_buffer; + +typedef struct copr_debug_buf { + int command; /* Used internally. Set to 0 */ + int parm1; + int parm2; + int flags; + int len; /* Length of data in bytes */ + } copr_debug_buf; + +typedef struct copr_msg { + int len; + unsigned char data[4000]; + } copr_msg; + +#define SNDCTL_COPR_RESET _IO ('C', 0) +#define SNDCTL_COPR_LOAD _IOWR('C', 1, copr_buffer) +#define SNDCTL_COPR_RDATA _IOWR('C', 2, copr_debug_buf) +#define SNDCTL_COPR_RCODE _IOWR('C', 3, copr_debug_buf) +#define SNDCTL_COPR_WDATA _IOW ('C', 4, copr_debug_buf) +#define SNDCTL_COPR_WCODE _IOW ('C', 5, copr_debug_buf) +#define SNDCTL_COPR_RUN _IOWR('C', 6, copr_debug_buf) +#define SNDCTL_COPR_HALT _IOWR('C', 7, copr_debug_buf) +#define SNDCTL_COPR_SENDMSG _IOW ('C', 8, copr_msg) +#define SNDCTL_COPR_RCVMSG _IOR ('C', 9, copr_msg) /********************************************* * IOCTL commands for /dev/mixer @@ -602,7 +664,7 @@ * the devices supported by the particular mixer. */ -#define SOUND_MIXER_NRDEVICES 12 +#define SOUND_MIXER_NRDEVICES 17 #define SOUND_MIXER_VOLUME 0 #define SOUND_MIXER_BASS 1 #define SOUND_MIXER_TREBLE 2 @@ -615,6 +677,17 @@ #define SOUND_MIXER_IMIX 9 /* Recording monitor */ #define SOUND_MIXER_ALTPCM 10 #define SOUND_MIXER_RECLEV 11 /* Recording level */ +#define SOUND_MIXER_IGAIN 12 /* Input gain */ +#define SOUND_MIXER_OGAIN 13 /* Output gain */ +/* + * The AD1848 codec and compatibles have three line level inputs + * (line, aux1 and aux2). Since each card manufacturer have assigned + * different meanings to these inputs, it's inpractical to assign + * specific meanings (line, cd, synth etc.) to them. + */ +#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */ +#define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */ +#define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */ /* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */ /* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */ @@ -627,10 +700,12 @@ /* Note! Number 31 cannot be used since the sign bit is reserved */ #define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ - "Mic ", "CD ", "Mix ", "Pcm2 ", "rec"} + "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \ + "Line1", "Line2", "Line3"} #define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \ - "mic", "cd", "mix", "pcm2", "rec"} + "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \ + "line1", "line2", "line3"} /* Device bitmask identifiers */ @@ -655,6 +730,11 @@ #define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX) #define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM) #define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV) +#define SOUND_MASK_IGAIN (1 << SOUND_MIXER_IGAIN) +#define SOUND_MASK_OGAIN (1 << SOUND_MIXER_OGAIN) +#define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1) +#define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2) +#define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3) #define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) #define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) @@ -673,6 +753,11 @@ #define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX) #define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM) #define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_READ_IGAIN MIXER_READ(SOUND_MIXER_IGAIN) +#define SOUND_MIXER_READ_OGAIN MIXER_READ(SOUND_MIXER_OGAIN) +#define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1) +#define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2) +#define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3) #define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) #define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) @@ -696,6 +781,11 @@ #define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX) #define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM) #define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_WRITE_IGAIN MIXER_WRITE(SOUND_MIXER_IGAIN) +#define SOUND_MIXER_WRITE_OGAIN MIXER_WRITE(SOUND_MIXER_OGAIN) +#define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1) +#define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2) +#define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3) #define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) #define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) @@ -922,7 +1012,7 @@ #endif /* - * Timing and synchronization macros + * Timing and syncronization macros */ #define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ diff -u --recursive --new-file v1.3.8/linux/include/linux/ultrasound.h linux/include/linux/ultrasound.h --- v1.3.8/linux/include/linux/ultrasound.h Wed Aug 10 19:26:44 1994 +++ linux/include/linux/ultrasound.h Fri Mar 3 12:03:07 1995 @@ -52,7 +52,7 @@ * _GUS_VOICEOFF - Stops voice (no parameters) * _GUS_VOICEFADE - Stops the voice smoothly. * _GUS_VOICEMODE - Alters the voice mode, don't start or stop voice (P1=voice mode) - * _GUS_VOICEBALA - Sets voice balance (P1, 0=left, 7=middle and 15=right, default 7) + * _GUS_VOICEBALA - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7) * _GUS_VOICEFREQ - Sets voice (sample) playback frequency (P1=Hz) * _GUS_VOICEVOL - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) * _GUS_VOICEVOL2 - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) diff -u --recursive --new-file v1.3.8/linux/ipc/Makefile linux/ipc/Makefile --- v1.3.8/linux/ipc/Makefile Wed Jan 4 21:16:06 1995 +++ linux/ipc/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS = util.o SRCS = util.c @@ -29,11 +27,5 @@ $(CPP) -M $(SRCS) > .depend modules: -dummy: -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/ipc/msg.c linux/ipc/msg.c --- v1.3.8/linux/ipc/msg.c Tue Jun 27 14:11:47 1995 +++ linux/ipc/msg.c Tue Jul 11 07:49:01 1995 @@ -105,7 +105,7 @@ msq->msg_stime = CURRENT_TIME; if (msq->rwait) wake_up (&msq->rwait); - return msgsz; + return 0; } asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, diff -u --recursive --new-file v1.3.8/linux/kernel/Makefile linux/kernel/Makefile --- v1.3.8/linux/kernel/Makefile Fri Jul 7 08:54:56 1995 +++ linux/kernel/Makefile Tue Jul 11 08:02:20 1995 @@ -9,8 +9,6 @@ .S.s: $(CPP) -traditional $< -o $*.s -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -o $*.o $< .c.o: @@ -36,13 +34,6 @@ dep: $(CPP) -M *.c > .depend -dummy: modules: -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/kernel/exec_domain.c linux/kernel/exec_domain.c --- v1.3.8/linux/kernel/exec_domain.c Mon Jan 23 23:04:10 1995 +++ linux/kernel/exec_domain.c Tue Jul 11 07:56:04 1995 @@ -28,6 +28,27 @@ static asmlinkage void no_lcall7(struct pt_regs * regs) { + + /* + * This may have been a static linked SVr4 binary, so we would have the + * personality set incorrectly. Check to see whether SVr4 is available, + * and use it, otherwise give the user a SEGV. + */ + if (current->exec_domain && current->exec_domain->use_count) + (*current->exec_domain->use_count)--; + + current->personality = PER_SVR4; + current->exec_domain = lookup_exec_domain(current->personality); + + if (current->exec_domain && current->exec_domain->use_count) + (*current->exec_domain->use_count)++; + + if (current->exec_domain && current->exec_domain->handler + && current->exec_domain->handler != no_lcall7) { + current->exec_domain->handler(regs); + return; + } + send_sig(SIGSEGV, current, 1); } diff -u --recursive --new-file v1.3.8/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.3.8/linux/kernel/ksyms.c Fri Jul 7 13:42:58 1995 +++ linux/kernel/ksyms.c Tue Jul 11 07:56:04 1995 @@ -68,6 +68,8 @@ extern void *sys_call_table; +extern int aout_core_dump(long signr, struct pt_regs * regs); + #ifdef CONFIG_FTAPE extern char * ftape_big_buffer; #endif diff -u --recursive --new-file v1.3.8/linux/kernel/signal.c linux/kernel/signal.c --- v1.3.8/linux/kernel/signal.c Fri Jun 30 16:22:30 1995 +++ linux/kernel/signal.c Mon Jul 10 07:43:21 1995 @@ -147,12 +147,10 @@ if (err) return err; memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); + new_sa.sa_mask |= _S(signum); if (new_sa.sa_flags & SA_NOMASK) - new_sa.sa_mask = 0; - else { - new_sa.sa_mask |= _S(signum); - new_sa.sa_mask &= _BLOCKABLE; - } + new_sa.sa_mask &= ~_S(signum); + new_sa.sa_mask &= _BLOCKABLE; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) diff -u --recursive --new-file v1.3.8/linux/lib/Makefile linux/lib/Makefile --- v1.3.8/linux/lib/Makefile Mon Jan 16 07:17:38 1995 +++ linux/lib/Makefile Tue Jul 11 08:02:20 1995 @@ -6,8 +6,6 @@ # unless it's something special (ie not a .c file). # -.c.s: - $(CC) $(CFLAGS) -S $< .s.o: $(AS) -c -o $*.o $< .c.o: @@ -24,10 +22,4 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/mm/Makefile linux/mm/Makefile --- v1.3.8/linux/mm/Makefile Wed Jan 11 21:21:06 1995 +++ linux/mm/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS = memory.o swap.o mmap.o filemap.o mprotect.o kmalloc.o vmalloc.o @@ -24,9 +22,5 @@ dep: $(CPP) -M *.c > .depend -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/802/Makefile linux/net/802/Makefile --- v1.3.8/linux/net/802/Makefile Tue Jun 6 12:59:13 1995 +++ linux/net/802/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS := p8023.o @@ -47,9 +45,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/Makefile linux/net/Makefile --- v1.3.8/linux/net/Makefile Thu Jun 29 19:02:55 1995 +++ linux/net/Makefile Tue Jul 11 08:02:20 1995 @@ -15,8 +15,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS = socket.o protocols.o @@ -35,12 +33,4 @@ modules: -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/appletalk/Makefile linux/net/appletalk/Makefile --- v1.3.8/linux/net/appletalk/Makefile Tue Jun 6 12:59:13 1995 +++ linux/net/appletalk/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS := aarp.o ddp.o @@ -27,9 +25,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/ax25/Makefile linux/net/ax25/Makefile --- v1.3.8/linux/net/ax25/Makefile Tue Jun 6 12:59:13 1995 +++ linux/net/ax25/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS := af_ax25.o @@ -32,9 +30,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/core/Makefile linux/net/core/Makefile --- v1.3.8/linux/net/core/Makefile Tue Jun 6 12:59:13 1995 +++ linux/net/core/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS := sock.o dev.o dev_mcast.o skbuff.o datagram.o @@ -35,9 +33,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/ethernet/Makefile linux/net/ethernet/Makefile --- v1.3.8/linux/net/ethernet/Makefile Tue Jun 6 12:59:13 1995 +++ linux/net/ethernet/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS := eth.o @@ -49,9 +47,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/ethernet/eth.c linux/net/ethernet/eth.c --- v1.3.8/linux/net/ethernet/eth.c Fri Jul 7 08:54:57 1995 +++ linux/net/ethernet/eth.c Mon Jul 10 17:08:04 1995 @@ -233,9 +233,12 @@ * Copy from an ethernet device memory space to an sk_buff while checksumming if IP */ -void eth_copy_and_sum(struct sk_buff *dest,unsigned char *src, int length, int base) +void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base) { - struct ethhdr *eth=(struct ethhdr *)dest->data; + struct ethhdr *eth; + + IS_SKB(dest); + eth=(struct ethhdr *)dest->data; memcpy(dest->data,src,34); /* ethernet is always >= 60 */ length-=34; if(eth->h_proto!=htons(ETH_P_IP)) diff -u --recursive --new-file v1.3.8/linux/net/ipv4/Makefile linux/net/ipv4/Makefile --- v1.3.8/linux/net/ipv4/Makefile Fri Jun 16 22:02:56 1995 +++ linux/net/ipv4/Makefile Tue Jul 11 08:02:20 1995 @@ -11,9 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< - OBJS := utils.o route.o proc.o timer.o protocol.o packet.o \ arp.o ip.o raw.o icmp.o tcp.o udp.o devinet.o af_inet.o \ @@ -43,9 +40,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/ipv4/ip.c linux/net/ipv4/ip.c --- v1.3.8/linux/net/ipv4/ip.c Fri Jul 7 13:42:58 1995 +++ linux/net/ipv4/ip.c Mon Jul 10 17:08:03 1995 @@ -81,6 +81,7 @@ * Alan Cox : Set saddr on raw output frames as per BSD. * Alan Cox : Stopped broadcast source route explosions. * Alan Cox : Can disable source routing + * Takeshi Sone : Masquerading didn't work. * * * @@ -1023,11 +1024,21 @@ */ - if(!(is_frag&4) && (fw_res=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0))!=1) + if(!(is_frag&4)) { - if(fw_res==-1) + fw_res=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0); + switch (fw_res) { + case 1: +#ifdef CONFIG_IP_MASQUERADE + case 2: +#endif + break; + case -1: icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); - return; + /* fall thru */ + default: + return; + } } #endif /* diff -u --recursive --new-file v1.3.8/linux/net/ipx/Makefile linux/net/ipx/Makefile --- v1.3.8/linux/net/ipx/Makefile Tue Jun 6 12:59:13 1995 +++ linux/net/ipx/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS := af_ipx.o @@ -27,9 +25,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/netrom/Makefile linux/net/netrom/Makefile --- v1.3.8/linux/net/netrom/Makefile Tue Jun 6 12:59:13 1995 +++ linux/net/netrom/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS := af_netrom.o @@ -32,9 +30,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.8/linux/net/unix/Makefile linux/net/unix/Makefile --- v1.3.8/linux/net/unix/Makefile Wed Aug 10 21:35:00 1994 +++ linux/net/unix/Makefile Tue Jul 11 08:02:20 1995 @@ -11,8 +11,6 @@ $(CC) $(CFLAGS) -c $< .s.o: $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< OBJS = sock.o proc.o @@ -25,9 +23,5 @@ tar: tar -cvf /dev/f1 . -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + +include $(TOPDIR)/Rules.make