Commit 6b4869cb authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.7

parent d86fb96f
...@@ -668,7 +668,7 @@ S: Chapel Hill, North Carolina 27514-4818 ...@@ -668,7 +668,7 @@ S: Chapel Hill, North Carolina 27514-4818
S: USA S: USA
N: Bernhard Kaindl N: Bernhard Kaindl
E: bartelt@computerhaus.at E: edv@bartelt.via.at
D: Author of a menu based configuration tool, kmenu, which D: Author of a menu based configuration tool, kmenu, which
D: is the predecessor of 'make menuconfig' and 'make xconfig'. D: is the predecessor of 'make menuconfig' and 'make xconfig'.
S: Tallak 95 S: Tallak 95
...@@ -1161,7 +1161,8 @@ D: the gpm mouse server and kernel support for it ...@@ -1161,7 +1161,8 @@ D: the gpm mouse server and kernel support for it
N: Thomas Sailer N: Thomas Sailer
E: sailer@ife.ee.ethz.ch E: sailer@ife.ee.ethz.ch
D: Baycom radio modem driver E: HB9JNX@HB9W.CHE.EU (packet radio)
D: Baycom and Soundcard radio modem driver
S: Weinbergstrasse 76 S: Weinbergstrasse 76
S: 8408 Winterthur S: 8408 Winterthur
S: Switzerland S: Switzerland
......
...@@ -1875,17 +1875,29 @@ CONFIG_SCC ...@@ -1875,17 +1875,29 @@ CONFIG_SCC
running kernel whenever you want), say M here and read running kernel whenever you want), say M here and read
Documentation/modules.txt. Documentation/modules.txt.
BAYCOM ser12 and par96 kiss emulation driver for AX.25 BAYCOM ser12 and par96 driver for AX.25
CONFIG_BAYCOM CONFIG_BAYCOM
This is an experimental driver for Baycom style simple amateur radio This is an experimental driver for Baycom style simple amateur radio
modems that connect to either a serial interface or a parallel modems that connect to either a serial interface or a parallel
interface. The driver supports the ser12 and par96 designs. To interface. The driver supports the ser12 and par96 designs. To
configure the driver, use the setbaycom utility available from configure the driver, use the sethdlc utility available
http://www.ife.ee.ethz.ch/~sailer/ham/ham.html#lnxbay. For in the standard ax25 utilities package. For information on the modems,
information on the modems, see http://www.baycom.de and see http://www.baycom.de and drivers/net/README.baycom.
drivers/char/README.baycom. If you want to compile this as a module If you want to compile this as a module ( = code which can be
( = code which can be inserted in and removed from the running inserted in and removed from the running kernel whenever you want),
kernel whenever you want), say M here and read say M here and read Documentation/modules.txt. This is recommended.
Soundcard modem driver for AX.25
CONFIG_SOUNDMODEM
This experimental driver allows a standard SoundBlaster or
WindowsSoundSystem compatible soundcard to be used as a packet radio
modem. To configure the driver, use the sethdlc, smdiag and smmixer
utilities available in the standard ax25 utilities package. For
informations on how to key the transmitter, see
http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html and
drivers/net/README.soundmodem. If you want to compile this as a
module ( = code which can be inserted in and removed from the
running kernel whenever you want), say M here and read
Documentation/modules.txt. This is recommended. Documentation/modules.txt. This is recommended.
PLIP (parallel port) support PLIP (parallel port) support
......
VERSION = 2 VERSION = 2
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 6 SUBLEVEL = 7
ARCH = i386 ARCH = i386
......
...@@ -142,9 +142,29 @@ entInt: ...@@ -142,9 +142,29 @@ entInt:
.ent entMM .ent entMM
entMM: entMM:
SAVE_ALL SAVE_ALL
lda $27,do_page_fault /* save $9 - $15 so the inline exception code can manipulate them. */
lda $26,ret_from_sys_call subq $30,56,$30
jsr $31,($27),do_page_fault stq $9,0($30)
stq $10,8($30)
stq $11,16($30)
stq $12,24($30)
stq $13,32($30)
stq $14,40($30)
stq $15,48($30)
addq $30,56,$19
/* handle the fault */
jsr $26,do_page_fault
/* reload the registers after the exception code played. */
ldq $9,0($30)
ldq $10,8($30)
ldq $11,16($30)
ldq $12,24($30)
ldq $13,32($30)
ldq $14,40($30)
ldq $15,48($30)
addq $30,56,$30
/* finish up the syscall as normal. */
br ret_from_sys_call
.end entMM .end entMM
.align 3 .align 3
...@@ -424,7 +444,7 @@ entUnaUser: ...@@ -424,7 +444,7 @@ entUnaUser:
/* /*
* A fork is the same as clone(SIGCHLD, 0); * A fork is the same as clone(SIGCHLD, 0);
*/ */
.align 3 .align 3
.globl sys_fork .globl sys_fork
.ent sys_fork .ent sys_fork
......
...@@ -178,63 +178,217 @@ struct unaligned_stat { ...@@ -178,63 +178,217 @@ struct unaligned_stat {
unsigned long count, va, pc; unsigned long count, va, pc;
} unaligned[2]; } unaligned[2];
/* Macro for exception fixup code to access integer registers. */
#define una_reg(r) (regs.regs[(r) >= 16 && (r) <= 18 ? (r)+19 : (r)])
asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg, asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
unsigned long a3, unsigned long a4, unsigned long a5, unsigned long a3, unsigned long a4, unsigned long a5,
struct allregs regs) struct allregs regs)
{ {
static int cnt = 0; static int cnt = 0;
static long last_time = 0; static long last_time = 0;
long error, tmp1, tmp2, tmp3, tmp4;
unsigned long pc = regs.pc - 4;
unsigned fixup;
if (cnt >= 5 && jiffies - last_time > 5*HZ) { if (cnt >= 5 && jiffies - last_time > 5*HZ) {
cnt = 0; cnt = 0;
} }
if (++cnt < 5) { if (++cnt < 5) {
printk("kernel: unaligned trap at %016lx: %p %lx %ld\n", printk("kernel: unaligned trap at %016lx: %p %lx %ld\n",
regs.pc - 4, va, opcode, reg); pc, va, opcode, reg);
} }
last_time = jiffies; last_time = jiffies;
++unaligned[0].count; unaligned[0].count++;
unaligned[0].va = (unsigned long) va - 4; unaligned[0].va = (unsigned long) va;
unaligned[0].pc = regs.pc; unaligned[0].pc = pc;
/* $16-$18 are PAL-saved, and are offset by 19 entries */
if (reg >= 16 && reg <= 18)
reg += 19;
{
/* Set up an exception handler address just in case we are
handling an unaligned fixup within get_user(). Notice
that we do *not* change the exception count because we
only want to bounce possible exceptions on through. */
__label__ handle_ex; /* We don't want to use the generic get/put unaligned macros as
register void *ex_vector __asm__("$28"); we want to trap exceptions. Only if we actually get an
__asm__ __volatile__ ("" : "=r"(ex_vector) : "0"(&&handle_ex)); exception will we decide whether we should have caught it. */
switch (opcode) { switch (opcode) {
#ifdef __HAVE_CPU_BWX
case 0x0c: /* ldwu */
__asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
"2: ldq_u %2,1(%3)\n"
" extwl %1,%3,%1\n"
" extwh %2,%3,%2\n"
"3:\n"
".section __ex_table,\"a\"\n"
" .gprel32 1b\n"
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
".text"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto got_exception;
una_reg(reg) = tmp1|tmp2;
return;
#endif
case 0x28: /* ldl */ case 0x28: /* ldl */
*(reg+regs.regs) = get_unaligned((int *)va); __asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
"2: ldq_u %2,3(%3)\n"
" extll %1,%3,%1\n"
" extlh %2,%3,%2\n"
"3:\n"
".section __ex_table,\"a\"\n"
" .gprel32 1b\n"
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
".text"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto got_exception;
una_reg(reg) = (int)(tmp1|tmp2);
return; return;
case 0x29: /* ldq */ case 0x29: /* ldq */
*(reg+regs.regs) = get_unaligned((long *)va); __asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
"2: ldq_u %2,7(%3)\n"
" extql %1,%3,%1\n"
" extqh %2,%3,%2\n"
"3:\n"
".section __ex_table,\"a\"\n"
" .gprel32 1b\n"
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
".text"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto got_exception;
una_reg(reg) = tmp1|tmp2;
return;
/* Note that the store sequences do not indicate that they change
memory because it _should_ be affecting nothing in this context.
(Otherwise we have other, much larger, problems.) */
#ifdef __HAVE_CPU_BWX
case 0x0d: /* stw */
__asm__ __volatile__(
"1: ldq_u %2,1(%5)\n"
"2: ldq_u %1,0(%5)\n"
" inswh %6,%5,%4\n"
" inswl %6,%5,%3\n"
" mskwh %2,%5,%2\n"
" mskwl %1,%5,%1\n"
" or %2,%4,%2\n"
" or %1,%3,%1\n"
"3: stq_u %2,1(%5)\n"
"4: stq_u %1,0(%5)\n"
"5:\n"
".section __ex_table,\"a\"\n"
" .gprel32 1b\n"
" lda %2,5b-1b(%0)\n"
" .gprel32 2b\n"
" lda %1,5b-2b(%0)\n"
" .gprel32 3b\n"
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
".text"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
if (error)
goto got_exception;
return; return;
#endif
case 0x2c: /* stl */ case 0x2c: /* stl */
put_unaligned(*(reg+regs.regs), (int *)va); __asm__ __volatile__(
"1: ldq_u %2,3(%5)\n"
"2: ldq_u %1,0(%5)\n"
" inslh %6,%5,%4\n"
" insll %6,%5,%3\n"
" msklh %2,%5,%2\n"
" mskll %1,%5,%1\n"
" or %2,%4,%2\n"
" or %1,%3,%1\n"
"3: stq_u %2,3(%5)\n"
"4: stq_u %1,0(%5)\n"
"5:\n"
".section __ex_table,\"a\"\n"
" .gprel32 1b\n"
" lda %2,5b-1b(%0)\n"
" .gprel32 2b\n"
" lda %1,5b-2b(%0)\n"
" .gprel32 3b\n"
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
".text"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
if (error)
goto got_exception;
return; return;
case 0x2d: /* stq */ case 0x2d: /* stq */
put_unaligned(*(reg+regs.regs), (long *)va); __asm__ __volatile__(
"1: ldq_u %2,7(%5)\n"
"2: ldq_u %1,0(%5)\n"
" insqh %6,%5,%4\n"
" insql %6,%5,%3\n"
" mskqh %2,%5,%2\n"
" mskql %1,%5,%1\n"
" or %2,%4,%2\n"
" or %1,%3,%1\n"
"3: stq_u %2,7(%5)\n"
"4: stq_u %1,0(%5)\n"
"5:\n"
".section __ex_table,\"a\"\n\t"
" .gprel32 1b\n"
" lda %2,5b-1b(%0)\n"
" .gprel32 2b\n"
" lda %1,5b-2b(%0)\n"
" .gprel32 3b\n"
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
".text"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
if (error)
goto got_exception;
return;
}
printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
pc, va, opcode, reg);
do_exit(SIGSEGV);
return; return;
/* We'll only get back here if we are handling a got_exception:
valid exception. */ /* Ok, we caught the exception, but we don't want it. Is there
handle_ex: someone to pass it along to? */
(&regs)->pc = *(28+regs.regs); if ((fixup = search_exception_table(pc)) != 0) {
unsigned long newpc;
newpc = fixup_exception(una_reg, fixup, pc);
printk("Forwarding unaligned exception at %lx (%lx)\n",
pc, newpc);
(&regs)->pc = newpc;
return; return;
} }
}
printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n", /* Yikes! No one to forward the exception to. */
regs.pc, va, opcode, reg); printk("%s: unhandled unaligned exception at pc=%lx ra=%lx"
" (bad address = %p)\n", current->comm,
pc, una_reg(26), va);
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
......
...@@ -25,6 +25,14 @@ ...@@ -25,6 +25,14 @@
* $1,$2,$3,$4,$5,$6 * $1,$2,$3,$4,$5,$6
*/ */
/* Allow an exception for an insn; exit if we get one. */
#define EX(x,y...) \
99: x,##y; \
.section __ex_table,"a"; \
.gprel32 99b; \
lda $31, $exception-99b($31); \
.text
.set noat .set noat
.set noreorder .set noreorder
.align 4 .align 4
...@@ -38,7 +46,7 @@ $loop: ...@@ -38,7 +46,7 @@ $loop:
and $1, 3, $4 # e0 : and $1, 3, $4 # e0 :
beq $4, 1f # .. e1 : beq $4, 1f # .. e1 :
0: stq_u $31, 0($6) # e0 : zero one word 0: EX( stq_u $31, 0($6) ) # e0 : zero one word
subq $0, 8, $0 # .. e1 : subq $0, 8, $0 # .. e1 :
subq $4, 1, $4 # e0 : subq $4, 1, $4 # e0 :
addq $6, 8, $6 # .. e1 : addq $6, 8, $6 # .. e1 :
...@@ -48,13 +56,13 @@ $loop: ...@@ -48,13 +56,13 @@ $loop:
1: bic $1, 3, $1 # e0 : 1: bic $1, 3, $1 # e0 :
beq $1, $tail # .. e1 : beq $1, $tail # .. e1 :
2: stq_u $31, 0($6) # e0 : zero four words 2: EX( stq_u $31, 0($6) ) # e0 : zero four words
subq $0, 8, $0 # .. e1 : subq $0, 8, $0 # .. e1 :
stq_u $31, 8($6) # e0 : EX( stq_u $31, 8($6) ) # e0 :
subq $0, 8, $0 # .. e1 : subq $0, 8, $0 # .. e1 :
stq_u $31, 16($6) # e0 : EX( stq_u $31, 16($6) ) # e0 :
subq $0, 8, $0 # .. e1 : subq $0, 8, $0 # .. e1 :
stq_u $31, 24($6) # e0 : EX( stq_u $31, 24($6) ) # e0 :
subq $0, 8, $0 # .. e1 : subq $0, 8, $0 # .. e1 :
subq $1, 4, $1 # e0 : subq $1, 4, $1 # e0 :
addq $6, 32, $6 # .. e1 : addq $6, 32, $6 # .. e1 :
...@@ -62,35 +70,29 @@ $loop: ...@@ -62,35 +70,29 @@ $loop:
$tail: $tail:
bne $2, 1f # e1 : is there a tail to do? bne $2, 1f # e1 : is there a tail to do?
stq $3, 0($7) # e0 : decrement exception count
ret $31, ($28), 1 # .. e1 : ret $31, ($28), 1 # .. e1 :
1: ldq_u $5, 0($6) # e1 : 1: EX( ldq_u $5, 0($6) ) # e0 :
mskqh $5, $0, $5 # e0 :
stq_u $5, 0($6) # e0 :
clr $0 # .. e1 : clr $0 # .. e1 :
stq $3, 0($7) # e0 : decrement exception count nop # e1 :
mskqh $5, $0, $5 # e0 :
EX( stq_u $5, 0($6) ) # e0 :
ret $31, ($28), 1 # .. e1 : ret $31, ($28), 1 # .. e1 :
__clear_user: __clear_user:
ldq $3, 0($7) # e0 : load exception count for increment
beq $0, $zerolength # .. e1 :
and $6, 7, $4 # e0 : find dest misalignment and $6, 7, $4 # e0 : find dest misalignment
addq $0, $4, $1 # e1 : bias counter beq $0, $zerolength # .. e1 :
addq $3, 1, $5 # e0 : addq $0, $4, $1 # e0 : bias counter
and $1, 7, $2 # .. e1 : number of bytes in tail and $1, 7, $2 # e1 : number of bytes in tail
srl $1, 3, $1 # e0 : srl $1, 3, $1 # e0 :
unop # :
stq $5, 0($7) # e0 : increment exception count
beq $4, $loop # .. e1 : beq $4, $loop # .. e1 :
ldq_u $5, 0($6) # e0 : load dst word to mask back in EX( ldq_u $5, 0($6) ) # e0 : load dst word to mask back in
beq $1, $oneword # .. e1 : sub-word store? beq $1, $oneword # .. e1 : sub-word store?
mskql $5, $6, $5 # e0 : take care of misaligned head mskql $5, $6, $5 # e0 : take care of misaligned head
addq $6, 8, $6 # .. e1 : addq $6, 8, $6 # .. e1 :
stq_u $5, -8($6) # e0 : EX( stq_u $5, -8($6) ) # e0 :
addq $0, $4, $0 # .. e1 : bytes left -= 8 - misalignment addq $0, $4, $0 # .. e1 : bytes left -= 8 - misalignment
subq $1, 1, $1 # e0 : subq $1, 1, $1 # e0 :
subq $0, 8, $0 # .. e1 : subq $0, 8, $0 # .. e1 :
...@@ -101,11 +103,11 @@ $oneword: ...@@ -101,11 +103,11 @@ $oneword:
mskql $5, $6, $4 # e0 : mskql $5, $6, $4 # e0 :
mskqh $5, $2, $5 # e0 : mskqh $5, $2, $5 # e0 :
or $5, $4, $5 # e1 : or $5, $4, $5 # e1 :
stq_u $5, 0($6) # e0 : EX( stq_u $5, 0($6) ) # e0 :
clr $0 # .. e1 : clr $0 # .. e1 :
stq $3, 0($7) # e0 : decrement exception count
$zerolength: $zerolength:
$exception:
ret $31, ($28), 1 # .. e1 : ret $31, ($28), 1 # .. e1 :
.end __clear_user .end __clear_user
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* destination address in $6 * destination address in $6
* source address in $7 * source address in $7
* exception pointer in $8 * exception pointer in $8
* return address in $28 (exceptions expect it there) * return address in $28
* *
* Outputs: * Outputs:
* bytes left to copy in $0 * bytes left to copy in $0
...@@ -27,28 +27,33 @@ ...@@ -27,28 +27,33 @@
* $1,$2,$3,$4,$5,$6,$7 * $1,$2,$3,$4,$5,$6,$7
*/ */
/* Allow an exception for an insn; exit if we get one. */
#define EX(x,y...) \
99: x,##y; \
.section __ex_table,"a"; \
.gprel32 99b; \
lda $31, $exit-99b($31); \
.text
.set noat .set noat
.align 3 .align 3
.globl __copy_user .globl __copy_user
.ent __copy_user .ent __copy_user
__copy_user: __copy_user:
ldq $5,0($8)
beq $0,$35
and $6,7,$3 and $6,7,$3
addq $5,1,$1 beq $0,$35
stq $1,0($8)
beq $3,$36 beq $3,$36
subq $3,8,$3 subq $3,8,$3
.align 5 .align 5
$37: $37:
ldq_u $1,0($7) EX( ldq_u $1,0($7) )
ldq_u $2,0($6) EX( ldq_u $2,0($6) )
extbl $1,$7,$1 extbl $1,$7,$1
mskbl $2,$6,$2 mskbl $2,$6,$2
insbl $1,$6,$1 insbl $1,$6,$1
addq $3,1,$3 addq $3,1,$3
bis $1,$2,$1 bis $1,$2,$1
stq_u $1,0($6) EX( stq_u $1,0($6) )
subq $0,1,$0 subq $0,1,$0
addq $6,1,$6 addq $6,1,$6
addq $7,1,$7 addq $7,1,$7
...@@ -59,10 +64,10 @@ $36: ...@@ -59,10 +64,10 @@ $36:
bic $0,7,$4 bic $0,7,$4
beq $1,$43 beq $1,$43
beq $4,$48 beq $4,$48
ldq_u $3,0($7) EX( ldq_u $3,0($7) )
.align 5 .align 5
$50: $50:
ldq_u $2,8($7) EX( ldq_u $2,8($7) )
subq $4,8,$4 subq $4,8,$4
extql $3,$7,$3 extql $3,$7,$3
extqh $2,$7,$1 extqh $2,$7,$1
...@@ -77,13 +82,13 @@ $48: ...@@ -77,13 +82,13 @@ $48:
beq $0,$41 beq $0,$41
.align 5 .align 5
$57: $57:
ldq_u $1,0($7) EX( ldq_u $1,0($7) )
ldq_u $2,0($6) EX( ldq_u $2,0($6) )
extbl $1,$7,$1 extbl $1,$7,$1
mskbl $2,$6,$2 mskbl $2,$6,$2
insbl $1,$6,$1 insbl $1,$6,$1
bis $1,$2,$1 bis $1,$2,$1
stq_u $1,0($6) EX( stq_u $1,0($6) )
subq $0,1,$0 subq $0,1,$0
addq $6,1,$6 addq $6,1,$6
addq $7,1,$7 addq $7,1,$7
...@@ -93,9 +98,8 @@ $57: ...@@ -93,9 +98,8 @@ $57:
$43: $43:
beq $4,$65 beq $4,$65
.align 5 .align 5
.align 5
$66: $66:
ldq $1,0($7) EX( ldq $1,0($7) )
subq $4,8,$4 subq $4,8,$4
stq $1,0($6) stq $1,0($6)
addq $7,8,$7 addq $7,8,$7
...@@ -104,15 +108,15 @@ $66: ...@@ -104,15 +108,15 @@ $66:
bne $4,$66 bne $4,$66
$65: $65:
beq $0,$41 beq $0,$41
ldq $2,0($7) EX( ldq $2,0($7) )
ldq $1,0($6) EX( ldq $1,0($6) )
mskql $2,$0,$2 mskql $2,$0,$2
mskqh $1,$0,$1 mskqh $1,$0,$1
bis $2,$1,$2 bis $2,$1,$2
stq $2,0($6) EX( stq $2,0($6) )
bis $31,$31,$0 bis $31,$31,$0
$41: $41:
stq $5,0($8)
$35: $35:
$exit:
ret $31,($28),1 ret $31,($28),1
.end __copy_user .end __copy_user
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
# #
# Note 2! The CFLAGS definition is now in the main makefile... # Note 2! The CFLAGS definition is now in the main makefile...
OBJS = init.o fault.o OBJS = init.o fault.o extable.o
mm.o: $(OBJS) mm.o: $(OBJS)
$(LD) -r -o mm.o $(OBJS) $(LD) -r -o mm.o $(OBJS)
......
/*
* linux/arch/alpha/mm/extable.c
*/
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
extern const struct exception_table_entry __stop___ex_table[];
static inline unsigned
search_one_table(const struct exception_table_entry *first,
const struct exception_table_entry *last,
signed int value)
{
while (first <= last) {
const struct exception_table_entry *mid;
long diff;
mid = (last - first) / 2 + first;
diff = mid->insn - value;
if (diff == 0)
return mid->fixup.unit;
else if (diff < 0)
first = mid+1;
else
last = mid-1;
}
return 0;
}
unsigned
search_exception_table(unsigned long addr)
{
unsigned ret;
signed int reladdr;
/* Search the kernel's table first. */
{
register unsigned long gp __asm__("$29");
reladdr = addr - gp;
}
ret = search_one_table(__start___ex_table,
__stop___ex_table-1, reladdr);
if (ret)
return ret;
/* FIXME -- search the module's tables here */
return 0;
}
...@@ -52,14 +52,24 @@ extern void die_if_kernel(char *,struct pt_regs *,long); ...@@ -52,14 +52,24 @@ extern void die_if_kernel(char *,struct pt_regs *,long);
* -1 = instruction fetch * -1 = instruction fetch
* 0 = load * 0 = load
* 1 = store * 1 = store
*
* Registers $9 through $15 are saved in a block just prior to `regs' and
* are saved and restored around the call to allow exception code to
* modify them.
*/ */
asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, long cause,
unsigned long a3, unsigned long a4, unsigned long a5, /* Macro for exception fixup code to access integer registers. */
struct pt_regs regs) #define dpf_reg(r) \
(((unsigned long *)regs)[(r) <= 8 ? (r) : (r) <= 15 ? (r)-16 : \
(r) <= 18 ? (r)+8 : (r)-10])
asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr,
long cause, struct pt_regs *regs)
{ {
struct vm_area_struct * vma; struct vm_area_struct * vma;
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm; struct mm_struct *mm = tsk->mm;
unsigned fixup;
down(&mm->mmap_sem); down(&mm->mmap_sem);
vma = find_vma(mm, address); vma = find_vma(mm, address);
...@@ -97,18 +107,21 @@ asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, long c ...@@ -97,18 +107,21 @@ asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, long c
*/ */
bad_area: bad_area:
up(&mm->mmap_sem); up(&mm->mmap_sem);
/* Did we have an exception handler installed? */
if (current->tss.ex.count == 1) { /* Are we prepared to handle this fault as an exception? */
printk("Taking exception at %lx (%lx)\n", regs.pc, regs.r28); if ((fixup = search_exception_table(regs->pc)) != 0) {
current->tss.ex.count = 0; unsigned long newpc;
/* return to the address in r28 */ newpc = fixup_exception(dpf_reg, fixup, regs->pc);
(&regs)->pc = regs.r28; printk("Taking exception at %lx (%lx)\n", regs->pc, newpc);
regs->pc = newpc;
return; return;
} }
if (user_mode(&regs)) {
printk("%s: memory violation at pc=%08lx rp=%08lx (bad address = %08lx)\n", if (user_mode(regs)) {
tsk->comm, regs.pc, regs.r26, address); printk("%s: memory violation at pc=%08lx ra=%08lx "
die_if_kernel("oops", &regs, cause); "(bad address = %08lx)\n",
tsk->comm, regs->pc, regs->r26, address);
die_if_kernel("oops", regs, cause);
force_sig(SIGSEGV, tsk); force_sig(SIGSEGV, tsk);
return; return;
} }
...@@ -116,8 +129,8 @@ asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, long c ...@@ -116,8 +129,8 @@ asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, long c
* Oops. The kernel tried to access some bad page. We'll have to * Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice. * terminate things with extreme prejudice.
*/ */
printk(KERN_ALERT printk(KERN_ALERT "Unable to handle kernel paging request at "
"Unable to handle kernel paging request at virtual address %016lx\n", address); "virtual address %016lx\n", address);
die_if_kernel("Oops", &regs, cause); die_if_kernel("Oops", regs, cause);
do_exit(SIGKILL); do_exit(SIGKILL);
} }
...@@ -8,6 +8,6 @@ ...@@ -8,6 +8,6 @@
# Note 2! The CFLAGS definition is now in the main makefile... # Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := mm.o O_TARGET := mm.o
O_OBJS := init.o fault.o ioremap.o O_OBJS := init.o fault.o ioremap.o extable.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
/*
* linux/arch/i386/mm/extable.c
*/
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
extern const struct exception_table_entry __stop___ex_table[];
static inline unsigned long
search_one_table(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
/* Some versions of the linker are buggy and do not align the
__start pointer along with the section, thus we may be low. */
if ((long)first & 3)
(long)first = ((long)first | 3) + 1;
while (first <= last) {
const struct exception_table_entry *mid;
long diff;
mid = (last - first) / 2 + first;
diff = mid->insn - value;
if (diff == 0)
return mid->fixup;
else if (diff < 0)
first = mid+1;
else
last = mid-1;
}
return 0;
}
unsigned long
search_exception_table(unsigned long addr)
{
unsigned long ret;
/* Search the kernel's table first. */
ret = search_one_table(__start___ex_table,
__stop___ex_table-1, addr);
if (ret)
return ret;
/* FIXME -- search the module's tables here */
return 0;
}
...@@ -93,6 +93,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -93,6 +93,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
struct vm_area_struct * vma; struct vm_area_struct * vma;
unsigned long address; unsigned long address;
unsigned long page; unsigned long page;
unsigned long fixup;
int write; int write;
/* get the address */ /* get the address */
...@@ -161,14 +162,14 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -161,14 +162,14 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
*/ */
bad_area: bad_area:
up(&mm->mmap_sem); up(&mm->mmap_sem);
/* is there valid exception data? Return to indicated handler if so */
if (tsk->tss.ex.count == 0) { /* Are we prepared to handle this fault? */
printk("Exception at %lx (%lx)\n", regs->eip, regs->edx); if ((fixup = search_exception_table(regs->eip)) != 0) {
tsk->tss.ex.count--; printk("Exception at %lx (%lx)\n", regs->eip, fixup);
regs->eip = regs->edx; regs->eip = fixup;
regs->edx = -EFAULT;
return; return;
} }
if (error_code & 4) { if (error_code & 4) {
tsk->tss.cr2 = address; tsk->tss.cr2 = address;
tsk->tss.error_code = error_code; tsk->tss.error_code = error_code;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define MD_DRIVER #define MD_DRIVER
#include <linux/blk.h> #include <linux/blk.h>
#include <asm/uaccess.h>
static struct hd_struct md_hd_struct[MAX_MD_DEV]; static struct hd_struct md_hd_struct[MAX_MD_DEV];
static int md_blocksizes[MAX_MD_DEV]; static int md_blocksizes[MAX_MD_DEV];
...@@ -296,10 +297,9 @@ static int md_ioctl (struct inode *inode, struct file *file, ...@@ -296,10 +297,9 @@ static int md_ioctl (struct inode *inode, struct file *file,
case BLKGETSIZE: /* Return device size */ case BLKGETSIZE: /* Return device size */
if (!arg) return -EINVAL; if (!arg) return -EINVAL;
err=verify_area (VERIFY_WRITE, (long *) arg, sizeof(long)); err = put_user (md_hd_struct[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
if (err) if (err)
return err; return err;
put_user (md_hd_struct[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
break; break;
case BLKFLSBUF: case BLKFLSBUF:
...@@ -315,10 +315,9 @@ static int md_ioctl (struct inode *inode, struct file *file, ...@@ -315,10 +315,9 @@ static int md_ioctl (struct inode *inode, struct file *file,
case BLKRAGET: case BLKRAGET:
if (!arg) return -EINVAL; if (!arg) return -EINVAL;
err=verify_area (VERIFY_WRITE, (long *) arg, sizeof(long)); err = put_user (read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
if (err) if (err)
return err; return err;
put_user (read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
break; break;
/* We have a problem here : there is no easy way to give a CHS /* We have a problem here : there is no easy way to give a CHS
...@@ -328,14 +327,19 @@ static int md_ioctl (struct inode *inode, struct file *file, ...@@ -328,14 +327,19 @@ static int md_ioctl (struct inode *inode, struct file *file,
case HDIO_GETGEO: case HDIO_GETGEO:
if (!loc) return -EINVAL; if (!loc) return -EINVAL;
err = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); err = put_user (2, (char *) &loc->heads);
if (err) if (err)
return err; return err;
put_user (2, (char *) &loc->heads); err = put_user (4, (char *) &loc->sectors);
put_user (4, (char *) &loc->sectors); if (err)
put_user (md_hd_struct[minor].nr_sects/8, (short *) &loc->cylinders); return err;
put_user (md_hd_struct[MINOR(inode->i_rdev)].start_sect, err = put_user (md_hd_struct[minor].nr_sects/8, (short *) &loc->cylinders);
if (err)
return err;
err = put_user (md_hd_struct[MINOR(inode->i_rdev)].start_sect,
(long *) &loc->start); (long *) &loc->start);
if (err)
return err;
break; break;
RO_IOCTLS(inode->i_rdev,arg); RO_IOCTLS(inode->i_rdev,arg);
...@@ -367,7 +371,7 @@ static void md_release (struct inode *inode, struct file *file) ...@@ -367,7 +371,7 @@ static void md_release (struct inode *inode, struct file *file)
} }
static int md_read (struct inode *inode, struct file *file, static long md_read (struct inode *inode, struct file *file,
char *buf, int count) char *buf, int count)
{ {
int minor=MINOR(inode->i_rdev); int minor=MINOR(inode->i_rdev);
...@@ -378,7 +382,7 @@ static int md_read (struct inode *inode, struct file *file, ...@@ -378,7 +382,7 @@ static int md_read (struct inode *inode, struct file *file,
return block_read (inode, file, buf, count); return block_read (inode, file, buf, count);
} }
static int md_write (struct inode *inode, struct file *file, static long md_write (struct inode *inode, struct file *file,
const char *buf, int count) const char *buf, int count)
{ {
int minor=MINOR(inode->i_rdev); int minor=MINOR(inode->i_rdev);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/fcntl.h> #include <asm/fcntl.h>
#include <asm/uaccess.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/ucdrom.h> #include <linux/ucdrom.h>
......
This diff is collapsed.
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/ftape.h> #include <linux/ftape.h>
#include <asm/segment.h> #include <asm/uaccess.h>
#include "tracing.h" #include "tracing.h"
#include "ftape-eof.h" #include "ftape-eof.h"
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/ftape.h> #include <linux/ftape.h>
#include <asm/segment.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/mtio.h> #include <linux/mtio.h>
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/ftape.h> #include <linux/ftape.h>
#include <asm/segment.h> #include <asm/uaccess.h>
#include "tracing.h" #include "tracing.h"
#include "ftape-read.h" #include "ftape-read.h"
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/ftape.h> #include <linux/ftape.h>
#include <asm/segment.h> #include <asm/uaccess.h>
#include "tracing.h" #include "tracing.h"
#include "ftape-write.h" #include "ftape-write.h"
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <asm/segment.h> #include <asm/uaccess.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/major.h> #include <linux/major.h>
......
...@@ -184,12 +184,14 @@ static struct symbol_table misc_syms = { ...@@ -184,12 +184,14 @@ static struct symbol_table misc_syms = {
#include <linux/symtab_end.h> #include <linux/symtab_end.h>
}; };
#if defined(CONFIG_PROC_FS) && !defined(MODULE)
static struct proc_dir_entry proc_misc = { static struct proc_dir_entry proc_misc = {
0, 4, "misc", 0, 4, "misc",
S_IFREG | S_IRUGO, 1, 0, 0, S_IFREG | S_IRUGO, 1, 0, 0,
0, NULL /* ops -- default to array */, 0, NULL /* ops -- default to array */,
&proc_misc_read /* get_info */, &proc_misc_read /* get_info */,
}; };
#endif
int misc_init(void) int misc_init(void)
{ {
......
...@@ -1940,9 +1940,6 @@ int tty_init(void) ...@@ -1940,9 +1940,6 @@ int tty_init(void)
#endif #endif
#ifdef CONFIG_RISCOM8 #ifdef CONFIG_RISCOM8
riscom8_init(); riscom8_init();
#endif
#ifdef CONFIG_BAYCOM
baycom_init();
#endif #endif
pty_init(); pty_init();
vcs_init(); vcs_init();
......
...@@ -117,6 +117,7 @@ ...@@ -117,6 +117,7 @@
* *
*/ */
#include <asm/uaccess.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h> #include <linux/version.h>
...@@ -915,7 +916,7 @@ void isdn_info_update(void) ...@@ -915,7 +916,7 @@ void isdn_info_update(void)
wake_up_interruptible(&(dev->info_waitq)); wake_up_interruptible(&(dev->info_waitq));
} }
static int isdn_read(struct inode *inode, struct file *file, char *buf, int count) static long isdn_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
{ {
uint minor = MINOR(inode->i_rdev); uint minor = MINOR(inode->i_rdev);
int len = 0; int len = 0;
...@@ -988,12 +989,13 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun ...@@ -988,12 +989,13 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun
return -ENODEV; return -ENODEV;
} }
static int isdn_lseek(struct inode *inode, struct file *file, off_t offset, int orig) static long long isdn_lseek(struct inode *inode, struct file *file, long long offset, int orig)
{ {
return -ESPIPE; return -ESPIPE;
} }
static int isdn_write(struct inode *inode, struct file *file, const char *buf, int count) static long isdn_write(struct inode *inode, struct file *file,
const char *buf, unsigned long count)
{ {
uint minor = MINOR(inode->i_rdev); uint minor = MINOR(inode->i_rdev);
int drvidx; int drvidx;
......
...@@ -106,6 +106,7 @@ ...@@ -106,6 +106,7 @@
* *
*/ */
#include <asm/uaccess.h>
#include <linux/config.h> #include <linux/config.h>
#define __NO_VERSION__ #define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
......
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
/* TODO: right tbusy handling when using MP */ /* TODO: right tbusy handling when using MP */
#include <asm/uaccess.h>
#include <linux/config.h> #include <linux/config.h>
#define __NO_VERSION__ #define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
...@@ -391,7 +392,7 @@ int isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long a ...@@ -391,7 +392,7 @@ int isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long a
switch (cmd) { switch (cmd) {
case PPPIOCBUNDLE: case PPPIOCBUNDLE:
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
if ((r = get_user(val, arg))) if ((r = get_user(val, argp)))
return r; return r;
printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
(int) min, (int) is->unit, (int) val); (int) min, (int) is->unit, (int) val);
...@@ -588,7 +589,6 @@ int isdn_ppp_read(int min, struct file *file, char *buf, int count) ...@@ -588,7 +589,6 @@ int isdn_ppp_read(int min, struct file *file, char *buf, int count)
{ {
struct ippp_struct *is; struct ippp_struct *is;
struct ippp_buf_queue *b; struct ippp_buf_queue *b;
int r;
unsigned long flags; unsigned long flags;
is = file->private_data; is = file->private_data;
...@@ -1445,7 +1445,6 @@ static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *de ...@@ -1445,7 +1445,6 @@ static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *de
{ {
struct ppp_stats *res, t; struct ppp_stats *res, t;
isdn_net_local *lp = (isdn_net_local *) dev->priv; isdn_net_local *lp = (isdn_net_local *) dev->priv;
int err;
res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
...@@ -1476,7 +1475,7 @@ static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *de ...@@ -1476,7 +1475,7 @@ static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *de
int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
{ {
int error; int error = 0;
char *r; char *r;
int len; int len;
isdn_net_local *lp = (isdn_net_local *) dev->priv; isdn_net_local *lp = (isdn_net_local *) dev->priv;
......
...@@ -109,6 +109,7 @@ ...@@ -109,6 +109,7 @@
* *
*/ */
#include <asm/uaccess.h>
#define __NO_VERSION__ #define __NO_VERSION__
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
*/ */
#define __NO_VERSION__ #define __NO_VERSION__
#include "teles.h" #include "teles.h"
#include <asm/uaccess.h>
extern struct IsdnCard cards[]; extern struct IsdnCard cards[];
extern int nrcards; extern int nrcards;
......
...@@ -25,7 +25,8 @@ fi ...@@ -25,7 +25,8 @@ fi
bool 'Radio network interfaces' CONFIG_NET_RADIO bool 'Radio network interfaces' CONFIG_NET_RADIO
if [ "$CONFIG_NET_RADIO" != "n" ]; then if [ "$CONFIG_NET_RADIO" != "n" ]; then
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'BAYCOM ser12 and par96 kiss emulation driver for AX.25' CONFIG_BAYCOM tristate 'BAYCOM ser12 and par96 driver for AX.25' CONFIG_BAYCOM
tristate 'Soundcard modem driver for AX.25' CONFIG_SOUNDMODEM
fi fi
if [ "$CONFIG_AX25" = "y" ]; then if [ "$CONFIG_AX25" = "y" ]; then
bool 'Gracilis PackeTwin support' CONFIG_PT bool 'Gracilis PackeTwin support' CONFIG_PT
......
...@@ -18,6 +18,8 @@ CONFIG_8390_BUILTIN := ...@@ -18,6 +18,8 @@ CONFIG_8390_BUILTIN :=
CONFIG_8390_MODULE := CONFIG_8390_MODULE :=
CONFIG_SLHC_BUILTIN := CONFIG_SLHC_BUILTIN :=
CONFIG_SLHC_MODULE := CONFIG_SLHC_MODULE :=
CONFIG_HDLCDRV_BUILTIN :=
CONFIG_HDLCDRV_MODULE :=
ifeq ($(CONFIG_ISDN),y) ifeq ($(CONFIG_ISDN),y)
ifeq ($(CONFIG_ISDN_PPP),y) ifeq ($(CONFIG_ISDN_PPP),y)
...@@ -518,6 +520,37 @@ else ...@@ -518,6 +520,37 @@ else
endif endif
endif endif
ifeq ($(CONFIG_BAYCOM),y)
L_OBJS += baycom.o
CONFIG_HDLCDRV_BUILTIN = y
else
ifeq ($(CONFIG_BAYCOM),m)
CONFIG_HDLCDRV_MODULE = y
M_OBJS += baycom.o
endif
endif
ifeq ($(CONFIG_SOUNDMODEM),y)
L_OBJS += soundmodem.o
CONFIG_HDLCDRV_BUILTIN = y
else
ifeq ($(CONFIG_SOUNDMODEM),m)
CONFIG_HDLCDRV_MODULE = y
M_OBJS += soundmodem.o
endif
endif
# If anything built-in uses the hdlcdrv, then build it into the kernel also.
# If not, but a module uses it, build as a module.
ifdef CONFIG_HDLCDRV_BUILTIN
LX_OBJS += hdlcdrv.o
else
ifdef CONFIG_HDLCDRV_MODULE
MX_OBJS += hdlcdrv.o
endif
endif
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
clean: clean:
......
LINUX DRIVER FOR BAYCOM MODEMS LINUX DRIVER FOR BAYCOM MODEMS
Thomas M. Sailer <hb9jnx@radio.amiv.ethz.ch> Thomas M. Sailer, HB9JNX/AE4WA, <sailer@ife.ee.ethz.ch>
This document describes the Linux Kernel Driver for simple Baycom style This document describes the Linux Kernel Driver for simple Baycom style
amateur radio modems. The driver supports the following modems: amateur radio modems. The driver supports the following modems:
...@@ -22,10 +22,11 @@ par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard. ...@@ -22,10 +22,11 @@ par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard.
implementation of the HDLC protocol and the scrambler polynomial to implementation of the HDLC protocol and the scrambler polynomial to
the PC. the PC.
par97: This is a redesign of the par96 modem by Henning Rech, DF9IC. The modem picpar: This is a redesign of the par96 modem by Henning Rech, DF9IC. The modem
is protocol compatible to par96, but uses only three low power ICs is protocol compatible to par96, but uses only three low power ICs
and can therefore be fed from the parallel port and does not require and can therefore be fed from the parallel port and does not require
an additional power supply. an additional power supply. Furthermore, it incorporates a carrier
detect circuitry.
All of the above modems only support half duplex communications. However, All of the above modems only support half duplex communications. However,
the driver supports the KISS (see below) fullduplex command. It then simply the driver supports the KISS (see below) fullduplex command. It then simply
...@@ -37,44 +38,14 @@ access protocol. ...@@ -37,44 +38,14 @@ access protocol.
The Interface of the driver The Interface of the driver
The driver interfaces to the AX25 stack via a KISS interface. The driver Unlike previous drivers, the driver is no longer a character device,
can be accessed as a character device with major 60. Major 60 is the first but it is now a true kernel network interface. Installation is therefore
number of the local/experimental range. I did no steps to coordinate a simple. Once installed, four interfaces named bc[0-3] are available.
major number for this driver, but I plan to do so in the near future. sethdlc from the ax25 utilities may be used to set driver states etc.
The driver supports multiple modems (currently four, as defined with Users of userland AX.25 stacks may use the net2kiss utility (also available
NR_PORTS). It therefore responds to minor numbers 0 to 3. I recommend in the ax25 utilities package) to converts packets of a network interface
to access the driver via the special device files /dev/bc[0-3], which to a KISS stream on a pseudo tty. There's also a patch available from
can be created with 'make bc'. me for WAMPES which allows attaching a kernel network interface directly.
Compiling and installing the driver
First unpack the source files into a directory. Then enter the following: (you
must be root to do it)
make dep
make
This will create the files baycom.o and setbaycom. baycom.o is as well copied
to /lib/modules/`uname -n`/misc. If you plan to use kerneld, do the following:
depmod -a
Do not forget to create the device special files if you install the driver the
first time. This can be done with:
make bc
You are now ready to use the driver. You can now activate the driver manually
by entering
insmod baycom
or leave this task to kerneld (if installed). Add the following line to
/etc/conf.modules
alias char-major-60 baycom
Configuring the driver Configuring the driver
...@@ -87,23 +58,21 @@ driver from the insmod command line (or by means of an option line in ...@@ -87,23 +58,21 @@ driver from the insmod command line (or by means of an option line in
Examples: Examples:
insmod baycom modem=1 iobase=0x3f8 irq=4 options=1 insmod baycom modem=1 iobase=0x3f8 irq=4 options=1
setbaycom -i /dev/bc0 -p ser12 0x3f8 4 1 sethdlc -i bc0 -p type ser12 io 0x3f8 irq 4 options 1
Both lines configure the first port to drive a ser12 modem at the first Both lines configure the first port to drive a ser12 modem at the first
serial port (COM1 under DOS). options=1 instructs the driver to use serial port (COM1 under DOS). options=1 instructs the driver to use
the software DCD algorithm (see below). the software DCD algorithm (see below).
insmod baycom modem=2 iobase=0x378 irq=7 options=1 insmod baycom modem=2 iobase=0x378 irq=7 options=1
setbaycom -i /dev/bc0 -p par96 0x378 7 1 sethdlc -i bc0 -p type par96 io 0x378 irq 7 options 1
Both lines configure the first port to drive a par96 or par97 modem at the Both lines configure the first port to drive a par96 or par97 modem at the
first parallel port (LPT1 under DOS). options=1 instructs the driver to use first parallel port (LPT1 under DOS). options=1 instructs the driver to use
the software DCD algorithm (see below). the software DCD algorithm (see below).
The channel access parameters must be set through KISS parameter frames. The The channel access parameters can be set with sethdlc -a or kissparms.
AX25 stack may be used to generate such frames. KA9Q NET derivatives such Note that both utilities interpret the values slightly different.
as WAMPES or TNOS offer the 'param' command for this purpose.
Hardware DCD versus Software DCD Hardware DCD versus Software DCD
...@@ -124,28 +93,13 @@ par96: the software DCD algorithm for this type of modem is rather poor. ...@@ -124,28 +93,13 @@ par96: the software DCD algorithm for this type of modem is rather poor.
feeds the DCD input of the PAR96 modem, the use of the hardware feeds the DCD input of the PAR96 modem, the use of the hardware
DCD circuitry is recommended. DCD circuitry is recommended.
par97: as far as I know it is in this respect equivalent to par96. picpar: the picpar modem features a builtin DCD hardware, which is highly
recommended.
Compatibility with the rest of the Linux kernel Compatibility with the rest of the Linux kernel
The tty interface gave me some headaches. I did not find a reasonable
documentation of its interfaces, so I'm not particularly sure if I implemented
it the way I should. Perhaps someone with a more profound knowledge about
tty drivers could check the interface routines.
The driver produces a rather high interrupt load. par96/par97 generates 600
interrupts per second, ser12 1200 while transmitting and 2400 if hardware
DCD is used, 3600 otherwise. If other device drivers disable interrupts
too long, the performance of the driver drops (the packet loss rate increases),
especially with the ser12 modem.
There were also reports that under rather high load situations the driver
drops frames. This might be either an interrupt problem, or an AX25 stack
running in user mode might not get enough CPU time to process the packets
before the drivers internal buffers overflow. There is no way to throttle
the other radio stations from this layer, throttling must be done in the
AX25 layer.
The serial driver, the line printer (lp) driver and the baycom driver compete The serial driver, the line printer (lp) driver and the baycom driver compete
for the same hardware resources. Of course only one driver can access a given for the same hardware resources. Of course only one driver can access a given
interface at a time. The serial driver grabs all interfaces it can find at interface at a time. The serial driver grabs all interfaces it can find at
...@@ -160,5 +114,5 @@ leave it to kerneld to load the correct driver depending on the application. ...@@ -160,5 +114,5 @@ leave it to kerneld to load the correct driver depending on the application.
vy 73s de vy 73s de
Tom Sailer, hb9jnx@radio.amiv.ethz.ch Tom Sailer, sailer@ife.ee.ethz.ch
hb9jnx @ hb9w.ampr.org hb9jnx @ hb9w.ampr.org
LINUX DRIVER FOR SOUNDCARDS AS AX.25 MODEMS
Thomas M. Sailer, HB9JNX/AE4WA, <sailer@ife.ee.ethz.ch>
This driver allows either SoundBlaster (sbc) or WindowsSoundSystem (wss)
compatible soundcards to be used as either 1200 baud AFSK or 9600 baud FSK
AX.25 packet radio modems. Only half duplex operation is supported; an
attempt to include full duplex support failed because the hardware did
not support it (it appeared that the card only provides one DMA channel,
although the Codec chip would support two channels). The driver needs
some processing power! A 486DX/2 66MHz is a minimum requirement, otherwise
interactive performance of the computer may become sluggish.
The Interface of the driver
The driver provides a kernel network drivers named sm[0-3]. sethdlc
from the ax25 utilities may be used to set driver states etc. Users
of userland AX.25 stacks may use the net2kiss utility (also available
in the ax25 utilities package) to converts packets of a network interface
to a KISS stream on a pseudo tty. There's also a patch available from
me for WAMPES which allows attaching a kernel network interface directly.
Configuring the driver
Some sound cards need to be initialized before they operate in either
SoundBlaster or WSS compatibility mode. The driver does _NOT_ do this;
you may use the standard linux sound driver to initialize the soundcard;
compile it as a module, and do
insmod sound
rmmod sound
The soundcard should then be initialized correctly. If this does not help,
you'll have to write your own initialization utility.
Every time the driver is inserted into the kernel, it has to know which
modems it should access at which ports. This can be done with the setbaycom
utility. If you are only using one modem, you can also configure the
driver from the insmod command line (or by means of an option line in
/etc/conf.modules).
Examples:
insmod soundmodem hw=0 mode=0 iobase=0x220 irq=5 dma=1
sethdlc -i sm0 -p hw sbc type afsk1200 io 0x220 irq 5 dma 1
Both lines configure the first port to drive a soundblaster card
in 1200 baud AFSK mode.
The channel access parameters can be set with sethdlc -a or kissparms.
Note that both utilities interpret the values slightly different.
Input and output levels
It is important that the input and output levels are adjusted properly.
There are two utilities, available in the ax25 utilities distribution,
to facilitate this: smmixer and smdiag. smdiag allows you to display
the input signal in an oscilloscope like display or an eye diagram.
smmixer allows you to adjust input/output levels. See the respective
man pages.
Transmitter keying
Since soundcards do not have a DC coupled output; PTT keying options include
the following:
* VOX circuitry
* Serial port pin
* Parallel port pin
* MPU401 MIDI output via a retriggerable monoflop.
Circuit schematics may be found at
http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html.
Compatibility with the rest of the Linux kernel
The sound driver and the soundcard modem driver compete for the same
hardware resources. Of course only one driver can access a given
interface at a time. Worse yet, the sound driver grabs the soundcard
at startup time. Therefore the soundcard modem driver subsequently won't
be able to access the soundcard. You might therefore find it necessary to
unload the sound driver before using the soundcard modem driver.
vy 73s de
Tom Sailer, sailer@ife.ee.ethz.ch
hb9jnx @ hb9w.ampr.org
This diff is collapsed.
...@@ -128,6 +128,7 @@ static const char *version = ...@@ -128,6 +128,7 @@ static const char *version =
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/uaccess.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -1133,6 +1133,25 @@ static void set_multicast_list(struct device *dev) ...@@ -1133,6 +1133,25 @@ static void set_multicast_list(struct device *dev)
} while (++i < 15); } while (++i < 15);
/* Now add this frame to the Tx list. */ /* Now add this frame to the Tx list. */
{
unsigned long flags;
unsigned int entry;
save_flags(flags); cli();
entry = tp->cur_tx++ % TX_RING_SIZE;
tp->dirty_tx++;
restore_flags(flags);
tp->tx_skbuff[entry] = 0;
/* Put the setup frame on the Tx list. */
tp->tx_ring[entry].length = 192 |
(entry == TX_RING_SIZE-1 ? 0x0a000000 : 0x08000000);
tp->tx_ring[entry].buffer1 = virt_to_bus((char *)tp->setup_frame);
tp->tx_ring[entry].buffer2 = 0;
tp->tx_ring[entry].status = TRING_OWN;
/* Trigger an immediate transmit demand. */
tio_write(TPOLL_TRIGGER, CSR1);
}
} }
} }
......
...@@ -336,11 +336,11 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) ...@@ -336,11 +336,11 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n"); if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
for(i=0; i<SCpnt->use_sg; i++) for(i=0; i<SCpnt->use_sg; i++)
{ {
cptr[i].dataptr = (long) sgpnt[i].address;
cptr[i].datalen = sgpnt[i].length; cptr[i].datalen = sgpnt[i].length;
cptr[i].dataptr = virt_to_bus(sgpnt[i].address);
} }
ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain); ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
ecb[ecbno].dataptr = (long) cptr; ecb[ecbno].dataptr = virt_to_bus(cptr);
#ifdef DEBUG #ifdef DEBUG
printk("cptr %x: ",cptr); printk("cptr %x: ",cptr);
ptr = (unsigned char *) cptr; ptr = (unsigned char *) cptr;
...@@ -351,15 +351,15 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) ...@@ -351,15 +351,15 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{ {
SCpnt->host_scribble = NULL; SCpnt->host_scribble = NULL;
ecb[ecbno].datalen = bufflen; ecb[ecbno].datalen = bufflen;
ecb[ecbno].dataptr = (long) buff; ecb[ecbno].dataptr = virt_to_bus(buff);
} }
ecb[ecbno].lun = SCpnt->lun; ecb[ecbno].lun = SCpnt->lun;
ecb[ecbno].ses = 1; /* Suppress underrun errors */ ecb[ecbno].ses = 1; /* Suppress underrun errors */
ecb[ecbno].dir= direction; ecb[ecbno].dir= direction;
ecb[ecbno].ars=1; /* Yes, get the sense on an error */ ecb[ecbno].ars=1; /* Yes, get the sense on an error */
ecb[ecbno].senselen = 12; ecb[ecbno].senselen = 12;
ecb[ecbno].senseptr = (long) ecb[ecbno].sense; ecb[ecbno].senseptr = virt_to_bus(ecb[ecbno].sense);
ecb[ecbno].statusptr = (long) ecb[ecbno].status; ecb[ecbno].statusptr = virt_to_bus(ecb[ecbno].status);
ecb[ecbno].done = done; ecb[ecbno].done = done;
ecb[ecbno].SCpnt = SCpnt; ecb[ecbno].SCpnt = SCpnt;
#ifdef DEBUG #ifdef DEBUG
......
This diff is collapsed.
...@@ -1799,7 +1799,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -1799,7 +1799,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
if ((++SCpnt->retries) < SCpnt->allowed) if ((++SCpnt->retries) < SCpnt->allowed)
{ {
if ((SCpnt->retries >= (SCpnt->allowed >> 1)) if ((SCpnt->retries >= (SCpnt->allowed >> 1))
&& !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD) && !(SCpnt->host->last_reset > 0 &&
jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
&& !(SCpnt->flags & WAS_RESET)) && !(SCpnt->flags & WAS_RESET))
{ {
printk("scsi%d channel %d : resetting for second half of retries.\n", printk("scsi%d channel %d : resetting for second half of retries.\n",
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment