diff -u --recursive --new-file v2.1.67/linux/Documentation/Changes linux/Documentation/Changes --- v2.1.67/linux/Documentation/Changes Tue Sep 23 16:48:46 1997 +++ linux/Documentation/Changes Sun Nov 30 12:23:16 1997 @@ -190,6 +190,19 @@ /dev/lp0 with the new Plug-and-Play driver. If printing breaks with the new driver, try checking your lpd configuration. +pppd +==== +This kernel version needs a minor bugfix to pppd. See +Documentation/networking/ppp.txt for more information. + +Syncookies +========== +When you build your kernel with Syncookie support (CONFIG_SYN_COOKIES) +the syncookie code still defaults to off (unlike the 2.0.30+ behaviour). +You have to explicitely enable it by add a line like +echo 1 >/proc/sys/net/ipv4/tcp_syncookies +to one of your startup scripts (e.g. /etc/rc.d/rc.local on a redhat system) + Bash ==== diff -u --recursive --new-file v2.1.67/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.67/linux/Documentation/Configure.help Sat Nov 29 11:25:08 1997 +++ linux/Documentation/Configure.help Sun Nov 30 10:30:18 1997 @@ -2781,18 +2781,51 @@ running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called scc.o. -BAYCOM ser12 and par96 driver for AX.25 -CONFIG_BAYCOM - This is an experimental driver for Baycom style simple amateur radio - modems that connect to either a serial interface or a parallel - interface. The driver supports the ser12 and par96 designs. To - configure the driver, use the sethdlc utility available in the - standard ax25 utilities package. For information on the modems, see +BAYCOM picpar and par96 driver for AX.25 +CONFIG_BAYCOM_PAR + This is a driver for Baycom style simple amateur radio + modems that connect to a parallel interface. The driver + supports the picpar and par96 designs. To configure the + driver, use the sethdlc utility available in the standard + ax25 utilities package. For information on the modems, see http://www.baycom.de and Documentation/networking/baycom.txt. If you want to compile this driver 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. The module will be called baycom.o. + recommended. The module will be called baycom_par.o. + +BAYCOM ser12 full duplex driver for AX.25 +CONFIG_BAYCOM_SER_FDX + This is one of two drivers for Baycom style simple amateur radio + modems that connect to a serial interface. The driver supports + the ser12 design in full duplex mode. In addition, it allows the + baudrate to be set between 300 and 4800 baud (however not all modems + support all baudrates). This is the preferred driver. baycom_ser_hdx.o + is the old driver and still provided in case this driver does not work + with your serial interface chip. To configure the driver, use the + sethdlc utility available in the standard ax25 utilities package. + For information on the modems, see http://www.baycom.de and + Documentation/networking/baycom.txt. If you want to compile + this driver 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. The module will be called baycom_ser_fdx.o. + +BAYCOM ser12 half duplex driver for AX.25 +CONFIG_BAYCOM_SER_HDX + This is one of two drivers for Baycom style simple amateur radio + modems that connect to a serial interface. The driver supports + the ser12 design in full duplex mode. This is the old driver. + It is still provided in case your serial interface chip does + not work with the full duplex driver. This driver is depreciated. + To configure the driver, use the sethdlc utility available + in the standard ax25 utilities package. For information + on the modems, see http://www.baycom.de and + Documentation/networking/baycom.txt. If you want to compile + this driver 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. The module will be called baycom_ser_hdx.o. Soundcard modem driver for AX.25 CONFIG_SOUNDMODEM @@ -5917,9 +5950,9 @@ flush the disks, reboot the system immediately or dump some status information). This is accomplished by pressing various keys while holding SysRq (Alt+PrintScreen). As you are expected to be a kernel - hacker to use this, the simple rule about learning what do the keys + hacker to use this, the simple rule about learning what the keys mean is "Use the source, Luke!" -- read drivers/char/sysrq.c. - Don't say Y unless you really know what does this hack do. + Don't say Y unless you really know what this hack does. ISDN subsystem CONFIG_ISDN diff -u --recursive --new-file v2.1.67/linux/Documentation/networking/ppp.txt linux/Documentation/networking/ppp.txt --- v2.1.67/linux/Documentation/networking/ppp.txt Tue Mar 5 00:01:26 1996 +++ linux/Documentation/networking/ppp.txt Sun Nov 30 12:23:16 1997 @@ -1,3 +1,33 @@ +*NEWSFLASH* +This kernel release needs a minor bug fix for pppd to run properly with +the new routing code. When your pppd doesn't work apply the following +patch to pppd-2.2.0f or install updated RPMs. + +Updated RPMs for libc5 machines (build on RedHat 4.0): +ftp://ftp.firstfloor.org/pub/ak/ppp-2.2.0f-4.src.rpm +ftp://ftp.firstfloor.org/pub/ak/ppp-2.2.0f-4.i386.rpm + +Patch: + +--- ppp-2.2.0f/pppd/sys-linux.c-o Wed Sep 17 00:23:01 1997 ++++ ppp-2.2.0f/pppd/sys-linux.c Wed Sep 17 00:23:11 1997 +@@ -927,8 +927,11 @@ + + if (ioctl(sockfd, SIOCADDRT, &rt) < 0) + { ++/* The new linux routing code doesn't like routes on down devices. */ ++#if 0 + syslog (LOG_ERR, "ioctl(SIOCADDRT) device route: %m"); + return (0); ++#endif + } + return 1; + } + + +-Andi Kleen +-------------------------------------------------------------------- + The PPP support for this kernel requires the 2.2.0 version of the pppd daemon. You will find the current version of the daemon on sunsite.unc.edu in the /pub/Linux/system/Network/serial directory. diff -u --recursive --new-file v2.1.67/linux/Documentation/networking/z8530drv.txt linux/Documentation/networking/z8530drv.txt --- v2.1.67/linux/Documentation/networking/z8530drv.txt Tue Oct 29 05:33:37 1996 +++ linux/Documentation/networking/z8530drv.txt Sat Nov 29 16:29:37 1997 @@ -4,14 +4,18 @@ Internet: ========= -1. db0bm.automation.fh-aachen.de/incoming/dl1bke/z8530drv-utils-3.0.tar.gz +1. ftp://db0bm.automation.fh-aachen.de/incoming/z8530drv/z8530drv-utils-3.0.tar.gz -2. ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz - If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz +2. ftp://ftp.pspt.fi/pub/ham/linux/ax25/z8530drv-utils-3.0.tar.gz -and various mirrors (i.e. nic.switch.ch) +3. ftp://ftp.ucsd.edu/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz + If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz Please note that the information in this document may be hopelessly outdated. +A new version of the documentation, along with links to other important +Linux Kernel AX.25 documentation and programs, is available on +http://www.rat.de/jr + ----------------------------------------------------------------------------- @@ -19,7 +23,7 @@ ******************************************************************** - (c) 1993,1996 by Joerg Reuter DL1BKE + (c) 1993,1997 by Joerg Reuter DL1BKE portions (c) 1993 Guido ten Dolle PE1NNZ @@ -134,7 +138,7 @@ to a higher value. -Example for the BayCom USCC: +Example for the BAYCOM USCC: ---------------------------- chip 1 @@ -228,7 +232,7 @@ gencfg 2 0x300 2 4 5 -4 0 7 4915200 0x10 -does the same for the BayCom USCC card. I my opinion it is much easier +does the same for the BAYCOM USCC card. I my opinion it is much easier to edit scc_config.h... @@ -332,7 +336,7 @@ and start your NOS and attach /dev/ptys0 there. The problem is that NOS is reachable only via digipeating through the kernel AX.25 -(disasterous on a DAMA controlled channel). To solve this problem, +(disastrous on a DAMA controlled channel). To solve this problem, configure "rxecho" to echo the incoming frames from "9k6" to "axlink" and outgoing frames from "axlink" to "9k6" and start: @@ -605,8 +609,9 @@ A very common problem is that the PTT locks until the maxkeyup timer expires, although interrupts and clock source are correct. In most -cases #define SCC_DELAY solves the problems. For more hints read -the (pseudo) FAQ and the documentation coming with z8530drv-utils. +cases compiling the driver with CONFIG_SCC_DELAY (set with +make config) solves the problems. For more hints read the (pseudo) FAQ +and the documentation coming with z8530drv-utils. I got reports that the driver has problems on some 386-based systems. (i.e. Amstrad) Those systems have a bogus AT bus timing which will @@ -624,7 +629,7 @@ - a high load of the machine --- running X, Xmorph, XV and Povray, while compiling the kernel... hmm ... even with 32 MB RAM ... ;-) - Or running a named for the whole .ampr.org. domain on an 8 MB + Or running a named for the whole .ampr.org domain on an 8 MB box... - using information from rxecho or kissbridge. @@ -651,4 +656,5 @@ Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU - Internet: jreuter@lykos.oche.de + Internet: jreuter@poboxes.com + WWW : http://www.rat.de/jr/ diff -u --recursive --new-file v2.1.67/linux/Makefile linux/Makefile --- v2.1.67/linux/Makefile Sat Nov 29 11:25:09 1997 +++ linux/Makefile Sat Nov 29 13:01:24 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 67 +SUBLEVEL = 68 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.67/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.1.67/linux/arch/alpha/kernel/alpha_ksyms.c Wed Apr 16 14:14:59 1997 +++ linux/arch/alpha/kernel/alpha_ksyms.c Sun Nov 30 10:59:02 1997 @@ -94,7 +94,7 @@ * The following are specially called from the uaccess assembly stubs. */ EXPORT_SYMBOL_NOVERS(__copy_user); -EXPORT_SYMBOL_NOVERS(__clear_user); +EXPORT_SYMBOL_NOVERS(__do_clear_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strlen_user); diff -u --recursive --new-file v2.1.67/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.67/linux/arch/alpha/kernel/entry.S Sat Oct 25 02:44:14 1997 +++ linux/arch/alpha/kernel/entry.S Sun Nov 30 10:59:02 1997 @@ -10,7 +10,7 @@ #define rti .long PAL_rti #define SIGCHLD 20 -#define NR_SYSCALLS 352 +#define NR_SYSCALLS 360 #define osf_vfork sys_fork /* @@ -32,13 +32,12 @@ #define TASK_STATE 0 #define TASK_COUNTER 8 #define TASK_PRIORITY 16 -#define TASK_SIGNAL 24 -#define TASK_BLOCKED 32 -#define TASK_FLAGS 40 +#define TASK_FLAGS 24 /* * task flags (must match include/linux/sched.h): */ +#define PF_SIGPENDING 0x00000008 #define PF_PTRACED 0x00000010 /* @@ -509,7 +508,7 @@ lda $4,NR_SYSCALLS($31) stq $16,SP_OFF+24($30) lda $5,sys_call_table - lda $27,do_entSys + lda $27,alpha_ni_syscall cmpult $0,$4,$4 ldq $3,TASK_FLAGS($8) stq $17,SP_OFF+32($30) @@ -519,7 +518,7 @@ bne $3,strace beq $4,1f ldq $27,0($5) -1: jsr $26,($27),do_entSys +1: jsr $26,($27),alpha_ni_syscall ldgp $29,0($26) blt $0,syscall_error /* the call failed */ stq $0,0($30) @@ -544,11 +543,10 @@ lda $4,init_task_union bne $2,reschedule xor $4,$8,$4 + ldq $5,TASK_FLAGS($8) beq $4,restore_all - ldq $4,TASK_SIGNAL($8) - ldq $16,TASK_BLOCKED($8) - bic $4,$16,$4 - bne $4,signal_return + and $5,PF_SIGPENDING,$5 + bne $5,signal_return restore_all: RESTORE_ALL rti @@ -574,12 +572,12 @@ /* get the system call pointer.. */ lda $1,NR_SYSCALLS($31) lda $2,sys_call_table - lda $27,do_entSys + lda $27,alpha_ni_syscall cmpult $0,$1,$1 s8addq $0,$2,$2 beq $1,1f ldq $27,0($2) -1: jsr $26,($27),do_entSys +1: jsr $26,($27),alpha_ni_syscall ldgp $29,0($26) /* check return.. */ @@ -656,6 +654,7 @@ bis $30,$30,$17 br $1,do_switch_stack bis $30,$30,$18 + bis $31,$31,$16 jsr $26,do_signal lda $30,SWITCH_STACK_SIZE($30) br $31,restore_all @@ -686,6 +685,17 @@ .end sys_sigreturn .align 3 +.ent sys_rt_sigreturn +sys_rt_sigreturn: + bis $30,$30,$17 + lda $30,-SWITCH_STACK_SIZE($30) + bis $30,$30,$18 + jsr $26,do_rt_sigreturn + br $1,undo_switch_stack + br $31,ret_from_sys_call +.end sys_rt_sigreturn + +.align 3 .ent sys_sigsuspend sys_sigsuspend: bis $30,$30,$17 @@ -696,80 +706,383 @@ br $31,ret_from_sys_call .end sys_sigsuspend +.align 3 +.ent sys_rt_sigsuspend +sys_rt_sigsuspend: + bis $30,$30,$18 + br $1,do_switch_stack + bis $30,$30,$19 + jsr $26,do_rt_sigsuspend + lda $30,SWITCH_STACK_SIZE($30) + br $31,ret_from_sys_call +.end sys_rt_sigsuspend + + .data .align 3 .globl sys_call_table sys_call_table: -/*0*/ .quad do_entSys, sys_exit, sys_fork, sys_read, sys_write - .quad do_entSys, sys_close, sys_wait4, do_entSys, sys_link - .quad sys_unlink, do_entSys, sys_chdir, sys_fchdir, sys_mknod - .quad sys_chmod, sys_chown, osf_brk, do_entSys, sys_lseek - .quad sys_getxpid, osf_mount, osf_umount, sys_setuid, sys_getxuid - .quad do_entSys, sys_ptrace, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, sys_access, do_entSys - .quad do_entSys, sys_sync, sys_kill, do_entSys, sys_setpgid - .quad do_entSys, sys_dup, sys_pipe, osf_set_program_attributes, do_entSys - .quad sys_open, do_entSys, sys_getxgid, osf_sigprocmask, do_entSys -/*50*/ .quad do_entSys, sys_acct, sys_sigpending, do_entSys, sys_ioctl - .quad do_entSys, do_entSys, sys_symlink, sys_readlink, sys_execve - .quad sys_umask, sys_chroot, do_entSys, sys_getpgrp, sys_getpagesize - .quad do_entSys, osf_vfork, sys_newstat, sys_newlstat, do_entSys - .quad do_entSys, osf_mmap, do_entSys, sys_munmap, sys_mprotect - .quad sys_madvise, sys_vhangup, do_entSys, do_entSys, sys_getgroups + .quad alpha_ni_syscall /* 0 */ + .quad sys_exit + .quad sys_fork + .quad sys_read + .quad sys_write + .quad alpha_ni_syscall /* 5 */ + .quad sys_close + .quad sys_wait4 + .quad alpha_ni_syscall + .quad sys_link + .quad sys_unlink /* 10 */ + .quad alpha_ni_syscall + .quad sys_chdir + .quad sys_fchdir + .quad sys_mknod + .quad sys_chmod /* 15 */ + .quad sys_chown + .quad osf_brk + .quad alpha_ni_syscall + .quad sys_lseek + .quad sys_getxpid /* 20 */ + .quad osf_mount + .quad osf_umount + .quad sys_setuid + .quad sys_getxuid + .quad alpha_ni_syscall /* 25 */ + .quad sys_ptrace + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 30 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad sys_access + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 35 */ + .quad sys_sync + .quad sys_kill + .quad alpha_ni_syscall + .quad sys_setpgid + .quad alpha_ni_syscall /* 40 */ + .quad sys_dup + .quad sys_pipe + .quad osf_set_program_attributes + .quad alpha_ni_syscall + .quad sys_open /* 45 */ + .quad alpha_ni_syscall + .quad sys_getxgid + .quad osf_sigprocmask + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 50 */ + .quad sys_acct + .quad osf_sigpending + .quad alpha_ni_syscall + .quad sys_ioctl + .quad alpha_ni_syscall /* 55 */ + .quad alpha_ni_syscall + .quad sys_symlink + .quad sys_readlink + .quad sys_execve + .quad sys_umask /* 60 */ + .quad sys_chroot + .quad alpha_ni_syscall + .quad sys_getpgrp + .quad sys_getpagesize + .quad alpha_ni_syscall /* 65 */ + .quad osf_vfork + .quad sys_newstat + .quad sys_newlstat + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 70 */ + .quad osf_mmap + .quad alpha_ni_syscall + .quad sys_munmap + .quad sys_mprotect + .quad sys_madvise /* 75 */ + .quad sys_vhangup + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad sys_getgroups /* map BSD's setpgrp to sys_setpgid for binary compatibility: */ - .quad sys_setgroups, do_entSys, sys_setpgid, sys_setitimer, do_entSys - .quad do_entSys, sys_getitimer, sys_gethostname, sys_sethostname, sys_getdtablesize - .quad sys_dup2, sys_newfstat, sys_fcntl, sys_select, sys_poll - .quad sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept -/*100*/ .quad osf_getpriority, sys_send, sys_recv, sys_sigreturn, sys_bind - .quad sys_setsockopt, sys_listen, do_entSys, do_entSys, do_entSys - .quad do_entSys, sys_sigsuspend, do_entSys, sys_recvmsg, sys_sendmsg - .quad do_entSys, sys_gettimeofday, sys_getrusage, sys_getsockopt, do_entSys - .quad sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod - .quad sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate - .quad sys_ftruncate, sys_flock, sys_setgid, sys_sendto, sys_shutdown - .quad sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, do_entSys - .quad do_entSys, sys_getpeername, do_entSys, do_entSys, sys_getrlimit - .quad sys_setrlimit, do_entSys, sys_setsid, sys_quotactl, do_entSys -/*150*/ .quad sys_getsockname, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, sys_sigaction, do_entSys, do_entSys, osf_getdirentries - .quad osf_statfs, osf_fstatfs, do_entSys, do_entSys, do_entSys - .quad osf_getdomainname, sys_setdomainname, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, osf_swapon -/*200*/ .quad sys_msgctl, sys_msgget, sys_msgrcv, sys_msgsnd, sys_semctl - .quad sys_semget, sys_semop, osf_utsname, do_entSys, osf_shmat - .quad sys_shmctl, sys_shmdt, sys_shmget, do_entSys, do_entSys - .quad do_entSys, do_entSys, sys_msync, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, sys_getpgid, sys_getsid - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, osf_sysinfo, do_entSys, do_entSys, osf_proplist_syscall - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys -/*250*/ .quad do_entSys, osf_usleep_thread, do_entSys, do_entSys, sys_sysfs - .quad do_entSys, osf_getsysinfo, osf_setsysinfo, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad sys_setgroups /* 80 */ + .quad alpha_ni_syscall + .quad sys_setpgid + .quad sys_setitimer + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 85 */ + .quad sys_getitimer + .quad sys_gethostname + .quad sys_sethostname + .quad sys_getdtablesize + .quad sys_dup2 /* 90 */ + .quad sys_newfstat + .quad sys_fcntl + .quad sys_select + .quad sys_poll + .quad sys_fsync /* 95 */ + .quad sys_setpriority + .quad sys_socket + .quad sys_connect + .quad sys_accept + .quad osf_getpriority /* 100 */ + .quad sys_send + .quad sys_recv + .quad sys_sigreturn + .quad sys_bind + .quad sys_setsockopt /* 105 */ + .quad sys_listen + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 110 */ + .quad sys_sigsuspend + .quad alpha_ni_syscall + .quad sys_recvmsg + .quad sys_sendmsg + .quad alpha_ni_syscall /* 115 */ + .quad sys_gettimeofday + .quad sys_getrusage + .quad sys_getsockopt + .quad alpha_ni_syscall + .quad sys_readv /* 120 */ + .quad sys_writev + .quad sys_settimeofday + .quad sys_fchown + .quad sys_fchmod + .quad sys_recvfrom /* 125 */ + .quad sys_setreuid + .quad sys_setregid + .quad sys_rename + .quad sys_truncate + .quad sys_ftruncate /* 130 */ + .quad sys_flock + .quad sys_setgid + .quad sys_sendto + .quad sys_shutdown + .quad sys_socketpair /* 135 */ + .quad sys_mkdir + .quad sys_rmdir + .quad sys_utimes + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 140 */ + .quad sys_getpeername + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad sys_getrlimit + .quad sys_setrlimit /* 145 */ + .quad alpha_ni_syscall + .quad sys_setsid + .quad sys_quotactl + .quad alpha_ni_syscall + .quad sys_getsockname /* 150 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 155 */ + .quad osf_sigaction + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad osf_getdirentries + .quad osf_statfs /* 160 */ + .quad osf_fstatfs + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad osf_getdomainname /* 165 */ + .quad sys_setdomainname + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 170 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 175 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 180 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 185 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 190 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 195 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad osf_swapon + .quad sys_msgctl /* 200 */ + .quad sys_msgget + .quad sys_msgrcv + .quad sys_msgsnd + .quad sys_semctl + .quad sys_semget /* 205 */ + .quad sys_semop + .quad osf_utsname + .quad alpha_ni_syscall + .quad osf_shmat + .quad sys_shmctl /* 210 */ + .quad sys_shmdt + .quad sys_shmget + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 215 */ + .quad alpha_ni_syscall + .quad sys_msync + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 220 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 225 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 230 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad sys_getpgid + .quad sys_getsid + .quad alpha_ni_syscall /* 235 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 240 */ + .quad osf_sysinfo + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad osf_proplist_syscall + .quad alpha_ni_syscall /* 245 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 250 */ + .quad osf_usleep_thread + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad sys_sysfs + .quad alpha_ni_syscall /* 255 */ + .quad osf_getsysinfo + .quad osf_setsysinfo + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 260 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 265 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 270 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 275 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 280 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 285 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 290 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 295 */ + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* linux-specific system calls start at 300 */ -/*300*/ .quad sys_bdflush, sys_sethae, sys_mount, sys_adjtimex, sys_swapoff - .quad sys_getdents, alpha_create_module, sys_init_module, sys_delete_module, sys_get_kernel_syms - .quad sys_syslog, sys_reboot, sys_clone, sys_uselib, sys_mlock - .quad sys_munlock, sys_mlockall, sys_munlockall, sys_sysinfo, sys_sysctl - .quad sys_idle, sys_umount, sys_swapon, sys_times, sys_personality - .quad sys_setfsuid, sys_setfsgid, sys_ustat, sys_statfs, sys_fstatfs - .quad sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler, sys_sched_yield - .quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname - .quad sys_nanosleep, sys_mremap, sys_nfsservctl, sys_setresuid, sys_getresuid - .quad sys_pciconfig_read, sys_pciconfig_write, sys_query_module - .quad sys_prctl, sys_pread, sys_pwrite - .quad do_entSys, do_entSys + .quad sys_bdflush /* 300 */ + .quad sys_sethae + .quad sys_mount + .quad sys_adjtimex + .quad sys_swapoff + .quad sys_getdents /* 305 */ + .quad alpha_create_module + .quad sys_init_module + .quad sys_delete_module + .quad sys_get_kernel_syms + .quad sys_syslog /* 310 */ + .quad sys_reboot + .quad sys_clone + .quad sys_uselib + .quad sys_mlock + .quad sys_munlock /* 315 */ + .quad sys_mlockall + .quad sys_munlockall + .quad sys_sysinfo + .quad sys_sysctl + .quad sys_idle /* 320 */ + .quad sys_umount + .quad sys_swapon + .quad sys_times + .quad sys_personality + .quad sys_setfsuid /* 325 */ + .quad sys_setfsgid + .quad sys_ustat + .quad sys_statfs + .quad sys_fstatfs + .quad sys_sched_setparam /* 330 */ + .quad sys_sched_getparam + .quad sys_sched_setscheduler + .quad sys_sched_getscheduler + .quad sys_sched_yield + .quad sys_sched_get_priority_max /* 335 */ + .quad sys_sched_get_priority_min + .quad sys_sched_rr_get_interval + .quad alpha_ni_syscall /* sys_afs_syscall */ + .quad sys_newuname + .quad sys_nanosleep /* 340 */ + .quad sys_mremap + .quad sys_nfsservctl + .quad sys_setresuid + .quad sys_getresuid + .quad sys_pciconfig_read /* 345 */ + .quad sys_pciconfig_write + .quad sys_query_module + .quad sys_prctl + .quad sys_pread + .quad sys_pwrite /* 350 */ + .quad sys_rt_sigreturn + .quad sys_rt_sigaction + .quad sys_rt_sigprocmask + .quad sys_rt_sigpending + .quad sys_rt_sigtimedwait /* 355 */ + .quad sys_rt_sigqueueinfo + .quad sys_rt_sigsuspend + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall + .quad alpha_ni_syscall /* 360 */ diff -u --recursive --new-file v2.1.67/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.1.67/linux/arch/alpha/kernel/ptrace.c Mon Aug 4 16:25:35 1997 +++ linux/arch/alpha/kernel/ptrace.c Sun Nov 30 10:59:02 1997 @@ -574,7 +574,7 @@ (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > NSIG) + if ((unsigned long) data > _NSIG) goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; @@ -606,7 +606,7 @@ case PTRACE_SINGLESTEP: { /* execute single instruction. */ ret = -EIO; - if ((unsigned long) data > NSIG) + if ((unsigned long) data > _NSIG) goto out; child->debugreg[4] = -1; /* mark single-stepping */ child->flags &= ~PF_TRACESYS; @@ -619,7 +619,7 @@ case PTRACE_DETACH: { /* detach a process that was attached. */ ret = -EIO; - if ((unsigned long) data > NSIG) + if ((unsigned long) data > _NSIG) goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); @@ -627,7 +627,7 @@ REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); - /* make sure single-step breakpoint is gone. */ + /* make sure single-step breakpoint is gone. */ ptrace_cancel_bpt(child); ret = 0; goto out; @@ -644,22 +644,20 @@ asmlinkage void syscall_trace(void) { - lock_kernel(); if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - goto out; + return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); /* - * this isn't the same as continuing with a signal, but it will do + * 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; -out: - unlock_kernel(); + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } } diff -u --recursive --new-file v2.1.67/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.1.67/linux/arch/alpha/kernel/signal.c Mon Aug 4 16:25:35 1997 +++ linux/arch/alpha/kernel/signal.c Sun Nov 30 10:59:02 1997 @@ -2,6 +2,8 @@ * linux/arch/alpha/kernel/signal.c * * Copyright (C) 1995 Linus Torvalds + * + * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson */ #include @@ -14,21 +16,26 @@ #include #include #include +#include +#include #include #include +#include + +#define DEBUG_SIG 0 -#define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int sys_wait4(int, int *, int, struct rusage *); asmlinkage void ret_from_sys_call(void); -asmlinkage int do_signal(unsigned long, struct pt_regs *, struct switch_stack *, - unsigned long, unsigned long); +asmlinkage int do_signal(sigset_t *, struct pt_regs *, + struct switch_stack *, unsigned long, unsigned long); extern int ptrace_set_bpt (struct task_struct *child); extern int ptrace_cancel_bpt (struct task_struct *child); + /* * The OSF/1 sigprocmask calling sequence is different from the * C sigprocmask() sequence.. @@ -44,51 +51,152 @@ * Note that we don't need to acquire the kernel lock for SMP * operation, as all of this is local to this thread. */ -asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask, - long a2, long a3, long a4, long a5, struct pt_regs regs) +asmlinkage unsigned long +osf_sigprocmask(int how, unsigned long newmask, long a2, long a3, + long a4, long a5, struct pt_regs regs) { - unsigned long ok, oldmask; - struct task_struct * tsk; + unsigned long oldmask = -EINVAL; - ok = how-1; /* 0 .. 2 */ - tsk = current; - ok = ok <= 2; - oldmask = -EINVAL; - if (ok) { - long sign; /* -1 .. 1 */ + if ((unsigned long)how-1 <= 2) { + long sign = how-2; /* -1 .. 1 */ unsigned long block, unblock; - oldmask = tsk->blocked; newmask &= _BLOCKABLE; - sign = how-2; + spin_lock_irq(¤t->sigmask_lock); + oldmask = current->blocked.sig[0]; + unblock = oldmask & ~newmask; block = oldmask | newmask; if (!sign) block = unblock; - regs.r0 = 0; /* special no error return */ if (sign <= 0) newmask = block; - tsk->blocked = newmask; + if (_NSIG_WORDS > 1 && sign > 0) + sigemptyset(¤t->blocked); + current->blocked.sig[0] = newmask; + spin_unlock_irq(¤t->sigmask_lock); + + (®s)->r0 = 0; /* special no error return */ } return oldmask; } +asmlinkage int +osf_sigaction(int sig, const struct osf_sigaction *act, + struct osf_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags)) + return -EFAULT; + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + new_ka.ka_restorer = NULL; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags)) + return -EFAULT; + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, + void *restorer, size_t sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (act) { + new_ka.ka_restorer = restorer; + if (copy_from_user(&new_ka.sa, act, sizeof(*act))) + return -EFAULT; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (copy_to_user(oact, &old_ka.sa, sizeof(*oact))) + return -EFAULT; + } + + return ret; +} + +asmlinkage int +osf_sigpending(old_sigset_t *set) +{ + sigset_t pending; + + spin_lock_irq(¤t->sigmask_lock); + sigandsets(&pending, ¤t->blocked, ¤t->signal); + spin_unlock_irq(¤t->sigmask_lock); + + return copy_to_user(set, &pending, sizeof(*set)); +} + /* - * atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw) +asmlinkage int +do_sigsuspend(old_sigset_t mask, struct pt_regs *reg, struct switch_stack *sw) +{ + sigset_t oldset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + oldset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&oldset, reg, sw, 0, 0)) + return -EINTR; + } +} + +asmlinkage int +do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize, + struct pt_regs *reg, struct switch_stack *sw) { - unsigned long oldmask; + sigset_t oldset, set; + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + if (copy_from_user(&set, uset, sizeof(set))) + return -EFAULT; + + sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); - oldmask = current->blocked; - current->blocked = mask & _BLOCKABLE; + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(oldmask, regs, sw, 0, 0)) + if (do_signal(&oldset, reg, sw, 0, 0)) return -EINTR; } } @@ -96,26 +204,35 @@ /* * Do a signal return; undo the signal stack. */ -asmlinkage void do_sigreturn(struct sigcontext * sc, - struct pt_regs * regs, struct switch_stack * sw) + +struct sigframe { - unsigned long mask, ps, usp; - int i; + struct sigcontext sc; + unsigned long extramask[_NSIG_WORDS-1]; + unsigned int retcode[3]; +}; - /* verify that it's a good sigcontext before using it */ - if (verify_area(VERIFY_READ, sc, sizeof(*sc))) - goto give_sigsegv; - if (__get_user(ps, &sc->sc_ps) || ps != 8) - goto give_sigsegv; - if (__get_user(mask, &sc->sc_mask) || (mask & ~_BLOCKABLE)) - goto give_sigsegv; +struct rt_sigframe +{ + struct siginfo info; + struct ucontext uc; + unsigned int retcode[3]; +}; + +#define INSN_MOV_R30_R16 0x47fe0410 +#define INSN_LDI_R0 0x201f0000 +#define INSN_CALLSYS 0x00000083 + + +static void +restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + struct switch_stack *sw) +{ + unsigned long usp; + int i; - /* ok, looks fine, start restoring */ - __get_user(usp, sc->sc_regs+30); - wrusp(usp); __get_user(regs->pc, &sc->sc_pc); sw->r26 = (unsigned long) ret_from_sys_call; - current->blocked = mask; __get_user(regs->r0, sc->sc_regs+0); __get_user(regs->r1, sc->sc_regs+1); @@ -147,47 +264,98 @@ __get_user(regs->r27, sc->sc_regs+27); __get_user(regs->r28, sc->sc_regs+28); __get_user(regs->gp, sc->sc_regs+29); + __get_user(usp, sc->sc_regs+30); + wrusp(usp); + for (i = 0; i < 31; i++) __get_user(sw->fp[i], sc->sc_fpregs+i); + __get_user(sw->fp[31], &sc->sc_fpcr); +} - /* send SIGTRAP if we're single-stepping: */ - lock_kernel(); +asmlinkage void +do_sigreturn(struct sigframe *frame, struct pt_regs *regs, + struct switch_stack *sw) +{ + unsigned long ps; + sigset_t set; + + /* Verify that it's a good sigcontext before using it */ + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto give_sigsegv; + if (__get_user(ps, &frame->sc.sc_ps) || ps != 8) + goto give_sigsegv; + if (__get_user(set.sig[0], &frame->sc.sc_mask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto give_sigsegv; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + restore_sigcontext(&frame->sc, regs, sw); + + /* Send SIGTRAP if we're single-stepping: */ if (ptrace_cancel_bpt (current)) send_sig(SIGTRAP, current, 1); - unlock_kernel(); return; give_sigsegv: lock_kernel(); do_exit(SIGSEGV); - unlock_kernel(); } -/* - * Set up a signal frame... - */ -static void setup_frame(struct sigaction * sa, - struct pt_regs * regs, - struct switch_stack * sw, int signr, - unsigned long oldmask) +asmlinkage void +do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs, + struct switch_stack *sw) { - int i; - unsigned long oldsp; - struct sigcontext * sc; + unsigned long ps; + sigset_t set; - oldsp = rdusp(); - sc = ((struct sigcontext *) oldsp) - 1; + /* Verify that it's a good sigcontext before using it */ + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto give_sigsegv; + if (__get_user(ps, &frame->uc.uc_mcontext.sc_ps) || ps != 8) + goto give_sigsegv; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto give_sigsegv; - /* check here if we would need to switch stacks.. */ - if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) - do_exit(SIGSEGV); + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); - wrusp((unsigned long) sc); + restore_sigcontext(&frame->uc.uc_mcontext, regs, sw); - __put_user(oldmask, &sc->sc_mask); - __put_user(8, &sc->sc_ps); + /* Send SIGTRAP if we're single-stepping: */ + if (ptrace_cancel_bpt (current)) + send_sig(SIGTRAP, current, 1); + return; + +give_sigsegv: + lock_kernel(); + do_exit(SIGSEGV); +} + + +/* + * Set up a signal frame. + */ + +static void +setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + struct switch_stack *sw, unsigned long mask, unsigned long sp) +{ + long i; + + __put_user(0, &sc->sc_onstack); + __put_user(mask, &sc->sc_mask); __put_user(regs->pc, &sc->sc_pc); - __put_user(oldsp, sc->sc_regs+30); + __put_user(8, &sc->sc_ps); __put_user(regs->r0 , sc->sc_regs+0); __put_user(regs->r1 , sc->sc_regs+1); @@ -219,63 +387,167 @@ __put_user(regs->r27, sc->sc_regs+27); __put_user(regs->r28, sc->sc_regs+28); __put_user(regs->gp , sc->sc_regs+29); + __put_user(sp, sc->sc_regs+30); + __put_user(0, sc->sc_regs+31); + for (i = 0; i < 31; i++) __put_user(sw->fp[i], sc->sc_fpregs+i); + __put_user(0, sc->sc_fpregs+31); + __put_user(sw->fp[31], &sc->sc_fpcr); + __put_user(regs->trap_a0, &sc->sc_traparg_a0); __put_user(regs->trap_a1, &sc->sc_traparg_a1); __put_user(regs->trap_a2, &sc->sc_traparg_a2); +} + +static void +setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, + struct pt_regs *regs, struct switch_stack * sw) +{ + unsigned long oldsp; + struct sigframe *frame; + + oldsp = rdusp(); + frame = (struct sigframe *)((oldsp - sizeof(*frame)) & -32); + + /* XXX: Check here if we would need to switch stacks.. */ + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); + if (_NSIG_WORDS > 1) { + __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->ka_restorer) { + regs->r26 = (unsigned long) ka->ka_restorer; + } else { + __put_user(INSN_MOV_R30_R16, frame->retcode+0); + __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); + __put_user(INSN_CALLSYS, frame->retcode+2); + imb(); + regs->r26 = (unsigned long) frame->retcode; + } + + /* "Return" to the handler */ + regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; + regs->r16 = sig; /* a0: signal number */ + regs->r17 = 0; /* a1: exception code */ + regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ + wrusp((unsigned long) frame); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", + current->comm, current->pid, frame, regs->pc, regs->r26); +#endif + + return; + +give_sigsegv: + lock_kernel(); + do_exit(SIGSEGV); +} + +static void +setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) +{ + unsigned long oldsp; + struct rt_sigframe *frame; + + oldsp = rdusp(); + frame = (struct rt_sigframe *)((oldsp - sizeof(*frame)) & -32); + + /* XXX: Check here if we would need to switch stacks.. */ + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; - /* - * The following is: - * - * bis $30,$30,$16 - * addq $31,0x67,$0 - * call_pal callsys - * - * ie, "sigreturn(stack-pointer)" - */ - __put_user(0x43ecf40047de0410, sc->sc_retcode+0); - __put_user(0x0000000000000083, sc->sc_retcode+1); - imb(); - - /* "return" to the handler */ - regs->r27 = regs->pc = (unsigned long) sa->sa_handler; - regs->r26 = (unsigned long) sc->sc_retcode; - regs->r16 = signr; /* a0: signal number */ - regs->r17 = 0; /* a1: exception code; see gentrap.h */ - regs->r18 = (unsigned long) sc; /* a2: sigcontext pointer */ + __copy_to_user(&frame->info, info, sizeof(siginfo_t)); + + /* Zero all bits of the ucontext besides the sigcontext. */ + __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + /* Copy in the bits we actually use. */ + __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); + setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp); + __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->ka_restorer) { + regs->r26 = (unsigned long) ka->ka_restorer; + } else { + __put_user(INSN_MOV_R30_R16, frame->retcode+0); + __put_user(INSN_LDI_R0+__NR_rt_sigreturn, frame->retcode+1); + __put_user(INSN_CALLSYS, frame->retcode+2); + imb(); + regs->r26 = (unsigned long) frame->retcode; + } + + /* "Return" to the handler */ + regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; + regs->r16 = sig; /* a0: signal number */ + regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ + regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */ + wrusp((unsigned long) frame); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", + current->comm, current->pid, frame, regs->pc, regs->r26); +#endif + + return; + +give_sigsegv: + lock_kernel(); + do_exit(SIGSEGV); } + /* - * OK, we're invoking a handler + * OK, we're invoking a handler. */ -static inline void handle_signal(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs * regs, struct switch_stack *sw) +static inline void +handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw) { - setup_frame(sa,regs,sw,signr,oldmask); - - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if (!(sa->sa_flags & SA_NOMASK)) - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs, sw); + else + setup_frame(sig, ka, oldset, regs, sw); + + if (ka->sa.sa_flags & SA_RESETHAND) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sigmask_lock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + } } -static inline void syscall_restart(unsigned long r0, unsigned long r19, - struct pt_regs * regs, struct sigaction * sa) +static inline void +syscall_restart(unsigned long r0, unsigned long r19, + struct pt_regs *regs, struct k_sigaction *ka) { switch (regs->r0) { + case ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { case ERESTARTNOHAND: - no_system_call_restart: regs->r0 = EINTR; break; - case ERESTARTSYS: - if (!(sa->sa_flags & SA_RESTART)) - goto no_system_call_restart; + } /* fallthrough */ - case ERESTARTNOINTR: - regs->r0 = r0; /* reset v0 and a3 and replay syscall */ - regs->r19 = r19; - regs->pc -= 4; + case ERESTARTNOINTR: + regs->r0 = r0; /* reset v0 and a3 and replay syscall */ + regs->r19 = r19; + regs->pc -= 4; + break; } } @@ -293,94 +565,118 @@ * restart. "r0" is also used as an indicator whether we can restart at * all (if we get here from anything but a syscall return, it will be 0) */ -asmlinkage int do_signal(unsigned long oldmask, - struct pt_regs * regs, - struct switch_stack * sw, - unsigned long r0, unsigned long r19) -{ - unsigned long mask; - unsigned long signr, single_stepping; - struct sigaction * sa; - int ret; +asmlinkage int +do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, + unsigned long r0, unsigned long r19) +{ + sigset_t _oldset; + siginfo_t info; + unsigned long signr, single_stepping, core = 0; + struct k_sigaction *ka; - lock_kernel(); - mask = ~current->blocked; single_stepping = ptrace_cancel_bpt(current); - while ((signr = current->signal & mask) != 0) { - signr = ffz(~signr); - clear_bit(signr, ¤t->signal); - sa = current->sig->action + signr; - signr++; + spin_lock_irq(current->sigmask_lock); + if (!oldset) { + _oldset = current->blocked; + oldset = &_oldset; + } + while ((signr = dequeue_signal(¤t->blocked, &info)) != 0) { + spin_unlock_irq(¤t->sigmask_lock); + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); single_stepping |= ptrace_cancel_bpt(current); + + /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) - continue; + goto skip_signal; current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) - continue; - if (_S(signr) & current->blocked) { - current->signal |= _S(signr); - continue; + goto skip_signal; + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); + goto skip_signal; } - sa = current->sig->action + signr - 1; - } - if (sa->sa_handler == SIG_IGN) { - if (signr != SIGCHLD) - continue; - /* check for SIGCHLD: it's special */ - while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) - /* nothing */; - continue; } - if (sa->sa_handler == SIG_DFL) { + + ka = ¤t->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_DFL) { + /* Init gets no signals it doesn't want. */ if (current->pid == 1) - continue; + goto skip_signal; + switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: - continue; + goto skip_signal; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) - continue; + goto skip_signal; + /* FALLTHRU */ + case SIGSTOP: - if (current->flags & PF_PTRACED) - continue; current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & - SA_NOCLDSTOP)) + if (!(current->p_pptr->sig->action[SIGCHLD-1] + .sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); single_stepping |= ptrace_cancel_bpt(current); - continue; + break; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - if (current->binfmt && current->binfmt->core_dump) { - if (current->binfmt->core_dump(signr, regs)) - signr |= 0x80; - } - /* fall through */ + lock_kernel(); + if (current->binfmt + && current->binfmt->core_dump + &¤t->binfmt->core_dump(signr, regs)) + core = 0x80; + unlock_kernel(); + /* FALLTHRU */ + default: - current->signal |= _S(signr & 0x7f); + lock_kernel(); + sigaddset(¤t->signal, signr); current->flags |= PF_SIGNALED; - do_exit(signr); + do_exit((signr & 0x7f) | core); } + } else if (ka->sa.sa_handler == SIG_IGN) { + if (signr == SIGCHLD) { + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; + } + } else { + /* Whee! Actually deliver the signal. */ + if (r0) syscall_restart(r0, r19, regs, ka); + handle_signal(signr, ka, &info, oldset, regs, sw); + if (single_stepping) + ptrace_set_bpt(current); /* re-set bpt */ + return 1; } - if (r0) - syscall_restart(r0, r19, regs, sa); - handle_signal(signr, sa, oldmask, regs, sw); - if (single_stepping) { - ptrace_set_bpt(current); /* re-set breakpoint */ - } - ret = 1; - goto out; + skip_signal: + spin_lock_irq(¤t->sigmask_lock); } + spin_unlock_irq(¤t->sigmask_lock); + if (r0 && (regs->r0 == ERESTARTNOHAND || regs->r0 == ERESTARTSYS || @@ -389,11 +685,8 @@ regs->r19 = r19; regs->pc -= 4; } - if (single_stepping) { + if (single_stepping) ptrace_set_bpt(current); /* re-set breakpoint */ - } - ret = 0; -out: - unlock_kernel(); - return ret; + + return 0; } diff -u --recursive --new-file v2.1.67/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.1.67/linux/arch/alpha/kernel/time.c Wed Nov 12 13:34:25 1997 +++ linux/arch/alpha/kernel/time.c Sun Nov 30 10:59:02 1997 @@ -17,17 +17,18 @@ * (round system clock to nearest tick instead of truncating) * fixed algorithm in time_init for getting time from CMOS clock */ +#include #include #include #include #include #include #include +#include #include #include #include -#include #include #include @@ -52,16 +53,18 @@ /* lump static variables together for more efficient access: */ static struct { - __u32 last_time; /* cycle counter last time it got invoked */ - unsigned long scaled_ticks_per_cycle; /* ticks/cycle * 2^48 */ - long last_rtc_update; /* last time the cmos clock got updated */ + /* cycle counter last time it got invoked */ + __u32 last_time; + /* ticks/cycle * 2^48 */ + unsigned long scaled_ticks_per_cycle; + /* last time the cmos clock got updated */ + time_t last_rtc_update; } state; static inline __u32 rpcc(void) { __u32 result; - asm volatile ("rpcc %0" : "r="(result)); return result; } @@ -73,37 +76,46 @@ */ void timer_interrupt(int irq, void *dev, struct pt_regs * regs) { - __u32 delta, now; - int i, nticks; + const unsigned long half = 1UL << (FIX_SHIFT - 1); + const unsigned long mask = (1UL << (FIX_SHIFT + 1)) - 1; + unsigned long delta; + __u32 now; + long nticks; + /* + * Estimate how many ticks have passed since the last update. + * Round the result, .5 to even. When we loose ticks due to + * say using IDE, the clock has been seen to run up to 15% slow + * if we truncate. + */ now = rpcc(); delta = now - state.last_time; state.last_time = now; - if(hwrpb->cycle_freq) { - nticks = (delta * state.scaled_ticks_per_cycle) >> (FIX_SHIFT-1); - nticks = (nticks+1) >> 1; - } - else nticks=1; /* No way to estimate lost ticks if we don't know - the cycle frequency. */ - for (i = 0; i < nticks; ++i) { + delta = delta * state.scaled_ticks_per_cycle; + if ((delta & mask) != half) + delta += half; + nticks = delta >> FIX_SHIFT; + + do { do_timer(regs); - } + } while (--nticks > 0); /* * If we have an externally synchronized Linux clock, then update * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. */ - if (time_state != TIME_BAD && xtime.tv_sec > state.last_rtc_update + 660 && - xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) - if (set_rtc_mmss(xtime.tv_sec) == 0) - state.last_rtc_update = xtime.tv_sec; - else - state.last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + if (time_state != TIME_BAD + && xtime.tv_sec > state.last_rtc_update + 660 + && xtime.tv_usec >= 500000 - (tick >> 1) + && xtime.tv_usec <= 500000 + (tick >> 1)) { + int tmp = set_rtc_mmss(xtime.tv_sec); + state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0); + } } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. +/* + * Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. * @@ -140,25 +152,40 @@ unsigned char save_control; #endif void (*irq_handler)(int, void *, struct pt_regs *); - unsigned int year, mon, day, hour, min, sec; + unsigned int year, mon, day, hour, min, sec, cc1, cc2; - /* The Linux interpretation of the CMOS clock register contents: + /* + * The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the * RTC registers show the second which has precisely just started. * Let's hope other operating systems interpret the RTC the same way. */ - /* read RTC exactly on falling edge of update flag */ - /* Wait for rise.... (may take up to 1 second) */ - - do {} while(!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); - -/* Jay Estabook : - * Wait for the Update Done Interrupt bit (0x10) in reg C (12) to be set, - * which (hopefully) indicates that the update is really done. - */ - - do {} while(!CMOS_READ(RTC_REG_C) & RTC_UIP); - + do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); + do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + + /* Read cycle counter exactly on falling edge of update flag */ + cc1 = rpcc(); + + /* If our cycle frequency isn't valid, go another round and give + a guess at what it should be. */ + if (hwrpb->cycle_freq == 0) { + printk("HWPRB cycle frequency bogus. Estimating... "); + + do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); + do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + cc2 = rpcc(); + hwrpb->cycle_freq = cc2 - cc1; + cc1 = cc2; + + printk("%lu Hz\n", hwrpb->cycle_freq); + } + + /* From John Bowman : allow the values + to settle, as the Update-In-Progress bit going low isn't good + enough on some hardware. 2ms is our guess; we havn't found + bogomips yet, but this is close on a 500Mhz box. */ + __delay(1000000); + sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); hour = CMOS_READ(RTC_HOURS); @@ -167,14 +194,14 @@ year = CMOS_READ(RTC_YEAR); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - } + { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } #ifdef ALPHA_PRE_V1_2_SRM_CONSOLE /* * The meaning of life, the universe, and everything. Plus @@ -192,9 +219,10 @@ extern void __you_loose (void); __you_loose(); } - state.last_time = rpcc(); - if(hwrpb->cycle_freq) - state.scaled_ticks_per_cycle = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq; + + state.last_time = cc1; + state.scaled_ticks_per_cycle + = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq; state.last_rtc_update = 0; #ifdef CONFIG_RTC @@ -210,22 +238,52 @@ /* setup timer */ irq_handler = timer_interrupt; if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL)) - panic("Could not allocate timer IRQ!"); + panic("Could not allocate timer IRQ!"); } /* - * We could get better timer accuracy by using the alpha - * time counters or something. Now this is limited to - * the HZ clock frequency. + * Use the cycle counter to estimate an displacement from the last time + * tick. Unfortunately the Alpha designers made only the low 32-bits of + * the cycle counter active, so we overflow on 8.2 seconds on a 500MHz + * part. So we can't do the "find absolute time in terms of cycles" thing + * that the other ports do. */ void do_gettimeofday(struct timeval *tv) { - unsigned long flags; + unsigned long flags, now, delta_cycles, delta_usec; + unsigned long sec, usec; - save_flags(flags); - cli(); - *tv = xtime; + now = rpcc(); + save_and_cli(flags); + sec = xtime.tv_sec; + usec = xtime.tv_usec; + delta_cycles = now - state.last_time; restore_flags(flags); + + /* + * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks) + * = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks) + * = cycles * (s_t_p_c) * 15625 / (2**42 * ticks) + * + * which, given a 600MHz cycle and a 1024Hz tick, has a + * dynamic range of about 1.7e17, which is less than the + * 1.8e19 in an unsigned long, so we are safe from overflow. + * + * Round, but with .5 up always, since .5 to even is harder + * with no clear gain. + */ + + delta_usec = delta_cycles * state.scaled_ticks_per_cycle * 15625; + delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6)) * HZ)) + 1) / 2; + + usec += delta_usec; + if (usec >= 1000000) { + sec += 1; + usec -= 1000000; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; } void do_settimeofday(struct timeval *tv) @@ -252,10 +310,12 @@ int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + /* Tell the clock it's being set */ + save_control = CMOS_READ(RTC_CONTROL); CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + /* Stop and reset prescaler */ + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); cmos_minutes = CMOS_READ(RTC_MINUTES); @@ -270,8 +330,10 @@ */ real_seconds = nowtime % 60; real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) { + /* correct for half hour time zone */ + real_minutes += 30; + } real_minutes %= 60; if (abs(real_minutes - cmos_minutes) < 30) { diff -u --recursive --new-file v2.1.67/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.1.67/linux/arch/alpha/kernel/traps.c Wed Sep 3 20:52:41 1997 +++ linux/arch/alpha/kernel/traps.c Sun Nov 30 10:59:02 1997 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -20,45 +21,41 @@ #include -void die_if_kernel(char * str, struct pt_regs * regs, long err, - unsigned long *r9_15) +static void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15) { - long i; - unsigned long ra; - unsigned int * pc; - unsigned long * sp; - - if (regs->ps & 8) - return; - printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); - sp = (unsigned long *) (regs+1); - __get_user(ra, (unsigned long *)sp); - printk("pc = [<%016lx>] ps = %04lx\n", regs->pc, regs->ps); - printk("rp = [<%016lx>] ra = [<%016lx>]\n", regs->r26, ra); - printk("r0 = %016lx r1 = %016lx\n", regs->r0, regs->r1); - printk("r2 = %016lx r3 = %016lx\n", regs->r2, regs->r3); - printk("r4 = %016lx r5 = %016lx\n", regs->r4, regs->r5); - printk("r6 = %016lx r7 = %016lx\n", regs->r6, regs->r7); + printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n", + regs->pc, regs->r26, regs->ps); + printk("r0 = %016lx r1 = %016lx r2 = %016lx\n", + regs->r0, regs->r1, regs->r2); + printk("r3 = %016lx r4 = %016lx r5 = %016lx\n", + regs->r3, regs->r4, regs->r5); + printk("r6 = %016lx r7 = %016lx r8 = %016lx\n", + regs->r6, regs->r7, regs->r8); if (r9_15) { - printk("r8 = %016lx r9 = %016lx\n", regs->r8, r9_15[9]); - printk("r10= %016lx r11= %016lx\n", r9_15[10], r9_15[11]); - printk("r12= %016lx r13= %016lx\n", r9_15[12], r9_15[13]); - printk("r14= %016lx r15= %016lx\n", r9_15[14], r9_15[15]); - } else { - printk("r8 = %016lx\n", regs->r8); - } + printk("r9 = %016lx r10= %016lx r11= %016lx\n", + r9_15[9], r9_15[10], r9_15[11]); + printk("r12= %016lx r13= %016lx r14= %016lx\n", + r9_15[12], r9_15[13], r9_15[14]); + printk("r15= %016lx\n", r9_15[15]); + } + + printk("r16= %016lx r17= %016lx r18= %016lx\n", + regs->r16, regs->r17, regs->r18); + printk("r19= %016lx r20= %016lx r21= %016lx\n", + regs->r19, regs->r20, regs->r21); + printk("r22= %016lx r23= %016lx r24= %016lx\n", + regs->r22, regs->r23, regs->r24); + printk("r25= %016lx r27= %016lx r28= %016lx\n", + regs->r25, regs->r27, regs->r28); + printk("gp = %016lx sp = %p\n", regs->gp, regs+1); +} - printk("r16= %016lx r17= %016lx\n", regs->r16, regs->r17); - printk("r18= %016lx r19= %016lx\n", regs->r18, regs->r19); - printk("r20= %016lx r21= %016lx\n", regs->r20, regs->r21); - printk("r22= %016lx r23= %016lx\n", regs->r22, regs->r23); - printk("r24= %016lx r25= %016lx\n", regs->r24, regs->r25); - printk("r27= %016lx r28= %016lx\n", regs->r27, regs->r28); - printk("gp = %016lx sp = %p\n", regs->gp, sp); +static void dik_show_code(unsigned int *pc) +{ + long i; printk("Code:"); - pc = (unsigned int *) regs->pc; for (i = -3; i < 6; i++) { unsigned int insn; if (__get_user(insn, pc+i)) @@ -66,6 +63,11 @@ printk("%c%08x%c",i?' ':'<',insn,i?' ':'>'); } printk("\n"); +} + +static void dik_show_trace(unsigned long *sp) +{ + long i = 0; printk("Trace:"); while (0x1ff8 & (unsigned long) sp) { extern unsigned long _stext, _etext; @@ -76,9 +78,30 @@ if (tmp >= (unsigned long) &_etext) continue; printk(" [<%lx>]", tmp); + if (++i > 40) { + printk(" ..."); + break; + } } printk("\n"); - +} + +void die_if_kernel(char * str, struct pt_regs *regs, long err, + unsigned long *r9_15) +{ + if (regs->ps & 8) + return; + printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); + dik_show_regs(regs, r9_15); + dik_show_code((unsigned int *)regs->pc); + dik_show_trace((unsigned long *)(regs+1)); + + if (current->tss.flags & (1UL << 63)) { + printk("die_if_kernel recursion detected.\n"); + sti(); + while (1); + } + current->tss.flags |= (1UL << 63); do_exit(SIGSEGV); } @@ -397,8 +420,6 @@ printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n", pc, va, opcode, reg); do_exit(SIGSEGV); - unlock_kernel(); - return; got_exception: /* Ok, we caught the exception, but we don't want it. Is there @@ -416,13 +437,48 @@ return; } - /* Yikes! No one to forward the exception to. */ + /* + * Yikes! No one to forward the exception to. + * Since the registers are in a weird format, dump them ourselves. + */ lock_kernel(); - printk("%s: unhandled unaligned exception at pc=%lx ra=%lx" - " (bad address = %p)\n", current->comm, - pc, una_reg(26), va); + + printk("%s(%d): unhandled unaligned exception\n", + current->comm, current->pid); + + printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n", + pc, una_reg(26), regs.ps); + printk("r0 = %016lx r1 = %016lx r2 = %016lx\n", + una_reg(0), una_reg(1), una_reg(2)); + printk("r3 = %016lx r4 = %016lx r5 = %016lx\n", + una_reg(3), una_reg(4), una_reg(5)); + printk("r6 = %016lx r7 = %016lx r8 = %016lx\n", + una_reg(6), una_reg(7), una_reg(8)); + printk("r9 = %016lx r10= %016lx r11= %016lx\n", + una_reg(9), una_reg(10), una_reg(11)); + printk("r12= %016lx r13= %016lx r14= %016lx\n", + una_reg(12), una_reg(13), una_reg(14)); + printk("r15= %016lx\n", una_reg(15)); + printk("r16= %016lx r17= %016lx r18= %016lx\n", + una_reg(16), una_reg(17), una_reg(18)); + printk("r19= %016lx r20= %016lx r21= %016lx\n", + una_reg(19), una_reg(20), una_reg(21)); + printk("r22= %016lx r23= %016lx r24= %016lx\n", + una_reg(22), una_reg(23), una_reg(24)); + printk("r25= %016lx r27= %016lx r28= %016lx\n", + una_reg(25), una_reg(27), una_reg(28)); + printk("gp = %016lx sp = %p\n", regs.gp, ®s+1); + + dik_show_code((unsigned int *)pc); + dik_show_trace((unsigned long *)(®s+1)); + + if (current->tss.flags & (1UL << 63)) { + printk("die_if_kernel recursion detected.\n"); + sti(); + while (1); + } + current->tss.flags |= (1UL << 63); do_exit(SIGSEGV); - unlock_kernel(); } /* @@ -800,26 +856,17 @@ } /* - * DEC means people to use the "retsys" instruction for return from - * a system call, but they are clearly misguided about this. We use - * "rti" in all cases, and fill in the stack with the return values. - * That should make signal handling etc much cleaner. - * - * Even more horribly, DEC doesn't allow system calls from kernel mode. - * "Security" features letting the user do something the kernel can't - * are a thinko. DEC palcode is strange. The PAL-code designers probably - * got terminally tainted by VMS at some point. + * Unimplemented system calls. */ -asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs) +asmlinkage long alpha_ni_syscall(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + struct pt_regs regs) { - lock_kernel(); /* Only report OSF system calls. */ if (regs.r0 != 112 && regs.r0 < 300) printk("", regs.r0, a0, a1, a2); - unlock_kernel(); - return -1; + return -ENOSYS; } extern asmlinkage void entMM(void); diff -u --recursive --new-file v2.1.67/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile --- v2.1.67/linux/arch/alpha/lib/Makefile Sun Dec 1 11:27:21 1996 +++ linux/arch/alpha/lib/Makefile Sun Nov 30 10:59:02 1997 @@ -19,9 +19,6 @@ lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) -memset.o: memset.S - $(CC) -c -o memset.o memset.S - __divqu.o: divide.S $(CC) -DDIV -c -o __divqu.o divide.S diff -u --recursive --new-file v2.1.67/linux/arch/alpha/lib/clear_user.S linux/arch/alpha/lib/clear_user.S --- v2.1.67/linux/arch/alpha/lib/clear_user.S Fri Jan 3 08:48:37 1997 +++ linux/arch/alpha/lib/clear_user.S Sun Nov 30 10:59:02 1997 @@ -37,8 +37,8 @@ .set noreorder .align 4 - .globl __clear_user - .ent __clear_user + .globl __do_clear_user + .ent __do_clear_user .frame $30, 0, $28 .prologue 0 @@ -79,7 +79,7 @@ EX( stq_u $5, 0($6) ) # e0 : ret $31, ($28), 1 # .. e1 : -__clear_user: +__do_clear_user: and $6, 7, $4 # e0 : find dest misalignment beq $0, $zerolength # .. e1 : addq $0, $4, $1 # e0 : bias counter @@ -110,4 +110,4 @@ $exception: ret $31, ($28), 1 # .. e1 : - .end __clear_user + .end __do_clear_user diff -u --recursive --new-file v2.1.67/linux/arch/alpha/lib/csum_partial_copy.c linux/arch/alpha/lib/csum_partial_copy.c --- v2.1.67/linux/arch/alpha/lib/csum_partial_copy.c Mon Apr 14 16:28:05 1997 +++ linux/arch/alpha/lib/csum_partial_copy.c Sun Nov 30 10:59:02 1997 @@ -8,7 +8,7 @@ */ #include -#include +#include #include diff -u --recursive --new-file v2.1.67/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.67/linux/arch/i386/kernel/entry.S Wed Nov 26 16:24:01 1997 +++ linux/arch/i386/kernel/entry.S Sun Nov 30 10:59:02 1997 @@ -73,15 +73,14 @@ state = 0 counter = 4 priority = 8 -signal = 12 -blocked = 16 -flags = 20 -dbgreg6 = 52 -dbgreg7 = 56 -exec_domain = 60 +flags = 12 +dbgreg6 = 44 +dbgreg7 = 48 +exec_domain = 52 ENOSYS = 38 + #define SAVE_ALL \ cld; \ push %es; \ @@ -170,10 +169,7 @@ ret_with_reschedule: cmpl $0,SYMBOL_NAME(need_resched) jne reschedule - movl blocked(%ebx),%eax - movl %eax,%esi # save blocked in %esi for signal handling - notl %eax - andl signal(%ebx),%eax + testb $0x8,flags(%ebx) # PF_SIGPENDING jne signal_return RESTORE_ALL ALIGN @@ -181,7 +177,7 @@ testl $(VM_MASK),EFLAGS(%esp) pushl %esp jne v86_signal_return - pushl %esi + pushl $0 call SYMBOL_NAME(do_signal) addl $8,%esp RESTORE_ALL @@ -190,7 +186,7 @@ call SYMBOL_NAME(save_v86_state) movl %eax,%esp pushl %eax - pushl %esi + pushl $0 call SYMBOL_NAME(do_signal) addl $8,%esp RESTORE_ALL @@ -529,6 +525,13 @@ .long SYMBOL_NAME(sys_setresgid) /* 170 */ .long SYMBOL_NAME(sys_getresgid) .long SYMBOL_NAME(sys_prctl) - .rept NR_syscalls-172 + .long SYMBOL_NAME(sys_rt_sigreturn) + .long SYMBOL_NAME(sys_rt_sigaction) + .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */ + .long SYMBOL_NAME(sys_rt_sigpending) + .long SYMBOL_NAME(sys_rt_sigtimedwait) + .long SYMBOL_NAME(sys_rt_sigqueueinfo) + .long SYMBOL_NAME(sys_rt_sigsuspend) + .rept NR_syscalls-179 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.1.67/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.1.67/linux/arch/i386/kernel/ptrace.c Mon Aug 4 16:25:35 1997 +++ linux/arch/i386/kernel/ptrace.c Sun Nov 30 10:59:02 1997 @@ -492,7 +492,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data > NSIG) + if ((unsigned long) data > _NSIG) goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; @@ -530,7 +530,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data > NSIG) + if ((unsigned long) data > _NSIG) goto out; child->flags &= ~PF_TRACESYS; tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; @@ -546,7 +546,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data > NSIG) + if ((unsigned long) data > _NSIG) goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); @@ -585,9 +585,7 @@ * stopping signal is not SIGTRAP. -brl */ if (current->exit_code) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= (1 << (current->exit_code - 1)); - spin_unlock_irq(¤t->sigmask_lock); + send_sig(current->exit_code, current, 1); + current->exit_code = 0; } - current->exit_code = 0; } diff -u --recursive --new-file v2.1.67/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.1.67/linux/arch/i386/kernel/signal.c Mon Aug 4 16:25:35 1997 +++ linux/arch/i386/kernel/signal.c Sun Nov 30 12:49:13 1997 @@ -2,6 +2,8 @@ * linux/arch/i386/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson */ #include @@ -16,40 +18,132 @@ #include #include #include +#include #include -#define _S(nr) (1<<((nr)-1)) +#define DEBUG_SIG 0 -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); - -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); /* - * atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set) +asmlinkage int +sys_sigsuspend(int history0, int history1, old_sigset_t mask) { - struct pt_regs * regs = (struct pt_regs *) &restart; - unsigned long mask; + struct pt_regs * regs = (struct pt_regs *) &history0; + sigset_t saveset; + mask &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->eax = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(mask, regs)) + if (do_signal(&saveset, regs)) return -EINTR; } } +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +{ + struct pt_regs * regs = (struct pt_regs *) &unewset; + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->eax = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe +{ + char *pretcode; + int sig; + struct sigcontext sc; + struct _fpstate fpstate; + unsigned long extramask[_NSIG_WORDS-1]; + char retcode[8]; +}; + +struct rt_sigframe +{ + char *pretcode; + int sig; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + struct _fpstate fpstate; + char retcode[8]; +}; + + static inline void restore_i387_hard(struct _fpstate *buf) { #ifdef __SMP__ @@ -64,94 +158,150 @@ #endif current->used_math = 1; current->flags &= ~PF_USEDFPU; - copy_from_user(¤t->tss.i387.hard, buf, sizeof(*buf)); + __copy_from_user(¤t->tss.i387.hard, buf, sizeof(*buf)); } -static void restore_i387(struct _fpstate *buf) +static inline void restore_i387(struct _fpstate *buf) { #ifndef CONFIG_MATH_EMULATION restore_i387_hard(buf); #else - if (hard_math) { + if (hard_math) restore_i387_hard(buf); - return; - } - restore_i387_soft(buf); -#endif + else + restore_i387_soft(buf); +#endif } - -/* - * This sets regs->esp even though we don't actually use sigstacks yet.. - */ -asmlinkage int sys_sigreturn(unsigned long __unused) +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { -#define COPY(x) regs->x = context->x -#define COPY_SEG(seg) \ -{ unsigned int tmp = context->seg; \ -if ( (tmp & 0xfffc) /* not a NULL selectors */ \ - && (tmp & 0x4) != 0x4 /* not a LDT selector */ \ - && (tmp & 3) != 3 /* not a RPL3 GDT selector */ \ - ) goto badframe; \ -regs->x##seg = tmp; } -#define COPY_SEG_STRICT(seg) \ -{ unsigned int tmp = context->seg; \ -if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \ -regs->x##seg = tmp; } -#define GET_SEG(seg) \ -{ unsigned int tmp = context->seg; \ -if ( (tmp & 0xfffc) /* not a NULL selectors */ \ - && (tmp & 0x4) != 0x4 /* not a LDT selector */ \ - && (tmp & 3) != 3 /* not a RPL3 GDT selector */ \ - ) goto badframe; \ -__asm__("mov %w0,%%" #seg: :"r" (tmp)); } - struct sigcontext * context; - struct pt_regs * regs; - - regs = (struct pt_regs *) &__unused; - context = (struct sigcontext *) regs->esp; - if (verify_area(VERIFY_READ, context, sizeof(*context))) - goto badframe; - current->blocked = context->oldmask & _BLOCKABLE; - COPY_SEG(ds); - COPY_SEG(es); - GET_SEG(fs); + unsigned int tmp; + +#define COPY(x) __get_user(regs->x, &sc->x) + +#define COPY_SEG(seg) \ + { __get_user(tmp, &sc->seg); \ + if ((tmp & 0xfffc) /* not a NULL selectors */ \ + && (tmp & 0x4) != 0x4 /* not a LDT selector */ \ + && (tmp & 3) != 3) /* not a RPL3 GDT selector */ \ + goto badframe; \ + regs->x##seg = tmp; } + +#define COPY_SEG_STRICT(seg) \ + { __get_user(tmp, &sc->seg); \ + if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \ + regs->x##seg = tmp; } + +#define GET_SEG(seg) \ + { __get_user(tmp, &sc->seg); \ + if ((tmp & 0xfffc) /* not a NULL selectors */ \ + && (tmp & 0x4) != 0x4 /* not a LDT selector */ \ + && (tmp & 3) != 3) /* not a RPL3 GDT selector */ \ + goto badframe; \ + __asm__ __volatile__("mov %w0,%%" #seg : : "r"(tmp)); } + GET_SEG(gs); - COPY_SEG_STRICT(ss); - COPY_SEG_STRICT(cs); - COPY(eip); - COPY(ecx); COPY(edx); + GET_SEG(fs); + COPY_SEG(es); + COPY_SEG(ds); + COPY(edi); + COPY(esi); + COPY(ebp); + COPY(esp); COPY(ebx); - COPY(esp); COPY(ebp); - COPY(edi); COPY(esi); - regs->eflags &= ~0x40DD5; - regs->eflags |= context->eflags & 0x40DD5; + COPY(edx); + COPY(ecx); + COPY(eip); + COPY_SEG_STRICT(cs); + COPY_SEG_STRICT(ss); + + __get_user(tmp, &sc->eflags); + regs->eflags = (regs->eflags & ~0x40DD5) | (tmp & 0x40DD5); regs->orig_eax = -1; /* disable syscall checks */ - if (context->fpstate) { - struct _fpstate * buf = context->fpstate; + + __get_user(tmp, (unsigned long *)&sc->fpstate); + if (tmp) { + struct _fpstate * buf = (struct _fpstate *) tmp; if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; restore_i387(buf); } - return context->eax; + + __get_user(tmp, &sc->eax); + return tmp; badframe: lock_kernel(); do_exit(SIGSEGV); - unlock_kernel(); } +asmlinkage int sys_sigreturn(unsigned long __unused) +{ + struct pt_regs *regs = (struct pt_regs *) &__unused; + struct sigframe *frame = (struct sigframe *)(regs->esp - 8); + sigset_t set; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + return restore_sigcontext(regs, &frame->sc); + +badframe: + lock_kernel(); + do_exit(SIGSEGV); +} + +asmlinkage int sys_rt_sigreturn(unsigned long __unused) +{ + struct pt_regs *regs = (struct pt_regs *) &__unused; + struct rt_sigframe *frame = (struct rt_sigframe *)(regs->esp - 4); + sigset_t set; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + return restore_sigcontext(regs, &frame->uc.uc_mcontext); + +badframe: + lock_kernel(); + do_exit(SIGSEGV); +} + +/* + * Set up a signal frame. + */ + static inline struct _fpstate * save_i387_hard(struct _fpstate * buf) { #ifdef __SMP__ if (current->flags & PF_USEDFPU) { - __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard)); + __asm__ __volatile__("fnsave %0":"=m"(current->tss.i387.hard)); stts(); current->flags &= ~PF_USEDFPU; } #else if (current == last_task_used_math) { - __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard)); + __asm__ __volatile__("fnsave %0":"=m"(current->tss.i387.hard)); last_task_used_math = NULL; __asm__ __volatile__("fwait"); /* not needed on 486+ */ stts(); @@ -163,7 +313,7 @@ return buf; } -static struct _fpstate * save_i387(struct _fpstate * buf) +static struct _fpstate * save_i387(struct _fpstate *buf) { if (!current->used_math) return NULL; @@ -171,85 +321,168 @@ #ifndef CONFIG_MATH_EMULATION return save_i387_hard(buf); #else - if (hard_math) - return save_i387_hard(buf); - return save_i387_soft(buf); + return hard_math ? save_i387_hard(buf) : save_i387_soft(buf); #endif } -/* - * Set up a signal frame... Make the stack look the way iBCS2 expects - * it to look. - */ -static void setup_frame(struct sigaction * sa, - struct pt_regs * regs, int signr, - unsigned long oldmask) -{ - unsigned long * frame; - - frame = (unsigned long *) regs->esp; - if ((regs->xss & 0xffff) != USER_DS && sa->sa_restorer) - frame = (unsigned long *) sa->sa_restorer; - frame -= 64; - if (!access_ok(VERIFY_WRITE,frame,64*4)) - goto segv_and_exit; +static void +setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate, + struct pt_regs *regs, unsigned long mask) +{ + unsigned int tmp; -/* set up the "normal" stack seen by the signal handler (iBCS2) */ -#define __CODE ((unsigned long)(frame+24)) -#define CODE(x) ((unsigned long *) ((x)+__CODE)) - - /* XXX Can possible miss a SIGSEGV when frame crosses a page border - and a thread unmaps it while we are accessing it. - So either check all put_user() calls or don't do it at all. - We use __put_user() here because the access_ok() call was already - done earlier. */ - if (__put_user(__CODE,frame)) + tmp = 0; + __asm__("mov %%gs,%w0" : "=r"(tmp): "0"(tmp)); + __put_user(tmp, (unsigned int *)&sc->gs); + __asm__("mov %%fs,%w0" : "=r"(tmp): "0"(tmp)); + __put_user(tmp, (unsigned int *)&sc->fs); + + __put_user(regs->xes, (unsigned int *)&sc->es); + __put_user(regs->xds, (unsigned int *)&sc->ds); + __put_user(regs->edi, &sc->edi); + __put_user(regs->esi, &sc->esi); + __put_user(regs->ebp, &sc->ebp); + __put_user(regs->esp, &sc->esp); + __put_user(regs->ebx, &sc->ebx); + __put_user(regs->edx, &sc->edx); + __put_user(regs->ecx, &sc->ecx); + __put_user(regs->eax, &sc->eax); + __put_user(current->tss.trap_no, &sc->trapno); + __put_user(current->tss.error_code, &sc->err); + __put_user(regs->eip, &sc->eip); + __put_user(regs->xcs, (unsigned int *)&sc->cs); + __put_user(regs->eflags, &sc->eflags); + __put_user(regs->esp, &sc->esp_at_signal); + __put_user(regs->xss, (unsigned int *)&sc->ss); + + __put_user(save_i387(fpstate), &sc->fpstate); + + /* non-iBCS2 extensions.. */ + __put_user(mask, &sc->oldmask); + __put_user(current->tss.cr2, &sc->cr2); +} + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs * regs) +{ + struct sigframe *frame; + + frame = (struct sigframe *)((regs->esp - sizeof(*frame)) & -8); + + /* XXX: Check here if we need to switch stacks.. */ + + /* This is legacy signal stack switching. */ + if ((regs->xss & 0xffff) != USER_DS + && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer) + frame = (struct sigframe *) ka->sa.sa_restorer; + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto segv_and_exit; - if (current->exec_domain && current->exec_domain->signal_invmap) - __put_user(current->exec_domain->signal_invmap[signr], frame+1); - else - __put_user(signr, frame+1); + + __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + + setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); + + if (_NSIG_WORDS > 1) { + __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + __put_user(ka->sa.sa_restorer, &frame->pretcode); + } else { + __put_user(frame->retcode, &frame->pretcode); + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + __put_user(0xb858, (short *)(frame->retcode+0)); + __put_user(__NR_sigreturn, (int *)(frame->retcode+2)); + __put_user(0x80cd, (short *)(frame->retcode+6)); + } + + /* Set up registers for signal handler */ + regs->esp = (unsigned long) frame; + regs->eip = (unsigned long) ka->sa.sa_handler; { - unsigned int tmp = 0; -#define PUT_SEG(seg, mem) \ -__asm__("mov %%" #seg",%w0":"=r" (tmp):"0" (tmp)); __put_user(tmp,mem); - PUT_SEG(gs, frame+2); - PUT_SEG(fs, frame+3); - } - __put_user(regs->xes, frame+4); - __put_user(regs->xds, frame+5); - __put_user(regs->edi, frame+6); - __put_user(regs->esi, frame+7); - __put_user(regs->ebp, frame+8); - __put_user(regs->esp, frame+9); - __put_user(regs->ebx, frame+10); - __put_user(regs->edx, frame+11); - __put_user(regs->ecx, frame+12); - __put_user(regs->eax, frame+13); - __put_user(current->tss.trap_no, frame+14); - __put_user(current->tss.error_code, frame+15); - __put_user(regs->eip, frame+16); - __put_user(regs->xcs, frame+17); - __put_user(regs->eflags, frame+18); - __put_user(regs->esp, frame+19); - __put_user(regs->xss, frame+20); - __put_user((unsigned long) save_i387((struct _fpstate *)(frame+32)),frame+21); -/* non-iBCS2 extensions.. */ - __put_user(oldmask, frame+22); - __put_user(current->tss.cr2, frame+23); -/* set up the return code... */ - __put_user(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */ - __put_user(0x80cd0000, CODE(4)); /* int $0x80 */ - __put_user(__NR_sigreturn, CODE(2)); -#undef __CODE -#undef CODE + unsigned long seg = USER_DS; + __asm__("mov %w0,%%fs ; mov %w0,%%gs": "=r"(seg) : "0"(seg)); + set_fs(seg); + regs->xds = seg; + regs->xes = seg; + regs->xss = seg; + regs->xcs = USER_CS; + } + regs->eflags &= ~TF_MASK; + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", + current->comm, current->pid, frame, regs->eip, frame->pretcode); +#endif + + return; + +segv_and_exit: + lock_kernel(); + do_exit(SIGSEGV); +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs * regs) +{ + struct rt_sigframe *frame; + + frame = (struct rt_sigframe *)((regs->esp - sizeof(*frame)) & -8); + + /* XXX: Check here if we need to switch stacks.. */ + + /* This is legacy signal stack switching. */ + if ((regs->xss & 0xffff) != USER_DS + && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer) + frame = (struct rt_sigframe *) ka->sa.sa_restorer; + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto segv_and_exit; + + __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + __put_user(&frame->info, &frame->pinfo); + __put_user(&frame->uc, &frame->puc); + __copy_to_user(&frame->info, info, sizeof(*info)); + + /* Clear all the bits of the ucontext we don't use. */ + __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, + regs, set->sig[0]); + __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + __put_user(ka->sa.sa_restorer, &frame->pretcode); + } else { + __put_user(frame->retcode, &frame->pretcode); + /* This is movl $,%eax ; int $0x80 */ + __put_user(0xb8, (char *)(frame->retcode+0)); + __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1)); + __put_user(0x80cd, (short *)(frame->retcode+5)); + } /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; - regs->eip = (unsigned long) sa->sa_handler; + regs->eip = (unsigned long) ka->sa.sa_handler; { unsigned long seg = USER_DS; - __asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg)); + __asm__("mov %w0,%%fs ; mov %w0,%%gs": "=r"(seg) : "0"(seg)); set_fs(seg); regs->xds = seg; regs->xes = seg; @@ -257,21 +490,28 @@ regs->xcs = USER_CS; } regs->eflags &= ~TF_MASK; + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", + current->comm, current->pid, frame, regs->eip, frame->pretcode); +#endif + return; segv_and_exit: lock_kernel(); do_exit(SIGSEGV); - unlock_kernel(); } /* * OK, we're invoking a handler */ -static void handle_signal(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs * regs) + +static void +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { - /* are we from a system call? */ + /* Are we from a system call? */ if (regs->orig_eax >= 0) { /* If so, check system call restarting.. */ switch (regs->eax) { @@ -280,7 +520,7 @@ break; case -ERESTARTSYS: - if (!(sa->sa_flags & SA_RESTART)) { + if (!(ka->sa.sa_flags & SA_RESTART)) { regs->eax = -EINTR; break; } @@ -291,14 +531,20 @@ } } - /* set up the stack frame */ - setup_frame(sa, regs, signr, oldmask); + /* Set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if (!(sa->sa_flags & SA_NOMASK)) { + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sigmask_lock); - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); } } @@ -312,107 +558,115 @@ * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) { - unsigned long mask; - unsigned long signr; - struct sigaction * sa; + sigset_t _oldset; + siginfo_t info; + unsigned long signr, core = 0; + struct k_sigaction *ka; /* - * We want the common case to go fast, which + * We want the common case to go fast, which * is why we may in certain cases get here from * kernel mode. Just return without doing anything * if so. */ if ((regs->xcs & 3) != 3) return 1; - mask = ~current->blocked; - while ((signr = current->signal & mask)) { - /* - * This stops gcc flipping out. Otherwise the assembler - * including volatiles for the inline function to get - * current combined with this gets it confused. - */ - struct task_struct *t=current; - __asm__("bsf %3,%1\n\t" -#ifdef __SMP__ - "lock ; " -#endif - "btrl %1,%0" - :"=m" (t->signal),"=r" (signr) - :"0" (t->signal), "1" (signr)); - sa = current->sig->action + signr; - signr++; + + spin_lock_irq(¤t->sigmask_lock); + if (!oldset) { + _oldset = current->blocked; + oldset = &_oldset; + } + while ((signr = dequeue_signal(¤t->blocked, &info)) != 0) { + spin_unlock_irq(¤t->sigmask_lock); + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); + + /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) - continue; + goto skip_signal; current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) - continue; - if (_S(signr) & current->blocked) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr); - spin_unlock_irq(¤t->sigmask_lock); - continue; + goto skip_signal; + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); + goto skip_signal; } - sa = current->sig->action + signr - 1; - } - if (sa->sa_handler == SIG_IGN) { - if (signr != SIGCHLD) - continue; - /* check for SIGCHLD: it's special */ - while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0) - /* nothing */; - continue; } - if (sa->sa_handler == SIG_DFL) { + + ka = ¤t->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_DFL) { + /* Init gets no signals it doesn't want. */ if (current->pid == 1) - continue; + goto skip_signal; + switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: - continue; + goto skip_signal; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) - continue; + goto skip_signal; + /* FALLTHRU */ + case SIGSTOP: - if (current->flags & PF_PTRACED) - continue; current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & - SA_NOCLDSTOP)) + if (!(current->p_pptr->sig->action[SIGCHLD-1] + .sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); - continue; + break; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: lock_kernel(); - if (current->binfmt && current->binfmt->core_dump) { - if (current->binfmt->core_dump(signr, regs)) - signr |= 0x80; - } + if (current->binfmt + && current->binfmt->core_dump + &¤t->binfmt->core_dump(signr, regs)) + core = 0x80; unlock_kernel(); - /* fall through */ - default: - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); + /* FALLTHRU */ + default: + lock_kernel(); + sigaddset(¤t->signal, signr); current->flags |= PF_SIGNALED; - - lock_kernel(); /* 8-( */ - do_exit(signr); - unlock_kernel(); + do_exit((signr & 0x7f) | core); + } + } else if (ka->sa.sa_handler == SIG_IGN) { + if (signr == SIGCHLD) { + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; } + } else { + /* Whee! Actually deliver the signal. */ + handle_signal(signr, ka, &info, oldset, regs); + return 1; } - handle_signal(signr, sa, oldmask, regs); - return 1; + skip_signal: + spin_lock_irq(¤t->sigmask_lock); } /* Did we come from a system call? */ diff -u --recursive --new-file v2.1.67/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.1.67/linux/arch/i386/kernel/vm86.c Tue May 13 22:41:01 1997 +++ linux/arch/i386/kernel/vm86.c Sun Nov 30 10:59:02 1997 @@ -438,8 +438,13 @@ } if (trapno !=1) return 1; /* we let this handle by the calling routine */ - if (current->flags & PF_PTRACED) - current->blocked &= ~(1 << (SIGTRAP-1)); + if (current->flags & PF_PTRACED) { + unsigned long flags; + spin_lock_irqsave(¤t->sigmask_lock, flags); + sigdelset(¤t->blocked, SIGTRAP); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + } send_sig(SIGTRAP, current, 1); current->tss.trap_no = trapno; current->tss.error_code = error_code; diff -u --recursive --new-file v2.1.67/linux/arch/i386/lib/delay.c linux/arch/i386/lib/delay.c --- v2.1.67/linux/arch/i386/lib/delay.c Sat Nov 29 11:25:09 1997 +++ linux/arch/i386/lib/delay.c Sat Nov 29 16:54:20 1997 @@ -9,7 +9,7 @@ */ #include -#include +#include #ifdef __SMP__ #include diff -u --recursive --new-file v2.1.67/linux/drivers/char/hfmodem/main.c linux/drivers/char/hfmodem/main.c --- v2.1.67/linux/drivers/char/hfmodem/main.c Mon Aug 11 14:47:04 1997 +++ linux/drivers/char/hfmodem/main.c Sun Nov 30 10:30:19 1997 @@ -136,8 +136,6 @@ #define LPT_CONTROL(iobase) (iobase+2) #define LPT_IRQ_ENABLE 0x10 -#define LPT_EXTENT 3 - #define MIDI_DATA(iobase) (iobase) #define MIDI_STATUS(iobase) (iobase+1) #define MIDI_READ_FULL 0x80 /* attention: negative logic!! */ @@ -150,33 +148,37 @@ #define SP_MIDI 4 /* ---------------------------------------------------------------------- */ -/* - * returns 0 if ok and != 0 on error; - * the same behaviour as par96_check_lpt in baycom.c - */ -__initfunc(static int check_lpt(unsigned int iobase)) +static int parptt_preempt(void *handle) { - unsigned char b1,b2; - int i; + /* we cannot relinquish the port in the middle of an operation */ + return 1; +} - if (iobase <= 0 || iobase > 0x1000-LPT_EXTENT) - return 0; - if (check_region(iobase, LPT_EXTENT)) - return 0; - b1 = inb(LPT_DATA(iobase)); - b2 = inb(LPT_CONTROL(iobase)); - outb(0xaa, LPT_DATA(iobase)); - i = inb(LPT_DATA(iobase)) == 0xaa; - outb(0x55, LPT_DATA(iobase)); - i &= inb(LPT_DATA(iobase)) == 0x55; - outb(0x0a, LPT_CONTROL(iobase)); - i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a; - outb(0x05, LPT_CONTROL(iobase)); - i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05; - outb(b1, LPT_DATA(iobase)); - outb(b2, LPT_CONTROL(iobase)); - return !i; +/* --------------------------------------------------------------------- */ + +static void parptt_wakeup(void *handle) +{ + struct hfmodem_state *dev = (struct hfmodem_state *)handle; + + printk(KERN_DEBUG "%s: parptt: why am I being woken up?\n", hfmodem_drvname); + if (!parport_claim(dev->ptt_out.pardev)) + printk(KERN_DEBUG "%s: parptt: I'm broken.\n", hfmodem_drvname); +} + +/* --------------------------------------------------------------------- */ +__initfunc(static int check_lpt(struct hfmodem_state *dev, unsigned int iobase)) +{ + struct parport *pp = parport_enumerate(); + + while (pp && pp->base != iobase) + pp = pp->next; + if (!pp) + return 0; + if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, parptt_preempt, parptt_wakeup, + NULL, PARPORT_DEV_LURK, dev))) + return 0; + return 1; } /* --------------------------------------------------------------------- */ @@ -272,8 +274,7 @@ { enum uart u = c_uart_unknown; - if (dev->ptt_out.seriobase > 0 && dev->ptt_out.seriobase <= 0x1000-SER_EXTENT && - ((u = check_uart(dev->ptt_out.seriobase))) != c_uart_unknown) + if (((u = check_uart(dev->ptt_out.seriobase))) != c_uart_unknown) printk(KERN_INFO "%s: PTT output: uart found at address 0x%x type %s\n", hfmodem_drvname, dev->ptt_out.seriobase, uart_str[u]); else { @@ -282,8 +283,7 @@ hfmodem_drvname, dev->ptt_out.seriobase); dev->ptt_out.seriobase = 0; } - if (dev->ptt_out.pariobase > 0 && dev->ptt_out.pariobase <= 0x1000-LPT_EXTENT && - !check_lpt(dev->ptt_out.pariobase)) + if (check_lpt(dev, dev->ptt_out.pariobase)) printk(KERN_INFO "%s: PTT output: parallel port found at address 0x%x\n", hfmodem_drvname, dev->ptt_out.pariobase); else { @@ -291,6 +291,7 @@ printk(KERN_WARNING "%s: PTT output: no parallel port found at address 0x%x\n", hfmodem_drvname, dev->ptt_out.pariobase); dev->ptt_out.pariobase = 0; + dev->ptt_out.pardev = NULL; } if (dev->ptt_out.midiiobase > 0 && dev->ptt_out.midiiobase <= 0x1000-MIDI_EXTENT && check_midi(dev->ptt_out.midiiobase)) @@ -324,12 +325,11 @@ hfmodem_drvname, dev->ptt_out.seriobase); } if (dev->ptt_out.pariobase > 0) { - if (!check_region(dev->ptt_out.pariobase, LPT_EXTENT)) { - request_region(dev->ptt_out.pariobase, LPT_EXTENT, "hfmodem par ptt"); - dev->ptt_out.flags |= SP_PAR; - } else + if (parport_claim(dev->ptt_out.pardev)) printk(KERN_WARNING "%s: PTT output: parallel port at 0x%x busy\n", hfmodem_drvname, dev->ptt_out.pariobase); + else + dev->ptt_out.flags |= SP_PAR; } if (dev->ptt_out.midiiobase > 0) { if (!check_region(dev->ptt_out.midiiobase, MIDI_EXTENT)) { @@ -361,7 +361,7 @@ if (dev->ptt_out.flags & SP_SER) release_region(dev->ptt_out.seriobase, SER_EXTENT); if (dev->ptt_out.flags & SP_PAR) - release_region(dev->ptt_out.pariobase, LPT_EXTENT); + parport_release(dev->ptt_out.pardev); if (dev->ptt_out.flags & SP_MIDI) release_region(dev->ptt_out.midiiobase, MIDI_EXTENT); dev->ptt_out.flags = 0; @@ -671,6 +671,10 @@ void cleanup_module(void) { + struct hfmodem_state *dev = &hfmodem_state[0]; + + if (dev->ptt_out.pariobase > 0) + parport_unregister_device(dev->ptt_out.pardev); misc_deregister(&hfmodem_device); } @@ -733,4 +737,3 @@ /* --------------------------------------------------------------------- */ #endif /* MODULE */ - diff -u --recursive --new-file v2.1.67/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.67/linux/drivers/char/lp.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/char/lp.c Sat Nov 29 16:19:53 1997 @@ -64,6 +64,11 @@ #undef LP_DEBUG #undef LP_READ_DEBUG +/* Magic numbers */ +#define AUTO -3 +#define OFF -2 +#define UNSPEC -1 + static inline void lp_parport_release (int minor) { parport_release (lp_table[minor].dev); @@ -123,7 +128,7 @@ do { status = r_str(minor); count++; - if (need_resched) + if (resched_needed()) lp_schedule (minor); } while (((use_polling && !LP_READY(minor, status)) || (!use_polling && !(status & LP_PBUSY))) && @@ -163,9 +168,7 @@ static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct parport *pb = (struct parport *) dev_id; - struct pardevice *pd = pb->cad; - struct lp_struct *lp_dev = (struct lp_struct *) pd->private; + struct lp_struct *lp_dev = (struct lp_struct *) dev_id; if (waitqueue_active (&lp_dev->lp_wait_q)) wake_up(&lp_dev->lp_wait_q); @@ -272,11 +275,11 @@ return total_bytes_written; } -static ssize_t lp_write(struct file * file, const char * buf, size_t count, loff_t *ppos) +static ssize_t lp_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; - unsigned int minor = MINOR(inode->i_rdev); - int retv; + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + ssize_t retv; if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) lp_table[minor].runchars = 0; @@ -288,7 +291,7 @@ */ lp_parport_claim (minor); - retv = lp_write_buf(minor, buf, count); + retv = lp_write_buf(minor, buf, count); lp_parport_release (minor); return retv; @@ -315,15 +318,15 @@ } /* Status readback confirming to ieee1284 */ -static ssize_t lp_read(struct file * file, char * buf, size_t count, loff_t *ppos) +static ssize_t lp_read(struct file * file, char * buf, + size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; unsigned char z=0, Byte=0, status; char *temp; - int retval; + ssize_t retval; unsigned int counter=0; unsigned int i; - unsigned int minor=MINOR(inode->i_rdev); + unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev); /* Claim Parport or sleep until it becomes available * (see lp_wakeup() for details) @@ -353,7 +356,7 @@ status=(r_str(minor) & 0x40); udelay(50); counter++; - if (need_resched) + if (resched_needed()) schedule (); } while ( (status == 0x40) && (counter < 20) ); if ( counter == 20 ) { /* Timeout */ @@ -372,7 +375,7 @@ status=(r_str(minor) & 0x40); udelay(20); counter++; - if (need_resched) + if (resched_needed()) schedule (); } while ( (status == 0) && (counter < 20) ); if (counter == 20) { /* Timeout */ @@ -568,7 +571,7 @@ lp_release }; -static int parport[LP_NO] = { -1, }; +static int parport[LP_NO] = { UNSPEC, }; #ifdef MODULE #define lp_init init_module @@ -589,11 +592,11 @@ printk(KERN_INFO "lp: too many ports, %s ignored.\n", str); } else if (!strcmp(str, "auto")) { - parport[0] = -3; + parport[0] = AUTO; } else { if (ints[0] == 0 || ints[1] == 0) { /* disable driver on "lp=" or "lp=0" */ - parport[0] = -2; + parport[0] = OFF; } else { printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]); } @@ -619,7 +622,7 @@ static int inline lp_searchfor(int list[], int a) { int i; - for (i = 0; i < LP_NO && list[i] != -1; i++) { + for (i = 0; i < LP_NO && list[i] != UNSPEC; i++) { if (list[i] == a) return 1; } return 0; @@ -630,15 +633,16 @@ int count = 0; struct parport *pb; - if (parport[0] == -2) return 0; + if (parport[0] == OFF) return 0; pb = parport_enumerate(); while (pb) { /* We only understand PC-style ports. */ if (pb->modes & PARPORT_MODE_PCSPP) { - if (parport[0] == -1 || lp_searchfor(parport, count) || - (parport[0] == -3 && + if (parport[0] == UNSPEC || + lp_searchfor(parport, count) || + (parport[0] == AUTO && pb->probe_info.class == PARPORT_CLASS_PRINTER)) { lp_table[count].dev = parport_register_device(pb, dev_name, @@ -646,6 +650,10 @@ lp_interrupt, PARPORT_DEV_TRAN, (void *) &lp_table[count]); lp_table[count].flags |= LP_EXIST; + init_waitqueue (&lp_table[count].lp_wait_q); + lp_parport_claim (count); + lp_reset (count); + lp_parport_release (count); printk(KERN_INFO "lp%d: using %s (%s).\n", count, pb->name, (pb->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); } diff -u --recursive --new-file v2.1.67/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.1.67/linux/drivers/char/mem.c Sat Oct 25 02:44:15 1997 +++ linux/drivers/char/mem.c Sat Nov 29 16:23:11 1997 @@ -539,7 +539,7 @@ * Some joysticks only appear when the soundcard they are * connected too is confgured. Keep the sound/joystick ordering. */ - joystick_init(); + js_init(); #endif #if CONFIG_QIC02_TAPE qic02_tape_init(); diff -u --recursive --new-file v2.1.67/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.1.67/linux/drivers/char/n_tty.c Sat Oct 25 02:44:15 1997 +++ linux/drivers/char/n_tty.c Sun Nov 30 10:59:02 1997 @@ -695,8 +695,8 @@ int is_ignored(int sig) { - return ((current->blocked & (1<<(sig-1))) || - (current->sig->action[sig-1].sa_handler == SIG_IGN)); + return (sigismember(¤t->blocked, sig) || + current->sig->action[sig-1].sa.sa_handler == SIG_IGN); } static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) diff -u --recursive --new-file v2.1.67/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.1.67/linux/drivers/char/pcwd.c Sat Nov 29 11:25:09 1997 +++ linux/drivers/char/pcwd.c Sat Nov 29 16:36:13 1997 @@ -29,6 +29,7 @@ * 961118 Changed some verbiage on some of the output, tidied up * code bits, and added compatibility to 2.1.x. * 970912 Enabled board on open and disable on close. + * 971107 Took account of recent VFS changes (broke read). */ #include @@ -222,7 +223,7 @@ } static int pcwd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { int i, cdat, rv; static struct watchdog_info ident= @@ -359,8 +360,13 @@ return 0; } -static long pcwd_write(struct inode *inode, struct file *file, const char *buf, unsigned long len) +static ssize_t pcwd_write(struct file *file, const char *buf, size_t len, + loff_t *ppos) { + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + if (len) { pcwd_send_heartbeat(); @@ -381,11 +387,15 @@ return(0); } -static ssize_t pcwd_read(struct file *file, char *buf, size_t count, loff_t *ppos) +static ssize_t pcwd_read(struct file *file, char *buf, size_t count, + loff_t *ppos) { unsigned short c = inb(current_readport); unsigned char cp; + /* Can't seek (pread) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; switch(MINOR(file->f_dentry->d_inode->i_rdev)) { case TEMP_MINOR: @@ -488,11 +498,16 @@ pcwd_read, /* Read */ pcwd_write, /* Write */ NULL, /* Readdir */ - NULL, /* Select */ + NULL, /* Poll */ pcwd_ioctl, /* IOctl */ NULL, /* MMAP */ pcwd_open, /* Open */ - pcwd_close /* Close */ + pcwd_close, /* Release */ + NULL, /* Fsync */ + NULL, /* Fasync */ + NULL, /* CheckMediaChange */ + NULL, /* Revalidate */ + NULL, /* Lock */ }; static struct miscdevice pcwd_miscdev = { diff -u --recursive --new-file v2.1.67/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.1.67/linux/drivers/char/vt.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/char/vt.c Sun Nov 30 10:59:02 1997 @@ -725,7 +725,7 @@ extern int spawnpid, spawnsig; if (!perm) return -EPERM; - if (arg < 1 || arg > NSIG || arg == SIGKILL) + if (arg < 1 || arg > _NSIG || arg == SIGKILL) return -EINVAL; spawnpid = current->pid; spawnsig = arg; diff -u --recursive --new-file v2.1.67/linux/drivers/misc/Makefile linux/drivers/misc/Makefile --- v2.1.67/linux/drivers/misc/Makefile Tue Sep 23 16:48:47 1997 +++ linux/drivers/misc/Makefile Sat Nov 29 16:19:40 1997 @@ -30,6 +30,13 @@ M_OBJS += parport_pc.o endif endif + ifeq ($(CONFIG_PARPORT_AX),y) + LX_OBJS += parport_ax.o + else + ifeq ($(CONFIG_PARPORT_AX),m) + M_OBJS += parport_ax.o + endif + endif LX_OBJS += parport_init.o else ifeq ($(CONFIG_PARPORT),m) @@ -42,6 +49,9 @@ endif ifeq ($(CONFIG_PARPORT_PC),m) MX_OBJS += parport_pc.o + endif + ifeq ($(CONFIG_PARPORT_AX),m) + MX_OBJS += parport_ax.o endif endif diff -u --recursive --new-file v2.1.67/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c --- v2.1.67/linux/drivers/misc/parport_ax.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/misc/parport_ax.c Sat Nov 29 16:19:40 1997 @@ -0,0 +1,554 @@ +/* $Id: parport_ax.c,v 1.2 1997/10/25 17:27:03 philip Exp $ + * Parallel-port routines for Sun Ultra/AX architecture + * + * Author: Eddie C. Dost + * + * based on work by: + * Phil Blundell + * Tim Waugh + * Jose Renau + * David Campbell + * Grant Guenther + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + + +/* + * Define this if you have Devices which don't support short + * host read/write cycles. + */ +#undef HAVE_SLOW_DEVICES + + +#define DATA 0x00 +#define STATUS 0x01 +#define CONTROL 0x02 + +#define CFIFO 0x400 +#define DFIFO 0x400 +#define TFIFO 0x400 +#define CNFA 0x400 +#define CNFB 0x401 +#define ECR 0x402 + +static void +ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) +{ + /* NULL function - Does nothing */ + return; +} + +#if 0 +static unsigned int +ax_read_configb(struct parport *p) +{ + return (unsigned int)inb(p->base + CNFB); +} +#endif + +static void +ax_write_data(struct parport *p, unsigned int d) +{ + outb(d, p->base + DATA); +} + +static unsigned int +ax_read_data(struct parport *p) +{ + return (unsigned int)inb(p->base + DATA); +} + +static void +ax_write_control(struct parport *p, unsigned int d) +{ + outb(d, p->base + CONTROL); +} + +static unsigned int +ax_read_control(struct parport *p) +{ + return (unsigned int)inb(p->base + CONTROL); +} + +static unsigned int +ax_frob_control(struct parport *p, unsigned int mask, unsigned int val) +{ + unsigned int old = (unsigned int)inb(p->base + CONTROL); + outb(((old & ~mask) ^ val), p->base + CONTROL); + return old; +} + +static void +ax_write_status(struct parport *p, unsigned int d) +{ + outb(d, p->base + STATUS); +} + +static unsigned int +ax_read_status(struct parport *p) +{ + return (unsigned int)inb(p->base + STATUS); +} + +static void +ax_write_econtrol(struct parport *p, unsigned int d) +{ + outb(d, p->base + ECR); +} + +static unsigned int +ax_read_econtrol(struct parport *p) +{ + return (unsigned int)inb(p->base + ECR); +} + +static unsigned int +ax_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val) +{ + unsigned int old = (unsigned int)inb(p->base + ECR); + outb(((old & ~mask) ^ val), p->base + ECR); + return old; +} + +static void +ax_change_mode(struct parport *p, int m) +{ + ax_frob_econtrol(p, 0xe0, m << 5); +} + +static void +ax_write_fifo(struct parport *p, unsigned int v) +{ + outb(v, p->base + DFIFO); +} + +static unsigned int +ax_read_fifo(struct parport *p) +{ + return inb(p->base + DFIFO); +} + +static void +ax_disable_irq(struct parport *p) +{ + struct linux_ebus_dma *dma = p->private_data; + unsigned int dcsr; + + dcsr = readl((unsigned long)&dma->dcsr); + dcsr &= ~(EBUS_DCSR_INT_EN); + writel(dcsr, (unsigned long)&dma->dcsr); +} + +static void +ax_enable_irq(struct parport *p) +{ + struct linux_ebus_dma *dma = p->private_data; + unsigned int dcsr; + + dcsr = readl((unsigned long)&dma->dcsr); + dcsr |= EBUS_DCSR_INT_EN; + writel(dcsr, (unsigned long)&dma->dcsr); +} + +static void +ax_release_resources(struct parport *p) +{ + if (p->irq != PARPORT_IRQ_NONE) { + ax_disable_irq(p); + free_irq(p->irq, p); + } + release_region(p->base, p->size); + if (p->modes & PARPORT_MODE_PCECR) + release_region(p->base+0x400, 3); + release_region((unsigned long)p->private_data, + sizeof(struct linux_ebus_dma)); +} + +static int +ax_claim_resources(struct parport *p) +{ + /* FIXME check that resources are free */ + if (p->irq != PARPORT_IRQ_NONE) { + request_irq(p->irq, ax_null_intr_func, 0, p->name, p); + ax_enable_irq(p); + } + request_region(p->base, p->size, p->name); + if (p->modes & PARPORT_MODE_PCECR) + request_region(p->base+0x400, 3, p->name); + request_region((unsigned long)p->private_data, + sizeof(struct linux_ebus_dma), p->name); + return 0; +} + +static void +ax_save_state(struct parport *p, struct parport_state *s) +{ + s->u.pc.ctr = ax_read_control(p); + s->u.pc.ecr = ax_read_econtrol(p); +} + +static void +ax_restore_state(struct parport *p, struct parport_state *s) +{ + ax_write_control(p, s->u.pc.ctr); + ax_write_econtrol(p, s->u.pc.ecr); +} + +static unsigned int +ax_epp_read_block(struct parport *p, void *buf, unsigned int length) +{ + return 0; /* FIXME */ +} + +static unsigned int +ax_epp_write_block(struct parport *p, void *buf, unsigned int length) +{ + return 0; /* FIXME */ +} + +static unsigned int +ax_ecp_read_block(struct parport *p, void *buf, unsigned int length, + void (*fn)(struct parport *, void *, unsigned int), + void *handle) +{ + return 0; /* FIXME */ +} + +static unsigned int +ax_ecp_write_block(struct parport *p, void *buf, unsigned int length, + void (*fn)(struct parport *, void *, unsigned int), + void *handle) +{ + return 0; /* FIXME */ +} + +static int +ax_examine_irq(struct parport *p) +{ + return 0; /* FIXME */ +} + +static void +ax_inc_use_count(void) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void +ax_dec_use_count(void) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +static struct parport_operations ax_ops = +{ + ax_write_data, + ax_read_data, + + ax_write_control, + ax_read_control, + ax_frob_control, + + ax_write_econtrol, + ax_read_econtrol, + ax_frob_econtrol, + + ax_write_status, + ax_read_status, + + ax_write_fifo, + ax_read_fifo, + + ax_change_mode, + + ax_release_resources, + ax_claim_resources, + + ax_epp_write_block, + ax_epp_read_block, + + ax_ecp_write_block, + ax_ecp_read_block, + + ax_save_state, + ax_restore_state, + + ax_enable_irq, + ax_disable_irq, + ax_examine_irq, + + ax_inc_use_count, + ax_dec_use_count +}; + + +/****************************************************** + * MODE detection section: + */ + +/* Check for ECP + * + * Old style XT ports alias io ports every 0x400, hence accessing ECR + * on these cards actually accesses the CTR. + * + * Modern cards don't do this but reading from ECR will return 0xff + * regardless of what is written here if the card does NOT support + * ECP. + * + * We will write 0x2c to ECR and 0xcc to CTR since both of these + * values are "safe" on the CTR since bits 6-7 of CTR are unused. + */ +static int parport_ECR_present(struct parport *pb) +{ + unsigned int r, octr = pb->ops->read_control(pb), + oecr = pb->ops->read_econtrol(pb); + + r = pb->ops->read_control(pb); + if ((pb->ops->read_econtrol(pb) & 0x3) == (r & 0x3)) { + pb->ops->write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */ + + r = pb->ops->read_control(pb); + if ((pb->ops->read_econtrol(pb) & 0x2) == (r & 0x2)) { + pb->ops->write_control(pb, octr); + return 0; /* Sure that no ECR register exists */ + } + } + + if ((pb->ops->read_econtrol(pb) & 0x3 ) != 0x1) + return 0; + + pb->ops->write_econtrol(pb, 0x34); + if (pb->ops->read_econtrol(pb) != 0x35) + return 0; + + pb->ops->write_econtrol(pb, oecr); + pb->ops->write_control(pb, octr); + + return PARPORT_MODE_PCECR; +} + +static int parport_ECP_supported(struct parport *pb) +{ + int i, oecr = pb->ops->read_econtrol(pb); + + /* If there is no ECR, we have no hope of supporting ECP. */ + if (!(pb->modes & PARPORT_MODE_PCECR)) + return 0; + + /* + * Using LGS chipset it uses ECR register, but + * it doesn't support ECP or FIFO MODE + */ + + pb->ops->write_econtrol(pb, 0xc0); /* TEST FIFO */ + for (i=0; i < 1024 && (pb->ops->read_econtrol(pb) & 0x01); i++) + pb->ops->write_fifo(pb, 0xaa); + + pb->ops->write_econtrol(pb, oecr); + return (i == 1024) ? 0 : PARPORT_MODE_PCECP; +} + +/* Detect PS/2 support. + * + * Bit 5 (0x20) sets the PS/2 data direction; setting this high + * allows us to read data from the data lines. In theory we would get back + * 0xff but any peripheral attached to the port may drag some or all of the + * lines down to zero. So if we get back anything that isn't the contents + * of the data register we deem PS/2 support to be present. + * + * Some SPP ports have "half PS/2" ability - you can't turn off the line + * drivers, but an external peripheral with sufficiently beefy drivers of + * its own can overpower them and assert its own levels onto the bus, from + * where they can then be read back as normal. Ports with this property + * and the right type of device attached are likely to fail the SPP test, + * (as they will appear to have stuck bits) and so the fact that they might + * be misdetected here is rather academic. + */ + +static int parport_PS2_supported(struct parport *pb) +{ + int ok = 0, octr = pb->ops->read_control(pb); + + pb->ops->write_control(pb, octr | 0x20); /* try to tri-state buffer */ + + pb->ops->write_data(pb, 0x55); + if (pb->ops->read_data(pb) != 0x55) ok++; + + pb->ops->write_data(pb, 0xaa); + if (pb->ops->read_data(pb) != 0xaa) ok++; + + pb->ops->write_control(pb, octr); /* cancel input mode */ + + return ok ? PARPORT_MODE_PCPS2 : 0; +} + +static int parport_ECPPS2_supported(struct parport *pb) +{ + int mode, oecr = pb->ops->read_econtrol(pb); + + if (!(pb->modes & PARPORT_MODE_PCECR)) + return 0; + + pb->ops->write_econtrol(pb, 0x20); + + mode = parport_PS2_supported(pb); + + pb->ops->write_econtrol(pb, oecr); + return mode ? PARPORT_MODE_PCECPPS2 : 0; +} + +#define printmode(x) \ +{ \ + if (p->modes & PARPORT_MODE_PC##x) { \ + printk("%s%s", f ? "," : "", #x); \ + f++; \ + } \ +} + +int +init_one_port(struct linux_ebus_device *dev) +{ + struct parport tmpport, *p; + unsigned long base; + unsigned long config; + unsigned char tmp; + int irq, dma; + + /* Pointer to NS87303 Configuration Registers */ + config = dev->base_address[1]; + + /* Setup temporary access to Device operations */ + tmpport.base = dev->base_address[0]; + tmpport.ops = &ax_ops; + + /* Enable ECP mode, set bit 2 of the CTR first */ + tmpport.ops->write_control(&tmpport, 0x04); + tmp = ns87303_readb(config, PCR); + tmp |= (PCR_EPP_IEEE | PCR_ECP_ENABLE | PCR_ECP_CLK_ENA); + ns87303_writeb(config, PCR, tmp); + + /* LPT CTR bit 5 controls direction of parallel port */ + tmp = ns87303_readb(config, PTR); + tmp |= PTR_LPT_REG_DIR; + ns87303_writeb(config, PTR, tmp); + + /* Configure IRQ to Push Pull, Level Low */ + tmp = ns87303_readb(config, PCR); + tmp &= ~(PCR_IRQ_ODRAIN); + tmp |= PCR_IRQ_POLAR; + ns87303_writeb(config, PCR, tmp); + +#ifndef HAVE_SLOW_DEVICES + /* Enable Zero Wait State for ECP */ + tmp = ns87303_readb(config, FCR); + tmp |= FCR_ZWS_ENA; + ns87303_writeb(config, FCR, tmp); +#endif + + /* + * Now continue initializing the port + */ + base = dev->base_address[0]; + irq = dev->irqs[0]; + dma = PARPORT_DMA_AUTO; + + if (!(p = parport_register_port(base, irq, dma, &ax_ops))) + return 0; + + /* Safe away pointer to our EBus DMA */ + p->private_data = (void *)dev->base_address[2]; + + p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p); + if (!check_region(p->base + 0x400, 3)) { + p->modes |= parport_ECR_present(p); + p->modes |= parport_ECP_supported(p); + p->modes |= parport_ECPPS2_supported(p); + } + p->size = 3; + + if (p->dma == PARPORT_DMA_AUTO) + p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE; + + printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); + if (p->irq != PARPORT_IRQ_NONE) + printk(", irq %x", (unsigned int)p->irq); + if (p->dma != PARPORT_DMA_NONE) + printk(", dma %d", p->dma); + printk(" ["); + { + int f = 0; + printmode(SPP); + printmode(PS2); + printmode(ECP); + printmode(ECPPS2); + } + printk("]\n"); + parport_proc_register(p); + p->flags |= PARPORT_FLAG_COMA; + + ax_write_control(p, 0x0c); + ax_write_data(p, 0); + + if (parport_probe_hook) + (*parport_probe_hook)(p); + + return 1; +} + +int +parport_ax_init(void) +{ + struct linux_ebus *ebus; + struct linux_ebus_device *edev; + int count = 0; + + for_all_ebusdev(edev, ebus) + if (!strcmp(edev->prom_name, "ecpp")) + count += init_one_port(edev); + return count; +} + +#ifdef MODULE + +int +init_module(void) +{ + return (parport_ax_init() ? 0 : 1); +} + +void +cleanup_module(void) +{ + struct parport *p = parport_enumerate(), *tmp; + while (p) { + tmp = p->next; + if (p->modes & PARPORT_MODE_PCSPP) { + if (!(p->flags & PARPORT_FLAG_COMA)) + parport_quiesce(p); + parport_proc_unregister(p); + parport_unregister_port(p); + } + p = tmp; + } +} +#endif diff -u --recursive --new-file v2.1.67/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c --- v2.1.67/linux/drivers/misc/parport_ieee1284.c Wed Sep 3 20:52:42 1997 +++ linux/drivers/misc/parport_ieee1284.c Sat Nov 29 16:19:40 1997 @@ -1,4 +1,5 @@ -/* IEEE-1284 implementation for parport. +/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $ + * IEEE-1284 implementation for parport. * * Authors: Phil Blundell * Carsten Gross @@ -6,83 +7,63 @@ */ #include - #include #include -#include -#include -#include #include -#include - -/* The following read functions are an implementation of a status readback - * and device id request confirming to IEEE1284-1994. - * - * These probably ought to go in some seperate file, so people like the SPARC - * don't have to pull them in. - */ /* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to * 25 for this. After this time we can create a timeout because the - * peripheral doesn't conform to IEEE1284. We want to save CPU time: we are - * waiting a maximum time of 500 us busy (this is for speed). If there is + * peripheral doesn't conform to IEEE1284. We want to save CPU time: we are + * waiting a maximum time of 500 us busy (this is for speed). If there is * not the right answer in this time, we call schedule and other processes - * are able "to eat" the time up to 30ms. So the maximum load avarage can't - * get above 5% for a read even if the peripheral is really slow. (but your - * read gets very slow then - only about 10 characters per second. This - * should be tuneable). Thanks to Andreas who pointed me to this and ordered - * the documentation. + * are able to eat the time up to 40ms. */ int parport_wait_peripheral(struct parport *port, unsigned char mask, unsigned char result) { - int counter=0; + int counter; unsigned char status; - do { + for (counter = 0; counter < 20; counter++) { status = parport_read_status(port); + if ((status & mask) == result) + return 0; udelay(25); - counter++; - if (need_resched) + if (resched_needed()) schedule(); - } while ( ((status & mask) != result) && (counter < 20) ); - if ( (counter == 20) && ((status & mask) != result) ) { - current->state=TASK_INTERRUPTIBLE; - current->timeout=jiffies+4; - schedule(); /* wait for 4 scheduler runs (40ms) */ - status = parport_read_status(port); - if ((status & mask) != result) return 1; /* timeout */ } - return 0; /* okay right response from device */ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies+4; + schedule(); /* wait for 40ms */ + status = parport_read_status(port); + return ((status & mask) == result)?0:1; } -/* Test if nibble mode for status readback is okay. Returns the value false - * if the printer doesn't support readback at all. If it supports readbacks - * and printer data is available the function returns 1, otherwise 2. The - * only valid values for "mode" are 0 and 4. 0 requests normal nibble mode, - * 4 is for "request device id using nibble mode". The request for the - * device id is best done in an ioctl (or at bootup time). There is no - * check for an invalid value, the only function using this call at the - * moment is lp_read and the ioctl LPGETDEVICEID both fixed calls from - * trusted kernel. +/* Test if the peripheral is IEEE 1284 compliant. + * return values are: + * 0 - handshake failed; peripheral is not compliant (or none present) + * 1 - handshake OK; IEEE1284 peripheral present but no data available + * 2 - handshake OK; IEEE1284 peripheral and data available */ int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) { parport_write_data(port, mode); - udelay(5); - parport_write_control(port, parport_read_control(port) & ~8); /* SelectIN low */ - parport_write_control(port, parport_read_control(port) | 2); /* AutoFeed high */ - if (parport_wait_peripheral(port, 0x78, 0x38)) { /* timeout? */ - parport_write_control(port, (parport_read_control(port) & ~2) | 8); - return 0; /* first stage of negotiation failed, - * no IEEE1284 compliant device on this port - */ + udelay(500); + /* nSelectIn high, nAutoFd low */ + parport_write_control(port, (parport_read_control(port) & ~8) | 2); + if (parport_wait_peripheral(port, 0x78, 0x38)) { + parport_write_control(port, + (parport_read_control(port) & ~2) | 8); + return 0; } - parport_write_control(port, parport_read_control(port) | 1); /* Strobe high */ + /* nStrobe low */ + parport_write_control(port, parport_read_control(port) | 1); udelay(5); /* Strobe wait */ - parport_write_control(port, parport_read_control(port) & ~1); /* Strobe low */ + /* nStrobe high */ + parport_write_control(port, parport_read_control(port) & ~1); udelay(5); - parport_write_control(port, parport_read_control(port) & ~2); /* AutoFeed low */ + /* nAutoFd low */ + parport_write_control(port, parport_read_control(port) & ~2); return (parport_wait_peripheral(port, 0x20, 0))?2:1; } diff -u --recursive --new-file v2.1.67/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c --- v2.1.67/linux/drivers/misc/parport_init.c Wed Sep 3 20:52:42 1997 +++ linux/drivers/misc/parport_init.c Sat Nov 29 16:19:41 1997 @@ -17,13 +17,15 @@ #include #include #include +#include #ifndef MODULE -static int io[PARPORT_MAX+1] __initdata = { 0, }; -static int irq[PARPORT_MAX] __initdata = { PARPORT_IRQ_NONE, }; -static int dma[PARPORT_MAX] __initdata = { PARPORT_DMA_NONE, }; +static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; +static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_NONE }; +static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE }; extern int parport_pc_init(int *io, int *irq, int *dma); +extern int parport_ax_init(void); static int parport_setup_ptr __initdata = 0; @@ -68,11 +70,19 @@ { struct parport *pb; - if (io[0] == PARPORT_DISABLE) return 1; + if (io[0] == PARPORT_DISABLE) + return 1; + +#ifdef CONFIG_PNP_PARPORT + parport_probe_hook = &parport_probe_one; +#endif parport_proc_init(); #ifdef CONFIG_PARPORT_PC parport_pc_init(io, irq, dma); #endif +#ifdef CONFIG_PARPORT_AX + parport_ax_init(); +#endif return 0; } #endif @@ -91,6 +101,7 @@ EXPORT_SYMBOL(parport_wait_peripheral); EXPORT_SYMBOL(parport_proc_register); EXPORT_SYMBOL(parport_proc_unregister); +EXPORT_SYMBOL(parport_probe_hook); void inc_parport_count(void) { diff -u --recursive --new-file v2.1.67/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.1.67/linux/drivers/misc/parport_pc.c Mon Nov 17 18:47:21 1997 +++ linux/drivers/misc/parport_pc.c Sat Nov 29 16:19:41 1997 @@ -837,7 +837,7 @@ } p->size = (p->modes & (PARPORT_MODE_PCEPP | PARPORT_MODE_PCECPEPP))?8:3; - printk(KERN_INFO "%s: PC-style at 0x%x", p->name, p->base); + printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); if (p->irq == PARPORT_IRQ_AUTO) { p->irq = PARPORT_IRQ_NONE; parport_irq_probe(p); @@ -868,6 +868,10 @@ /* Done probing. Now put the port into a sensible start-up state. */ pc_write_control(p, 0xc); pc_write_data(p, 0); + + if (parport_probe_hook) + (*parport_probe_hook)(p); + return 1; } diff -u --recursive --new-file v2.1.67/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.1.67/linux/drivers/misc/parport_procfs.c Wed Sep 3 20:52:42 1997 +++ linux/drivers/misc/parport_procfs.c Sat Nov 29 16:19:41 1997 @@ -125,7 +125,7 @@ struct parport *pp = (struct parport *)data; int len=0; - len += sprintf(page+len, "base:\t0x%x\n",pp->base); + len += sprintf(page+len, "base:\t0x%lx\n",pp->base); if (pp->irq == PARPORT_IRQ_NONE) len += sprintf(page+len, "irq:\tnone\n"); else diff -u --recursive --new-file v2.1.67/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c --- v2.1.67/linux/drivers/misc/parport_share.c Tue Sep 23 16:48:47 1997 +++ linux/drivers/misc/parport_share.c Sat Nov 29 16:19:41 1997 @@ -1,4 +1,5 @@ -/* Parallel-port resource manager code. +/* $Id: parport_share.c,v 1.8 1997/11/08 18:55:29 philip Exp $ + * Parallel-port resource manager code. * * Authors: David Campbell * Tim Waugh @@ -29,6 +30,8 @@ static struct parport *portlist = NULL, *portlist_tail = NULL; static int portcount = 0; +void (*parport_probe_hook)(struct parport *port) = NULL; + /* Return a list of all the ports we know about. */ struct parport *parport_enumerate(void) { @@ -275,11 +278,11 @@ dev->port->cad = dev; /* Swap the IRQ handlers. */ - if (dev->port->irq >= 0) { + if (dev->port->irq != PARPORT_IRQ_NONE) { free_irq(dev->port->irq, dev->port); request_irq(dev->port->irq, dev->irq_func ? dev->irq_func : parport_null_intr_func, SA_INTERRUPT, dev->name, - dev->port); + dev->private); } /* Restore control registers */ @@ -303,10 +306,10 @@ dev->port->ops->save_state(dev->port, dev->state); /* Point IRQs somewhere harmless. */ - if (dev->port->irq >= 0) { + if (dev->port->irq != PARPORT_IRQ_NONE) { free_irq(dev->port->irq, dev->port); request_irq(dev->port->irq, parport_null_intr_func, - SA_INTERRUPT, dev->port->name, dev->port); + SA_INTERRUPT, dev->port->name, NULL); } /* Walk the list, offering a wakeup callback to everybody other diff -u --recursive --new-file v2.1.67/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.67/linux/drivers/net/3c59x.c Tue May 13 22:41:08 1997 +++ linux/drivers/net/3c59x.c Sun Nov 30 12:21:45 1997 @@ -38,6 +38,8 @@ #include #include +#include + #ifdef CONFIG_PCI #include #include @@ -498,7 +500,7 @@ outw(EEPROM_Read + PhysAddr01 + i, ioaddr + Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ for (timer = 162*4 + 400; timer >= 0; timer--) { - SLOW_DOWN_IO; + udelay(1); if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) break; } diff -u --recursive --new-file v2.1.67/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.67/linux/drivers/net/Config.in Sat Nov 29 11:25:09 1997 +++ linux/drivers/net/Config.in Sun Nov 30 10:30:19 1997 @@ -157,9 +157,15 @@ tristate 'Gracilis PackeTwin driver for AX.25' CONFIG_PT tristate 'Ottawa PI and PI2 driver for AX.25' CONFIG_PI tristate 'Z8530 SCC driver for AX.25' CONFIG_SCC + if [ "$CONFIG_SCC" != "n" ]; then + bool ' additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY + bool ' support for TRX that feedback the tx signal to rx' CONFIG_SCC_TRXECHO + fi fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'BAYCOM ser12 and par96 driver for AX.25' CONFIG_BAYCOM + tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX + tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX + tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR tristate 'Soundcard modem driver for AX.25' CONFIG_SOUNDMODEM if [ "$CONFIG_SOUNDMODEM" != "n" ]; then bool 'Soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC diff -u --recursive --new-file v2.1.67/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.67/linux/drivers/net/Makefile Tue Sep 23 16:48:48 1997 +++ linux/drivers/net/Makefile Sun Nov 30 10:30:19 1997 @@ -73,13 +73,6 @@ L_OBJS += sk_g16.o endif -ifeq ($(CONFIG_NET_IPIP),y) -L_OBJS += tunnel.o -else - ifeq ($(CONFIG_NET_IPIP),m) - M_OBJS += tunnel.o - endif -endif ifeq ($(CONFIG_HP100),y) L_OBJS += hp100.o @@ -735,13 +728,33 @@ endif endif -ifeq ($(CONFIG_BAYCOM),y) -L_OBJS += baycom.o +ifeq ($(CONFIG_BAYCOM_SER_FDX),y) +L_OBJS += baycom_ser_fdx.o +CONFIG_HDLCDRV_BUILTIN = y +else + ifeq ($(CONFIG_BAYCOM_SER_FDX),m) + CONFIG_HDLCDRV_MODULE = y + M_OBJS += baycom_ser_fdx.o + endif +endif + +ifeq ($(CONFIG_BAYCOM_SER_HDX),y) +L_OBJS += baycom_ser_hdx.o +CONFIG_HDLCDRV_BUILTIN = y +else + ifeq ($(CONFIG_BAYCOM_SER_HDX),m) + CONFIG_HDLCDRV_MODULE = y + M_OBJS += baycom_ser_hdx.o + endif +endif + +ifeq ($(CONFIG_BAYCOM_PAR),y) +L_OBJS += baycom_par.o CONFIG_HDLCDRV_BUILTIN = y else - ifeq ($(CONFIG_BAYCOM),m) + ifeq ($(CONFIG_BAYCOM_PAR),m) CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom.o + M_OBJS += baycom_par.o endif endif diff -u --recursive --new-file v2.1.67/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v2.1.67/linux/drivers/net/at1700.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/at1700.c Sun Nov 30 12:21:45 1997 @@ -102,7 +102,7 @@ #define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */ /* Delay between EEPROM clock transitions. */ -#define eeprom_delay() do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) +#define eeprom_delay() do { int _i = 40; while (--_i > 0) { inb(0x80); }} while (0) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5 << 6) diff -u --recursive --new-file v2.1.67/linux/drivers/net/baycom.c linux/drivers/net/baycom.c --- v2.1.67/linux/drivers/net/baycom.c Mon Aug 11 14:47:04 1997 +++ linux/drivers/net/baycom.c Wed Dec 31 16:00:00 1969 @@ -1,1280 +0,0 @@ -/*****************************************************************************/ - -/* - * baycom.c -- baycom ser12 and par96 radio modem driver. - * - * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - * - * Supported modems - * - * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only - * of a modulator/demodulator chip, usually a TI TCM3105. The computer - * is responsible for regenerating the receiver bit clock, as well as - * for handling the HDLC protocol. The modem connects to a serial port, - * hence the name. Since the serial port is not used as an async serial - * port, the kernel driver for serial ports cannot be used, and this - * driver only supports standard serial hardware (8250, 16450, 16550) - * - * par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard. - * The modem does all the filtering and regenerates the receiver clock. - * Data is transferred from and to the PC via a shift register. - * The shift register is filled with 16 bits and an interrupt is - * signalled. The PC then empties the shift register in a burst. This - * modem connects to the parallel port, hence the name. The modem - * leaves the implementation of the HDLC protocol and the scrambler - * polynomial to the PC. This modem is no longer available (at least - * from Baycom) and has been replaced by the PICPAR modem (see below). - * You may however still build one from the schematics published in - * cq-DL :-). - * - * 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 and can therefore be fed from the parallel port and - * does not require an additional power supply. It features - * built in DCD circuitry. The driver should therefore be configured - * for hardware DCD. - * - * - * Command line options (insmod command line) - * - * mode driver mode string. Valid choices are ser12 and par96. An - * optional * enables software DCD. - * 2=par96/par97, any other value invalid - * iobase base address of the port; common values are for ser12 0x3f8, - * 0x2f8, 0x3e8, 0x2e8 and for par96/par97 0x378, 0x278, 0x3bc - * irq interrupt line of the port; common values are for ser12 3,4 - * and for par96/par97 7 - * - * - * History: - * 0.1 26.06.96 Adapted from baycom.c and made network driver interface - * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) - * 0.3 26.04.97 init code/data tagged - * 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints) - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* --------------------------------------------------------------------- */ - -/* - * currently this module is supposed to support both module styles, i.e. - * the old one present up to about 2.1.9, and the new one functioning - * starting with 2.1.21. The reason is I have a kit allowing to compile - * this module also under 2.0.x which was requested by several people. - * This will go in 2.2 - */ -#include - -#if LINUX_VERSION_CODE >= 0x20100 -#include -#else -#include -#include - -#undef put_user -#undef get_user - -#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) -#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) - -extern inline int copy_from_user(void *to, const void *from, unsigned long n) -{ - int i = verify_area(VERIFY_READ, from, n); - if (i) - return i; - memcpy_fromfs(to, from, n); - return 0; -} - -extern inline int copy_to_user(void *to, const void *from, unsigned long n) -{ - int i = verify_area(VERIFY_WRITE, to, n); - if (i) - return i; - memcpy_tofs(to, from, n); - return 0; -} -#endif - -#if LINUX_VERSION_CODE >= 0x20123 -#include -#else -#define __init -#define __initdata -#define __initfunc(x) x -#endif - -/* --------------------------------------------------------------------- */ - -#define BAYCOM_DEBUG - -/* - * modem options; bit mask - */ -#define BAYCOM_OPTIONS_SOFTDCD 1 -#define BAYCOM_ALT_SER12 - -/* --------------------------------------------------------------------- */ - -static const char bc_drvname[] = "baycom"; -static const char bc_drvinfo[] = KERN_INFO "baycom: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n" -KERN_INFO "baycom: version 0.4 compiled " __TIME__ " " __DATE__ "\n"; - -/* --------------------------------------------------------------------- */ - -#define NR_PORTS 4 - -static struct device baycom_device[NR_PORTS]; - -static struct { - char *mode; - int iobase, irq; -} baycom_ports[NR_PORTS] = { { NULL, 0, 0 }, }; - -/* --------------------------------------------------------------------- */ - -#define RBR(iobase) (iobase+0) -#define THR(iobase) (iobase+0) -#define IER(iobase) (iobase+1) -#define IIR(iobase) (iobase+2) -#define FCR(iobase) (iobase+2) -#define LCR(iobase) (iobase+3) -#define MCR(iobase) (iobase+4) -#define LSR(iobase) (iobase+5) -#define MSR(iobase) (iobase+6) -#define SCR(iobase) (iobase+7) -#define DLL(iobase) (iobase+0) -#define DLM(iobase) (iobase+1) - -#define SER12_EXTENT 8 - -#define LPT_DATA(iobase) (iobase+0) -#define LPT_STATUS(iobase) (iobase+1) -#define LPT_CONTROL(iobase) (iobase+2) -#define LPT_IRQ_ENABLE 0x10 -#define PAR96_BURSTBITS 16 -#define PAR96_BURST 4 -#define PAR96_PTT 2 -#define PAR96_TXBIT 1 -#define PAR96_ACK 0x40 -#define PAR96_RXBIT 0x20 -#define PAR96_DCD 0x10 -#define PAR97_POWER 0xf8 - -#define PAR96_EXTENT 3 - -/* ---------------------------------------------------------------------- */ -/* - * Information that need to be kept for each board. - */ - -struct baycom_state { - struct hdlcdrv_state hdrv; - - unsigned int options; - - struct modem_state { - short arb_divider; - unsigned char flags; - unsigned int shreg; - struct modem_state_ser12 { - unsigned char tx_bit; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned char last_sample; - unsigned char last_rxbit; - unsigned int dcd_shreg; - unsigned int dcd_time; - unsigned int bit_pll; -#ifdef BAYCOM_ALT_SER12 - unsigned long last_jiffies; - unsigned int pll_time; - unsigned int txshreg; -#else /* BAYCOM_ALT_SER12 */ - unsigned char interm_sample; -#endif /* BAYCOM_ALT_SER12 */ - } ser12; - struct modem_state_par96 { - int dcd_count; - unsigned int dcd_shreg; - unsigned long descram; - unsigned long scram; - } par96; - } modem; - -#ifdef BAYCOM_DEBUG - struct debug_vals { - unsigned long last_jiffies; - unsigned cur_intcnt; - unsigned last_intcnt; - int cur_pllcorr; - int last_pllcorr; - } debug_vals; -#endif /* BAYCOM_DEBUG */ -}; - -/* --------------------------------------------------------------------- */ - -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#define max(a, b) (((a) > (b)) ? (a) : (b)) - -/* --------------------------------------------------------------------- */ - -static void inline baycom_int_freq(struct baycom_state *bc) -{ -#ifdef BAYCOM_DEBUG - unsigned long cur_jiffies = jiffies; - /* - * measure the interrupt frequency - */ - bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { - bc->debug_vals.last_jiffies = cur_jiffies; - bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; - bc->debug_vals.cur_intcnt = 0; - bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; - bc->debug_vals.cur_pllcorr = 0; - } -#endif /* BAYCOM_DEBUG */ -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== SER12 specific routines ========================= - */ - -#ifdef BAYCOM_ALT_SER12 - -#define SER12_BAUD 1200 - -/* --------------------------------------------------------------------- */ - -extern inline unsigned int hweight16(unsigned short w) - __attribute__ ((unused)); -extern inline unsigned int hweight8(unsigned char w) - __attribute__ ((unused)); - -extern inline unsigned int hweight16(unsigned short w) -{ - unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555); - res = (res & 0x3333) + ((res >> 2) & 0x3333); - res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); - return (res & 0x00FF) + ((res >> 8) & 0x00FF); -} - -extern inline unsigned int hweight8(unsigned char w) -{ - unsigned short res = (w & 0x55) + ((w >> 1) & 0x55); - res = (res & 0x33) + ((res >> 2) & 0x33); - return (res & 0x0F) + ((res >> 4) & 0x0F); -} - -/* --------------------------------------------------------------------- */ - -static __inline__ void ser12_rxsample(struct device *dev, struct baycom_state *bc, unsigned char news) -{ - bc->modem.ser12.dcd_shreg <<= 1; - bc->modem.ser12.bit_pll += 0x2000; - if (bc->modem.ser12.last_sample != news) { - bc->modem.ser12.last_sample = news; - bc->modem.ser12.dcd_shreg |= 1; - if (bc->modem.ser12.bit_pll < 0x9000) - bc->modem.ser12.bit_pll += 0x1000; - else - bc->modem.ser12.bit_pll -= 0x1000; - bc->modem.ser12.dcd_sum0 += 4 * hweight8(bc->modem.ser12.dcd_shreg & 0x38) - - hweight16(bc->modem.ser12.dcd_shreg & 0x7c0); - } - hdlcdrv_channelbit(&bc->hdrv, !!bc->modem.ser12.last_sample); - if ((--bc->modem.ser12.dcd_time) <= 0) { - hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + - bc->modem.ser12.dcd_sum1 + - bc->modem.ser12.dcd_sum2) < 0); - bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; - bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; - bc->modem.ser12.dcd_sum0 = 2; /* slight bias */ - bc->modem.ser12.dcd_time = 120; - } - if (bc->modem.ser12.bit_pll >= 0x10000) { - bc->modem.ser12.bit_pll &= 0xffff; - bc->modem.shreg >>= 1; - if (bc->modem.ser12.last_rxbit == bc->modem.ser12.last_sample) - bc->modem.shreg |= 0x10000; - bc->modem.ser12.last_rxbit = bc->modem.ser12.last_sample; - if (bc->modem.shreg & 1) { - hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1); - bc->modem.shreg = 0x10000; - } - } -} - -/* --------------------------------------------------------------------- */ - -static __inline__ void ser12_rx(struct device *dev, struct baycom_state *bc, unsigned char curs) -{ - unsigned long curjiff; - struct timeval tv; - unsigned int timediff; - - /* - * get current time - */ - curjiff = jiffies; - do_gettimeofday(&tv); - if ((signed)(curjiff - bc->modem.ser12.last_jiffies) >= HZ/4) { - /* long inactivity; clear HDLC and DCD */ - bc->modem.ser12.dcd_sum1 = 0; - bc->modem.ser12.dcd_sum2 = 0; - bc->modem.ser12.dcd_sum0 = 2; - bc->modem.ser12.dcd_time = 120; - hdlcdrv_setdcd(&bc->hdrv, 0); - hdlcdrv_putbits(&bc->hdrv, 0xffff); - bc->modem.ser12.last_jiffies = curjiff; - bc->modem.ser12.pll_time = tv.tv_usec; - } - bc->modem.ser12.last_jiffies = curjiff; - timediff = tv.tv_usec + 1000000 - bc->modem.ser12.pll_time; - timediff %= 1000000; - timediff /= 125000/SER12_BAUD; - bc->modem.ser12.pll_time = (bc->modem.ser12.pll_time + timediff * (125000/SER12_BAUD)) % 1000000; - for (; timediff > 1; timediff--) - ser12_rxsample(dev, bc, bc->modem.ser12.last_sample); - if (timediff >= 1) - ser12_rxsample(dev, bc, curs); -} - -/* --------------------------------------------------------------------- */ - -static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; - unsigned char iir, msr = 0; - unsigned int txcount = 0; - unsigned int rxcount = 0; - - if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) - return; - - for (;;) { - iir = inb(IIR(dev->base_addr)); - if (iir & 1) - break; - switch (iir & 6) { - case 6: - inb(LSR(dev->base_addr)); - continue; - - case 4: - inb(RBR(dev->base_addr)); - continue; - - case 2: - /* - * make sure the next interrupt is generated; - * 0 must be used to power the modem; the modem draws its - * power from the TxD line - */ - outb(0x00, THR(dev->base_addr)); - bc->modem.arb_divider--; - baycom_int_freq(bc); - if (hdlcdrv_ptt(&bc->hdrv)) { - /* - * first output the last bit (!) then call HDLC transmitter, - * since this may take quite long - */ - outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); - txcount++; - } else - outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ - continue; - - default: - msr = inb(MSR(dev->base_addr)); - if (msr & 1) /* delta CTS interrupt */ - rxcount++; - continue; - } - } - if (rxcount) - ser12_rx(dev, bc, msr & 0x10); - if (txcount) { -#ifdef BAYCOM_DEBUG - if (bc->debug_vals.cur_pllcorr < txcount) - bc->debug_vals.cur_pllcorr = txcount; -#endif /* BAYCOM_DEBUG */ - if (bc->modem.ser12.txshreg <= 1) - bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); - bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1)); - bc->modem.ser12.txshreg >>= 1; - } - sti(); - if (bc->modem.arb_divider <= 0) { - bc->modem.arb_divider = SER12_BAUD/100; - hdlcdrv_arbitrate(dev, &bc->hdrv); - } - hdlcdrv_transmitter(dev, &bc->hdrv); - hdlcdrv_receiver(dev, &bc->hdrv); -} - -/* --------------------------------------------------------------------- */ -#else /* BAYCOM_ALT_SER12 */ - -static void inline ser12_set_divisor(struct device *dev, - unsigned char divisor) -{ - outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ - outb(divisor, DLL(dev->base_addr)); - outb(0, DLM(dev->base_addr)); - outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ - /* - * make sure the next interrupt is generated; - * 0 must be used to power the modem; the modem draws its - * power from the TxD line - */ - outb(0x00, THR(dev->base_addr)); - /* - * it is important not to set the divider while transmitting; - * this reportedly makes some UARTs generating interrupts - * in the hundredthousands per second region - * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno) - */ -} - -/* --------------------------------------------------------------------- */ - -/* - * must call the TX arbitrator every 10ms - */ -#define SER12_ARB_DIVIDER(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \ - 36 : 24) -#define SER12_DCD_INTERVAL(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \ - 240 : 12) - -static inline void ser12_tx(struct device *dev, struct baycom_state *bc) -{ - /* one interrupt per channel bit */ - ser12_set_divisor(dev, 12); - /* - * first output the last bit (!) then call HDLC transmitter, - * since this may take quite long - */ - outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); - if (bc->modem.shreg <= 1) - bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); - bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ - (bc->modem.shreg & 1)); - bc->modem.shreg >>= 1; -} - -/* --------------------------------------------------------------------- */ - -static inline void ser12_rx(struct device *dev, struct baycom_state *bc) -{ - unsigned char cur_s; - /* - * do demodulator - */ - cur_s = inb(MSR(dev->base_addr)) & 0x10; /* the CTS line */ - hdlcdrv_channelbit(&bc->hdrv, cur_s); - bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) | - (cur_s != bc->modem.ser12.last_sample); - bc->modem.ser12.last_sample = cur_s; - if(bc->modem.ser12.dcd_shreg & 1) { - if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { - unsigned int dcdspos, dcdsneg; - - dcdspos = dcdsneg = 0; - dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); - if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) - dcdspos += 2; - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); - - bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; - } else - bc->modem.ser12.dcd_sum0--; - } - if(!bc->modem.ser12.dcd_time) { - hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + - bc->modem.ser12.dcd_sum1 + - bc->modem.ser12.dcd_sum2) < 0); - bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; - bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; - /* offset to ensure DCD off on silent input */ - bc->modem.ser12.dcd_sum0 = 2; - bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); - } - bc->modem.ser12.dcd_time--; - if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { - /* - * PLL code for the improved software DCD algorithm - */ - if (bc->modem.ser12.interm_sample) { - /* - * intermediate sample; set timing correction to normal - */ - ser12_set_divisor(dev, 4); - } else { - /* - * do PLL correction and call HDLC receiver - */ - switch (bc->modem.ser12.dcd_shreg & 7) { - case 1: /* transition too late */ - ser12_set_divisor(dev, 5); -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr++; -#endif /* BAYCOM_DEBUG */ - break; - case 4: /* transition too early */ - ser12_set_divisor(dev, 3); -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr--; -#endif /* BAYCOM_DEBUG */ - break; - default: - ser12_set_divisor(dev, 4); - break; - } - bc->modem.shreg >>= 1; - if (bc->modem.ser12.last_sample == - bc->modem.ser12.last_rxbit) - bc->modem.shreg |= 0x10000; - bc->modem.ser12.last_rxbit = - bc->modem.ser12.last_sample; - } - if (++bc->modem.ser12.interm_sample >= 3) - bc->modem.ser12.interm_sample = 0; - /* - * DCD stuff - */ - if (bc->modem.ser12.dcd_shreg & 1) { - unsigned int dcdspos, dcdsneg; - - dcdspos = dcdsneg = 0; - dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); - dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) - << 1; - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); - - bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; - } - } else { - /* - * PLL algorithm for the hardware squelch DCD algorithm - */ - if (bc->modem.ser12.interm_sample) { - /* - * intermediate sample; set timing correction to normal - */ - ser12_set_divisor(dev, 6); - } else { - /* - * do PLL correction and call HDLC receiver - */ - switch (bc->modem.ser12.dcd_shreg & 3) { - case 1: /* transition too late */ - ser12_set_divisor(dev, 7); -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr++; -#endif /* BAYCOM_DEBUG */ - break; - case 2: /* transition too early */ - ser12_set_divisor(dev, 5); -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr--; -#endif /* BAYCOM_DEBUG */ - break; - default: - ser12_set_divisor(dev, 6); - break; - } - bc->modem.shreg >>= 1; - if (bc->modem.ser12.last_sample == - bc->modem.ser12.last_rxbit) - bc->modem.shreg |= 0x10000; - bc->modem.ser12.last_rxbit = - bc->modem.ser12.last_sample; - } - bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample; - /* - * DCD stuff - */ - bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1); - } - outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ - if (bc->modem.shreg & 1) { - hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1); - bc->modem.shreg = 0x10000; - } - if(!bc->modem.ser12.dcd_time) { - hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + - bc->modem.ser12.dcd_sum1 + - bc->modem.ser12.dcd_sum2) < 0); - bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; - bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; - /* offset to ensure DCD off on silent input */ - bc->modem.ser12.dcd_sum0 = 2; - bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); - } - bc->modem.ser12.dcd_time--; -} - -/* --------------------------------------------------------------------- */ - -static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; - - if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) - return; - - baycom_int_freq(bc); - /* - * check if transmitter active - */ - if (hdlcdrv_ptt(&bc->hdrv)) - ser12_tx(dev, bc); - else { - ser12_rx(dev, bc); - if (--bc->modem.arb_divider <= 0) { - bc->modem.arb_divider = SER12_ARB_DIVIDER(bc); - sti(); - hdlcdrv_arbitrate(dev, &bc->hdrv); - } - } - sti(); - hdlcdrv_transmitter(dev, &bc->hdrv); - hdlcdrv_receiver(dev, &bc->hdrv); -} -#endif /* BAYCOM_ALT_SER12 */ - -/* --------------------------------------------------------------------- */ - -enum uart { c_uart_unknown, c_uart_8250, - c_uart_16450, c_uart_16550, c_uart_16550A}; -static const char *uart_str[] = { - "unknown", "8250", "16450", "16550", "16550A" -}; - -static enum uart ser12_check_uart(unsigned int iobase) -{ - unsigned char b1,b2,b3; - enum uart u; - enum uart uart_tab[] = - { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; - - b1 = inb(MCR(iobase)); - outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ - b2 = inb(MSR(iobase)); - outb(0x1a, MCR(iobase)); - b3 = inb(MSR(iobase)) & 0xf0; - outb(b1, MCR(iobase)); /* restore old values */ - outb(b2, MSR(iobase)); - if (b3 != 0x90) - return c_uart_unknown; - inb(RBR(iobase)); - inb(RBR(iobase)); - outb(0x01, FCR(iobase)); /* enable FIFOs */ - u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; - if (u == c_uart_16450) { - outb(0x5a, SCR(iobase)); - b1 = inb(SCR(iobase)); - outb(0xa5, SCR(iobase)); - b2 = inb(SCR(iobase)); - if ((b1 != 0x5a) || (b2 != 0xa5)) - u = c_uart_8250; - } - return u; -} - -/* --------------------------------------------------------------------- */ - -static int ser12_open(struct device *dev) -{ - struct baycom_state *bc = (struct baycom_state *)dev->priv; - enum uart u; - - if (!dev || !bc) - return -ENXIO; - if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || - dev->irq < 2 || dev->irq > 15) - return -ENXIO; - if (check_region(dev->base_addr, SER12_EXTENT)) - return -EACCES; - memset(&bc->modem, 0, sizeof(bc->modem)); - bc->hdrv.par.bitrate = 1200; - if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) - return -EIO; - outb(0, FCR(dev->base_addr)); /* disable FIFOs */ - outb(0x0d, MCR(dev->base_addr)); - outb(0x0d, MCR(dev->base_addr)); - outb(0, IER(dev->base_addr)); - if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT, - "baycom_ser12", dev)) - return -EBUSY; - request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12"); -#ifdef BAYCOM_ALT_SER12 - bc->hdrv.par.bitrate = SER12_BAUD; - /* - * set the SIO to 6 Bits/character and 19600 baud, so that - * we get exactly (hopefully) one interrupt per radio symbol - */ - outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ - outb(115200/8/SER12_BAUD, DLL(dev->base_addr)); - outb(0, DLM(dev->base_addr)); - outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ - /* - * enable transmitter empty interrupt and modem status interrupt - */ - outb(0x0a, IER(dev->base_addr)); - /* - * make sure the next interrupt is generated; - * 0 must be used to power the modem; the modem draws its - * power from the TxD line - */ - outb(0x00, THR(dev->base_addr)); - printk(KERN_INFO "%s: ser12(alt modem) at iobase 0x%lx irq %u options " - "0x%x uart %s\n", bc_drvname, dev->base_addr, dev->irq, - bc->options, uart_str[u]); -#else /* BAYCOM_ALT_SER12 */ - /* - * enable transmitter empty interrupt - */ - outb(2, IER(dev->base_addr)); - /* - * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that - * we get exactly (hopefully) 2 or 3 interrupts per radio symbol, - * depending on the usage of the software DCD routine - */ - ser12_set_divisor(dev, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6); - printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u options " - "0x%x uart %s\n", bc_drvname, dev->base_addr, dev->irq, - bc->options, uart_str[u]); -#endif /* BAYCOM_ALT_SER12 */ - MOD_INC_USE_COUNT; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int ser12_close(struct device *dev) -{ - struct baycom_state *bc = (struct baycom_state *)dev->priv; - - if (!dev || !bc) - return -EINVAL; - /* - * disable interrupts - */ - outb(0, IER(dev->base_addr)); - outb(1, MCR(dev->base_addr)); - free_irq(dev->irq, dev); - release_region(dev->base_addr, SER12_EXTENT); - printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n", - bc_drvname, dev->base_addr, dev->irq); - MOD_DEC_USE_COUNT; - return 0; -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== PAR96 specific routines ========================= - */ - -#define PAR96_DESCRAM_TAP1 0x20000 -#define PAR96_DESCRAM_TAP2 0x01000 -#define PAR96_DESCRAM_TAP3 0x00001 - -#define PAR96_DESCRAM_TAPSH1 17 -#define PAR96_DESCRAM_TAPSH2 12 -#define PAR96_DESCRAM_TAPSH3 0 - -#define PAR96_SCRAM_TAP1 0x20000 /* X^17 */ -#define PAR96_SCRAM_TAPN 0x00021 /* X^0+X^5 */ - -/* --------------------------------------------------------------------- */ - -static inline void par96_tx(struct device *dev, struct baycom_state *bc) -{ - int i; - unsigned int data = hdlcdrv_getbits(&bc->hdrv); - - for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) { - unsigned char val = PAR97_POWER; - bc->modem.par96.scram = ((bc->modem.par96.scram << 1) | - (bc->modem.par96.scram & 1)); - if (!(data & 1)) - bc->modem.par96.scram ^= 1; - if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1)) - bc->modem.par96.scram ^= - (PAR96_SCRAM_TAPN << 1); - if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2)) - val |= PAR96_TXBIT; - outb(val, LPT_DATA(dev->base_addr)); - outb(val | PAR96_BURST, LPT_DATA(dev->base_addr)); - } -} - -/* --------------------------------------------------------------------- */ - -static inline void par96_rx(struct device *dev, struct baycom_state *bc) -{ - int i; - unsigned int data, mask, mask2, descx; - - /* - * do receiver; differential decode and descramble on the fly - */ - for(data = i = 0; i < PAR96_BURSTBITS; i++) { - bc->modem.par96.descram = (bc->modem.par96.descram << 1); - if (inb(LPT_STATUS(dev->base_addr)) & PAR96_RXBIT) - bc->modem.par96.descram |= 1; - descx = bc->modem.par96.descram ^ - (bc->modem.par96.descram >> 1); - /* now the diff decoded data is inverted in descram */ - outb(PAR97_POWER | PAR96_PTT, LPT_DATA(dev->base_addr)); - descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^ - (descx >> PAR96_DESCRAM_TAPSH2)); - data >>= 1; - if (!(descx & 1)) - data |= 0x8000; - outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, - LPT_DATA(dev->base_addr)); - } - hdlcdrv_putbits(&bc->hdrv, data); - /* - * do DCD algorithm - */ - if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { - bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16) - | (data << 16); - /* search for flags and set the dcd counter appropriately */ - for(mask = 0x1fe00, mask2 = 0xfc00, i = 0; - i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) - if ((bc->modem.par96.dcd_shreg & mask) == mask2) - bc->modem.par96.dcd_count = HDLCDRV_MAXFLEN+4; - /* check for abort/noise sequences */ - for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0; - i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) - if (((bc->modem.par96.dcd_shreg & mask) == mask2) && - (bc->modem.par96.dcd_count >= 0)) - bc->modem.par96.dcd_count -= HDLCDRV_MAXFLEN-10; - /* decrement and set the dcd variable */ - if (bc->modem.par96.dcd_count >= 0) - bc->modem.par96.dcd_count -= 2; - hdlcdrv_setdcd(&bc->hdrv, bc->modem.par96.dcd_count > 0); - } else { - hdlcdrv_setdcd(&bc->hdrv, !!(inb(LPT_STATUS(dev->base_addr)) - & PAR96_DCD)); - } -} - -/* --------------------------------------------------------------------- */ - -static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; - - if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) - return; - - baycom_int_freq(bc); - /* - * check if transmitter active - */ - if (hdlcdrv_ptt(&bc->hdrv)) - par96_tx(dev, bc); - else { - par96_rx(dev, bc); - if (--bc->modem.arb_divider <= 0) { - bc->modem.arb_divider = 6; - sti(); - hdlcdrv_arbitrate(dev, &bc->hdrv); - } - } - sti(); - hdlcdrv_transmitter(dev, &bc->hdrv); - hdlcdrv_receiver(dev, &bc->hdrv); -} - -/* --------------------------------------------------------------------- */ - -static int par96_check_lpt(unsigned int iobase) -{ - unsigned char b1,b2; - int i; - - b1 = inb(LPT_DATA(iobase)); - b2 = inb(LPT_CONTROL(iobase)); - outb(0xaa, LPT_DATA(iobase)); - i = inb(LPT_DATA(iobase)) == 0xaa; - outb(0x55, LPT_DATA(iobase)); - i &= inb(LPT_DATA(iobase)) == 0x55; - outb(0x0a, LPT_CONTROL(iobase)); - i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a; - outb(0x05, LPT_CONTROL(iobase)); - i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05; - outb(b1, LPT_DATA(iobase)); - outb(b2, LPT_CONTROL(iobase)); - return !i; -} - -/* --------------------------------------------------------------------- */ - -static int par96_open(struct device *dev) -{ - struct baycom_state *bc = (struct baycom_state *)dev->priv; - - if (!dev || !bc) - return -ENXIO; - if (!dev->base_addr || dev->base_addr > 0x1000-PAR96_EXTENT || - dev->irq < 2 || dev->irq > 15) - return -ENXIO; - if (check_region(dev->base_addr, PAR96_EXTENT)) - return -EACCES; - memset(&bc->modem, 0, sizeof(bc->modem)); - bc->hdrv.par.bitrate = 9600; - if (par96_check_lpt(dev->base_addr)) - return -EIO; - /* disable interrupt */ - outb(0, LPT_CONTROL(dev->base_addr)); - /* switch off PTT */ - outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev->base_addr)); - printk(KERN_INFO "%s: par96 at iobase 0x%lx irq %u options 0x%x\n", - bc_drvname, dev->base_addr, dev->irq, bc->options); - if (request_irq(dev->irq, par96_interrupt, SA_INTERRUPT, - "baycom_par96", dev)) - return -EBUSY; - request_region(dev->base_addr, PAR96_EXTENT, "baycom_par96"); - /* enable interrupt */ - outb(LPT_IRQ_ENABLE, LPT_CONTROL(dev->base_addr)); - MOD_INC_USE_COUNT; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int par96_close(struct device *dev) -{ - struct baycom_state *bc = (struct baycom_state *)dev->priv; - - if (!dev || !bc) - return -EINVAL; - /* disable interrupt */ - outb(0, LPT_CONTROL(dev->base_addr)); - /* switch off PTT */ - outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev->base_addr)); - free_irq(dev->irq, dev); - release_region(dev->base_addr, PAR96_EXTENT); - printk(KERN_INFO "%s: close par96 at iobase 0x%lx irq %u\n", - bc_drvname, dev->base_addr, dev->irq); - MOD_DEC_USE_COUNT; - return 0; -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== hdlcdrv driver interface ========================= - */ - -/* --------------------------------------------------------------------- */ - -static int baycom_ioctl(struct device *dev, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd); - -/* --------------------------------------------------------------------- */ - -static struct hdlcdrv_ops ser12_ops = { - bc_drvname, - bc_drvinfo, - ser12_open, - ser12_close, - baycom_ioctl -}; - -/* --------------------------------------------------------------------- */ - -static struct hdlcdrv_ops par96_ops = { - bc_drvname, - bc_drvinfo, - par96_open, - par96_close, - baycom_ioctl -}; - -/* --------------------------------------------------------------------- */ - -static struct hdlcdrv_ops dummy_ops = { - bc_drvname, - bc_drvinfo, - NULL, - NULL, - baycom_ioctl -}; - -/* --------------------------------------------------------------------- */ - -static int baycom_setmode(struct baycom_state *bc, char *modestr) -{ - struct hdlcdrv_ops *newops = NULL; - unsigned long flags; - - if (!strncmp(modestr, "off", 3)) - newops = &dummy_ops; - else if (!strncmp(modestr, "ser12", 5)) - newops = &ser12_ops; - else if (!strncmp(modestr, "par96", 5)) - newops = &par96_ops; - else - return -EINVAL; - save_flags(flags); - cli(); - bc->hdrv.ops = newops; - bc->options = !!strchr(modestr, '*'); - restore_flags(flags); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int baycom_ioctl(struct device *dev, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct baycom_state *bc; - struct baycom_ioctl bi; - int cmd2; - - if (!dev || !dev->priv || - ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "bc_ioctl: invalid device struct\n"); - return -EINVAL; - } - bc = (struct baycom_state *)dev->priv; - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - if (get_user(cmd2, (int *)ifr->ifr_data)) - return -EFAULT; - switch (hi->cmd) { - default: - break; - - case HDLCDRVCTL_GETMODE: - if (bc->hdrv.ops == &ser12_ops) - strcpy(hi->data.modename, "ser12"); - else if (bc->hdrv.ops == &par96_ops) - strcpy(hi->data.modename, "par96"); - else if (bc->hdrv.ops == &dummy_ops) - strcpy(hi->data.modename, "off"); - else - strcpy(hi->data.modename, "invalid"); - if (bc->options & 1) - strcat(hi->data.modename, "*"); - if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_SETMODE: - if (!suser() || dev->start) - return -EACCES; - hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; - return baycom_setmode(bc, hi->data.modename); - - case HDLCDRVCTL_MODELIST: - strcpy(hi->data.modename, "ser12,par96"); - if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_MODEMPARMASK: - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ; - - } - - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - switch (bi.cmd) { - default: - return -ENOIOCTLCMD; - -#ifdef BAYCOM_DEBUG - case BAYCOMCTL_GETDEBUG: - bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; - bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; - bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; - break; -#endif /* BAYCOM_DEBUG */ - - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -__initfunc(int baycom_init(void)) -{ - int i, j, found = 0; - char set_hw = 1; - struct baycom_state *bc; - char ifname[HDLCDRV_IFNAMELEN]; - - - printk(bc_drvinfo); - /* - * register net devices - */ - for (i = 0; i < NR_PORTS; i++) { - struct device *dev = baycom_device+i; - sprintf(ifname, "bc%d", i); - - if (!baycom_ports[i].mode) - set_hw = 0; - if (!set_hw) - baycom_ports[i].iobase = baycom_ports[i].irq = 0; - j = hdlcdrv_register_hdlcdrv(dev, &dummy_ops, - sizeof(struct baycom_state), - ifname, baycom_ports[i].iobase, - baycom_ports[i].irq, 0); - if (!j) { - bc = (struct baycom_state *)dev->priv; - if (set_hw && baycom_setmode(bc, baycom_ports[i].mode)) - set_hw = 0; - found++; - } else { - printk(KERN_WARNING "%s: cannot register net device\n", - bc_drvname); - } - } - if (!found) - return -ENXIO; - return 0; -} - -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -/* - * command line settable parameters - */ -static char *mode = NULL; -static int iobase = 0x3f8; -static int irq = 4; - -#if LINUX_VERSION_CODE >= 0x20115 - -MODULE_PARM(mode, "s"); -MODULE_PARM_DESC(mode, "baycom operating mode; eg. ser12* or par96"); -MODULE_PARM(iobase, "i"); -MODULE_PARM_DESC(iobase, "baycom io base address"); -MODULE_PARM(irq, "i"); -MODULE_PARM_DESC(irq, "baycom irq number"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom ser12, par96 and picpar amateur radio modem driver"); - -#endif - -__initfunc(int init_module(void)) -{ - baycom_ports[0].mode = mode; - baycom_ports[0].iobase = iobase; - baycom_ports[0].irq = irq; - baycom_ports[1].mode = NULL; - - return baycom_init(); -} - -/* --------------------------------------------------------------------- */ - -void cleanup_module(void) -{ - int i; - - for(i = 0; i < NR_PORTS; i++) { - struct device *dev = baycom_device+i; - struct baycom_state *bc = (struct baycom_state *)dev->priv; - - if (bc) { - if (bc->hdrv.magic != HDLCDRV_MAGIC) - printk(KERN_ERR "baycom: invalid magic in " - "cleanup_module\n"); - else - hdlcdrv_unregister_hdlcdrv(dev); - } - } -} - -#else /* MODULE */ -/* --------------------------------------------------------------------- */ -/* - * format: baycom=io,irq,mode - * mode: {ser12,par96}[*] - * * indicates sofware DCD - */ - -__initfunc(void baycom_setup(char *str, int *ints)) -{ - int i; - - for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++); - if ((i >= NR_PORTS) || (ints[0] < 2)) { - printk(KERN_INFO "%s: too many or invalid interface " - "specifications\n", bc_drvname); - return; - } - baycom_ports[i].mode = str; - baycom_ports[i].iobase = ints[1]; - baycom_ports[i].irq = ints[2]; - if (i < NR_PORTS-1) - baycom_ports[i+1].mode = NULL; -} - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.67/linux/drivers/net/baycom_par.c linux/drivers/net/baycom_par.c --- v2.1.67/linux/drivers/net/baycom_par.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/baycom_par.c Sun Nov 30 10:30:19 1997 @@ -0,0 +1,661 @@ +/*****************************************************************************/ + +/* + * baycom_par.c -- baycom par96 and picpar radio modem driver. + * + * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * Supported modems + * + * par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard. + * The modem does all the filtering and regenerates the receiver clock. + * Data is transferred from and to the PC via a shift register. + * The shift register is filled with 16 bits and an interrupt is + * signalled. The PC then empties the shift register in a burst. This + * modem connects to the parallel port, hence the name. The modem + * leaves the implementation of the HDLC protocol and the scrambler + * polynomial to the PC. This modem is no longer available (at least + * from Baycom) and has been replaced by the PICPAR modem (see below). + * You may however still build one from the schematics published in + * cq-DL :-). + * + * 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 and can therefore be fed from the parallel port and + * does not require an additional power supply. It features + * built in DCD circuitry. The driver should therefore be configured + * for hardware DCD. + * + * + * Command line options (insmod command line) + * + * mode driver mode string. Valid choices are par96 and picpar. + * iobase base address of the port; common values are 0x378, 0x278, 0x3bc + * + * + * History: + * 0.1 26.06.96 Adapted from baycom.c and made network driver interface + * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) + * 0.3 26.04.97 init code/data tagged + * 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints) + * 0.5 11.11.97 split into separate files for ser12/par96 + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* --------------------------------------------------------------------- */ + +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern __inline__ int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern __inline__ int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + +/* --------------------------------------------------------------------- */ + +#define BAYCOM_DEBUG + +/* + * modem options; bit mask + */ +#define BAYCOM_OPTIONS_SOFTDCD 1 + +/* --------------------------------------------------------------------- */ + +static const char bc_drvname[] = "baycom_par"; +static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n" +KERN_INFO "baycom_par: version 0.5 compiled " __TIME__ " " __DATE__ "\n"; + +/* --------------------------------------------------------------------- */ + +#define NR_PORTS 4 + +static struct device baycom_device[NR_PORTS]; + +static struct { + const char *mode; + int iobase; +} baycom_ports[NR_PORTS] = { { NULL, 0 }, }; + +/* --------------------------------------------------------------------- */ + +#define SER12_EXTENT 8 + +#define LPT_DATA(dev) ((dev)->base_addr+0) +#define LPT_STATUS(dev) ((dev)->base_addr+1) +#define LPT_CONTROL(dev) ((dev)->base_addr+2) +#define LPT_IRQ_ENABLE 0x10 + +#define PAR96_BURSTBITS 16 +#define PAR96_BURST 4 +#define PAR96_PTT 2 +#define PAR96_TXBIT 1 +#define PAR96_ACK 0x40 +#define PAR96_RXBIT 0x20 +#define PAR96_DCD 0x10 +#define PAR97_POWER 0xf8 + +/* ---------------------------------------------------------------------- */ +/* + * Information that need to be kept for each board. + */ + +struct baycom_state { + struct hdlcdrv_state hdrv; + + struct pardevice *pdev; + unsigned int options; + + struct modem_state { + short arb_divider; + unsigned char flags; + unsigned int shreg; + struct modem_state_par96 { + int dcd_count; + unsigned int dcd_shreg; + unsigned long descram; + unsigned long scram; + } par96; + } modem; + +#ifdef BAYCOM_DEBUG + struct debug_vals { + unsigned long last_jiffies; + unsigned cur_intcnt; + unsigned last_intcnt; + int cur_pllcorr; + int last_pllcorr; + } debug_vals; +#endif /* BAYCOM_DEBUG */ +}; + +/* --------------------------------------------------------------------- */ + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +/* --------------------------------------------------------------------- */ + +static void __inline__ baycom_int_freq(struct baycom_state *bc) +{ +#ifdef BAYCOM_DEBUG + unsigned long cur_jiffies = jiffies; + /* + * measure the interrupt frequency + */ + bc->debug_vals.cur_intcnt++; + if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + bc->debug_vals.last_jiffies = cur_jiffies; + bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; + bc->debug_vals.cur_intcnt = 0; + bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; + bc->debug_vals.cur_pllcorr = 0; + } +#endif /* BAYCOM_DEBUG */ +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== PAR96 specific routines ========================= + */ + +#define PAR96_DESCRAM_TAP1 0x20000 +#define PAR96_DESCRAM_TAP2 0x01000 +#define PAR96_DESCRAM_TAP3 0x00001 + +#define PAR96_DESCRAM_TAPSH1 17 +#define PAR96_DESCRAM_TAPSH2 12 +#define PAR96_DESCRAM_TAPSH3 0 + +#define PAR96_SCRAM_TAP1 0x20000 /* X^17 */ +#define PAR96_SCRAM_TAPN 0x00021 /* X^0+X^5 */ + +/* --------------------------------------------------------------------- */ + +static __inline__ void par96_tx(struct device *dev, struct baycom_state *bc) +{ + int i; + unsigned int data = hdlcdrv_getbits(&bc->hdrv); + + for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) { + unsigned char val = PAR97_POWER; + bc->modem.par96.scram = ((bc->modem.par96.scram << 1) | + (bc->modem.par96.scram & 1)); + if (!(data & 1)) + bc->modem.par96.scram ^= 1; + if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1)) + bc->modem.par96.scram ^= + (PAR96_SCRAM_TAPN << 1); + if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2)) + val |= PAR96_TXBIT; + outb(val, LPT_DATA(dev)); + outb(val | PAR96_BURST, LPT_DATA(dev)); + } +} + +/* --------------------------------------------------------------------- */ + +static __inline__ void par96_rx(struct device *dev, struct baycom_state *bc) +{ + int i; + unsigned int data, mask, mask2, descx; + + /* + * do receiver; differential decode and descramble on the fly + */ + for(data = i = 0; i < PAR96_BURSTBITS; i++) { + bc->modem.par96.descram = (bc->modem.par96.descram << 1); + if (inb(LPT_STATUS(dev)) & PAR96_RXBIT) + bc->modem.par96.descram |= 1; + descx = bc->modem.par96.descram ^ + (bc->modem.par96.descram >> 1); + /* now the diff decoded data is inverted in descram */ + outb(PAR97_POWER | PAR96_PTT, LPT_DATA(dev)); + descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^ + (descx >> PAR96_DESCRAM_TAPSH2)); + data >>= 1; + if (!(descx & 1)) + data |= 0x8000; + outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, LPT_DATA(dev)); + } + hdlcdrv_putbits(&bc->hdrv, data); + /* + * do DCD algorithm + */ + if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { + bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16) + | (data << 16); + /* search for flags and set the dcd counter appropriately */ + for(mask = 0x1fe00, mask2 = 0xfc00, i = 0; + i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) + if ((bc->modem.par96.dcd_shreg & mask) == mask2) + bc->modem.par96.dcd_count = HDLCDRV_MAXFLEN+4; + /* check for abort/noise sequences */ + for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0; + i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) + if (((bc->modem.par96.dcd_shreg & mask) == mask2) && + (bc->modem.par96.dcd_count >= 0)) + bc->modem.par96.dcd_count -= HDLCDRV_MAXFLEN-10; + /* decrement and set the dcd variable */ + if (bc->modem.par96.dcd_count >= 0) + bc->modem.par96.dcd_count -= 2; + hdlcdrv_setdcd(&bc->hdrv, bc->modem.par96.dcd_count > 0); + } else { + hdlcdrv_setdcd(&bc->hdrv, !!(inb(LPT_STATUS(dev)) & PAR96_DCD)); + } +} + +/* --------------------------------------------------------------------- */ + +static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct parport *pp = (struct parport *)dev_id; + struct pardevice *pd = pp->cad; + struct device *dev = (struct device *)pd->private; + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) + return; + + baycom_int_freq(bc); + /* + * check if transmitter active + */ + if (hdlcdrv_ptt(&bc->hdrv)) + par96_tx(dev, bc); + else { + par96_rx(dev, bc); + if (--bc->modem.arb_divider <= 0) { + bc->modem.arb_divider = 6; + sti(); + hdlcdrv_arbitrate(dev, &bc->hdrv); + } + } + sti(); + hdlcdrv_transmitter(dev, &bc->hdrv); + hdlcdrv_receiver(dev, &bc->hdrv); +} + +/* --------------------------------------------------------------------- */ + +static int par96_preempt(void *handle) +{ + /* we cannot relinquish the port in the middle of an operation */ + return 1; +} + +/* --------------------------------------------------------------------- */ + +static void par96_wakeup(void *handle) +{ + struct device *dev = (struct device *)handle; + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + printk(KERN_DEBUG "baycom_par: %s: why am I being woken up?\n", dev->name); + if (!parport_claim(bc->pdev)) + printk(KERN_DEBUG "baycom_par: %s: I'm broken.\n", dev->name); +} + +/* --------------------------------------------------------------------- */ + +static int par96_open(struct device *dev) +{ + struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct parport *pp = parport_enumerate(); + + if (!dev || !bc) + return -ENXIO; + while (pp && pp->base != dev->base_addr) + pp = pp->next; + if (!pp) { + printk(KERN_ERR "baycom_par: parport at 0x%lx unknown\n", dev->base_addr); + return -ENXIO; + } + if (pp->irq < 0) { + printk(KERN_ERR "baycom_par: parport at 0x%x has no irq\n", pp->base); + return -ENXIO; + } + memset(&bc->modem, 0, sizeof(bc->modem)); + bc->hdrv.par.bitrate = 9600; + if (!(bc->pdev = parport_register_device(pp, dev->name, par96_preempt, par96_wakeup, + par96_interrupt, PARPORT_DEV_LURK, dev))) { + printk(KERN_ERR "baycom_par: cannot register parport at 0x%x\n", pp->base); + return -ENXIO; + } + if (parport_claim(bc->pdev)) { + printk(KERN_ERR "baycom_par: parport at 0x%x busy\n", pp->base); + parport_unregister_device(bc->pdev); + return -EBUSY; + } + dev->irq = pp->irq; + /* bc->pdev->port->ops->change_mode(bc->pdev->port, PARPORT_MODE_PCSPP); not yet implemented */ + /* switch off PTT */ + outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev)); + /*bc->pdev->port->ops->enable_irq(bc->pdev->port); not yet implemented */ + outb(LPT_IRQ_ENABLE, LPT_CONTROL(dev)); + printk(KERN_INFO "%s: par96 at iobase 0x%lx irq %u options 0x%x\n", + bc_drvname, dev->base_addr, dev->irq, bc->options); + MOD_INC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int par96_close(struct device *dev) +{ + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + if (!dev || !bc) + return -EINVAL; + /* disable interrupt */ + outb(0, LPT_CONTROL(dev)); + /*bc->pdev->port->ops->disable_irq(bc->pdev->port); not yet implemented */ + /* switch off PTT */ + outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev)); + parport_release(bc->pdev); + parport_unregister_device(bc->pdev); + printk(KERN_INFO "%s: close par96 at iobase 0x%lx irq %u\n", + bc_drvname, dev->base_addr, dev->irq); + MOD_DEC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== hdlcdrv driver interface ========================= + */ + +static int baycom_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd); + +/* --------------------------------------------------------------------- */ + +static struct hdlcdrv_ops par96_ops = { + bc_drvname, + bc_drvinfo, + par96_open, + par96_close, + baycom_ioctl +}; + +/* --------------------------------------------------------------------- */ + +static int baycom_setmode(struct baycom_state *bc, const char *modestr) +{ + if (!strncmp(modestr, "picpar", 6)) + bc->options = 0; + else if (!strncmp(modestr, "par96", 5)) + bc->options = BAYCOM_OPTIONS_SOFTDCD; + else + bc->options = !!strchr(modestr, '*'); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int baycom_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct baycom_state *bc; + struct baycom_ioctl bi; + int cmd2; + + if (!dev || !dev->priv || + ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "bc_ioctl: invalid device struct\n"); + return -EINVAL; + } + bc = (struct baycom_state *)dev->priv; + + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + if (get_user(cmd2, (int *)ifr->ifr_data)) + return -EFAULT; + switch (hi->cmd) { + default: + break; + + case HDLCDRVCTL_GETMODE: + strcpy(hi->data.modename, bc->options ? "par96" : "picpar"); + if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) + return -EFAULT; + return 0; + + case HDLCDRVCTL_SETMODE: + if (!suser() || dev->start) + return -EACCES; + hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; + return baycom_setmode(bc, hi->data.modename); + + case HDLCDRVCTL_MODELIST: + strcpy(hi->data.modename, "par96,picpar"); + if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) + return -EFAULT; + return 0; + + case HDLCDRVCTL_MODEMPARMASK: + return HDLCDRV_PARMASK_IOBASE; + + } + + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + switch (bi.cmd) { + default: + return -ENOIOCTLCMD; + +#ifdef BAYCOM_DEBUG + case BAYCOMCTL_GETDEBUG: + bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; + bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; + bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; + break; +#endif /* BAYCOM_DEBUG */ + + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + +} + +/* --------------------------------------------------------------------- */ + +__initfunc(int baycom_par_init(void)) +{ + int i, j, found = 0; + char set_hw = 1; + struct baycom_state *bc; + char ifname[HDLCDRV_IFNAMELEN]; + + + printk(bc_drvinfo); + /* + * register net devices + */ + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = baycom_device+i; + sprintf(ifname, "bcp%d", i); + + if (!baycom_ports[i].mode) + set_hw = 0; + if (!set_hw) + baycom_ports[i].iobase = 0; + j = hdlcdrv_register_hdlcdrv(dev, &par96_ops, + sizeof(struct baycom_state), + ifname, baycom_ports[i].iobase, 0, 0); + if (!j) { + bc = (struct baycom_state *)dev->priv; + if (set_hw && baycom_setmode(bc, baycom_ports[i].mode)) + set_hw = 0; + found++; + } else { + printk(KERN_WARNING "%s: cannot register net device\n", + bc_drvname); + } + } + if (!found) + return -ENXIO; + return 0; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +/* + * command line settable parameters + */ +static const char *mode[NR_PORTS] = { "picpar", }; +static int iobase[NR_PORTS] = { 0x378, }; + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); +MODULE_PARM_DESC(mode, "baycom operating mode; eg. par96 or picpar"); +MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(iobase, "baycom io base address"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Baycom par96 and picpar amateur radio modem driver"); + +#endif + +__initfunc(int init_module(void)) +{ + int i; + + for (i = 0; (i < NR_PORTS) && (mode[i]); i++) { + baycom_ports[i].mode = mode[i]; + baycom_ports[i].iobase = iobase[i]; + } + if (i < NR_PORTS-1) + baycom_ports[i+1].mode = NULL; + return baycom_par_init(); +} + +/* --------------------------------------------------------------------- */ + +void cleanup_module(void) +{ + int i; + + for(i = 0; i < NR_PORTS; i++) { + struct device *dev = baycom_device+i; + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + if (bc) { + if (bc->hdrv.magic != HDLCDRV_MAGIC) + printk(KERN_ERR "baycom: invalid magic in " + "cleanup_module\n"); + else + hdlcdrv_unregister_hdlcdrv(dev); + } + } +} + +#else /* MODULE */ +/* --------------------------------------------------------------------- */ +/* + * format: baycom_par=io,mode + * mode: par96,picpar + */ + +__initfunc(void baycom_par_setup(char *str, int *ints)) +{ + int i; + + for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++); + if ((i >= NR_PORTS) || (ints[0] < 1)) { + printk(KERN_INFO "%s: too many or invalid interface " + "specifications\n", bc_drvname); + return; + } + baycom_ports[i].mode = str; + baycom_ports[i].iobase = ints[1]; + if (i < NR_PORTS-1) + baycom_ports[i+1].mode = NULL; +} + +#endif /* MODULE */ +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.67/linux/drivers/net/baycom_ser_fdx.c linux/drivers/net/baycom_ser_fdx.c --- v2.1.67/linux/drivers/net/baycom_ser_fdx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/baycom_ser_fdx.c Sun Nov 30 10:30:19 1997 @@ -0,0 +1,762 @@ +/*****************************************************************************/ + +/* + * baycom_ser_fdx.c -- baycom ser12 fullduplex radio modem driver. + * + * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * Supported modems + * + * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only + * of a modulator/demodulator chip, usually a TI TCM3105. The computer + * is responsible for regenerating the receiver bit clock, as well as + * for handling the HDLC protocol. The modem connects to a serial port, + * hence the name. Since the serial port is not used as an async serial + * port, the kernel driver for serial ports cannot be used, and this + * driver only supports standard serial hardware (8250, 16450, 16550A) + * + * + * Command line options (insmod command line) + * + * mode * enables software DCD. + * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 + * baud baud rate (between 300 and 4800) + * irq interrupt line of the port; common values are 4,3 + * + * + * History: + * 0.1 26.06.96 Adapted from baycom.c and made network driver interface + * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) + * 0.3 26.04.97 init code/data tagged + * 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints) + * 0.5 11.11.97 ser12/par96 split into separate files + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* --------------------------------------------------------------------- */ + +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + +/* --------------------------------------------------------------------- */ + +#define BAYCOM_DEBUG + +/* + * modem options; bit mask + */ +#define BAYCOM_OPTIONS_SOFTDCD 1 + +/* --------------------------------------------------------------------- */ + +static const char bc_drvname[] = "baycom_ser_fdx"; +static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n" +KERN_INFO "baycom_ser_fdx: version 0.5 compiled " __TIME__ " " __DATE__ "\n"; + +/* --------------------------------------------------------------------- */ + +#define NR_PORTS 4 + +static struct device baycom_device[NR_PORTS]; + +static struct { + char *mode; + int iobase, irq, baud; +} baycom_ports[NR_PORTS] = { { NULL, 0, 0 }, }; + +/* --------------------------------------------------------------------- */ + +#define RBR(iobase) (iobase+0) +#define THR(iobase) (iobase+0) +#define IER(iobase) (iobase+1) +#define IIR(iobase) (iobase+2) +#define FCR(iobase) (iobase+2) +#define LCR(iobase) (iobase+3) +#define MCR(iobase) (iobase+4) +#define LSR(iobase) (iobase+5) +#define MSR(iobase) (iobase+6) +#define SCR(iobase) (iobase+7) +#define DLL(iobase) (iobase+0) +#define DLM(iobase) (iobase+1) + +#define SER12_EXTENT 8 + +/* ---------------------------------------------------------------------- */ +/* + * Information that need to be kept for each board. + */ + +struct baycom_state { + struct hdlcdrv_state hdrv; + + unsigned int baud, baud_us8, baud_arbdiv; + unsigned int options; + + struct modem_state { + short arb_divider; + unsigned char flags; + unsigned int shreg; + struct modem_state_ser12 { + unsigned char tx_bit; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned char last_sample; + unsigned char last_rxbit; + unsigned int dcd_shreg; + unsigned int dcd_time; + unsigned int bit_pll; + unsigned long last_jiffies; + unsigned int pll_time; + unsigned int txshreg; + } ser12; + } modem; + +#ifdef BAYCOM_DEBUG + struct debug_vals { + unsigned long last_jiffies; + unsigned cur_intcnt; + unsigned last_intcnt; + int cur_pllcorr; + int last_pllcorr; + } debug_vals; +#endif /* BAYCOM_DEBUG */ +}; + +/* --------------------------------------------------------------------- */ + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +/* --------------------------------------------------------------------- */ + +static void inline baycom_int_freq(struct baycom_state *bc) +{ +#ifdef BAYCOM_DEBUG + unsigned long cur_jiffies = jiffies; + /* + * measure the interrupt frequency + */ + bc->debug_vals.cur_intcnt++; + if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + bc->debug_vals.last_jiffies = cur_jiffies; + bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; + bc->debug_vals.cur_intcnt = 0; + bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; + bc->debug_vals.cur_pllcorr = 0; + } +#endif /* BAYCOM_DEBUG */ +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== SER12 specific routines ========================= + */ + +/* --------------------------------------------------------------------- */ + +extern inline unsigned int hweight16(unsigned short w) + __attribute__ ((unused)); +extern inline unsigned int hweight8(unsigned char w) + __attribute__ ((unused)); + +extern inline unsigned int hweight16(unsigned short w) +{ + unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555); + res = (res & 0x3333) + ((res >> 2) & 0x3333); + res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); + return (res & 0x00FF) + ((res >> 8) & 0x00FF); +} + +extern inline unsigned int hweight8(unsigned char w) +{ + unsigned short res = (w & 0x55) + ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res & 0x0F) + ((res >> 4) & 0x0F); +} + +/* --------------------------------------------------------------------- */ + +static __inline__ void ser12_rxsample(struct device *dev, struct baycom_state *bc, unsigned char news) +{ + bc->modem.ser12.dcd_shreg <<= 1; + bc->modem.ser12.bit_pll += 0x2000; + if (bc->modem.ser12.last_sample != news) { + bc->modem.ser12.last_sample = news; + bc->modem.ser12.dcd_shreg |= 1; + if (bc->modem.ser12.bit_pll < 0x9000) + bc->modem.ser12.bit_pll += 0x1000; + else + bc->modem.ser12.bit_pll -= 0x1000; + bc->modem.ser12.dcd_sum0 += 4 * hweight8(bc->modem.ser12.dcd_shreg & 0x38) + - hweight16(bc->modem.ser12.dcd_shreg & 0x7c0); + } + hdlcdrv_channelbit(&bc->hdrv, !!bc->modem.ser12.last_sample); + if ((--bc->modem.ser12.dcd_time) <= 0) { + hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + + bc->modem.ser12.dcd_sum1 + + bc->modem.ser12.dcd_sum2) < 0); + bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; + bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; + bc->modem.ser12.dcd_sum0 = 2; /* slight bias */ + bc->modem.ser12.dcd_time = 120; + } + if (bc->modem.ser12.bit_pll >= 0x10000) { + bc->modem.ser12.bit_pll &= 0xffff; + bc->modem.shreg >>= 1; + if (bc->modem.ser12.last_rxbit == bc->modem.ser12.last_sample) + bc->modem.shreg |= 0x10000; + bc->modem.ser12.last_rxbit = bc->modem.ser12.last_sample; + if (bc->modem.shreg & 1) { + hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1); + bc->modem.shreg = 0x10000; + } + } +} + +/* --------------------------------------------------------------------- */ + +static __inline__ void ser12_rx(struct device *dev, struct baycom_state *bc, unsigned char curs) +{ + unsigned long curjiff; + struct timeval tv; + unsigned int timediff; + + /* + * get current time + */ + curjiff = jiffies; + do_gettimeofday(&tv); + if ((signed)(curjiff - bc->modem.ser12.last_jiffies) >= HZ/4) { + /* long inactivity; clear HDLC and DCD */ + bc->modem.ser12.dcd_sum1 = 0; + bc->modem.ser12.dcd_sum2 = 0; + bc->modem.ser12.dcd_sum0 = 2; + bc->modem.ser12.dcd_time = 120; + hdlcdrv_setdcd(&bc->hdrv, 0); + hdlcdrv_putbits(&bc->hdrv, 0xffff); + bc->modem.ser12.last_jiffies = curjiff; + bc->modem.ser12.pll_time = tv.tv_usec; + } + bc->modem.ser12.last_jiffies = curjiff; + timediff = tv.tv_usec + 1000000 - bc->modem.ser12.pll_time; + timediff %= 1000000; + timediff /= bc->baud_us8; + bc->modem.ser12.pll_time = (bc->modem.ser12.pll_time + timediff * (bc->baud_us8)) % 1000000; + for (; timediff > 1; timediff--) + ser12_rxsample(dev, bc, bc->modem.ser12.last_sample); + if (timediff >= 1) + ser12_rxsample(dev, bc, curs); +} + +/* --------------------------------------------------------------------- */ + +static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct baycom_state *bc = (struct baycom_state *)dev->priv; + unsigned char iir, msr = 0; + unsigned int txcount = 0; + unsigned int rxcount = 0; + + if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) + return; + + for (;;) { + iir = inb(IIR(dev->base_addr)); + if (iir & 1) + break; + switch (iir & 6) { + case 6: + inb(LSR(dev->base_addr)); + continue; + + case 4: + inb(RBR(dev->base_addr)); + continue; + + case 2: + /* + * make sure the next interrupt is generated; + * 0 must be used to power the modem; the modem draws its + * power from the TxD line + */ + outb(0x00, THR(dev->base_addr)); + bc->modem.arb_divider--; + baycom_int_freq(bc); + if (hdlcdrv_ptt(&bc->hdrv)) { + /* + * first output the last bit (!) then call HDLC transmitter, + * since this may take quite long + */ + outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); + txcount++; + } else + outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ + continue; + + default: + msr = inb(MSR(dev->base_addr)); + if (msr & 1) /* delta CTS interrupt */ + rxcount++; + continue; + } + } + if (rxcount) + ser12_rx(dev, bc, msr & 0x10); + if (txcount) { +#ifdef BAYCOM_DEBUG + if (bc->debug_vals.cur_pllcorr < txcount) + bc->debug_vals.cur_pllcorr = txcount; +#endif /* BAYCOM_DEBUG */ + if (bc->modem.ser12.txshreg <= 1) + bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); + bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1)); + bc->modem.ser12.txshreg >>= 1; + } + sti(); + if (bc->modem.arb_divider <= 0) { + bc->modem.arb_divider = bc->baud_arbdiv; + hdlcdrv_arbitrate(dev, &bc->hdrv); + } + hdlcdrv_transmitter(dev, &bc->hdrv); + hdlcdrv_receiver(dev, &bc->hdrv); +} + +/* --------------------------------------------------------------------- */ + +enum uart { c_uart_unknown, c_uart_8250, + c_uart_16450, c_uart_16550, c_uart_16550A}; +static const char *uart_str[] = { + "unknown", "8250", "16450", "16550", "16550A" +}; + +static enum uart ser12_check_uart(unsigned int iobase) +{ + unsigned char b1,b2,b3; + enum uart u; + enum uart uart_tab[] = + { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; + + b1 = inb(MCR(iobase)); + outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ + b2 = inb(MSR(iobase)); + outb(0x1a, MCR(iobase)); + b3 = inb(MSR(iobase)) & 0xf0; + outb(b1, MCR(iobase)); /* restore old values */ + outb(b2, MSR(iobase)); + if (b3 != 0x90) + return c_uart_unknown; + inb(RBR(iobase)); + inb(RBR(iobase)); + outb(0x01, FCR(iobase)); /* enable FIFOs */ + u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; + if (u == c_uart_16450) { + outb(0x5a, SCR(iobase)); + b1 = inb(SCR(iobase)); + outb(0xa5, SCR(iobase)); + b2 = inb(SCR(iobase)); + if ((b1 != 0x5a) || (b2 != 0xa5)) + u = c_uart_8250; + } + return u; +} + +/* --------------------------------------------------------------------- */ + +static int ser12_open(struct device *dev) +{ + struct baycom_state *bc = (struct baycom_state *)dev->priv; + enum uart u; + + if (!dev || !bc) + return -ENXIO; + if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || + dev->irq < 2 || dev->irq > 15) + return -ENXIO; + if (bc->baud < 300 || bc->baud > 4800) + return -EINVAL; + if (check_region(dev->base_addr, SER12_EXTENT)) + return -EACCES; + memset(&bc->modem, 0, sizeof(bc->modem)); + bc->hdrv.par.bitrate = bc->baud; + bc->baud_us8 = 125000/bc->baud; + bc->baud_arbdiv = bc->baud/100; + if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) + return -EIO; + outb(0, FCR(dev->base_addr)); /* disable FIFOs */ + outb(0x0d, MCR(dev->base_addr)); + outb(0x0d, MCR(dev->base_addr)); + outb(0, IER(dev->base_addr)); + if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT, + "baycom_ser_fdx", dev)) + return -EBUSY; + request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx"); + /* + * set the SIO to 6 Bits/character and 19600 baud, so that + * we get exactly (hopefully) one interrupt per radio symbol + */ + outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ + outb(115200/8/bc->baud, DLL(dev->base_addr)); + outb(0, DLM(dev->base_addr)); + outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ + /* + * enable transmitter empty interrupt and modem status interrupt + */ + outb(0x0a, IER(dev->base_addr)); + /* + * make sure the next interrupt is generated; + * 0 must be used to power the modem; the modem draws its + * power from the TxD line + */ + outb(0x00, THR(dev->base_addr)); + printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u options " + "0x%x baud %u uart %s\n", bc_drvname, dev->base_addr, dev->irq, + bc->options, bc->baud, uart_str[u]); + MOD_INC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int ser12_close(struct device *dev) +{ + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + if (!dev || !bc) + return -EINVAL; + /* + * disable interrupts + */ + outb(0, IER(dev->base_addr)); + outb(1, MCR(dev->base_addr)); + free_irq(dev->irq, dev); + release_region(dev->base_addr, SER12_EXTENT); + printk(KERN_INFO "%s: close ser_fdx at iobase 0x%lx irq %u\n", + bc_drvname, dev->base_addr, dev->irq); + MOD_DEC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== hdlcdrv driver interface ========================= + */ + +/* --------------------------------------------------------------------- */ + +static int baycom_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd); + +/* --------------------------------------------------------------------- */ + +static struct hdlcdrv_ops ser12_ops = { + bc_drvname, + bc_drvinfo, + ser12_open, + ser12_close, + baycom_ioctl +}; + +/* --------------------------------------------------------------------- */ + +static int baycom_setmode(struct baycom_state *bc, const char *modestr) +{ + unsigned int baud; + + if (!strncmp(modestr, "ser", 3)) { + baud = simple_strtoul(modestr+3, NULL, 10); + if (baud >= 3 && baud <= 48) + bc->baud = baud*100; + } + bc->options = !!strchr(modestr, '*'); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int baycom_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct baycom_state *bc; + struct baycom_ioctl bi; + int cmd2; + + if (!dev || !dev->priv || + ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "bc_ioctl: invalid device struct\n"); + return -EINVAL; + } + bc = (struct baycom_state *)dev->priv; + + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + if (get_user(cmd2, (int *)ifr->ifr_data)) + return -EFAULT; + switch (hi->cmd) { + default: + break; + + case HDLCDRVCTL_GETMODE: + sprintf(hi->data.modename, "ser%u", bc->baud / 100); + if (bc->options & 1) + strcat(hi->data.modename, "*"); + if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) + return -EFAULT; + return 0; + + case HDLCDRVCTL_SETMODE: + if (!suser() || dev->start) + return -EACCES; + hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; + return baycom_setmode(bc, hi->data.modename); + + case HDLCDRVCTL_MODELIST: + strcpy(hi->data.modename, "ser12,ser3,ser24"); + if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) + return -EFAULT; + return 0; + + case HDLCDRVCTL_MODEMPARMASK: + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ; + + } + + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + switch (bi.cmd) { + default: + return -ENOIOCTLCMD; + +#ifdef BAYCOM_DEBUG + case BAYCOMCTL_GETDEBUG: + bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; + bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; + bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; + break; +#endif /* BAYCOM_DEBUG */ + + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + +} + +/* --------------------------------------------------------------------- */ + +__initfunc(int baycom_ser_fdx_init(void)) +{ + int i, j, found = 0; + char set_hw = 1; + struct baycom_state *bc; + char ifname[HDLCDRV_IFNAMELEN]; + + + printk(bc_drvinfo); + /* + * register net devices + */ + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = baycom_device+i; + sprintf(ifname, "bcsf%d", i); + + if (!baycom_ports[i].mode) + set_hw = 0; + if (!set_hw) + baycom_ports[i].iobase = baycom_ports[i].irq = 0; + j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops, + sizeof(struct baycom_state), + ifname, baycom_ports[i].iobase, + baycom_ports[i].irq, 0); + if (!j) { + bc = (struct baycom_state *)dev->priv; + if (set_hw && baycom_setmode(bc, baycom_ports[i].mode)) + set_hw = 0; + bc->baud = baycom_ports[i].baud; + found++; + } else { + printk(KERN_WARNING "%s: cannot register net device\n", + bc_drvname); + } + } + if (!found) + return -ENXIO; + return 0; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +/* + * command line settable parameters + */ +static char *mode[NR_PORTS] = { "ser12*", }; +static int iobase[NR_PORTS] = { 0x3f8, }; +static int irq[NR_PORTS] = { 4, }; +static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 }; + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); +MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); +MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(iobase, "baycom io base address"); +MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(irq, "baycom irq number"); +MODULE_PARM(baud, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver"); + +#endif + +__initfunc(int init_module(void)) +{ + int i; + + for (i = 0; (i < NR_PORTS) && (mode[i]); i++) { + baycom_ports[i].mode = mode[i]; + baycom_ports[i].iobase = iobase[i]; + baycom_ports[i].irq = irq[i]; + baycom_ports[i].baud = baud[i]; + } + if (i < NR_PORTS-1) + baycom_ports[i+1].mode = NULL; + return baycom_ser_fdx_init(); +} + +/* --------------------------------------------------------------------- */ + +void cleanup_module(void) +{ + int i; + + for(i = 0; i < NR_PORTS; i++) { + struct device *dev = baycom_device+i; + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + if (bc) { + if (bc->hdrv.magic != HDLCDRV_MAGIC) + printk(KERN_ERR "baycom: invalid magic in " + "cleanup_module\n"); + else + hdlcdrv_unregister_hdlcdrv(dev); + } + } +} + +#else /* MODULE */ +/* --------------------------------------------------------------------- */ +/* + * format: baycom_ser_=io,irq,mode + * mode: [*] + * * indicates sofware DCD + */ + +__initfunc(void baycom_ser_fdx_setup(char *str, int *ints)) +{ + int i; + + for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++); + if ((i >= NR_PORTS) || (ints[0] < 2)) { + printk(KERN_INFO "%s: too many or invalid interface " + "specifications\n", bc_drvname); + return; + } + baycom_ports[i].mode = str; + baycom_ports[i].iobase = ints[1]; + baycom_ports[i].irq = ints[2]; + if (ints[0] >= 3) + baycom_ports[i].baud = ints[3]; + else + baycom_ports[i].baud = 1200; + if (i < NR_PORTS-1) + baycom_ports[i+1].mode = NULL; +} + +#endif /* MODULE */ +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.67/linux/drivers/net/baycom_ser_hdx.c linux/drivers/net/baycom_ser_hdx.c --- v2.1.67/linux/drivers/net/baycom_ser_hdx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/baycom_ser_hdx.c Sun Nov 30 10:30:19 1997 @@ -0,0 +1,792 @@ +/*****************************************************************************/ + +/* + * baycom_ser_hdx.c -- baycom ser12 halfduplex radio modem driver. + * + * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * Supported modems + * + * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only + * of a modulator/demodulator chip, usually a TI TCM3105. The computer + * is responsible for regenerating the receiver bit clock, as well as + * for handling the HDLC protocol. The modem connects to a serial port, + * hence the name. Since the serial port is not used as an async serial + * port, the kernel driver for serial ports cannot be used, and this + * driver only supports standard serial hardware (8250, 16450, 16550A) + * + * + * Command line options (insmod command line) + * + * mode * enables software DCD. + * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 + * irq interrupt line of the port; common values are 4,3 + * + * + * History: + * 0.1 26.06.96 Adapted from baycom.c and made network driver interface + * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) + * 0.3 26.04.97 init code/data tagged + * 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints) + * 0.5 11.11.97 ser12/par96 split into separate files + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* --------------------------------------------------------------------- */ + +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + +/* --------------------------------------------------------------------- */ + +#define BAYCOM_DEBUG + +/* + * modem options; bit mask + */ +#define BAYCOM_OPTIONS_SOFTDCD 1 + +/* --------------------------------------------------------------------- */ + +static const char bc_drvname[] = "baycom_ser_hdx"; +static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n" +KERN_INFO "baycom_ser_hdx: version 0.5 compiled " __TIME__ " " __DATE__ "\n"; + +/* --------------------------------------------------------------------- */ + +#define NR_PORTS 4 + +static struct device baycom_device[NR_PORTS]; + +static struct { + char *mode; + int iobase, irq; +} baycom_ports[NR_PORTS] = { { NULL, 0, 0 }, }; + +/* --------------------------------------------------------------------- */ + +#define RBR(iobase) (iobase+0) +#define THR(iobase) (iobase+0) +#define IER(iobase) (iobase+1) +#define IIR(iobase) (iobase+2) +#define FCR(iobase) (iobase+2) +#define LCR(iobase) (iobase+3) +#define MCR(iobase) (iobase+4) +#define LSR(iobase) (iobase+5) +#define MSR(iobase) (iobase+6) +#define SCR(iobase) (iobase+7) +#define DLL(iobase) (iobase+0) +#define DLM(iobase) (iobase+1) + +#define SER12_EXTENT 8 + +/* ---------------------------------------------------------------------- */ +/* + * Information that need to be kept for each board. + */ + +struct baycom_state { + struct hdlcdrv_state hdrv; + + unsigned int options; + + struct modem_state { + short arb_divider; + unsigned char flags; + unsigned int shreg; + struct modem_state_ser12 { + unsigned char tx_bit; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned char last_sample; + unsigned char last_rxbit; + unsigned int dcd_shreg; + unsigned int dcd_time; + unsigned int bit_pll; + unsigned char interm_sample; + } ser12; + } modem; + +#ifdef BAYCOM_DEBUG + struct debug_vals { + unsigned long last_jiffies; + unsigned cur_intcnt; + unsigned last_intcnt; + int cur_pllcorr; + int last_pllcorr; + } debug_vals; +#endif /* BAYCOM_DEBUG */ +}; + +/* --------------------------------------------------------------------- */ + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +/* --------------------------------------------------------------------- */ + +static void inline baycom_int_freq(struct baycom_state *bc) +{ +#ifdef BAYCOM_DEBUG + unsigned long cur_jiffies = jiffies; + /* + * measure the interrupt frequency + */ + bc->debug_vals.cur_intcnt++; + if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + bc->debug_vals.last_jiffies = cur_jiffies; + bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; + bc->debug_vals.cur_intcnt = 0; + bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; + bc->debug_vals.cur_pllcorr = 0; + } +#endif /* BAYCOM_DEBUG */ +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== SER12 specific routines ========================= + */ + +static void inline ser12_set_divisor(struct device *dev, + unsigned char divisor) +{ + outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ + outb(divisor, DLL(dev->base_addr)); + outb(0, DLM(dev->base_addr)); + outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ + /* + * make sure the next interrupt is generated; + * 0 must be used to power the modem; the modem draws its + * power from the TxD line + */ + outb(0x00, THR(dev->base_addr)); + /* + * it is important not to set the divider while transmitting; + * this reportedly makes some UARTs generating interrupts + * in the hundredthousands per second region + * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno) + */ +} + +/* --------------------------------------------------------------------- */ + +/* + * must call the TX arbitrator every 10ms + */ +#define SER12_ARB_DIVIDER(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \ + 36 : 24) +#define SER12_DCD_INTERVAL(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \ + 240 : 12) + +static inline void ser12_tx(struct device *dev, struct baycom_state *bc) +{ + /* one interrupt per channel bit */ + ser12_set_divisor(dev, 12); + /* + * first output the last bit (!) then call HDLC transmitter, + * since this may take quite long + */ + outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); + if (bc->modem.shreg <= 1) + bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); + bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ + (bc->modem.shreg & 1)); + bc->modem.shreg >>= 1; +} + +/* --------------------------------------------------------------------- */ + +static inline void ser12_rx(struct device *dev, struct baycom_state *bc) +{ + unsigned char cur_s; + /* + * do demodulator + */ + cur_s = inb(MSR(dev->base_addr)) & 0x10; /* the CTS line */ + hdlcdrv_channelbit(&bc->hdrv, cur_s); + bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) | + (cur_s != bc->modem.ser12.last_sample); + bc->modem.ser12.last_sample = cur_s; + if(bc->modem.ser12.dcd_shreg & 1) { + if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { + unsigned int dcdspos, dcdsneg; + + dcdspos = dcdsneg = 0; + dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); + if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) + dcdspos += 2; + dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); + dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); + dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); + + bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; + } else + bc->modem.ser12.dcd_sum0--; + } + if(!bc->modem.ser12.dcd_time) { + hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + + bc->modem.ser12.dcd_sum1 + + bc->modem.ser12.dcd_sum2) < 0); + bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; + bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; + /* offset to ensure DCD off on silent input */ + bc->modem.ser12.dcd_sum0 = 2; + bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); + } + bc->modem.ser12.dcd_time--; + if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { + /* + * PLL code for the improved software DCD algorithm + */ + if (bc->modem.ser12.interm_sample) { + /* + * intermediate sample; set timing correction to normal + */ + ser12_set_divisor(dev, 4); + } else { + /* + * do PLL correction and call HDLC receiver + */ + switch (bc->modem.ser12.dcd_shreg & 7) { + case 1: /* transition too late */ + ser12_set_divisor(dev, 5); +#ifdef BAYCOM_DEBUG + bc->debug_vals.cur_pllcorr++; +#endif /* BAYCOM_DEBUG */ + break; + case 4: /* transition too early */ + ser12_set_divisor(dev, 3); +#ifdef BAYCOM_DEBUG + bc->debug_vals.cur_pllcorr--; +#endif /* BAYCOM_DEBUG */ + break; + default: + ser12_set_divisor(dev, 4); + break; + } + bc->modem.shreg >>= 1; + if (bc->modem.ser12.last_sample == + bc->modem.ser12.last_rxbit) + bc->modem.shreg |= 0x10000; + bc->modem.ser12.last_rxbit = + bc->modem.ser12.last_sample; + } + if (++bc->modem.ser12.interm_sample >= 3) + bc->modem.ser12.interm_sample = 0; + /* + * DCD stuff + */ + if (bc->modem.ser12.dcd_shreg & 1) { + unsigned int dcdspos, dcdsneg; + + dcdspos = dcdsneg = 0; + dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); + dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) + << 1; + dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); + dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); + dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); + + bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; + } + } else { + /* + * PLL algorithm for the hardware squelch DCD algorithm + */ + if (bc->modem.ser12.interm_sample) { + /* + * intermediate sample; set timing correction to normal + */ + ser12_set_divisor(dev, 6); + } else { + /* + * do PLL correction and call HDLC receiver + */ + switch (bc->modem.ser12.dcd_shreg & 3) { + case 1: /* transition too late */ + ser12_set_divisor(dev, 7); +#ifdef BAYCOM_DEBUG + bc->debug_vals.cur_pllcorr++; +#endif /* BAYCOM_DEBUG */ + break; + case 2: /* transition too early */ + ser12_set_divisor(dev, 5); +#ifdef BAYCOM_DEBUG + bc->debug_vals.cur_pllcorr--; +#endif /* BAYCOM_DEBUG */ + break; + default: + ser12_set_divisor(dev, 6); + break; + } + bc->modem.shreg >>= 1; + if (bc->modem.ser12.last_sample == + bc->modem.ser12.last_rxbit) + bc->modem.shreg |= 0x10000; + bc->modem.ser12.last_rxbit = + bc->modem.ser12.last_sample; + } + bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample; + /* + * DCD stuff + */ + bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1); + } + outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ + if (bc->modem.shreg & 1) { + hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1); + bc->modem.shreg = 0x10000; + } + if(!bc->modem.ser12.dcd_time) { + hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + + bc->modem.ser12.dcd_sum1 + + bc->modem.ser12.dcd_sum2) < 0); + bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; + bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; + /* offset to ensure DCD off on silent input */ + bc->modem.ser12.dcd_sum0 = 2; + bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); + } + bc->modem.ser12.dcd_time--; +} + +/* --------------------------------------------------------------------- */ + +static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) + return; + + baycom_int_freq(bc); + /* + * check if transmitter active + */ + if (hdlcdrv_ptt(&bc->hdrv)) + ser12_tx(dev, bc); + else { + ser12_rx(dev, bc); + if (--bc->modem.arb_divider <= 0) { + bc->modem.arb_divider = SER12_ARB_DIVIDER(bc); + sti(); + hdlcdrv_arbitrate(dev, &bc->hdrv); + } + } + sti(); + hdlcdrv_transmitter(dev, &bc->hdrv); + hdlcdrv_receiver(dev, &bc->hdrv); +} + +/* --------------------------------------------------------------------- */ + +enum uart { c_uart_unknown, c_uart_8250, + c_uart_16450, c_uart_16550, c_uart_16550A}; +static const char *uart_str[] = { + "unknown", "8250", "16450", "16550", "16550A" +}; + +static enum uart ser12_check_uart(unsigned int iobase) +{ + unsigned char b1,b2,b3; + enum uart u; + enum uart uart_tab[] = + { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; + + b1 = inb(MCR(iobase)); + outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ + b2 = inb(MSR(iobase)); + outb(0x1a, MCR(iobase)); + b3 = inb(MSR(iobase)) & 0xf0; + outb(b1, MCR(iobase)); /* restore old values */ + outb(b2, MSR(iobase)); + if (b3 != 0x90) + return c_uart_unknown; + inb(RBR(iobase)); + inb(RBR(iobase)); + outb(0x01, FCR(iobase)); /* enable FIFOs */ + u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; + if (u == c_uart_16450) { + outb(0x5a, SCR(iobase)); + b1 = inb(SCR(iobase)); + outb(0xa5, SCR(iobase)); + b2 = inb(SCR(iobase)); + if ((b1 != 0x5a) || (b2 != 0xa5)) + u = c_uart_8250; + } + return u; +} + +/* --------------------------------------------------------------------- */ + +static int ser12_open(struct device *dev) +{ + struct baycom_state *bc = (struct baycom_state *)dev->priv; + enum uart u; + + if (!dev || !bc) + return -ENXIO; + if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || + dev->irq < 2 || dev->irq > 15) + return -ENXIO; + if (check_region(dev->base_addr, SER12_EXTENT)) + return -EACCES; + memset(&bc->modem, 0, sizeof(bc->modem)); + bc->hdrv.par.bitrate = 1200; + if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) + return -EIO; + outb(0, FCR(dev->base_addr)); /* disable FIFOs */ + outb(0x0d, MCR(dev->base_addr)); + outb(0x0d, MCR(dev->base_addr)); + outb(0, IER(dev->base_addr)); + if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT, + "baycom_ser12", dev)) + return -EBUSY; + request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12"); + /* + * enable transmitter empty interrupt + */ + outb(2, IER(dev->base_addr)); + /* + * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that + * we get exactly (hopefully) 2 or 3 interrupts per radio symbol, + * depending on the usage of the software DCD routine + */ + ser12_set_divisor(dev, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6); + printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u options " + "0x%x uart %s\n", bc_drvname, dev->base_addr, dev->irq, + bc->options, uart_str[u]); + MOD_INC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int ser12_close(struct device *dev) +{ + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + if (!dev || !bc) + return -EINVAL; + /* + * disable interrupts + */ + outb(0, IER(dev->base_addr)); + outb(1, MCR(dev->base_addr)); + free_irq(dev->irq, dev); + release_region(dev->base_addr, SER12_EXTENT); + printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n", + bc_drvname, dev->base_addr, dev->irq); + MOD_DEC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== hdlcdrv driver interface ========================= + */ + +/* --------------------------------------------------------------------- */ + +static int baycom_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd); + +/* --------------------------------------------------------------------- */ + +static struct hdlcdrv_ops ser12_ops = { + bc_drvname, + bc_drvinfo, + ser12_open, + ser12_close, + baycom_ioctl +}; + +/* --------------------------------------------------------------------- */ + +static int baycom_setmode(struct baycom_state *bc, const char *modestr) +{ + bc->options = !!strchr(modestr, '*'); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int baycom_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct baycom_state *bc; + struct baycom_ioctl bi; + int cmd2; + + if (!dev || !dev->priv || + ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "bc_ioctl: invalid device struct\n"); + return -EINVAL; + } + bc = (struct baycom_state *)dev->priv; + + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + if (get_user(cmd2, (int *)ifr->ifr_data)) + return -EFAULT; + switch (hi->cmd) { + default: + break; + + case HDLCDRVCTL_GETMODE: + strcpy(hi->data.modename, "ser12"); + if (bc->options & 1) + strcat(hi->data.modename, "*"); + if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) + return -EFAULT; + return 0; + + case HDLCDRVCTL_SETMODE: + if (!suser() || dev->start) + return -EACCES; + hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; + return baycom_setmode(bc, hi->data.modename); + + case HDLCDRVCTL_MODELIST: + strcpy(hi->data.modename, "ser12"); + if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) + return -EFAULT; + return 0; + + case HDLCDRVCTL_MODEMPARMASK: + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ; + + } + + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + switch (bi.cmd) { + default: + return -ENOIOCTLCMD; + +#ifdef BAYCOM_DEBUG + case BAYCOMCTL_GETDEBUG: + bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; + bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; + bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; + break; +#endif /* BAYCOM_DEBUG */ + + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + +} + +/* --------------------------------------------------------------------- */ + +__initfunc(int baycom_ser_hdx_init(void)) +{ + int i, j, found = 0; + char set_hw = 1; + struct baycom_state *bc; + char ifname[HDLCDRV_IFNAMELEN]; + + + printk(bc_drvinfo); + /* + * register net devices + */ + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = baycom_device+i; + sprintf(ifname, "bcsh%d", i); + + if (!baycom_ports[i].mode) + set_hw = 0; + if (!set_hw) + baycom_ports[i].iobase = baycom_ports[i].irq = 0; + j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops, + sizeof(struct baycom_state), + ifname, baycom_ports[i].iobase, + baycom_ports[i].irq, 0); + if (!j) { + bc = (struct baycom_state *)dev->priv; + if (set_hw && baycom_setmode(bc, baycom_ports[i].mode)) + set_hw = 0; + found++; + } else { + printk(KERN_WARNING "%s: cannot register net device\n", + bc_drvname); + } + } + if (!found) + return -ENXIO; + return 0; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +/* + * command line settable parameters + */ +static char *mode[NR_PORTS] = { "ser12*", }; +static int iobase[NR_PORTS] = { 0x3f8, }; +static int irq[NR_PORTS] = { 4, }; + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); +MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); +MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(iobase, "baycom io base address"); +MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(irq, "baycom irq number"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver"); + +#endif + +__initfunc(int init_module(void)) +{ + int i; + + for (i = 0; (i < NR_PORTS) && (mode[i]); i++) { + baycom_ports[i].mode = mode[i]; + baycom_ports[i].iobase = iobase[i]; + baycom_ports[i].irq = irq[i]; + } + if (i < NR_PORTS-1) + baycom_ports[i+1].mode = NULL; + return baycom_ser_hdx_init(); +} + +/* --------------------------------------------------------------------- */ + +void cleanup_module(void) +{ + int i; + + for(i = 0; i < NR_PORTS; i++) { + struct device *dev = baycom_device+i; + struct baycom_state *bc = (struct baycom_state *)dev->priv; + + if (bc) { + if (bc->hdrv.magic != HDLCDRV_MAGIC) + printk(KERN_ERR "baycom: invalid magic in " + "cleanup_module\n"); + else + hdlcdrv_unregister_hdlcdrv(dev); + } + } +} + +#else /* MODULE */ +/* --------------------------------------------------------------------- */ +/* + * format: baycom_ser_=io,irq,mode + * mode: [*] + * * indicates sofware DCD + */ + +__initfunc(void baycom_ser_hdx_setup(char *str, int *ints)) +{ + int i; + + for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++); + if ((i >= NR_PORTS) || (ints[0] < 2)) { + printk(KERN_INFO "%s: too many or invalid interface " + "specifications\n", bc_drvname); + return; + } + baycom_ports[i].mode = str; + baycom_ports[i].iobase = ints[1]; + baycom_ports[i].irq = ints[2]; + if (i < NR_PORTS-1) + baycom_ports[i+1].mode = NULL; +} + +#endif /* MODULE */ +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.67/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.1.67/linux/drivers/net/de600.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/de600.c Sun Nov 30 12:21:45 1997 @@ -39,8 +39,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **************************************************************/ -/* Add another "; SLOW_DOWN_IO" here if your adapter won't work OK: */ -#define DE600_SLOW_DOWN SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO +/* Add more time here if your adapter won't work OK: */ +#define DE600_SLOW_DOWN udelay(delay_time) /* * If you still have trouble reading/writing to the adapter, @@ -104,6 +104,7 @@ #include #include #include +#include #include #include @@ -112,6 +113,9 @@ static unsigned int de600_debug = DE600_DEBUG; MODULE_PARM(de600_debug, "i"); + +static unsigned int delay_time = 10; +MODULE_PARM(delay_time, "i"); #ifdef FAKE_SMALL_MAX static unsigned long de600_rspace(struct sock *sk); diff -u --recursive --new-file v2.1.67/linux/drivers/net/e2100.c linux/drivers/net/e2100.c --- v2.1.67/linux/drivers/net/e2100.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/e2100.c Sun Nov 30 12:21:45 1997 @@ -150,7 +150,7 @@ /* Verify by making certain that there is a 8390 at there. */ outb(E8390_NODMA + E8390_STOP, ioaddr); - SLOW_DOWN_IO; + udelay(1); /* we want to delay one I/O cycle - which is 2MHz */ status = inb(ioaddr); if (status != 0x21 && status != 0x23) return ENODEV; diff -u --recursive --new-file v2.1.67/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.1.67/linux/drivers/net/eepro.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/eepro.c Sun Nov 30 12:21:45 1997 @@ -102,6 +102,7 @@ #include #include #include +#include #include #include @@ -652,8 +653,8 @@ outb(SEL_RESET_CMD, ioaddr); /* We are supposed to wait for 2 us after a SEL_RESET */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; + + udelay(2); lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; /* or = RCV_RAM */ lp->tx_last = 0; @@ -695,8 +696,7 @@ /* Try to restart the adaptor. */ outb(SEL_RESET_CMD, ioaddr); /* We are supposed to wait for 2 us after a SEL_RESET */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; + udelay(2); /* Do I also need to flush the transmit buffers here? YES? */ lp->tx_start = lp->tx_end = rcv_ram; @@ -824,9 +824,9 @@ /* Update the statistics here. What statistics? */ /* We are supposed to wait for 200 us after a RESET */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; /* May not be enough? */ + udelay(200); + MOD_DEC_USE_COUNT; return 0; } @@ -933,8 +933,7 @@ /* Acknowledge that the MC setup is done */ do { /* We should be doing this in the eepro_interrupt()! */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; + udelay(2); if (inb(ioaddr + STATUS_REG) & 0x08) { i = inb(ioaddr); @@ -962,7 +961,7 @@ /* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */ /* The delay between EEPROM clock transitions. */ -#define eeprom_delay() { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} +#define eeprom_delay() { udelay(40); } #define EE_READ_CMD (6 << 6) int diff -u --recursive --new-file v2.1.67/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.1.67/linux/drivers/net/eepro100.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/eepro100.c Sun Nov 30 12:21:45 1997 @@ -61,6 +61,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include diff -u --recursive --new-file v2.1.67/linux/drivers/net/eexpress.h linux/drivers/net/eexpress.h --- v2.1.67/linux/drivers/net/eexpress.h Sat Sep 28 12:06:12 1996 +++ linux/drivers/net/eexpress.h Sun Nov 30 12:21:45 1997 @@ -37,7 +37,7 @@ #define ASIC_RST 0x40 #define i586_RST 0x80 -#define eeprom_delay() { int _i = 40; while (--_i>0) { __SLOW_DOWN_IO; }} +#define eeprom_delay() { udelay(40); } /* * i82586 Memory Configuration diff -u --recursive --new-file v2.1.67/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c --- v2.1.67/linux/drivers/net/hdlcdrv.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/hdlcdrv.c Sun Nov 30 10:30:19 1997 @@ -143,9 +143,9 @@ * io regions, irqs and dma channels */ -static char ax25_bcast[7] = +static char ax25_bcast[AX25_ADDR_LEN] = {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static char ax25_test[7] = +static char ax25_nocall[AX25_ADDR_LEN] = {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; /* --------------------------------------------------------------------- */ @@ -890,11 +890,11 @@ dev->set_mac_address = hdlcdrv_set_mac_address; dev->type = ARPHRD_AX25; /* AF_AX25 device */ - dev->hard_header_len = 73; /* We do digipeaters now */ - dev->mtu = 1500; /* eth_mtu is the default */ - dev->addr_len = 7; /* sizeof an ax.25 address */ - memcpy(dev->broadcast, ax25_bcast, 7); - memcpy(dev->dev_addr, ax25_test, 7); + dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; + dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ + dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); /* New style flags */ dev->flags = 0; diff -u --recursive --new-file v2.1.67/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c --- v2.1.67/linux/drivers/net/hp-plus.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/hp-plus.c Sun Nov 30 12:21:45 1997 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -266,7 +267,7 @@ /* Reset the 8390 and HP chip. */ option_reg = inw(ioaddr + HPP_OPTION); outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION); - SLOW_DOWN_IO; SLOW_DOWN_IO; + udelay(5); /* Unreset the board and enable interrupts. */ outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION); @@ -307,12 +308,11 @@ outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION); /* Pause a few cycles for the hardware reset to take place. */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; + udelay(5); ei_status.txing = 0; outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION); - SLOW_DOWN_IO; SLOW_DOWN_IO; + udelay(5); if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0) diff -u --recursive --new-file v2.1.67/linux/drivers/net/hp.c linux/drivers/net/hp.c --- v2.1.67/linux/drivers/net/hp.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/hp.c Sun Nov 30 12:21:45 1997 @@ -233,11 +233,10 @@ outb_p(0x00, hp_base + HP_CONFIGURE); ei_status.txing = 0; /* Pause just a few cycles for the hardware reset to take place. */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; + udelay(5); outb_p(saved_config, hp_base + HP_CONFIGURE); - SLOW_DOWN_IO; SLOW_DOWN_IO; + udelay(5); if ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0) printk("%s: hp_reset_8390() did not complete.\n", dev->name); diff -u --recursive --new-file v2.1.67/linux/drivers/net/scc.c linux/drivers/net/scc.c --- v2.1.67/linux/drivers/net/scc.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/scc.c Sat Nov 29 16:29:37 1997 @@ -1,4 +1,4 @@ -#define RCS_ID "$Id: scc.c,v 1.69 1997/04/06 19:22:45 jreuter Exp jreuter $" +#define RCS_ID "$Id: scc.c,v 1.71 1997/11/29 19:59:20 jreuter Exp jreuter $" #define VERSION "3.0" #define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n" @@ -89,6 +89,7 @@ 970108 - Fixed the remaining problems. 970402 - Hopefully fixed the problems with the new *_timer() routines, added calibration code. + 971012 - made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO Thanks to all who contributed to this driver with ideas and bug reports! @@ -113,14 +114,14 @@ vy 73, Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU - Internet: jreuter@lykos.oche.de + Internet: jreuter@poboxes.com + www : http://www.rat.de/jr */ /* ----------------------------------------------------------------------- */ -#undef SCC_DELAY /* perhaps your ISA bus is a *bit* too fast? */ -#undef SCC_LDELAY 1 /* slow it even a bit more down */ -#undef DONT_CHECK /* don't look if the SCCs you specified are available */ +#undef SCC_LDELAY 1 /* slow it even a bit more down */ +#undef DONT_CHECK /* don't look if the SCCs you specified are available */ #define MAXSCC 4 /* number of max. supported chips */ #define BUFSIZE 384 /* must not exceed 4096 */ @@ -224,7 +225,7 @@ static int Nchips = 0; static io_port Vector_Latch = 0; -MODULE_AUTHOR("Joerg Reuter "); +MODULE_AUTHOR("Joerg Reuter "); MODULE_DESCRIPTION("Network Device Driver for Z8530 based HDLC cards for Amateur Packet Radio"); MODULE_SUPPORTED_DEVICE("scc"); @@ -936,8 +937,10 @@ { /* force simplex operation */ if (tx) { +#ifdef CONFIG_SCC_TRXECHO cl(scc, R3, RxENABLE|ENT_HM); /* switch off receiver */ cl(scc, R15, DCDIE); /* No DCD changes, please */ +#endif set_brg(scc, time_const); /* reprogram baudrate generator */ /* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */ @@ -951,29 +954,34 @@ /* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */ wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP); - +#ifdef CONFIG_SCC_TRXECHO or(scc,R3,RxENABLE|ENT_HM); or(scc,R15, DCDIE); +#endif } } else { if (tx) { +#ifdef CONFIG_SCC_TRXECHO if (scc->kiss.fulldup == KISS_DUPLEX_HALF) { cl(scc, R3, RxENABLE); cl(scc, R15, DCDIE); } +#endif or(scc,R5,RTS|TxENAB); /* enable tx */ } else { cl(scc,R5,RTS|TxENAB); /* disable tx */ - + +#ifdef CONFIG_SCC_TRXECHO if (scc->kiss.fulldup == KISS_DUPLEX_HALF) { or(scc, R3, RxENABLE|ENT_HM); or(scc, R15, DCDIE); } +#endif } } @@ -2198,7 +2206,7 @@ result = scc_init(); if (result == 0) - printk(KERN_INFO "Copyright 1993,1997 Joerg Reuter DL1BKE (jreuter@lykos.tng.oche.de)\n"); + printk(KERN_INFO "Copyright 1993,1997 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n"); return result; } diff -u --recursive --new-file v2.1.67/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.1.67/linux/drivers/net/tlan.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/tlan.c Sun Nov 30 12:21:45 1997 @@ -244,12 +244,11 @@ priv->nextDevice = TLanDevices; TLanDevices = dev; TLanDevicesInstalled++; - printk("TLAN: %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLan -DeviceList[dl_ix].deviceName ); + printk("TLAN: %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLanDeviceList[dl_ix].deviceName ); } } - // printk( "TLAN: Found %d device(s).\n", TLanDevicesInstalled ); + /* printk( "TLAN: Found %d device(s).\n", TLanDevicesInstalled ); */ return ( ( TLanDevicesInstalled >= 0 ) ? 0 : -ENODEV ); @@ -399,8 +398,7 @@ * **************************************************************/ -int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_ -io_base, u32 *dl_ix ) +int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ) { static int dl_index = 0; static int pci_index = 0; @@ -438,10 +436,8 @@ pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_REVISION_ID, pci_rev); pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_INTERRUPT_LINE, pci_irq); pcibios_read_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, &pci_command); - pcibios_read_config_dword( *pci_bus, *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_ba -se); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, &pci_laten -cy); + pcibios_read_config_dword( *pci_bus, *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base); + pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 0x10) { pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff); @@ -452,8 +448,7 @@ pcibios_read_config_dword( *pci_bus, *pci_dfn, reg, pci_io_base); if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pc -i_io_base); + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pci_io_base); break; } else { *pci_io_base = 0; @@ -592,11 +587,9 @@ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); - err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev - ); + err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev); if ( err ) { - printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name -, dev->irq ); + printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name , dev->irq ); return -EAGAIN; } @@ -631,8 +624,7 @@ outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); } - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s opened. Revision = %x\n", dev->na -me, priv->tlanRev ); + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s opened. Revision = %x\n", dev->name, priv->tlanRev ); return 0; @@ -677,8 +669,7 @@ tail_list = priv->txList + priv->txTail; if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev -->name, priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); dev->tbusy = 1; priv->txBusyCount++; return 1; @@ -698,22 +689,19 @@ tail_list->buffer[1].count = 0; tail_list->buffer[1].address = 0; } - // are we transferring? + /* are we transferring? */ cli(); tail_list->cStat = TLAN_CSTAT_READY; if ( ! priv->txInProgress ) { priv->txInProgress = 1; outw( 0x4, dev->base_addr + TLAN_HOST_INT ); - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Starting TX on buffer %d\n", priv->t -xTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD ); } else { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Adding buffer %d to TX channel\n", p -riv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); if ( priv->txTail == 0 ) - ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_lis -t ); + ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list ); else ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list ); } @@ -764,14 +752,13 @@ dev = (struct device *) dev_id; if ( dev->interrupt ) - printk( "TLAN: Re-entering interrupt handler for %s: %d.\n" , dev->name, dev -->interrupt ); + printk( "TLAN: Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt ); dev->interrupt++; cli(); host_int = inw( dev->base_addr + TLAN_HOST_INT ); - outw( host_int, dev->base_addr + TLAN_HOST_INT ); // Deactivate Ints + outw( host_int, dev->base_addr + TLAN_HOST_INT ); /* Deactivate Ints */ type = ( host_int & TLAN_HI_IT_MASK ) >> 2; @@ -852,10 +839,8 @@ /* Should only read stats if open ? */ TLan_ReadAndClearStats( dev, TLAN_RECORD ); - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: %s EOC count = %d\n", dev->name, priv- ->rxEocCount ); - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s Busy count = %d\n", dev->name, pri -v->txBusyCount ); + TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); if ( debug & TLAN_DEBUG_GNRL ) { TLan_PrintDio( dev->base_addr ); TLan_PhyPrint( dev ); @@ -971,7 +956,7 @@ u32 TLan_HandleInvalid( struct device *dev, u16 host_int ) { host_int = 0; - // printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); + /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */ return 0; } /* TLan_HandleInvalid */ @@ -1008,8 +993,7 @@ TLanList *head_list; u32 ack = 1; - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", - priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); host_int = 0; head_list = priv->txList + priv->txHead; if ( head_list->cStat & TLAN_CSTAT_EOC ) @@ -1017,7 +1001,7 @@ if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { printk( "TLAN: Received interrupt for uncompleted TX frame.\n" ); } - // printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat ); + /* printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat ); */ #if LINUX_KERNEL_VERSION > 0x20100 priv->stats->tx_bytes += head_list->frameSize; @@ -1029,8 +1013,7 @@ if ( priv->txHead >= TLAN_NUM_TX_LISTS ) priv->txHead = 0; if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n" -, priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); @@ -1042,14 +1025,14 @@ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) { if ( priv->timerSetAt == 0 ) { - // printk("TxEOF Starting timer...\n"); + /* printk("TxEOF Starting timer...\n"); */ priv->timerSetAt = jiffies; priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; priv->timerType = TLAN_TIMER_ACT; add_timer( &priv->timer ); } else if ( priv->timerType == TLAN_TIMER_ACT ) { priv->timerSetAt = jiffies; - // printk("TxEOF continuing timer...\n"); + /* printk("TxEOF continuing timer...\n"); */ } } @@ -1125,8 +1108,7 @@ TLanList *tail_list; void *t; - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", -priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); host_int = 0; head_list = priv->rxList + priv->rxHead; tail_list = priv->rxList + priv->rxTail; @@ -1143,7 +1125,7 @@ skb->dev = dev; skb_reserve( skb, 2 ); t = (void *) skb_put( skb, head_list->frameSize ); - // printk( " %hd %p %p\n", head_list->frameSize, skb->data, t ); + /* printk( " %hd %p %p\n", head_list->frameSize, skb->data, t ); */ #if LINUX_KERNEL_VERSION > 0x20100 priv->stats->rx_bytes += head_list->frameSize; @@ -1165,8 +1147,7 @@ if ( priv->rxTail >= TLAN_NUM_RX_LISTS ) priv->rxTail = 0; if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", - priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; @@ -1175,13 +1156,13 @@ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) { if ( priv->timerSetAt == 0 ) { - // printk("RxEOF Starting timer...\n"); + /* printk("RxEOF Starting timer...\n"); */ priv->timerSetAt = jiffies; priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; priv->timerType = TLAN_TIMER_ACT; add_timer( &priv->timer ); } else if ( priv->timerType == TLAN_TIMER_ACT ) { - // printk("RxEOF tarting continuing timer...\n"); + /* printk("RxEOF tarting continuing timer...\n"); */ priv->timerSetAt = jiffies; } } @@ -1250,8 +1231,7 @@ host_int = 0; if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- - IRQ\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); @@ -1312,7 +1292,7 @@ priv->timerType = TLAN_TIMER_LINK; add_timer( &priv->timer ); } else { - //printk( " RX GO---->\n" ); + /*printk( " RX GO---->\n" ); */ outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); } @@ -1328,8 +1308,7 @@ TLan_PhyPrint( dev ); } } - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Status Check! %s Net_Sts=%x\n", dev->name, -(unsigned) net_sts ); + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts ); } return ack; @@ -1367,8 +1346,7 @@ host_int = 0; if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- -IRQ\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; @@ -1427,8 +1405,7 @@ u16 gen_sts; TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - // printk( "TLAN: %s Entered Timer, type = %d\n", dev->name, priv->timerType ) -; + /* printk( "TLAN: %s Entered Timer, type = %d\n", dev->name, priv->timerType ); */ switch ( priv->timerType ) { case TLAN_TIMER_LINK: @@ -1497,8 +1474,7 @@ for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { list = priv->txList + i; list->cStat = TLAN_CSTAT_UNUSED; - list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_S -IZE ) ); + list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); list->buffer[2].count = 0; list->buffer[2].address = 0; } @@ -1510,8 +1486,7 @@ list->cStat = TLAN_CSTAT_READY; list->frameSize = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; - list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_S -IZE ) ); + list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); list->buffer[1].count = 0; list->buffer[1].address = 0; if ( i < TLAN_NUM_RX_LISTS - 1 ) @@ -1544,8 +1519,7 @@ u32 data0, data1; int i; - printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_bas -e ); + printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_base ); printk( "TLAN: Off. +0 +4\n" ); for ( i = 0; i < 0x4C; i+= 8 ) { data0 = TLan_DioRead32( io_base, i ); @@ -1583,10 +1557,9 @@ printk( "TLAN: Forward = 0x%08x\n", list->forward ); printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); - // for ( i = 0; i < 10; i++ ) { + /* for ( i = 0; i < 10; i++ ) { */ for ( i = 0; i < 2; i++ ) { - printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffe -r[i].count, list->buffer[i].address ); + printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address ); } } /* TLan_PrintList */ @@ -1695,41 +1668,41 @@ u32 data; u8 data8; -// 1. Assert reset bit. +/* 1. Assert reset bit. */ data = inl(dev->base_addr + TLAN_HOST_CMD); data |= TLAN_HC_AD_RST; outl(data, dev->base_addr + TLAN_HOST_CMD); -// 2. Turn off interrupts. ( Probably isn't necessary ) +/* 2. Turn off interrupts. ( Probably isn't necessary ) */ data = inl(dev->base_addr + TLAN_HOST_CMD); data |= TLAN_HC_INT_OFF; outl(data, dev->base_addr + TLAN_HOST_CMD); -// 3. Clear AREGs and HASHs. +/* 3. Clear AREGs and HASHs. */ for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) { TLan_DioWrite32( dev->base_addr, (u16) i, 0 ); } -// 4. Setup NetConfig register. +/* 4. Setup NetConfig register. */ data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data ); -// 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. +/* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */ outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD ); outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD ); -// 6. Unreset the MII by setting NMRST (in NetSio) to 1. +/* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */ outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR ); addr = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; TLan_SetBit( TLAN_NET_SIO_NMRST, addr ); -// 7. Setup the remaining registers. +/* 7. Setup the remaining registers. */ if ( priv->tlanRev >= 0x30 ) { data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC; @@ -1947,17 +1920,18 @@ u16 vendor; u16 device; - priv->phyCheck = &TLan_PhyNop; // Make sure these aren't ever NULL + priv->phyCheck = &TLan_PhyNop; /* Make sure these aren't ever NULL */ priv->phyService = &TLan_PhyNop; vendor = TLanDeviceList[priv->pciEntry].vendorId; device = TLanDeviceList[priv->pciEntry].deviceId; - // This is a bit uglier than I'd like, but the 0xF130 device must - // NOT be assigned a valid PHY as it uses an unmanaged, bit-rate - // PHY. It is simplest just to use another goto, rather than - // nesting the two for loops in the if statement. - + /* + * This is a bit uglier than I'd like, but the 0xF130 device must + * NOT be assigned a valid PHY as it uses an unmanaged, bit-rate + * PHY. It is simplest just to use another goto, rather than + * nesting the two for loops in the if statement. + */ if ( ( vendor == PCI_VENDOR_ID_COMPAQ ) && ( device == PCI_DEVICE_ID_NETFLEX_3P ) ) { entry = 0; @@ -2085,8 +2059,7 @@ TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl ); if ( gen_ctl & MII_GC_PDOWN ) { TLan_MiiSync( io ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ -ISOLATE ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE ); TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK ); udelay(50000); TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK ); @@ -2097,8 +2070,8 @@ while ( value & MII_GC_RESET ) TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); - // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); - // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); + /* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); */ + /* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); */ TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 ); udelay(500000); @@ -2110,9 +2083,9 @@ value &= ~TLAN_TC_AUISEL; TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); - // Read Possible Latched Link Status + /* Read Possible Latched Link Status */ TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); - // Read Real Link Status + /* Read Real Link Status */ TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); if ( ( value & MII_GS_LINK ) || aui ) { priv->phyOnline = 1; @@ -2122,7 +2095,7 @@ TLan_DioWrite8( io, TLAN_LED_REG, 0 ); } - // Enable Interrupts + /* Enable Interrupts */ TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); value |= TLAN_TC_INTEN; TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); @@ -2223,11 +2196,9 @@ TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl ); if ( gen_ctl & MII_GC_PDOWN ) { TLan_MiiSync( io ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ -ISOLATE ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE ); TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK ); - for ( i = 0; i < 500000; i++ ) - SLOW_DOWN_IO; + udelay(500000); TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK ); TLan_MiiSync( io ); } @@ -2236,8 +2207,8 @@ while ( value & MII_GC_RESET ) TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); - // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); - // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); + /* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); */ + /* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); */ TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 ); TLan_MiiReadReg( io, phy, MII_AN_ADV, &value ); value &= ~0x0140; @@ -2245,13 +2216,11 @@ TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 ); TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 ); - for ( i = 0; i < 50000; i++ ) - SLOW_DOWN_IO; - -/* - // Read Possible Latched Link Status + udelay(50000); +#if 0 + /* Read Possible Latched Link Status */ TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); - // Read Real Link Status + /* Read Real Link Status */ TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); if ( value & MII_GS_LINK ) { priv->phyOnline = 1; @@ -2261,15 +2230,15 @@ TLan_DioWrite8( io, TLAN_LED_REG, 0 ); } - // Enable Interrupts + /* Enable Interrupts */ TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); value |= TLAN_TC_INTEN; TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); -*/ +#endif sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO ); sio &= ~TLAN_NET_SIO_MINTEN; TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio ); -// priv->phyOnline = 1; +/* priv->phyOnline = 1; */ return 0; @@ -2592,7 +2561,7 @@ outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; - // Assume clock is low, tx is enabled; + /* Assume clock is low, tx is enabled; */ for ( place = 0x80; place != 0; place >>= 1 ) { if ( place & data ) TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); @@ -2608,8 +2577,7 @@ TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); if ( ( ! err ) && stop ) { - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // STOP, raise data while clock is h -igh + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); } @@ -2654,7 +2622,7 @@ sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; *data = 0; - // Assume clock is low, tx is enabled; + /* Assume clock is low, tx is enabled; */ TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); for ( place = 0x80; place; place >>= 1 ) { TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); @@ -2665,15 +2633,14 @@ TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); if ( ! stop ) { - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // Ack = 0 + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* Ack = 0 */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); } else { - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); // No ack = 1 (?) + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); /* No ack = 1 (?) */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // STOP, raise data while clock is h -igh + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); } diff -u --recursive --new-file v2.1.67/linux/drivers/net/tlan.h linux/drivers/net/tlan.h --- v2.1.67/linux/drivers/net/tlan.h Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/tlan.h Sun Nov 30 12:21:45 1997 @@ -483,26 +483,19 @@ { return ( ( a && ! b ) || ( ! a && b ) ); } -#define XOR8( a, b, c, d, e, f, g, h ) xor( a, xor( b, xor( c, xor( d, xor( e, x -or( f, xor( g, h ) ) ) ) ) ) ) +#define XOR8( a, b, c, d, e, f, g, h ) xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) ) #define DA( a, bit ) ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) ) inline u32 TLan_HashFunc( u8 *a ) { u32 hash; - hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,3 -6), DA(a,42) ); - hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,3 -7), DA(a,43) ) << 1; - hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,3 -8), DA(a,44) ) << 2; - hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,3 -9), DA(a,45) ) << 3; - hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,4 -0), DA(a,46) ) << 4; - hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,4 -1), DA(a,47) ) << 5; + hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) ); + hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1; + hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2; + hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3; + hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4; + hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5; return hash; diff -u --recursive --new-file v2.1.67/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h --- v2.1.67/linux/drivers/scsi/BusLogic.h Sat Nov 29 11:25:10 1997 +++ linux/drivers/scsi/BusLogic.h Sun Nov 30 12:45:23 1997 @@ -1526,15 +1526,11 @@ static inline void BusLogic_Delay(int Seconds) { + int Milliseconds = 1000 * Seconds; unsigned long ProcessorFlags; save_flags(ProcessorFlags); sti(); - while (--Seconds >= 0) { - int i = 1000; - do { - udelay(1000); - } while (--i); - } + while (--Milliseconds >= 0) udelay(1000); restore_flags(ProcessorFlags); } diff -u --recursive --new-file v2.1.67/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.67/linux/drivers/scsi/Config.in Mon Nov 17 18:47:21 1997 +++ linux/drivers/scsi/Config.in Sun Nov 30 11:34:27 1997 @@ -85,7 +85,7 @@ if [ "$CONFIG_MCA" = "y" ]; then dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI if [ "$CONFIG_SCSI_IBMMCA" != "n" ]; then - bool ' reset SCSI-devices while booting' SCSI_IBMMCA_DEV_RESET + bool ' reset SCSI-devices while booting' CONFIG_SCSI_IBMMCA_DEV_RESET fi fi if [ "$CONFIG_PARPORT" != "n" ]; then diff -u --recursive --new-file v2.1.67/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c --- v2.1.67/linux/drivers/scsi/ibmmca.c Mon Oct 20 10:36:52 1997 +++ linux/drivers/scsi/ibmmca.c Sun Nov 30 11:34:27 1997 @@ -199,11 +199,10 @@ 5) Magneto-Optical drives and medium-changers are also recognized, now. Therefore, we have a completely gapfree recognition of all SCSI- device-types, that are known by Linux up to kernel 2.1.31. - 6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within - the configuration, each connected SCSI-device will get a reset command - during boottime. This can be necessary for some special SCSI-devices. - This flag should be included in Config.in. - (See also the new Config.in file.) + 6) The flag CONFIG_SCSI_IBMMCA_DEV_RESET has been inserted. If it is set + within the configuration, each connected SCSI-device will get a reset + command during boottime. This can be necessary for some special + SCSI-devices. (See also the new Config.in file.) Probable next improvement: bad disk handler. - Michael Lang @@ -1164,7 +1163,7 @@ if (device_exists (shpnt, ldn, &ld[ldn].block_length, &ld[ldn].device_type)) { -#ifdef SCSI_IBMMCA_DEV_RESET +#ifdef CONFIG_SCSI_IBMMCA_DEV_RESET int ticks; printk("(resetting)"); ticks = IM_RESET_DELAY*HZ; diff -u --recursive --new-file v2.1.67/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.67/linux/drivers/sound/Makefile Sat Nov 29 11:25:10 1997 +++ linux/drivers/sound/Makefile Sun Nov 30 10:30:18 1997 @@ -109,10 +109,10 @@ endif endif -ifeq ($(CONFIG_ADLIB),y) +ifeq ($(CONFIG_MSS),y) LX_OBJS += ad1848.o else - ifeq ($(CONFIG_ADLIB),m) + ifeq ($(CONFIG_MSS),m) MX_OBJS += ad1848.o endif endif diff -u --recursive --new-file v2.1.67/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.1.67/linux/drivers/sound/dmabuf.c Sat Nov 29 11:25:11 1997 +++ linux/drivers/sound/dmabuf.c Sun Nov 30 10:30:18 1997 @@ -1539,10 +1539,11 @@ { /* This routine is called when driver is being unloaded */ #ifdef RUNTIME_DMA_ALLOC - sound_free_dmap (dev, audio_devs[dev]->dmap_out, - audio_devs[dev]->dmap_out->dma); + if (audio_devs[dev]) + sound_free_dmap (dev, audio_devs[dev]->dmap_out, + audio_devs[dev]->dmap_out->dma); - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev] && audio_devs[dev]->flags & DMA_DUPLEX) sound_free_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); #endif diff -u --recursive --new-file v2.1.67/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.1.67/linux/drivers/sound/pss.c Sat Nov 29 11:25:11 1997 +++ linux/drivers/sound/pss.c Sun Nov 30 10:30:18 1997 @@ -116,17 +116,15 @@ if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ return 0; - if (check_region(devc->base, 16)) - { - printk("PSS: I/O port conflict\n"); - return 0; - } + if (check_region(devc->base, 16)) { + printk(KERN_ERR "PSS: I/O port conflict\n"); + return 0; + } id = inw(REG(PSS_ID)); - if ((id >> 8) != 'E') - { - /* printk( "No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); */ - return 0; - } + if ((id >> 8) != 'E') { + printk(KERN_ERR "No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); + return 0; + } return 1; } @@ -855,14 +853,28 @@ #ifdef MODULE -int io = -1; -int irq = -1; -int dma = -1; +int pss_io = 0x220; -int pssmpu, pssmss; -struct address_info cfg; +int mss_io = 0x530; +int mss_irq = 11; +int mss_dma = 1; + +int mpu_io = 0x330; +int mpu_irq = -1; + +struct address_info cfgpss = { 0 /* pss_io */, 0, -1, -1 }; +struct address_info cfgmpu = { 0 /* mpu_io */, 0 /* mpu_irq */, 0, -1 }; +struct address_info cfgmss = { 0 /* mss_io */, 0 /* mss_irq */, 0 /* mss_dma */, -1 }; + +MODULE_PARM(pss_io, "i"); +MODULE_PARM(mss_io, "i"); +MODULE_PARM(mss_irq, "i"); +MODULE_PARM(mss_dma, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(mpu_irq, "i"); static int fw_load = 0; +static int pssmpu = 0, pssmss = 0; /* * Load a PSS sound card module @@ -871,34 +883,39 @@ int init_module(void) { - if (io == -1 || irq == -1 || dma == -1) - { +#if 0 + if (pss_io == -1 || irq == -1 || dma == -1) { printk("pss: dma, irq and io must be set.\n"); return -EINVAL; - } - cfg.io_base = io; - cfg.irq = irq; + } +#endif + cfgpss.io_base = pss_io; - if (!pss_synth) - { - fw_load = 1; - pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth); - } - if (probe_pss(&cfg)) + cfgmss.io_base = mss_io; + cfgmss.irq = mss_irq; + cfgmss.dma = mss_dma; + + cfgmpu.io_base = mpu_io; + cfgmpu.irq = mpu_irq; + + if (!pss_synth) { + fw_load = 1; + pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth); + } + if (!probe_pss(&cfgpss)) return -ENODEV; + attach_pss(&cfgpss); /* * Attach stuff */ - if (probe_pss_mpu(&cfg)) - { - pssmpu = 1; - attach_pss_mpu(&cfg); - } - if (probe_pss_mss(&cfg)) - { - pssmss = 1; - attach_pss_mss(&cfg); - } + if (probe_pss_mpu(&cfgmpu)) { + pssmpu = 1; + attach_pss_mpu(&cfgmpu); + } + if (probe_pss_mss(&cfgmss)) { + pssmss = 1; + attach_pss_mss(&cfgmss); + } SOUND_LOCK; return 0; } @@ -909,10 +926,10 @@ if (fw_load && pss_synth) kfree(pss_synth); if (pssmss) - unload_pss_mss(&cfg); + unload_pss_mss(&cfgmss); if (pssmpu) - unload_pss_mpu(&cfg); - unload_pss(&cfg); + unload_pss_mpu(&cfgmpu); + unload_pss(&cfgpss); SOUND_LOCK_END; } #endif diff -u --recursive --new-file v2.1.67/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c --- v2.1.67/linux/fs/autofs/waitq.c Sat Oct 25 02:44:17 1997 +++ linux/fs/autofs/waitq.c Sun Nov 30 10:59:02 1997 @@ -42,30 +42,34 @@ static int autofs_write(struct file *file, const void *addr, int bytes) { - unsigned long fs; - unsigned long old_signal; + unsigned long fs, sigpipe, flags; const char *data = (const char *)addr; - int written = 0; + ssize_t wr = 0; /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/ + sigpipe = sigismember(¤t->signal, SIGPIPE); + /* Save pointer to user space and point back to kernel space */ fs = get_fs(); set_fs(KERNEL_DS); - old_signal = current->signal; - - while ( bytes && (written = file->f_op->write(file,data,bytes,&file->f_pos)) > 0 ) { - data += written; - bytes -= written; + while (bytes && + (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) { + data += wr; + bytes -= wr; } - if ( written == -EPIPE && !(old_signal & (1 << (SIGPIPE-1))) ) { - /* Keep the currently executing process from receiving a - SIGPIPE unless it was already supposed to get one */ - current->signal &= ~(1 << (SIGPIPE-1)); - } set_fs(fs); + + /* Keep the currently executing process from receiving a + SIGPIPE unless it was already supposed to get one */ + if (wr == -EPIPE && !sigpipe) { + spin_lock_irqsave(¤t->sigmask_lock, flags); + sigdelset(¤t->signal, SIGPIPE); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + } return (bytes > 0); } diff -u --recursive --new-file v2.1.67/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.67/linux/fs/buffer.c Wed Nov 26 16:24:03 1997 +++ linux/fs/buffer.c Sun Nov 30 10:59:02 1997 @@ -1944,7 +1944,10 @@ /* If there are still a lot of dirty buffers around, skip the sleep and flush some more */ if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) { - current->signal = 0; + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + interruptible_sleep_on(&bdflush_wait); } } diff -u --recursive --new-file v2.1.67/linux/fs/dcache.c linux/fs/dcache.c --- v2.1.67/linux/fs/dcache.c Tue Nov 18 17:22:08 1997 +++ linux/fs/dcache.c Sun Nov 30 10:59:02 1997 @@ -129,7 +129,7 @@ return; } - printk("Negative d_count (%d) for %s/%s\n", + printk(KERN_CRIT "Negative d_count (%d) for %s/%s\n", count, dentry->d_parent->d_name.name, dentry->d_name.name); @@ -378,7 +378,7 @@ if (!list_empty(&dentry->d_subdirs)) { this_parent = dentry; #ifdef DCACHE_DEBUG -printk("select_parent: descending to %s/%s, found=%d\n", +printk(KERN_DEBUG "select_parent: descending to %s/%s, found=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, found); #endif goto repeat; @@ -391,7 +391,7 @@ next = this_parent->d_child.next; this_parent = this_parent->d_parent; #ifdef DCACHE_DEBUG -printk("select_parent: ascending to %s/%s, found=%d\n", +printk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n", this_parent->d_parent->d_name.name, this_parent->d_name.name, found); #endif goto resume; @@ -439,7 +439,7 @@ goal = 50; count = select_dcache(32, goal); #ifdef DCACHE_DEBUG -printk("check_dcache_memory: goal=%d, count=%d\n", goal, count); +printk(KERN_DEBUG "check_dcache_memory: goal=%d, count=%d\n", goal, count); #endif if (count) { prune_dcache(count); @@ -678,7 +678,7 @@ void d_move(struct dentry * dentry, struct dentry * target) { if (!dentry->d_inode) - printk("VFS: moving negative dcache entry\n"); + printk(KERN_WARNING "VFS: moving negative dcache entry\n"); /* Move the dentry to the target hash queue */ list_del(&dentry->d_hash); diff -u --recursive --new-file v2.1.67/linux/fs/exec.c linux/fs/exec.c --- v2.1.67/linux/fs/exec.c Sat Oct 25 02:44:17 1997 +++ linux/fs/exec.c Sun Nov 30 10:59:02 1997 @@ -459,18 +459,10 @@ * so that a new one can be started */ -static inline void flush_old_signals(struct signal_struct *sig) +static inline void flush_old_signals(struct task_struct *t) { - int i; - struct sigaction * sa = sig->action; - - for (i=32 ; i != 0 ; i--) { - sa->sa_mask = 0; - sa->sa_flags = 0; - if (sa->sa_handler != SIG_IGN) - sa->sa_handler = NULL; - sa++; - } + flush_signals(t); + flush_signal_handlers(t); } static inline void flush_old_files(struct files_struct * files) @@ -531,7 +523,7 @@ permission(bprm->dentry->d_inode,MAY_READ)) current->dumpable = 0; - flush_old_signals(current->sig); + flush_old_signals(current); flush_old_files(current->files); return 0; diff -u --recursive --new-file v2.1.67/linux/fs/fcntl.c linux/fs/fcntl.c --- v2.1.67/linux/fs/fcntl.c Wed Sep 24 20:05:48 1997 +++ linux/fs/fcntl.c Sun Nov 30 10:59:02 1997 @@ -178,7 +178,7 @@ (euid ^ p->suid) && (euid ^ p->uid) && (uid ^ p->suid) && (uid ^ p->uid)) continue; - p->signal |= 1 << (SIGIO-1); + send_sig(SIGIO, p, 1); if (p->state == TASK_INTERRUPTIBLE && signal_pending(p)) wake_up_process(p); } diff -u --recursive --new-file v2.1.67/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c --- v2.1.67/linux/fs/lockd/clntproc.c Wed Oct 15 16:04:23 1997 +++ linux/fs/lockd/clntproc.c Sun Nov 30 10:59:02 1997 @@ -90,7 +90,8 @@ struct nfs_server *nfssrv = NFS_SERVER(inode); struct nlm_host *host; struct nlm_rqst reqst, *call = &reqst; - unsigned long oldmask; + sigset_t oldset; + unsigned long flags; int status; /* Always use NLM version 1 over UDP for now... */ @@ -114,16 +115,21 @@ } /* Keep the old signal mask */ - oldmask = current->blocked; + spin_lock_irqsave(¤t->sigmask_lock, flags); + oldset = current->blocked; /* If we're cleaning up locks because the process is exiting, * perform the RPC call asynchronously. */ if (cmd == F_SETLK && fl->fl_type == F_UNLCK - && (current->flags & PF_EXITING)) { - current->blocked = ~0UL; /* Mask all signals */ + && (current->flags & PF_EXITING)) { + sigfillset(¤t->blocked); /* Mask all signals */ + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + call = nlmclnt_alloc_call(); call->a_flags = RPC_TASK_ASYNC; } else { + spin_unlock_irqrestore(¤t->sigmask_lock, flags); call->a_flags = 0; } call->a_host = host; @@ -145,7 +151,10 @@ if (status < 0 && (call->a_flags & RPC_TASK_ASYNC)) rpc_free(call); - current->blocked = oldmask; + spin_lock_irqsave(¤t->sigmask_lock, flags); + current->blocked = oldset; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); done: dprintk("lockd: clnt proc returns %d\n", status); @@ -454,11 +463,16 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) { struct nlm_rqst *req; - unsigned long oldmask = current->blocked; + unsigned long flags; + sigset_t oldset; int status; /* Block all signals while setting up call */ - current->blocked = ~0UL; + spin_lock_irqsave(¤t->sigmask_lock, flags); + oldset = current->blocked; + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); do { req = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC, @@ -474,7 +488,11 @@ if (status < 0) rpc_free(req); - current->blocked = oldmask; + spin_lock_irqsave(¤t->sigmask_lock, flags); + current->blocked = oldset; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + return status; } diff -u --recursive --new-file v2.1.67/linux/fs/lockd/svc.c linux/fs/lockd/svc.c --- v2.1.67/linux/fs/lockd/svc.c Wed Oct 15 16:04:23 1997 +++ linux/fs/lockd/svc.c Sun Nov 30 10:59:02 1997 @@ -37,8 +37,7 @@ #define NLMDBG_FACILITY NLMDBG_SVC #define LOCKD_BUFSIZE (1024 + NLMSSVC_XDRSIZE) -#define BLOCKABLE_SIGS (~(_S(SIGKILL) | _S(SIGSTOP))) -#define _S(sig) (1 << ((sig) - 1)) +#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) extern struct svc_program nlmsvc_program; struct nlmsvc_binding * nlmsvc_ops = NULL; @@ -65,7 +64,6 @@ lockd(struct svc_rqst *rqstp) { struct svc_serv *serv = rqstp->rq_server; - sigset_t oldsigmask; int err = 0; /* Lock module and set up kernel thread */ @@ -118,8 +116,11 @@ */ while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { - if (signalled()) - current->signal = 0; + if (signalled()) { + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + } /* * Retry any blocked locks that have been notified by @@ -162,10 +163,17 @@ } /* Process request with all signals blocked. */ - oldsigmask = current->blocked; - current->blocked = BLOCKABLE_SIGS; + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, ~BLOCKABLE_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + svc_process(serv, rqstp); - current->blocked = oldsigmask; + + spin_lock_irq(¤t->sigmask_lock); + sigemptyset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); /* Unlock export hash tables */ if (nlmsvc_ops) diff -u --recursive --new-file v2.1.67/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c --- v2.1.67/linux/fs/ncpfs/sock.c Mon Nov 17 18:47:22 1997 +++ linux/fs/ncpfs/sock.c Sun Nov 30 10:59:02 1997 @@ -75,8 +75,6 @@ #define NCP_SLACK_SPACE 1024 -#define _S(nr) (1<<((nr)-1)) - static int do_ncp_rpc_call(struct ncp_server *server, int size) { struct file *file; @@ -93,7 +91,8 @@ int major_timeout_seen; int acknowledge_seen; int n; - unsigned long old_mask; + sigset_t old_set; + unsigned long mask, flags; /* We have to check the result, so store the complete header */ struct ncp_request_header request = @@ -115,17 +114,25 @@ retrans = server->m.retry_count; major_timeout_seen = 0; acknowledge_seen = 0; - old_mask = current->blocked; - current->blocked |= ~(_S(SIGKILL) -#if 0 - | _S(SIGSTOP) -#endif - | ((server->m.flags & NCP_MOUNT_INTR) - ? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL - ? _S(SIGINT) : 0) - | (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL - ? _S(SIGQUIT) : 0)) - : 0)); + + spin_lock_irqsave(¤t->sigmask_lock, flags); + old_set = current->blocked; + mask = sigmask(SIGKILL) | sigmask(SIGSTOP); + if (server->m.flags & NCP_MOUNT_INTR) { + /* FIXME: This doesn't seem right at all. So, like, + we can't handle SIGINT and get whatever to stop? + What if we've blocked it ourselves? What about + alarms? Why, in fact, are we mucking with the + sigmask at all? -- r~ */ + if (current->sig->action[SIGINT - 1].sa_handler == SIG_DFL) + mask |= sigmask(SIGINT); + if (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL) + mask |= sigmask(SIGQUIT); + } + siginitmaskinv(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + fs = get_fs(); set_fs(get_ds()); for (n = 0, timeout = init_timeout;; n++, timeout <<= 1) { @@ -269,7 +276,12 @@ printk(KERN_ERR "NCP: result=%d\n", result); result = -EIO; } + + spin_lock_irqsave(¤t->sigmask_lock, flags); current->blocked = old_mask; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + set_fs(fs); return result; } diff -u --recursive --new-file v2.1.67/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.1.67/linux/fs/nfsd/nfssvc.c Wed Apr 23 19:01:27 1997 +++ linux/fs/nfsd/nfssvc.c Sun Nov 30 12:50:53 1997 @@ -35,9 +35,9 @@ #define NFSDDBG_FACILITY NFSDDBG_SVC #define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE) -#define BLOCKABLE_SIGS (~(_S(SIGKILL) | _S(SIGSTOP))) -#define SHUTDOWN_SIGS (_S(SIGKILL)|_S(SIGINT)|_S(SIGTERM)) -#define _S(sig) (1 << ((sig) - 1)) + +#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) extern struct svc_program nfsd_program; static void nfsd(struct svc_rqst *rqstp); @@ -96,7 +96,6 @@ nfsd(struct svc_rqst *rqstp) { struct svc_serv *serv = rqstp->rq_server; - sigset_t oldsigmask; int oldumask, err; lock_kernel(); @@ -108,7 +107,7 @@ sprintf(current->comm, "nfsd"); oldumask = current->fs->umask; /* Set umask to 0. */ - current->blocked |= ~SHUTDOWN_SIGS; + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); current->fs->umask = 0; nfssvc_boot = xtime; /* record boot time */ lockd_up(); /* start lockd */ @@ -142,10 +141,17 @@ serv->sv_stats->rpcbadclnt++; } else { /* Process request with all signals blocked. */ - oldsigmask = current->blocked; - current->blocked = BLOCKABLE_SIGS; + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, ~BLOCKABLE_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + svc_process(serv, rqstp); - current->blocked = oldsigmask; + + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); } /* Unlock export hash tables */ @@ -157,8 +163,9 @@ } else { unsigned int signo; - for (signo = 0; signo < 32; signo++) - if (current->signal & current->blocked & (1<signal, signo) && + !sigismember(¤t->signal, signo)) break; printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo); } diff -u --recursive --new-file v2.1.67/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.1.67/linux/fs/proc/array.c Sat Oct 25 02:44:18 1997 +++ linux/fs/proc/array.c Sun Nov 30 10:59:02 1997 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -643,37 +644,58 @@ return buffer; } -static inline char * task_sig(struct task_struct *p, char *buffer) +char * render_sigset_t(sigset_t *set, char *buffer) { - buffer += sprintf(buffer, - "SigPnd:\t%08lx\n" - "SigBlk:\t%08lx\n", - p->signal, p->blocked); + int i = _NSIG, x; + do { + i -= 4, x = 0; + if (sigismember(set, i+1)) x |= 1; + if (sigismember(set, i+2)) x |= 2; + if (sigismember(set, i+3)) x |= 4; + if (sigismember(set, i+4)) x |= 8; + *buffer++ = (x < 10 ? '0' : 'a' - 10) + x; + } while (i >= 4); + *buffer = 0; + return buffer; +} + +static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, + sigset_t *catch) +{ + struct k_sigaction *k; + int i; + + sigemptyset(ign); + sigemptyset(catch); + if (p->sig) { - struct sigaction * action = p->sig->action; - unsigned long sig_ign = 0, sig_caught = 0; - unsigned long bit = 1; - int i; - - for (i = 0; i < 32; i++) { - switch((unsigned long) action->sa_handler) { - case 0: - break; - case 1: - sig_ign |= bit; - break; - default: - sig_caught |= bit; - } - bit <<= 1; - action++; + k = p->sig->action; + for (i = 1; i <= _NSIG; ++i, ++k) { + if (k->sa.sa_handler == SIG_IGN) + sigaddset(ign, i); + else if (k->sa.sa_handler != SIG_DFL) + sigaddset(catch, i); } - - buffer += sprintf(buffer, - "SigIgn:\t%08lx\n" - "SigCgt:\t%08lx\n", - sig_ign, sig_caught); } +} + +static inline char * task_sig(struct task_struct *p, char *buffer) +{ + sigset_t ign, catch; + + buffer += sprintf(buffer, "SigPnd:\t"); + buffer = render_sigset_t(&p->signal, buffer); + buffer += sprintf(buffer, "SigBlk:\t"); + buffer = render_sigset_t(&p->blocked, buffer); + *buffer++ = '\n'; + + collect_sigign_sigcatch(p, &ign, &catch); + buffer += sprintf(buffer, "SigIgn:\t"); + buffer = render_sigset_t(&ign, buffer); + buffer += sprintf(buffer, "SigCat:\t"); + buffer = render_sigset_t(&catch, buffer); + *buffer++ = '\n'; + return buffer; } @@ -694,10 +716,14 @@ static int get_stat(int pid, char * buffer) { struct task_struct *tsk = find_task_by_pid(pid); - unsigned long sigignore=0, sigcatch=0, wchan; - unsigned long vsize, eip, esp; + unsigned long vsize, eip, esp, wchan; long priority, nice; - int i,tty_pgrp; + int tty_pgrp; + sigset_t sigign, sigcatch; + char signal_str[sizeof(sigset_t)*2+1]; + char blocked_str[sizeof(sigset_t)*2+1]; + char sigign_str[sizeof(sigset_t)*2+1]; + char sigcatch_str[sizeof(sigset_t)*2+1]; char state; if (!tsk) @@ -716,22 +742,15 @@ eip = KSTK_EIP(tsk); esp = KSTK_ESP(tsk); } + wchan = get_wchan(tsk); - if (tsk->sig) { - unsigned long bit = 1; - for(i=0; i<32; ++i) { - switch((unsigned long) tsk->sig->action[i].sa_handler) { - case 0: - break; - case 1: - sigignore |= bit; - break; - default: - sigcatch |= bit; - } - bit <<= 1; - } - } + + collect_sigign_sigcatch(tsk, &sigign, &sigcatch); + render_sigset_t(&tsk->signal, signal_str); + render_sigset_t(&tsk->blocked, blocked_str); + render_sigset_t(&sigign, sigign_str); + render_sigset_t(&sigcatch, sigcatch_str); + if (tsk->tty) tty_pgrp = tsk->tty->pgrp; else @@ -746,7 +765,7 @@ return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ -%lu %lu %lu %lu %lu %lu %lu %lu\n", +%lu %s %s %s %s %lu %lu %lu\n", pid, tsk->comm, state, @@ -777,10 +796,10 @@ tsk->mm ? tsk->mm->start_stack : 0, esp, eip, - tsk->signal, - tsk->blocked, - sigignore, - sigcatch, + signal_str, + blocked_str, + sigign_str, + sigcatch_str, wchan, tsk->nswap, tsk->cnswap); diff -u --recursive --new-file v2.1.67/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c --- v2.1.67/linux/fs/smbfs/sock.c Wed Nov 26 16:24:03 1997 +++ linux/fs/smbfs/sock.c Sun Nov 30 10:59:03 1997 @@ -26,8 +26,6 @@ #define SMBFS_PARANOIA 1 /* #define SMBFS_DEBUG_VERBOSE 1 */ -#define _S(nr) (1<<((nr)-1)) - static int _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags) @@ -599,8 +597,8 @@ int smb_request(struct smb_sb_info *server) { - unsigned long old_mask; - unsigned long fs; + unsigned long fs, flags, sigpipe; + sigset_t old_set; int len, result; unsigned char *buffer; @@ -619,8 +617,13 @@ len = smb_len(buffer) + 4; pr_debug("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]); - old_mask = current->blocked; - current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); + spin_lock_irqsave(¤t->sigmask_lock, flags); + sigpipe = sigismember(¤t->signal, SIGPIPE); + old_set = current->blocked; + siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + fs = get_fs(); set_fs(get_ds()); @@ -629,9 +632,15 @@ { result = smb_receive(server); } + /* read/write errors are handled by errno */ - current->signal &= ~_S(SIGPIPE); - current->blocked = old_mask; + spin_lock_irqsave(¤t->sigmask_lock, flags); + if (result == -EPIPE && !sigpipe) + sigdelset(¤t->signal, SIGPIPE); + current->blocked = old_set; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + set_fs(fs); if (result >= 0) @@ -758,8 +767,8 @@ int *lrdata, unsigned char **rdata, int *lrparam, unsigned char **rparam) { - unsigned long old_mask; - unsigned long fs; + sigset_t old_set; + unsigned long fs, flags, sigpipe; int result; pr_debug("smb_trans2_request: com=%d, ld=%d, lp=%d\n", @@ -778,8 +787,13 @@ if ((result = smb_dont_catch_keepalive(server)) != 0) goto bad_conn; - old_mask = current->blocked; - current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); + spin_lock_irqsave(¤t->sigmask_lock, flags); + sigpipe = sigismember(¤t->signal, SIGPIPE); + old_set = current->blocked; + siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + fs = get_fs(); set_fs(get_ds()); @@ -790,9 +804,15 @@ result = smb_receive_trans2(server, lrdata, rdata, lrparam, rparam); } + /* read/write errors are handled by errno */ - current->signal &= ~_S(SIGPIPE); - current->blocked = old_mask; + spin_lock_irqsave(¤t->sigmask_lock, flags); + if (result == -EPIPE && !sigpipe) + sigdelset(¤t->signal, SIGPIPE); + current->blocked = old_set; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + set_fs(fs); if (result >= 0) diff -u --recursive --new-file v2.1.67/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h --- v2.1.67/linux/include/asm-alpha/processor.h Mon Jun 16 16:35:59 1997 +++ linux/include/asm-alpha/processor.h Sun Nov 30 10:59:03 1997 @@ -44,6 +44,7 @@ /* bit 1..5: IEEE_TRAP_ENABLE bits (see fpu.h) */ /* bit 6..8: UAC bits (see sysinfo.h) */ /* bit 17..21: IEEE_STATUS_MASK bits (see fpu.h) */ + /* bit 63: die_if_kernel recursion lock */ unsigned long flags; /* perform syscall argument validation (get/set_fs) */ unsigned long fs; diff -u --recursive --new-file v2.1.67/linux/include/asm-alpha/sigcontext.h linux/include/asm-alpha/sigcontext.h --- v2.1.67/linux/include/asm-alpha/sigcontext.h Mon Sep 30 07:43:29 1996 +++ linux/include/asm-alpha/sigcontext.h Sun Nov 30 10:59:03 1997 @@ -3,7 +3,7 @@ struct sigcontext { /* - * what should we have here? I'd probably better use the same + * What should we have here? I'd probably better use the same * stack layout as OSF/1, just in case we ever want to try * running their binaries.. * @@ -28,7 +28,15 @@ unsigned long sc_fp_trap_pc; unsigned long sc_fp_trigger_sum; unsigned long sc_fp_trigger_inst; - unsigned long sc_retcode[2]; +}; + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + old_sigset_t uc_osf_sigmask; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ }; #endif diff -u --recursive --new-file v2.1.67/linux/include/asm-alpha/siginfo.h linux/include/asm-alpha/siginfo.h --- v2.1.67/linux/include/asm-alpha/siginfo.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-alpha/siginfo.h Sun Nov 30 10:59:03 1997 @@ -0,0 +1,195 @@ +#ifndef _ALPHA_SIGINFO_H +#define _ALPHA_SIGINFO_H + +#include + +/* This structure matches OSF/1 for binary compatibility. */ + +typedef union sigval { + int sival_int; + void *sival_ptr; +} sigval_t; + +#define SI_MAX_SIZE 128 +#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 4) + +typedef struct siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[SI_PAD_SIZE]; + + /* kill() */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + unsigned int _timer1; + unsigned int _timer2; + } _timer; + + /* POSIX.1b signals */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + pid_t _pid; /* which child */ + int _status; /* exit code */ + clock_t _utime; + clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + void *_addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} siginfo_t; + +/* + * How these fields are to be accessed. + */ +#define si_pid _sifields._kill._pid +#define si_uid _sifields._kill._uid +#define si_status _sifields._sigchld._status +#define si_utime _sifields._sigchld._utime +#define si_stime _sifields._sigchld._stime +#define si_value _sifields._rt._sigval +#define si_int _sifields._rt._sigval.sival_int +#define si_ptr _sifields._rt._sigval.sival_ptr +#define si_addr _sifields._sigfault._addr +#define si_band _sifields._sigpoll._band +#define si_fd _sifields._sigpoll._fd + +/* + * si_code values + * Digital reserves positive values for kernel-generated signals. + */ +#define SI_USER 0 /* sent by kill, sigsend, raise */ +#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ +#define SI_QUEUE -1 /* sent by sigqueue */ +#define SI_TIMER -2 /* sent by timer expiration */ +#define SI_MESGQ -3 /* sent by real time mesq state change */ +#define SI_ASYNCIO -4 /* sent by AIO completion */ + +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) + +/* + * SIGILL si_codes + */ +#define ILL_ILLOPC 1 /* illegal opcode */ +#define ILL_ILLOPN 2 /* illegal operand */ +#define ILL_ILLADR 3 /* illegal addressing mode */ +#define ILL_ILLTRP 4 /* illegal trap */ +#define ILL_PRVOPC 5 /* privileged opcode */ +#define ILL_PRVREG 6 /* privileged register */ +#define ILL_COPROC 7 /* coprocessor error */ +#define ILL_BADSTK 8 /* internal stack error */ +#define NSIGILL 8 + +/* + * SIGFPE si_codes + */ +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ +#define NSIGFPE 8 + +/* + * SIGSEGV si_codes + */ +#define SEGV_MAPERR 1 /* address not mapped to object */ +#define SRGV_ACCERR 2 /* invalid permissions for mapped object */ +#define NSIGSEGV 2 + +/* + * SIGBUS si_codes + */ +#define BUS_ADRALN 1 /* invalid address alignment */ +#define BUS_ADRERR 2 /* non-existant physical address */ +#define BUS_OBJERR 3 /* object specific hardware error */ +#define NSIGBUS 3 + +/* + * SIGTRAP si_codes + */ +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ +#define NSIGTRAP + +/* + * SIGCHLD si_codes + */ +#define CLD_EXITED 1 /* child has exited */ +#define CLD_KILLED 2 /* child was killed */ +#define CLD_DUMPED 3 /* child terminated abnormally */ +#define CLD_TRAPPED 4 /* traced child has trapped */ +#define CLD_STOPPED 5 /* child has stopped */ +#define CLD_CONTINUED 6 /* stopped child has continued */ +#define NSIGCHLD + +/* + * SIGPOLL si_codes + */ +#define POLL_IN 1 /* data input available */ +#define POLL_OUT 2 /* output buffers available */ +#define POLL_MSG 3 /* input message available */ +#define POLL_ERR 4 /* i/o error */ +#define POLL_PRI 5 /* high priority input available */ +#define POLL_HUP 6 /* device disconnected */ +#define NSIGPOLL 6 + +/* + * sigevent definitions + * + * It seems likely that SIGEV_THREAD will have to be handled from + * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the + * thread manager then catches and does the appropriate nonsense. + * However, everything is written out here so as to not get lost. + */ +#define SIGEV_SIGNAL 0 /* notify via signal */ +#define SIGEV_NONE 1 /* other notification: meaningless */ +#define SIGEV_THREAD 2 /* deliver via thread creation */ + +#define SIGEV_MAX_SIZE 64 +#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) + +typedef struct sigevent { + sigval_t sigev_value; + int sigev_signo; + int sigev_notify; + union { + int _pad[SIGEV_PAD_SIZE]; + + struct { + void (*_function)(sigval_t); + void *_attribute; /* really pthread_attr_t */ + } _sigev_thread; + } _sigev_un; +} sigevent_t; + +#define sigev_notify_function _sigev_un._sigev_thread._function +#define sigev_notify_attributes _sigev_un._sigev_thread._attribute + +#endif diff -u --recursive --new-file v2.1.67/linux/include/asm-alpha/signal.h linux/include/asm-alpha/signal.h --- v2.1.67/linux/include/asm-alpha/signal.h Thu Feb 29 21:50:56 1996 +++ linux/include/asm-alpha/signal.h Sun Nov 30 10:59:03 1997 @@ -1,10 +1,23 @@ #ifndef _ASMAXP_SIGNAL_H #define _ASMAXP_SIGNAL_H -typedef unsigned long sigset_t; /* at least 32 bits */ +#include -#define _NSIG 32 -#define NSIG _NSIG +/* Avoid too many header ordering problems. */ +struct siginfo; + +/* Digital Unix defines 64 signals. Most things should be clean enough + to redefine this at will, if care is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 64 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; /* * Linux/AXP has different signal numbers that Linux/i386: I'm trying @@ -46,23 +59,36 @@ #define SIGPWR SIGINFO #define SIGIOT SIGABRT +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + /* - * sa_flags values: SA_STACK is not currently supported, but will allow the - * usage of signal stacks by using the (now obsolete) sa_restorer field in - * the sigaction structure as a stack pointer. This is now possible due to - * the changes in signal handling. LBT 010493. + * SA_FLAGS values: + * + * SA_ONSTACK is not currently supported, but will allow sigaltstack(2). * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the * SA_RESTART flag to get restarting signals (which were the default long ago) - * SA_SHIRQ flag is for shared interrupt support on PCI and EISA. + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. */ -#define SA_NOCLDSTOP 0x00000004 -#define SA_STACK 0x00000001 +#define SA_ONSTACK 0x00000001 #define SA_RESTART 0x00000002 -#define SA_INTERRUPT 0x20000000 -#define SA_NOMASK 0x00000008 -#define SA_ONESHOT 0x00000010 -#define SA_SHIRQ 0x00000020 +#define SA_NOCLDSTOP 0x00000004 +#define SA_NODEFER 0x00000008 +#define SA_RESETHAND 0x00000010 +#define SA_NOCLDWAIT 0x00000020 /* not supported yet */ +#define SA_SIGINFO 0x00000040 + +#define SA_ONESHOT SA_RESETHAND +#define SA_NOMASK SA_NODEFER +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ #ifdef __KERNEL__ /* @@ -70,12 +96,13 @@ * irq handling routines. * * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x40000000 #endif - #define SIG_BLOCK 1 /* for blocking signals */ #define SIG_UNBLOCK 2 /* for unblocking signals */ #define SIG_SETMASK 3 /* for setting the signal mask */ @@ -87,11 +114,28 @@ #define SIG_IGN ((__sighandler_t)1) /* ignore signal */ #define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ +struct osf_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + int sa_flags; +}; + struct sigaction { __sighandler_t sa_handler; - sigset_t sa_mask; - unsigned int sa_flags; + unsigned long sa_flags; + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; + void (*ka_restorer)(void); }; + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; #ifdef __KERNEL__ #include diff -u --recursive --new-file v2.1.67/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h --- v2.1.67/linux/include/asm-alpha/system.h Tue May 13 22:41:17 1997 +++ linux/include/asm-alpha/system.h Sun Nov 30 10:59:03 1997 @@ -52,6 +52,8 @@ extern unsigned long rdusp(void); extern unsigned long rdmces (void); extern void wrmces (unsigned long); +extern unsigned long whami(void); +extern void wripir(unsigned long); #define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory") @@ -119,11 +121,13 @@ #define __cli() setipl(7) #define __sti() setipl(0) #define __save_flags(flags) do { (flags) = getipl(); } while (0) +#define __save_and_cli(flags) do { (flags) = swpipl(7); } while (0) #define __restore_flags(flags) setipl(flags) #define cli() setipl(7) #define sti() setipl(0) #define save_flags(flags) do { (flags) = getipl(); } while (0) +#define save_and_cli(flags) do { (flags) = swpipl(7); } while (0) #define restore_flags(flags) setipl(flags) /* diff -u --recursive --new-file v2.1.67/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h --- v2.1.67/linux/include/asm-alpha/uaccess.h Sun Sep 7 13:10:43 1997 +++ linux/include/asm-alpha/uaccess.h Sun Nov 30 10:59:03 1997 @@ -412,7 +412,19 @@ return retval; \ }) -extern void __clear_user(void); +extern void __do_clear_user(void); + +#define __clear_user(to,n) \ +({ \ + register void * __cl_to __asm__("$6") = (to); \ + register long __cl_len __asm__("$0") = (n); \ + __asm__ __volatile__( \ + "jsr $28,(%2),__do_clear_user" \ + : "=r"(__cl_len), "=r"(__cl_to) \ + : "r"(__do_clear_user), "0"(__cl_len), "1"(__cl_to) \ + : "$1","$2","$3","$4","$5","$28","memory"); \ + __cl_len; \ +}) #define clear_user(to,n) \ ({ \ @@ -420,14 +432,13 @@ register long __cl_len __asm__("$0") = (n); \ if (__access_ok(((long)__cl_to),__cl_len,__access_mask)) { \ __asm__ __volatile__( \ - "jsr $28,(%2),__clear_user" \ + "jsr $28,(%2),__do_clear_user" \ : "=r"(__cl_len), "=r"(__cl_to) \ - : "r"(__clear_user), "0"(__cl_len), "1"(__cl_to)\ + : "r"(__do_clear_user), "0"(__cl_len), "1"(__cl_to)\ : "$1","$2","$3","$4","$5","$28","memory"); \ } \ __cl_len; \ }) - /* Returns: -EFAULT if exception before terminator, N if the entire buffer filled, else strlen. */ diff -u --recursive --new-file v2.1.67/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v2.1.67/linux/include/asm-alpha/unistd.h Sat Oct 25 02:44:18 1997 +++ linux/include/asm-alpha/unistd.h Sun Nov 30 10:59:03 1997 @@ -156,7 +156,7 @@ #define __NR_osf_pid_block 153 /* not implemented */ #define __NR_osf_pid_unblock 154 /* not implemented */ -#define __NR_sigaction 156 +#define __NR_osf_sigaction 156 #define __NR_osf_sigwaitprim 157 /* not implemented */ #define __NR_osf_nfssvc 158 /* not implemented */ #define __NR_osf_getdirentries 159 @@ -288,6 +288,14 @@ #define __NR_prctl 348 #define __NR_pread 349 #define __NR_pwrite 350 +#define __NR_rt_sigreturn 351 +#define __NR_rt_sigaction 352 +#define __NR_rt_sigprocmask 353 +#define __NR_rt_sigpending 354 +#define __NR_rt_sigtimedwait 355 +#define __NR_rt_sigqueueinfo 356 +#define __NR_rt_sigsuspend 357 + #if defined(__LIBRARY__) && defined(__GNUC__) diff -u --recursive --new-file v2.1.67/linux/include/asm-i386/delay.h linux/include/asm-i386/delay.h --- v2.1.67/linux/include/asm-i386/delay.h Sat Nov 29 11:25:12 1997 +++ linux/include/asm-i386/delay.h Sat Nov 29 12:56:42 1997 @@ -12,7 +12,7 @@ extern void __delay(unsigned long loops); #define udelay(n) (__builtin_constant_p(n) ? \ - __const_udelay((n) * 0x10c6) : \ + __const_udelay((n) * 0x10c6ul) : \ __udelay(n)) #endif /* defined(_I386_DELAY_H) */ diff -u --recursive --new-file v2.1.67/linux/include/asm-i386/io.h linux/include/asm-i386/io.h --- v2.1.67/linux/include/asm-i386/io.h Wed Nov 12 13:34:27 1997 +++ linux/include/asm-i386/io.h Sun Nov 30 12:42:48 1997 @@ -36,9 +36,9 @@ #endif #ifdef REALLY_SLOW_IO -#define SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO +#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO #else -#define SLOW_DOWN_IO __SLOW_DOWN_IO +#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO #endif /* @@ -52,7 +52,7 @@ #define __OUT(s,s1,x) \ __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \ -__OUT1(s##_p,x) __OUT2(s,s1,"w") SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \ +__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \ #define __IN1(s) \ extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; @@ -62,7 +62,7 @@ #define __IN(s,s1,i...) \ __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ -__IN1(s##_p) __IN2(s,s1,"w") SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ +__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ #define __INS(s) \ extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ diff -u --recursive --new-file v2.1.67/linux/include/asm-i386/sigcontext.h linux/include/asm-i386/sigcontext.h --- v2.1.67/linux/include/asm-i386/sigcontext.h Mon Sep 30 07:43:21 1996 +++ linux/include/asm-i386/sigcontext.h Sun Nov 30 10:59:03 1997 @@ -51,4 +51,12 @@ unsigned long cr2; }; +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + #endif diff -u --recursive --new-file v2.1.67/linux/include/asm-i386/siginfo.h linux/include/asm-i386/siginfo.h --- v2.1.67/linux/include/asm-i386/siginfo.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-i386/siginfo.h Sun Nov 30 10:59:03 1997 @@ -0,0 +1,195 @@ +#ifndef _I386_SIGINFO_H +#define _I386_SIGINFO_H + +#include + +/* XXX: This structure was copied from the Alpha; is there an iBCS version? */ + +typedef union sigval { + int sival_int; + void *sival_ptr; +} sigval_t; + +#define SI_MAX_SIZE 128 +#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 3) + +typedef struct siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[SI_PAD_SIZE]; + + /* kill() */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + unsigned int _timer1; + unsigned int _timer2; + } _timer; + + /* POSIX.1b signals */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + pid_t _pid; /* which child */ + int _status; /* exit code */ + clock_t _utime; + clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + void *_addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} siginfo_t; + +/* + * How these fields are to be accessed. + */ +#define si_pid _sifields._kill._pid +#define si_uid _sifields._kill._uid +#define si_status _sifields._sigchld._status +#define si_utime _sifields._sigchld._utime +#define si_stime _sifields._sigchld._stime +#define si_value _sifields._rt._sigval +#define si_int _sifields._rt._sigval.sival_int +#define si_ptr _sifields._rt._sigval.sival_ptr +#define si_addr _sifields._sigfault._addr +#define si_band _sifields._sigpoll._band +#define si_fd _sifields._sigpoll._fd + +/* + * si_code values + * Digital reserves positive values for kernel-generated signals. + */ +#define SI_USER 0 /* sent by kill, sigsend, raise */ +#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ +#define SI_QUEUE -1 /* sent by sigqueue */ +#define SI_TIMER -2 /* sent by timer expiration */ +#define SI_MESGQ -3 /* sent by real time mesq state change */ +#define SI_ASYNCIO -4 /* sent by AIO completion */ + +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) + +/* + * SIGILL si_codes + */ +#define ILL_ILLOPC 1 /* illegal opcode */ +#define ILL_ILLOPN 2 /* illegal operand */ +#define ILL_ILLADR 3 /* illegal addressing mode */ +#define ILL_ILLTRP 4 /* illegal trap */ +#define ILL_PRVOPC 5 /* privileged opcode */ +#define ILL_PRVREG 6 /* privileged register */ +#define ILL_COPROC 7 /* coprocessor error */ +#define ILL_BADSTK 8 /* internal stack error */ +#define NSIGILL 8 + +/* + * SIGFPE si_codes + */ +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ +#define NSIGFPE 8 + +/* + * SIGSEGV si_codes + */ +#define SEGV_MAPERR 1 /* address not mapped to object */ +#define SRGV_ACCERR 2 /* invalid permissions for mapped object */ +#define NSIGSEGV 2 + +/* + * SIGBUS si_codes + */ +#define BUS_ADRALN 1 /* invalid address alignment */ +#define BUS_ADRERR 2 /* non-existant physical address */ +#define BUS_OBJERR 3 /* object specific hardware error */ +#define NSIGBUS 3 + +/* + * SIGTRAP si_codes + */ +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ +#define NSIGTRAP + +/* + * SIGCHLD si_codes + */ +#define CLD_EXITED 1 /* child has exited */ +#define CLD_KILLED 2 /* child was killed */ +#define CLD_DUMPED 3 /* child terminated abnormally */ +#define CLD_TRAPPED 4 /* traced child has trapped */ +#define CLD_STOPPED 5 /* child has stopped */ +#define CLD_CONTINUED 6 /* stopped child has continued */ +#define NSIGCHLD + +/* + * SIGPOLL si_codes + */ +#define POLL_IN 1 /* data input available */ +#define POLL_OUT 2 /* output buffers available */ +#define POLL_MSG 3 /* input message available */ +#define POLL_ERR 4 /* i/o error */ +#define POLL_PRI 5 /* high priority input available */ +#define POLL_HUP 6 /* device disconnected */ +#define NSIGPOLL 6 + +/* + * sigevent definitions + * + * It seems likely that SIGEV_THREAD will have to be handled from + * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the + * thread manager then catches and does the appropriate nonsense. + * However, everything is written out here so as to not get lost. + */ +#define SIGEV_SIGNAL 0 /* notify via signal */ +#define SIGEV_NONE 1 /* other notification: meaningless */ +#define SIGEV_THREAD 2 /* deliver via thread creation */ + +#define SIGEV_MAX_SIZE 64 +#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) + +typedef struct sigevent { + sigval_t sigev_value; + int sigev_signo; + int sigev_notify; + union { + int _pad[SIGEV_PAD_SIZE]; + + struct { + void (*_function)(sigval_t); + void *_attribute; /* really pthread_attr_t */ + } _sigev_thread; + } _sigev_un; +} sigevent_t; + +#define sigev_notify_function _sigev_un._sigev_thread._function +#define sigev_notify_attributes _sigev_un._sigev_thread._attribute + +#endif diff -u --recursive --new-file v2.1.67/linux/include/asm-i386/signal.h linux/include/asm-i386/signal.h --- v2.1.67/linux/include/asm-i386/signal.h Mon Sep 30 07:47:39 1996 +++ linux/include/asm-i386/signal.h Sun Nov 30 10:59:03 1997 @@ -1,10 +1,23 @@ #ifndef _ASMi386_SIGNAL_H #define _ASMi386_SIGNAL_H -typedef unsigned long sigset_t; /* at least 32 bits */ +#include -#define _NSIG 32 -#define NSIG _NSIG +/* Avoid too many header ordering problems. */ +struct siginfo; + +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; #define SIGHUP 1 #define SIGINT 2 @@ -43,22 +56,37 @@ #define SIGPWR 30 #define SIGUNUSED 31 +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + /* - * sa_flags values: SA_STACK is not currently supported, but will allow the - * usage of signal stacks by using the (now obsolete) sa_restorer field in - * the sigaction structure as a stack pointer. This is now possible due to - * the changes in signal handling. LBT 010493. + * SA_FLAGS values: + * + * SA_ONSTACK is not currently supported, but will allow sigaltstack(2). * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the * SA_RESTART flag to get restarting signals (which were the default long ago) - * SA_SHIRQ flag is for shared interrupt support on PCI and EISA. + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. */ -#define SA_NOCLDSTOP 1 -#define SA_SHIRQ 0x04000000 -#define SA_STACK 0x08000000 +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 #define SA_RESTART 0x10000000 -#define SA_INTERRUPT 0x20000000 -#define SA_NOMASK 0x40000000 -#define SA_ONESHOT 0x80000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ + +#define SA_RESTORER 0x04000000 #ifdef __KERNEL__ /* @@ -66,12 +94,13 @@ * irq handling routines. * * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 #endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ @@ -83,15 +112,71 @@ #define SIG_IGN ((__sighandler_t)1) /* ignore signal */ #define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + struct sigaction { __sighandler_t sa_handler; - sigset_t sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ }; +struct k_sigaction { + struct sigaction sa; +}; + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + #ifdef __KERNEL__ #include #endif + +#define __HAVE_ARCH_SIG_BITOPS + +extern __inline__ void sigaddset(sigset_t *set, int _sig) +{ + __asm__("btsl %1,%0" : "=m"(*set) : "ir"(_sig - 1) : "cc"); +} + +extern __inline__ void sigdelset(sigset_t *set, int _sig) +{ + __asm__("btrl %1,%0" : "=m"(*set) : "ir"(_sig - 1) : "cc"); +} + +extern __inline__ int __const_sigismember(sigset_t *set, int _sig) +{ + unsigned long sig = _sig - 1; + return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)); +} + +extern __inline__ int __gen_sigismember(sigset_t *set, int _sig) +{ + int ret; + __asm__("btl %2,%1\n\tsbbl %0,%0" + : "=r"(ret) : "m"(*set), "ir"(_sig-1) : "cc"); + return ret; +} + +#define sigismember(set,sig) \ + (__builtin_constant_p(sig) ? \ + __const_sigismember((set),(sig)) : \ + __gen_sigismember((set),(sig))) + +#define sigmask(sig) (1UL << ((sig) - 1)) + +extern __inline__ int sigfindinword(unsigned long word) +{ + __asm__("bsfl %1,%0" : "=r"(word) : "rm"(word) : "cc"); + return word; +} #endif diff -u --recursive --new-file v2.1.67/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- v2.1.67/linux/include/asm-i386/unistd.h Sat Nov 29 11:25:12 1997 +++ linux/include/asm-i386/unistd.h Sun Nov 30 10:59:03 1997 @@ -178,6 +178,13 @@ #define __NR_setresgid 170 #define __NR_getresgid 171 #define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 /* user-visible error numbers are in the range -1 - -122: see */ diff -u --recursive --new-file v2.1.67/linux/include/linux/acct.h linux/include/linux/acct.h --- v2.1.67/linux/include/linux/acct.h Sun Mar 10 23:39:34 1996 +++ linux/include/linux/acct.h Sun Nov 30 12:44:11 1997 @@ -1,29 +1,86 @@ -#ifndef __LINUX_ACCT_H -#define __LINUX_ACCT_H +/* + * BSD Process Accounting for Linux - Definitions + * + * Author: Marco van Wieringen (mvw@planets.elm.net) + * + * This header file contains the definitions needed to implement + * BSD-style process accounting. The kernel accounting code and all + * user-level programs that try to do something useful with the + * process accounting log must include this file. + * + * Copyright (C) 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V. + * + */ -#define ACCT_COMM 16 +#ifndef _LINUX_ACCT_H +#define _LINUX_ACCT_H + +#include + +/* + * comp_t is a 16-bit "floating" point number with a 3-bit base 8 + * exponent and a 13-bit fraction. See linux/kernel/acct.c for the + * specific encoding system used. + */ + +typedef u16 comp_t; + +/* + * accounting file record + * + * This structure contains all of the information written out to the + * process accounting file whenever a process exits. + */ + +#define ACCT_COMM 16 struct acct { - char ac_comm[ACCT_COMM]; /* Accounting command name */ - time_t ac_utime; /* Accounting user time */ - time_t ac_stime; /* Accounting system time */ - time_t ac_etime; /* Accounting elapsed time */ - time_t ac_btime; /* Beginning time */ - uid_t ac_uid; /* Accounting user ID */ - gid_t ac_gid; /* Accounting group ID */ - dev_t ac_tty; /* controlling tty */ - char ac_flag; /* Accounting flag */ - long ac_minflt; /* Accounting minor pagefaults */ - long ac_majflt; /* Accounting major pagefaults */ - long ac_exitcode; /* Accounting process exitcode */ + char ac_flag; /* Accounting Flags */ +/* + * No binary format break with 2.0 - but when we hit 32bit uid we'll + * have to bite one + */ + u16 ac_uid; /* Accounting Real User ID */ + u16 ac_gid; /* Accounting Real Group ID */ + u16 ac_tty; /* Accounting Control Terminal */ + u32 ac_btime; /* Accounting Process Creation Time */ + comp_t ac_utime; /* Accounting User Time */ + comp_t ac_stime; /* Accounting System Time */ + comp_t ac_etime; /* Accounting Elapsed Time */ + comp_t ac_mem; /* Accounting Average Memory Usage */ + comp_t ac_io; /* Accounting Chars Transferred */ + comp_t ac_rw; /* Accounting Blocks Read or Written */ + comp_t ac_minflt; /* Accounting Minor Pagefaults */ + comp_t ac_majflt; /* Accounting Major Pagefaults */ + comp_t ac_swaps; /* Accounting Number of Swaps */ + u32 ac_exitcode; /* Accounting Exitcode */ + char ac_comm[ACCT_COMM + 1]; /* Accounting Command Name */ + char ac_pad[10]; /* Accounting Padding Bytes */ }; -#define AFORK 0001 /* has executed fork, but no exec */ -#define ASU 0002 /* used super-user privileges */ -#define ACORE 0004 /* dumped core */ -#define AXSIG 0010 /* killed by a signal */ +/* + * accounting flags + */ + /* bit set when the process ... */ +#define AFORK 0x01 /* ... executed fork, but did not exec */ +#define ASU 0x02 /* ... used super-user privileges */ +#define ACOMPAT 0x04 /* ... used compatibility mode (VAX only not used) */ +#define ACORE 0x08 /* ... dumped core */ +#define AXSIG 0x10 /* ... was killed by a signal */ -#define AHZ 100 +#define AHZ 100 +#ifdef __KERNEL__ + +#include + +#ifdef CONFIG_BSD_PROCESS_ACCT +extern int acct_process(long exitcode); +#else +#define acct_process(x) do { } while (0) #endif + +#endif /* __KERNEL */ + +#endif /* _LINUX_ACCT_H */ diff -u --recursive --new-file v2.1.67/linux/include/linux/baycom.h linux/include/linux/baycom.h --- v2.1.67/linux/include/linux/baycom.h Fri Dec 20 03:17:18 1996 +++ linux/include/linux/baycom.h Sun Nov 30 10:30:19 1997 @@ -1,7 +1,7 @@ /* * The Linux BAYCOM driver for the Baycom serial 1200 baud modem * and the parallel 9600 baud modem - * (C) 1996 by Thomas Sailer, HB9JNX + * (C) 1997 by Thomas Sailer, HB9JNX/AE4WA */ #ifndef _BAYCOM_H diff -u --recursive --new-file v2.1.67/linux/include/linux/hfmodem.h linux/include/linux/hfmodem.h --- v2.1.67/linux/include/linux/hfmodem.h Mon Aug 11 14:47:05 1997 +++ linux/include/linux/hfmodem.h Sun Nov 30 10:30:19 1997 @@ -100,6 +100,7 @@ /* --------------------------------------------------------------------- */ #ifdef __KERNEL__ +#include #define DMA_MODE_AUTOINIT 0x10 @@ -133,6 +134,7 @@ unsigned int pariobase; unsigned int midiiobase; unsigned int flags; + struct pardevice *pardev; } ptt_out; struct { diff -u --recursive --new-file v2.1.67/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v2.1.67/linux/include/linux/kernel.h Mon Oct 20 10:36:53 1997 +++ linux/include/linux/kernel.h Sun Nov 30 10:59:03 1997 @@ -50,10 +50,6 @@ extern int session_of_pgrp(int pgrp); -extern int kill_proc(int pid, int sig, int priv); -extern int kill_pg(int pgrp, int sig, int priv); -extern int kill_sl(int sess, int sig, int priv); - asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); diff -u --recursive --new-file v2.1.67/linux/include/linux/parport.h linux/include/linux/parport.h --- v2.1.67/linux/include/linux/parport.h Wed Sep 3 20:52:44 1997 +++ linux/include/linux/parport.h Sat Nov 29 16:19:47 1997 @@ -1,4 +1,4 @@ -/* $Id: parport.h,v 1.2.6.3.2.2 1997/04/18 15:03:53 phil Exp $ */ +/* $Id: parport.h,v 1.3 1997/10/19 18:02:00 phil Exp $ */ #ifndef _PARPORT_H_ #define _PARPORT_H_ @@ -160,7 +160,7 @@ /* A parallel port */ struct parport { - unsigned int base; /* base address */ + unsigned long base; /* base address */ unsigned int size; /* IO extent */ char *name; int irq; /* interrupt (or -1 for none) */ @@ -266,11 +266,11 @@ extern int parport_proc_register(struct parport *pp); extern int parport_proc_unregister(struct parport *pp); -/* Prototypes from parport_ksyms.c */ extern void dec_parport_count(void); extern void inc_parport_count(void); extern int parport_probe(struct parport *port, char *buffer, int len); extern void parport_probe_one(struct parport *port); +extern void (*parport_probe_hook)(struct parport *port); #endif /* _PARPORT_H_ */ diff -u --recursive --new-file v2.1.67/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.67/linux/include/linux/pci.h Wed Nov 26 16:24:03 1997 +++ linux/include/linux/pci.h Sat Nov 29 16:21:04 1997 @@ -43,8 +43,8 @@ -#ifndef PCI_H -#define PCI_H +#ifndef LINUX_PCI_H +#define LINUX_PCI_H /* * Under PCI, each device has 256 bytes of configuration address space, @@ -802,6 +802,7 @@ #define PCI_DEVICE_ID_ARK_STINGARK 0xa099 #define PCI_DEVICE_ID_ARK_2000MT 0xa0a1 +#ifdef __KERNEL__ /* * The PCI interface treats multi-function devices as independent * devices. The slot/function address of each device is encoded @@ -892,5 +893,5 @@ extern const char *pci_strdev (unsigned int vendor, unsigned int device); extern int get_pci_list (char *buf); - -#endif /* PCI_H */ +#endif /* __KERNEL__ */ +#endif /* LINUX_PCI_H */ diff -u --recursive --new-file v2.1.67/linux/include/linux/scc.h linux/include/linux/scc.h --- v2.1.67/linux/include/linux/scc.h Sun Apr 13 10:18:22 1997 +++ linux/include/linux/scc.h Sat Nov 29 16:29:37 1997 @@ -184,7 +184,7 @@ #define RXINT 0x04 #define SPINT 0x06 -#ifdef SCC_DELAY +#ifdef CONFIG_SCC_DELAY #define Inb(port) inb_p(port) #define Outb(port, val) outb_p(val, port) #else diff -u --recursive --new-file v2.1.67/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.1.67/linux/include/linux/sched.h Mon Oct 20 10:36:53 1997 +++ linux/include/linux/sched.h Sun Nov 30 12:42:48 1997 @@ -19,6 +19,7 @@ #include #include #include +#include /* * cloning flags: @@ -165,14 +166,14 @@ struct signal_struct { atomic_t count; - struct sigaction action[32]; + struct k_sigaction action[_NSIG]; spinlock_t siglock; }; #define INIT_SIGNALS { \ ATOMIC_INIT(1), \ - { {0,}, }, \ + { {{0,}}, }, \ SPIN_LOCK_UNLOCKED } struct task_struct { @@ -180,8 +181,6 @@ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ long counter; long priority; - unsigned long signal; - unsigned long blocked; /* bitmap of masked signals */ unsigned long flags; /* per process flags, defined below */ int errno; long debugreg[8]; /* Hardware debugging registers */ @@ -196,11 +195,10 @@ unsigned long personality; int dumpable:1; int did_exec:1; - /* shouldn't this be pid_t? */ - int pid; - int pgrp; - int tty_old_pgrp; - int session; + pid_t pid; + pid_t pgrp; + pid_t tty_old_pgrp; + pid_t session; /* boolean value for session group leader */ int leader; int ngroups; @@ -220,8 +218,8 @@ struct task_struct **tarray_ptr; struct wait_queue *wait_chldexit; /* for wait4() */ - unsigned short uid,euid,suid,fsuid; - unsigned short gid,egid,sgid,fsgid; + uid_t uid,euid,suid,fsuid; + gid_t gid,egid,sgid,fsgid; unsigned long timeout, policy, rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; unsigned long it_real_incr, it_prof_incr, it_virt_incr; @@ -257,6 +255,8 @@ struct mm_struct *mm; /* signal handlers */ struct signal_struct *sig; + sigset_t signal, blocked; + struct signal_queue *sigqueue, **sigqueue_tail; /* SMP state */ int has_cpu; int processor; @@ -271,17 +271,17 @@ */ #define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */ /* Not implemented yet, only for 486*/ -#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called. */ +#define PF_STARTING 0x00000002 /* being created */ +#define PF_EXITING 0x00000004 /* getting shut down */ +#define PF_SIGPENDING 0x00000008 /* at least on unblocked sig ready */ +#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called */ #define PF_TRACESYS 0x00000020 /* tracing system calls */ #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ #define PF_DUMPCORE 0x00000200 /* dumped core */ #define PF_SIGNALED 0x00000400 /* killed by a signal */ -#define PF_STARTING 0x00000002 /* being created */ -#define PF_EXITING 0x00000004 /* getting shut down */ - -#define PF_USEDFPU 0x00100000 /* Process used the FPU this quantum (SMP only) */ +#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ #define PF_DTRACE 0x00200000 /* delayed trace (used on m68k) */ #define PF_ONSIGSTK 0x00400000 /* works on signal stack (m68k only) */ @@ -308,7 +308,7 @@ * your own risk!. Base=0, limit=0x1fffff (=2MB) */ #define INIT_TASK \ -/* state etc */ { 0,DEF_PRIORITY,DEF_PRIORITY,0,0,0,0, \ +/* state etc */ { 0,DEF_PRIORITY,DEF_PRIORITY,0,0, \ /* debugregs */ { 0, }, \ /* exec domain */&default_exec_domain, \ /* binfmt */ NULL, \ @@ -336,7 +336,7 @@ /* fs */ &init_fs, \ /* files */ &init_files, \ /* mm */ &init_mm, \ -/* signals */ &init_signals, \ +/* signals */ &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, \ /* SMP */ 0,0,0,0, \ /* locks */ INIT_LOCKS \ } @@ -445,15 +445,67 @@ extern void FASTCALL(wake_up_interruptible(struct wait_queue ** p)); extern void FASTCALL(wake_up_process(struct task_struct * tsk)); -extern void notify_parent(struct task_struct * tsk, int signal); -extern void force_sig(unsigned long sig,struct task_struct * p); -extern int send_sig(unsigned long sig,struct task_struct * p,int priv); extern int in_group_p(gid_t grp); +extern void flush_signals(struct task_struct *); +extern void flush_signal_handlers(struct task_struct *); +extern int dequeue_signal(sigset_t *block, siginfo_t *); +extern int send_sig_info(int, struct siginfo *info, struct task_struct *); +extern int force_sig_info(int, struct siginfo *info, struct task_struct *); +extern int kill_pg_info(int, struct siginfo *info, pid_t); +extern int kill_sl_info(int, struct siginfo *info, pid_t); +extern int kill_proc_info(int, struct siginfo *info, pid_t); +extern int kill_something_info(int, struct siginfo *info, int); +extern void notify_parent(struct task_struct * tsk, int); +extern void force_sig(int sig, struct task_struct * p); +extern int send_sig(int sig, struct task_struct * p, int priv); +extern int kill_pg(pid_t, int, int); +extern int kill_sl(pid_t, int, int); +extern int kill_proc(pid_t, int, int); +extern int do_sigaction(int sig, const struct k_sigaction *act, + struct k_sigaction *oact); + extern inline int signal_pending(struct task_struct *p) { - return (p->signal &~ p->blocked) != 0; + return (p->flags & PF_SIGPENDING) != 0; } + +/* Reevaluate whether the task has signals pending delivery. + This is required every time the blocked sigset_t changes. + All callers should have t->sigmask_lock. */ + +static inline void recalc_sigpending(struct task_struct *t) +{ + unsigned long ready, nflags; + long i; + + switch (_NSIG_WORDS) { + default: + for (i = _NSIG_WORDS, ready = 0; --i >= 0 ;) + ready |= t->signal.sig[i] &~ t->blocked.sig[i]; + break; + + case 4: ready = t->signal.sig[3] &~ t->blocked.sig[3]; + ready |= t->signal.sig[2] &~ t->blocked.sig[2]; + ready |= t->signal.sig[1] &~ t->blocked.sig[1]; + ready |= t->signal.sig[0] &~ t->blocked.sig[0]; + break; + + case 2: ready = t->signal.sig[1] &~ t->blocked.sig[1]; + ready |= t->signal.sig[0] &~ t->blocked.sig[0]; + break; + + case 1: ready = t->signal.sig[0] &~ t->blocked.sig[0]; + } + + /* Poor gcc has trouble with conditional moves... */ + nflags = t->flags &~ PF_SIGPENDING; + if (ready) + nflags = t->flags | PF_SIGPENDING; + + t->flags = nflags; +} + extern int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), diff -u --recursive --new-file v2.1.67/linux/include/linux/signal.h linux/include/linux/signal.h --- v2.1.67/linux/include/linux/signal.h Mon Sep 30 07:47:39 1996 +++ linux/include/linux/signal.h Sun Nov 30 10:59:03 1997 @@ -2,5 +2,204 @@ #define _LINUX_SIGNAL_H #include +#include -#endif +#ifdef __KERNEL__ +/* + * Real Time signals may be queued. + */ + +struct signal_queue +{ + struct signal_queue *next; + siginfo_t info; +}; + +/* + * Define some primitives to manipulate sigset_t. + */ + +#ifndef __HAVE_ARCH_SIG_BITOPS +#include + +/* We don't use for these because there is no need to + be atomic. */ +extern inline void sigaddset(sigset_t *set, int _sig) +{ + unsigned long sig = _sig - 1; + if (_NSIG_WORDS == 1) + set->sig[0] |= 1UL << sig; + else + set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW); +} + +extern inline void sigdelset(sigset_t *set, int _sig) +{ + unsigned long sig = _sig - 1; + if (_NSIG_WORDS == 1) + set->sig[0] &= ~(1UL << sig); + else + set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW)); +} + +extern inline int sigismember(sigset_t *set, int _sig) +{ + unsigned long sig = _sig - 1; + if (_NSIG_WORDS == 1) + return 1 & (set->sig[0] >> sig); + else + return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)); +} + +extern inline int sigfindinword(unsigned long word) +{ + return ffz(~word); +} + +#define sigmask(sig) (1UL << ((sig) - 1)) + +#endif /* __HAVE_ARCH_SIG_BITOPS */ + +#ifndef __HAVE_ARCH_SIG_SETOPS +#include + +#define _SIG_SET_BINOP(name, op) \ +extern inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \ +{ \ + unsigned long a0, a1, a2, a3, b0, b1, b2, b3; \ + unsigned long i; \ + \ + for (i = 0; i < _NSIG_WORDS/4; ++i) { \ + a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; \ + a2 = a->sig[4*i+2]; a3 = a->sig[4*i+3]; \ + b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; \ + b2 = b->sig[4*i+2]; b3 = b->sig[4*i+3]; \ + r->sig[4*i+0] = op(a0, b0); \ + r->sig[4*i+1] = op(a1, b1); \ + r->sig[4*i+2] = op(a2, b2); \ + r->sig[4*i+3] = op(a3, b3); \ + } \ + switch (_NSIG_WORDS % 4) { \ + case 3: \ + a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; a2 = a->sig[4*i+2]; \ + b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; b2 = b->sig[4*i+2]; \ + r->sig[4*i+0] = op(a0, b0); \ + r->sig[4*i+1] = op(a1, b1); \ + r->sig[4*i+2] = op(a2, b2); \ + break; \ + case 2: \ + a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; \ + b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; \ + r->sig[4*i+0] = op(a0, b0); \ + r->sig[4*i+1] = op(a1, b1); \ + break; \ + case 1: \ + a0 = a->sig[4*i+0]; b0 = b->sig[4*i+0]; \ + r->sig[4*i+0] = op(a0, b0); \ + break; \ + } \ +} + +#define _sig_or(x,y) ((x) | (y)) +_SIG_SET_BINOP(sigorsets, _sig_or) + +#define _sig_and(x,y) ((x) & (y)) +_SIG_SET_BINOP(sigandsets, _sig_and) + +#define _sig_nand(x,y) ((x) & ~(y)) +_SIG_SET_BINOP(signandsets, _sig_nand) + +#undef _SIG_SET_BINOP +#undef _sig_or +#undef _sig_and +#undef _sig_nand + +#define _SIG_SET_OP(name, op) \ +extern inline void name(sigset_t *set) \ +{ \ + unsigned long i; \ + \ + for (i = 0; i < _NSIG_WORDS/4; ++i) { \ + set->sig[4*i+0] = op(set->sig[4*i+0]); \ + set->sig[4*i+1] = op(set->sig[4*i+1]); \ + set->sig[4*i+2] = op(set->sig[4*i+2]); \ + set->sig[4*i+3] = op(set->sig[4*i+3]); \ + } \ + switch (_NSIG_WORDS % 4) { \ + case 3: set->sig[4*i+2] = op(set->sig[4*i+2]); \ + case 2: set->sig[4*i+1] = op(set->sig[4*i+1]); \ + case 1: set->sig[4*i+0] = op(set->sig[4*i+0]); \ + } \ +} + +#define _sig_not(x) (~(x)) +_SIG_SET_OP(signotset, _sig_not) + +#undef _SIG_SET_OP +#undef _sig_not + +extern inline void sigemptyset(sigset_t *set) +{ + switch (_NSIG_WORDS) { + default: + memset(set, 0, sizeof(sigset_t)); + break; + case 2: set->sig[1] = 0; + case 1: set->sig[0] = 0; + break; + } +} + +extern inline void sigfillset(sigset_t *set) +{ + switch (_NSIG_WORDS) { + default: + memset(set, -1, sizeof(sigset_t)); + break; + case 2: set->sig[1] = -1; + case 1: set->sig[0] = -1; + break; + } +} + +/* Some extensions for manipulating the low 32 signals in particular. */ + +extern inline void sigaddsetmask(sigset_t *set, unsigned long mask) +{ + set->sig[0] |= mask; +} + +extern inline void sigdelsetmask(sigset_t *set, unsigned long mask) +{ + set->sig[0] &= ~mask; +} + +extern inline void siginitset(sigset_t *set, unsigned long mask) +{ + set->sig[0] = mask; + switch (_NSIG_WORDS) { + default: + memset(&set->sig[1], 0, sizeof(long)*(_NSIG_WORDS-1)); + break; + case 2: set->sig[1] = 0; + case 1: + } +} + +extern inline void siginitsetinv(sigset_t *set, unsigned long mask) +{ + set->sig[0] = ~mask; + switch (_NSIG_WORDS) { + default: + memset(&set->sig[1], -1, sizeof(long)*(_NSIG_WORDS-1)); + break; + case 2: set->sig[1] = -1; + case 1: + } +} + +#endif /* __HAVE_ARCH_SIG_SETOPS */ + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SIGNAL_H */ diff -u --recursive --new-file v2.1.67/linux/include/linux/time.h linux/include/linux/time.h --- v2.1.67/linux/include/linux/time.h Fri Dec 27 02:04:48 1996 +++ linux/include/linux/time.h Sun Nov 30 10:59:03 1997 @@ -1,6 +1,8 @@ #ifndef _LINUX_TIME_H #define _LINUX_TIME_H +#include + #ifndef _STRUCT_TIMESPEC #define _STRUCT_TIMESPEC struct timespec { @@ -9,6 +11,30 @@ }; #endif /* _STRUCT_TIMESPEC */ +/* + * change timeval to jiffies, trying to avoid the + * most obvious overflows.. + */ +static inline unsigned long +timespec_to_jiffies(struct timespec *value) +{ + unsigned long sec = value->tv_sec; + long nsec = value->tv_nsec; + + if (sec > ((long)(~0UL >> 1) / HZ)) + return ~0UL >> 1; + nsec += 1000000000L / HZ - 1; + nsec /= 1000000000L / HZ; + return HZ * sec + nsec; +} + +static inline void +jiffies_to_timespec(unsigned long jiffies, struct timespec *value) +{ + value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ); + value->tv_sec = jiffies / HZ; +} + struct timeval { int tv_sec; /* seconds */ int tv_usec; /* microseconds */ diff -u --recursive --new-file v2.1.67/linux/init/main.c linux/init/main.c --- v2.1.67/linux/init/main.c Wed Nov 26 16:24:03 1997 +++ linux/init/main.c Sun Nov 30 10:59:03 1997 @@ -75,6 +75,7 @@ extern long powermac_init(unsigned long, unsigned long); extern void sysctl_init(void); extern void filescache_init(void); +extern void signals_init(void); extern void smp_setup(char *str, int *ints); extern void no_scroll(char *str, int *ints); @@ -220,8 +221,14 @@ #ifdef CONFIG_RISCOM8 extern void riscom8_setup(char *str, int *ints); #endif -#ifdef CONFIG_BAYCOM -extern void baycom_setup(char *str, int *ints); +#ifdef CONFIG_BAYCOM_PAR +extern void baycom_par_setup(char *str, int *ints); +#endif +#ifdef CONFIG_BAYCOM_SER_FDX +extern void baycom_ser_fdx_setup(char *str, int *ints); +#endif +#ifdef CONFIG_BAYCOM_SER_HDX +extern void baycom_ser_hdx_setup(char *str, int *ints); #endif #ifdef CONFIG_SOUNDMODEM extern void sm_setup(char *str, int *ints); @@ -541,8 +548,14 @@ #ifdef CONFIG_RISCOM8 { "riscom8=", riscom8_setup }, #endif -#ifdef CONFIG_BAYCOM - { "baycom=", baycom_setup }, +#ifdef CONFIG_BAYCOM_PAR + { "baycom_par=", baycom_par_setup }, +#endif +#ifdef CONFIG_BAYCOM_SER_FDX + { "baycom_ser_fdx=", baycom_ser_fdx_setup }, +#endif +#ifdef CONFIG_BAYCOM_SER_HDX + { "baycom_ser_hdx=", baycom_ser_hdx_setup }, #endif #ifdef CONFIG_SOUNDMODEM { "soundmodem=", sm_setup }, @@ -955,6 +968,7 @@ dcache_init(); vma_init(); buffer_init(); + signals_init(); inode_init(); file_table_init(); sock_init(); diff -u --recursive --new-file v2.1.67/linux/kernel/Makefile linux/kernel/Makefile --- v2.1.67/linux/kernel/Makefile Tue Jan 9 23:27:39 1996 +++ linux/kernel/Makefile Sun Nov 30 12:37:29 1997 @@ -12,11 +12,13 @@ O_TARGET := kernel.o O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \ - module.o exit.o signal.o itimer.o info.o time.o softirq.o \ - resource.o sysctl.o + module.o exit.o itimer.o info.o time.o softirq.o resource.o \ + sysctl.o acct.o + +OX_OBJS += signal.o ifeq ($(CONFIG_MODULES),y) -OX_OBJS = ksyms.o +OX_OBJS += ksyms.o endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.67/linux/kernel/acct.c linux/kernel/acct.c --- v2.1.67/linux/kernel/acct.c Wed Dec 31 16:00:00 1969 +++ linux/kernel/acct.c Sun Nov 30 12:34:44 1997 @@ -0,0 +1,335 @@ +/* + * linux/kernel/acct.c + * + * BSD Process Accounting for Linux + * + * Author: Marco van Wieringen + * + * Some code based on ideas and code from: + * Thomas K. Dyas + * + * This file implements BSD-style process accounting. Whenever any + * process exits, an accounting record of type "struct acct" is + * written to the file specified with the acct() system call. It is + * up to user-level programs to do useful things with the accounting + * log. The kernel just provides the raw accounting information. + * + * (C) Copyright 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V. + * + */ + +#include +#include +#include + +#ifdef CONFIG_BSD_PROCESS_ACCT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * These constants control the amount of freespace that suspend and + * resume the process accounting system, and the time delay between + * each check. + */ + +#define RESUME (4) /* More than 4% free space will resume */ +#define SUSPEND (2) /* Less than 2% free space will suspend */ +#define ACCT_TIMEOUT (30 * HZ) /* 30 second timeout between checks */ + +/* + * External references and all of the globals. + */ +extern int close_fp(struct file *); + +void acct_timeout(unsigned long); + +static volatile int acct_active = 0; +static volatile int acct_needcheck = 0; +static struct file *acct_file = NULL; +static struct timer_list acct_timer = { NULL, NULL, 0, 0, acct_timeout }; + +/* + * Called whenever the timer says to check the free space. + */ +void acct_timeout(unsigned long unused) +{ + acct_needcheck = 1; +} + +/* + * Check the amount of free space and suspend/resume accordingly. + */ +static void check_free_space(void) +{ + unsigned long fs; + struct statfs sbuf; + + if (!acct_file || !acct_needcheck) + return; + + if (!acct_file->f_dentry->d_inode->i_sb->s_op || + !acct_file->f_dentry->d_inode->i_sb->s_op->statfs) + return; + + fs = get_fs(); + set_fs(KERNEL_DS); + acct_file->f_dentry->d_inode->i_sb->s_op->statfs(acct_file->f_dentry->d_inode->i_sb, &sbuf, sizeof(struct statfs)); + set_fs(fs); + + if (acct_active) { + if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100) { + acct_active = 0; + printk(KERN_INFO "Process accounting paused\r\n"); + } + } else { + if (sbuf.f_bavail >= RESUME * sbuf.f_blocks / 100) { + acct_active = 1; + printk(KERN_INFO "Process accounting resumed\r\n"); + } + } + del_timer(&acct_timer); + acct_needcheck = 0; + acct_timer.expires = jiffies + ACCT_TIMEOUT; + add_timer(&acct_timer); +} + +/* + * sys_acct() is the only system call needed to implement process + * accounting. It takes the name of the file where accounting records + * should be written. If the filename is NULL, accounting will be + * shutdown. + */ +asmlinkage int sys_acct(const char *name) +{ + struct dentry *dentry; + struct inode *inode; + char *tmp; + int error = -EPERM; + + lock_kernel(); + if (!suser()) + goto out; + + if (name == (char *)NULL) { + if (acct_active) { + acct_process(0); + del_timer(&acct_timer); + acct_active = 0; + acct_needcheck = 0; + close_fp(acct_file); + } + error = 0; + goto out; + } else { + if (!acct_active) { + tmp = getname(name); + error = PTR_ERR(tmp); + if (IS_ERR(tmp)) + goto out; + + dentry = open_namei(tmp, O_RDWR, 0600); + putname(tmp); + + error = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out; + + inode = dentry->d_inode; + + if (!S_ISREG(inode->i_mode)) { + dput(dentry); + error = -EACCES; + goto out; + } + + if (!inode->i_op || !inode->i_op->default_file_ops || + !inode->i_op->default_file_ops->write) { + dput(dentry); + error = -EIO; + goto out; + } + + if ((acct_file = get_empty_filp()) != (struct file *)NULL) { + acct_file->f_mode = (O_WRONLY + 1) & O_ACCMODE; + acct_file->f_flags = O_WRONLY; + acct_file->f_dentry = dentry; + acct_file->f_pos = inode->i_size; + acct_file->f_reada = 0; + acct_file->f_op = inode->i_op->default_file_ops; + if ((error = get_write_access(acct_file->f_dentry->d_inode)) == 0) { + if (acct_file->f_op && acct_file->f_op->open) + error = acct_file->f_op->open(inode, acct_file); + if (error == 0) { + acct_needcheck = 0; + acct_active = 1; + acct_timer.expires = jiffies + ACCT_TIMEOUT; + add_timer(&acct_timer); + error = 0; + goto out; + } + put_write_access(acct_file->f_dentry->d_inode); + } + acct_file->f_count--; + } else + error = -EUSERS; + dput(dentry); + } else + error = -EBUSY; + } +out: + unlock_kernel(); + return error; +} + +void acct_auto_close(kdev_t dev) +{ + if (acct_active && acct_file && acct_file->f_dentry->d_inode->i_dev == dev) + sys_acct((char *)NULL); +} + +/* + * encode an unsigned long into a comp_t + * + * This routine has been adopted from the encode_comp_t() function in + * the kern_acct.c file of the FreeBSD operating system. The encoding + * is a 13-bit fraction with a 3-bit (base 8) exponent. + */ + +#define MANTSIZE 13 /* 13 bit mantissa. */ +#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */ +#define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */ + +static comp_t encode_comp_t(unsigned long value) +{ + int exp, rnd; + + exp = rnd = 0; + while (value > MAXFRACT) { + rnd = value & (1 << (EXPSIZE - 1)); /* Round up? */ + value >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */ + exp++; + } + + /* + * If we need to round up, do it (and handle overflow correctly). + */ + if (rnd && (++value > MAXFRACT)) { + value >>= EXPSIZE; + exp++; + } + + /* + * Clean it up and polish it off. + */ + exp <<= MANTSIZE; /* Shift the exponent into place */ + exp += value; /* and add on the mantissa. */ + return exp; +} + +/* + * Write an accounting entry for an exiting process + * + * The acct_process() call is the workhorse of the process + * accounting system. The struct acct is built here and then written + * into the accounting file. This function should only be called from + * do_exit(). + */ +#define KSTK_EIP(stack) (((unsigned long *)(stack))[1019]) +#define KSTK_ESP(stack) (((unsigned long *)(stack))[1022]) + +int acct_process(long exitcode) +{ + struct acct ac; + unsigned long fs; + unsigned long vsize; + + /* + * First check to see if there is enough free_space to continue the process + * accounting system. Check_free_space toggle's the acct_active flag so we + * need to check that after check_free_space. + */ + check_free_space(); + + if (!acct_active) + return 0; + + + /* + * Fill the accounting struct with the needed info as recorded by the different + * kernel functions. + */ + memset((caddr_t)&ac, 0, sizeof(struct acct)); + + strncpy(ac.ac_comm, current->comm, ACCT_COMM); + ac.ac_comm[ACCT_COMM - 1] = '\0'; + + ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ)); + ac.ac_etime = encode_comp_t(jiffies - current->start_time); + ac.ac_utime = encode_comp_t(current->times.tms_utime); + ac.ac_stime = encode_comp_t(current->times.tms_stime); + ac.ac_uid = current->uid; + ac.ac_gid = current->gid; + ac.ac_tty = (current->tty) ? kdev_t_to_nr(current->tty->device) : 0; + + ac.ac_flag = 0; + if (current->flags & PF_FORKNOEXEC) + ac.ac_flag |= AFORK; + if (current->flags & PF_SUPERPRIV) + ac.ac_flag |= ASU; + if (current->flags & PF_DUMPCORE) + ac.ac_flag |= ACORE; + if (current->flags & PF_SIGNALED) + ac.ac_flag |= AXSIG; + + vsize = 0; + if (current->mm) { + struct vm_area_struct *vma = current->mm->mmap; + while (vma) { + vsize += vma->vm_end - vma->vm_start; + vma = vma->vm_next; + } + } + vsize = vsize / 1024; + ac.ac_mem = encode_comp_t(vsize); + ac.ac_io = encode_comp_t(current->io_usage); + ac.ac_rw = encode_comp_t(ac.ac_io / 1024); + ac.ac_minflt = encode_comp_t(current->min_flt); + ac.ac_majflt = encode_comp_t(current->maj_flt); + ac.ac_swaps = encode_comp_t(current->nswap); + ac.ac_exitcode = exitcode; + + /* + * Kernel segment override to datasegment and write it to the accounting file. + */ + fs = get_fs(); + set_fs(KERNEL_DS); + acct_file->f_op->write(acct_file, (char *)&ac, + sizeof(struct acct), &acct_file->f_pos); + set_fs(fs); + return 0; +} + +#else +/* + * Dummy system call when BSD process accounting is not configured + * into the kernel. + */ + +asmlinkage int sys_acct(const char * filename) +{ + return -ENOSYS; +} +#endif diff -u --recursive --new-file v2.1.67/linux/kernel/exit.c linux/kernel/exit.c --- v2.1.67/linux/kernel/exit.c Wed Sep 24 20:05:48 1997 +++ linux/kernel/exit.c Sun Nov 30 12:41:39 1997 @@ -20,113 +20,17 @@ #include #include #include +#include #include #include #include extern void sem_exit (void); -extern void acct_process (long exitcode); extern void kerneld_exit(void); int getrusage(struct task_struct *, int, struct rusage *); -static inline void generate(unsigned long sig, struct task_struct * p) -{ - unsigned flags; - unsigned long mask = 1 << (sig-1); - struct sigaction * sa = sig + p->sig->action - 1; - - /* - * Optimize away the signal, if it's a signal that can - * be handled immediately (ie non-blocked and untraced) - * and that is ignored (either explicitly or by default) - */ - spin_lock_irqsave(&p->sig->siglock, flags); - if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) { - /* don't bother with ignored signals (but SIGCHLD is special) */ - if (sa->sa_handler == SIG_IGN && sig != SIGCHLD) - goto out; - /* some signals are ignored by default.. (but SIGCONT already did its deed) */ - if ((sa->sa_handler == SIG_DFL) && - (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG)) - goto out; - } - spin_lock(&p->sigmask_lock); - p->signal |= mask; - spin_unlock(&p->sigmask_lock); - if (p->state == TASK_INTERRUPTIBLE && signal_pending(p)) - wake_up_process(p); -out: - spin_unlock_irqrestore(&p->sig->siglock, flags); -} - -/* - * Force a signal that the process can't ignore: if necessary - * we unblock the signal and change any SIG_IGN to SIG_DFL. - */ -void force_sig(unsigned long sig, struct task_struct * p) -{ - sig--; - if (p->sig) { - unsigned flags; - unsigned long mask = 1UL << sig; - struct sigaction *sa = p->sig->action + sig; - - spin_lock_irqsave(&p->sig->siglock, flags); - - spin_lock(&p->sigmask_lock); - p->signal |= mask; - p->blocked &= ~mask; - spin_unlock(&p->sigmask_lock); - - if (sa->sa_handler == SIG_IGN) - sa->sa_handler = SIG_DFL; - if (p->state == TASK_INTERRUPTIBLE) - wake_up_process(p); - - spin_unlock_irqrestore(&p->sig->siglock, flags); - } -} - -int send_sig(unsigned long sig,struct task_struct * p,int priv) -{ - if (!p || sig > 32) - return -EINVAL; - if (!priv && ((sig != SIGCONT) || (current->session != p->session)) && - (current->euid ^ p->suid) && (current->euid ^ p->uid) && - (current->uid ^ p->suid) && (current->uid ^ p->uid) && - !suser()) - return -EPERM; - - if (sig && p->sig) { - unsigned flags; - spin_lock_irqsave(&p->sigmask_lock, flags); - if ((sig == SIGKILL) || (sig == SIGCONT)) { - if (p->state == TASK_STOPPED) - wake_up_process(p); - p->exit_code = 0; - p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) | - (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) ); - } - if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) - p->signal &= ~(1<<(SIGCONT-1)); - spin_unlock_irqrestore(&p->sigmask_lock, flags); - - /* Actually generate the signal */ - generate(sig,p); - } - return 0; -} - -void notify_parent(struct task_struct * tsk, int signal) -{ - struct task_struct * parent = tsk->p_pptr; - - send_sig(signal, parent, 1); - wake_up_interruptible(&parent->wait_chldexit); -} - static void release(struct task_struct * p) { if (p != current) { @@ -179,118 +83,6 @@ } /* - * kill_pg() sends a signal to a process group: this is what the tty - * control characters do (^C, ^Z etc) - */ -int kill_pg(int pgrp, int sig, int priv) -{ - int retval; - - retval = -EINVAL; - if (sig >= 0 && sig <= 32 && pgrp > 0) { - struct task_struct *p; - int found = 0; - - retval = -ESRCH; - read_lock(&tasklist_lock); - for_each_task(p) { - if (p->pgrp == pgrp) { - int err = send_sig(sig,p,priv); - if (err != 0) - retval = err; - else - found++; - } - } - read_unlock(&tasklist_lock); - if (found) - retval = 0; - } - return retval; -} - -/* - * kill_sl() sends a signal to the session leader: this is used - * to send SIGHUP to the controlling process of a terminal when - * the connection is lost. - */ -int kill_sl(int sess, int sig, int priv) -{ - int retval; - - retval = -EINVAL; - if (sig >= 0 && sig <= 32 && sess > 0) { - struct task_struct *p; - int found = 0; - - retval = -ESRCH; - read_lock(&tasklist_lock); - for_each_task(p) { - if (p->leader && p->session == sess) { - int err = send_sig(sig,p,priv); - - if (err) - retval = err; - else - found++; - } - } - read_unlock(&tasklist_lock); - if (found) - retval = 0; - } - return retval; -} - -int kill_proc(int pid, int sig, int priv) -{ - int retval; - - retval = -EINVAL; - if (sig >= 0 && sig <= 32) { - struct task_struct *p = find_task_by_pid(pid); - - if(p) - retval = send_sig(sig, p, priv); - else - retval = -ESRCH; - } - return retval; -} - -/* - * POSIX specifies that kill(-1,sig) is unspecified, but what we have - * is probably wrong. Should make it like BSD or SYSV. - */ -asmlinkage int sys_kill(int pid,int sig) -{ - if (!pid) - return kill_pg(current->pgrp,sig,0); - - if (pid == -1) { - int retval = 0, count = 0; - struct task_struct * p; - - read_lock(&tasklist_lock); - for_each_task(p) { - if (p->pid > 1 && p != current) { - int err; - ++count; - if ((err = send_sig(sig,p,0)) != -EPERM) - retval = err; - } - } - read_unlock(&tasklist_lock); - return count ? retval : -ESRCH; - } - if (pid < 0) - return kill_pg(-pid,sig,0); - - /* Normal kill */ - return kill_proc(pid,sig,0); -} - -/* * Determine if a process group is "orphaned", according to the POSIX * definition in 2.2.2.52. Orphaned process groups are not to be affected * by terminal-generated stop signals. Newly orphaned process groups are @@ -398,7 +190,7 @@ void exit_files(struct task_struct *tsk) { - __exit_files(tsk); + __exit_files(tsk); } static inline void __exit_fs(struct task_struct *tsk) @@ -417,7 +209,7 @@ void exit_fs(struct task_struct *tsk) { - __exit_fs(tsk); + __exit_fs(tsk); } static inline void __exit_sighand(struct task_struct *tsk) @@ -429,6 +221,8 @@ if (atomic_dec_and_test(&sig->count)) kfree(sig); } + + flush_signals(tsk); } void exit_sighand(struct task_struct *tsk) @@ -527,9 +321,11 @@ { if (in_interrupt()) printk("Aiee, killing interrupt handler\n"); + if (current == task[0]) + panic("Attempted to kill the idle task!"); fake_volatile: - acct_process(code); current->flags |= PF_EXITING; + acct_process(code); del_timer(¤t->real_timer); sem_exit(); kerneld_exit(); diff -u --recursive --new-file v2.1.67/linux/kernel/fork.c linux/kernel/fork.c --- v2.1.67/linux/kernel/fork.c Wed Oct 15 16:04:24 1997 +++ linux/kernel/fork.c Sun Nov 30 10:59:03 1997 @@ -459,7 +459,7 @@ p->did_exec = 0; p->swappable = 0; p->state = TASK_UNINTERRUPTIBLE; - p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPRIV); + p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPRIV|PF_SIGPENDING); p->flags |= PF_FORKNOEXEC; p->pid = get_pid(clone_flags); p->next_run = NULL; @@ -467,7 +467,9 @@ p->p_pptr = p->p_opptr = current; p->p_cptr = NULL; init_waitqueue(&p->wait_chldexit); - p->signal = 0; + sigemptyset(¤t->signal); + p->sigqueue = NULL; + p->sigqueue_tail = &p->sigqueue; p->it_real_value = p->it_virt_value = p->it_prof_value = 0; p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0; init_timer(&p->real_timer); diff -u --recursive --new-file v2.1.67/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.67/linux/kernel/ksyms.c Sat Nov 29 11:25:12 1997 +++ linux/kernel/ksyms.c Sun Nov 30 10:59:03 1997 @@ -331,9 +331,6 @@ EXPORT_SYMBOL(loops_per_sec); EXPORT_SYMBOL(need_resched); EXPORT_SYMBOL(kstat); -EXPORT_SYMBOL(kill_proc); -EXPORT_SYMBOL(kill_pg); -EXPORT_SYMBOL(kill_sl); /* misc */ EXPORT_SYMBOL(panic); @@ -352,9 +349,6 @@ EXPORT_SYMBOL(_ctype); EXPORT_SYMBOL(secure_tcp_sequence_number); EXPORT_SYMBOL(get_random_bytes); - -/* Signal interfaces */ -EXPORT_SYMBOL(send_sig); /* Program loader interfaces */ EXPORT_SYMBOL(setup_arg_pages); diff -u --recursive --new-file v2.1.67/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.67/linux/kernel/sched.c Mon Oct 20 10:36:53 1997 +++ linux/kernel/sched.c Sun Nov 30 10:59:03 1997 @@ -85,8 +85,6 @@ unsigned long prof_len = 0; unsigned long prof_shift = 0; -#define _S(nr) (1<<((nr)-1)) - extern void mem_use(void); unsigned long volatile jiffies=0; @@ -1419,28 +1417,6 @@ return 0; } -/* - * change timeval to jiffies, trying to avoid the - * most obvious overflows.. - */ -static unsigned long timespectojiffies(struct timespec *value) -{ - unsigned long sec = (unsigned) value->tv_sec; - long nsec = value->tv_nsec; - - if (sec > (LONG_MAX / HZ)) - return LONG_MAX; - nsec += 1000000000L / HZ - 1; - nsec /= 1000000000L / HZ; - return HZ * sec + nsec; -} - -static void jiffiestotimespec(unsigned long jiffies, struct timespec *value) -{ - value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ); - value->tv_sec = jiffies / HZ; -} - asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) { struct timespec t; @@ -1466,7 +1442,7 @@ return 0; } - expire = timespectojiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies; + expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies; current->timeout = expire; current->state = TASK_INTERRUPTIBLE; @@ -1474,8 +1450,8 @@ if (expire > jiffies) { if (rmtp) { - jiffiestotimespec(expire - jiffies - - (expire > jiffies + 1), &t); + jiffies_to_timespec(expire - jiffies - + (expire > jiffies + 1), &t); if (copy_to_user(rmtp, &t, sizeof(struct timespec))) return -EFAULT; } @@ -1524,6 +1500,19 @@ printk(" %5d\n", p->p_osptr->pid); else printk("\n"); + + { + extern char * render_sigset_t(sigset_t *set, char *buffer); + struct signal_queue *q; + char s[sizeof(sigset_t)*2+1], b[sizeof(sigset_t)*2+1]; + + render_sigset_t(&p->signal, s); + render_sigset_t(&p->blocked, b); + printk("\tsig: %d %s %s :", signal_pending(p), s, b); + for (q = p->sigqueue; q ; q = q->next) + printk(" %d", q->info.si_signo); + printk(" X\n"); + } } void show_state(void) diff -u --recursive --new-file v2.1.67/linux/kernel/signal.c linux/kernel/signal.c --- v2.1.67/linux/kernel/signal.c Wed Apr 23 19:01:29 1997 +++ linux/kernel/signal.c Sun Nov 30 10:59:03 1997 @@ -2,8 +2,11 @@ * linux/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson */ +#include #include #include #include @@ -14,192 +17,921 @@ #include #include #include +#include #include -#define _S(nr) (1<<((nr)-1)) +/* + * SLAB caches for signal bits. + */ -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define DEBUG_SIG 0 + +#if DEBUG_SIG +#define SIG_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */) +#else +#define SIG_SLAB_DEBUG 0 +#endif + +static kmem_cache_t *signal_queue_cachep; + +void +signals_init(void) +{ + signal_queue_cachep = + kmem_cache_create("signal_queue", + sizeof(struct signal_queue), + __alignof__(struct signal_queue), + SIG_SLAB_DEBUG, NULL, NULL); +} -#ifndef __alpha__ /* - * This call isn't used by all ports, in particular, the Alpha - * uses osf_sigprocmask instead. Maybe it should be moved into - * arch-dependent dir? + * Flush all pending signals for a task. + */ + +void +flush_signals(struct task_struct *t) +{ + struct signal_queue *q, *n; + + t->flags &= ~PF_SIGPENDING; + sigemptyset(&t->signal); + q = t->sigqueue; + t->sigqueue = NULL; + t->sigqueue_tail = &t->sigqueue; + + while (q) { + n = q->next; + kmem_cache_free(signal_queue_cachep, q); + q = n; + } +} + +/* + * Flush all handlers for a task. + */ + +void +flush_signal_handlers(struct task_struct *t) +{ + memset(t->sig->action, 0, sizeof(t->sig->action)); +} + +/* + * Dequeue a signal and return the element to the caller, which is + * expected to free it. * + * All callers of must be holding current->sigmask_lock. + */ + +int +dequeue_signal(sigset_t *mask, siginfo_t *info) +{ + unsigned long i, *s, *m, x; + int sig = 0; + +#if DEBUG_SIG +printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid, + (current->flags & PF_SIGPENDING) != 0); +#endif + + /* Find the first desired signal that is pending. */ + s = current->signal.sig; + m = mask->sig; + switch (_NSIG_WORDS) { + default: + for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m) + if ((x = *s &~ *m) != 0) { + sig = ffz(~x) + i*_NSIG_BPW + 1; + break; + } + break; + + case 2: if ((x = s[0] &~ m[0]) != 0) + sig = 1; + else if ((x = s[1] &~ m[0]) != 0) + sig = _NSIG_BPW + 1; + else + break; + sig += ffz(~x); + break; + + case 1: if ((x = *s &~ *m) != 0) sig = ffz(~x) + 1; + break; + } + + if (sig) { + int reset = 1; + + /* Collect the siginfo appropriate to this signal. */ + if (sig < SIGRTMIN) { + /* XXX: As an extension, support queueing exactly + one non-rt signal if SA_SIGINFO is set, so that + we can get more detailed information about the + cause of the signal. */ + /* Deciding not to init these couple of fields is + more expensive that just initializing them. */ + info->si_signo = sig; + info->si_errno = 0; + info->si_code = 0; + info->si_pid = 0; + info->si_uid = 0; + } else { + struct signal_queue *q, **pp; + pp = ¤t->sigqueue; + q = current->sigqueue; + + /* Find the one we're interested in ... */ + for ( ; q ; pp = &q->next, q = q->next) + if (q->info.si_signo == sig) + break; + if (q) { + if ((*pp = q->next) == NULL) + current->sigqueue_tail = pp; + *info = q->info; + kmem_cache_free(signal_queue_cachep,q); + + /* then see if this signal is still pending. */ + q = *pp; + while (q) { + if (q->info.si_signo == sig) { + reset = 0; + break; + } + q = q->next; + } + } else { + /* Ok, it wasn't in the queue. It must have + been sent either by a non-rt mechanism and + we ran out of queue space. So zero out the + info. */ + info->si_signo = sig; + info->si_errno = 0; + info->si_code = 0; + info->si_pid = 0; + info->si_uid = 0; + } + } + + if (reset) + sigdelset(¤t->signal, sig); + recalc_sigpending(current); + + /* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER, + we need to xchg out the timer overrun values. */ + } else { + /* XXX: Once CLONE_PID is in to join those "threads" that are + part of the same "process", look for signals sent to the + "process" as well. */ + + /* Sanity check... */ + if (mask == ¤t->blocked && + (current->flags & PF_SIGPENDING) != 0) { + printk(KERN_CRIT "SIG: sigpending lied\n"); + current->flags &= ~PF_SIGPENDING; + } + } + +#if DEBUG_SIG +printk(" %d -> %d\n", (current->flags & PF_SIGPENDING) != 0, sig); +#endif + + return sig; +} + +int +send_sig_info(int sig, struct siginfo *info, struct task_struct *t) +{ + struct k_sigaction *ka; + unsigned long flags; + int ret; + +#if DEBUG_SIG +printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); +#endif + + ret = -EINVAL; + if (sig < 0 || sig > _NSIG) + goto out_nolock; + + /* If t->sig is gone, we must be trying to kill the task. So + pretend that it doesn't exist anymore. */ + ret = -ESRCH; + if (t->sig == NULL) + goto out_nolock; + + /* The somewhat baroque permissions check... */ + ret = -EPERM; + if ((!info || ((unsigned long)info != 1 && SI_FROMUSER(info))) + && ((sig != SIGCONT) || (current->session != t->session)) + && (current->euid ^ t->suid) && (current->euid ^ t->uid) + && (current->uid ^ t->suid) && (current->uid ^ t->uid) + && !suser()) + goto out_nolock; + + /* The null signal is a permissions and process existance probe. + No signal is actually delivered. */ + ret = 0; + if (!sig) + goto out_nolock; + + ka = &t->sig->action[sig-1]; + spin_lock_irqsave(&t->sigmask_lock, flags); + + switch (sig) { + case SIGKILL: case SIGCONT: + /* Wake up the process if stopped. */ + if (t->state == TASK_STOPPED) + wake_up_process(t); + t->exit_code = 0; + sigdelsetmask(&t->signal, (sigmask(SIGSTOP)|sigmask(SIGTSTP)| + sigmask(SIGTTOU)|sigmask(SIGTTIN))); + /* Inflict this corner case with recalculaions, not mainline */ + recalc_sigpending(t); + break; + + case SIGSTOP: case SIGTSTP: + case SIGTTIN: case SIGTTOU: + /* If we're stopping again, cancel SIGCONT */ + sigdelset(&t->signal, SIGCONT); + /* Inflict this corner case with recalculaions, not mainline */ + recalc_sigpending(t); + break; + } + + /* Optimize away the signal, if it's a signal that can be + handled immediately (ie non-blocked and untraced) and + that is ignored (either explicitly or by default). */ + + if (!(t->flags & PF_PTRACED) && !sigismember(&t->blocked, sig) + /* Don't bother with ignored sigs (SIGCHLD is special) */ + && ((ka->sa.sa_handler == SIG_IGN && sig != SIGCHLD) + /* Some signals are ignored by default.. (but SIGCONT + already did its deed) */ + || (ka->sa.sa_handler == SIG_DFL + && (sig == SIGCONT || sig == SIGCHLD + || sig == SIGWINCH || sig == SIGURG)))) { + goto out; + } + + if (sig < SIGRTMIN) { + /* Non-real-time signals are not queued. */ + /* XXX: As an extension, support queueing exactly one + non-rt signal if SA_SIGINFO is set, so that we can + get more detailed information about the cause of + the signal. */ + if (sigismember(&t->signal, sig)) + goto out; + } else { + /* Real-time signals must be queued if sent by sigqueue, or + some other real-time mechanism. It is implementation + defined whether kill() does so. We attempt to do so, on + the principle of least surprise, but since kill is not + allowed to fail with EAGAIN when low on memory we just + make sure at least one signal gets delivered and don't + pass on the info struct. */ + + struct signal_queue *q = (struct signal_queue *) + kmem_cache_alloc(signal_queue_cachep, GFP_KERNEL); + + if (q) { + q->next = NULL; + *t->sigqueue_tail = q; + t->sigqueue_tail = &q->next; + switch ((unsigned long) info) { + case 0: + q->info.si_signo = sig; + q->info.si_errno = 0; + q->info.si_code = SI_USER; + q->info.si_pid = current->pid; + q->info.si_uid = current->uid; + break; + case 1: + q->info.si_signo = sig; + q->info.si_errno = 0; + q->info.si_code = SI_KERNEL; + q->info.si_pid = 0; + q->info.si_uid = 0; + break; + default: + q->info = *info; + break; + } + } else { + /* If this was sent by a rt mechanism, try again. */ + if (info->si_code < 0) { + ret = -EAGAIN; + goto out; + } + /* Otherwise, mention that the signal is pending, + but don't queue the info. */ + } + } + + sigaddset(&t->signal, sig); + if (!sigismember(&t->blocked, sig)) + t->flags |= PF_SIGPENDING; + +out: + spin_unlock_irqrestore(&t->sigmask_lock, flags); + if (t->state == TASK_INTERRUPTIBLE && signal_pending(t)) + wake_up_process(t); + +out_nolock: +#if DEBUG_SIG +printk(" %d -> %d\n", (t->flags & PF_SIGPENDING) != 0, ret); +#endif + + return ret; +} + +/* + * Force a signal that the process can't ignore: if necessary + * we unblock the signal and change any SIG_IGN to SIG_DFL. + */ + +int +force_sig_info(int sig, struct siginfo *info, struct task_struct *t) +{ + if (t->sig == NULL) + return -ESRCH; + + if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN) + t->sig->action[sig-1].sa.sa_handler = SIG_DFL; + sigdelset(&t->blocked, sig); + + return send_sig_info(sig, info, t); +} + +/* + * kill_pg() sends a signal to a process group: this is what the tty + * control characters do (^C, ^Z etc) + */ + +int +kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) +{ + int retval = -EINVAL; + if (pgrp > 0) { + struct task_struct *p; + int found = 0; + + retval = -ESRCH; + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->pgrp == pgrp) { + int err = send_sig_info(sig, info, p); + if (err != 0) + retval = err; + else + found++; + } + } + read_unlock(&tasklist_lock); + if (found) + retval = 0; + } + return retval; +} + +/* + * kill_sl() sends a signal to the session leader: this is used + * to send SIGHUP to the controlling process of a terminal when + * the connection is lost. + */ + +int +kill_sl_info(int sig, struct siginfo *info, pid_t sess) +{ + int retval = -EINVAL; + if (sess > 0) { + struct task_struct *p; + int found = 0; + + retval = -ESRCH; + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->leader && p->session == sess) { + int err = send_sig_info(sig, info, p); + if (err) + retval = err; + else + found++; + } + } + read_unlock(&tasklist_lock); + if (found) + retval = 0; + } + return retval; +} + +inline int +kill_proc_info(int sig, struct siginfo *info, pid_t pid) +{ + struct task_struct *p = find_task_by_pid(pid); + return p ? send_sig_info(sig, info, p) : -ESRCH; +} + +/* + * kill_something() interprets pid in interesting ways just like kill(2). + * + * POSIX specifies that kill(-1,sig) is unspecified, but what we have + * is probably wrong. Should make it like BSD or SYSV. + */ + +int +kill_something_info(int sig, struct siginfo *info, int pid) +{ + if (!pid) { + return kill_pg_info(sig, info, current->pgrp); + } else if (pid == -1) { + int retval = 0, count = 0; + struct task_struct * p; + + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->pid > 1 && p != current) { + int err = send_sig_info(sig, info, p); + ++count; + if (err != -EPERM) + retval = err; + } + } + read_unlock(&tasklist_lock); + return count ? retval : -ESRCH; + } else if (pid < 0) { + return kill_pg_info(sig, info, -pid); + } else { + return kill_proc_info(sig, info, pid); + } +} + +/* + * These are for backward compatibility with the rest of the kernel source. + */ + +int +send_sig(int sig, struct task_struct *p, int priv) +{ + return send_sig_info(sig, (void*)(long)(priv != 0), p); +} + +void +force_sig(int sig, struct task_struct *p) +{ + force_sig_info(sig, (void*)1L, p); +} + +int +kill_pg(pid_t pgrp, int sig, int priv) +{ + return kill_pg_info(sig, (void *)(long)(priv != 0), pgrp); +} + +int +kill_sl(pid_t sess, int sig, int priv) +{ + return kill_sl_info(sig, (void *)(long)(priv != 0), sess); +} + +int +kill_proc(pid_t pid, int sig, int priv) +{ + return kill_proc_info(sig, (void *)(long)(priv != 0), pid); +} + +/* + * Let a parent know about a status change of a child. + */ + +void +notify_parent(struct task_struct *tsk, int sig) +{ + struct siginfo info; + int why; + + info.si_signo = sig; + info.si_errno = 0; + info.si_pid = tsk->pid; + + /* FIXME: find out whether or not this is supposed to be c*time. */ + info.si_utime = tsk->times.tms_utime; + info.si_stime = tsk->times.tms_stime; + + why = SI_KERNEL; /* shouldn't happen */ + switch (tsk->state) { + case TASK_ZOMBIE: + if (tsk->exit_code & 0x80) + why = CLD_DUMPED; + else if (tsk->exit_code & 0x7f) + why = CLD_KILLED; + else + why = CLD_EXITED; + break; + case TASK_STOPPED: + /* FIXME -- can we deduce CLD_TRAPPED or CLD_CONTINUED? */ + why = CLD_STOPPED; + break; + + default: + printk(KERN_DEBUG "eh? notify_parent with state %ld?\n", + tsk->state); + break; + } + info.si_code = why; + + send_sig_info(sig, &info, tsk->p_pptr); + wake_up_interruptible(&tsk->p_pptr->wait_chldexit); +} + +EXPORT_SYMBOL(dequeue_signal); +EXPORT_SYMBOL(flush_signals); +EXPORT_SYMBOL(force_sig); +EXPORT_SYMBOL(force_sig_info); +EXPORT_SYMBOL(kill_pg); +EXPORT_SYMBOL(kill_pg_info); +EXPORT_SYMBOL(kill_proc); +EXPORT_SYMBOL(kill_proc_info); +EXPORT_SYMBOL(kill_sl); +EXPORT_SYMBOL(kill_sl_info); +EXPORT_SYMBOL(notify_parent); +EXPORT_SYMBOL(recalc_sigpending); +EXPORT_SYMBOL(send_sig); +EXPORT_SYMBOL(send_sig_info); + + +/* + * System call entry points. + */ + +/* * We don't need to get the kernel lock - this is all local to this * particular thread.. (and that's good, because this is _heavily_ * used by various programs) - * - * No SMP locking would prevent the inherent races present in this - * routine, thus we do not perform any locking at all. */ -asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) + +asmlinkage int +sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize) { - sigset_t old_set = current->blocked; + sigset_t old_set, new_set; - if (set) { - sigset_t new_set; + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; - if(get_user(new_set, set)) + if (set) { + if (copy_from_user(&new_set, set, sizeof(*set))) return -EFAULT; + sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); + + spin_lock_irq(¤t->sigmask_lock); + old_set = current->blocked; - new_set &= _BLOCKABLE; switch (how) { default: return -EINVAL; case SIG_BLOCK: - new_set |= old_set; + sigorsets(&new_set, &old_set, &new_set); break; case SIG_UNBLOCK: - new_set = old_set & ~new_set; + signandsets(&new_set, &old_set, &new_set); break; case SIG_SETMASK: break; } + current->blocked = new_set; - } - if (oset) { - if(put_user(old_set, oset)) + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (oset) { + if (copy_to_user(oset, &old_set, sizeof(*oset))) + return -EFAULT; + } + } else if (oset) { + spin_lock_irq(¤t->sigmask_lock); + old_set = current->blocked; + spin_unlock_irq(¤t->sigmask_lock); + + if (copy_to_user(oset, &old_set, sizeof(*oset))) return -EFAULT; } + return 0; } -/* - * For backwards compatibility? Functionality superseded by sigprocmask. - */ -asmlinkage int sys_sgetmask(void) +asmlinkage int +sys_rt_sigpending(sigset_t *set, size_t sigsetsize) { - /* SMP safe */ - return current->blocked; -} + sigset_t pending; -asmlinkage int sys_ssetmask(int newmask) -{ - int old; + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; spin_lock_irq(¤t->sigmask_lock); - old = current->blocked; - current->blocked = newmask & _BLOCKABLE; + sigandsets(&pending, ¤t->blocked, ¤t->signal); spin_unlock_irq(¤t->sigmask_lock); - return old; + return copy_to_user(set, &pending, sizeof(*set)); } -#endif - -asmlinkage int sys_sigpending(sigset_t *set) +asmlinkage int +sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, + const struct timespec *uts, size_t sigsetsize) { - int ret; + sigset_t these; + struct timespec ts; + unsigned long expire; + siginfo_t info; + int ret, sig; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&these, uthese, sizeof(these))) + return -EFAULT; + else { + /* Invert the set of allowed signals to get those we + want to block. */ + signotset(&these); + } + + if (uts) { + if (copy_from_user(&ts, uts, sizeof(ts))) + return -EFAULT; + if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 + || ts.tv_sec < 0) + return -EINVAL; + } - /* fill in "set" with signals pending but blocked. */ spin_lock_irq(¤t->sigmask_lock); - ret = put_user(current->blocked & current->signal, set); + sig = dequeue_signal(&these, &info); + if (!sig) { + /* None ready -- temporarily unblock those we're interested + in so that we'll be awakened when they arrive. */ + sigset_t oldblocked = current->blocked; + sigandsets(¤t->blocked, ¤t->blocked, &these); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (uts) { + expire = (timespec_to_jiffies(&ts) + + (ts.tv_sec || ts.tv_nsec)); + expire += jiffies; + current->timeout = expire; + } + + current->state = TASK_INTERRUPTIBLE; + schedule(); + + spin_lock_irq(¤t->sigmask_lock); + sig = dequeue_signal(&these, &info); + current->blocked = oldblocked; + recalc_sigpending(current); + } spin_unlock_irq(¤t->sigmask_lock); + + if (sig) { + ret = sig; + if (uinfo) { + if (copy_to_user(uinfo, &info, sizeof(siginfo_t))) + ret = -EFAULT; + } + } else { + ret = !uts || expire > jiffies ? -EINTR : -EAGAIN; + } + return ret; } -/* - * POSIX 3.3.1.3: - * "Setting a signal action to SIG_IGN for a signal that is pending - * shall cause the pending signal to be discarded, whether or not - * it is blocked." - * - * "Setting a signal action to SIG_DFL for a signal that is pending - * and whose default action is to ignore the signal (for example, - * SIGCHLD), shall cause the pending signal to be discarded, whether - * or not it is blocked" - * - * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal - * isn't actually ignored, but does automatic child reaping, while - * SIG_DFL is explicitly said by POSIX to force the signal to be ignored.. - * - * All callers of check_pending must be holding current->sig->siglock. - */ -inline void check_pending(int signum) +asmlinkage int +sys_kill(int pid, int sig) { - struct sigaction *p; + struct siginfo info; + + info.si_signo = sig; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->pid; + info.si_uid = current->uid; - p = signum - 1 + current->sig->action; - spin_lock(¤t->sigmask_lock); - if (p->sa_handler == SIG_IGN) { - current->signal &= ~_S(signum); - } else if (p->sa_handler == SIG_DFL) { - if (signum == SIGCONT || - signum == SIGCHLD || - signum != SIGWINCH) - current->signal &= ~_S(signum); - } - spin_unlock(¤t->sigmask_lock); + return kill_something_info(sig, &info, pid); } -#ifndef __alpha__ -/* - * For backwards compatibility? Functionality superseded by sigaction. - */ -asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler) +asmlinkage int +sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo) { - struct sigaction tmp; + siginfo_t info; - if (signum<1 || signum>32) - return -EINVAL; - if (signum==SIGKILL || signum==SIGSTOP) + if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) + return -EFAULT; + + /* Not even root can pretend to send signals from the kernel. + Nor can they impersonate a kill(), which adds source info. */ + if (info.si_code >= 0) + return -EPERM; + + /* POSIX.1b doesn't mention process groups. */ + return kill_proc_info(sig, &info, pid); +} + +int +do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) +{ + struct k_sigaction *k; + + if (sig < 1 || sig > _NSIG || + (act && (sig == SIGKILL || sig == SIGSTOP))) return -EINVAL; - if (handler != SIG_DFL && handler != SIG_IGN) { - if(verify_area(VERIFY_READ, handler, 1)) + + spin_lock_irq(¤t->sigmask_lock); + k = ¤t->sig->action[sig-1]; + + if (oact) *oact = *k; + + if (act) { + *k = *act; + + /* + * POSIX 3.3.1.3: + * "Setting a signal action to SIG_IGN for a signal that is + * pending shall cause the pending signal to be discarded, + * whether or not it is blocked." + * + * "Setting a signal action to SIG_DFL for a signal that is + * pending and whose default action is to ignore the signal + * (for example, SIGCHLD), shall cause the pending signal to + * be discarded, whether or not it is blocked" + * + * Note the silly behaviour of SIGCHLD: SIG_IGN means that the + * signal isn't actually ignored, but does automatic child + * reaping, while SIG_DFL is explicitly said by POSIX to force + * the signal to be ignored. + */ + + if (k->sa.sa_handler == SIG_IGN + || (k->sa.sa_handler == SIG_DFL + && (sig == SIGCONT || + sig == SIGCHLD || + sig != SIGWINCH))) { + /* So dequeue any that might be pending. + XXX: process-wide signals? */ + if (sig >= SIGRTMIN && + sigismember(¤t->signal, sig)) { + struct signal_queue *q, **pp; + pp = ¤t->sigqueue; + q = current->sigqueue; + while (q) { + if (q->info.si_signo != sig) + pp = &q->next; + else { + *pp = q->next; + kmem_cache_free(signal_queue_cachep, q); + } + q = *pp; + } + + } + sigdelset(¤t->signal, sig); + recalc_sigpending(current); + } + } + + spin_unlock_irq(¤t->sigmask_lock); + + return 0; +} + +#if !defined(__alpha__) +/* Alpha has its own versions with special arguments. */ + +asmlinkage int +sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset) +{ + old_sigset_t old_set, new_set; + + if (set) { + if (copy_from_user(&new_set, set, sizeof(*set))) + return -EFAULT; + new_set &= ~(sigmask(SIGKILL)|sigmask(SIGSTOP)); + + spin_lock_irq(¤t->sigmask_lock); + old_set = current->blocked.sig[0]; + + switch (how) { + default: + return -EINVAL; + case SIG_BLOCK: + sigaddsetmask(¤t->blocked, new_set); + break; + case SIG_UNBLOCK: + sigdelsetmask(¤t->blocked, new_set); + break; + case SIG_SETMASK: + siginitset(¤t->blocked, new_set); + break; + } + + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (oset) { + if (copy_to_user(oset, &old_set, sizeof(*oset))) + return -EFAULT; + } + } else if (oset) { + old_set = current->blocked.sig[0]; + if (copy_to_user(oset, &old_set, sizeof(*oset))) return -EFAULT; } - memset(&tmp, 0, sizeof(tmp)); - tmp.sa_handler = handler; - tmp.sa_flags = SA_ONESHOT | SA_NOMASK; + return 0; +} + +asmlinkage int +sys_sigpending(old_sigset_t *set) +{ + old_sigset_t pending; - spin_lock_irq(¤t->sig->siglock); - handler = current->sig->action[signum-1].sa_handler; - current->sig->action[signum-1] = tmp; - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); + spin_lock_irq(¤t->sigmask_lock); + pending = current->blocked.sig[0] & current->signal.sig[0]; + spin_unlock_irq(¤t->sigmask_lock); - return (unsigned long) handler; + return copy_to_user(set, &pending, sizeof(*set)); } -#endif -#ifndef __sparc__ -asmlinkage int sys_sigaction(int signum, const struct sigaction * action, - struct sigaction * oldaction) +asmlinkage int +sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, + size_t sigsetsize) { - struct sigaction new_sa, *p; + struct k_sigaction new_sa, old_sa; + int ret; - if (signum < 1 || signum > 32) + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) return -EINVAL; - p = signum - 1 + current->sig->action; - - if (action) { - if (copy_from_user(&new_sa, action, sizeof(struct sigaction))) + if (act) { + if (copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa))) return -EFAULT; - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; } - if (oldaction) { - /* In the clone() case we could copy half consistant - * state to the user, however this could sleep and - * deadlock us if we held the signal lock on SMP. So for - * now I take the easy way out and do no locking. - */ - if (copy_to_user(oldaction, p, sizeof(struct sigaction))) + ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); + + if (!ret && oact) { + if (copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa))) return -EFAULT; } - if (action) { - spin_lock_irq(¤t->sig->siglock); - *p = new_sa; - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); - } - return 0; + return ret; } #endif + +#if !defined(__alpha__) +/* + * For backwards compatibility. Functionality superseded by sigprocmask. + */ +asmlinkage int +sys_sgetmask(void) +{ + /* SMP safe */ + return current->blocked.sig[0]; +} + +asmlinkage int +sys_ssetmask(int newmask) +{ + int old; + + spin_lock_irq(¤t->sigmask_lock); + old = current->blocked.sig[0]; + + siginitset(¤t->blocked, newmask & ~(sigmask(SIGKILL)| + sigmask(SIGSTOP))); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + return old; +} + +/* + * For backwards compatibility. Functionality superseded by sigaction. + */ +asmlinkage unsigned long +sys_signal(int sig, __sighandler_t handler) +{ + struct k_sigaction new_sa, old_sa; + int ret; + + new_sa.sa.sa_handler = handler; + new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; + + ret = do_sigaction(sig, &new_sa, &old_sa); + + return ret ? ret : (unsigned long)old_sa.sa.sa_handler; +} +#endif /* !alpha */ diff -u --recursive --new-file v2.1.67/linux/kernel/sys.c linux/kernel/sys.c --- v2.1.67/linux/kernel/sys.c Sat Oct 25 02:44:18 1997 +++ linux/kernel/sys.c Sun Nov 30 12:34:44 1997 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -160,8 +159,6 @@ } -extern asmlinkage int sys_kill(int, int); - /* * Reboot system call: for obvious reasons only root may call it, * and even root needs to set up some magic numbers in the registers @@ -169,7 +166,6 @@ * You can also set the meaning of the ctrl-alt-del-key here. * * reboot doesn't sync: do that yourself before calling this. - * */ asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg) { @@ -322,127 +318,6 @@ return 0; } -static char acct_active = 0; -static struct file acct_file; - -int acct_process(long exitcode) -{ - struct acct ac; - unsigned long fs; - - if (acct_active) { - strncpy(ac.ac_comm, current->comm, ACCT_COMM); - ac.ac_comm[ACCT_COMM-1] = '\0'; - ac.ac_utime = current->times.tms_utime; - ac.ac_stime = current->times.tms_stime; - ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ)); - ac.ac_etime = CURRENT_TIME - ac.ac_btime; - ac.ac_uid = current->uid; - ac.ac_gid = current->gid; - ac.ac_tty = (current)->tty == NULL ? -1 : - kdev_t_to_nr(current->tty->device); - ac.ac_flag = 0; - if (current->flags & PF_FORKNOEXEC) - ac.ac_flag |= AFORK; - if (current->flags & PF_SUPERPRIV) - ac.ac_flag |= ASU; - if (current->flags & PF_DUMPCORE) - ac.ac_flag |= ACORE; - if (current->flags & PF_SIGNALED) - ac.ac_flag |= AXSIG; - ac.ac_minflt = current->min_flt; - ac.ac_majflt = current->maj_flt; - ac.ac_exitcode = exitcode; - - /* Kernel segment override */ - fs = get_fs(); - set_fs(KERNEL_DS); - - acct_file.f_op->write(&acct_file, (char *)&ac, sizeof(struct acct), - &acct_file.f_pos); - set_fs(fs); - } - return 0; -} - -asmlinkage int sys_acct(const char *name) -{ - int error = -EPERM; - - lock_kernel(); - if (!suser()) - goto out; - - if (name == (char *)0) { - if (acct_active) { - if (acct_file.f_op->release) - acct_file.f_op->release(acct_file.f_dentry->d_inode, &acct_file); - - if (acct_file.f_dentry != NULL) - dput(acct_file.f_dentry); - - acct_active = 0; - } - error = 0; - } else { - error = -EBUSY; - if (!acct_active) { - struct dentry *dentry; - struct inode *inode; - char *tmp; - - tmp = getname(name); - error = PTR_ERR(tmp); - if (IS_ERR(tmp)) - goto out; - - dentry = open_namei(tmp, O_RDWR, 0600); - putname(tmp); - - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) - goto out; - inode = dentry->d_inode; - - error = -EACCES; - if (!S_ISREG(inode->i_mode)) { - dput(dentry); - goto out; - } - - error = -EIO; - if (!inode->i_op || !inode->i_op->default_file_ops || - !inode->i_op->default_file_ops->write) { - dput(dentry); - goto out; - } - - acct_file.f_mode = 3; - acct_file.f_flags = 0; - acct_file.f_count = 1; - acct_file.f_dentry = dentry; - acct_file.f_pos = inode->i_size; - acct_file.f_reada = 0; - acct_file.f_op = inode->i_op->default_file_ops; - - if(acct_file.f_op->open) { - error = acct_file.f_op->open(inode, &acct_file); - if (error) { - dput(dentry); - goto out; - } - } - - acct_active = 1; - error = 0; - } - } -out: - unlock_kernel(); - return error; -} - - /* * Unprivileged users may change the real uid to the effective uid * or vice versa. (BSD-style) diff -u --recursive --new-file v2.1.67/linux/mm/memory.c linux/mm/memory.c --- v2.1.67/linux/mm/memory.c Wed Sep 3 20:52:44 1997 +++ linux/mm/memory.c Sun Nov 30 10:59:03 1997 @@ -79,9 +79,7 @@ void oom(struct task_struct * task) { printk("\nOut of memory for %s.\n", task->comm); - task->sig->action[SIGKILL-1].sa_handler = NULL; - task->blocked &= ~(1<<(SIGKILL-1)); - send_sig(SIGKILL,task,1); + force_sig(SIGKILL, task); } /* diff -u --recursive --new-file v2.1.67/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.67/linux/mm/vmscan.c Sat Oct 25 02:44:18 1997 +++ linux/mm/vmscan.c Sun Nov 30 10:59:03 1997 @@ -426,7 +426,7 @@ current->session = 1; current->pgrp = 1; sprintf(current->comm, "kswapd"); - current->blocked = ~0UL; + sigfillset(¤t->blocked); /* * As a kernel thread we want to tamper with system buffers @@ -447,7 +447,7 @@ int fail; kswapd_awake = 0; - current->signal = 0; + flush_signals(current); run_task_queue(&tq_disk); interruptible_sleep_on(&kswapd_wait); kswapd_awake = 1; diff -u --recursive --new-file v2.1.67/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.67/linux/net/core/dev.c Tue Sep 23 16:48:50 1997 +++ linux/net/core/dev.c Sun Nov 30 10:30:19 1997 @@ -1613,7 +1613,9 @@ extern void dlci_setup(void); extern int pt_init(void); extern int sm_init(void); -extern int baycom_init(void); +extern int baycom_ser_fdx_init(void); +extern int baycom_ser_hdx_init(void); +extern int baycom_par_init(void); extern int lapbeth_init(void); extern void arcnet_init(void); @@ -1681,8 +1683,14 @@ #if defined(CONFIG_SDLA) sdla_setup(); #endif -#if defined(CONFIG_BAYCOM) - baycom_init(); +#if defined(CONFIG_BAYCOM_PAR) + baycom_par_init(); +#endif +#if defined(CONFIG_BAYCOM_SER_FDX) + baycom_ser_fdx_init(); +#endif +#if defined(CONFIG_BAYCOM_SER_HDX) + baycom_ser_hdx_init(); #endif #if defined(CONFIG_SOUNDMODEM) sm_init(); diff -u --recursive --new-file v2.1.67/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c --- v2.1.67/linux/net/sunrpc/clnt.c Sat Nov 29 11:25:12 1997 +++ linux/net/sunrpc/clnt.c Sun Nov 30 10:59:03 1997 @@ -60,8 +60,6 @@ static u32 * call_header(struct rpc_task *task); static u32 * call_verify(struct rpc_task *task); -#define _S(nr) (1 << ((nr) - 1)) - /* * Create an RPC client * FIXME: This should also take a flags argument (as in task->tk_flags). @@ -197,19 +195,24 @@ int flags, rpc_action func, void *data) { struct rpc_task my_task, *task = &my_task; - unsigned long oldmask, sigallow = _S(SIGKILL); + unsigned long sigallow = sigmask(SIGKILL); + sigset_t oldset; + unsigned long irqflags; int async, status; /* Turn off various signals */ if (clnt->cl_intr) { - struct sigaction *action = current->sig->action; - if (action[SIGINT-1].sa_handler == SIG_DFL) - sigallow |= _S(SIGINT); - if (action[SIGQUIT-1].sa_handler == SIG_DFL) - sigallow |= _S(SIGQUIT); - } - oldmask = current->blocked; - current->blocked |= ~sigallow; + struct k_sigaction *action = current->sig->action; + if (action[SIGINT-1].sa.sa_handler == SIG_DFL) + sigallow |= sigmask(SIGINT); + if (action[SIGQUIT-1].sa.sa_handler == SIG_DFL) + sigallow |= sigmask(SIGQUIT); + } + spin_lock_irqsave(¤t->sigmask_lock, irqflags); + oldset = current->blocked; + siginitsetinv(¤t->blocked, sigallow & ~oldset.sig[0]); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); /* Create/initialize a new RPC task */ if ((async = (flags & RPC_TASK_ASYNC)) != 0) { @@ -238,7 +241,11 @@ } out: - current->blocked = oldmask; + spin_lock_irqsave(¤t->sigmask_lock, irqflags); + current->blocked = oldset; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); + return status; } diff -u --recursive --new-file v2.1.67/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- v2.1.67/linux/net/sunrpc/sched.c Wed Oct 15 16:04:24 1997 +++ linux/net/sunrpc/sched.c Sun Nov 30 10:59:03 1997 @@ -23,8 +23,6 @@ static int rpc_task_id = 0; #endif -#define _S(signo) (1 << ((signo)-1)) - /* * We give RPC the same get_free_pages priority as NFS */ @@ -410,9 +408,7 @@ * break the loop here, but go around once more. */ if (0 && !RPC_IS_ASYNC(task) && signalled()) { - dprintk("RPC: %4d got signal (map %08lx)\n", - task->tk_pid, - current->signal & ~current->blocked); + dprintk("RPC: %4d got signal\n", task->tk_pid); rpc_exit(task, -ERESTARTSYS); } } @@ -746,7 +742,7 @@ exit_files(current); exit_mm(current); - current->blocked |= ~_S(SIGKILL); + siginitsetinv(¤t->blocked, sigmask(SIGKILL)); current->session = 1; current->pgrp = 1; sprintf(current->comm, "rpciod"); @@ -754,13 +750,13 @@ dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid); while (rpciod_users) { if (signalled()) { - if (current->signal & _S(SIGKILL)) { + if (sigismember(¤t->signal, SIGKILL)) { rpciod_killall(); } else { printk("rpciod: ignoring signal (%d users)\n", rpciod_users); } - current->signal &= current->blocked; + flush_signals(current); } __rpc_schedule(); @@ -795,17 +791,32 @@ static void rpciod_killall(void) { - while (all_tasks) { - unsigned long oldsig = current->signal; + unsigned long flags; + sigset_t old_set; + + /* FIXME: What had been going on before was saving and restoring + current->signal. This as opposed to blocking signals? Do we + still need them to wake up out of schedule? In any case it + isn't playing nice and a better way should be found. */ + + spin_lock_irqsave(¤t->sigmask_lock, flags); + old_set = current->blocked; + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); - current->signal = 0; + while (all_tasks) { rpc_killall_tasks(NULL); __rpc_schedule(); current->timeout = jiffies + HZ / 100; need_resched = 1; schedule(); - current->signal = oldsig; } + + spin_lock_irqsave(¤t->sigmask_lock, flags); + current->blocked = old_set; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); } /* @@ -846,7 +857,7 @@ void rpciod_down(void) { - unsigned long oldflags; + unsigned long flags; MOD_INC_USE_COUNT; down(&rpciod_sema); @@ -867,8 +878,7 @@ * Usually rpciod will exit very quickly, so we * wait briefly before checking the process id. */ - oldflags = current->signal; - current->signal = 0; + current->flags &= ~PF_SIGPENDING; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); @@ -884,7 +894,9 @@ } interruptible_sleep_on(&rpciod_killer); } - current->signal = oldflags; + spin_lock_irqsave(¤t->sigmask_lock, flags); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); out: up(&rpciod_sema); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.1.67/linux/net/sunrpc/svc.c linux/net/sunrpc/svc.c --- v2.1.67/linux/net/sunrpc/svc.c Wed Oct 15 16:04:24 1997 +++ linux/net/sunrpc/svc.c Sun Nov 30 10:59:03 1997 @@ -169,7 +169,8 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port) { struct svc_program *progp; - unsigned long oldsigs = 0; + unsigned long flags; + sigset_t old_set; int i, error = 0, dummy; progp = serv->sv_program; @@ -177,9 +178,17 @@ dprintk("RPC: svc_register(%s, %s, %d)\n", progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port); + /* FIXME: What had been going on before was saving and restoring + current->signal. This as opposed to blocking signals? Do we + still need them to wake up out of schedule? In any case it + isn't playing nice and a better way should be found. */ + if (!port) { - oldsigs = current->signal; - current->signal = 0; + spin_lock_irqsave(¤t->sigmask_lock, flags); + old_set = current->blocked; + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); } for (i = 0; i < progp->pg_nvers; i++) { @@ -193,7 +202,14 @@ break; } } - current->signal |= oldsigs; + + if (!port) { + spin_lock_irqsave(¤t->sigmask_lock, flags); + current->blocked = old_set; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + } + return error; }