diff -u --recursive --new-file v2.1.70/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.70/linux/Documentation/Configure.help Tue Dec 2 16:45:17 1997 +++ linux/Documentation/Configure.help Wed Dec 3 15:21:57 1997 @@ -326,6 +326,13 @@ chipsets. Most of these also require special kernel boot parameters to actually turn on the support at runtime. +Generic 4 drives/port support +CONFIG_BLK_DEV_4DRIVES + Certain older chipsets, including the Tekram 690CD, use a + single set of I/O ports at 0x1f0 to control up to four drives, + instead of the customary two drives per port. Support for this + is enabled at runtime using the "ide0=four" kernel boot parameter. + DTC-2278 support CONFIG_BLK_DEV_DTC2278 This driver is enabled at runtime using the "ide0=dtc2278" kernel @@ -351,7 +358,14 @@ "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt and drivers/block/pdc4030.c files for more info. -OPTi 82C621 support (EXPERIMENTAL) +Tekram TRM290 support (EXPERIMENTAL) +CONFIG_BLK_DEV_TRM290 + This driver adds support for bus master DMA transfers + using the Tekram TRM290 PCI IDE chip. Volunteers are + needed for further tweaking and development. + Please read the comments at the top of drivers/block/trm290.c. + +OPTi 82C621 support (EXPERIMENTAL) CONFIG_BLK_DEV_OPTI621 This driver allows use of hdparm to change the PIO timings for drives attached to an OPTi MIDE controller. @@ -4873,11 +4887,11 @@ floppies however cannot be read with this driver due to an incompatibility of the floppy controller used in an Amiga and the standard floppy controller in PCs and workstations. Read - Documentation/filesystems/affs.txt. This filesystem is also - available as a module ( = code which can be inserted in and removed - from the running kernel whenever you want). The module is called - affs.o. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say N. + Documentation/filesystems/affs.txt and fs/affs/Changes. This + filesystem is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called affs.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. If unsure, say N. ROM filesystem support CONFIG_ROMFS_FS @@ -4899,11 +4913,10 @@ Console on virtual terminal CONFIG_VT_CONSOLE - If you enable this option, all kernel messages will be sent to the - device /dev/tty which corresponds to the virtual terminal you have - visible on your display. You should say N here only if you have some - other console device, in which case you probably want to say Y to - "Console on serial port", below. If unsure, say N. + If you enable this option, by default all kernel messages will be sent + to the device /dev/tty0 which corresponds to the virtual terminal you + have visible on your display. You should say Y here unless you only + want to have the kernel messages output on a serial port. Software generated cursor CONFIG_SOFTCURSOR @@ -4932,15 +4945,12 @@ Console on serial port CONFIG_SERIAL_CONSOLE - If you enable this option, all kernel messages will be sent to the - device /dev/ttyS0 which corresponds to a serial port; this could be - useful if you attached a terminal or printer to that port. (You can - change the number of the serial port used from 0 to something else - by setting the variable CONFIG_SERIAL_CONSOLE_PORT.) You can use - this option in combination with the option "Console on virtual - terminal" above, in which case you get the output on both the serial - port and on your display. Most people say N here so that they can - use the serial port for modem, mouse or some other device. + If you enable this option, it is possible to use a serial port as the + console. By default still the virtual console will be used at the + system console but you can alter that using a kernel command line + option. If you don't have a VGA card installed the kernel will + automatically use /dev/ttyS0 as system console if this option is + enabled. Comtrol Rocketport support CONFIG_ROCKETPORT diff -u --recursive --new-file v2.1.70/linux/Documentation/filesystems/affs.txt linux/Documentation/filesystems/affs.txt --- v2.1.70/linux/Documentation/filesystems/affs.txt Wed Jul 24 23:08:28 1996 +++ linux/Documentation/filesystems/affs.txt Tue Dec 2 22:25:07 1997 @@ -38,12 +38,6 @@ protect If this option is set, the protection bits cannot be altered. -uid[=uid] This sets the uid of the root directory (i. e. the mount point - to uid or to the uid of the current user, if the =uid is - omitted. - -gid[=gid] Same as above, but for gid. - setuid[=uid] This sets the owner of all files and directories in the file system to uid or the uid of the current user, respectively. @@ -69,7 +63,7 @@ mode changes. verbose The volume name, file system type and block size will - be written to the syslog. + be written to the syslog when the filesystem is mounted. prefix=path Path will be prefixed to every absolute path name of symbolic links on an AFFS partition. Default = / @@ -89,9 +83,9 @@ - If both W and D are allowed, w will be set. - - If both R and S are set, x will be set. + - E maps to x. - - H, P and E are always retained and ignored under Linux. + - H and P are always retained and ignored under Linux. - A is always reset when written. @@ -107,7 +101,7 @@ - w permission will set W and D for user, group and others. - - x permission of the user will set S for plain files. + - x permission of the user will set E for plain files. - All other flags (suid, sgid, ...) are ignored and will not be retained. @@ -152,12 +146,12 @@ Quite a few things may not work as advertised. Not everything is tested, though several hundred MB have been read and written using -this fs. - -Filenames are truncated to 30 characters without warning. +this fs. For a most up-to-date list of bugs please consult +fs/affs/Changes. -Currently there are no checks against invalid characters (':') -in filenames. +Filenames are truncated to 30 characters without warning (this +can be changed by setting the compile-time option AFFS_NO_TRUNCATE +ina include/linux/amigaffs.h). Case is ignored by the affs in filename matching, but Linux shells do care about the case. Example (with /mnt being an affs mounted fs): diff -u --recursive --new-file v2.1.70/linux/Documentation/serial-console.txt linux/Documentation/serial-console.txt --- v2.1.70/linux/Documentation/serial-console.txt Tue May 13 22:41:00 1997 +++ linux/Documentation/serial-console.txt Wed Dec 3 15:21:57 1997 @@ -1,48 +1,67 @@ Linux Serial Console -These examples are valid if you want to use /dev/ttyS1 (COM2) -as the serial console. Replace as needed. +It is possible to specify multiple devices for console output. You can +define a new kernel command line option to select which device(s) to +use for console output. -1. Tell LILO to use the serial port. +The format of this option is: + + console=device,options + + device: tty0 for the foreground virtual console + ttyX for any other virtual console + ttySx for a serial port + + options: depend on the driver. For the serial port this + defines the baudrate/parity/bits of the port, + in the format BBBBPN, where BBBB is the speed, + P is parity (n/o/e), and N is bits. Default is + 9600n8. The maximum baudrate is 115200. + +You can specify multiple console= options on the kernel command line. +Output will appear on all of them. The first device will be used when +you open /dev/console. So, for example: + + console=tty0 console=ttyS1,9600 + +defines that opening /dev/console will get you the current foreground +virtual console, and kernel messages will appear on both the VGA +console and the 2nd serial port (ttyS1 or COM2) at 9600 baud. + +Note that you can only define one console per device type (serial, video). + +If no console device is specified, the first device found capable of +acting as a system console will be used. At this time, the system +first looks for a VGA card and then for a serial port. So if you don't +have a VGA card in your system the first serial port will automatically +become the console. + +You will need to create a new device to use /dev/console. The official +/dev/console is now character device 5,1. + +Here's an example that will use /dev/ttyS1 (COM2) as the console. +Replace the sample values as needed. + +1. Create /dev/console (real console) and /dev/tty0 (master virtual + console): + + cd /dev + rm -f console tty0 + mknod -m 622 console c 5 1 + mknod -m 622 tty0 c 4 0 + +2. LILO can also take input from a serial device. This is a very + useful option. To tell LILO to use the serial port: In lilo.conf (global section): serial = 1,9600n8 (ttyS1, 9600 bd, no parity, 8 bits) -2. Adjust to kernel flags for the new kernel, +3. Adjust to kernel flags for the new kernel, again in lilo.conf (kernel section) - append = "console=1,9600,n8" - - (Note the extra comma needed if you want to supply parity/framing - information.) - -3. Link /dev/console to the serial port. + append = "console=ttyS1,9600" - Your probably want to save your old /dev/console (the "master" virtual - console). Check if it is a symbolic link first. If not, `mv' it to - `/dev/tty0': - - ls -l /dev/console - mv /dev/console /dev/tty0 - - Now link the serial port you are going to use as the console to - /dev/console, for example ttyS1: - - ln -s /dev/ttyS1 /dev/console - - On some systems you might want to edit your bootup scripts to make sure - they don't reset this arrangement on boot. (On Debian, check - /etc/rc.boot/console and /etc/default/console). You probably also want - to put a getty on either /dev/console or /dev/ttyS1. - -4. Init and /dev/console. - Sysvinit will open /dev/console on boot. If this does not point - to the serial console device, the startup messages will be printed - to the wrong device. The kernel also passes the environment variable - "CONSOLE" to the init program. sysvinit-2.64 reckognizes this, and - opens that device instead. Boot scripts as mentioned in (3) can - also check this variable to see what device the system console is. - If CONSOLE is not set you can assume the console is /dev/tty0. +4. Init and /etc/ioctl.save Sysvinit remembers its stty settings in a file in /etc, called `/etc/ioctl.save'. REMOVE THIS FILE before using the serial @@ -51,28 +70,25 @@ 5. /dev/console and X Programs that want to do something with the virtual console usually - open /dev/console. XF86 does this, and probably SVGALIB as well. - IMO this is wrong; they should open /dev/tty0. - I have binary patched /usr/bin/X11/XF86_SVGA to use "tty0" - instead of "console". - -6. Notes. - - If you compile the next little program, you will be able - to really "halt" the system. It will enter a little - monitor :) - - main() { reboot(0xfee1dead, 672274793, 0xCDEF0123); } - - This is just a call to the new "halt" function that later - kernels have. This is included the "halt" command of - the recent sysvinit versions. - - The monitor will also be entered at a kernel panic, or - when you press "break". That last function does not - work at the moment I think, but it would be useful for - kernel debugging. You don't have alt-scrollock on a serial - console to find out the current EIP... + open /dev/console. If you have created the new /dev/console device, + and your console is NOT the virtual console some programs will fail. + Those are programs that want to access the VT interface, and use + /dev/console instead of /dev/tty0. Some of those programs are: + + Xfree86, svgalib, gpm, SVGATextMode + + I have binary patched the above mentioned programs to use "tty0" + instead of "console". This will be reported to the maintainers of + said programs. + + Note that if you boot without a console= option (or with + console=/dev/tty0), /dev/console is the same as /dev/tty0. In that + case everything will still work. + +6. Thanks + + Thanks to Geert Uytterhoeven + for porting the patches from 2.1.4x to 2.1.6x for taking care of + the integration of these patches into m68k, ppc and alpha. -Miquel van Smoorenburg , 21-Jun-1996 -Stephen C. Tweedie , 23-Dec-1996 +Miquel van Smoorenburg , 03-Dec-1997 diff -u --recursive --new-file v2.1.70/linux/Makefile linux/Makefile --- v2.1.70/linux/Makefile Tue Dec 2 16:45:17 1997 +++ linux/Makefile Wed Dec 3 17:14:04 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 70 +SUBLEVEL = 71 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) @@ -133,7 +133,7 @@ DRIVERS := $(DRIVERS) drivers/scsi/scsi.a endif -ifeq ($(CONFIG_CDROM),y) +ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR),) DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a endif @@ -310,6 +310,7 @@ if [ -f FS_MODULES ]; then inst_mod FS_MODULES fs; fi; \ if [ -f NLS_MODULES ]; then inst_mod NLS_MODULES fs; fi; \ if [ -f CDROM_MODULES ]; then inst_mod CDROM_MODULES cdrom; fi; \ + if [ -f HAM_MODULES ]; then inst_mod HAM_MODULES net; fi; \ \ ls *.o > .allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \ diff -u --recursive --new-file v2.1.70/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.70/linux/arch/alpha/config.in Tue Dec 2 16:45:17 1997 +++ linux/arch/alpha/config.in Wed Dec 3 15:17:30 1997 @@ -134,6 +134,8 @@ endmenu fi +source drivers/net/hamradio/Config.in + mainmenu_option next_comment comment 'ISDN subsystem' diff -u --recursive --new-file v2.1.70/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.1.70/linux/arch/alpha/kernel/signal.c Tue Dec 2 09:49:38 1997 +++ linux/arch/alpha/kernel/signal.c Wed Dec 3 15:26:59 1997 @@ -577,7 +577,7 @@ single_stepping = ptrace_cancel_bpt(current); - spin_lock_irq(current->sigmask_lock); + spin_lock_irq(¤t->sigmask_lock); if (!oldset) { _oldset = current->blocked; oldset = &_oldset; diff -u --recursive --new-file v2.1.70/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.1.70/linux/arch/i386/config.in Tue Dec 2 16:45:17 1997 +++ linux/arch/i386/config.in Wed Dec 3 15:17:30 1997 @@ -84,6 +84,8 @@ endmenu fi +source drivers/net/hamradio/Config.in + mainmenu_option next_comment comment 'ISDN subsystem' diff -u --recursive --new-file v2.1.70/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.70/linux/arch/i386/defconfig Tue Dec 2 16:45:17 1997 +++ linux/arch/i386/defconfig Wed Dec 3 15:34:15 1997 @@ -103,7 +103,6 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set -# CONFIG_AX25 is not set # # SCSI support @@ -184,14 +183,20 @@ # CONFIG_FDDI is not set # CONFIG_DLCI is not set # CONFIG_PPP is not set -# CONFIG_NET_RADIO is not set # CONFIG_SLIP is not set +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set # CONFIG_TR is not set # CONFIG_WAN_DRIVERS is not set # CONFIG_LAPBETHER is not set # CONFIG_X25_ASY is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# # ISDN subsystem # # CONFIG_ISDN is not set @@ -241,6 +246,7 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_MOUSE=y diff -u --recursive --new-file v2.1.70/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.1.70/linux/arch/ppc/config.in Tue Dec 2 16:45:17 1997 +++ linux/arch/ppc/config.in Wed Dec 3 15:17:30 1997 @@ -89,6 +89,7 @@ endmenu fi +source drivers/net/hamradio/Config.in mainmenu_option next_comment comment 'ISDN subsystem' diff -u --recursive --new-file v2.1.70/linux/drivers/Makefile linux/drivers/Makefile --- v2.1.70/linux/drivers/Makefile Mon Aug 18 18:19:45 1997 +++ linux/drivers/Makefile Wed Dec 3 15:17:30 1997 @@ -71,4 +71,14 @@ ALL_SUB_DIRS += ap1000 endif +# make will try to add $(MOD_SUB_DIRS).o to modules/MOD_LIST_NAME +# when MOD_LIST_NAME is set. We don't have hamradio.o and Linus +# sort-of insisted on making hamradio a subdirectory to drivers/net. +# + +ifeq ($(CONFIG_HAMRADIO),y) + SUB_DIRS += net/hamradio + MOD_SUB_DIRS += net/hamradio +endif + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.70/linux/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c --- v2.1.70/linux/drivers/ap1000/ddv.c Tue Dec 2 16:45:18 1997 +++ linux/drivers/ap1000/ddv.c Wed Dec 3 15:26:21 1997 @@ -363,7 +363,10 @@ current->session = 1; current->pgrp = 1; sprintf(current->comm, "ddv_daemon"); - current->blocked = ~0UL; /* block all signals */ + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); /* block all signals */ + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); /* Give it a realtime priority. */ current->policy = SCHED_FIFO; diff -u --recursive --new-file v2.1.70/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.1.70/linux/drivers/block/Config.in Mon Dec 1 12:04:11 1997 +++ linux/drivers/block/Config.in Wed Dec 3 04:36:30 1997 @@ -26,6 +26,7 @@ bool ' PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Tekram TRM290 DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 bool ' OPTi 82C621 enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 fi fi @@ -33,14 +34,15 @@ bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then comment 'Note: most of these also require special kernel boot parameters' - bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX - bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 - bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B + bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES + bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX + bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 + bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 + bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 fi - bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 - bool ' UMC 8672 support' CONFIG_BLK_DEV_UMC8672 + bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 + bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 fi fi fi diff -u --recursive --new-file v2.1.70/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.1.70/linux/drivers/block/Makefile Mon Dec 1 12:04:11 1997 +++ linux/drivers/block/Makefile Wed Dec 3 04:36:30 1997 @@ -129,6 +129,10 @@ L_OBJS += pdc4030.o endif +ifeq ($(CONFIG_BLK_DEV_TRM290),y) +L_OBJS += trm290.o +endif + ifeq ($(CONFIG_BLK_DEV_OPTI621),y) L_OBJS += opti621.o endif diff -u --recursive --new-file v2.1.70/linux/drivers/block/ali14xx.c linux/drivers/block/ali14xx.c --- v2.1.70/linux/drivers/block/ali14xx.c Sun Aug 4 22:12:25 1996 +++ linux/drivers/block/ali14xx.c Wed Dec 3 04:36:30 1997 @@ -211,6 +211,8 @@ ide_hwifs[1].chipset = ide_ali14xx; ide_hwifs[0].tuneproc = &ali14xx_tune_drive; ide_hwifs[1].tuneproc = &ali14xx_tune_drive; + ide_hwifs[0].mate = &ide_hwifs[1]; + ide_hwifs[1].mate = &ide_hwifs[0]; /* initialize controller registers */ if (!initRegisters()) { diff -u --recursive --new-file v2.1.70/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c --- v2.1.70/linux/drivers/block/cmd640.c Wed Nov 6 04:49:31 1996 +++ linux/drivers/block/cmd640.c Wed Dec 3 04:36:30 1997 @@ -795,6 +795,8 @@ cmd_hwif0->serialized = 1; cmd_hwif1->serialized = 1; cmd_hwif1->chipset = ide_cmd640; + cmd_hwif0->mate = cmd_hwif1; + cmd_hwif1->mate = cmd_hwif0; #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED cmd_hwif1->tuneproc = &cmd640_tune_drive; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ diff -u --recursive --new-file v2.1.70/linux/drivers/block/dtc2278.c linux/drivers/block/dtc2278.c --- v2.1.70/linux/drivers/block/dtc2278.c Sun Aug 4 22:12:25 1996 +++ linux/drivers/block/dtc2278.c Wed Dec 3 04:36:30 1997 @@ -125,4 +125,6 @@ ide_hwifs[0].drives[1].no_unmask = 1; ide_hwifs[1].drives[0].no_unmask = 1; ide_hwifs[1].drives[1].no_unmask = 1; + ide_hwifs[0].mate = &ide_hwifs[1]; + ide_hwifs[1].mate = &ide_hwifs[0]; } diff -u --recursive --new-file v2.1.70/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.70/linux/drivers/block/floppy.c Mon Dec 1 12:04:11 1997 +++ linux/drivers/block/floppy.c Tue Dec 2 22:19:33 1997 @@ -3975,6 +3975,7 @@ fdc_state[0].address = FDC1; if (fdc_state[0].address == -1) { unregister_blkdev(MAJOR_NR,"fd"); + del_timer(&fd_timeout); return -ENODEV; } #if N_FDC > 1 @@ -3983,6 +3984,7 @@ if (floppy_grab_irq_and_dma()){ unregister_blkdev(MAJOR_NR,"fd"); + del_timer(&fd_timeout); return -EBUSY; } diff -u --recursive --new-file v2.1.70/linux/drivers/block/ht6560b.c linux/drivers/block/ht6560b.c --- v2.1.70/linux/drivers/block/ht6560b.c Sun Aug 4 22:12:25 1996 +++ linux/drivers/block/ht6560b.c Wed Dec 3 04:36:30 1997 @@ -227,6 +227,8 @@ ide_hwifs[1].tuneproc = &tune_ht6560b; ide_hwifs[0].serialized = 1; ide_hwifs[1].serialized = 1; + ide_hwifs[0].mate = &ide_hwifs[1]; + ide_hwifs[1].mate = &ide_hwifs[0]; } else printk("\nht6560b: not found\n"); } diff -u --recursive --new-file v2.1.70/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.1.70/linux/drivers/block/ide-disk.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/block/ide-disk.c Wed Dec 3 04:36:30 1997 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-disk.c Version 1.02 Nov 29, 1997 + * linux/drivers/block/ide-disk.c Version 1.03 Nov 30, 1997 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -40,6 +40,7 @@ * support optional byte-swapping of all data * Version 1.01 fix previous byte-swapping code * Verions 1.02 remove ", LBA" from drive identification msgs + * Verions 1.03 fix display of id->buf_size for big-endian */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -601,6 +602,8 @@ if (drive->cyl > drive->bios_cyl) drive->bios_cyl = drive->cyl; } + /* fix byte-ordering of buffer size field */ + id->buf_size = le16_to_cpu(id->buf_size); (void) idedisk_capacity (drive); /* initialize LBA selection */ diff -u --recursive --new-file v2.1.70/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.1.70/linux/drivers/block/ide-dma.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/block/ide-dma.c Wed Dec 3 17:36:04 1997 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-dma.c Version 4.01 November 30, 1997 + * linux/drivers/block/ide-dma.c Version 4.06 December 3, 1997 * * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -64,6 +64,7 @@ * * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports. */ +#include #include #include #include @@ -75,7 +76,6 @@ #include #include #include -#include #include #include @@ -141,14 +141,20 @@ } /* - * build_dmatable() prepares a dma request. + * ide_build_dmatable() prepares a dma request. * Returns 0 if all went okay, returns 1 otherwise. + * May also be invoked from trm290.c */ -static int build_dmatable (ide_drive_t *drive) +int ide_build_dmatable (ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; struct buffer_head *bh = rq->bh; unsigned long size, addr, *table = HWIF(drive)->dmatable; +#ifdef CONFIG_BLK_DEV_TRM290 + unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290); +#else + const int is_trm290_chipset = 0; +#endif unsigned int count = 0; do { @@ -172,32 +178,40 @@ size += bh->b_size; } } - /* * Fill in the dma table, without crossing any 64kB boundaries. - * We assume 16-bit alignment of all blocks. + * The hardware requires 16-bit alignment of all blocks + * (trm290 requires 32-bit alignment). */ + if ((addr & 3)) { + printk("%s: misaligned DMA buffer\n", drive->name); + return 0; + } while (size) { if (++count >= PRD_ENTRIES) { printk("%s: DMA table too small\n", drive->name); - return 1; /* revert to PIO for this request */ + return 0; /* revert to PIO for this request */ } else { - unsigned long bcount = 0x10000 - (addr & 0xffff); + unsigned long xcount, bcount = 0x10000 - (addr & 0xffff); if (bcount > size) bcount = size; *table++ = addr; - *table++ = bcount & 0xffff; + xcount = bcount & 0xffff; + if (is_trm290_chipset) + xcount = ((xcount >> 2) - 1) << 16; + *table++ = xcount; addr += bcount; size -= bcount; } } } while (bh != NULL); if (count) { - *--table |= 0x80000000; /* set End-Of-Table (EOT) bit */ - return 0; + if (!is_trm290_chipset) + *--table |= 0x80000000; /* set End-Of-Table (EOT) bit */ + return count; } printk("%s: empty DMA table?\n", drive->name); - return 1; /* let the PIO routines handle this weirdness */ + return 0; } /* @@ -214,11 +228,13 @@ * Returns 0 if all went well. * Returns 1 if DMA read/write could not be started, in which case * the caller should revert to PIO for the current request. + * May also be invoked from trm290.c */ -static int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { - unsigned long dma_base = HWIF(drive)->dma_base; - unsigned int reading = 0; + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + unsigned int count, reading = 0; switch (func) { case ide_dma_off: @@ -243,11 +259,11 @@ printk("ide_dmaproc: unsupported func: %d\n", func); return 1; case ide_dma_read: - reading = (1 << 3); + reading = 1 << 3; case ide_dma_write: - if (build_dmatable (drive)) - return 1; - outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */ + if (!(count = ide_build_dmatable(drive))) + return 1; /* try PIO instead of DMA */ + outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */ outb(reading, dma_base); /* specify r/w */ outb(inb(dma_base+2)|0x06, dma_base+2); /* clear status bits */ if (drive->media != ide_disk) @@ -262,32 +278,85 @@ static int config_drive_for_dma (ide_drive_t *drive) { const char **list; - struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + if (id && (id->capability & 1)) { /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) - return ide_dmaproc(ide_dma_on, drive); + return hwif->dmaproc(ide_dma_on, drive); /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */ if (id->field_valid & 2) /* regular DMA */ if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) - return ide_dmaproc(ide_dma_on, drive); + return hwif->dmaproc(ide_dma_on, drive); /* Consult the list of known "good" drives */ list = good_dma_drives; while (*list) { if (!strcmp(*list++,id->model)) - return ide_dmaproc(ide_dma_on, drive); + return hwif->dmaproc(ide_dma_on, drive); } } - return ide_dmaproc(ide_dma_off_quietly, drive); + return hwif->dmaproc(ide_dma_off_quietly, drive); } +void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports) +{ + static unsigned long dmatable = 0; + static unsigned leftover = 0; + + printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dmabase, dmabase + num_ports - 1); + if (check_region(dmabase, num_ports)) { + printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n"); + return; + } + request_region(dmabase, num_ports, hwif->name); + hwif->dma_base = dmabase; + if (leftover < (PRD_ENTRIES * PRD_BYTES)) { + /* + * The BM-DMA uses full 32bit addr, so we can + * safely use __get_free_page() here instead + * of __get_dma_pages() -- no ISA limitations. + */ + dmatable = __get_free_pages(GFP_KERNEL,1,0); + leftover = dmatable ? PAGE_SIZE : 0; + } + if (!dmatable) { + printk(" -- ERROR, UNABLE TO ALLOCATE PRD TABLE\n"); + } else { + hwif->dmatable = (unsigned long *) dmatable; + dmatable += (PRD_ENTRIES * PRD_BYTES); + leftover -= (PRD_ENTRIES * PRD_BYTES); + hwif->dmaproc = &ide_dmaproc; + if (hwif->chipset != ide_trm290) { + byte dma_stat = inb(dmabase+2); + printk(", BIOS DMA settings: %s:%s %s:%s", + hwif->drives[0].name, (dma_stat & 0x20) ? "yes" : "no ", + hwif->drives[1].name, (dma_stat & 0x40) ? "yes" : "no"); + } + printk("\n"); + } +} + +#ifdef CONFIG_BLK_DEV_TRM290 +extern void ide_init_trm290(byte, byte, ide_hwif_t *); +#define INIT_TRM290 (&ide_init_trm290) +#else +#define INIT_TRM290 (NULL) +#endif /* CONFIG_BLK_DEV_TRM290 */ + +#ifdef CONFIG_BLK_DEV_OPTI621 +extern void ide_init_opti621(byte, byte, ide_hwif_t *); +#define INIT_OPTI (&ide_init_opti621) +#else +#define INIT_OPTI (NULL) +#endif /* CONFIG_BLK_DEV_OPTI621 */ + #define DEVID_PIIX (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371_1 <<16)) #define DEVID_PIIX3 (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371SB_1 <<16)) #define DEVID_PIIX4 (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371AB <<16)) #define DEVID_VP_IDE (PCI_VENDOR_ID_VIA |(PCI_DEVICE_ID_VIA_82C586_1 <<16)) -#define DEVID_PDC2046 (PCI_VENDOR_ID_PROMISE|(PCI_DEVICE_ID_PROMISE_20246 <<16)) +#define DEVID_PDC20246 (PCI_VENDOR_ID_PROMISE|(PCI_DEVICE_ID_PROMISE_20246 <<16)) #define DEVID_RZ1000 (PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1000 <<16)) #define DEVID_RZ1001 (PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1001 <<16)) #define DEVID_CMD640 (PCI_VENDOR_ID_CMD |(PCI_DEVICE_ID_CMD_640 <<16)) @@ -295,13 +364,9 @@ #define DEVID_SIS5513 (PCI_VENDOR_ID_SI |(PCI_DEVICE_ID_SI_5513 <<16)) #define DEVID_OPTI (PCI_VENDOR_ID_OPTI |(PCI_DEVICE_ID_OPTI_82C621 <<16)) #define DEVID_OPTI2 (PCI_VENDOR_ID_OPTI |(0xd568 /* from datasheets */ <<16)) - -#ifdef CONFIG_BLK_DEV_OPTI621 -extern void ide_init_opti621(byte, byte, ide_hwif_t *); -#define INIT_OPTI (&ide_init_opti621) -#else -#define INIT_OPTI (NULL) -#endif +#define DEVID_TRM290 (PCI_VENDOR_ID_TEKRAM |(PCI_DEVICE_ID_TEKRAM_DC290 <<16)) +#define DEVID_NS87410 (PCI_VENDOR_ID_NS |(PCI_DEVICE_ID_NS_87410 <<16)) +#define DEVID_HT6565 (PCI_VENDOR_ID_HOLTEK |(PCI_DEVICE_ID_HOLTEK_6565 <<16)) typedef struct ide_pci_enablebit_s { byte reg; /* byte pci reg holding the enable-bit */ @@ -321,14 +386,17 @@ {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, {DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} }, - {DEVID_PDC2046, "PDC2046", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}} }, + {DEVID_PDC20246,"PDC20246", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}} }, {DEVID_RZ1000, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, {DEVID_RZ1001, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, {DEVID_CMD640, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, {DEVID_OPTI, "OPTI", INIT_OPTI, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} }, {DEVID_OPTI2, "OPTI2", INIT_OPTI, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} }, - {DEVID_SIS5513, "SIS5513", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_SIS5513, "SIS5513", NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} }, {DEVID_CMD646, "CMD646", NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}} }, + {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_NS87410, "NS87410", NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}} }, + {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, {0, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }}; __initfunc(static ide_pci_device_t *lookup_devid(unsigned int devid)) @@ -339,38 +407,6 @@ return d; } -__initfunc(static void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase)) -{ - static unsigned long dmatable = 0; - static unsigned leftover = 0; - - printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dmabase, dmabase+7); - if (check_region(dmabase, 8)) { - printk(" -- ERROR, PORTS ALREADY IN USE"); - } else { - request_region(dmabase, 8, hwif->name); - hwif->dma_base = dmabase; - if (leftover < (PRD_ENTRIES * PRD_BYTES)) { - /* - * The BM-DMA uses full 32bit addr, so we can - * safely use __get_free_page() here instead - * of __get_dma_pages() -- no ISA limitations. - */ - dmatable = __get_free_pages(GFP_KERNEL,1,0); - leftover = dmatable ? PAGE_SIZE : 0; - } - if (dmatable) { - printk(", PRD table at %08lx", dmatable); - hwif->dmatable = (unsigned long *) dmatable; - dmatable += (PRD_ENTRIES * PRD_BYTES); - leftover -= (PRD_ENTRIES * PRD_BYTES); - outl(virt_to_bus(hwif->dmatable), dmabase + 4); - hwif->dmaproc = &ide_dmaproc; - } - } - printk("\n"); -} - /* The next two functions were stolen from cmd640.c, with a few modifications */ @@ -501,7 +537,7 @@ } return NULL; } - + /* * ide_setup_pci_device() looks at the primary/secondary interfaces * on a PCI IDE device and, if they are enabled, prepares the IDE driver @@ -516,11 +552,9 @@ { unsigned int port, at_least_one_hwif_enabled = 0; unsigned short base = 0, ctl = 0; - byte tmp = 0, pciirq = 0; - ide_hwif_t *hwif; + byte tmp = 0; + ide_hwif_t *hwif, *mate = NULL; - if (pcibios_read_config_byte(bus, fn, 0x3c, &pciirq)) - pciirq = 0; /* probe later if not set */ for (port = 0; port <= 1; ++port) { ide_pci_enablebit_t *e = &(d->enablebits[port]); if (e->reg) { @@ -542,25 +576,33 @@ continue; } hwif->chipset = ide_pci; + hwif->pci_port = port; + if (mate) { + hwif->mate = mate; + mate->mate = hwif; + } + mate = hwif; /* for next iteration */ if (hwif->io_ports[IDE_DATA_OFFSET] != base) { ide_init_hwif_ports(hwif->io_ports, base, NULL); hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2; } - if (!hwif->irq) - hwif->irq = port ? 0 : pciirq; /* always probe for secondary irq */ if (bmiba) { if ((inb(bmiba+2) & 0x80)) { /* simplex DMA only? */ printk("%s: simplex device: DMA disabled\n", d->name); } else { /* supports simultaneous DMA on both channels */ - ide_setup_dma(hwif, bmiba + (8 * port)); + ide_setup_dma(hwif, bmiba + (8 * port), 8); } } + if (d->id) { /* For "known" chipsets, allow other irqs during i/o */ + hwif->drives[0].unmask = 1; + hwif->drives[1].unmask = 1; + } if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */ d->init_hwif(bus, fn, hwif); at_least_one_hwif_enabled = 1; } if (!at_least_one_hwif_enabled) - printk("%s: neither IDE port is enabled\n", d->name); + printk("%s: neither IDE port enabled (BIOS)\n", d->name); } /* @@ -570,9 +612,9 @@ __initfunc(static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)) { unsigned int devid, ccode; - unsigned short pcicmd; + unsigned short pcicmd, class; ide_pci_device_t *d; - byte hedt; + byte hedt, progif; if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt)) hedt = 0; @@ -582,26 +624,36 @@ || pcibios_read_config_dword(bus, fn, 0x08, &ccode)) return; d = lookup_devid(devid); - if (d->name == NULL) /* some chips (cmd640 & rz1000) are handled elsewhere */ + if (d->name == NULL) /* some chips (cmd640, rz1000) are handled elsewhere */ continue; - if (d->id || (ccode >> 16) == PCI_CLASS_STORAGE_IDE) { - printk("%s: %sIDE device on PCI bus %d function %d\n", d->name, d->id ? "" : "unknown ", bus, fn); + progif = (ccode >> 8) & 0xff; + class = ccode >> 16; + if (d->id || class == PCI_CLASS_STORAGE_IDE) { + if (d->id) + printk("%s: IDE device on PCI bus %d function %d\n", d->name, bus, fn); + else + printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n", + d->name, bus, fn, devid & 0xffff, devid >> 16); /* - * See if IDE ports are enabled - */ + * See if IDE ports are enabled + */ if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)) { printk("%s: error accessing PCICMD\n", d->name); } else if ((pcicmd & 1) == 0) { - printk("%s: device is disabled (BIOS)\n", d->name); + printk("%s: device disabled (BIOS)\n", d->name); } else { unsigned int bmiba = 0; /* - * Check for Bus-Master DMA capability - */ - if (!(pcicmd & 4) || !(bmiba = ide_get_or_set_bmiba(bus, fn, d->name))) { - if ((ccode >> 16) == PCI_CLASS_STORAGE_RAID || (ccode && 0x8000)) - printk("%s: Bus-Master DMA is disabled (BIOS)\n", d->name); + * Check for Bus-Master DMA capability + */ + if (d->id == DEVID_PDC20246 || (class == PCI_CLASS_STORAGE_IDE && (progif & 0x80))) { + if ((!(pcicmd & 4) || !(bmiba = ide_get_or_set_bmiba(bus, fn, d->name)))) { + printk("%s: Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, progif=0x%02x, bmiba=0x%04x\n", d->name, pcicmd, progif, bmiba); + } } + /* + * Setup the IDE ports + */ ide_setup_pci_device(bus, fn, bmiba, d); } } diff -u --recursive --new-file v2.1.70/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.1.70/linux/drivers/block/ide-probe.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/block/ide-probe.c Wed Dec 3 10:43:31 1997 @@ -123,11 +123,13 @@ #endif /* CONFIG_BLK_DEV_PDC4030 */ switch (type) { case ide_floppy: - if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP")) - printk("cdrom or floppy?, assuming "); - if (drive->media != ide_cdrom) { - printk ("FLOPPY"); - break; + if (!strstr(id->model, "CD-ROM")) { + if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP")) + printk("cdrom or floppy?, assuming "); + if (drive->media != ide_cdrom) { + printk ("FLOPPY"); + break; + } } type = ide_cdrom; /* Early cdrom models used zero */ case ide_cdrom: diff -u --recursive --new-file v2.1.70/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.70/linux/drivers/block/ide.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/block/ide.c Wed Dec 3 17:16:33 1997 @@ -2175,8 +2175,8 @@ /* * Be VERY CAREFUL changing this: note hardcoded indexes below */ - const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", - "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "reset", NULL}; + const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "qd6580", + "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "four", "reset", NULL}; hw = s[3] - '0'; hwif = &ide_hwifs[hw]; i = match_parm(&s[4], ide_words, vals, 3); @@ -2184,7 +2184,7 @@ /* * Cryptic check to ensure chipset not already set for hwif: */ - if (i > 0 || (i <= -5 && i != -12)) { + if (i > 0 || (i <= -5 && i != -13)) { if (hwif->chipset != ide_unknown) goto bad_option; if (i <= -5) { @@ -2200,9 +2200,24 @@ } switch (i) { - case -12: /* "reset" */ + case -13: /* "reset" */ hwif->reset = 1; goto done; +#ifdef CONFIG_BLK_DEV_4DRIVES + case -12: /* "four" drives on one set of ports */ + { + ide_hwif_t *mate = &ide_hwifs[hw^1]; + mate->mate = hwif; + hwif->mate = mate; + hwif->chipset = mate->chipset = ide_4drives; + hwif->serialized = mate->serialized = 1; + mate->drives[0].select.all ^= 0x20; + mate->drives[1].select.all ^= 0x20; + memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports)); + mate->irq = hwif->irq; + goto done; + } +#endif /* CONFIG_BLK_DEV_4DRIVES */ #ifdef CONFIG_BLK_DEV_PDC4030 case -11: /* "dc4030" */ { diff -u --recursive --new-file v2.1.70/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v2.1.70/linux/drivers/block/ide.h Mon Dec 1 12:04:12 1997 +++ linux/drivers/block/ide.h Thu Dec 4 13:35:53 1997 @@ -164,7 +164,7 @@ #define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ #define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ -#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) +#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290) #define SELECT_DRIVE(hwif,drive) \ { \ if (hwif->selectproc) \ @@ -289,7 +289,7 @@ typedef void (ide_tuneproc_t)(ide_drive_t *, byte); /* - * This is used to provide HT6560B & PDC4030 interface support. + * This is used to provide HT6560B & PDC4030 & TRM290 interface support. */ typedef void (ide_selectproc_t) (ide_drive_t *); @@ -300,7 +300,8 @@ typedef enum { ide_unknown, ide_generic, ide_pci, ide_cmd640, ide_dtc2278, ide_ali14xx, ide_qd6580, ide_umc8672, ide_ht6560b, - ide_pdc4030, ide_rz1000 } + ide_pdc4030, ide_rz1000, ide_trm290, + ide_4drives } hwif_chipset_t; typedef struct hwif_s { @@ -310,11 +311,12 @@ ide_drive_t drives[MAX_DRIVES]; /* drive info */ struct gendisk *gd; /* gendisk structure */ ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */ -#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) +#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290) ide_selectproc_t *selectproc; /* tweaks hardware to select drive */ #endif ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ unsigned long *dmatable; /* dma physical region descriptor table */ + struct hwif_s *mate; /* other hwif from same PCI chip */ unsigned short dma_base; /* base addr for dma ports (triton) */ int irq; /* our irq number */ byte major; /* our major number */ @@ -329,6 +331,7 @@ unsigned is_pdc4030_2: 1;/* 2nd i/f on pdc4030 */ #endif /* CONFIG_BLK_DEV_PDC4030 */ unsigned reset : 1; /* reset after probe */ + unsigned pci_port : 1; /* for dual-port chips: 0=primary, 1=secondary */ #if (DISK_RECOVERY_TIME > 0) unsigned long last_time; /* time when previous rq was done */ #endif @@ -609,6 +612,12 @@ ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n); int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version); int ide_unregister_subdriver (ide_drive_t *drive); + +#ifdef CONFIG_BLK_DEV_IDEDMA +int ide_build_dmatable (ide_drive_t *drive); +int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive); +void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports); +#endif #ifdef CONFIG_BLK_DEV_IDE int ideprobe_init (void); diff -u --recursive --new-file v2.1.70/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.1.70/linux/drivers/block/nbd.c Tue Dec 2 09:49:39 1997 +++ linux/drivers/block/nbd.c Wed Dec 3 15:26:21 1997 @@ -78,7 +78,7 @@ oldfs = get_fs(); set_fs(get_ds()); do { - int save; + sigset_t oldset; iov.iov_base = buf; iov.iov_len = size; @@ -91,13 +91,22 @@ msg.msg_namelen = 0; msg.msg_flags = 0; - save = current->blocked; - current->blocked = ~0UL; + spin_lock_irq(¤t->sigmask_lock); + oldset = current->blocked; + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + if (send) result = sock_sendmsg(sock, &msg, size); else result = sock_recvmsg(sock, &msg, size, 0); - current->blocked = save; + + spin_lock_irq(¤t->sigmask_lock); + current->blocked = oldset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + if (result <= 0) { #ifdef PARANOIA printk(KERN_ERR "NBD: %s - sock=%d at buf=%d, size=%d returned %d.\n", diff -u --recursive --new-file v2.1.70/linux/drivers/block/opti621.c linux/drivers/block/opti621.c --- v2.1.70/linux/drivers/block/opti621.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/block/opti621.c Wed Dec 3 04:39:27 1997 @@ -233,7 +233,7 @@ drdy = 2; /* DRDY is default 2 (by OPTi Databook) */ - cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2); + cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2); cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2); misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1); @@ -276,11 +276,9 @@ /* * ide_init_opti621() is Called from idedma.c once for each hwif found at boot. */ -void ide_init_opti621 (byte bus, byte fn, ide_hwif_t *hwifs) +void ide_init_opti621 (byte bus, byte fn, ide_hwif_t *hwif) { - if (hwif->io_ports[IDE_DATA_OFFSET]) { - hwif->drives[0].timing_data = PIO_DONT_KNOW; - hwif->drives[1].timing_data = PIO_DONT_KNOW; - hwif->tuneproc = &opti621_tune_drive; - } + hwif->drives[0].timing_data = PIO_DONT_KNOW; + hwif->drives[1].timing_data = PIO_DONT_KNOW; + hwif->tuneproc = &opti621_tune_drive; } diff -u --recursive --new-file v2.1.70/linux/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c --- v2.1.70/linux/drivers/block/pdc4030.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/block/pdc4030.c Wed Dec 3 04:36:30 1997 @@ -169,8 +169,10 @@ default: hwif->irq = 15; break; } printk("on IRQ %d\n",hwif->irq); - hwif->chipset = second_hwif->chipset = ide_pdc4030; - hwif->selectproc = second_hwif->selectproc = &promise_selectproc; + hwif->chipset = second_hwif->chipset = ide_pdc4030; + hwif->mate = second_hwif; + second_hwif->mate = hwif; + hwif->selectproc = second_hwif->selectproc = &promise_selectproc; /* Shift the remaining interfaces down by one */ for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) { ide_hwif_t *h = &ide_hwifs[i]; diff -u --recursive --new-file v2.1.70/linux/drivers/block/qd6580.c linux/drivers/block/qd6580.c --- v2.1.70/linux/drivers/block/qd6580.c Sun Aug 4 22:12:25 1996 +++ linux/drivers/block/qd6580.c Wed Dec 3 04:36:30 1997 @@ -63,4 +63,6 @@ ide_hwifs[0].chipset = ide_qd6580; ide_hwifs[1].chipset = ide_qd6580; ide_hwifs[0].tuneproc = &tune_qd6580; + ide_hwifs[0].mate = &ide_hwifs[1]; + ide_hwifs[1].mate = &ide_hwifs[0]; } diff -u --recursive --new-file v2.1.70/linux/drivers/block/trm290.c linux/drivers/block/trm290.c --- v2.1.70/linux/drivers/block/trm290.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/trm290.c Wed Dec 3 04:36:30 1997 @@ -0,0 +1,227 @@ +/* + * linux/drivers/block/trm290.c Version 1.00 December 3, 1997 + * + * Copyright (c) 1997-1998 Mark Lord + * May be copied or modified under the terms of the GNU General Public License + */ + +/* + * This module provides support for the bus-master IDE DMA function + * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards, + * including a "Precision Instruments" board. The TRM290 pre-dates + * the sff-8038 standard (ide-dma.c) by a few months, and differs + * significantly enough to warrant separate routines for some functions, + * while re-using others from ide-dma.c. + * + * EXPERIMENTAL! It works for me (a sample of one). + * + * Works reliably for me in DMA mode (READs only), + * DMA WRITEs are disabled by default (see #define below); + * + * DMA is not enabled automatically for this chipset, + * but can be turned on manually (with "hdparm -d1") at run time. + * + * I need volunteers with "spare" drives for further testing + * and development, and maybe to help figure out the peculiarities. + * Even knowing the registers (below), some things behave strangely. + */ + +#define TRM290_NO_DMA_WRITES /* DMA writes seem unreliable sometimes */ + +/* + * TRM-290 PCI-IDE2 Bus Master Chip + * ================================ + * The configuration registers are addressed in normal I/O port space + * and are used as follows: + * + * 0x3df2 when WRITTEN: chiptest register (byte, write-only) + * bit7 must always be written as "1" + * bits6-2 undefined + * bit1 1=legacy_compatible_mode, 0=native_pci_mode + * bit0 1=test_mode, 0=normal(default) + * + * 0x3df2 when READ: status register (byte, read-only) + * bits7-2 undefined + * bit1 channel0 busmaster interrupt status 0=none, 1=asserted + * bit0 channel0 interrupt status 0=none, 1=asserted + * + * 0x3df3 Interrupt mask register + * bits7-5 undefined + * bit4 legacy_header: 1=present, 0=absent + * bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only) + * bit2 channel1 interrupt status 0=none, 1=asserted (read only) + * bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default) + * bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default) + * + * 0x3df1 "CPR" Config Pointer Register (byte) + * bit7 1=autoincrement CPR bits 2-0 after each access of CDR + * bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state + * bit5 0=enabled master burst access (default), 1=disable (write only) + * bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast + * bit3 0=primary IDE channel, 1=secondary IDE channel + * bits2-0 register index for accesses through CDR port + * + * 0x3df0 "CDR" Config Data Register (word) + * two sets of seven config registers, + * selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6), + * each index defined below: + * + * Index-0 Base address register for command block (word) + * defaults: 0x1f0 for primary, 0x170 for secondary + * + * Index-1 general config register (byte) + * bit7 1=DMA enable, 0=DMA disable + * bit6 1=activate IDE_RESET, 0=no action (default) + * bit5 1=enable IORDY, 0=disable IORDY (default) + * bit4 0=16-bit data port(default), 1=8-bit (XT) data port + * bit3 interrupt polarity: 1=active_low, 0=active_high(default) + * bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only) + * bit1 bus_master_mode(?): 1=enable, 0=disable(default) + * bit0 enable_io_ports: 1=enable(default), 0=disable + * + * Index-2 read-ahead counter preload bits 0-7 (byte, write only) + * bits7-0 bits7-0 of readahead count + * + * Index-3 read-ahead config register (byte, write only) + * bit7 1=enable_readahead, 0=disable_readahead(default) + * bit6 1=clear_FIFO, 0=no_action + * bit5 undefined + * bit4 mode4 timing control: 1=enable, 0=disable(default) + * bit3 undefined + * bit2 undefined + * bits1-0 bits9-8 of read-ahead count + * + * Index-4 base address register for control block (word) + * defaults: 0x3f6 for primary, 0x376 for secondary + * + * Index-5 data port timings (shared by both drives) (byte) + * standard PCI "clk" (clock) counts, default value = 0xf5 + * + * bits7-6 setup time: 00=1clk, 01=2clk, 10=3clk, 11=4clk + * bits5-3 hold time: 000=1clk, 001=2clk, 010=3clk, + * 011=4clk, 100=5clk, 101=6clk, + * 110=8clk, 111=12clk + * bits2-0 active time: 000=2clk, 001=3clk, 010=4clk, + * 011=5clk, 100=6clk, 101=8clk, + * 110=12clk, 111=16clk + * + * Index-6 command/control port timings (shared by both drives) (byte) + * same layout as Index-5, default value = 0xde + * + * Suggested CDR programming for PIO mode0 (600ns): + * 0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde ; primary + * 0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde ; secondary + * + * Suggested CDR programming for PIO mode3 (180ns): + * 0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde ; primary + * 0x0170,0x21,0xff,0x80,0x0376,0x09,0xde ; secondary + * + * Suggested CDR programming for PIO mode4 (120ns): + * 0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde ; primary + * 0x0170,0x21,0xff,0x80,0x0376,0x00,0xde ; secondary + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ide.h" + +static void select_dma_or_pio(ide_hwif_t *hwif, int dma) +{ + static int previous[2] = {-1,-1}; + unsigned long flags; + + if (previous[hwif->pci_port] != dma) { + unsigned short cfg1 = dma ? 0xa3 : 0x21; + previous[hwif->pci_port] = dma; + save_flags(flags); + cli(); + outb(0x51|(hwif->pci_port<<3),0x3df1); + outw(cfg1,0x3df0); + restore_flags(flags); + } +} + +/* + * trm290_dma_intr() is the handler for trm290 disk read/write DMA interrupts + */ +static void trm290_dma_intr (ide_drive_t *drive) +{ + byte stat; + int i; + struct request *rq = HWGROUP(drive)->rq; + + stat = GET_STAT(); /* get drive status */ + if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { + unsigned short dma_stat = inw(HWIF(drive)->dma_base + 2); + if (dma_stat == 0x00ff) { + rq = HWGROUP(drive)->rq; + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + ide_end_request(1, HWGROUP(drive)); + } + return; + } + printk("%s: bad trm290 DMA status: 0x%04x\n", drive->name, dma_stat); + } + sti(); + ide_error(drive, "dma_intr", stat); +} + +static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned int count, reading = 1 << 1; + + if (drive->media == ide_disk) { + switch (func) { + case ide_dma_write: + reading = 0; +#ifdef TRM290_NO_DMA_WRITES + break; /* always use PIO for writes */ +#endif + case ide_dma_read: + if (!(count = ide_build_dmatable(drive))) + break; /* try PIO instead of DMA */ + select_dma_or_pio(hwif, 1); /* select DMA mode */ + outl_p(virt_to_bus(hwif->dmatable)|reading, hwif->dma_base); + outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ + ide_set_handler(drive, &trm290_dma_intr, WAIT_CMD); + OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + return 0; + default: + return ide_dmaproc(func, drive); + } + } + select_dma_or_pio(hwif, 0); /* force PIO mode for this operation */ + return 1; +} + +static void trm290_selectproc (ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + + select_dma_or_pio(hwif, drive->using_dma); + OUT_BYTE(drive->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); +} + +/* + * Invoked from ide-dma.c at boot time. + */ +__initfunc(void ide_init_trm290 (byte bus, byte fn, ide_hwif_t *hwif)) +{ + hwif->chipset = ide_trm290; + hwif->selectproc = trm290_selectproc; + hwif->drives[0].autotune = 2; /* play it safe */ + hwif->drives[1].autotune = 2; /* play it safe */ + ide_setup_dma(hwif, hwif->pci_port ? 0x3d74 : 0x3df4, 2); + hwif->dmaproc = &trm290_dmaproc; +} diff -u --recursive --new-file v2.1.70/linux/drivers/block/umc8672.c linux/drivers/block/umc8672.c --- v2.1.70/linux/drivers/block/umc8672.c Tue Oct 29 05:28:40 1996 +++ linux/drivers/block/umc8672.c Wed Dec 3 04:36:30 1997 @@ -151,5 +151,6 @@ ide_hwifs[1].chipset = ide_umc8672; ide_hwifs[0].tuneproc = &tune_umc; ide_hwifs[1].tuneproc = &tune_umc; - + ide_hwifs[0].mate = &ide_hwifs[1]; + ide_hwifs[1].mate = &ide_hwifs[0]; } diff -u --recursive --new-file v2.1.70/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v2.1.70/linux/drivers/cdrom/aztcd.c Tue Dec 2 16:45:18 1997 +++ linux/drivers/cdrom/aztcd.c Wed Dec 3 04:29:41 1997 @@ -160,6 +160,8 @@ Werner Zimmermann, Nov 29, 97 */ +#include + #define MAJOR_NR AZTECH_CDROM_MAJOR #include diff -u --recursive --new-file v2.1.70/linux/drivers/cdrom/aztcd.h linux/drivers/cdrom/aztcd.h --- v2.1.70/linux/drivers/cdrom/aztcd.h Tue Dec 2 16:45:18 1997 +++ linux/drivers/cdrom/aztcd.h Wed Dec 3 04:29:41 1997 @@ -1,7 +1,7 @@ -/* $Id: aztcd.h,v 2.50 1996/05/17 16:15:43 root Exp root $ +/* $Id: aztcd.h,v 2.60 1997/11/29 09:51:22 root Exp root $ * * Definitions for a AztechCD268 CD-ROM interface - * Copyright (C) 1994, 1995 Werner Zimmermann + * Copyright (C) 1994-98 Werner Zimmermann * * based on Mitsumi CDROM driver by Martin Harriss * @@ -20,11 +20,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History: W.Zimmermann adaption to Aztech CD268-01A Version 1.3 - * October 1994 Email: zimmerma@rz.fht-esslingen.de + * October 1994 Email: Werner.Zimmermann@fht-esslingen.de */ -/* *** change this to set the I/O port address of your CD-ROM drive*/ -#define AZT_BASE_ADDR 0x320 +/* *** change this to set the I/O port address of your CD-ROM drive, + set to '-1', if you want autoprobing */ +#define AZT_BASE_ADDR -1 + +/* list of autoprobing addresses (not more than 15), last value must be 0x000 + Note: Autoprobing is only enabled, if AZT_BASE_ADDR is set to '-1' ! */ +#define AZT_BASE_AUTO { 0x320, 0x300, 0x310, 0x330, 0x000 } /* Uncomment this, if your CDROM is connected to a Soundwave32-soundcard and configure AZT_BASE_ADDR and AZT_SW32_BASE_ADDR */ @@ -54,6 +59,9 @@ chapter '5.1 Multisession support' in README.aztcd for details. Normally it's uncritical to leave this setting untouched */ #define AZT_MULTISESSION 1 + +/*Uncomment this, if you are using a linux kernel version prior to 2.1.0 */ +/*#define AZT_KERNEL_PRIOR_2_1 */ /*---------------------------------------------------------------------------*/ /*-----nothing to be configured for normal applications below this line------*/ diff -u --recursive --new-file v2.1.70/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.1.70/linux/drivers/cdrom/cdrom.c Tue Dec 2 16:45:18 1997 +++ linux/drivers/cdrom/cdrom.c Wed Dec 3 10:40:13 1997 @@ -111,8 +111,6 @@ static int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); static int cdrom_media_changed(kdev_t dev); -static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, - void *buffer, size_t *lenp); static int open_for_data(struct cdrom_device_info * cdi); static int check_for_audio_disc(struct cdrom_device_info * cdi, struct cdrom_device_ops * cdo); @@ -307,11 +305,15 @@ ret=-ENOMEDIUM; goto clean_up_and_return; } +#if 0 + /* this breaks CD-Players which don't use O_NONBLOCK, workman + * for example, probably others too */ if (cdi->options & CDO_CHECK_TYPE && tracks.data==0) { cdinfo(CD_OPEN, "bummer. wrong media type...\n"); ret=-EMEDIUMTYPE; goto clean_up_and_return; } +#endif cdinfo(CD_OPEN, "all seems well, opening the device...\n"); @@ -879,24 +881,85 @@ EXPORT_SYMBOL(cdrom_fops); #ifdef CONFIG_SYSCTL -#define CDROM_STR_SIZE 1000 -static char cdrom_drive_info[CDROM_STR_SIZE]="info\n"; -#ifdef MODULE +#define CDROM_STR_SIZE 1000 -static struct ctl_table_header *cdrom_sysctl_header; +static char cdrom_drive_info[CDROM_STR_SIZE]="info\n"; -static void cdrom_sysctl_register(void) +int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) { - cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 0); -} + int retv,pos; + struct cdrom_device_info *cdi; -static void cdrom_sysctl_unregister(void) -{ - unregister_sysctl_table(cdrom_sysctl_header); -} + pos = sprintf(cdrom_drive_info, "CD-ROM information\n"); + + pos += sprintf(cdrom_drive_info+pos, "\ndrive name:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%s", cdi->name); + + pos += sprintf(cdrom_drive_info+pos, "\ndrive speed:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", cdi->speed); + + pos += sprintf(cdrom_drive_info+pos, "\ndrive # of slots:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", cdi->capacity); + + pos += sprintf(cdrom_drive_info+pos, "\nCan close tray:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_CLOSE_TRAY)!=0)); + + pos += sprintf(cdrom_drive_info+pos, "\nCan open tray:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_OPEN_TRAY)!=0)); + + pos += sprintf(cdrom_drive_info+pos, "\nCan lock tray:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_LOCK)!=0)); + + pos += sprintf(cdrom_drive_info+pos, "\nCan change speed:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_SELECT_SPEED)!=0)); + + pos += sprintf(cdrom_drive_info+pos, "\nCan select disk:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_SELECT_DISC)!=0)); + + pos += sprintf(cdrom_drive_info+pos, "\nCan read multisession:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_MULTI_SESSION)!=0)); + + pos += sprintf(cdrom_drive_info+pos, "\nCan read MCN:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_MCN)!=0)); + + pos += sprintf(cdrom_drive_info+pos, "\nReports media changed:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_MEDIA_CHANGED)!=0)); + + pos += sprintf(cdrom_drive_info+pos, "\nCan play audio:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(cdrom_drive_info+pos, "\t%d", + ((cdi->ops->capability & CDC_PLAY_AUDIO)!=0)); -#endif + strcpy(cdrom_drive_info+pos,"\n\n"); + *lenp=pos+3; + if (!write) { + retv = proc_dostring(ctl, write, filp, buffer, lenp); + } + else + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} /* Place files in /proc/sys/dev/cdrom */ ctl_table cdrom_table[] = { @@ -916,57 +979,26 @@ {0} }; +#endif /* endif CONFIG_SYSCTL */ -int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, - void *buffer, size_t *lenp) -{ - int retv; - char buf[40]; - struct cdrom_device_info *cdi; - sprintf(cdrom_drive_info, "CD-ROM information\n\n"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next){ - sprintf(buf, "drive name:\t\t%s\n", cdi->name); - strcat(cdrom_drive_info, buf); - sprintf(buf, "drive speed:\t\t%d\n", cdi->speed); - strcat(cdrom_drive_info, buf); - sprintf(buf, "drive # of slots:\t%d\n", cdi->capacity); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Can close tray:\t\t%d\n", ((cdi->ops->capability & CDC_CLOSE_TRAY)!=0)); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Can open tray:\t\t%d\n", ((cdi->ops->capability & CDC_OPEN_TRAY)!=0)); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Can lock tray:\t\t%d\n", ((cdi->ops->capability & CDC_LOCK)!=0)); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Can change speed:\t%d\n", ((cdi->ops->capability & CDC_SELECT_SPEED)!=0)); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Can select disk:\t%d\n", ((cdi->ops->capability & CDC_SELECT_DISC)!=0)); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Can read multisession:\t%d\n", ((cdi->ops->capability & CDC_MULTI_SESSION)!=0)); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Can read MCN:\t\t%d\n", ((cdi->ops->capability & CDC_MCN)!=0)); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Reports media changed:\t%d\n", ((cdi->ops->capability & CDC_MEDIA_CHANGED)!=0)); - strcat(cdrom_drive_info, buf); - sprintf(buf, "Can play audio:\t\t%d\n", ((cdi->ops->capability & CDC_PLAY_AUDIO)!=0)); - strcat(cdrom_drive_info, buf); - strcat(cdrom_drive_info, "\n\n"); - } - *lenp=sizeof(cdrom_drive_info); +#ifdef MODULE - if (!write) { - retv = proc_dostring(ctl, write, filp, buffer, lenp); - } - else - retv = proc_dostring(ctl, write, filp, buffer, lenp); - return retv; -} +#ifdef CONFIG_SYSCTL +static struct ctl_table_header *cdrom_sysctl_header; -#endif /* endif CONFIG_SYSCTL */ +static void cdrom_sysctl_register(void) +{ + cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 0); +} +static void cdrom_sysctl_unregister(void) +{ + unregister_sysctl_table(cdrom_sysctl_header); +} +#endif /* endif CONFIG_SYSCTL */ -#ifdef MODULE int init_module(void) { cdrom_init(); diff -u --recursive --new-file v2.1.70/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.1.70/linux/drivers/char/Config.in Tue Dec 2 16:45:18 1997 +++ linux/drivers/char/Config.in Wed Dec 3 15:21:57 1997 @@ -6,16 +6,18 @@ bool 'Virtual terminal' CONFIG_VT if [ "$CONFIG_VT" = "y" ]; then - bool 'Console on virtual terminal' CONFIG_VT_CONSOLE + bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE fi tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL +if [ "$CONFIG_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE +fi bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6 - bool ' Console on serial port' CONFIG_SERIAL_CONSOLE fi bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then diff -u --recursive --new-file v2.1.70/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.70/linux/drivers/char/console.c Thu Jun 26 12:33:38 1997 +++ linux/drivers/char/console.c Wed Dec 3 15:21:57 1997 @@ -158,6 +158,7 @@ extern void compute_shiftstate(void); extern void reset_palette(int currcons); extern void set_palette(void); +extern int con_is_present(void); extern unsigned long con_type_init(unsigned long, const char **); extern void con_type_init_finish(void); extern int set_get_cmap(unsigned char *, int); @@ -1836,7 +1837,7 @@ } #ifdef CONFIG_VT_CONSOLE -void vt_console_print(const char * b, unsigned count) +void vt_console_print(struct console *co, const char * b, unsigned count) { int currcons = fg_console; unsigned char c; @@ -1885,16 +1886,25 @@ printing = 0; } -static int vt_console_device(void) +static kdev_t vt_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, fg_console + 1); + return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1); } -extern void keyboard_wait_for_keypress(void); +extern int keyboard_wait_for_keypress(struct console *); struct console vt_console_driver = { - vt_console_print, do_unblank_screen, - keyboard_wait_for_keypress, vt_console_device + "tty", + vt_console_print, + NULL, + vt_console_device, + keyboard_wait_for_keypress, + do_unblank_screen, + NULL, + CON_PRINTBUFFER, + -1, + 0, + NULL }; #endif @@ -1983,6 +1993,9 @@ * * Reads the information preserved by setup.s to determine the current display * type and sets everything accordingly. + * + * FIXME: return early if we don't _have_ a video card installed. + * */ __initfunc(unsigned long con_init(unsigned long kmem_start)) { @@ -2117,7 +2130,7 @@ * within the bus probing code... :-( */ #ifdef CONFIG_VT_CONSOLE - if (video_type != VIDEO_TYPE_TGAC) + if (video_type != VIDEO_TYPE_TGAC && con_is_present()) register_console(&vt_console_driver); #endif diff -u --recursive --new-file v2.1.70/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.1.70/linux/drivers/char/cyclades.c Tue Dec 2 16:45:19 1997 +++ linux/drivers/char/cyclades.c Thu Dec 4 13:09:01 1997 @@ -1,6 +1,6 @@ #define BLOCKMOVE static char rcsid[] = -"$Revision: 2.1 $$Date: 1997/11/01 17:42:41 $"; +"$Revision: 2.1.1.1 $$Date: 1997/12/03 17:31:19 $"; /* * linux/drivers/char/cyclades.c @@ -30,6 +30,12 @@ * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.1.1.1 1997/12/03 17:31:19 ivan + * Code review for the module cleanup routine (fixed memory leak); + * fixed RTS and DTR status report for new CD1400's in get_modem_info; + * purged conditional code for older kernels; + * includes anonymous changes regarding signal_pending + * * Revision 2.1 1997/11/01 17:42:41 ivan * Changes in the driver to support Alpha systems (except 8Zo V_1); * BREAK fix for the Cyclades-Z boards; @@ -524,8 +530,6 @@ #include -#if (LINUX_VERSION_CODE >= 0x020100) - #include #include @@ -540,17 +544,6 @@ return result; } -#else - -#define __initfunc(__arginit) __arginit -#define copy_from_user memcpy_fromfs -#define copy_to_user memcpy_tofs -#define cy_get_user get_fs_long -#define cy_put_user put_fs_long -#define ioremap vremap - -#endif - #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -875,7 +868,6 @@ if (!tty) return; -#if (LINUX_VERSION_CODE >= 0x020125) if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { tty_hangup(info->tty); wake_up_interruptible(&info->open_wait); @@ -892,24 +884,6 @@ } wake_up_interruptible(&tty->write_wait); } -#else - if (clear_bit(Cy_EVENT_HANGUP, &info->event)) { - tty_hangup(info->tty); - wake_up_interruptible(&info->open_wait); - info->flags &= ~(ASYNC_NORMAL_ACTIVE| - ASYNC_CALLOUT_ACTIVE); - } - if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { - wake_up_interruptible(&info->open_wait); - } - if (clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } - wake_up_interruptible(&tty->write_wait); - } -#endif } /* do_softint */ @@ -2339,7 +2313,7 @@ break; } restore_flags(flags); - if (signal_pending(current)) { + if (signal_pending(current)) { retval = -ERESTARTSYS; break; } @@ -3318,12 +3292,18 @@ status |= cy_readb(base_addr+(CyMSVR2<rtsdtr_inv) { + result = ((status & CyRTS) ? TIOCM_DTR : 0) + | ((status & CyDTR) ? TIOCM_RTS : 0); + } else { + result = ((status & CyRTS) ? TIOCM_RTS : 0) + | ((status & CyDTR) ? TIOCM_DTR : 0); + } + result |= ((status & CyDCD) ? TIOCM_CAR : 0) + | ((status & CyRI) ? TIOCM_RNG : 0) + | ((status & CyDSR) ? TIOCM_DSR : 0) + | ((status & CyCTS) ? TIOCM_CTS : 0); } else { base_addr = (unsigned char*) (cy_card[card].base_addr); @@ -4329,7 +4309,7 @@ /* probe for CD1400... */ -#if !defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020100) +#if !defined(__alpha__) cy_isa_address = ioremap((unsigned int)cy_isa_address, CyISA_Ywin); #endif @@ -4483,9 +4463,6 @@ continue; } #else -#if (LINUX_VERSION_CODE < 0x020100) - if ((ulong)cy_pci_addr2 >= 0x100000) /* above 1M? */ -#endif cy_pci_addr2 = (ulong) ioremap(cy_pci_addr2, CyPCI_Ywin); #endif @@ -5098,10 +5075,13 @@ save_flags(flags); cli(); remove_bh(CYCLADES_BH); + + free_page((unsigned long)tmp_buf); if (tty_unregister_driver(&cy_callout_driver)) printk("Couldn't unregister Cyclom callout driver\n"); if (tty_unregister_driver(&cy_serial_driver)) printk("Couldn't unregister Cyclom serial driver\n"); + restore_flags(flags); for (i = 0; i < NR_CARDS; i++) { diff -u --recursive --new-file v2.1.70/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.1.70/linux/drivers/char/keyboard.c Mon Aug 4 16:25:37 1997 +++ linux/drivers/char/keyboard.c Wed Dec 3 15:21:57 1997 @@ -63,10 +63,12 @@ extern void scrollfront(int); struct wait_queue * keypress_wait = NULL; +struct console; -void keyboard_wait_for_keypress(void) +int keyboard_wait_for_keypress(struct console *co) { sleep_on(&keypress_wait); + return 0; } /* diff -u --recursive --new-file v2.1.70/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.1.70/linux/drivers/char/n_tty.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/char/n_tty.c Wed Dec 3 15:21:57 1997 @@ -40,6 +40,7 @@ #include #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) +#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1) #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -854,6 +855,7 @@ check of the logic of this change. -- jlc */ /* don't stop on /dev/console */ if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV && + file->f_dentry->d_inode->i_rdev != SYSCONS_DEV && current->tty == tty) { if (tty->pgrp <= 0) printk("read_chan: tty->pgrp <= 0!\n"); @@ -1012,7 +1014,8 @@ ssize_t retval = 0, num; /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ - if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV) { + if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV && + file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) { retval = tty_check_change(tty); if (retval) return retval; diff -u --recursive --new-file v2.1.70/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.1.70/linux/drivers/char/serial.c Tue Dec 2 09:49:39 1997 +++ linux/drivers/char/serial.c Wed Dec 3 15:21:57 1997 @@ -49,6 +49,9 @@ #include #include #include +#ifdef CONFIG_SERIAL_CONSOLE +#include +#endif #include #include @@ -152,6 +155,9 @@ static volatile int rs_irq_triggered; static volatile int rs_triggered; static int rs_wild_int_mask; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +#endif static void autoconfig(struct serial_state * info); static void change_speed(struct async_struct *info); @@ -2752,7 +2758,13 @@ *tty->termios = info->state->callout_termios; change_speed(info); } - +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info); + } +#endif info->session = current->session; info->pgrp = current->pgrp; @@ -3195,7 +3207,18 @@ sizeof(struct rs_multiport_struct)); #endif } - +#ifdef CONFIG_SERIAL_CONSOLE + /* + * The interrupt of the serial console port + * can't be shared. + */ + if (sercons.flags & CON_FIRST) { + for(i = 0; i < NR_PORTS; i++) + if (i != sercons.index && + rs_table[i].irq == rs_table[sercons.index].irq) + rs_table[i].irq = 0; + } +#endif show_serial_version(); /* Initialize the tty_driver structure */ @@ -3398,53 +3421,51 @@ */ #ifdef CONFIG_SERIAL_CONSOLE -#include +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) /* - * this defines the index into rs_table for the port to use + * Wait for transmitter & holding register to empty */ -#ifndef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 0 -#endif - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* Wait for transmitter & holding register to empty */ static inline void wait_for_xmitr(struct serial_state *ser) { int lsr; + unsigned int tmout = 1000000; + do { lsr = inb(ser->port + UART_LSR); + if (--tmout == 0) break; } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY); } /* - * Print a string to the serial port trying not to disturb any possible - * real use of the port... + * Print a string to the serial port trying not to disturb + * any possible real use of the port... */ -static void serial_console_write(const char *s, unsigned count) +static void serial_console_write(struct console *co, const char *s, + unsigned count) { struct serial_state *ser; int ier; unsigned i; - ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT; + ser = rs_table + co->index; /* - * First save the IER then disable the interrupts + * First save the IER then disable the interrupts */ ier = inb(ser->port + UART_IER); outb(0x00, ser->port + UART_IER); /* - * Now, do each character + * Now, do each character */ for (i = 0; i < count; i++, s++) { wait_for_xmitr(ser); - /* Send the character out. */ + /* + * Send the character out. + * If a LF, also do CR... + */ outb(*s, ser->port + UART_TX); - - /* if a LF, also do CR... */ if (*s == 10) { wait_for_xmitr(ser); outb(13, ser->port + UART_TX); @@ -3452,29 +3473,29 @@ } /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER + * Finally, Wait for transmitter & holding register to empty + * and restore the IER */ wait_for_xmitr(ser); outb(ier, ser->port + UART_IER); } /* - * Receive character from the serial port + * Receive character from the serial port */ -static void serial_console_wait_key(void) +static int serial_console_wait_key(struct console *co) { struct serial_state *ser; int ier; int lsr; int c; - ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT; + ser = rs_table + co->index; /* - * First save the IER then disable the interrupts so - * that the real driver for the port does not get the - * character. + * First save the IER then disable the interrupts so + * that the real driver for the port does not get the + * character. */ ier = inb(ser->port + UART_IER); outb(0x00, ser->port + UART_IER); @@ -3484,39 +3505,142 @@ } while (!(lsr & UART_LSR_DR)); c = inb(ser->port + UART_RX); - /* Restore the interrupts */ + /* + * Restore the interrupts + */ outb(ier, ser->port + UART_IER); + + return c; } -static int serial_console_device(void) +static kdev_t serial_console_device(struct console *c) { - return MKDEV(TTYAUX_MAJOR, 64 + CONFIG_SERIAL_CONSOLE_PORT); + return MKDEV(TTY_MAJOR, 64 + c->index); } -long serial_console_init(long kmem_start, long kmem_end) +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + */ +__initfunc(static void serial_console_setup(struct console *co, char *options)) { - static struct console console = { - serial_console_write, 0, - serial_console_wait_key, serial_console_device - }; struct serial_state *ser; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } - ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT; + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; - /* Disable all interrupts, it works in polled mode */ - outb(0x00, ser->port + UART_IER); + /* + * Divisor, bytesize and parity + */ + ser = rs_table + co->index; + quot = BASE_BAUD / baud; + cval = cflag & (CSIZE | CSTOPB); +#if defined(__powerpc__) || defined(__alpha__) + cval >>= 8; +#else /* !__powerpc__ && !__alpha__ */ + cval >>= 4; +#endif /* !__powerpc__ && !__alpha__ */ + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; /* - * now do hardwired init + * Disable UART interrupts, set DTR and RTS high + * and set speed. */ - outb(0x03, ser->port + UART_LCR); /* No parity, 8 data bits, 1 stop */ - outb(0x83, ser->port + UART_LCR); /* Access divisor latch */ - outb(0x00, ser->port + UART_DLM); /* 9600 baud */ - outb(0x0c, ser->port + UART_DLL); - outb(0x03, ser->port + UART_LCR); /* Done with divisor */ + outb(0, ser->port + UART_IER); + outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR); + outb(cval | UART_LCR_DLAB, ser->port + UART_LCR); /* set DLAB */ + outb(quot & 0xff, ser->port + UART_DLL); /* LS of divisor */ + outb(quot >> 8, ser->port + UART_DLM); /* MS of divisor */ + outb(cval, ser->port + UART_LCR); /* reset DLAB */ - register_console(&console); - return kmem_start; } +static struct console sercons = { + "ttyS", + serial_console_write, + NULL, + serial_console_device, + serial_console_wait_key, + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ +__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +{ + register_console(&sercons); + return kmem_start; +} #endif diff -u --recursive --new-file v2.1.70/linux/drivers/char/specialix.c linux/drivers/char/specialix.c --- v2.1.70/linux/drivers/char/specialix.c Tue Dec 2 16:45:19 1997 +++ linux/drivers/char/specialix.c Wed Dec 3 17:36:26 1997 @@ -70,6 +70,7 @@ * ../../Documentation/specialix.txt */ +#include #include #include @@ -1375,7 +1376,7 @@ !(port->flags & ASYNC_CLOSING) && (do_clocal || CD)) break; - if (current->signal & ~current->blocked) { + if (signal_pending(current)) { retval = -ERESTARTSYS; break; } diff -u --recursive --new-file v2.1.70/linux/drivers/char/tga.c linux/drivers/char/tga.c --- v2.1.70/linux/drivers/char/tga.c Mon Jun 16 16:35:55 1997 +++ linux/drivers/char/tga.c Wed Dec 3 15:21:57 1997 @@ -443,6 +443,19 @@ { } + +/* + * See if we have a TGA card. + */ +__initfunc(int con_is_present()) +{ + int status; + + status = pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, + 0, &pci_bus, &pci_devfn); + return (status == PCIBIOS_DEVICE_NOT_FOUND) ? 0 : 1; +} + /* * video init code, called from within the PCI bus probing code; * when TGA console is configured, at the end of the probing code, diff -u --recursive --new-file v2.1.70/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.70/linux/drivers/char/tty_io.c Tue Dec 2 16:45:19 1997 +++ linux/drivers/char/tty_io.c Thu Dec 4 13:08:49 1997 @@ -90,6 +90,7 @@ #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) #define TTY_DEV MKDEV(TTYAUX_MAJOR,0) +#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1) #undef TTY_DEBUG_HANGUP @@ -386,7 +387,8 @@ continue; if (!filp->f_dentry->d_inode) continue; - if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV) + if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV || + filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) continue; if (filp->f_op != &tty_fops) continue; @@ -517,9 +519,7 @@ void wait_for_keypress(void) { struct console *c = console_drivers; - while(c && !c->wait_key) - c = c->next; - if (c) c->wait_key(); + if (c) c->wait_key(c); } void stop_tty(struct tty_struct *tty) @@ -647,8 +647,13 @@ if (ppos != &file->f_pos) return -ESPIPE; + /* + * For now, we redirect writes from /dev/console as + * well as /dev/tty0. + */ inode = file->f_dentry->d_inode; - is_console = (inode->i_rdev == CONSOLE_DEV); + is_console = (inode->i_rdev == SYSCONS_DEV || + inode->i_rdev == CONSOLE_DEV); if (is_console && redirect) tty = redirect; @@ -1182,13 +1187,20 @@ filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ /* noctty = 1; */ } +#ifdef CONFIG_VT if (device == CONSOLE_DEV) { + extern int fg_console; + device = MKDEV(TTY_MAJOR, fg_console + 1); + noctty = 1; + } +#endif + if (device == SYSCONS_DEV) { struct console *c = console_drivers; while(c && !c->device) c = c->next; if (!c) return -ENODEV; - device = c->device(); + device = c->device(c); noctty = 1; } minor = MINOR(device); @@ -1369,7 +1381,8 @@ static int tioccons(struct tty_struct *tty, struct tty_struct *real_tty) { - if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) { + if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE || + tty->driver.type == TTY_DRIVER_TYPE_SYSCONS) { if (!suser()) return -EPERM; redirect = NULL; @@ -1466,6 +1479,19 @@ return 0; } +static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg) +{ + /* + * (tty == real_tty) is a cheap way of + * testing if the tty is NOT a master pty. + */ + if (tty == real_tty && current->tty != real_tty) + return -ENOTTY; + if (real_tty->session <= 0) + return -ENOTTY; + return put_user(real_tty->session, arg); +} + static int tiocttygstruct(struct tty_struct *tty, struct tty_struct *arg) { if (copy_to_user(arg, tty, sizeof(*arg))) @@ -1585,6 +1611,8 @@ return tiocgpgrp(tty, real_tty, (pid_t *) arg); case TIOCSPGRP: return tiocspgrp(tty, real_tty, (pid_t *) arg); + case TIOCGSID: + return tiocgsid(tty, real_tty, (pid_t *) arg); case TIOCGETD: return put_user(tty->ldisc.num, (int *) arg); case TIOCSETD: @@ -1890,16 +1918,17 @@ * set up the console device so that later boot sequences can * inform about problems etc.. */ -#ifdef CONFIG_SERIAL_CONSOLE - kmem_start = serial_console_init(kmem_start, kmem_end); -#endif #ifdef CONFIG_VT kmem_start = con_init(kmem_start); #endif +#ifdef CONFIG_SERIAL_CONSOLE + kmem_start = serial_console_init(kmem_start, kmem_end); +#endif return kmem_start; } -static struct tty_driver dev_tty_driver, dev_console_driver; +static struct tty_driver dev_tty_driver, dev_console_driver, + dev_syscons_driver; /* * Ok, now we can initialize the rest of the tty devices and can count @@ -1930,17 +1959,28 @@ if (tty_register_driver(&dev_tty_driver)) panic("Couldn't register /dev/tty driver\n"); + dev_syscons_driver = dev_tty_driver; + dev_syscons_driver.driver_name = "/dev/console"; + dev_syscons_driver.name = dev_syscons_driver.driver_name + 5; + dev_syscons_driver.major = TTYAUX_MAJOR; + dev_syscons_driver.minor_start = 1; + dev_syscons_driver.type = TTY_DRIVER_TYPE_SYSTEM; + dev_syscons_driver.subtype = SYSTEM_TYPE_SYSCONS; + + if (tty_register_driver(&dev_syscons_driver)) + panic("Couldn't register /dev/console driver\n"); + +#ifdef CONFIG_VT dev_console_driver = dev_tty_driver; - dev_console_driver.driver_name = "/dev/console"; + dev_console_driver.driver_name = "/dev/tty0"; dev_console_driver.name = dev_console_driver.driver_name + 5; dev_console_driver.major = TTY_MAJOR; dev_console_driver.type = TTY_DRIVER_TYPE_SYSTEM; dev_console_driver.subtype = SYSTEM_TYPE_CONSOLE; if (tty_register_driver(&dev_console_driver)) - panic("Couldn't register /dev/console driver\n"); + panic("Couldn't register /dev/tty0 driver\n"); -#ifdef CONFIG_VT kbd_init(); #endif #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ diff -u --recursive --new-file v2.1.70/linux/drivers/char/vga.c linux/drivers/char/vga.c --- v2.1.70/linux/drivers/char/vga.c Mon Aug 4 16:25:37 1997 +++ linux/drivers/char/vga.c Wed Dec 3 15:21:57 1997 @@ -153,6 +153,32 @@ hide_cursor(); } +__initfunc(int con_is_present(void)) +{ + unsigned short saved; + unsigned short *p; + + /* + * Find out if there is a graphics card present. + * Are there smarter methods around? + */ + p = (unsigned short *)(((ORIG_VIDEO_MODE == 7) ? 0xb0000 : 0xb8000) + + + VGA_OFFSET); + saved = scr_readw(p); + scr_writew(0xAA55, p); + if (scr_readw(p) != 0xAA55) { + scr_writew(saved, p); + return 0; + } + scr_writew(0x55AA, p); + if (scr_readw(p) != 0x55AA) { + scr_writew(saved, p); + return 0; + } + scr_writew(saved, p); + return 1; +} + __initfunc(unsigned long con_type_init(unsigned long kmem_start, const char **display_desc)) { diff -u --recursive --new-file v2.1.70/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.70/linux/drivers/net/Config.in Mon Dec 1 12:04:12 1997 +++ linux/drivers/net/Config.in Wed Dec 3 15:17:30 1997 @@ -149,49 +149,15 @@ comment 'CCP compressors for PPP are only built as modules.' fi -bool 'Radio network interfaces' CONFIG_NET_RADIO -if [ "$CONFIG_NET_RADIO" != "n" ]; then - if [ "$CONFIG_AX25" != "n" ]; then - tristate 'Serial port KISS driver for AX.25' CONFIG_MKISS - tristate 'BPQ Ethernet driver for AX.25' CONFIG_BPQETHER - 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 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 - bool 'Soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS - bool 'Soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200 - bool 'Soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7 - bool 'Soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8 - bool 'Soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800 - bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 - fi - tristate 'Shortwave radio modem driver' CONFIG_HFMODEM - if [ "$CONFIG_HFMODEM" != "n" ]; then - bool 'HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC - bool 'HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS - fi - fi - tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP - tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN -fi - tristate 'SLIP (serial line) support' CONFIG_SLIP if [ "$CONFIG_SLIP" != "n" ]; then bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED bool ' Keepalive and linefill' CONFIG_SLIP_SMART bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 fi + +tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP +tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" = "y" ]; then diff -u --recursive --new-file v2.1.70/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.70/linux/drivers/net/Makefile Mon Dec 1 12:04:12 1997 +++ linux/drivers/net/Makefile Wed Dec 3 15:38:48 1997 @@ -9,30 +9,32 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) hamradio L_TARGET := net.a L_OBJS := auto_irq.o M_OBJS := MOD_LIST_NAME := NET_MODULES -# Need these to keep track of whether the 8390 and SLHC modules should +# Need these to keep track of whether the 8390, PPP and SLHC modules should # really go in the kernel or a module. CONFIG_8390_BUILTIN := CONFIG_8390_MODULE := CONFIG_SLHC_BUILTIN := CONFIG_SLHC_MODULE := -CONFIG_HDLCDRV_BUILTIN := -CONFIG_HDLCDRV_MODULE := +CONFIG_PPPDEF_BUILTIN := +CONFIG_PPPDEF_MODULE := ifeq ($(CONFIG_ISDN),y) ifeq ($(CONFIG_ISDN_PPP),y) CONFIG_SLHC_BUILTIN = y + CONFIG_PPPDEF_BUILTIN = y endif else ifeq ($(CONFIG_ISDN),m) ifeq ($(CONFIG_ISDN_PPP),y) CONFIG_SLHC_MODULE = y + CONFIG_PPPDEF_BUILTIN = y endif endif endif @@ -186,9 +188,11 @@ ifeq ($(CONFIG_PPP),y) LX_OBJS += ppp.o CONFIG_SLHC_BUILTIN = y +CONFIG_PPPDEF_BUILTIN = y else ifeq ($(CONFIG_PPP),m) CONFIG_SLHC_MODULE = y + CONFIG_PPPDEF_MODULE = y MX_OBJS += ppp.o endif endif @@ -201,11 +205,13 @@ L_OBJS += slip.o ifeq ($(CONFIG_SLIP_COMPRESSED),y) CONFIG_SLHC_BUILTIN = y + CONFIG_PPPDEF_BUILTIN = y endif else ifeq ($(CONFIG_SLIP),m) ifeq ($(CONFIG_SLIP_COMPRESSED),y) CONFIG_SLHC_MODULE = y + CONFIG_PPPDEF_MODULE = y endif M_OBJS += slip.o endif @@ -538,46 +544,6 @@ endif endif -ifeq ($(CONFIG_SCC),y) -L_OBJS += scc.o -else - ifeq ($(CONFIG_SCC),m) - M_OBJS += scc.o - endif -endif - -ifeq ($(CONFIG_MKISS),y) -L_OBJS += mkiss.o -else - ifeq ($(CONFIG_MKISS),m) - M_OBJS += mkiss.o - endif -endif - -ifeq ($(CONFIG_PI),y) -L_OBJS += pi2.o -else - ifeq ($(CONFIG_PI),m) - M_OBJS += pi2.o - endif -endif - -ifeq ($(CONFIG_PT),y) -L_OBJS += pt.o -else - ifeq ($(CONFIG_PT),m) - M_OBJS += pt.o - endif -endif - -ifeq ($(CONFIG_BPQETHER),y) -L_OBJS += bpqether.o -else - ifeq ($(CONFIG_BPQETHER),m) - M_OBJS += bpqether.o - endif -endif - ifeq ($(CONFIG_LAPBETHER),y) L_OBJS += lapbether.o else @@ -596,6 +562,15 @@ endif endif +# if anything built-in uses ppp_deflate, then build it into the kernel also. +# If not, but a module uses it, build as a module: +ifdef CONFIG_PPPDEF_BUILTIN +LX_OBJS += ppp_deflate.o +else + ifdef CONFIG_PPPDEF_MODULE + MX_OBJS += ppp_deflate.o + endif +endif # If anything built-in uses the 8390, then build it into the kernel also. # If not, but a module uses it, build as a module. @@ -728,63 +703,10 @@ endif endif -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_PAR),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_par.o - endif -endif - -ifeq ($(CONFIG_SOUNDMODEM),y) -ALL_SUB_DIRS += soundmodem -SUB_DIRS += soundmodem -L_OBJS += soundmodem/soundmodem.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_SOUNDMODEM),m) - CONFIG_HDLCDRV_MODULE = y - ALL_SUB_DIRS += soundmodem - MOD_SUB_DIRS += soundmodem - endif -endif - ifeq ($(CONFIG_MACE),y) L_OBJS += mace.o endif -# If anything built-in uses the hdlcdrv, then build it into the kernel also. -# If not, but a module uses it, build as a module. -ifdef CONFIG_HDLCDRV_BUILTIN -LX_OBJS += hdlcdrv.o -else - ifdef CONFIG_HDLCDRV_MODULE - MX_OBJS += hdlcdrv.o - endif -endif - ifeq ($(CONFIG_VENDOR_SANGOMA),y) M_OBJS += sdladrv.o M_OBJS += wanpipe.o @@ -818,9 +740,6 @@ 3c503.o: 3c503.c CONFIG $(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $< - -pi2.o: pi2.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(PI_OPTS) -c $< 3c505.o: 3c505.c CONFIG $(CC) $(CPPFLAGS) $(CFLAGS) $(ELP_OPTS) -c $< diff -u --recursive --new-file v2.1.70/linux/drivers/net/baycom_par.c linux/drivers/net/baycom_par.c --- v2.1.70/linux/drivers/net/baycom_par.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/net/baycom_par.c Wed Dec 31 16:00:00 1969 @@ -1,661 +0,0 @@ -/*****************************************************************************/ - -/* - * 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.70/linux/drivers/net/baycom_ser_fdx.c linux/drivers/net/baycom_ser_fdx.c --- v2.1.70/linux/drivers/net/baycom_ser_fdx.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/net/baycom_ser_fdx.c Wed Dec 31 16:00:00 1969 @@ -1,762 +0,0 @@ -/*****************************************************************************/ - -/* - * 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.70/linux/drivers/net/baycom_ser_hdx.c linux/drivers/net/baycom_ser_hdx.c --- v2.1.70/linux/drivers/net/baycom_ser_hdx.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/net/baycom_ser_hdx.c Wed Dec 31 16:00:00 1969 @@ -1,792 +0,0 @@ -/*****************************************************************************/ - -/* - * 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.70/linux/drivers/net/bpqether.c linux/drivers/net/bpqether.c --- v2.1.70/linux/drivers/net/bpqether.c Sat Nov 29 11:25:09 1997 +++ linux/drivers/net/bpqether.c Wed Dec 31 16:00:00 1969 @@ -1,669 +0,0 @@ -/* - * G8BPQ compatible "AX.25 via ethernet" driver release 003 - * - * This code REQUIRES 2.0.0 or higher/ NET3.029 - * - * This module: - * This module 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 is a "pseudo" network driver to allow AX.25 over Ethernet - * using G8BPQ encapsulation. It has been extracted from the protocol - * implementation because - * - * - things got unreadable within the protocol stack - * - to cure the protocol stack from "feature-ism" - * - a protocol implementation shouldn't need to know on - * which hardware it is running - * - user-level programs like the AX.25 utilities shouldn't - * need to know about the hardware. - * - IP over ethernet encapsulated AX.25 was impossible - * - rxecho.c did not work - * - to have room for extensions - * - it just deserves to "live" as an own driver - * - * This driver can use any ethernet destination address, and can be - * limited to accept frames from one dedicated ethernet card only. - * - * Note that the driver sets up the BPQ devices automagically on - * startup or (if started before the "insmod" of an ethernet device) - * on "ifconfig up". It hopefully will remove the BPQ on "rmmod"ing - * the ethernet device (in fact: as soon as another ethernet or bpq - * device gets "ifconfig"ured). - * - * I have heard that several people are thinking of experiments - * with highspeed packet radio using existing ethernet cards. - * Well, this driver is prepared for this purpose, just add - * your tx key control and a txdelay / tailtime algorithm, - * probably some buffering, and /voila/... - * - * History - * BPQ 001 Joerg(DL1BKE) Extracted BPQ code from AX.25 - * protocol stack and added my own - * yet existing patches - * BPQ 002 Joerg(DL1BKE) Scan network device list on - * startup. - * BPQ 003 Joerg(DL1BKE) Ethernet destination address - * and accepted source address - * can be configured by an ioctl() - * call. - * Fixed to match Linux networking - * changes - 2.1.15. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -static unsigned char ax25_bcast[AX25_ADDR_LEN] = - {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static unsigned char ax25_defaddr[AX25_ADDR_LEN] = - {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - -static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - -static char bpq_eth_addr[6]; - -static int bpq_rcv(struct sk_buff *, struct device *, struct packet_type *); -static int bpq_device_event(struct notifier_block *, unsigned long, void *); -static char *bpq_print_ethaddr(unsigned char *); - -static struct packet_type bpq_packet_type = { - 0, /* ntohs(ETH_P_BPQ),*/ - 0, /* copy */ - bpq_rcv, - NULL, - NULL, -}; - -static struct notifier_block bpq_dev_notifier = { - bpq_device_event, - 0 -}; - - -#define MAXBPQDEV 100 - -static struct bpqdev { - struct bpqdev *next; - char ethname[14]; /* ether device name */ - struct device *ethdev; /* link to ethernet device */ - struct device axdev; /* bpq device (bpq#) */ - struct net_device_stats stats; /* some statistics */ - char dest_addr[6]; /* ether destination address */ - char acpt_addr[6]; /* accept ether frames from this address only */ -} *bpq_devices = NULL; - - -/* ------------------------------------------------------------------------ */ - - -/* - * Get the ethernet device for a BPQ device - */ -static __inline__ struct device *bpq_get_ether_dev(struct device *dev) -{ - struct bpqdev *bpq; - - bpq = (struct bpqdev *)dev->priv; - - return (bpq != NULL) ? bpq->ethdev : NULL; -} - -/* - * Get the BPQ device for the ethernet device - */ -static __inline__ struct device *bpq_get_ax25_dev(struct device *dev) -{ - struct bpqdev *bpq; - - for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) - if (bpq->ethdev == dev) - return &bpq->axdev; - - return NULL; -} - -static __inline__ int dev_is_ethdev(struct device *dev) -{ - return ( - dev->type == ARPHRD_ETHER - && strncmp(dev->name, "dummy", 5) - ); -} - -/* - * Sanity check: remove all devices that ceased to exists and - * return '1' if the given BPQ device was affected. - */ -static int bpq_check_devices(struct device *dev) -{ - struct bpqdev *bpq, *bpq_prev; - int result = 0; - unsigned long flags; - - save_flags(flags); - cli(); - - bpq_prev = NULL; - - for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) { - if (!dev_get(bpq->ethname)) { - if (bpq_prev) - bpq_prev->next = bpq->next; - else - bpq_devices = bpq->next; - - if (&bpq->axdev == dev) - result = 1; - - unregister_netdev(&bpq->axdev); - kfree(bpq); - } - - bpq_prev = bpq; - } - - restore_flags(flags); - - return result; -} - - -/* ------------------------------------------------------------------------ */ - - -/* - * Receive an AX.25 frame via an ethernet interface. - */ -static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) -{ - int len; - char * ptr; - struct ethhdr *eth = (struct ethhdr *)skb->mac.raw; - struct bpqdev *bpq; - - skb->sk = NULL; /* Initially we don't know who it's for */ - - dev = bpq_get_ax25_dev(dev); - - if (dev == NULL || dev->start == 0) { - kfree_skb(skb, FREE_READ); - return 0; - } - - /* - * if we want to accept frames from just one ethernet device - * we check the source address of the sender. - */ - - bpq = (struct bpqdev *)dev->priv; - - if (!(bpq->acpt_addr[0] & 0x01) && memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) { - printk(KERN_DEBUG "bpqether: wrong dest %s\n", bpq_print_ethaddr(eth->h_source)); - kfree_skb(skb, FREE_READ); - return 0; - } - - len = skb->data[0] + skb->data[1] * 256 - 5; - - skb_pull(skb, 2); /* Remove the length bytes */ - skb_trim(skb, len); /* Set the length of the data */ - - ((struct bpqdev *)dev->priv)->stats.rx_packets++; - ((struct bpqdev *)dev->priv)->stats.rx_bytes+=len; - - ptr = skb_push(skb, 1); - *ptr = 0; - - skb->dev = dev; - skb->protocol = htons(ETH_P_AX25); - skb->mac.raw = skb->data; - skb->pkt_type = PACKET_HOST; - - netif_rx(skb); - - return 0; -} - -/* - * Send an AX.25 frame via an ethernet interface - */ -static int bpq_xmit(struct sk_buff *skb, struct device *dev) -{ - struct sk_buff *newskb; - unsigned char *ptr; - struct bpqdev *bpq; - int size; - - /* - * Just to be *really* sure not to send anything if the interface - * is down, the ethernet device may have gone. - */ - if (!dev->start) { - bpq_check_devices(dev); - kfree_skb(skb, FREE_WRITE); - return -ENODEV; - } - - skb_pull(skb, 1); - size = skb->len; - - /* - * The AX.25 code leaves enough room for the ethernet header, but - * sendto() does not. - */ - if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { /* Ough! */ - if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { - printk(KERN_WARNING "bpqether: out of memory\n"); - kfree_skb(skb, FREE_WRITE); - return -ENOMEM; - } - - if (skb->sk != NULL) - skb_set_owner_w(newskb, skb->sk); - - kfree_skb(skb, FREE_WRITE); - skb = newskb; - } - - skb->protocol = htons(ETH_P_AX25); - - ptr = skb_push(skb, 2); - - *ptr++ = (size + 5) % 256; - *ptr++ = (size + 5) / 256; - - bpq = (struct bpqdev *)dev->priv; - - if ((dev = bpq_get_ether_dev(dev)) == NULL) { - bpq->stats.tx_dropped++; - kfree_skb(skb, FREE_WRITE); - return -ENODEV; - } - - skb->dev = dev; - dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); - bpq->stats.tx_packets++; - bpq->stats.tx_bytes+=skb->len; - - dev_queue_xmit(skb); - - return 0; -} - -/* - * Statistics - */ -static struct net_device_stats *bpq_get_stats(struct device *dev) -{ - struct bpqdev *bpq; - - bpq = (struct bpqdev *)dev->priv; - - return &bpq->stats; -} - -/* - * Set AX.25 callsign - */ -static int bpq_set_mac_address(struct device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *)addr; - - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - - return 0; -} - -/* Ioctl commands - * - * SIOCSBPQETHOPT reserved for enhancements - * SIOCSBPQETHADDR set the destination and accepted - * source ethernet address (broadcast - * or multicast: accept all) - */ -static int bpq_ioctl(struct device *dev, struct ifreq *ifr, int cmd) -{ - int err; - struct bpq_ethaddr *ethaddr = (struct bpq_ethaddr *)ifr->ifr_data; - struct bpqdev *bpq = dev->priv; - struct bpq_req req; - - if (!suser()) - return -EPERM; - - if (bpq == NULL) /* woops! */ - return -ENODEV; - - switch (cmd) { - case SIOCSBPQETHOPT: - if ((err = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct bpq_req))) != 0) - return err; - copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req)); - switch (req.cmd) { - case SIOCGBPQETHPARAM: - case SIOCSBPQETHPARAM: - default: - return -EINVAL; - } - - break; - - case SIOCSBPQETHADDR: - if ((err = verify_area(VERIFY_READ, ethaddr, sizeof(struct bpq_ethaddr))) != 0) - return err; - copy_from_user(bpq->dest_addr, ethaddr->destination, ETH_ALEN); - copy_from_user(bpq->acpt_addr, ethaddr->accept, ETH_ALEN); - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * open/close a device - */ -static int bpq_open(struct device *dev) -{ - if (bpq_check_devices(dev)) - return -ENODEV; /* oops, it's gone */ - - dev->tbusy = 0; - dev->start = 1; - - MOD_INC_USE_COUNT; - - return 0; -} - -static int bpq_close(struct device *dev) -{ - dev->tbusy = 1; - dev->start = 0; - - MOD_DEC_USE_COUNT; - - return 0; -} - -/* - * currently unused - */ -static int bpq_dev_init(struct device *dev) -{ - return 0; -} - - -/* ------------------------------------------------------------------------ */ - - -/* - * Proc filesystem - */ -static char * bpq_print_ethaddr(unsigned char *e) -{ - static char buf[18]; - - sprintf(buf, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", - e[0], e[1], e[2], e[3], e[4], e[5]); - - return buf; -} - -int bpq_get_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - struct bpqdev *bpqdev; - int len = 0; - off_t pos = 0; - off_t begin = 0; - - cli(); - - len += sprintf(buffer, "dev ether destination accept from\n"); - - for (bpqdev = bpq_devices; bpqdev != NULL; bpqdev = bpqdev->next) { - len += sprintf(buffer + len, "%-5s %-10s %s ", - bpqdev->axdev.name, bpqdev->ethname, - bpq_print_ethaddr(bpqdev->dest_addr)); - - len += sprintf(buffer + len, "%s\n", - (bpqdev->acpt_addr[0] & 0x01) ? "*" : bpq_print_ethaddr(bpqdev->acpt_addr)); - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; - } - - sti(); - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) len = length; - - return len; -} - - -/* ------------------------------------------------------------------------ */ - - -/* - * Setup a new device. - */ -static int bpq_new_device(struct device *dev) -{ - int k; - unsigned char *buf; - struct bpqdev *bpq, *bpq2; - - if ((bpq = kmalloc(sizeof(struct bpqdev), GFP_KERNEL)) == NULL) - return -ENOMEM; - - memset(bpq, 0, sizeof(struct bpqdev)); - - bpq->ethdev = dev; - - bpq->ethname[sizeof(bpq->ethname)-1] = '\0'; - strncpy(bpq->ethname, dev->name, sizeof(bpq->ethname)-1); - - memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr)); - memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); - - dev = &bpq->axdev; - buf = kmalloc(14, GFP_KERNEL); - - for (k = 0; k < MAXBPQDEV; k++) { - struct device *odev; - - sprintf(buf, "bpq%d", k); - - if ((odev = dev_get(buf)) == NULL || bpq_check_devices(odev)) - break; - } - - if (k == MAXBPQDEV) { - kfree(bpq); - return -ENODEV; - } - - dev->priv = (void *)bpq; /* pointer back */ - dev->name = buf; - dev->init = bpq_dev_init; - - if (register_netdev(dev) != 0) { - kfree(bpq); - return -EIO; - } - - dev_init_buffers(dev); - - dev->hard_start_xmit = bpq_xmit; - dev->open = bpq_open; - dev->stop = bpq_close; - dev->set_mac_address = bpq_set_mac_address; - dev->get_stats = bpq_get_stats; - dev->do_ioctl = bpq_ioctl; - - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN); - - dev->flags = 0; - -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; -#endif - - dev->type = ARPHRD_AX25; - dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; - dev->mtu = AX25_DEF_PACLEN; - dev->addr_len = AX25_ADDR_LEN; - - cli(); - - if (bpq_devices == NULL) { - bpq_devices = bpq; - } else { - for (bpq2 = bpq_devices; bpq2->next != NULL; bpq2 = bpq2->next); - bpq2->next = bpq; - } - - sti(); - - return 0; -} - - -/* - * Handle device status changes. - */ -static int bpq_device_event(struct notifier_block *this,unsigned long event, void *ptr) -{ - struct device *dev = (struct device *)ptr; - - if (!dev_is_ethdev(dev)) - return NOTIFY_DONE; - - bpq_check_devices(NULL); - - switch (event) { - case NETDEV_UP: /* new ethernet device -> new BPQ interface */ - if (bpq_get_ax25_dev(dev) == NULL) - bpq_new_device(dev); - break; - - case NETDEV_DOWN: /* ethernet device closed -> close BPQ interface */ - if ((dev = bpq_get_ax25_dev(dev)) != NULL) - dev_close(dev); - break; - - default: - break; - } - - return NOTIFY_DONE; -} - - -/* ------------------------------------------------------------------------ */ - -/* - * Initialize driver. To be called from af_ax25 if not compiled as a - * module - */ -__initfunc(int bpq_init(void)) -{ - struct device *dev; - - bpq_packet_type.type = htons(ETH_P_BPQ); - dev_add_pack(&bpq_packet_type); - - register_netdevice_notifier(&bpq_dev_notifier); - - printk(KERN_INFO "AX.25 ethernet driver version 0.01\n"); - -#ifdef CONFIG_PROC_FS - proc_net_register(&(struct proc_dir_entry) { - PROC_NET_AX25_BPQETHER, 8, "bpqether", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - bpq_get_info - }); -#endif - - for (dev = dev_base; dev != NULL; dev = dev->next) { - if (dev_is_ethdev(dev)) - bpq_new_device(dev); - } - - return 0; -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -MODULE_AUTHOR("Joerg Reuter DL1BKE "); -MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet"); - -int init_module(void) -{ - return bpq_init(); -} - -void cleanup_module(void) -{ - struct bpqdev *bpq; - - dev_remove_pack(&bpq_packet_type); - - unregister_netdevice_notifier(&bpq_dev_notifier); - -#ifdef CONFIG_PROC_FS - proc_net_unregister(PROC_NET_AX25_BPQETHER); -#endif - - for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) - unregister_netdev(&bpq->axdev); -} -#endif diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in --- v2.1.70/linux/drivers/net/hamradio/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/Config.in Wed Dec 3 15:17:30 1997 @@ -0,0 +1,62 @@ +# +# Amateur Radio protocols and AX.25 device configuration +# +# 19971130 Now in an own category to make correct compilation of the +# AX.25 stuff easier... +# Joerg Reuter DL1BKE + +mainmenu_option next_comment +comment 'Amateur Radio support' +bool 'Amateur Radio support' CONFIG_HAMRADIO + +if [ "$CONFIG_HAMRADIO" != "n" ] ; then + if [ "$CONFIG_NET" != "n" ] ; then + comment 'Packet Radio protocols' + tristate 'Amateur Radio AX.25 Level 2 protocol' CONFIG_AX25 + if [ "$CONFIG_AX25" != "n" ]; then + bool ' AX.25 DAMA Slave support' CONFIG_AX25_DAMA_SLAVE +# bool ' AX.25 DAMA Master support' CONFIG_AX25_DAMA_MASTER + dep_tristate ' Amateur Radio NET/ROM protocol' CONFIG_NETROM $CONFIG_AX25 + dep_tristate ' Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25 + fi + + if [ "$CONFIG_AX25" != "n" ]; then + comment 'AX.25 network device drivers' + tristate 'Serial port KISS driver' CONFIG_MKISS +# tristate 'Serial port 6PACK driver' CONFIG_6PACK + tristate 'BPQ Ethernet driver' CONFIG_BPQETHER + tristate 'Gracilis PackeTwin driver' CONFIG_PT + tristate 'Ottawa PI and PI2 driver' CONFIG_PI + + tristate 'Z8530 SCC driver' 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 + + 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' CONFIG_SOUNDMODEM + if [ "$CONFIG_SOUNDMODEM" != "n" ]; then + bool ' soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC + bool ' soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS + bool ' soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200 + bool ' soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7 + bool ' soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8 + bool ' soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800 + bool ' soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 + fi + fi + fi + + comment 'Misc. hamradio protocols' + tristate 'Shortwave radio modem driver' CONFIG_HFMODEM + if [ "$CONFIG_HFMODEM" != "n" ]; then + bool ' HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC + bool ' HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS + fi +fi + +endmenu diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile --- v2.1.70/linux/drivers/net/hamradio/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/Makefile Wed Dec 3 15:17:30 1997 @@ -0,0 +1,120 @@ +# File: drivers/hamradio/Makefile +# +# Makefile for the Linux AX.25 and HFMODEM device drivers. +# +# 19971130 Moved the amateur radio related network drivers from +# drivers/net/ to drivers/hamradio for easier maintainance. +# Joerg Reuter DL1BKE + + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +L_TARGET := hamradio.a +L_OBJS := +M_OBJS := +MOD_LIST_NAME := HAM_MODULES + +# Need these to keep track of whether the hdlc module should +# really go in the kernel or a module. +CONFIG_HDLCDRV_BUILTIN := +CONFIG_HDLCDRV_MODULE := + +ifeq ($(CONFIG_SCC),y) +L_OBJS += scc.o +else + ifeq ($(CONFIG_SCC),m) + M_OBJS += scc.o + endif +endif + +ifeq ($(CONFIG_MKISS),y) +L_OBJS += mkiss.o +else + ifeq ($(CONFIG_MKISS),m) + M_OBJS += mkiss.o + endif +endif + +ifeq ($(CONFIG_PI),y) +L_OBJS += pi2.o +else + ifeq ($(CONFIG_PI),m) + M_OBJS += pi2.o + endif +endif + +ifeq ($(CONFIG_PT),y) +L_OBJS += pt.o +else + ifeq ($(CONFIG_PT),m) + M_OBJS += pt.o + endif +endif + +ifeq ($(CONFIG_BPQETHER),y) +L_OBJS += bpqether.o +else + ifeq ($(CONFIG_BPQETHER),m) + M_OBJS += bpqether.o + endif +endif + +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_PAR),m) + CONFIG_HDLCDRV_MODULE = y + M_OBJS += baycom_par.o + endif +endif + +ifeq ($(CONFIG_SOUNDMODEM),y) +ALL_SUB_DIRS += soundmodem +SUB_DIRS += soundmodem +L_OBJS += soundmodem/soundmodem.o +CONFIG_HDLCDRV_BUILTIN = y +else + ifeq ($(CONFIG_SOUNDMODEM),m) + CONFIG_HDLCDRV_MODULE = y + ALL_SUB_DIRS += soundmodem + MOD_SUB_DIRS += soundmodem + endif +endif + +# If anything built-in uses the hdlcdrv, then build it into the kernel also. +# If not, but a module uses it, build as a module. +ifdef CONFIG_HDLCDRV_BUILTIN +LX_OBJS += hdlcdrv.o +else + ifdef CONFIG_HDLCDRV_MODULE + MX_OBJS += hdlcdrv.o + endif +endif + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c --- v2.1.70/linux/drivers/net/hamradio/baycom_par.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/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.70/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c --- v2.1.70/linux/drivers/net/hamradio/baycom_ser_fdx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/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.70/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c --- v2.1.70/linux/drivers/net/hamradio/baycom_ser_hdx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/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.70/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c --- v2.1.70/linux/drivers/net/hamradio/bpqether.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/bpqether.c Sat Nov 29 10:33:19 1997 @@ -0,0 +1,669 @@ +/* + * G8BPQ compatible "AX.25 via ethernet" driver release 003 + * + * This code REQUIRES 2.0.0 or higher/ NET3.029 + * + * This module: + * This module 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 is a "pseudo" network driver to allow AX.25 over Ethernet + * using G8BPQ encapsulation. It has been extracted from the protocol + * implementation because + * + * - things got unreadable within the protocol stack + * - to cure the protocol stack from "feature-ism" + * - a protocol implementation shouldn't need to know on + * which hardware it is running + * - user-level programs like the AX.25 utilities shouldn't + * need to know about the hardware. + * - IP over ethernet encapsulated AX.25 was impossible + * - rxecho.c did not work + * - to have room for extensions + * - it just deserves to "live" as an own driver + * + * This driver can use any ethernet destination address, and can be + * limited to accept frames from one dedicated ethernet card only. + * + * Note that the driver sets up the BPQ devices automagically on + * startup or (if started before the "insmod" of an ethernet device) + * on "ifconfig up". It hopefully will remove the BPQ on "rmmod"ing + * the ethernet device (in fact: as soon as another ethernet or bpq + * device gets "ifconfig"ured). + * + * I have heard that several people are thinking of experiments + * with highspeed packet radio using existing ethernet cards. + * Well, this driver is prepared for this purpose, just add + * your tx key control and a txdelay / tailtime algorithm, + * probably some buffering, and /voila/... + * + * History + * BPQ 001 Joerg(DL1BKE) Extracted BPQ code from AX.25 + * protocol stack and added my own + * yet existing patches + * BPQ 002 Joerg(DL1BKE) Scan network device list on + * startup. + * BPQ 003 Joerg(DL1BKE) Ethernet destination address + * and accepted source address + * can be configured by an ioctl() + * call. + * Fixed to match Linux networking + * changes - 2.1.15. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static unsigned char ax25_bcast[AX25_ADDR_LEN] = + {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; +static unsigned char ax25_defaddr[AX25_ADDR_LEN] = + {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; + +static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; + +static char bpq_eth_addr[6]; + +static int bpq_rcv(struct sk_buff *, struct device *, struct packet_type *); +static int bpq_device_event(struct notifier_block *, unsigned long, void *); +static char *bpq_print_ethaddr(unsigned char *); + +static struct packet_type bpq_packet_type = { + 0, /* ntohs(ETH_P_BPQ),*/ + 0, /* copy */ + bpq_rcv, + NULL, + NULL, +}; + +static struct notifier_block bpq_dev_notifier = { + bpq_device_event, + 0 +}; + + +#define MAXBPQDEV 100 + +static struct bpqdev { + struct bpqdev *next; + char ethname[14]; /* ether device name */ + struct device *ethdev; /* link to ethernet device */ + struct device axdev; /* bpq device (bpq#) */ + struct net_device_stats stats; /* some statistics */ + char dest_addr[6]; /* ether destination address */ + char acpt_addr[6]; /* accept ether frames from this address only */ +} *bpq_devices = NULL; + + +/* ------------------------------------------------------------------------ */ + + +/* + * Get the ethernet device for a BPQ device + */ +static __inline__ struct device *bpq_get_ether_dev(struct device *dev) +{ + struct bpqdev *bpq; + + bpq = (struct bpqdev *)dev->priv; + + return (bpq != NULL) ? bpq->ethdev : NULL; +} + +/* + * Get the BPQ device for the ethernet device + */ +static __inline__ struct device *bpq_get_ax25_dev(struct device *dev) +{ + struct bpqdev *bpq; + + for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) + if (bpq->ethdev == dev) + return &bpq->axdev; + + return NULL; +} + +static __inline__ int dev_is_ethdev(struct device *dev) +{ + return ( + dev->type == ARPHRD_ETHER + && strncmp(dev->name, "dummy", 5) + ); +} + +/* + * Sanity check: remove all devices that ceased to exists and + * return '1' if the given BPQ device was affected. + */ +static int bpq_check_devices(struct device *dev) +{ + struct bpqdev *bpq, *bpq_prev; + int result = 0; + unsigned long flags; + + save_flags(flags); + cli(); + + bpq_prev = NULL; + + for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) { + if (!dev_get(bpq->ethname)) { + if (bpq_prev) + bpq_prev->next = bpq->next; + else + bpq_devices = bpq->next; + + if (&bpq->axdev == dev) + result = 1; + + unregister_netdev(&bpq->axdev); + kfree(bpq); + } + + bpq_prev = bpq; + } + + restore_flags(flags); + + return result; +} + + +/* ------------------------------------------------------------------------ */ + + +/* + * Receive an AX.25 frame via an ethernet interface. + */ +static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) +{ + int len; + char * ptr; + struct ethhdr *eth = (struct ethhdr *)skb->mac.raw; + struct bpqdev *bpq; + + skb->sk = NULL; /* Initially we don't know who it's for */ + + dev = bpq_get_ax25_dev(dev); + + if (dev == NULL || dev->start == 0) { + kfree_skb(skb, FREE_READ); + return 0; + } + + /* + * if we want to accept frames from just one ethernet device + * we check the source address of the sender. + */ + + bpq = (struct bpqdev *)dev->priv; + + if (!(bpq->acpt_addr[0] & 0x01) && memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) { + printk(KERN_DEBUG "bpqether: wrong dest %s\n", bpq_print_ethaddr(eth->h_source)); + kfree_skb(skb, FREE_READ); + return 0; + } + + len = skb->data[0] + skb->data[1] * 256 - 5; + + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ + + ((struct bpqdev *)dev->priv)->stats.rx_packets++; + ((struct bpqdev *)dev->priv)->stats.rx_bytes+=len; + + ptr = skb_push(skb, 1); + *ptr = 0; + + skb->dev = dev; + skb->protocol = htons(ETH_P_AX25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + netif_rx(skb); + + return 0; +} + +/* + * Send an AX.25 frame via an ethernet interface + */ +static int bpq_xmit(struct sk_buff *skb, struct device *dev) +{ + struct sk_buff *newskb; + unsigned char *ptr; + struct bpqdev *bpq; + int size; + + /* + * Just to be *really* sure not to send anything if the interface + * is down, the ethernet device may have gone. + */ + if (!dev->start) { + bpq_check_devices(dev); + kfree_skb(skb, FREE_WRITE); + return -ENODEV; + } + + skb_pull(skb, 1); + size = skb->len; + + /* + * The AX.25 code leaves enough room for the ethernet header, but + * sendto() does not. + */ + if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { /* Ough! */ + if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { + printk(KERN_WARNING "bpqether: out of memory\n"); + kfree_skb(skb, FREE_WRITE); + return -ENOMEM; + } + + if (skb->sk != NULL) + skb_set_owner_w(newskb, skb->sk); + + kfree_skb(skb, FREE_WRITE); + skb = newskb; + } + + skb->protocol = htons(ETH_P_AX25); + + ptr = skb_push(skb, 2); + + *ptr++ = (size + 5) % 256; + *ptr++ = (size + 5) / 256; + + bpq = (struct bpqdev *)dev->priv; + + if ((dev = bpq_get_ether_dev(dev)) == NULL) { + bpq->stats.tx_dropped++; + kfree_skb(skb, FREE_WRITE); + return -ENODEV; + } + + skb->dev = dev; + dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); + bpq->stats.tx_packets++; + bpq->stats.tx_bytes+=skb->len; + + dev_queue_xmit(skb); + + return 0; +} + +/* + * Statistics + */ +static struct net_device_stats *bpq_get_stats(struct device *dev) +{ + struct bpqdev *bpq; + + bpq = (struct bpqdev *)dev->priv; + + return &bpq->stats; +} + +/* + * Set AX.25 callsign + */ +static int bpq_set_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa = (struct sockaddr *)addr; + + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + + return 0; +} + +/* Ioctl commands + * + * SIOCSBPQETHOPT reserved for enhancements + * SIOCSBPQETHADDR set the destination and accepted + * source ethernet address (broadcast + * or multicast: accept all) + */ +static int bpq_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + int err; + struct bpq_ethaddr *ethaddr = (struct bpq_ethaddr *)ifr->ifr_data; + struct bpqdev *bpq = dev->priv; + struct bpq_req req; + + if (!suser()) + return -EPERM; + + if (bpq == NULL) /* woops! */ + return -ENODEV; + + switch (cmd) { + case SIOCSBPQETHOPT: + if ((err = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct bpq_req))) != 0) + return err; + copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req)); + switch (req.cmd) { + case SIOCGBPQETHPARAM: + case SIOCSBPQETHPARAM: + default: + return -EINVAL; + } + + break; + + case SIOCSBPQETHADDR: + if ((err = verify_area(VERIFY_READ, ethaddr, sizeof(struct bpq_ethaddr))) != 0) + return err; + copy_from_user(bpq->dest_addr, ethaddr->destination, ETH_ALEN); + copy_from_user(bpq->acpt_addr, ethaddr->accept, ETH_ALEN); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * open/close a device + */ +static int bpq_open(struct device *dev) +{ + if (bpq_check_devices(dev)) + return -ENODEV; /* oops, it's gone */ + + dev->tbusy = 0; + dev->start = 1; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int bpq_close(struct device *dev) +{ + dev->tbusy = 1; + dev->start = 0; + + MOD_DEC_USE_COUNT; + + return 0; +} + +/* + * currently unused + */ +static int bpq_dev_init(struct device *dev) +{ + return 0; +} + + +/* ------------------------------------------------------------------------ */ + + +/* + * Proc filesystem + */ +static char * bpq_print_ethaddr(unsigned char *e) +{ + static char buf[18]; + + sprintf(buf, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", + e[0], e[1], e[2], e[3], e[4], e[5]); + + return buf; +} + +int bpq_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + struct bpqdev *bpqdev; + int len = 0; + off_t pos = 0; + off_t begin = 0; + + cli(); + + len += sprintf(buffer, "dev ether destination accept from\n"); + + for (bpqdev = bpq_devices; bpqdev != NULL; bpqdev = bpqdev->next) { + len += sprintf(buffer + len, "%-5s %-10s %s ", + bpqdev->axdev.name, bpqdev->ethname, + bpq_print_ethaddr(bpqdev->dest_addr)); + + len += sprintf(buffer + len, "%s\n", + (bpqdev->acpt_addr[0] & 0x01) ? "*" : bpq_print_ethaddr(bpqdev->acpt_addr)); + + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + + if (pos > offset + length) + break; + } + + sti(); + + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) len = length; + + return len; +} + + +/* ------------------------------------------------------------------------ */ + + +/* + * Setup a new device. + */ +static int bpq_new_device(struct device *dev) +{ + int k; + unsigned char *buf; + struct bpqdev *bpq, *bpq2; + + if ((bpq = kmalloc(sizeof(struct bpqdev), GFP_KERNEL)) == NULL) + return -ENOMEM; + + memset(bpq, 0, sizeof(struct bpqdev)); + + bpq->ethdev = dev; + + bpq->ethname[sizeof(bpq->ethname)-1] = '\0'; + strncpy(bpq->ethname, dev->name, sizeof(bpq->ethname)-1); + + memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr)); + memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); + + dev = &bpq->axdev; + buf = kmalloc(14, GFP_KERNEL); + + for (k = 0; k < MAXBPQDEV; k++) { + struct device *odev; + + sprintf(buf, "bpq%d", k); + + if ((odev = dev_get(buf)) == NULL || bpq_check_devices(odev)) + break; + } + + if (k == MAXBPQDEV) { + kfree(bpq); + return -ENODEV; + } + + dev->priv = (void *)bpq; /* pointer back */ + dev->name = buf; + dev->init = bpq_dev_init; + + if (register_netdev(dev) != 0) { + kfree(bpq); + return -EIO; + } + + dev_init_buffers(dev); + + dev->hard_start_xmit = bpq_xmit; + dev->open = bpq_open; + dev->stop = bpq_close; + dev->set_mac_address = bpq_set_mac_address; + dev->get_stats = bpq_get_stats; + dev->do_ioctl = bpq_ioctl; + + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN); + + dev->flags = 0; + +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; +#endif + + dev->type = ARPHRD_AX25; + dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; + dev->mtu = AX25_DEF_PACLEN; + dev->addr_len = AX25_ADDR_LEN; + + cli(); + + if (bpq_devices == NULL) { + bpq_devices = bpq; + } else { + for (bpq2 = bpq_devices; bpq2->next != NULL; bpq2 = bpq2->next); + bpq2->next = bpq; + } + + sti(); + + return 0; +} + + +/* + * Handle device status changes. + */ +static int bpq_device_event(struct notifier_block *this,unsigned long event, void *ptr) +{ + struct device *dev = (struct device *)ptr; + + if (!dev_is_ethdev(dev)) + return NOTIFY_DONE; + + bpq_check_devices(NULL); + + switch (event) { + case NETDEV_UP: /* new ethernet device -> new BPQ interface */ + if (bpq_get_ax25_dev(dev) == NULL) + bpq_new_device(dev); + break; + + case NETDEV_DOWN: /* ethernet device closed -> close BPQ interface */ + if ((dev = bpq_get_ax25_dev(dev)) != NULL) + dev_close(dev); + break; + + default: + break; + } + + return NOTIFY_DONE; +} + + +/* ------------------------------------------------------------------------ */ + +/* + * Initialize driver. To be called from af_ax25 if not compiled as a + * module + */ +__initfunc(int bpq_init(void)) +{ + struct device *dev; + + bpq_packet_type.type = htons(ETH_P_BPQ); + dev_add_pack(&bpq_packet_type); + + register_netdevice_notifier(&bpq_dev_notifier); + + printk(KERN_INFO "AX.25 ethernet driver version 0.01\n"); + +#ifdef CONFIG_PROC_FS + proc_net_register(&(struct proc_dir_entry) { + PROC_NET_AX25_BPQETHER, 8, "bpqether", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + bpq_get_info + }); +#endif + + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (dev_is_ethdev(dev)) + bpq_new_device(dev); + } + + return 0; +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Joerg Reuter DL1BKE "); +MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet"); + +int init_module(void) +{ + return bpq_init(); +} + +void cleanup_module(void) +{ + struct bpqdev *bpq; + + dev_remove_pack(&bpq_packet_type); + + unregister_netdevice_notifier(&bpq_dev_notifier); + +#ifdef CONFIG_PROC_FS + proc_net_unregister(PROC_NET_AX25_BPQETHER); +#endif + + for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) + unregister_netdev(&bpq->axdev); +} +#endif diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c --- v2.1.70/linux/drivers/net/hamradio/hdlcdrv.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/hdlcdrv.c Sun Nov 30 10:30:19 1997 @@ -0,0 +1,1024 @@ +/*****************************************************************************/ + +/* + * hdlcdrv.c -- HDLC packet radio network 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. + * + * The driver was derived from Donald Beckers skeleton.c + * Written 1993-94 by Donald Becker. + * + * History: + * 0.1 21.09.96 Started + * 18.10.96 Changed to new user space access routines + * (copy_{to,from}_user) + * 0.2 21.11.96 various small changes + * 0.3 03.03.97 fixed (hopefully) IP not working with ax.25 as a module + * 0.4 16.04.97 init code/data tagged + * 0.5 30.07.97 made HDLC buffers bigger (solves a problem with the + * soundmodem driver) + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +/* prototypes for ax25_encapsulate and ax25_rebuild_header */ +#include +#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + +/* make genksyms happy */ +#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 < 0x20115 +extern __inline__ void dev_init_buffers(struct device *dev) +{ + int i; + for(i=0;ibuffs[i]); + } +} +#endif + +/* --------------------------------------------------------------------- */ + +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + +/* --------------------------------------------------------------------- */ + +#if LINUX_VERSION_CODE < 0x20125 +#define test_and_set_bit set_bit +#define test_and_clear_bit clear_bit +#endif + +/* --------------------------------------------------------------------- */ + +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ + +static char ax25_bcast[AX25_ADDR_LEN] = +{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; +static char ax25_nocall[AX25_ADDR_LEN] = +{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; + +/* --------------------------------------------------------------------- */ + +#define KISS_VERBOSE + +/* --------------------------------------------------------------------- */ + +#define PARAM_TXDELAY 1 +#define PARAM_PERSIST 2 +#define PARAM_SLOTTIME 3 +#define PARAM_TXTAIL 4 +#define PARAM_FULLDUP 5 +#define PARAM_HARDWARE 6 +#define PARAM_RETURN 255 + +/* --------------------------------------------------------------------- */ + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +/* --------------------------------------------------------------------- */ +/* + * the CRC routines are stolen from WAMPES + * by Dieter Deyke + */ + +static const unsigned short crc_ccitt_table[] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/*---------------------------------------------------------------------------*/ + +static inline void append_crc_ccitt(unsigned char *buffer, int len) +{ + unsigned int crc = 0xffff; + + for (;len>0;len--) + crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff]; + crc ^= 0xffff; + *buffer++ = crc; + *buffer++ = crc >> 8; +} + +/*---------------------------------------------------------------------------*/ + +static inline int check_crc_ccitt(const unsigned char *buf, int cnt) +{ + unsigned int crc = 0xffff; + + for (; cnt > 0; cnt--) + crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; + return (crc & 0xffff) == 0xf0b8; +} + +/*---------------------------------------------------------------------------*/ + +#if 0 +static int calc_crc_ccitt(const unsigned char *buf, int cnt) +{ + unsigned int crc = 0xffff; + + for (; cnt > 0; cnt--) + crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; + crc ^= 0xffff; + return (crc & 0xffff); +} +#endif + +/* ---------------------------------------------------------------------- */ + +#define tenms_to_2flags(s,tenms) ((tenms * s->par.bitrate) / 100 / 16) + +/* ---------------------------------------------------------------------- */ +/* + * The HDLC routines + */ + +static int hdlc_rx_add_bytes(struct hdlcdrv_state *s, unsigned int bits, + int num) +{ + int added = 0; + + while (s->hdlcrx.rx_state && num >= 8) { + if (s->hdlcrx.len >= sizeof(s->hdlcrx.buffer)) { + s->hdlcrx.rx_state = 0; + return 0; + } + *s->hdlcrx.bp++ = bits >> (32-num); + s->hdlcrx.len++; + num -= 8; + added += 8; + } + return added; +} + +static void hdlc_rx_flag(struct device *dev, struct hdlcdrv_state *s) +{ + struct sk_buff *skb; + int pkt_len; + unsigned char *cp; + + if (s->hdlcrx.len < 4) + return; + if (!check_crc_ccitt(s->hdlcrx.buffer, s->hdlcrx.len)) + return; + pkt_len = s->hdlcrx.len - 2 + 1; /* KISS kludge */ + if (!(skb = dev_alloc_skb(pkt_len))) { + printk("%s: memory squeeze, dropping packet\n", + s->ifname); + s->stats.rx_dropped++; + return; + } + skb->dev = dev; + cp = skb_put(skb, pkt_len); + *cp++ = 0; /* KISS kludge */ + memcpy(cp, s->hdlcrx.buffer, pkt_len - 1); + skb->protocol = htons(ETH_P_AX25); + skb->mac.raw = skb->data; + netif_rx(skb); + s->stats.rx_packets++; +} + +void hdlcdrv_receiver(struct device *dev, struct hdlcdrv_state *s) +{ + int i; + unsigned int mask1, mask2, mask3, mask4, mask5, mask6, word; + + if (!s || s->magic != HDLCDRV_MAGIC) + return; + if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx)) + return; + + while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) { + word = hdlcdrv_hbuf_get(&s->hdlcrx.hbuf); + +#ifdef HDLCDRV_DEBUG + hdlcdrv_add_bitbuffer_word(&s->bitbuf_hdlc, word); +#endif /* HDLCDRV_DEBUG */ + s->hdlcrx.bitstream >>= 16; + s->hdlcrx.bitstream |= word << 16; + s->hdlcrx.bitbuf >>= 16; + s->hdlcrx.bitbuf |= word << 16; + s->hdlcrx.numbits += 16; + for(i = 15, mask1 = 0x1fc00, mask2 = 0x1fe00, mask3 = 0x0fc00, + mask4 = 0x1f800, mask5 = 0xf800, mask6 = 0xffff; + i >= 0; + i--, mask1 <<= 1, mask2 <<= 1, mask3 <<= 1, mask4 <<= 1, + mask5 <<= 1, mask6 = (mask6 << 1) | 1) { + if ((s->hdlcrx.bitstream & mask1) == mask1) + s->hdlcrx.rx_state = 0; /* abort received */ + else if ((s->hdlcrx.bitstream & mask2) == mask3) { + /* flag received */ + if (s->hdlcrx.rx_state) { + hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf + << (8+i), + s->hdlcrx.numbits + -8-i); + hdlc_rx_flag(dev, s); + } + s->hdlcrx.len = 0; + s->hdlcrx.bp = s->hdlcrx.buffer; + s->hdlcrx.rx_state = 1; + s->hdlcrx.numbits = i; + } else if ((s->hdlcrx.bitstream & mask4) == mask5) { + /* stuffed bit */ + s->hdlcrx.numbits--; + s->hdlcrx.bitbuf = (s->hdlcrx.bitbuf & (~mask6)) | + ((s->hdlcrx.bitbuf & mask6) << 1); + } + } + s->hdlcrx.numbits -= hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf, + s->hdlcrx.numbits); + } + clear_bit(0, &s->hdlcrx.in_hdlc_rx); +} + +/* ---------------------------------------------------------------------- */ + +static void inline do_kiss_params(struct hdlcdrv_state *s, + unsigned char *data, unsigned long len) +{ + +#ifdef KISS_VERBOSE +#define PKP(a,b) printk(KERN_INFO "%s: channel params: " a "\n", s->ifname, b) +#else /* KISS_VERBOSE */ +#define PKP(a,b) +#endif /* KISS_VERBOSE */ + + if (len < 2) + return; + switch(data[0]) { + case PARAM_TXDELAY: + s->ch_params.tx_delay = data[1]; + PKP("TX delay = %ums", 10 * s->ch_params.tx_delay); + break; + case PARAM_PERSIST: + s->ch_params.ppersist = data[1]; + PKP("p persistence = %u", s->ch_params.ppersist); + break; + case PARAM_SLOTTIME: + s->ch_params.slottime = data[1]; + PKP("slot time = %ums", s->ch_params.slottime); + break; + case PARAM_TXTAIL: + s->ch_params.tx_tail = data[1]; + PKP("TX tail = %ums", s->ch_params.tx_tail); + break; + case PARAM_FULLDUP: + s->ch_params.fulldup = !!data[1]; + PKP("%s duplex", s->ch_params.fulldup ? "full" : "half"); + break; + default: + break; + } +#undef PKP +} + +/* ---------------------------------------------------------------------- */ + +void hdlcdrv_transmitter(struct device *dev, struct hdlcdrv_state *s) +{ + unsigned int mask1, mask2, mask3; + int i; + struct sk_buff *skb; + int pkt_len; + + if (!s || s->magic != HDLCDRV_MAGIC) + return; + if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx)) + return; + for (;;) { + if (s->hdlctx.numbits >= 16) { + if (hdlcdrv_hbuf_full(&s->hdlctx.hbuf)) { + clear_bit(0, &s->hdlctx.in_hdlc_tx); + return; + } + hdlcdrv_hbuf_put(&s->hdlctx.hbuf, s->hdlctx.bitbuf); + s->hdlctx.bitbuf >>= 16; + s->hdlctx.numbits -= 16; + } + switch (s->hdlctx.tx_state) { + default: + clear_bit(0, &s->hdlctx.in_hdlc_tx); + return; + case 0: + case 1: + if (s->hdlctx.numflags) { + s->hdlctx.numflags--; + s->hdlctx.bitbuf |= + 0x7e7e << s->hdlctx.numbits; + s->hdlctx.numbits += 16; + break; + } + if (s->hdlctx.tx_state == 1) { + clear_bit(0, &s->hdlctx.in_hdlc_tx); + return; + } + if (!(skb = skb_dequeue(&s->send_queue))) { + int flgs = tenms_to_2flags + (s, s->ch_params.tx_tail); + if (flgs < 2) + flgs = 2; + s->hdlctx.tx_state = 1; + s->hdlctx.numflags = flgs; + break; + } + if (skb->data[0] != 0) { + do_kiss_params(s, skb->data, skb->len); + dev_kfree_skb(skb, FREE_WRITE); + break; + } + pkt_len = skb->len-1; /* strip KISS byte */ + if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) { + s->hdlctx.tx_state = 0; + s->hdlctx.numflags = 1; + dev_kfree_skb(skb, FREE_WRITE); + break; + } + memcpy(s->hdlctx.buffer, skb->data+1, pkt_len); + dev_kfree_skb(skb, FREE_WRITE); + s->hdlctx.bp = s->hdlctx.buffer; + append_crc_ccitt(s->hdlctx.buffer, pkt_len); + s->hdlctx.len = pkt_len+2; /* the appended CRC */ + s->hdlctx.tx_state = 2; + s->hdlctx.bitstream = 0; + s->stats.tx_packets++; + break; + case 2: + if (!s->hdlctx.len) { + s->hdlctx.tx_state = 0; + s->hdlctx.numflags = 1; + break; + } + s->hdlctx.len--; + s->hdlctx.bitbuf |= *s->hdlctx.bp << + s->hdlctx.numbits; + s->hdlctx.bitstream >>= 8; + s->hdlctx.bitstream |= (*s->hdlctx.bp++) << 16; + mask1 = 0x1f000; + mask2 = 0x10000; + mask3 = 0xffffffff >> (31-s->hdlctx.numbits); + s->hdlctx.numbits += 8; + for(i = 0; i < 8; i++, mask1 <<= 1, mask2 <<= 1, + mask3 = (mask3 << 1) | 1) { + if ((s->hdlctx.bitstream & mask1) != mask1) + continue; + s->hdlctx.bitstream &= ~mask2; + s->hdlctx.bitbuf = + (s->hdlctx.bitbuf & mask3) | + ((s->hdlctx.bitbuf & + (~mask3)) << 1); + s->hdlctx.numbits++; + mask3 = (mask3 << 1) | 1; + } + break; + } + } +} + +/* ---------------------------------------------------------------------- */ + +static void start_tx(struct device *dev, struct hdlcdrv_state *s) +{ + s->hdlctx.tx_state = 0; + s->hdlctx.numflags = tenms_to_2flags(s, s->ch_params.tx_delay); + s->hdlctx.bitbuf = s->hdlctx.bitstream = s->hdlctx.numbits = 0; + hdlcdrv_transmitter(dev, s); + s->hdlctx.ptt = 1; + s->ptt_keyed++; +} + +/* ---------------------------------------------------------------------- */ + +static unsigned short random_seed; + +static inline unsigned short random_num(void) +{ + random_seed = 28629 * random_seed + 157; + return random_seed; +} + +/* ---------------------------------------------------------------------- */ + +void hdlcdrv_arbitrate(struct device *dev, struct hdlcdrv_state *s) +{ + if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt || + skb_queue_empty(&s->send_queue)) + return; + if (s->ch_params.fulldup) { + start_tx(dev, s); + return; + } + if (s->hdlcrx.dcd) { + s->hdlctx.slotcnt = s->ch_params.slottime; + return; + } + if ((--s->hdlctx.slotcnt) > 0) + return; + s->hdlctx.slotcnt = s->ch_params.slottime; + if ((random_num() % 256) > s->ch_params.ppersist) + return; + start_tx(dev, s); +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== network driver interface ========================= + */ + +static inline int hdlcdrv_paranoia_check(struct device *dev, + const char *routine) +{ + if (!dev || !dev->priv || + ((struct hdlcdrv_state *)dev->priv)->magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "hdlcdrv: bad magic number for hdlcdrv_state " + "struct in routine %s\n", routine); + return 1; + } + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int hdlcdrv_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct hdlcdrv_state *sm; + + if (hdlcdrv_paranoia_check(dev, "hdlcdrv_send_packet")) + return 0; + sm = (struct hdlcdrv_state *)dev->priv; + skb_queue_tail(&sm->send_queue, skb); + dev->trans_start = jiffies; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int hdlcdrv_set_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa = (struct sockaddr *)addr; + + /* addr is an AX.25 shifted ASCII mac address */ + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + return 0; +} + +/* --------------------------------------------------------------------- */ + +#if LINUX_VERSION_CODE >= 0x20119 +static struct net_device_stats *hdlcdrv_get_stats(struct device *dev) +#else +static struct enet_statistics *hdlcdrv_get_stats(struct device *dev) +#endif +{ + struct hdlcdrv_state *sm; + + if (hdlcdrv_paranoia_check(dev, "hdlcdrv_get_stats")) + return NULL; + sm = (struct hdlcdrv_state *)dev->priv; + /* + * Get the current statistics. This may be called with the + * card open or closed. + */ + return &sm->stats; +} + +/* --------------------------------------------------------------------- */ +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ + +static int hdlcdrv_open(struct device *dev) +{ + struct hdlcdrv_state *s; + int i; + + if (hdlcdrv_paranoia_check(dev, "hdlcdrv_open")) + return -EINVAL; + s = (struct hdlcdrv_state *)dev->priv; + + if (dev->start) + return 0; + if (!s->ops || !s->ops->open) + return -ENODEV; + + dev->start = 1; + /* + * initialise some variables + */ + s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; + s->hdlcrx.in_hdlc_rx = 0; + s->hdlcrx.rx_state = 0; + + s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; + s->hdlctx.in_hdlc_tx = 0; + s->hdlctx.tx_state = 1; + s->hdlctx.numflags = 0; + s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; + s->hdlctx.ptt = 0; + s->hdlctx.slotcnt = s->ch_params.slottime; + s->hdlctx.calibrate = 0; + + i = s->ops->open(dev); + if (i) { + dev->start = 0; + return i; + } + + dev->tbusy = 0; + dev->interrupt = 0; + + return 0; +} + +/* --------------------------------------------------------------------- */ +/* + * The inverse routine to hdlcdrv_open(). + */ + +static int hdlcdrv_close(struct device *dev) +{ + struct hdlcdrv_state *s; + struct sk_buff *skb; + int i = 0; + + if (hdlcdrv_paranoia_check(dev, "hdlcdrv_close")) + return -EINVAL; + s = (struct hdlcdrv_state *)dev->priv; + + if (!dev->start) + return 0; + dev->start = 0; + dev->tbusy = 1; + + if (s->ops && s->ops->close) + i = s->ops->close(dev); + /* Free any buffers left in the hardware transmit queue */ + while ((skb = skb_dequeue(&s->send_queue))) + dev_kfree_skb(skb, FREE_WRITE); + return i; +} + +/* --------------------------------------------------------------------- */ + +static int hdlcdrv_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + struct hdlcdrv_state *s; + struct hdlcdrv_ioctl bi; + + if (hdlcdrv_paranoia_check(dev, "hdlcdrv_ioctl")) + return -EINVAL; + s = (struct hdlcdrv_state *)dev->priv; + + if (cmd != SIOCDEVPRIVATE) { + if (s->ops && s->ops->ioctl) + return s->ops->ioctl(dev, ifr, &bi, cmd); + return -ENOIOCTLCMD; + } + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + + switch (bi.cmd) { + default: + if (s->ops && s->ops->ioctl) + return s->ops->ioctl(dev, ifr, &bi, cmd); + return -ENOIOCTLCMD; + + case HDLCDRVCTL_GETCHANNELPAR: + bi.data.cp.tx_delay = s->ch_params.tx_delay; + bi.data.cp.tx_tail = s->ch_params.tx_tail; + bi.data.cp.slottime = s->ch_params.slottime; + bi.data.cp.ppersist = s->ch_params.ppersist; + bi.data.cp.fulldup = s->ch_params.fulldup; + break; + + case HDLCDRVCTL_SETCHANNELPAR: + if (!suser()) + return -EACCES; + s->ch_params.tx_delay = bi.data.cp.tx_delay; + s->ch_params.tx_tail = bi.data.cp.tx_tail; + s->ch_params.slottime = bi.data.cp.slottime; + s->ch_params.ppersist = bi.data.cp.ppersist; + s->ch_params.fulldup = bi.data.cp.fulldup; + s->hdlctx.slotcnt = 1; + return 0; + + case HDLCDRVCTL_GETMODEMPAR: + bi.data.mp.iobase = dev->base_addr; + bi.data.mp.irq = dev->irq; + bi.data.mp.dma = dev->dma; + bi.data.mp.dma2 = s->ptt_out.dma2; + bi.data.mp.seriobase = s->ptt_out.seriobase; + bi.data.mp.pariobase = s->ptt_out.pariobase; + bi.data.mp.midiiobase = s->ptt_out.midiiobase; + break; + + case HDLCDRVCTL_SETMODEMPAR: + if ((!suser()) || dev->start) + return -EACCES; + dev->base_addr = bi.data.mp.iobase; + dev->irq = bi.data.mp.irq; + dev->dma = bi.data.mp.dma; + s->ptt_out.dma2 = bi.data.mp.dma2; + s->ptt_out.seriobase = bi.data.mp.seriobase; + s->ptt_out.pariobase = bi.data.mp.pariobase; + s->ptt_out.midiiobase = bi.data.mp.midiiobase; + return 0; + + case HDLCDRVCTL_GETSTAT: + bi.data.cs.ptt = hdlcdrv_ptt(s); + bi.data.cs.dcd = s->hdlcrx.dcd; + bi.data.cs.ptt_keyed = s->ptt_keyed; + bi.data.cs.tx_packets = s->stats.tx_packets; + bi.data.cs.tx_errors = s->stats.tx_errors; + bi.data.cs.rx_packets = s->stats.rx_packets; + bi.data.cs.rx_errors = s->stats.rx_errors; + break; + + case HDLCDRVCTL_OLDGETSTAT: + bi.data.ocs.ptt = hdlcdrv_ptt(s); + bi.data.ocs.dcd = s->hdlcrx.dcd; + bi.data.ocs.ptt_keyed = s->ptt_keyed; +#if LINUX_VERSION_CODE < 0x20100 + bi.data.ocs.stats = s->stats; +#endif + break; + + case HDLCDRVCTL_CALIBRATE: + s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16; + return 0; + + case HDLCDRVCTL_GETSAMPLES: +#ifndef HDLCDRV_DEBUG + return -EPERM; +#else /* HDLCDRV_DEBUG */ + if (s->bitbuf_channel.rd == s->bitbuf_channel.wr) + return -EAGAIN; + bi.data.bits = + s->bitbuf_channel.buffer[s->bitbuf_channel.rd]; + s->bitbuf_channel.rd = (s->bitbuf_channel.rd+1) % + sizeof(s->bitbuf_channel.buffer); + break; +#endif /* HDLCDRV_DEBUG */ + + case HDLCDRVCTL_GETBITS: +#ifndef HDLCDRV_DEBUG + return -EPERM; +#else /* HDLCDRV_DEBUG */ + if (s->bitbuf_hdlc.rd == s->bitbuf_hdlc.wr) + return -EAGAIN; + bi.data.bits = + s->bitbuf_hdlc.buffer[s->bitbuf_hdlc.rd]; + s->bitbuf_hdlc.rd = (s->bitbuf_hdlc.rd+1) % + sizeof(s->bitbuf_hdlc.buffer); + break; +#endif /* HDLCDRV_DEBUG */ + + case HDLCDRVCTL_DRIVERNAME: + if (s->ops && s->ops->drvname) { + strncpy(bi.data.drivername, s->ops->drvname, + sizeof(bi.data.drivername)); + break; + } + bi.data.drivername[0] = '\0'; + break; + + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + +} + +/* --------------------------------------------------------------------- */ + +/* + * Check for a network adaptor of this type, and return '0' if one exists. + * If dev->base_addr == 0, probe all likely locations. + * If dev->base_addr == 1, always return failure. + * If dev->base_addr == 2, allocate space for the device and return success + * (detachable devices only). + */ +static int hdlcdrv_probe(struct device *dev) +{ + const struct hdlcdrv_channel_params dflt_ch_params = { + 20, 2, 10, 40, 0 + }; + struct hdlcdrv_state *s; + + if (!dev) + return -ENXIO; + /* + * not a real probe! only initialize data structures + */ + s = (struct hdlcdrv_state *)dev->priv; + /* + * initialize the hdlcdrv_state struct + */ + s->ch_params = dflt_ch_params; + s->ptt_keyed = 0; + + s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; + s->hdlcrx.in_hdlc_rx = 0; + s->hdlcrx.rx_state = 0; + + s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; + s->hdlctx.in_hdlc_tx = 0; + s->hdlctx.tx_state = 1; + s->hdlctx.numflags = 0; + s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; + s->hdlctx.ptt = 0; + s->hdlctx.slotcnt = s->ch_params.slottime; + s->hdlctx.calibrate = 0; + +#ifdef HDLCDRV_DEBUG + s->bitbuf_channel.rd = s->bitbuf_channel.wr = 0; + s->bitbuf_channel.shreg = 0x80; + + s->bitbuf_hdlc.rd = s->bitbuf_hdlc.wr = 0; + s->bitbuf_hdlc.shreg = 0x80; +#endif /* HDLCDRV_DEBUG */ + + /* + * initialize the device struct + */ + dev->open = hdlcdrv_open; + dev->stop = hdlcdrv_close; + dev->do_ioctl = hdlcdrv_ioctl; + dev->hard_start_xmit = hdlcdrv_send_packet; + dev->get_stats = hdlcdrv_get_stats; + + /* Fill in the fields of the device structure */ + + dev_init_buffers(dev); + + skb_queue_head_init(&s->send_queue); + +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; +#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + dev->hard_header = NULL; + dev->rebuild_header = NULL; +#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + dev->set_mac_address = hdlcdrv_set_mac_address; + + dev->type = ARPHRD_AX25; /* AF_AX25 device */ + 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; + + return 0; +} + +/* --------------------------------------------------------------------- */ + +int hdlcdrv_register_hdlcdrv(struct device *dev, const struct hdlcdrv_ops *ops, + unsigned int privsize, char *ifname, + unsigned int baseaddr, unsigned int irq, + unsigned int dma) +{ + struct hdlcdrv_state *s; + + if (!dev || !ops) + return -EACCES; + if (privsize < sizeof(struct hdlcdrv_state)) + privsize = sizeof(struct hdlcdrv_state); + memset(dev, 0, sizeof(struct device)); + if (!(s = dev->priv = kmalloc(privsize, GFP_KERNEL))) + return -ENOMEM; + /* + * initialize part of the hdlcdrv_state struct + */ + memset(s, 0, privsize); + s->magic = HDLCDRV_MAGIC; + strncpy(s->ifname, ifname, sizeof(s->ifname)); + s->ops = ops; + /* + * initialize part of the device struct + */ + dev->name = s->ifname; + dev->if_port = 0; + dev->init = hdlcdrv_probe; + dev->start = 0; + dev->tbusy = 1; + dev->base_addr = baseaddr; + dev->irq = irq; + dev->dma = dma; + if (register_netdev(dev)) { + printk(KERN_WARNING "hdlcdrv: cannot register net " + "device %s\n", s->ifname); + kfree(dev->priv); + return -ENXIO; + } + MOD_INC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +int hdlcdrv_unregister_hdlcdrv(struct device *dev) +{ + struct hdlcdrv_state *s; + + if (!dev) + return -EINVAL; + if (!(s = (struct hdlcdrv_state *)dev->priv)) + return -EINVAL; + if (s->magic != HDLCDRV_MAGIC) + return -EINVAL; + if (dev->start && s->ops->close) + s->ops->close(dev); + unregister_netdev(dev); + kfree(s); + MOD_DEC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +#if LINUX_VERSION_CODE >= 0x20115 + +EXPORT_SYMBOL(hdlcdrv_receiver); +EXPORT_SYMBOL(hdlcdrv_transmitter); +EXPORT_SYMBOL(hdlcdrv_arbitrate); +EXPORT_SYMBOL(hdlcdrv_register_hdlcdrv); +EXPORT_SYMBOL(hdlcdrv_unregister_hdlcdrv); + +#else + +static struct symbol_table hdlcdrv_syms = { +#include + X(hdlcdrv_receiver), + X(hdlcdrv_transmitter), + X(hdlcdrv_arbitrate), + X(hdlcdrv_register_hdlcdrv), + X(hdlcdrv_unregister_hdlcdrv), +#include +}; + +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder"); + +#endif + +/* --------------------------------------------------------------------- */ + +__initfunc(int init_module(void)) +{ + printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n"); + printk(KERN_INFO "hdlcdrv: version 0.5 compiled " __TIME__ " " __DATE__ "\n"); +#if LINUX_VERSION_CODE < 0x20115 + register_symtab(&hdlcdrv_syms); +#endif + return 0; +} + +/* --------------------------------------------------------------------- */ + +void cleanup_module(void) +{ + printk(KERN_INFO "hdlcdrv: cleanup\n"); +} + +#endif /* MODULE */ +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c --- v2.1.70/linux/drivers/net/hamradio/mkiss.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/mkiss.c Sat Nov 29 10:33:19 1997 @@ -0,0 +1,1134 @@ +/* + * MKISS Driver + * + * This module: + * This module 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 module implements the AX.25 protocol for kernel-based + * devices like TTYs. It interfaces between a raw TTY, and the + * kernel's AX.25 protocol layers, just like slip.c. + * AX.25 needs to be seperated from slip.c while slip.c is no + * longer a static kernel device since it is a module. + * This method clears the way to implement other kiss protocols + * like mkiss smack g8bpq ..... so far only mkiss is implemented. + * + * Hans Alblas + * + * History + * Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include "mkiss.h" + +#ifdef CONFIG_INET +#include +#include +#endif + +#ifdef MODULE +#define AX25_VERSION "AX25-MODULAR-NET3.019-NEWTTY" +#define min(a,b) (a < b ? a : b) +#else +#define AX25_VERSION "AX25-NET3.019-NEWTTY" +#endif + +#define NR_MKISS 4 +#define MKISS_SERIAL_TYPE_NORMAL 1 + +struct mkiss_channel { + int magic; /* magic word */ + int init; /* channel exists? */ + struct tty_struct *tty; /* link to tty control structure */ +}; + +typedef struct ax25_ctrl { + char if_name[8]; /* "ax0\0" .. "ax99999\0" */ + struct ax_disp ctrl; /* */ + struct device dev; /* the device */ +} ax25_ctrl_t; + +static ax25_ctrl_t **ax25_ctrls = NULL; + +int ax25_maxdev = AX25_MAXDEV; /* Can be overridden with insmod! */ + +static struct tty_ldisc ax_ldisc; +static struct tty_driver mkiss_driver; +static int mkiss_refcount; +static struct tty_struct *mkiss_table[NR_MKISS]; +static struct termios *mkiss_termios[NR_MKISS]; +static struct termios *mkiss_termios_locked[NR_MKISS]; +struct mkiss_channel MKISS_Info[NR_MKISS]; + +static int ax25_init(struct device *); +static int mkiss_init(void); +static int mkiss_write(struct tty_struct *, int, const unsigned char *, int); +static int kiss_esc(unsigned char *, unsigned char *, int); +static void kiss_unesc(struct ax_disp *, unsigned char); + +/* Find a free channel, and link in this `tty' line. */ +static inline struct ax_disp *ax_alloc(void) +{ + ax25_ctrl_t *axp; + int i; + + if (ax25_ctrls == NULL) /* Master array missing ! */ + return NULL; + + for (i = 0; i < ax25_maxdev; i++) { + axp = ax25_ctrls[i]; + + /* Not allocated ? */ + if (axp == NULL) + break; + + /* Not in use ? */ + if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags)) + break; + } + + /* Sorry, too many, all slots in use */ + if (i >= ax25_maxdev) + return NULL; + + /* If no channels are available, allocate one */ + if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) { + axp = ax25_ctrls[i]; + memset(axp, 0, sizeof(ax25_ctrl_t)); + + /* Initialize channel control data */ + set_bit(AXF_INUSE, &axp->ctrl.flags); + sprintf(axp->if_name, "ax%d", i++); + axp->ctrl.tty = NULL; + axp->dev.name = axp->if_name; + axp->dev.base_addr = i; + axp->dev.priv = (void *)&axp->ctrl; + axp->dev.next = NULL; + axp->dev.init = ax25_init; + } + + if (axp != NULL) { + /* + * register device so that it can be ifconfig'ed + * ax25_init() will be called as a side-effect + * SIDE-EFFECT WARNING: ax25_init() CLEARS axp->ctrl ! + */ + if (register_netdev(&axp->dev) == 0) { + /* (Re-)Set the INUSE bit. Very Important! */ + set_bit(AXF_INUSE, &axp->ctrl.flags); + axp->ctrl.dev = &axp->dev; + axp->dev.priv = (void *)&axp->ctrl; + + return &axp->ctrl; + } else { + clear_bit(AXF_INUSE,&axp->ctrl.flags); + printk(KERN_ERR "mkiss: ax_alloc() - register_netdev() failure.\n"); + } + } + + return NULL; +} + +/* Free an AX25 channel. */ +static inline void ax_free(struct ax_disp *ax) +{ + /* Free all AX25 frame buffers. */ + if (ax->rbuff) + kfree(ax->rbuff); + ax->rbuff = NULL; + if (ax->xbuff) + kfree(ax->xbuff); + ax->xbuff = NULL; + if (!test_and_clear_bit(AXF_INUSE, &ax->flags)) + printk(KERN_ERR "mkiss: %s: ax_free for already free unit.\n", ax->dev->name); +} + +static void ax_changedmtu(struct ax_disp *ax) +{ + struct device *dev = ax->dev; + unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; + int len; + unsigned long flags; + + len = dev->mtu * 2; + + /* + * allow for arrival of larger UDP packets, even if we say not to + * also fixes a bug in which SunOS sends 512-byte packets even with + * an MSS of 128 + */ + if (len < 576 * 2) + len = 576 * 2; + + xbuff = kmalloc(len + 4, GFP_ATOMIC); + rbuff = kmalloc(len + 4, GFP_ATOMIC); + + if (xbuff == NULL || rbuff == NULL) { + printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, MTU change cancelled.\n", + ax->dev->name); + dev->mtu = ax->mtu; + if (xbuff != NULL) + kfree(xbuff); + if (rbuff != NULL) + kfree(rbuff); + return; + } + + save_flags(flags); + cli(); + + oxbuff = ax->xbuff; + ax->xbuff = xbuff; + orbuff = ax->rbuff; + ax->rbuff = rbuff; + + if (ax->xleft) { + if (ax->xleft <= len) { + memcpy(ax->xbuff, ax->xhead, ax->xleft); + } else { + ax->xleft = 0; + ax->tx_dropped++; + } + } + + ax->xhead = ax->xbuff; + + if (ax->rcount) { + if (ax->rcount <= len) { + memcpy(ax->rbuff, orbuff, ax->rcount); + } else { + ax->rcount = 0; + ax->rx_over_errors++; + set_bit(AXF_ERROR, &ax->flags); + } + } + + ax->mtu = dev->mtu + 73; + ax->buffsize = len; + + restore_flags(flags); + + if (oxbuff != NULL) + kfree(oxbuff); + if (orbuff != NULL) + kfree(orbuff); +} + + +/* Set the "sending" flag. This must be atomic, hence the ASM. */ +static inline void ax_lock(struct ax_disp *ax) +{ + if (test_and_set_bit(0, (void *)&ax->dev->tbusy)) + printk(KERN_ERR "mkiss: %s: trying to lock already locked device!\n", ax->dev->name); +} + + +/* Clear the "sending" flag. This must be atomic, hence the ASM. */ +static inline void ax_unlock(struct ax_disp *ax) +{ + if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy)) + printk(KERN_ERR "mkiss: %s: trying to unlock already unlocked device!\n", ax->dev->name); +} + +/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ +static void ax_bump(struct ax_disp *ax) +{ + struct ax_disp *tmp_ax; + struct sk_buff *skb; + struct mkiss_channel *mkiss; + int count; + + tmp_ax = ax; + + if (ax->rbuff[0] > 0x0f) { + if (ax->mkiss != NULL) { + mkiss= ax->mkiss->tty->driver_data; + if (mkiss->magic == MKISS_DRIVER_MAGIC) + tmp_ax = ax->mkiss; + } + } + + count = ax->rcount; + + if ((skb = dev_alloc_skb(count)) == NULL) { + printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); + ax->rx_dropped++; + return; + } + + skb->dev = tmp_ax->dev; + memcpy(skb_put(skb,count), ax->rbuff, count); + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_AX25); + netif_rx(skb); + tmp_ax->rx_packets++; +} + +/* Encapsulate one AX.25 packet and stuff into a TTY queue. */ +static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) +{ + unsigned char *p; + int actual, count; + struct mkiss_channel *mkiss = ax->tty->driver_data; + + if (ax->mtu != ax->dev->mtu + 73) /* Someone has been ifconfigging */ + ax_changedmtu(ax); + + if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ + len = ax->mtu; + printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name); + ax->tx_dropped++; + ax_unlock(ax); + return; + } + + p = icp; + + if (mkiss->magic != MKISS_DRIVER_MAGIC) { + count = kiss_esc(p, (unsigned char *)ax->xbuff, len); + ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + actual = ax->tty->driver.write(ax->tty, 0, ax->xbuff, count); + ax->tx_packets++; + ax->dev->trans_start = jiffies; + ax->xleft = count - actual; + ax->xhead = ax->xbuff + actual; + } else { + count = kiss_esc(p, (unsigned char *) ax->mkiss->xbuff, len); + ax->mkiss->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + actual = ax->mkiss->tty->driver.write(ax->mkiss->tty, 0, ax->mkiss->xbuff, count); + ax->tx_packets++; + ax->mkiss->dev->trans_start = jiffies; + ax->mkiss->xleft = count - actual; + ax->mkiss->xhead = ax->mkiss->xbuff + actual; + } +} + +/* + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + */ +static void ax25_write_wakeup(struct tty_struct *tty) +{ + int actual; + struct ax_disp *ax = (struct ax_disp *)tty->disc_data; + struct mkiss_channel *mkiss; + + /* First make sure we're connected. */ + if (ax == NULL || ax->magic != AX25_MAGIC || !ax->dev->start) + return; + if (ax->xleft <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet + */ + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + + if (ax->mkiss != NULL) { + mkiss= ax->mkiss->tty->driver_data; + if (mkiss->magic == MKISS_DRIVER_MAGIC) + ax_unlock(ax->mkiss); + } + + ax_unlock(ax); + mark_bh(NET_BH); + return; + } + + actual = tty->driver.write(tty, 0, ax->xhead, ax->xleft); + ax->xleft -= actual; + ax->xhead += actual; +} + +/* Encapsulate an AX.25 packet and kick it into a TTY queue. */ +static int ax_xmit(struct sk_buff *skb, struct device *dev) +{ + struct ax_disp *ax = (struct ax_disp*)dev->priv; + struct mkiss_channel *mkiss = ax->tty->driver_data; + struct ax_disp *tmp_ax; + + tmp_ax = NULL; + + if (mkiss->magic == MKISS_DRIVER_MAGIC) { + if (skb->data[0] < 0x10) + skb->data[0] = skb->data[0] + 0x10; + tmp_ax = ax->mkiss; + } + + if (!dev->start) { + printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); + return 1; + } + + if (tmp_ax != NULL) + if (tmp_ax->dev->tbusy) + return 1; + + if (tmp_ax != NULL) + if (dev->tbusy) { + printk(KERN_ERR "mkiss: dev busy while serial dev is free\n"); + ax_unlock(ax); + } + + if (dev->tbusy) { + /* + * May be we must check transmitter timeout here ? + * 14 Oct 1994 Dmitry Gorodchanin. + */ + if (jiffies - dev->trans_start < 20 * HZ) { + /* 20 sec timeout not reached */ + return 1; + } + + printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, + (ax->tty->driver.chars_in_buffer(ax->tty) || ax->xleft) ? + "bad line quality" : "driver error"); + + ax->xleft = 0; + ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + ax_unlock(ax); + } + + /* We were not busy, so we are now... :-) */ + if (skb != NULL) { + ax_lock(ax); + if (tmp_ax != NULL) + ax_lock(tmp_ax); + ax_encaps(ax, skb->data, skb->len); + kfree_skb(skb, FREE_WRITE); + } + + return 0; +} + +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + +/* Return the frame type ID */ +static int ax_header(struct sk_buff *skb, struct device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len) +{ +#ifdef CONFIG_INET + if (type != htons(ETH_P_AX25)) + return ax25_encapsulate(skb, dev, type, daddr, saddr, len); +#endif + return 0; +} + + +static int ax_rebuild_header(struct sk_buff *skb) +{ +#ifdef CONFIG_INET + return ax25_rebuild_header(skb); +#else + return 0; +#endif +} + +#endif /* CONFIG_{AX25,AX25_MODULE} */ + +/* Open the low-level part of the AX25 channel. Easy! */ +static int ax_open(struct device *dev) +{ + struct ax_disp *ax = (struct ax_disp*)dev->priv; + unsigned long len; + + if (ax->tty == NULL) + return -ENODEV; + + /* + * Allocate the frame buffers: + * + * rbuff Receive buffer. + * xbuff Transmit buffer. + * cbuff Temporary compression buffer. + */ + len = dev->mtu * 2; + + /* + * allow for arrival of larger UDP packets, even if we say not to + * also fixes a bug in which SunOS sends 512-byte packets even with + * an MSS of 128 + */ + if (len < 576 * 2) + len = 576 * 2; + + if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) + goto norbuff; + + if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) + goto noxbuff; + + ax->mtu = dev->mtu + 73; + ax->buffsize = len; + ax->rcount = 0; + ax->xleft = 0; + + ax->flags &= (1 << AXF_INUSE); /* Clear ESCAPE & ERROR flags */ + dev->tbusy = 0; + dev->start = 1; + + return 0; + + /* Cleanup */ + kfree(ax->xbuff); + +noxbuff: + kfree(ax->rbuff); + +norbuff: + return -ENOMEM; +} + + +/* Close the low-level part of the AX25 channel. Easy! */ +static int ax_close(struct device *dev) +{ + struct ax_disp *ax = (struct ax_disp*)dev->priv; + + if (ax->tty == NULL) + return -EBUSY; + + ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + + dev->tbusy = 1; + dev->start = 0; + + return 0; +} + +static int ax25_receive_room(struct tty_struct *tty) +{ + return 65536; /* We can handle an infinite amount of data. :-) */ +} + +/* + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of data has been received, which can now be decapsulated + * and sent on to the AX.25 layer for further processing. + */ +static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + struct ax_disp *ax = (struct ax_disp *)tty->disc_data; + + if (ax == NULL || ax->magic != AX25_MAGIC || !ax->dev->start) + return; + + /* + * Argh! mtu change time! - costs us the packet part received + * at the change + */ + if (ax->mtu != ax->dev->mtu + 73) + ax_changedmtu(ax); + + /* Read the characters out of the buffer */ + while (count--) { + if (fp != NULL && *fp++) { + if (!test_and_set_bit(AXF_ERROR, &ax->flags)) + ax->rx_errors++; + cp++; + continue; + } + + kiss_unesc(ax, *cp++); + } +} + +static int ax25_open(struct tty_struct *tty) +{ + struct ax_disp *ax = (struct ax_disp *)tty->disc_data; + struct ax_disp *tmp_ax; + struct mkiss_channel *mkiss; + int err, cnt; + + /* First make sure we're not already connected. */ + if (ax && ax->magic == AX25_MAGIC) + return -EEXIST; + + /* OK. Find a free AX25 channel to use. */ + if ((ax = ax_alloc()) == NULL) + return -ENFILE; + + ax->tty = tty; + tty->disc_data = ax; + + ax->mkiss = NULL; + tmp_ax = NULL; + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + /* Restore default settings */ + ax->dev->type = ARPHRD_AX25; + + /* Perform the low-level AX25 initialization. */ + if ((err = ax_open(ax->dev))) + return err; + + mkiss= ax->tty->driver_data; + + if (mkiss->magic == MKISS_DRIVER_MAGIC) { + for (cnt = 1; cnt < ax25_maxdev; cnt++) { + if (ax25_ctrls[cnt]) { + if (ax25_ctrls[cnt]->dev.start) { + if (ax == &ax25_ctrls[cnt]->ctrl) { + cnt--; + tmp_ax = &ax25_ctrls[cnt]->ctrl; + break; + } + } + } + } + } + + if (tmp_ax != NULL) { + ax->mkiss = tmp_ax; + tmp_ax->mkiss = ax; + } + + MOD_INC_USE_COUNT; + + /* Done. We have linked the TTY line to a channel. */ + return ax->dev->base_addr; +} + +static void ax25_close(struct tty_struct *tty) +{ + struct ax_disp *ax = (struct ax_disp *)tty->disc_data; + int mkiss ; + + /* First make sure we're connected. */ + if (ax == NULL || ax->magic != AX25_MAGIC) + return; + + mkiss = ax->mode; + if (ax->dev->flags & IFF_UP) + { + dev_lock_wait(); + dev_close(ax->dev); + dev_unlock_list(); + } + + tty->disc_data = 0; + ax->tty = NULL; + + /* VSV = very important to remove timers */ + ax_free(ax); + unregister_netdev(ax->dev); + + MOD_DEC_USE_COUNT; +} + + +static struct net_device_stats *ax_get_stats(struct device *dev) +{ + static struct net_device_stats stats; + struct ax_disp *ax = (struct ax_disp*)dev->priv; + + memset(&stats, 0, sizeof(struct net_device_stats)); + + stats.rx_packets = ax->rx_packets; + stats.tx_packets = ax->tx_packets; + stats.rx_dropped = ax->rx_dropped; + stats.tx_dropped = ax->tx_dropped; + stats.tx_errors = ax->tx_errors; + stats.rx_errors = ax->rx_errors; + stats.rx_over_errors = ax->rx_over_errors; + + return &stats; +} + + +/************************************************************************ + * STANDARD ENCAPSULATION * + ************************************************************************/ + +int kiss_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = END; + + while (len-- > 0) { + switch (c = *s++) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; + break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } + } + + *ptr++ = END; + + return ptr - d; +} + +static void kiss_unesc(struct ax_disp *ax, unsigned char s) +{ + switch (s) { + case END: + /* drop keeptest bit = VSV */ + if (test_bit(AXF_KEEPTEST, &ax->flags)) + clear_bit(AXF_KEEPTEST, &ax->flags); + + if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) + ax_bump(ax); + + clear_bit(AXF_ESCAPE, &ax->flags); + ax->rcount = 0; + return; + + case ESC: + set_bit(AXF_ESCAPE, &ax->flags); + return; + case ESC_ESC: + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) + s = ESC; + break; + case ESC_END: + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) + s = END; + break; + } + + if (!test_bit(AXF_ERROR, &ax->flags)) { + if (ax->rcount < ax->buffsize) { + ax->rbuff[ax->rcount++] = s; + return; + } + + ax->rx_over_errors++; + set_bit(AXF_ERROR, &ax->flags); + } +} + + +int ax_set_mac_address(struct device *dev, void *addr) +{ + int err; + + if ((err = verify_area(VERIFY_READ, addr, AX25_ADDR_LEN)) != 0) + return err; + + /* addr is an AX.25 shifted ASCII mac address */ + copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN); + + return 0; +} + +static int ax_set_dev_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa = addr; + + memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); + + return 0; +} + + +/* Perform I/O control on an active ax25 channel. */ +static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) +{ + struct ax_disp *ax = (struct ax_disp *)tty->disc_data; + int err; + unsigned int tmp; + + /* First make sure we're connected. */ + if (ax == NULL || ax->magic != AX25_MAGIC) + return -EINVAL; + + switch (cmd) { + case SIOCGIFNAME: + if ((err = verify_area(VERIFY_WRITE, arg, strlen(ax->dev->name) + 1)) != 0) + return err; + copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1); + return 0; + + case SIOCGIFENCAP: + if ((err = verify_area(VERIFY_WRITE, arg, sizeof(int))) != 0) + return err; + put_user(4, (int *)arg); + return 0; + + case SIOCSIFENCAP: + if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0) + return err; + get_user(tmp, (int *)arg); + ax->mode = tmp; + ax->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ + ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; + ax->dev->type = ARPHRD_AX25; + return 0; + + case SIOCSIFHWADDR: + return ax_set_mac_address(ax->dev, arg); + + default: + return -ENOIOCTLCMD; + } +} + +static int ax_open_dev(struct device *dev) +{ + struct ax_disp *ax = (struct ax_disp*)dev->priv; + + if (ax->tty==NULL) + return -ENODEV; + + return 0; +} + +/* Initialize AX25 control device -- register AX25 line discipline */ +__initfunc(int mkiss_init_ctrl_dev(void)) +{ + int status; + + if (ax25_maxdev < 4) ax25_maxdev = 4; /* Sanity */ + + if ((ax25_ctrls = kmalloc(sizeof(void*) * ax25_maxdev, GFP_KERNEL)) == NULL) { + printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array ! No mkiss available\n"); + return -ENOMEM; + } + + /* Clear the pointer array, we allocate devices when we need them */ + memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */ + + /* Fill in our line protocol discipline, and register it */ + memset(&ax_ldisc, 0, sizeof(ax_ldisc)); + ax_ldisc.magic = TTY_LDISC_MAGIC; + ax_ldisc.name = "mkiss"; + ax_ldisc.flags = 0; + ax_ldisc.open = ax25_open; + ax_ldisc.close = ax25_close; + ax_ldisc.read = NULL; + ax_ldisc.write = NULL; + ax_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long))ax25_disp_ioctl; + ax_ldisc.poll = NULL; + + ax_ldisc.receive_buf = ax25_receive_buf; + ax_ldisc.receive_room = ax25_receive_room; + ax_ldisc.write_wakeup = ax25_write_wakeup; + + if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) + printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status); + + mkiss_init(); + +#ifdef MODULE + return status; +#else + /* + * Return "not found", so that dev_init() will unlink + * the placeholder device entry for us. + */ + return ENODEV; +#endif +} + + +/* Initialize the driver. Called by network startup. */ + +static int ax25_init(struct device *dev) +{ + struct ax_disp *ax = (struct ax_disp*)dev->priv; + + static char ax25_bcast[AX25_ADDR_LEN] = + {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; + static char ax25_test[AX25_ADDR_LEN] = + {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; + + if (ax == NULL) /* Allocation failed ?? */ + return -ENODEV; + + /* Set up the "AX25 Control Block". (And clear statistics) */ + memset(ax, 0, sizeof (struct ax_disp)); + ax->magic = AX25_MAGIC; + ax->dev = dev; + + /* Finish setting up the DEVICE info. */ + dev->mtu = AX_MTU; + dev->hard_start_xmit = ax_xmit; + dev->open = ax_open_dev; + dev->stop = ax_close; + dev->get_stats = ax_get_stats; +#ifdef HAVE_SET_MAC_ADDR + dev->set_mac_address = ax_set_dev_mac_address; +#endif + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = ARPHRD_AX25; + dev->tx_queue_len = 10; + + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + dev->hard_header = ax_header; + dev->rebuild_header = ax_rebuild_header; +#endif + + dev_init_buffers(dev); + + /* New-style flags. */ + dev->flags = 0; + + return 0; +} + +static int mkiss_open(struct tty_struct *tty, struct file *filp) +{ + struct mkiss_channel *mkiss; + int chan; + + chan = MINOR(tty->device) - tty->driver.minor_start; + + if (chan < 0 || chan >= NR_MKISS) + return -ENODEV; + + mkiss = &MKISS_Info[chan]; + + mkiss->magic = MKISS_DRIVER_MAGIC; + mkiss->init = 1; + mkiss->tty = tty; + + tty->driver_data = mkiss; + + tty->termios->c_iflag = IGNBRK | IGNPAR; + tty->termios->c_cflag = B9600 | CS8 | CLOCAL; + tty->termios->c_cflag &= ~CBAUD; + + return 0; +} + +static void mkiss_close(struct tty_struct *tty, struct file * filp) +{ + struct mkiss_channel *mkiss = tty->driver_data; + + if (mkiss == NULL || mkiss->magic != MKISS_DRIVER_MAGIC) + return; + + mkiss->tty = NULL; + mkiss->init = 0; + tty->stopped = 0; +} + +static int mkiss_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) +{ + return 0; +} + +static int mkiss_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) +{ + /* Ignore serial ioctl's */ + switch (cmd) { + case TCSBRK: + case TIOCMGET: + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + case TCSETS: + case TCSETSF: /* should flush first, but... */ + case TCSETSW: /* should wait until flush, but... */ + return 0; + default: + return -ENOIOCTLCMD; + } +} + + +static void mkiss_dummy(struct tty_struct *tty) +{ + struct mkiss_channel *mkiss = tty->driver_data; + + if (tty == NULL) + return; + + if (mkiss == NULL) + return; +} + +static void mkiss_dummy2(struct tty_struct *tty, unsigned char ch) +{ + struct mkiss_channel *mkiss = tty->driver_data; + + if (tty == NULL) + return; + + if (mkiss == NULL) + return; +} + + +static int mkiss_write_room(struct tty_struct * tty) +{ + struct mkiss_channel *mkiss = tty->driver_data; + + if (tty == NULL) + return 0; + + if (mkiss == NULL) + return 0; + + return 65536; /* We can handle an infinite amount of data. :-) */ +} + + +static int mkiss_chars_in_buffer(struct tty_struct *tty) +{ + struct mkiss_channel *mkiss = tty->driver_data; + + if (tty == NULL) + return 0; + + if (mkiss == NULL) + return 0; + + return 0; +} + + +static void mkiss_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + /* we don't do termios */ +} + +/* ******************************************************************** */ +/* * Init MKISS driver * */ +/* ******************************************************************** */ + +__initfunc(static int mkiss_init(void)) +{ + memset(&mkiss_driver, 0, sizeof(struct tty_driver)); + + mkiss_driver.magic = MKISS_DRIVER_MAGIC; + mkiss_driver.name = "mkiss"; + mkiss_driver.major = MKISS_MAJOR; + mkiss_driver.minor_start = 0; + mkiss_driver.num = NR_MKISS; + mkiss_driver.type = TTY_DRIVER_TYPE_SERIAL; + mkiss_driver.subtype = MKISS_SERIAL_TYPE_NORMAL; /* not needed */ + + mkiss_driver.init_termios = tty_std_termios; + mkiss_driver.init_termios.c_iflag = IGNBRK | IGNPAR; + mkiss_driver.init_termios.c_cflag = B9600 | CS8 | CLOCAL; + + mkiss_driver.flags = TTY_DRIVER_REAL_RAW; + mkiss_driver.refcount = &mkiss_refcount; + mkiss_driver.table = mkiss_table; + mkiss_driver.termios = (struct termios **)mkiss_termios; + mkiss_driver.termios_locked = (struct termios **)mkiss_termios_locked; + + mkiss_driver.ioctl = mkiss_ioctl; + mkiss_driver.open = mkiss_open; + mkiss_driver.close = mkiss_close; + mkiss_driver.write = mkiss_write; + mkiss_driver.write_room = mkiss_write_room; + mkiss_driver.chars_in_buffer = mkiss_chars_in_buffer; + mkiss_driver.set_termios = mkiss_set_termios; + + /* some unused functions */ + mkiss_driver.flush_buffer = mkiss_dummy; + mkiss_driver.throttle = mkiss_dummy; + mkiss_driver.unthrottle = mkiss_dummy; + mkiss_driver.stop = mkiss_dummy; + mkiss_driver.start = mkiss_dummy; + mkiss_driver.hangup = mkiss_dummy; + mkiss_driver.flush_chars = mkiss_dummy; + mkiss_driver.put_char = mkiss_dummy2; + + if (tty_register_driver(&mkiss_driver)) { + printk(KERN_ERR "mkiss: couldn't register Mkiss device\n"); + return -EIO; + } + + printk(KERN_INFO "AX.25 Multikiss device enabled\n"); + + return 0; +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +MODULE_PARM(ax25_maxdev, "i"); +MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices"); + +MODULE_AUTHOR("Hans Albas PE1AYX "); +MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); + +int init_module(void) +{ + return mkiss_init_ctrl_dev(); +} + +void cleanup_module(void) +{ + int i; + + if (ax25_ctrls != NULL) { + for (i = 0; i < ax25_maxdev; i++) { + if (ax25_ctrls[i]) { + /* + * VSV = if dev->start==0, then device + * unregistred while close proc. + */ + if (ax25_ctrls[i]->dev.start) + unregister_netdev(&(ax25_ctrls[i]->dev)); + + kfree(ax25_ctrls[i]); + ax25_ctrls[i] = NULL; + } + } + + kfree(ax25_ctrls); + ax25_ctrls = NULL; + } + + if ((i = tty_register_ldisc(N_AX25, NULL))) + printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i); + + if (tty_unregister_driver(&mkiss_driver)) /* remove devive */ + printk(KERN_ERR "mkiss: can't unregister MKISS device\n"); +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/mkiss.h linux/drivers/net/hamradio/mkiss.h --- v2.1.70/linux/drivers/net/hamradio/mkiss.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/mkiss.h Sun Nov 10 09:12:56 1996 @@ -0,0 +1,56 @@ +/**************************************************************************** + * Defines for the Multi-KISS driver. + ****************************************************************************/ + +#define AX25_MAXDEV 16 /* MAX number of AX25 channels; + This can be overridden with + insmod -oax25_maxdev=nnn */ +#define AX_MTU 236 + +/* SLIP/KISS protocol characters. */ +#define END 0300 /* indicates end of frame */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +struct ax_disp { + int magic; + + /* Various fields. */ + struct tty_struct *tty; /* ptr to TTY structure */ + struct device *dev; /* easy for intr handling */ + struct ax_disp *mkiss; /* mkiss txport if mkiss channel*/ + + /* These are pointers to the malloc()ed frame buffers. */ + unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *xhead; /* pointer to next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + + /* SLIP interface statistics. */ + unsigned long rx_packets; /* inbound frames counter */ + unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_errors; /* Parity, etc. errors */ + unsigned long tx_errors; /* Planned stuff */ + unsigned long rx_dropped; /* No memory for skb */ + unsigned long tx_dropped; /* When MTU change */ + unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ + + /* Detailed SLIP statistics. */ + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + + + unsigned char flags; /* Flag values/ mode etc */ +#define AXF_INUSE 0 /* Channel in use */ +#define AXF_ESCAPE 1 /* ESC received */ +#define AXF_ERROR 2 /* Parity, etc. error */ +#define AXF_KEEPTEST 3 /* Keepalive test flag */ +#define AXF_OUTWAIT 4 /* is outpacket was flag */ + + int mode; +}; + +#define AX25_MAGIC 0x5316 +#define MKISS_DRIVER_MAGIC 1215 diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/pi2.c linux/drivers/net/hamradio/pi2.c --- v2.1.70/linux/drivers/net/hamradio/pi2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/pi2.c Sat Nov 29 10:33:19 1997 @@ -0,0 +1,1677 @@ +/* + pi2.c: Driver for the Ottawa Amateur Radio Club PI and PI2 interface. + Copyright (c) 1994 David Perry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2, as + published by the Free Software Foundation. + + 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. + + The file skeleton.c by Donald Becker was used as a starting point + for this driver. + + Revision History + + April 6, 1994 (dp) Created + version 0.0 ALPHA + April 10, 1994 (dp) Included cleanup, suggestions from J. P. Morrison. + version 0.1 ALPHA + April 13, 1994 (dp) Included address probing from JPM, autoirq + version 0.2 ALPHA + April 14, 1994 (ac) Sketched in the NET3 changes. + April 17, 1994 (dp) Finished the NET3 changes. Used init_etherdev() + instead of kmalloc() to ensure that DMA buffers will + reside under the 16 meg line. + version 0.4 ALPHA + April 18, 1994 (dp) Now using the kernel provided sk_buff handling functions. + Fixed a nasty problem with DMA. + version 0.5 ALPHA + June 6, 1994 (ac) Fixed to match the buffer locking changes. Added a hack to + fix a funny I see (search for HACK) and fixed the calls in + init() so it doesn't migrate module based ethernet cards up + to eth2 Took out the old module ideas as they are no longer + relevant to the PI driver. + July 16, 1994 (dp) Fixed the B channel rx overrun problem ac referred to + above. Also added a bit of a hack to improve the maximum + baud rate on the B channel (Search for STUFF2). Included + ioctl stuff from John Paul Morrison. version 0.6 ALPHA + Feb 9, 1995 (dp) Updated for 1.1.90 kernel + version 0.7 ALPHA + Apr 6, 1995 (ac) Tweaks for NET3 pre snapshot 002 AX.25 + April 23, 1995 (dp) Fixed ioctl so it works properly with piconfig program + when changing the baud rate or clock mode. + version 0.8 ALPHA + July 17, 1995 (ac) Finally polishing of AX25.030+ support + Oct 29, 1995 (ac) A couple of minor fixes before this, and this release changes + to the proper set_mac_address semantics which will break + a few programs I suspect. + Aug 18, 1996 (jsn) Converted to be used as a module. + Dec 13, 1996 (jsn) Fixed to match Linux networking changes. +*/ + +/* The following #define invokes a hack that will improve performance (baud) + for the B port. The up side is it makes 9600 baud work ok on the B port. + It may do 38400, depending on the host. The down side is it burns up + CPU cycles with ints locked for up to 1 character time, at the beginning + of each transmitted packet. If this causes you to lose sleep, #undefine it. +*/ + +/*#define STUFF2 1*/ + +/* The default configuration */ +#define PI_DMA 3 + +#define DEF_A_SPEED 0 /* 0 means external clock */ +#define DEF_A_TXDELAY 15 /* 15 mS transmit delay */ +#define DEF_A_PERSIST 128 /* 50% persistence */ +#define DEF_A_SLOTIME 15 /* 15 mS slot time */ +#define DEF_A_SQUELDELAY 1 /* 1 mS squelch delay - allows fcs and flag */ +#define DEF_A_CLOCKMODE 0 /* clock mode - 0 is normal */ + +#define DEF_B_SPEED 1200 /* 1200 baud */ +#define DEF_B_TXDELAY 40 /* 400 mS */ +#define DEF_B_PERSIST 128 /* 50% */ +#define DEF_B_SLOTIME 30 /* 300 mS */ +#define DEF_B_SQUELDELAY 3 /* 30 mS */ +#define DEF_B_CLOCKMODE 0 /* Normal clock mode */ + +/* The following #define is only really required for the PI card, not + the PI2 - but it's safer to leave it in. */ +#define REALLY_SLOW_IO 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "z8530.h" +#include + +struct mbuf { + struct mbuf *next; + int cnt; + char data[0]; +}; + +/* + * The actual devices we will use + */ + +/* + * PI device declarations. + */ + +static int pi0_preprobe(struct device *dev){return 0;} /* Dummy probe function */ +static struct device pi0a = { "pi0a", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pi0_preprobe }; +static struct device pi0b = { "pi0b", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pi0_preprobe }; + + +/* The number of low I/O ports used by the card. */ +#define PI_TOTAL_SIZE 8 + + +/* Index to functions, as function prototypes. */ + +static int pi_probe(struct device *dev, int card_type); +static int pi_open(struct device *dev); +static int pi_send_packet(struct sk_buff *skb, struct device *dev); +static void pi_interrupt(int reg_ptr, void *dev_id, struct pt_regs *regs); +static int pi_close(struct device *dev); +static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd); +static struct net_device_stats *pi_get_stats(struct device *dev); +static void rts(struct pi_local *lp, int x); +static void b_rxint(struct device *dev, struct pi_local *lp); +static void b_txint(struct pi_local *lp); +static void b_exint(struct pi_local *lp); +static void a_rxint(struct device *dev, struct pi_local *lp); +static void a_txint(struct pi_local *lp); +static void a_exint(struct pi_local *lp); +static char *get_dma_buffer(unsigned long *mem_ptr); +static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize); + +static char ax25_bcast[7] = +{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; +static char ax25_test[7] = +{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; + +static int ext2_secrm_seed = 152; /* Random generator base */ + +extern inline unsigned char random(void) +{ + return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed + * 69069l + 1); +} + +extern inline void wrtscc(int cbase, int ctl, int sccreg, int val) +{ + /* assume caller disables interrupts! */ + outb_p(0, cbase + DMAEN); /* Disable DMA while we touch the scc */ + outb_p(sccreg, ctl); /* Select register */ + outb_p(val, ctl); /* Output value */ + outb_p(1, cbase + DMAEN); /* Enable DMA */ +} + +extern inline int rdscc(int cbase, int ctl, int sccreg) +{ + int retval; + + /* assume caller disables interrupts! */ + outb_p(0, cbase + DMAEN); /* Disable DMA while we touch the scc */ + outb_p(sccreg, ctl); /* Select register */ + retval = inb_p(ctl); + outb_p(1, cbase + DMAEN); /* Enable DMA */ + return retval; +} + +static void switchbuffers(struct pi_local *lp) +{ + if (lp->rcvbuf == lp->rxdmabuf1) + lp->rcvbuf = lp->rxdmabuf2; + else + lp->rcvbuf = lp->rxdmabuf1; +} + +static void hardware_send_packet(struct pi_local *lp, struct sk_buff *skb) +{ + char kickflag; + unsigned long flags; + + lp->stats.tx_packets++; + + save_flags(flags); + cli(); + kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL); + restore_flags(flags); + + skb_queue_tail(&lp->sndq, skb); + if (kickflag) + { + /* simulate interrupt to xmit */ + switch (lp->base & 2) + { + case 2: + a_txint(lp); /* process interrupt */ + break; + case 0: + save_flags(flags); + cli(); + if (lp->tstate == IDLE) + b_txint(lp); + restore_flags(flags); + break; + } + } +} + +static void setup_rx_dma(struct pi_local *lp) +{ + unsigned long flags; + int cmd; + unsigned long dma_abs; + unsigned dmachan; + + save_flags(flags); + cli(); + + dma_abs = (unsigned long) (lp->rcvbuf->data); + dmachan = lp->dmachan; + cmd = lp->base + CTL; + + if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf))) + panic("PI: RX buffer violates DMA boundary!"); + + /* Get ready for RX DMA */ + wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); + + disable_dma(dmachan); + clear_dma_ff(dmachan); + + /* Set DMA mode register to single transfers, incrementing address, + * auto init, writes + */ + set_dma_mode(dmachan, DMA_MODE_READ | 0x10); + set_dma_addr(dmachan, dma_abs); + set_dma_count(dmachan, lp->bufsiz); + enable_dma(dmachan); + + /* If a packet is already coming in, this line is supposed to + avoid receiving a partial packet. + */ + wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC); + + /* Enable RX dma */ + wrtscc(lp->cardbase, cmd, R1, + WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); + + restore_flags(flags); +} + +static void setup_tx_dma(struct pi_local *lp, int length) +{ + unsigned long dma_abs; + unsigned long flags; + unsigned long dmachan; + + save_flags(flags); + cli(); + + dmachan = lp->dmachan; + dma_abs = (unsigned long) (lp->txdmabuf); + + if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf))) + panic("PI: TX buffer violates DMA boundary!"); + + disable_dma(dmachan); + /* Set DMA mode register to single transfers, incrementing address, + * no auto init, reads + */ + set_dma_mode(dmachan, DMA_MODE_WRITE); + clear_dma_ff(dmachan); + set_dma_addr(dmachan, dma_abs); + /* output byte count */ + set_dma_count(dmachan, length); + + restore_flags(flags); +} + +static void tdelay(struct pi_local *lp, int time) +{ + int port; + unsigned int t1; + unsigned char sc; + + if (lp->base & 2) { /* If A channel */ + sc = SC1; + t1 = time; + port = lp->cardbase + TMR1; + } else { + sc = SC2; + t1 = 10 * time; /* 10s of milliseconds for the B channel */ + port = lp->cardbase + TMR2; + wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB); + } + + /* Setup timer sc */ + outb_p(sc | LSB_MSB | MODE0, lp->cardbase + TMRCMD); + + /* times 2 to make millisecs */ + outb_p((t1 << 1) & 0xFF, port); + outb_p((t1 >> 7) & 0xFF, port); + + /* Enable correct int for timeout */ + wrtscc(lp->cardbase, lp->base + CTL, R15, CTSIE); + wrtscc(lp->cardbase, lp->base + CTL, R0, RES_EXT_INT); +} + +static void a_txint(struct pi_local *lp) +{ + int cmd; + unsigned long flags; + + save_flags(flags); + cli(); + + cmd = CTL + lp->base; + + switch (lp->tstate) { + case IDLE: + /* Transmitter idle. Find a frame for transmission */ + if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { + rts(lp, OFF); + restore_flags(flags); + return; + } + /* If a buffer to send, we drop thru here */ + case DEFER: + /* we may have deferred prev xmit attempt */ + /* Check DCD - debounce it + * See Intel Microcommunications Handbook, p2-308 + */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { + lp->tstate = DEFER; + tdelay(lp, 100); + /* defer until DCD transition or timeout */ + wrtscc(lp->cardbase, cmd, R15, CTSIE | DCDIE); + restore_flags(flags); + return; + } + if (random() > lp->persist) { + lp->tstate = DEFER; + tdelay(lp, lp->slotime); + restore_flags(flags); + return; + } + /* Assert RTS early minimize collision window */ + wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); + rts(lp, ON); /* Transmitter on */ + lp->tstate = ST_TXDELAY; + tdelay(lp, lp->txdelay); + restore_flags(flags); + return; + default: + break; + } /* end switch(lp->state) */ + + restore_flags(flags); +} /*a_txint */ + +static void a_exint(struct pi_local *lp) +{ + unsigned long flags; + int cmd; + char st; + int length; + + save_flags(flags); + cli(); /* disable interrupts */ + + st = rdscc(lp->cardbase, lp->base + CTL, R0); /* Fetch status */ + + /* reset external status latch */ + wrtscc(lp->cardbase, CTL + lp->base, R0, RES_EXT_INT); + cmd = lp->base + CTL; + + if ((lp->rstate >= ACTIVE) && (st & BRK_ABRT)) { + setup_rx_dma(lp); + lp->rstate = ACTIVE; + } + switch (lp->tstate) { + case ACTIVE: + kfree_skb(lp->sndbuf, FREE_WRITE); + lp->sndbuf = NULL; + lp->tstate = FLAGOUT; + tdelay(lp, lp->squeldelay); + break; + case FLAGOUT: + if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { + /* Nothing to send - return to receive mode */ + lp->tstate = IDLE; + rts(lp, OFF); + restore_flags(flags); + return; + } + /* NOTE - fall through if more to send */ + case ST_TXDELAY: + /* Disable DMA chan */ + disable_dma(lp->dmachan); + + /* Set up for TX dma */ + wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); + + + /* Get all chars */ + /* Strip KISS control byte */ + length = lp->sndbuf->len - 1; + memcpy(lp->txdmabuf, &lp->sndbuf->data[1], length); + + + /* Setup DMA controller for tx */ + setup_tx_dma(lp, length); + + /* select transmit interrupts to enable */ + /* Allow DMA on chan */ + enable_dma(lp->dmachan); + + /* reset CRC, Txint pend*/ + wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC | RES_Tx_P); + + /* allow Underrun int only */ + wrtscc(lp->cardbase, cmd, R15, TxUIE); + + /* Enable TX DMA */ + wrtscc(lp->cardbase, cmd, R1, WT_RDY_ENAB | WT_FN_RDYFN | EXT_INT_ENAB); + + /* Send CRC on underrun */ + wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); + + + /* packet going out now */ + lp->tstate = ACTIVE; + break; + case DEFER: + /* we have deferred prev xmit attempt + * See Intel Microcommunications Handbook, p2-308 + */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { + lp->tstate = DEFER; + tdelay(lp, 100); + /* Defer until dcd transition or 100mS timeout */ + wrtscc(lp->cardbase, CTL + lp->base, R15, CTSIE | DCDIE); + restore_flags(flags); + return; + } + if (random() > lp->persist) { + lp->tstate = DEFER; + tdelay(lp, lp->slotime); + restore_flags(flags); + return; + } + /* Assert RTS early minimize collision window */ + wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); + rts(lp, ON); /* Transmitter on */ + lp->tstate = ST_TXDELAY; + tdelay(lp, lp->txdelay); + restore_flags(flags); + return; + } /* switch(lp->tstate) */ + + restore_flags(flags); +} /* a_exint() */ + +/* Receive interrupt handler for the A channel + */ +static void a_rxint(struct device *dev, struct pi_local *lp) +{ + unsigned long flags; + int cmd; + int bytecount; + char rse; + struct sk_buff *skb; + int sksize, pkt_len; + struct mbuf *cur_buf; + unsigned char *cfix; + + save_flags(flags); + cli(); /* disable interrupts */ + cmd = lp->base + CTL; + + rse = rdscc(lp->cardbase, cmd, R1); /* Get special condition bits from R1 */ + if (rse & Rx_OVR) + lp->rstate = RXERROR; + + if (rse & END_FR) { + /* If end of frame */ + /* figure length of frame from 8237 */ + clear_dma_ff(lp->dmachan); + bytecount = lp->bufsiz - get_dma_residue(lp->dmachan); + + if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (bytecount < 10)) { + if ((bytecount >= 10) && (rse & CRC_ERR)) { + lp->stats.rx_crc_errors++; + } + if (lp->rstate == RXERROR) { + lp->stats.rx_errors++; + lp->stats.rx_over_errors++; + } + /* Reset buffer pointers */ + lp->rstate = ACTIVE; + setup_rx_dma(lp); + } else { + /* Here we have a valid frame */ + /* Toss 2 crc bytes , add one for KISS */ + pkt_len = lp->rcvbuf->cnt = bytecount - 2 + 1; + + /* Get buffer for next frame */ + cur_buf = lp->rcvbuf; + switchbuffers(lp); + setup_rx_dma(lp); + + + /* Malloc up new buffer. */ + sksize = pkt_len; + + skb = dev_alloc_skb(sksize); + if (skb == NULL) { + printk(KERN_ERR "PI: %s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + restore_flags(flags); + return; + } + skb->dev = dev; + + /* KISS kludge - prefix with a 0 byte */ + cfix=skb_put(skb,pkt_len); + *cfix++=0; + /* 'skb->data' points to the start of sk_buff data area. */ + memcpy(cfix, (char *) cur_buf->data, + pkt_len - 1); + skb->protocol=htons(ETH_P_AX25); + skb->mac.raw=skb->data; + netif_rx(skb); + lp->stats.rx_packets++; + } /* end good frame */ + } /* end EOF check */ + wrtscc(lp->cardbase, lp->base + CTL, R0, ERR_RES); /* error reset */ + restore_flags(flags); +} + +static void b_rxint(struct device *dev, struct pi_local *lp) +{ + unsigned long flags; + int cmd; + char rse; + struct sk_buff *skb; + int sksize; + int pkt_len; + unsigned char *cfix; + + save_flags(flags); + cli(); /* disable interrupts */ + cmd = CTL + lp->base; + + rse = rdscc(lp->cardbase, cmd, R1); /* get status byte from R1 */ + + if ((rdscc(lp->cardbase, cmd, R0)) & Rx_CH_AV) { + /* there is a char to be stored + * read special condition bits before reading the data char + */ + if (rse & Rx_OVR) { + /* Rx overrun - toss buffer */ + /* reset buffer pointers */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + + lp->rstate = RXERROR; /* set error flag */ + lp->stats.rx_errors++; + lp->stats.rx_over_errors++; + } else if (lp->rcvbuf->cnt >= lp->bufsiz) { + /* Too large -- toss buffer */ + /* reset buffer pointers */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + lp->rstate = TOOBIG;/* when set, chars are not stored */ + } + /* ok, we can store the received character now */ + if (lp->rstate == ACTIVE) { /* If no errors... */ + *lp->rcp++ = rdscc(lp->cardbase, cmd, R8); /* char to rcv buff */ + lp->rcvbuf->cnt++; /* bump count */ + } else { + /* got to empty FIFO */ + (void) rdscc(lp->cardbase, cmd, R8); + wrtscc(lp->cardbase, cmd, R0, ERR_RES); /* reset err latch */ + lp->rstate = ACTIVE; + } + } + if (rse & END_FR) { + /* END OF FRAME -- Make sure Rx was active */ + if (lp->rcvbuf->cnt > 0) { + if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (lp->rcvbuf->cnt < 10)) { + if ((lp->rcvbuf->cnt >= 10) && (rse & CRC_ERR)) { + lp->stats.rx_crc_errors++; + } + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + } else { + /* Here we have a valid frame */ + pkt_len = lp->rcvbuf->cnt -= 2; /* Toss 2 crc bytes */ + pkt_len += 1; /* Make room for KISS control byte */ + + /* Malloc up new buffer. */ + sksize = pkt_len; + skb = dev_alloc_skb(sksize); + if (skb == NULL) { + printk(KERN_ERR "PI: %s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + restore_flags(flags); + return; + } + skb->dev = dev; + + /* KISS kludge - prefix with a 0 byte */ + cfix=skb_put(skb,pkt_len); + *cfix++=0; + /* 'skb->data' points to the start of sk_buff data area. */ + memcpy(cfix, lp->rcvbuf->data, pkt_len - 1); + skb->protocol=ntohs(ETH_P_AX25); + skb->mac.raw=skb->data; + netif_rx(skb); + lp->stats.rx_packets++; + /* packet queued - initialize buffer for next frame */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + + } /* end good frame queued */ + } /* end check for active receive upon EOF */ + lp->rstate = ACTIVE; /* and clear error status */ + } /* end EOF check */ + restore_flags(flags); +} + + +static void b_txint(struct pi_local *lp) +{ + unsigned long flags; + int cmd; + unsigned char c; + + save_flags(flags); + cli(); + cmd = CTL + lp->base; + + switch (lp->tstate) { + case CRCOUT: + lp->tstate = FLAGOUT; + tdelay(lp, lp->squeldelay); + restore_flags(flags); + return; + case IDLE: + /* Transmitter idle. Find a frame for transmission */ + if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { + /* Nothing to send - return to receive mode + * Tx OFF now - flag should have gone + */ + rts(lp, OFF); + + restore_flags(flags); + return; + } + lp->txptr = lp->sndbuf->data; + lp->txptr++; /* Ignore KISS control byte */ + lp->txcnt = (int) lp->sndbuf->len - 1; + /* If a buffer to send, we drop thru here */ + case DEFER: /* we may have deferred prev xmit attempt */ + /* Check DCD - debounce it */ + /* See Intel Microcommunications Handbook, p2-308 */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { + lp->tstate = DEFER; + tdelay(lp, 100); + /* defer until DCD transition or timeout */ + wrtscc(lp->cardbase, cmd, R15, CTSIE | DCDIE); + restore_flags(flags); + return; + } + if (random() > lp->persist) { + lp->tstate = DEFER; + tdelay(lp, lp->slotime); + restore_flags(flags); + return; + } + rts(lp, ON); /* Transmitter on */ + lp->tstate = ST_TXDELAY; + tdelay(lp, lp->txdelay); + restore_flags(flags); + return; + + case ACTIVE: + /* Here we are actively sending a frame */ + if (lp->txcnt--) { + c = *lp->txptr++; + /* next char is gone */ + wrtscc(lp->cardbase, cmd, R8, c); + /* stuffing a char satisfies Interrupt condition */ + } else { + /* No more to send */ + kfree_skb(lp->sndbuf, FREE_WRITE); + lp->sndbuf = NULL; + if ((rdscc(lp->cardbase, cmd, R0) & 0x40)) { + /* Did we underrun? */ + /* unexpected underrun */ + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); + lp->tstate = FLAGOUT; + tdelay(lp, lp->squeldelay); + restore_flags(flags); + return; + } + lp->tstate = UNDERRUN; /* Now we expect to underrun */ + /* Send flags on underrun */ + if (lp->speed) { /* If internally clocked */ + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); + } else { + wrtscc(lp->cardbase, cmd, R10, CRCPS); + } + wrtscc(lp->cardbase, cmd, R0, RES_Tx_P); /* reset Tx Int Pend */ + } + restore_flags(flags); + return; /* back to wait for interrupt */ + } /* end switch */ + restore_flags(flags); +} + +/* Pi SIO External/Status interrupts (for the B channel) + * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM. + * Receiver automatically goes to Hunt on an abort. + * + * If the Tx Underrun interrupt hits, change state and + * issue a reset command for it, and return. + */ +static void b_exint(struct pi_local *lp) +{ + unsigned long flags; + char st; + int cmd; + char c; + + cmd = CTL + lp->base; + save_flags(flags); + cli(); /* disable interrupts */ + st = rdscc(lp->cardbase, cmd, R0); /* Fetch status */ + /* reset external status latch */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + + + switch (lp->tstate) { + case ACTIVE: /* Unexpected underrun */ + kfree_skb(lp->sndbuf, FREE_WRITE); + lp->sndbuf = NULL; + wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); + lp->tstate = FLAGOUT; + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + tdelay(lp, lp->squeldelay); + restore_flags(flags); + return; + case UNDERRUN: + lp->tstate = CRCOUT; + restore_flags(flags); + return; + case FLAGOUT: + /* Find a frame for transmission */ + if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { + /* Nothing to send - return to receive mode + * Tx OFF now - flag should have gone + */ + rts(lp, OFF); + lp->tstate = IDLE; + restore_flags(flags); + return; + } + lp->txptr = lp->sndbuf->data; + lp->txptr++; /* Ignore KISS control byte */ + lp->txcnt = (int) lp->sndbuf->len - 1; + /* Get first char to send */ + lp->txcnt--; + c = *lp->txptr++; + wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC); /* reset for next frame */ + + /* Send abort on underrun */ + if (lp->speed) { /* If internally clocked */ + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI | ABUNDER); + } else { + wrtscc(lp->cardbase, cmd, R10, CRCPS | ABUNDER); + } + + wrtscc(lp->cardbase, cmd, R8, c); /* First char out now */ + wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); /* Reset end of message latch */ + +#ifdef STUFF2 + /* stuff an extra one if we can */ + if (lp->txcnt) { + lp->txcnt--; + c = *lp->txptr++; + /* Wait for tx buffer empty */ + while((rdscc(lp->cardbase, cmd, R0) & 0x04) == 0) + ; + wrtscc(lp->cardbase, cmd, R8, c); + } +#endif + + /* select transmit interrupts to enable */ + + wrtscc(lp->cardbase, cmd, R15, TxUIE); /* allow Underrun int only */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + wrtscc(lp->cardbase, cmd, R1, TxINT_ENAB | EXT_INT_ENAB); /* Tx/Ext ints */ + + lp->tstate = ACTIVE; /* char going out now */ + restore_flags(flags); + return; + + case DEFER: + /* Check DCD - debounce it + * See Intel Microcommunications Handbook, p2-308 + */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { + lp->tstate = DEFER; + tdelay(lp, 100); + /* defer until DCD transition or timeout */ + wrtscc(lp->cardbase, cmd, R15, CTSIE | DCDIE); + restore_flags(flags); + return; + } + if (random() > lp->persist) { + lp->tstate = DEFER; + tdelay(lp, lp->slotime); + restore_flags(flags); + return; + } + rts(lp, ON); /* Transmitter on */ + lp->tstate = ST_TXDELAY; + tdelay(lp, lp->txdelay); + restore_flags(flags); + return; + + case ST_TXDELAY: + + /* Get first char to send */ + lp->txcnt--; + c = *lp->txptr++; + wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC); /* reset for next frame */ + + /* Send abort on underrun */ + if (lp->speed) { /* If internally clocked */ + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI | ABUNDER); + } else { + wrtscc(lp->cardbase, cmd, R10, CRCPS | ABUNDER); + } + + wrtscc(lp->cardbase, cmd, R8, c); /* First char out now */ + wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); /* Reset end of message latch */ + +#ifdef STUFF2 + /* stuff an extra one if we can */ + if (lp->txcnt) { + lp->txcnt--; + c = *lp->txptr++; + /* Wait for tx buffer empty */ + while((rdscc(lp->cardbase, cmd, R0) & 0x04) == 0) + ; + wrtscc(lp->cardbase, cmd, R8, c); + } +#endif + + /* select transmit interrupts to enable */ + + wrtscc(lp->cardbase, cmd, R15, TxUIE); /* allow Underrun int only */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + /* Tx/Extern ints on */ + wrtscc(lp->cardbase, cmd, R1, TxINT_ENAB | EXT_INT_ENAB); + + lp->tstate = ACTIVE; /* char going out now */ + restore_flags(flags); + return; + } + + /* Receive Mode only + * This triggers when hunt mode is entered, & since an ABORT + * automatically enters hunt mode, we use that to clean up + * any waiting garbage + */ + if ((lp->rstate == ACTIVE) && (st & BRK_ABRT)) { + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; /* rewind on DCD transition */ + } + restore_flags(flags); +} + +/* Probe for a PI card. */ +/* This routine also initializes the timer chip */ + +__initfunc(static int hw_probe(int ioaddr)) +{ + int time = 1000; /* Number of milliseconds for test */ + unsigned long start_time, end_time; + + int base, tmr0, tmr1, tmrcmd; + int a = 1; + int b = 1; + + base = ioaddr & 0x3f0; + tmr0 = TMR0 + base; + tmr1 = TMR1 + base; + tmrcmd = TMRCMD + base; + + /* Set up counter chip timer 0 for 500 uS period square wave */ + /* assuming a 3.68 mhz clock for now */ + outb_p(SC0 | LSB_MSB | MODE3, tmrcmd); + outb_p(922 & 0xFF, tmr0); + outb_p(922 >> 8, tmr0); + + /* Setup timer control word for timer 1*/ + outb_p(SC1 | LSB_MSB | MODE0, tmrcmd); + outb_p((time << 1) & 0xFF, tmr1); + outb_p((time >> 7) & 0XFF, tmr1); + + /* wait until counter reg is loaded */ + do { + /* Latch count for reading */ + outb_p(SC1, tmrcmd); + a = inb_p(tmr1); + b = inb_p(tmr1); + } while (b == 0); + start_time = jiffies; + while (b != 0) { + /* Latch count for reading */ + outb_p(SC1, tmrcmd); + a = inb_p(tmr1); + b = inb_p(tmr1); + end_time = jiffies; + /* Don't wait forever - there may be no card here */ + if ((end_time - start_time) > 200) + return 0; /* No card found */ + } + end_time = jiffies; + /* 87 jiffies, for a 3.68 mhz clock, half that for a double speed clock */ + if ((end_time - start_time) > 65) { + return (1); /* PI card found */ + } else { + /* Faster crystal - tmr0 needs adjusting */ + /* Set up counter chip */ + /* 500 uS square wave */ + outb_p(SC0 | LSB_MSB | MODE3, tmrcmd); + outb_p(1844 & 0xFF, tmr0); + outb_p(1844 >> 8, tmr0); + return (2); /* PI2 card found */ + } +} + +static void rts(struct pi_local *lp, int x) +{ + int tc; + long br; + int cmd; + int dummy; + + /* assumes interrupts are off */ + cmd = CTL + lp->base; + + /* Reprogram BRG and turn on transmitter to send flags */ + if (x == ON) { /* Turn Tx ON and Receive OFF */ + /* Exints off first to avoid abort int */ + wrtscc(lp->cardbase, cmd, R15, 0); + wrtscc(lp->cardbase, cmd, R3, Rx8); /* Rx off */ + lp->rstate = IDLE; + if (cmd & 2) { /* if channel a */ + /* Set up for TX dma */ + wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); + } else { + wrtscc(lp->cardbase, cmd, R1, 0); /* No interrupts */ + } + + if (!lp->clockmode) { + if (lp->speed) { /* if internally clocked */ + br = lp->speed; /* get desired speed */ + tc = (lp->xtal / br) - 2; /* calc 1X BRG divisor */ + wrtscc(lp->cardbase, cmd, R12, tc & 0xFF); /* lower byte */ + wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xFF); /* upper byte */ + } + } + wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR); + /* Transmitter now on */ + } else { /* Tx OFF and Rx ON */ + lp->tstate = IDLE; + wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); /* TX off */ + + if (!lp->clockmode) { + if (lp->speed) { /* if internally clocked */ + /* Reprogram BRG for 32x clock for receive DPLL */ + /* BRG off, keep Pclk source */ + wrtscc(lp->cardbase, cmd, R14, BRSRC); + br = lp->speed; /* get desired speed */ + /* calc 32X BRG divisor */ + tc = ((lp->xtal / 32) / br) - 2; + wrtscc(lp->cardbase, cmd, R12, tc & 0xFF); /* lower byte */ + wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xFF); /* upper byte */ + /* SEARCH mode, BRG source */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); + /* Enable the BRG */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); + } + } + /* Flush rx fifo */ + wrtscc(lp->cardbase, cmd, R3, Rx8); /* Make sure rx is off */ + wrtscc(lp->cardbase, cmd, R0, ERR_RES); /* reset err latch */ + dummy = rdscc(lp->cardbase, cmd, R1); /* get status byte from R1 */ + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + + (void) rdscc(lp->cardbase, cmd, R8); + + /* Now, turn on the receiver and hunt for a flag */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | Rx8); + lp->rstate = ACTIVE; /* Normal state */ + + if (cmd & 2) { /* if channel a */ + setup_rx_dma(lp); + } else { + /* reset buffer pointers */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB)); + } + wrtscc(lp->cardbase, cmd, R15, BRKIE); /* allow ABORT int */ + } +} + +static void scc_init(struct device *dev) +{ + unsigned long flags; + struct pi_local *lp = (struct pi_local *) dev->priv; + + int tc; + long br; + register int cmd; + + /* Initialize 8530 channel for SDLC operation */ + + cmd = CTL + lp->base; + save_flags(flags); + cli(); + + switch (cmd & CHANA) { + case CHANA: + wrtscc(lp->cardbase, cmd, R9, CHRA); /* Reset channel A */ + wrtscc(lp->cardbase, cmd, R2, 0xff); /* Initialize interrupt vector */ + break; + default: + wrtscc(lp->cardbase, cmd, R9, CHRB); /* Reset channel B */ + break; + } + + /* Deselect all Rx and Tx interrupts */ + wrtscc(lp->cardbase, cmd, R1, 0); + + /* Turn off external interrupts (like CTS/CD) */ + wrtscc(lp->cardbase, cmd, R15, 0); + + /* X1 clock, SDLC mode */ + wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK); + + /* Tx/Rx parameters */ + if (lp->speed) { /* Use internal clocking */ + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); + if (!lp->clockmode) + /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */ + wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI); + else + /* Tx Clk from DPLL, Rcv Clk from DPLL, TRxC Outputs BRG */ + wrtscc(lp->cardbase, cmd, R11, TCDPLL | RCDPLL | TRxCBR | TRxCOI); + } else { /* Use external clocking */ + wrtscc(lp->cardbase, cmd, R10, CRCPS); + /* Tx Clk from Trxcl. Rcv Clk from Rtxcl, TRxC pin is input */ + wrtscc(lp->cardbase, cmd, R11, TCTRxCP); + } + + /* Null out SDLC start address */ + wrtscc(lp->cardbase, cmd, R6, 0); + + /* SDLC flag */ + wrtscc(lp->cardbase, cmd, R7, FLAG); + + /* Set up the Transmitter but don't enable it + * DTR, 8 bit TX chars only + */ + wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); + + /* Receiver initial setup */ + wrtscc(lp->cardbase, cmd, R3, Rx8); /* 8 bits/char */ + + /* Setting up BRG now - turn it off first */ + wrtscc(lp->cardbase, cmd, R14, BRSRC); /* BRG off, keep Pclk source */ + + /* set the 32x time constant for the BRG in Receive mode */ + + if (lp->speed) { + br = lp->speed; /* get desired speed */ + tc = ((lp->xtal / 32) / br) - 2; /* calc 32X BRG divisor */ + } else { + tc = 14; + } + + wrtscc(lp->cardbase, cmd, R12, tc & 0xFF); /* lower byte */ + wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xFF); /* upper byte */ + + /* Following subroutine sets up and ENABLES the receiver */ + rts(lp, OFF); /* TX OFF and RX ON */ + + if (lp->speed) { + /* DPLL frm BRG, BRG src PCLK */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR); + } else { + /* DPLL frm rtxc,BRG src PCLK */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | SSRTxC); + } + wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); /* SEARCH mode, keep BRG src */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); /* Enable the BRG */ + + if (!(cmd & 2)) /* if channel b */ + wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB)); + + wrtscc(lp->cardbase, cmd, R15, BRKIE); /* ABORT int */ + + /* Now, turn on the receiver and hunt for a flag */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | Rx8); + + restore_flags(flags); +} + +static void chipset_init(struct device *dev) +{ + int cardbase; + unsigned long flags; + + cardbase = dev->base_addr & 0x3f0; + + save_flags(flags); + cli(); + wrtscc(cardbase, dev->base_addr + CTL, R9, FHWRES); /* Hardware reset */ + /* Disable interrupts with master interrupt ctrl reg */ + wrtscc(cardbase, dev->base_addr + CTL, R9, 0); + restore_flags(flags); + +} + + +__initfunc(int pi_init(void)) +{ + int *port; + int ioaddr = 0; + int card_type = 0; + int ports[] = {0x380, 0x300, 0x320, 0x340, 0x360, 0x3a0, 0}; + + printk(KERN_INFO "PI: V0.8 ALPHA April 23 1995 David Perry (dp@hydra.carleton.ca)\n"); + + /* Only one card supported for now */ + for (port = &ports[0]; *port && !card_type; port++) { + ioaddr = *port; + + if (check_region(ioaddr, PI_TOTAL_SIZE) == 0) { + printk(KERN_INFO "PI: Probing for card at address %#3x\n",ioaddr); + card_type = hw_probe(ioaddr); + } + } + + switch (card_type) { + case 1: + printk(KERN_INFO "PI: Found a PI card at address %#3x\n", ioaddr); + break; + case 2: + printk(KERN_INFO "PI: Found a PI2 card at address %#3x\n", ioaddr); + break; + default: + printk(KERN_ERR "PI: ERROR: No card found\n"); + return -EIO; + } + + /* Link a couple of device structures into the chain */ + /* For the A port */ + /* Allocate space for 4 buffers even though we only need 3, + because one of them may cross a DMA page boundary and + be rejected by get_dma_buffer(). + */ + register_netdev(&pi0a); + + pi0a.priv = kmalloc(sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); + + pi0a.dma = PI_DMA; + pi0a.base_addr = ioaddr + 2; + pi0a.irq = 0; + + /* And the B port */ + register_netdev(&pi0b); + pi0b.base_addr = ioaddr; + pi0b.irq = 0; + + pi0b.priv = kmalloc(sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); + + /* Now initialize them */ + pi_probe(&pi0a, card_type); + pi_probe(&pi0b, card_type); + + pi0b.irq = pi0a.irq; /* IRQ is shared */ + + return 0; +} + +static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize) +{ + if (((addr & 0xffff) + dev_buffsize) <= 0x10000) + return 1; + else + return 0; +} + +static int pi_set_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa = (struct sockaddr *)addr; + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); /* addr is an AX.25 shifted ASCII */ + return 0; /* mac address */ +} + +/* Allocate a buffer which does not cross a DMA page boundary */ +static char * +get_dma_buffer(unsigned long *mem_ptr) +{ + char *ret; + + ret = (char *)*mem_ptr; + + if(!valid_dma_page(*mem_ptr, DMA_BUFF_SIZE + sizeof(struct mbuf))){ + *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); + ret = (char *)*mem_ptr; + } + *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); + return (ret); +} + +static int pi_probe(struct device *dev, int card_type) +{ + short ioaddr; + struct pi_local *lp; + unsigned long flags; + unsigned long mem_ptr; + + ioaddr = dev->base_addr; + + /* Initialize the device structure. */ + /* Must be done before chipset_init */ + /* Make certain the data structures used by the PI2 are aligned. */ + dev->priv = (void *) (((int) dev->priv + 7) & ~7); + lp = (struct pi_local *) dev->priv; + + memset(dev->priv, 0, sizeof(struct pi_local)); + + /* Allocate some buffers which do not cross DMA page boundaries */ + mem_ptr = (unsigned long) dev->priv + sizeof(struct pi_local); + lp->txdmabuf = get_dma_buffer(&mem_ptr); + lp->rxdmabuf1 = (struct mbuf *) get_dma_buffer(&mem_ptr); + lp->rxdmabuf2 = (struct mbuf *) get_dma_buffer(&mem_ptr); + + /* Initialize rx buffer */ + lp->rcvbuf = lp->rxdmabuf1; + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + + /* Initialize the transmit queue head structure */ + skb_queue_head_init(&lp->sndq); + + /* These need to be initialized before scc_init is called. */ + if (card_type == 1) + lp->xtal = (unsigned long) SINGLE / 2; + else + lp->xtal = (unsigned long) DOUBLE / 2; + lp->base = dev->base_addr; + lp->cardbase = dev->base_addr & 0x3f0; + if (dev->base_addr & CHANA) { + lp->speed = DEF_A_SPEED; + /* default channel access Params */ + lp->txdelay = DEF_A_TXDELAY; + lp->persist = DEF_A_PERSIST; + lp->slotime = DEF_A_SLOTIME; + lp->squeldelay = DEF_A_SQUELDELAY; + lp->clockmode = DEF_A_CLOCKMODE; + + } else { + lp->speed = DEF_B_SPEED; + /* default channel access Params */ + lp->txdelay = DEF_B_TXDELAY; + lp->persist = DEF_B_PERSIST; + lp->slotime = DEF_B_SLOTIME; + lp->squeldelay = DEF_B_SQUELDELAY; + lp->clockmode = DEF_B_CLOCKMODE; + } + lp->bufsiz = DMA_BUFF_SIZE; + lp->tstate = IDLE; + + chipset_init(dev); + + if (dev->base_addr & CHANA) { /* Do these things only for the A port */ + /* Note that a single IRQ services 2 devices (A and B channels) */ + + lp->dmachan = dev->dma; + if (lp->dmachan < 1 || lp->dmachan > 3) + printk(KERN_ERR "PI: DMA channel %d out of range\n", lp->dmachan); + + /* chipset_init() was already called */ + + if (dev->irq < 2) { + autoirq_setup(0); + save_flags(flags); + cli(); + wrtscc(lp->cardbase, CTL + lp->base, R1, EXT_INT_ENAB); + /* enable PI card interrupts */ + wrtscc(lp->cardbase, CTL + lp->base, R9, MIE | NV); + restore_flags(flags); + /* request a timer interrupt for 1 mS hence */ + tdelay(lp, 1); + /* 20 "jiffies" should be plenty of time... */ + dev->irq = autoirq_report(20); + if (!dev->irq) { + printk(KERN_ERR "PI: Failed to detect IRQ line.\n"); + } + save_flags(flags); + cli(); + wrtscc(lp->cardbase, dev->base_addr + CTL, R9, FHWRES); /* Hardware reset */ + /* Disable interrupts with master interrupt ctrl reg */ + wrtscc(lp->cardbase, dev->base_addr + CTL, R9, 0); + restore_flags(flags); + } + + printk(KERN_INFO "PI: Autodetected IRQ %d, assuming DMA %d.\n", + dev->irq, dev->dma); + + /* This board has jumpered interrupts. Snarf the interrupt vector + now. There is no point in waiting since no other device can use + the interrupt, and this marks the 'irqaction' as busy. */ + { + int irqval = request_irq(dev->irq, &pi_interrupt,0, "pi2", dev); + if (irqval) { + printk(KERN_ERR "PI: unable to get IRQ %d (irqval=%d).\n", + dev->irq, irqval); + return EAGAIN; + } + } + + /* Grab the region */ + request_region(ioaddr & 0x3f0, PI_TOTAL_SIZE, "pi2" ); + + + } /* Only for A port */ + dev->open = pi_open; + dev->stop = pi_close; + dev->do_ioctl = pi_ioctl; + dev->hard_start_xmit = pi_send_packet; + dev->get_stats = pi_get_stats; + + /* Fill in the fields of the device structure */ + + dev_init_buffers(dev); + +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; +#endif + + dev->set_mac_address = pi_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); + + /* New-style flags. */ + dev->flags = 0; + return 0; +} + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine should set everything up anew at each open, even + registers that "should" only need to be set once at boot, so that + there is non-reboot way to recover if something goes wrong. + */ +static int pi_open(struct device *dev) +{ + unsigned long flags; + static first_time = 1; + + struct pi_local *lp = (struct pi_local *) dev->priv; + + if (dev->base_addr & 2) { /* if A channel */ + if (first_time) { + if (request_dma(dev->dma,"pi2")) { + free_irq(dev->irq, dev); + return -EAGAIN; + } + } + /* Reset the hardware here. */ + chipset_init(dev); + } + lp->tstate = IDLE; + + if (dev->base_addr & 2) { /* if A channel */ + scc_init(dev); /* Called once for each channel */ + scc_init(dev->next); + } + /* master interrupt enable */ + save_flags(flags); + cli(); + wrtscc(lp->cardbase, CTL + lp->base, R9, MIE | NV); + restore_flags(flags); + + lp->open_time = jiffies; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + first_time = 0; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int pi_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct pi_local *lp = (struct pi_local *) dev->priv; + + hardware_send_packet(lp, skb); + dev->trans_start = jiffies; + + return 0; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ +static void pi_interrupt(int reg_ptr, void *dev_id, struct pt_regs *regs) +{ +/* int irq = -(((struct pt_regs *) reg_ptr)->orig_eax + 2);*/ + struct pi_local *lp; + int st; + unsigned long flags; + +/* dev_b = dev_a->next; Relies on the order defined in Space.c */ + +#if 0 + if (dev_a == NULL) { + printk(KERN_ERR "PI: pi_interrupt(): irq %d for unknown device.\n", irq); + return; + } +#endif + /* Read interrupt status register (only valid from channel A) + * Process all pending interrupts in while loop + */ + lp = (struct pi_local *) pi0a.priv; /* Assume channel A */ + while ((st = rdscc(lp->cardbase, pi0a.base_addr | CHANA | CTL, R3)) != 0) { + if (st & CHBTxIP) { + /* Channel B Transmit Int Pending */ + lp = (struct pi_local *) pi0b.priv; + b_txint(lp); + } else if (st & CHARxIP) { + /* Channel A Rcv Interrupt Pending */ + lp = (struct pi_local *) pi0a.priv; + a_rxint(&pi0a, lp); + } else if (st & CHATxIP) { + /* Channel A Transmit Int Pending */ + lp = (struct pi_local *) pi0a.priv; + a_txint(lp); + } else if (st & CHAEXT) { + /* Channel A External Status Int */ + lp = (struct pi_local *) pi0a.priv; + a_exint(lp); + } else if (st & CHBRxIP) { + /* Channel B Rcv Interrupt Pending */ + lp = (struct pi_local *) pi0b.priv; + b_rxint(&pi0b, lp); + } else if (st & CHBEXT) { + /* Channel B External Status Int */ + lp = (struct pi_local *) pi0b.priv; + b_exint(lp); + } + /* Reset highest interrupt under service */ + save_flags(flags); + cli(); + wrtscc(lp->cardbase, lp->base + CTL, R0, RES_H_IUS); + restore_flags(flags); + } /* End of while loop on int processing */ + return; +} + +/* The inverse routine to pi_open(). */ +static int pi_close(struct device *dev) +{ + unsigned long flags; + struct pi_local *lp; + struct sk_buff *ptr; + + save_flags(flags); + cli(); + + lp = (struct pi_local *) dev->priv; + ptr = NULL; + + chipset_init(dev); /* reset the scc */ + disable_dma(lp->dmachan); + + lp->open_time = 0; + + dev->tbusy = 1; + dev->start = 0; + + /* Free any buffers left in the hardware transmit queue */ + while ((ptr = skb_dequeue(&lp->sndq)) != NULL) + kfree_skb(ptr, FREE_WRITE); + + restore_flags(flags); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + unsigned long flags; + struct pi_req rq; + struct pi_local *lp = (struct pi_local *) dev->priv; + + int ret = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct pi_req)); + if (ret) + return ret; + + if(cmd!=SIOCDEVPRIVATE) + return -EINVAL; + + copy_from_user(&rq, ifr->ifr_data, sizeof(struct pi_req)); + + switch (rq.cmd) { + case SIOCSPIPARAM: + + if (!suser()) + return -EPERM; + save_flags(flags); + cli(); + lp->txdelay = rq.txdelay; + lp->persist = rq.persist; + lp->slotime = rq.slotime; + lp->squeldelay = rq.squeldelay; + lp->clockmode = rq.clockmode; + lp->speed = rq.speed; + pi_open(&pi0a); /* both channels get reset %%% */ + restore_flags(flags); + ret = 0; + break; + + case SIOCSPIDMA: + + if (!suser()) + return -EPERM; + ret = 0; + if (dev->base_addr & 2) { /* if A channel */ + if (rq.dmachan < 1 || rq.dmachan > 3) + return -EINVAL; + save_flags(flags); + cli(); + pi_close(dev); + free_dma(lp->dmachan); + dev->dma = lp->dmachan = rq.dmachan; + if (request_dma(lp->dmachan,"pi2")) + ret = -EAGAIN; + pi_open(dev); + restore_flags(flags); + } + break; + + case SIOCSPIIRQ: + ret = -EINVAL; /* add this later */ + break; + + case SIOCGPIPARAM: + case SIOCGPIDMA: + case SIOCGPIIRQ: + + rq.speed = lp->speed; + rq.txdelay = lp->txdelay; + rq.persist = lp->persist; + rq.slotime = lp->slotime; + rq.squeldelay = lp->squeldelay; + rq.clockmode = lp->clockmode; + rq.dmachan = lp->dmachan; + rq.irq = dev->irq; + copy_to_user(ifr->ifr_data, &rq, sizeof(struct pi_req)); + ret = 0; + break; + + default: + ret = -EINVAL; + } + return ret; +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct net_device_stats *pi_get_stats(struct device *dev) +{ + struct pi_local *lp = (struct pi_local *) dev->priv; + + return &lp->stats; +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("David Perry "); +MODULE_DESCRIPTION("AX.25 driver for the Ottawa PI and PI/2 HDLC cards"); + +int init_module(void) +{ + return pi_init(); +} + +void cleanup_module(void) +{ + free_irq(pi0a.irq, &pi0a); /* IRQs and IO Ports are shared */ + release_region(pi0a.base_addr & 0x3f0, PI_TOTAL_SIZE); + + kfree(pi0a.priv); + pi0a.priv = NULL; + unregister_netdev(&pi0a); + + kfree(pi0b.priv); + pi0b.priv = NULL; + unregister_netdev(&pi0b); +} +#endif diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/pt.c linux/drivers/net/hamradio/pt.c --- v2.1.70/linux/drivers/net/hamradio/pt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/pt.c Sat Nov 29 10:33:20 1997 @@ -0,0 +1,1778 @@ +#undef PT_DEBUG 1 +/* + * pt.c: Linux device driver for the Gracilis PackeTwin. + * Copyright (c) 1995 Craig Small VK2XLZ (vk2xlz@vk2xlz.ampr.org.) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge MA 02139, USA. + * + * This driver is largely based upon the PI driver by David Perry. + * + * Revision History + * 23/02/95 cs Started again on driver, last one scrapped + * 27/02/95 cs Program works, we have chan A only. Tx stays on + * 28/02/95 cs Fix Tx problem (& TxUIE instead of | ) + * Fix Chan B Tx timer problem, used TMR2 instead of TMR1 + * 03/03/95 cs Painfully found out (after 3 days) SERIAL_CFG is write only + * created image of it and DMA_CFG + * 21/06/95 cs Upgraded to suit PI driver 0.8 ALPHA + * 22/08/95 cs Changed it all around to make it like pi driver + * 23/08/95 cs It now works, got caught again by TMR2 and we must have + * auto-enables for daughter boards. + * 07/10/95 cs Fixed for 1.3.30 (hopefully) + * 26/11/95 cs Fixed for 1.3.43, ala 29/10 for pi2.c by ac + * 21/12/95 cs Got rid of those nasty warnings when compiling, for 1.3.48 + * 08/08/96 jsn Convert to use as a module. Removed send_kiss, empty_scc and + * pt_loopback functions - they were unused. + * 13/12/96 jsn Fixed to match Linux networking changes. + */ + +/* + * default configuration of the PackeTwin, + * ie What Craig uses his PT for. + */ +#define PT_DMA 3 + +#define DEF_A_SPEED 4800 /* 4800 baud */ +#define DEF_A_TXDELAY 350 /* 350 mS */ +#define DEF_A_PERSIST 64 /* 25% persistence */ +#define DEF_A_SLOTIME 10 /* 10 mS */ +#define DEF_A_SQUELDELAY 30 /* 30 mS */ +#define DEF_A_CLOCKMODE 0 /* Normal clock mode */ +#define DEF_A_NRZI 1 /* NRZI mode */ + +#define DEF_B_SPEED 0 /* 0 means external clock */ +#define DEF_B_TXDELAY 250 /* 250 mS */ +#define DEF_B_PERSIST 64 /* 25% */ +#define DEF_B_SLOTIME 10 /* 10 mS */ +#define DEF_B_SQUELDELAY 30 /* 30 mS */ +#define DEF_B_CLOCKMODE 0 /* Normal clock mode ?!? */ +#define DEF_B_NRZI 1 /* NRZI mode */ + + +#define PARAM_TXDELAY 1 +#define PARAM_PERSIST 2 +#define PARAM_SLOTTIME 3 +#define PARAM_FULLDUP 5 +#define PARAM_HARDWARE 6 +#define PARAM_RETURN 255 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "z8530.h" +#include + +struct mbuf { + struct mbuf *next; + int cnt; + char data[0]; +}; + +/* + * The actual PT devices we will use + */ +static int pt0_preprobe(struct device *dev) {return 0;} /* Dummy probe function */ +static struct device pt0a = { "pt0a", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pt0_preprobe }; +static struct device pt0b = { "pt0b", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pt0_preprobe }; + +/* Ok, they shouldn't be here, but both channels share them */ +/* The Images of the Serial and DMA config registers */ +static unsigned char pt_sercfg = 0; +static unsigned char pt_dmacfg = 0; + +/* The number of IO ports used by the card */ +#define PT_TOTAL_SIZE 16 + +/* Index to functions, as function prototypes. */ + +static int pt_probe(struct device *dev); +static int pt_open(struct device *dev); +static int pt_send_packet(struct sk_buff *skb, struct device *dev); +static void pt_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int pt_close(struct device *dev); +static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd); +static struct net_device_stats *pt_get_stats(struct device *dev); +static void pt_rts(struct pt_local *lp, int x); +static void pt_rxisr(struct device *dev); +static void pt_txisr(struct pt_local *lp); +static void pt_exisr(struct pt_local *lp); +static void pt_tmrisr(struct pt_local *lp); +static char *get_dma_buffer(unsigned long *mem_ptr); +static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize); +static int hw_probe(int ioaddr); +static void tdelay(struct pt_local *lp, int time); +static void chipset_init(struct device *dev); + +static char ax25_bcast[7] = +{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; +static char ax25_test[7] = +{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; + + + +static int ext2_secrm_seed = 152; + +static inline unsigned char random(void) +{ + return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed * 60691 + 1); +} + +static inline void wrtscc(int cbase, int ctl, int sccreg, unsigned char val) +{ + outb_p(sccreg, ctl); /* Select register */ + outb_p(val, ctl); /* Output value */ +} + +static inline unsigned char rdscc(int cbase, int ctl, int sccreg) +{ + unsigned char retval; + + outb_p(sccreg, ctl); /* Select register */ + retval = inb_p(ctl); + return retval; +} + +static void switchbuffers(struct pt_local *lp) +{ + if (lp->rcvbuf == lp->rxdmabuf1) + lp->rcvbuf = lp->rxdmabuf2; + else + lp->rcvbuf = lp->rxdmabuf1; +} + +static void hardware_send_packet(struct pt_local *lp, struct sk_buff *skb) +{ + char kickflag; + unsigned long flags; + char *ptr; + struct device *dev; + + /* First, let's see if this packet is actually a KISS packet */ + ptr = skb->data; + if (ptr[0] != 0 && skb->len >= 2) + { +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: Rx KISS... Control = %d, value = %d.\n", ptr[0], (skb->len > 1? ptr[1] : -1)); +#endif + /* Kludge to get device */ + if ((struct pt_local*)(&pt0b.priv) == lp) + dev = &pt0b; + else + dev = &pt0a; + switch(ptr[0]) + { + + case PARAM_TXDELAY: + /*TxDelay is in 10mS increments */ + lp->txdelay = ptr[1] * 10; + break; + case PARAM_PERSIST: + lp->persist = ptr[1]; + break; + case PARAM_SLOTTIME: + lp->slotime = ptr[1]; + break; + case PARAM_FULLDUP: + /* Yeah right, you wish! Fullduplex is a little while to + * go folks, but this is how you fire it up + */ + break; + /* Perhaps we should have txtail here?? */ + } /*switch */ + return; + } + + lp->stats.tx_packets++; + lp->stats.tx_bytes+=skb->len; + save_flags(flags); + cli(); + kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL); + restore_flags(flags); + +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: hardware_send_packet(): kickflag = %d (%d).\n", kickflag, lp->base & CHANA); +#endif + skb_queue_tail(&lp->sndq, skb); + if (kickflag) + { + /* Simulate interrupt to transmit */ + if (lp->dmachan) + pt_txisr(lp); + else + { + save_flags(flags); + cli(); + if (lp->tstate == IDLE) + pt_txisr(lp); + restore_flags(flags); + } + } +} /* hardware_send_packet() */ + +static void setup_rx_dma(struct pt_local *lp) +{ + unsigned long flags; + int cmd; + unsigned long dma_abs; + unsigned char dmachan; + + save_flags(flags); + cli(); + + dma_abs = (unsigned long) (lp->rcvbuf->data); + dmachan = lp->dmachan; + cmd = lp->base + CTL; + + if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf))) + panic("PI: RX buffer violates DMA boundary!"); + + /* Get ready for RX DMA */ + wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); + + disable_dma(dmachan); + clear_dma_ff(dmachan); + + /* + * Set DMA mode register to single transfers, incrementing address, + * auto init, writes + */ + + set_dma_mode(dmachan, DMA_MODE_READ | 0x10); + set_dma_addr(dmachan, dma_abs); + set_dma_count(dmachan, lp->bufsiz); + enable_dma(dmachan); + + /* + * If a packet is already coming in, this line is supposed to + * avoid receiving a partial packet. + */ + + wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC); + + /* Enable RX dma */ + wrtscc(lp->cardbase, cmd, R1, + WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); + + restore_flags(flags); +} + +static void setup_tx_dma(struct pt_local *lp, int length) +{ + unsigned long dma_abs; + unsigned long flags; + unsigned long dmachan; + + save_flags(flags); + cli(); + + dmachan = lp->dmachan; + dma_abs = (unsigned long) (lp->txdmabuf); + + if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf))) + panic("PT: TX buffer violates DMA boundary!"); + + disable_dma(dmachan); + /* Set DMA mode register to single transfers, incrementing address, + * no auto init, reads + */ + set_dma_mode(dmachan, DMA_MODE_WRITE); + clear_dma_ff(dmachan); + set_dma_addr(dmachan, dma_abs); + /* output byte count */ + set_dma_count(dmachan, length); + + restore_flags(flags); +} + +/* + * This sets up all the registers in the SCC for the given channel + * based upon tsync_hwint() + */ +static void scc_init(struct device *dev) +{ + unsigned long flags; + struct pt_local *lp = (struct pt_local*) dev->priv; + register int cmd = lp->base + CTL; + int tc, br; + +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: scc_init(): (%d).\n", lp->base & CHANA); +#endif + save_flags(flags); + cli(); + + /* We may put something here to enable_escc */ + + if (cmd & CHANA) + { + wrtscc(lp->cardbase, cmd, R9, CHRA); /* Reset channel A */ + wrtscc(lp->cardbase, cmd, R2, 0xff); /* Initialise interrupt vector */ + } + else + wrtscc(lp->cardbase, cmd, R9, CHRB); /* Reset channel B */ + + /* Deselect all Rx and Tx interrupts */ + wrtscc(lp->cardbase, cmd, R1, 0); + + /* Turn off external interrupts (like CTS/CD) */ + wrtscc(lp->cardbase, cmd, R15, 0); + + /* X1 clock, SDLC mode */ + wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK); + + /* Preset CRC and set mode */ + if (lp->nrzi) + /* Preset Tx CRC, put into NRZI mode */ + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); + else + /* Preset Tx CRC, put into NRZ mode */ + wrtscc(lp->cardbase, cmd, R10, CRCPS); + + /* Tx/Rx parameters */ + if (lp->speed) /* Use internal clocking */ + /* Tx Clk from BRG. Rx Clk form DPLL, TRxC pin outputs DPLL */ + wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI); + else /* Use external clocking */ + { + /* Tx Clk from TRxCL. Rx Clk from RTxCL, TRxC pin if input */ + wrtscc(lp->cardbase, cmd, R11, TCTRxCP | RCRTxCP | TRxCBR); + wrtscc(lp->cardbase,cmd, R14, 0); /* wiz1 */ + } + + /* Null out SDLC start address */ + wrtscc(lp->cardbase, cmd, R6, 0); + + /* SDLC flag */ + wrtscc(lp->cardbase, cmd, R7, FLAG); + + /* Setup Tx but don't enable it */ + wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); + + /* Setup Rx */ + wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); + + /* Setup the BRG, turn it off first */ + wrtscc(lp->cardbase, cmd, R14, BRSRC); + + /* set the 32x time constant for the BRG in Rx mode */ + if (lp->speed) + { + br = lp->speed; + tc = ((lp->xtal / 32) / (br * 2)) - 2; + wrtscc(lp->cardbase, cmd, R12, tc & 0xff); /* lower byte */ + wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); /* upper byte */ + } + + /* Turn transmitter off, to setup stuff */ + pt_rts(lp, OFF); + + /* External clocking */ + if (lp->speed) + { + /* DPLL frm BRG, BRG src PCLK */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR); + wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); /* SEARCH mode, keep BRG src */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); /* Enable the BRG */ + + /* Turn off external clock port */ + if (lp->base & CHANA) + outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) ); + else + outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) ); + } + else + { + /* DPLL frm rtxc,BRG src PCLK */ + /* Turn on external clock port */ + if (lp->base & CHANA) + outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) ); + else + outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) ); + } + + if (!lp->dmachan) + wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB)); + + wrtscc(lp->cardbase, cmd, R15, BRKIE); /* ABORT int */ + + /* Turn on the DTR to tell modem we're alive */ + if (lp->base & CHANA) + outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) ); + else + outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) ); + + /* Now, turn on the receiver and hunt for a flag */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 ); + + restore_flags(flags); + +} /* scc_init() */ + +/* Resets the given channel and whole SCC if both channels off */ +static void chipset_init(struct device *dev) +{ + + struct pt_local *lp = (struct pt_local*) dev->priv; +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: chipset_init(): pt0a tstate = %d.\n", ((struct pt_local*)pt0a.priv)->tstate); + printk(KERN_DEBUG "PT: chipset_init(): pt0b tstate = %d.\n", ((struct pt_local*)pt0b.priv)->tstate); +#endif + /* Reset SCC if both channels are to be canned */ + if ( ((lp->base & CHANA) && !(pt_sercfg & PT_DTRB_ON)) || + (!(lp->base & CHANA) && !(pt_sercfg & PT_DTRA_ON)) ) + { + wrtscc(lp->cardbase, lp->base + CTL, R9, FHWRES); + /* Reset int and dma registers */ + outb_p((pt_sercfg = 0), lp->cardbase + SERIAL_CFG); + outb_p((pt_dmacfg = 0), lp->cardbase + DMA_CFG); +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: chipset_init() Resetting SCC, called by ch (%d).\n", lp->base & CHANA); +#endif + } + /* Reset individual channel */ + if (lp->base & CHANA) { + wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | DLC | NV | CHRA); + outb_p( (pt_sercfg &= ~PT_DTRA_ON), lp->cardbase + SERIAL_CFG); + } else { + wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | DLC | NV | CHRB); + outb_p( (pt_sercfg &= ~PT_DTRB_ON), lp->cardbase + SERIAL_CFG); + } +} /* chipset_init() */ + + + +__initfunc(int pt_init(void)) +{ + int *port; + int ioaddr = 0; + int card_type = 0; + int ports[] = + { 0x230, 0x240, 0x250, 0x260, 0x270, 0x280, 0x290, 0x2a0, + 0x2b0, 0x300, 0x330, 0x3f0, 0}; + + printk(KERN_INFO "PT: 0.41 ALPHA 07 October 1995 Craig Small (csmall@small.dropbear.id.au)\n"); + + for (port = &ports[0]; *port && !card_type; port++) { + ioaddr = *port; + + if (check_region(ioaddr, PT_TOTAL_SIZE) == 0) { + printk(KERN_INFO "PT: Probing for card at address %#3x\n", ioaddr); + card_type = hw_probe(ioaddr); + } + } + if (card_type) { + printk(KERN_INFO "PT: Found a PT at address %#3x\n",ioaddr); + } else { + printk(KERN_ERR "PT: ERROR: No card found.\n"); + return -EIO; + } + + /* + * Link a couple of device structures into the chain + * + * For the A port + * Allocate space for 4 buffers even though we only need 3, + * because one of them may cross a DMA page boundary and + * be rejected by get_dma_buffer(). + */ + register_netdev(&pt0a); + + pt0a.priv= kmalloc(sizeof(struct pt_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); + + pt0a.dma = 0; /* wizzer - no dma yet */ + pt0a.base_addr = ioaddr + CHANA; + pt0a.irq = 0; + + /* And B port */ + register_netdev(&pt0b); + + pt0b.priv= kmalloc(sizeof(struct pt_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); + + pt0b.base_addr = ioaddr + CHANB; + pt0b.irq = 0; + + /* Now initialise them */ + pt_probe(&pt0a); + pt_probe(&pt0b); + + pt0b.irq = pt0a.irq; /* IRQ is shared */ + + return 0; +} /* pt_init() */ + +/* + * Probe for PT card. Also initialises the timers + */ +__initfunc(static int hw_probe(int ioaddr)) +{ + int time = 1000; /* Number of milliseconds to test */ + int a = 1; + int b = 1; + unsigned long start_time, end_time; + + inb_p(ioaddr + TMR1CLR); + inb_p(ioaddr + TMR2CLR); + + /* Timer counter channel 0, 1mS period */ + outb_p(SC0 | LSB_MSB | MODE3, ioaddr + TMRCMD); + outb_p(0x00, ioaddr + TMR0); + outb_p(0x18, ioaddr + TMR0); + + /* Setup timer control word for timer 1 */ + outb_p(SC1 | LSB_MSB | MODE0, ioaddr + TMRCMD); + outb_p((time << 1) & 0xff, ioaddr + TMR1); + outb_p((time >> 7) & 0xff, ioaddr + TMR1); + + /* wait until counter reg is loaded */ + do { + /* Latch count for reading */ + outb_p(SC1, ioaddr + TMRCMD); + a = inb_p(ioaddr + TMR1); + b = inb_p(ioaddr + TMR1); + } while (b == 0); + start_time = jiffies; + while(b != 0) + { + /* Latch count for reading */ + outb_p(SC1, ioaddr + TMRCMD); + a = inb_p(ioaddr + TMR1); + b = inb_p(ioaddr + TMR1); + end_time = jiffies; + /* Don't wait forever - there may be no card here */ + if ((end_time - start_time) > 200) + { + inb_p(ioaddr + TMR1CLR); + return 0; + } + } + + /* Now fix the timers up for general operation */ + + /* Clear the timers */ + inb_p(ioaddr + TMR1CLR); + inb_p(ioaddr + TMR2CLR); + + outb_p(SC1 | LSB_MSB | MODE0, ioaddr + TMRCMD); + inb_p(ioaddr + TMR1CLR); + + outb_p(SC2 | LSB_MSB | MODE0, ioaddr + TMRCMD); + /* Should this be tmr1 or tmr2? wiz3*/ + inb_p(ioaddr + TMR1CLR); + + return 1; +} /* hw_probe() */ + + +static void pt_rts(struct pt_local *lp, int x) +{ + int tc; + long br; + int cmd = lp->base + CTL; +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_rts(): Transmitter status will be %d (%d).\n", x, lp->base & CHANA); +#endif + if (x == ON) { + /* Ex ints off to avoid int */ + wrtscc(lp->cardbase, cmd, R15, 0); + wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); /* Rx off */ + lp->rstate = IDLE; + + if(lp->dmachan) + { + /* Setup for Tx DMA */ + wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); + } else { + /* No interrupts */ + wrtscc(lp->cardbase, cmd, R1, 0); + } + + if (!lp->clockmode) + { + if (lp->speed) + { + br = lp->speed; + tc = (lp->xtal / (br * 2)) - 2; + wrtscc(lp->cardbase, cmd, R12, tc & 0xff); + wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); + } + } + /* Turn on Tx by raising RTS */ + wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR); + /* Transmitter on now */ + } else { /* turning off Tx */ + lp->tstate = IDLE; + + /* Turn off Tx by dropping RTS */ + wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); + if (!lp->clockmode) + { + if (lp->speed) /* internally clocked */ + { + /* Reprogram BRG from 32x clock for Rx DPLL */ + /* BRG off, keep PClk source */ + wrtscc(lp->cardbase, cmd, R14, BRSRC); + br = lp->speed; + tc = ((lp->xtal / 32) / (br * 2)) - 2; + wrtscc(lp->cardbase, cmd, R12, tc & 0xff); + wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); + + /* SEARCH mode, BRG source */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); + /* Enable the BRG */ + wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); + } + } + /* Flush Rx fifo */ + /* Turn Rx off */ + wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); + + /* Reset error latch */ + wrtscc(lp->cardbase, cmd, R0, ERR_RES); + + /* get status byte from R1 */ + (void) rdscc(lp->cardbase, cmd, R1); + + /* Read and dump data in queue */ + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + + /* Now, turn on Rx and hunt for a flag */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | AUTO_ENAB | Rx8 ); + + lp->rstate = ACTIVE; + + if (lp->dmachan) + { + setup_rx_dma(lp); + } else { + /* Reset buffer pointers */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + /* Allow aborts to interrupt us */ + wrtscc(lp->cardbase, cmd, R1, INT_ALL_Rx | EXT_INT_ENAB); + + } + wrtscc(lp->cardbase, cmd, R15, BRKIE ); + } +} /* pt_rts() */ + + +static int valid_dma_page(unsigned long addr, unsigned long dev_bufsize) +{ + if (((addr & 0xffff) + dev_bufsize) <= 0x10000) + return 1; + else + return 0; +} + +static int pt_set_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa = (struct sockaddr *)addr; + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); /* addr is an AX.25 shifted ASCII */ + return 0; /* mac address */ +} + + +/* Allocate a buffer which does not cross a DMA page boundary */ +static char * get_dma_buffer(unsigned long *mem_ptr) +{ + char *ret; + + ret = (char *) *mem_ptr; + + if (!valid_dma_page(*mem_ptr, DMA_BUFF_SIZE + sizeof(struct mbuf))) { + *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); + ret = (char *) *mem_ptr; + } + *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); + return (ret); +} /* get_dma_buffer() */ + + +/* + * Sets up all the structures for the PT device + */ +static int pt_probe(struct device *dev) +{ + short ioaddr; + struct pt_local *lp; + unsigned long flags; + unsigned long mem_ptr; + + ioaddr = dev->base_addr; + + /* + * Initialise the device structure. + * Must be done before chipset_init() + * Make sure data structures used by the PT are aligned + */ + dev->priv = (void *) (((int) dev->priv + 7) & ~7); + lp = (struct pt_local*) dev->priv; + + memset(dev->priv, 0, sizeof(struct pt_local)); + + /* Allocate some buffers which do not cross DMA boundaries */ + mem_ptr = (unsigned long) dev->priv + sizeof(struct pt_local); + lp->txdmabuf = get_dma_buffer(&mem_ptr); + lp->rxdmabuf1 = (struct mbuf *) get_dma_buffer(&mem_ptr); + lp->rxdmabuf2 = (struct mbuf *) get_dma_buffer(&mem_ptr); + + /* Initialise the Rx buffer */ + lp->rcvbuf = lp->rxdmabuf1; + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + + /* Initialise the transmit queue head structure */ + skb_queue_head_init(&lp->sndq); + + lp->base = dev->base_addr; + lp->cardbase = dev->base_addr & 0x3f0; + + /* These need to be initialised before scc_init() is called. + */ + lp->xtal = XTAL; + + if (dev->base_addr & CHANA) { + lp->speed = DEF_A_SPEED; + lp->txdelay = DEF_A_TXDELAY; + lp->persist = DEF_A_PERSIST; + lp->slotime = DEF_A_SLOTIME; + lp->squeldelay = DEF_A_SQUELDELAY; + lp->clockmode = DEF_A_CLOCKMODE; + lp->nrzi = DEF_A_NRZI; + } else { + lp->speed = DEF_B_SPEED; + lp->txdelay = DEF_B_TXDELAY; + lp->persist = DEF_B_PERSIST; + lp->slotime = DEF_B_SLOTIME; + lp->squeldelay = DEF_B_SQUELDELAY; + lp->clockmode = DEF_B_CLOCKMODE; + lp->nrzi = DEF_B_NRZI; + } + lp->bufsiz = DMA_BUFF_SIZE; + lp->tstate = IDLE; + + chipset_init(dev); + + if (dev->base_addr & CHANA) { + /* Note that a single IRQ services 2 devices (A and B channels) + */ + + /* + * We disable the dma for a while, we have to get ints working + * properly first!! + */ + lp->dmachan = 0; + + if (dev->irq < 2) { + autoirq_setup(0); + + /* Turn on PT interrupts */ + save_flags(flags); + cli(); + outb_p( pt_sercfg |= PT_EI, lp->cardbase + INT_CFG); + restore_flags(flags); + + /* Set a timer interrupt */ + tdelay(lp, 1); + dev->irq = autoirq_report(20); + + /* Turn off PT interrupts */ + save_flags(flags); + cli(); + outb_p( (pt_sercfg &= ~ PT_EI), lp->cardbase + INT_CFG); + restore_flags(flags); + + if (!dev->irq) { + printk(KERN_ERR "PT: ERROR: Failed to detect IRQ line, assuming IRQ7.\n"); + } + } + + printk(KERN_INFO "PT: Autodetected IRQ %d, assuming DMA %d\n", dev->irq, dev->dma); + + /* This board has jumpered interrupts. Snarf the interrupt vector + * now. There is no point in waiting since no other device can use + * the interrupt, and this marks the 'irqaction' as busy. + */ + { + int irqval = request_irq(dev->irq, &pt_interrupt,0, "pt", dev); + if (irqval) { + printk(KERN_ERR "PT: ERROR: Unable to get IRQ %d (irqval = %d).\n", + dev->irq, irqval); + return EAGAIN; + } + } + + /* Grab the region */ + request_region(ioaddr & 0x3f0, PT_TOTAL_SIZE, "pt" ); + } /* A port */ + dev->open = pt_open; + dev->stop = pt_close; + dev->do_ioctl = pt_ioctl; + dev->hard_start_xmit = pt_send_packet; + dev->get_stats = pt_get_stats; + + /* Fill in the fields of the device structure */ + dev_init_buffers(dev); + +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; +#endif + + dev->set_mac_address = pt_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 default */ + dev->addr_len = 7; /* sizeof an ax.25 address */ + memcpy(dev->broadcast, ax25_bcast, 7); + memcpy(dev->dev_addr, ax25_test, 7); + + /* New style flags */ + dev->flags = 0; + + return 0; +} /* pt_probe() */ + + +/* Open/initialise the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that 'should' only be set once at boot, so that there is + * a non-reboot way to recover if something goes wrong. + * derived from last half of tsync_attach() + */ +static int pt_open(struct device *dev) +{ + unsigned long flags; + struct pt_local *lp = dev->priv; + static first_time = 1; + + if (dev->base_addr & CHANA) + { + if (first_time) + { + if (request_dma(dev->dma, "pt")) + { + free_irq(dev->irq, dev); + return -EAGAIN; + } + } + + /* Reset hardware */ + chipset_init(dev); + } + lp->tstate = IDLE; + + if (dev->base_addr & CHANA) + { + scc_init(dev); + scc_init(dev->next); + } + /* Save a copy of register RR0 for comparing with later on */ + /* We always put 0 in zero count */ + lp->saved_RR0 = rdscc(lp->cardbase, lp->base + CTL, R0) & ~ZCOUNT; + + /* master interrupt enable */ + save_flags(flags); + cli(); + wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | NV); + outb_p( pt_sercfg |= PT_EI, lp->cardbase + INT_CFG); + restore_flags(flags); + + lp->open_time = jiffies; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + first_time = 0; + + MOD_INC_USE_COUNT; + + return 0; +} /* pt_open() */ + +static int pt_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct pt_local *lp = (struct pt_local *) dev->priv; + +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_send_packet(): (%d)\n", lp->base & CHANA); +#endif + hardware_send_packet(lp, skb); + dev->trans_start = jiffies; + + return 0; +} + + + +/* The inverse routine to pt_open() */ +static int pt_close(struct device *dev) +{ + unsigned long flags; + struct pt_local *lp = dev->priv; + struct sk_buff *ptr = NULL; + int cmd; + + cmd = lp->base + CTL; + + save_flags(flags); + cli(); + + /* Reset SCC or channel */ + chipset_init(dev); + disable_dma(lp->dmachan); + + lp->open_time = 0; + dev->tbusy = 1; + dev->start = 0; + + /* Free any buffers left in the hardware transmit queue */ + while ((ptr = skb_dequeue(&lp->sndq)) != NULL) + kfree_skb(ptr, FREE_WRITE); + + restore_flags(flags); + +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_close(): Closing down channel (%d).\n", lp->base & CHANA); +#endif + + MOD_DEC_USE_COUNT; + + return 0; +} /* pt_close() */ + + +static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + unsigned long flags; + struct pt_req rq; + struct pt_local *lp = (struct pt_local *) dev->priv; + + int ret = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct pt_req)); + if (ret) + return ret; + + if (cmd != SIOCDEVPRIVATE) + return -EINVAL; + + copy_from_user(&rq, ifr->ifr_data, sizeof(struct pt_req)); + + switch (rq.cmd) { + case SIOCSPIPARAM: + + if (!suser()) + return -EPERM; + save_flags(flags); + cli(); + lp->txdelay = rq.txdelay; + lp->persist = rq.persist; + lp->slotime = rq.slotime; + lp->squeldelay = rq.squeldelay; + lp->clockmode = rq.clockmode; + lp->speed = rq.speed; + pt_open(&pt0a); + restore_flags(flags); + ret = 0; + break; + + case SIOCSPIDMA: + + if (!suser()) + return -EPERM; + ret = 0; + if (dev->base_addr & CHANA) { /* if A channel */ + if (rq.dmachan < 1 || rq.dmachan > 3) + return -EINVAL; + save_flags(flags); + cli(); + pt_close(dev); + free_dma(lp->dmachan); + dev->dma = lp->dmachan = rq.dmachan; + if (request_dma(lp->dmachan,"pt")) + ret = -EAGAIN; + pt_open(dev); + restore_flags(flags); + } + break; + + case SIOCSPIIRQ: + ret = -EINVAL; /* add this later */ + break; + + case SIOCGPIPARAM: + case SIOCGPIDMA: + case SIOCGPIIRQ: + + rq.speed = lp->speed; + rq.txdelay = lp->txdelay; + rq.persist = lp->persist; + rq.slotime = lp->slotime; + rq.squeldelay = lp->squeldelay; + rq.clockmode = lp->clockmode; + rq.dmachan = lp->dmachan; + rq.irq = dev->irq; + copy_to_user(ifr->ifr_data, &rq, sizeof(struct pt_req)); + ret = 0; + break; + + default: + ret = -EINVAL; + } + return ret; +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ + +static struct net_device_stats *pt_get_stats(struct device *dev) +{ + struct pt_local *lp = (struct pt_local *) dev->priv; + return &lp->stats; +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ + + +static void tdelay(struct pt_local *lp, int time) +{ + /* For some reason, we turn off the Tx interrupts here! */ + if (!lp->dmachan) + wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB); + + if (lp->base & CHANA) + { + outb_p(time & 0xff, lp->cardbase + TMR1); + outb_p((time >> 8)&0xff, lp->cardbase + TMR1); + } + else + { + outb_p(time & 0xff, lp->cardbase + TMR2); + outb_p((time >> 8)&0xff, lp->cardbase + TMR2); + } +} /* tdelay */ + + +static void pt_txisr(struct pt_local *lp) +{ + unsigned long flags; + int cmd; + unsigned char c; + + save_flags(flags); + cli(); + cmd = lp->base + CTL; + +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_txisr(): tstate = %d (%d).\n", lp->tstate, lp->base & CHANA); +#endif + + switch (lp->tstate) + { + case CRCOUT: + lp->tstate = FLAGOUT; + tdelay(lp, lp->squeldelay); + restore_flags(flags); + return; + + case IDLE: + /* Transmitter idle. Find a frame for transmission */ + if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) + { + /* Nothing to send - return to receive mode + * Tx off now - flag should have gone + */ + pt_rts(lp, OFF); + + restore_flags(flags); + return; + } + if (!lp->dmachan) + { + lp->txptr = lp->sndbuf->data; + lp->txptr++; /* Ignore KISS control byte */ + lp->txcnt = (int) lp->sndbuf->len - 1; + } + /* If a buffer to send, drop though here */ + + case DEFER: + /* Check DCD - debounce it */ + /* See Intel Microcommunications Handbook p2-308 */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) + { + lp->tstate = DEFER; + tdelay(lp, 100); + /* DEFER until DCD transition or timeout */ + wrtscc(lp->cardbase, cmd, R15, DCDIE); + restore_flags(flags); + return; + } + if (random() > lp->persist) + { + lp->tstate = DEFER; + tdelay(lp, lp->slotime); + restore_flags(flags); + return; + } + pt_rts(lp, ON); /* Tx on */ + if (lp->dmachan) + wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); + lp->tstate = ST_TXDELAY; + tdelay(lp, lp->txdelay); + restore_flags(flags); + return; + + case ACTIVE: + /* Here we are actively sending a frame */ + if (lp->txcnt--) + { + /* XLZ - checkout Gracilis PT code to see if the while + * loop is better or not. + */ + c = *lp->txptr++; + /* next char is gone */ + wrtscc(lp->cardbase, cmd, R8, c); + /* stuffing a char satisfies interrupt condition */ + } else { + /* No more to send */ + kfree_skb(lp->sndbuf, FREE_WRITE); + lp->sndbuf = NULL; + if ((rdscc(lp->cardbase, cmd, R0) & TxEOM)) + { + /* Did we underrun */ + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); + lp->tstate = FLAGOUT; + tdelay(lp, lp->squeldelay); + restore_flags(flags); + return; + } + lp->tstate = UNDERRUN; + /* Send flags on underrun */ + if (lp->nrzi) + { + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); + } else { + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZ); + } + /* Reset Tx interrupt pending */ + wrtscc(lp->cardbase, cmd, R0, RES_Tx_P); + } + restore_flags(flags); + return; + default: + printk(KERN_ERR "PT: pt_txisr(): Invalid tstate (%d) for chan %s.\n", lp->tstate, (cmd & CHANA? "A": "B") ); + pt_rts(lp, OFF); + lp->tstate = IDLE; + break; + } /*switch */ + restore_flags(flags); +} + +static void pt_rxisr(struct device *dev) +{ + struct pt_local *lp = (struct pt_local*) dev->priv; + int cmd = lp->base + CTL; + int bytecount; + unsigned long flags; + char rse; + struct sk_buff *skb; + int sksize, pkt_len; + struct mbuf *cur_buf = NULL; + unsigned char *cfix; + + save_flags(flags); + cli(); + + /* Get status byte from R1 */ + rse = rdscc(lp->cardbase, cmd, R1); + +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_rxisr(): R1 = %#3x. (%d)\n", rse, lp->base & CHANA); +#endif + + if (lp->dmachan && (rse & Rx_OVR)) + lp->rstate = RXERROR; + + if (rdscc(lp->cardbase, cmd, R0) & Rx_CH_AV && !lp->dmachan) + { + /* There is a char to be stored + * Read special condition bits before reading the data char + */ + if (rse & Rx_OVR) + { + /* Rx overrun - toss buffer */ + /* wind back the pointers */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + lp->rstate = RXERROR; + lp->stats.rx_errors++; + lp->stats.rx_fifo_errors++; + } else if (lp->rcvbuf->cnt >= lp->bufsiz) + { + /* Too large packet + * wind back Rx buffer pointers + */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + lp->rstate = TOOBIG; + } + /* ok, we can store the Rx char if no errors */ + if (lp->rstate == ACTIVE) + { + *lp->rcp++ = rdscc(lp->cardbase, cmd, R8); + lp->rcvbuf->cnt++; + } else { + /* we got an error, dump the FIFO */ + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + + /* Reset error latch */ + wrtscc(lp->cardbase, cmd, R0, ERR_RES); + lp->rstate = ACTIVE; + + /* Resync the SCC */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); + + } + } + + if (rse & END_FR) + { +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_rxisr() Got end of a %u byte frame.\n", lp->rcvbuf->cnt); +#endif + if (lp->dmachan) + { + clear_dma_ff(lp->dmachan); + bytecount = lp->bufsiz - get_dma_residue(lp->dmachan); + } else { + bytecount = lp->rcvbuf->cnt; + } + + /* END OF FRAME - Make sure Rx was active */ + if (lp->rcvbuf->cnt > 0 || lp->dmachan) + { + if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (bytecount < 10)) + { + if ((bytecount >= 10) && (rse & CRC_ERR)) + { + lp->stats.rx_crc_errors++; + } + if (lp->dmachan) + { + if (lp->rstate == RXERROR) + { + lp->stats.rx_errors++; + lp->stats.rx_over_errors++; + } + lp->rstate = ACTIVE; + setup_rx_dma(lp); + } else { + /* wind back Rx buffer pointers */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + + /* Re-sync the SCC */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); + + } +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_rxisr() %s error.\n", (rse & CRC_ERR)? "CRC" : "state"); +#endif + } else { + /* We have a valid frame */ + if (lp->dmachan) + { + pkt_len = lp->rcvbuf->cnt = bytecount - 2 +1; + /* Get buffer for next frame */ + cur_buf = lp->rcvbuf; + switchbuffers(lp); + setup_rx_dma(lp); + } else { + pkt_len = lp->rcvbuf->cnt -= 2; /* Toss 2 CRC bytes */ + pkt_len += 1; /* make room for KISS control byte */ + } + + /* Malloc up new buffer */ + sksize = pkt_len; + skb = dev_alloc_skb(sksize); + if (skb == NULL) + { + printk(KERN_ERR "PT: %s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + restore_flags(flags); + return; + } + skb->dev = dev; + + /* KISS kludge = prefix with a 0 byte */ + cfix=skb_put(skb,pkt_len); + *cfix++=0; + /* skb->data points to the start of sk_buff area */ + if (lp->dmachan) + memcpy(cfix, (char*)cur_buf->data, pkt_len - 1); + else + memcpy(cfix, lp->rcvbuf->data, pkt_len - 1); + skb->protocol = ntohs(ETH_P_AX25); + skb->mac.raw=skb->data; + lp->stats.rx_bytes+=skb->len; + netif_rx(skb); + lp->stats.rx_packets++; + if (!lp->dmachan) + { + /* packet queued - wind back buffer for next frame */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + } + } /* good frame */ + } /* check active Rx */ + /* Clear error status */ + lp->rstate = ACTIVE; + /* Reset error latch */ + } /* end EOF check */ + wrtscc(lp->cardbase, cmd, R0, ERR_RES); + restore_flags(flags); +} /* pt_rxisr() */ + +/* + * This handles the two timer interrupts. + * This is a real bugger, cause you have to rip it out of the pi's + * external status code. They use the CTS line or something. + */ +static void pt_tmrisr(struct pt_local *lp) +{ + unsigned long flags; + +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_tmrisr(): tstate = %d (%d).\n", lp->tstate, lp->base & CHANA); +#endif + + save_flags(flags); + cli(); + + + switch (lp->tstate) + { + /* Most of this stuff is in pt_exisr() */ + case FLAGOUT: + case ST_TXDELAY: + case DEFER: +/* case ACTIVE: + case UNDERRUN:*/ + pt_exisr(lp); + break; + + default: + if (lp->base & CHANA) + printk(KERN_ERR "PT: pt_tmrisr(): Invalid tstate %d for Channel A\n", lp->tstate); + else + printk(KERN_ERR "PT: pt_tmrisr(): Invalid tstate %d for Channel B\n", lp->tstate); + break; + } /* end switch */ + restore_flags(flags); +} /* pt_tmrisr() */ + + +/* + * This routine is called by the kernel when there is an interrupt for the + * PT. + */ +static void pt_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* It's a tad dodgy here, but we assume pt0a until proven otherwise */ + struct device *dev = &pt0a; + struct pt_local *lp = dev->priv; + unsigned char intreg; + unsigned char st; + register int cbase = dev->base_addr & 0x3f0; + unsigned long flags; + + /* Read the PT's interrupt register, this is not the SCC one! */ + intreg = inb_p(cbase + INT_REG); + while(( intreg & 0x07) != 0x07) { + /* Read interrupt register pending from Channel A */ + while ((st = rdscc(cbase, cbase + CHANA + CTL, R3)) != 0) + { + /* Read interrupt vector from R2, channel B */ +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_interrupt(): R3 = %#3x", st); +#endif +/* st = rdscc(lp->cardbase, cbase + CHANB + CTL, R2) & 0x0e;*/ +#ifdef PT_DEBUG + printk(KERN_DEBUG "PI: R2 = %#3x.\n", st); +#endif + if (st & CHARxIP) { + /* Channel A Rx */ + lp = (struct pt_local*)pt0a.priv; + pt_rxisr(&pt0a); + } else if (st & CHATxIP) { + /* Channel A Tx */ + lp = (struct pt_local*)pt0a.priv; + pt_txisr(lp); + } else if (st & CHAEXT) { + /* Channel A External Status */ + lp = (struct pt_local*)pt0a.priv; + pt_exisr(lp); + } else if (st & CHBRxIP) { + /* Channel B Rx */ + lp= (struct pt_local*)pt0b.priv; + pt_rxisr(&pt0b); + } else if (st & CHBTxIP) { + /* Channel B Tx */ + lp = (struct pt_local*)pt0b.priv; + pt_txisr(lp); + } else if (st & CHBEXT) { + /* Channel B External Status */ + lp = (struct pt_local*)pt0b.priv; + pt_exisr(lp); + } + /* Reset highest interrupt under service */ + save_flags(flags); + cli(); + wrtscc(lp->cardbase, lp->base + CTL, R0, RES_H_IUS); + restore_flags(flags); + } /* end of SCC ints */ + + if (!(intreg & PT_TMR1_MSK)) + { + /* Clear timer 1 */ + inb_p(cbase + TMR1CLR); + + pt_tmrisr( (struct pt_local*)pt0a.priv); + } + + if (!(intreg & PT_TMR2_MSK)) + { + /* Clear timer 2 */ + inb_p(cbase + TMR2CLR); + + pt_tmrisr( (struct pt_local*)pt0b.priv); + } + + /* Get the next PT interrupt vector */ + intreg = inb_p(cbase + INT_REG); + } /* while (intreg) */ +} /* pt_interrupt() */ + + +static void pt_exisr(struct pt_local *lp) +{ + unsigned long flags; + int cmd = lp->base + CTL; + unsigned char st; + char c; + int length; + + save_flags(flags); + cli(); + + /* Get external status */ + st = rdscc(lp->cardbase, cmd, R0); + +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: exisr(): R0 = %#3x tstate = %d (%d).\n", st, lp->tstate, lp->base & CHANA); +#endif + /* Reset external status latch */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + + if ((lp->rstate >= ACTIVE) && (st & BRK_ABRT) && lp->dmachan) + { + setup_rx_dma(lp); + lp->rstate = ACTIVE; + } + + switch (lp->tstate) + { + case ACTIVE: /* Unexpected underrun */ +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: exisr(): unexpected underrun detected.\n"); +#endif + kfree_skb(lp->sndbuf, FREE_WRITE); + lp->sndbuf = NULL; + if (!lp->dmachan) + { + wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + } + lp->tstate = FLAGOUT; + tdelay(lp, lp->squeldelay); + restore_flags(flags); + return; + case UNDERRUN: + lp->tstate = CRCOUT; + restore_flags(flags); + return; + case FLAGOUT: + /* squeldelay has timed out */ + /* Find a frame for transmission */ + if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) + { + /* Nothing to send - return to Rx mode */ + pt_rts(lp, OFF); + lp->tstate = IDLE; + restore_flags(flags); + return; + } + if (!lp->dmachan) + { + lp->txptr = lp->sndbuf->data; + lp->txptr++; /* Ignore KISS control byte */ + lp->txcnt = (int) lp->sndbuf->len - 1; + } + /* Fall through if we have a packet */ + + case ST_TXDELAY: + if (lp->dmachan) + { + /* Disable DMA chan */ + disable_dma(lp->dmachan); + + /* Set up for TX dma */ + wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); + + length = lp->sndbuf->len - 1; + memcpy(lp->txdmabuf, &lp->sndbuf->data[1], length); + + /* Setup DMA controller for Tx */ + setup_tx_dma(lp, length); + + enable_dma(lp->dmachan); + + /* Reset CRC, Txint pending */ + wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC | RES_Tx_P); + + /* Allow underrun only */ + wrtscc(lp->cardbase, cmd, R15, TxUIE); + + /* Enable TX DMA */ + wrtscc(lp->cardbase, cmd, R1, WT_RDY_ENAB | WT_FN_RDYFN | EXT_INT_ENAB); + + /* Send CRC on underrun */ + wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); + + lp->tstate = ACTIVE; + break; + } + /* Get first char to send */ + lp->txcnt--; + c = *lp->txptr++; + /* Reset CRC for next frame */ + wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC); + + /* send abort on underrun */ + if (lp->nrzi) + { + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI | ABUNDER); + } else { + wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZ | ABUNDER); + } + /* send first char */ + wrtscc(lp->cardbase, cmd, R8, c); + + /* Reset end of message latch */ + wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); + + /* stuff an extra one in */ +/* while ((rdscc(lp->cardbase, cmd, R0) & Tx_BUF_EMP) && lp->txcnt) + { + lp->txcnt--; + c = *lp->txptr++; + wrtscc(lp->cardbase, cmd, R8, c); + }*/ + + /* select Tx interrupts to enable */ + /* Allow underrun int only */ + wrtscc(lp->cardbase, cmd, R15, TxUIE); + + /* Reset external interrupts */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + + /* Tx and Rx ints enabled */ + wrtscc(lp->cardbase, cmd, R1, TxINT_ENAB | EXT_INT_ENAB); + + lp->tstate = ACTIVE; + restore_flags(flags); + return; + + /* slotime has timed out */ + case DEFER: + /* Check DCD - debounce it + * see Intel Microcommunications Handbook, p2-308 + */ + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); + if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) + { + lp->tstate = DEFER; + tdelay(lp, 100); + /* DEFER until DCD transition or timeout */ + wrtscc(lp->cardbase, cmd, R15, DCDIE); + restore_flags(flags); + return; + } + if (random() > lp->persist) + { + lp->tstate = DEFER; + tdelay(lp, lp->slotime); + restore_flags(flags); + return; + } + if (lp->dmachan) + wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); + pt_rts(lp, ON); /* Tx on */ + lp->tstate = ST_TXDELAY; + tdelay(lp, lp->txdelay); + restore_flags(flags); + return; + + /* Only for int driven parts */ + if (lp->dmachan) + { + restore_flags(flags); + return; + } + + } /* end switch */ + /* + * Rx mode only + * This triggers when hunt mode is entered, & since an ABORT + * automatically enters hunt mode, we use that to clean up + * any waiting garbage + */ + if ((lp->rstate == ACTIVE) && (st & BRK_ABRT) ) + { +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: exisr(): abort detected.\n"); +#endif + /* read and dump all of SCC Rx FIFO */ + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + (void) rdscc(lp->cardbase, cmd, R8); + + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + + /* Re-sync the SCC */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); + + } + + /* Check for DCD transitions */ + if ( (st & DCD) != (lp->saved_RR0 & DCD)) + { +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_exisr(): DCD is now %s.\n", (st & DCD)? "ON" : "OFF" ); +#endif + if (st & DCD) + { + /* Check that we don't already have some data */ + if (lp->rcvbuf->cnt > 0) + { +#ifdef PT_DEBUG + printk(KERN_DEBUG "PT: pt_exisr() dumping %u bytes from buffer.\n", lp->rcvbuf->cnt); +#endif + /* wind back buffers */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + } + } else { /* DCD off */ + + /* read and dump al SCC FIFO */ + (void)rdscc(lp->cardbase, cmd, R8); + (void)rdscc(lp->cardbase, cmd, R8); + (void)rdscc(lp->cardbase, cmd, R8); + + /* wind back buffers */ + lp->rcp = lp->rcvbuf->data; + lp->rcvbuf->cnt = 0; + + /* Re-sync the SCC */ + wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); + } + + } + /* Update the saved version of register RR) */ + lp->saved_RR0 = st &~ ZCOUNT; + restore_flags(flags); + +} /* pt_exisr() */ + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Craig Small VK2XLZ "); +MODULE_DESCRIPTION("AX.25 driver for the Gracillis PacketTwin HDLC card"); + +int init_module(void) +{ + return pt_init(); +} + +void cleanup_module(void) +{ + free_irq(pt0a.irq, &pt0a); /* IRQs and IO Ports are shared */ + release_region(pt0a.base_addr & 0x3f0, PT_TOTAL_SIZE); + + kfree(pt0a.priv); + pt0a.priv = NULL; + unregister_netdev(&pt0a); + + kfree(pt0b.priv); + pt0b.priv = NULL; + unregister_netdev(&pt0b); +} +#endif diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c --- v2.1.70/linux/drivers/net/hamradio/scc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/scc.c Sat Nov 29 16:29:37 1997 @@ -0,0 +1,2257 @@ +#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" + +/* + * Please use z8530drv-utils-3.0 with this version. + * ------------------ + */ + +/* + ******************************************************************** + * SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 * + ******************************************************************** + + + ******************************************************************** + + Copyright (c) 1993, 1997 Joerg Reuter DL1BKE + + portions (c) 1993 Guido ten Dolle PE1NNZ + + ******************************************************************** + + The driver and the programs in the archive are UNDER CONSTRUCTION. + The code is likely to fail, and so your kernel could --- even + a whole network. + + This driver is intended for Amateur Radio use. If you are running it + for commercial purposes, please drop me a note. I am nosy... + + ...BUT: + + ! You m u s t recognize the appropriate legislations of your country ! + ! before you connect a radio to the SCC board and start to transmit or ! + ! receive. The GPL allows you to use the d r i v e r, NOT the RADIO! ! + + For non-Amateur-Radio use please note that you might need a special + allowance/licence from the designer of the SCC Board and/or the + MODEM. + + This program is free software; you can redistribute it and/or modify + it under the terms of the (modified) GNU General Public License + delivered with the Linux kernel source. + + 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 find a copy of the GNU General Public License in + /usr/src/linux/COPYING; + + ******************************************************************** + + + Incomplete history of z8530drv: + ------------------------------- + + 940913 - started to write the driver, rescued most of my own + code (and Hans Alblas' memory buffer pool concept) from + an earlier project "sccdrv" which was initiated by + Guido ten Dolle. Not much of the old driver survived, + though. The first version I put my hands on was sccdrv1.3 + from August 1993. The memory buffer pool concept + appeared in an unauthorized sccdrv version (1.5) from + August 1994. + + 950131 - changed copyright notice to GPL without limitations. + + . + . + . + + 961005 - New semester, new driver... + + * KISS TNC emulator removed (TTY driver) + * Source moved to drivers/net/ + * Includes Z8530 defines from drivers/net/z8530.h + * Uses sk_buffer memory management + * Reduced overhead of /proc/net/z8530drv output + * Streamlined quite a lot things + * Invents brand new bugs... ;-) + + The move to version number 3.0 reflects theses changes. + You can use 'kissbridge' if you need a KISS TNC emulator. + + 961213 - Fixed for Linux networking changes. (G4KLX) + 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! + + NB -- if you find errors, change something, please let me know + first before you distribute it... And please don't touch + the version number. Just replace my callsign in + "v3.0.dl1bke" with your own. Just to avoid confusion... + + If you want to add your modification to the linux distribution + please (!) contact me first. + + New versions of the driver will be announced on the linux-hams + mailing list on vger.rutgers.edu. To subscribe send an e-mail + to majordomo@vger.rutgers.edu with the following line in + the body of the mail: + + subscribe linux-hams + + The content of the "Subject" field will be ignored. + + vy 73, + Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org + AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU + Internet: jreuter@poboxes.com + www : http://www.rat.de/jr +*/ + +/* ----------------------------------------------------------------------- */ + +#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 */ +#define MAXQUEUE 8 /* number of buffers we queue ourself */ +#undef DISABLE_ALL_INTS /* use cli()/sti() in ISR instead of */ + /* enable_irq()/disable_irq() */ +#undef SCC_DEBUG + +#define DEFAULT_CLOCK 4915200 /* default pclock if nothing is specified */ + +/* ----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "z8530.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#endif + +int scc_init(void); + +static void t_dwait(unsigned long); +static void t_txdelay(unsigned long); +static void t_tail(unsigned long); +static void t_busy(unsigned long); +static void t_maxkeyup(unsigned long); +static void t_idle(unsigned long); +static void scc_tx_done(struct scc_channel *); +static void scc_start_tx_timer(struct scc_channel *, void (*)(unsigned long), unsigned long); +static void scc_start_maxkeyup(struct scc_channel *); +static void scc_start_defer(struct scc_channel *); + +static void z8530_init(void); + +static void init_channel(struct scc_channel *scc); +static void scc_key_trx (struct scc_channel *scc, char tx); +static void scc_isr(int irq, void *dev_id, struct pt_regs *regs); +static void scc_init_timer(struct scc_channel *scc); + +static int scc_net_setup(struct scc_channel *scc, unsigned char *name); +static int scc_net_init(struct device *dev); +static int scc_net_open(struct device *dev); +static int scc_net_close(struct device *dev); +static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb); +static int scc_net_tx(struct sk_buff *skb, struct device *dev); +static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd); +static int scc_net_set_mac_address(struct device *dev, void *addr); +static int scc_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); +static struct net_device_stats * scc_net_get_stats(struct device *dev); + +static unsigned char *SCC_DriverName = "scc"; + +static struct irqflags { unsigned char used : 1; } Ivec[16]; + +static struct scc_channel SCC_Info[2 * MAXSCC]; /* information per channel */ + +static struct scc_ctrl { + io_port chan_A; + io_port chan_B; + int irq; +} SCC_ctrl[MAXSCC+1]; + +static unsigned char Driver_Initialized = 0; +static int Nchips = 0; +static io_port Vector_Latch = 0; + +MODULE_AUTHOR("Joerg Reuter "); +MODULE_DESCRIPTION("Network Device Driver for Z8530 based HDLC cards for Amateur Packet Radio"); +MODULE_SUPPORTED_DEVICE("scc"); + +/* ******************************************************************** */ +/* * Port Access Functions * */ +/* ******************************************************************** */ + +/* These provide interrupt save 2-step access to the Z8530 registers */ + +extern __inline__ unsigned char InReg(io_port port, unsigned char reg) +{ + unsigned long flags; + unsigned char r; + + save_flags(flags); + cli(); +#ifdef SCC_LDELAY + Outb(port, reg); + udelay(SCC_LDELAY); + r=Inb(port); + udelay(SCC_LDELAY); +#else + Outb(port, reg); + r=Inb(port); +#endif + restore_flags(flags); + return r; +} + +extern __inline__ void OutReg(io_port port, unsigned char reg, unsigned char val) +{ + unsigned long flags; + + save_flags(flags); + cli(); +#ifdef SCC_LDELAY + Outb(port, reg); udelay(SCC_LDELAY); + Outb(port, val); udelay(SCC_LDELAY); +#else + Outb(port, reg); + Outb(port, val); +#endif + restore_flags(flags); +} + +extern __inline__ void wr(struct scc_channel *scc, unsigned char reg, + unsigned char val) +{ + OutReg(scc->ctrl, reg, (scc->wreg[reg] = val)); +} + +extern __inline__ void or(struct scc_channel *scc, unsigned char reg, unsigned char val) +{ + OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val)); +} + +extern __inline__ void cl(struct scc_channel *scc, unsigned char reg, unsigned char val) +{ + OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val)); +} + +#ifdef DISABLE_ALL_INTS +extern __inline__ void scc_cli(int irq) +{ cli(); } +extern __inline__ void scc_sti(int irq) +{ sti(); } +#else +static __inline__ void scc_cli(int irq) +{ disable_irq(irq); } +static __inline__ void scc_sti(int irq) +{ enable_irq(irq); } +#endif + +/* ******************************************************************** */ +/* * Some useful macros * */ +/* ******************************************************************** */ + + +extern __inline__ void scc_lock_dev(struct scc_channel *scc) +{ + scc->dev->tbusy = 1; +} + +extern __inline__ void scc_unlock_dev(struct scc_channel *scc) +{ + scc->dev->tbusy = 0; +} + +extern __inline__ void scc_discard_buffers(struct scc_channel *scc) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + if (scc->tx_buff != NULL) + { + dev_kfree_skb(scc->tx_buff, FREE_WRITE); + scc->tx_buff = NULL; + } + + while (skb_queue_len(&scc->tx_queue)) + dev_kfree_skb(skb_dequeue(&scc->tx_queue), FREE_WRITE); + + restore_flags(flags); +} + + + +/* ******************************************************************** */ +/* * Interrupt Service Routines * */ +/* ******************************************************************** */ + + +/* ----> subroutines for the interrupt handlers <---- */ + +extern __inline__ void scc_notify(struct scc_channel *scc, int event) +{ + struct sk_buff *skb; + char *bp; + + if (scc->kiss.fulldup != KISS_DUPLEX_OPTIMA) + return; + + skb = dev_alloc_skb(2); + if (skb != NULL) + { + bp = skb_put(skb, 2); + *bp++ = PARAM_HWEVENT; + *bp++ = event; + scc_net_rx(scc, skb); + } else + scc->stat.nospace++; +} + +extern __inline__ void flush_rx_FIFO(struct scc_channel *scc) +{ + int k; + + for (k=0; k<3; k++) + Inb(scc->data); + + if(scc->rx_buff != NULL) /* did we receive something? */ + { + scc->stat.rxerrs++; /* then count it as an error */ + kfree_skb(scc->rx_buff, FREE_READ); + scc->rx_buff = NULL; + } +} + + +/* ----> four different interrupt handlers for Tx, Rx, changing of */ +/* DCD/CTS and Rx/Tx errors */ + +/* Transmitter interrupt handler */ +extern __inline__ void scc_txint(struct scc_channel *scc) +{ + struct sk_buff *skb; + + scc->stat.txints++; + skb = scc->tx_buff; + + /* send first octet */ + + if (skb == NULL) + { + skb = skb_dequeue(&scc->tx_queue); + scc->tx_buff = skb; + scc_unlock_dev(scc); + + if (skb == NULL) + { + scc_tx_done(scc); + Outb(scc->ctrl, RES_Tx_P); + return; + } + + if (skb->len == 0) /* Paranoia... */ + { + dev_kfree_skb(skb, FREE_WRITE); + scc->tx_buff = NULL; + scc_tx_done(scc); + Outb(scc->ctrl, RES_Tx_P); + return; + } + + scc->stat.tx_state = TXS_ACTIVE; + + OutReg(scc->ctrl, R0, RES_Tx_CRC); + /* reset CRC generator */ + or(scc,R10,ABUNDER); /* re-install underrun protection */ + Outb(scc->data,*skb->data); /* send byte */ + skb_pull(skb, 1); + + if (!scc->enhanced) /* reset EOM latch */ + Outb(scc->ctrl,RES_EOM_L); + return; + } + + /* End Of Frame... */ + + if (skb->len == 0) + { + Outb(scc->ctrl, RES_Tx_P); /* reset pending int */ + cl(scc, R10, ABUNDER); /* send CRC */ + dev_kfree_skb(skb, FREE_WRITE); + scc->tx_buff = NULL; + scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */ + return; + } + + /* send octet */ + + Outb(scc->data,*skb->data); + skb_pull(skb, 1); +} + + +/* External/Status interrupt handler */ +extern __inline__ void scc_exint(struct scc_channel *scc) +{ + unsigned char status,changes,chg_and_stat; + + scc->stat.exints++; + + status = InReg(scc->ctrl,R0); + changes = status ^ scc->status; + chg_and_stat = changes & status; + + /* ABORT: generated whenever DCD drops while receiving */ + + if (chg_and_stat & BRK_ABRT) /* Received an ABORT */ + flush_rx_FIFO(scc); + + + /* DCD: on = start to receive packet, off = ABORT condition */ + /* (a successfully received packet generates a special condition int) */ + + if(changes & DCD) /* DCD input changed state */ + { + if(status & DCD) /* DCD is now ON */ + { + if (scc->modem.clocksrc != CLK_EXTERNAL) + OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */ + + or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */ + } else { /* DCD is now OFF */ + cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */ + flush_rx_FIFO(scc); + } + + if (!scc->kiss.softdcd) + scc_notify(scc, (status & DCD)? HWEV_DCD_ON:HWEV_DCD_OFF); + } + + /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */ + + if (changes & SYNC_HUNT) + { + if (scc->kiss.softdcd) + scc_notify(scc, (status & SYNC_HUNT)? HWEV_DCD_OFF:HWEV_DCD_ON); + else + cl(scc,R15,SYNCIE); /* oops, we were too lazy to disable this? */ + } + +#ifdef notdef + /* CTS: use external TxDelay (what's that good for?!) + * Anyway: If we _could_ use it (BayCom USCC uses CTS for + * own purposes) we _should_ use the "autoenable" feature + * of the Z8530 and not this interrupt... + */ + + if (chg_and_stat & CTS) /* CTS is now ON */ + { + if (scc->kiss.txdelay == 0) /* zero TXDELAY = wait for CTS */ + scc_start_tx_timer(scc, t_txdelay, 0); + } +#endif + + if (scc->stat.tx_state == TXS_ACTIVE && (status & TxEOM)) + { + scc->stat.tx_under++; /* oops, an underrun! count 'em */ + Outb(scc->ctrl, RES_EXT_INT); /* reset ext/status interrupts */ + + if (scc->tx_buff != NULL) + { + dev_kfree_skb(scc->tx_buff, FREE_WRITE); + scc->tx_buff = NULL; + } + + or(scc,R10,ABUNDER); + scc_start_tx_timer(scc, t_txdelay, 0); /* restart transmission */ + } + + scc->status = status; + Outb(scc->ctrl,RES_EXT_INT); +} + + +/* Receiver interrupt handler */ +extern __inline__ void scc_rxint(struct scc_channel *scc) +{ + struct sk_buff *skb; + + scc->stat.rxints++; + + if((scc->wreg[5] & RTS) && scc->kiss.fulldup == KISS_DUPLEX_HALF) + { + Inb(scc->data); /* discard char */ + or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ + return; + } + + skb = scc->rx_buff; + + if (skb == NULL) + { + skb = dev_alloc_skb(scc->stat.bufsize); + if (skb == NULL) + { + scc->dev_stat.rx_dropped++; + scc->stat.nospace++; + Inb(scc->data); + or(scc, R3, ENT_HM); + return; + } + + scc->rx_buff = skb; + *(skb_put(skb, 1)) = 0; /* KISS data */ + } + + if (skb->len >= scc->stat.bufsize) + { +#ifdef notdef + printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n"); +#endif + kfree_skb(skb, FREE_READ); + scc->rx_buff = NULL; + Inb(scc->data); + or(scc, R3, ENT_HM); + return; + } + + *(skb_put(skb, 1)) = Inb(scc->data); +} + + +/* Receive Special Condition interrupt handler */ +extern __inline__ void scc_spint(struct scc_channel *scc) +{ + unsigned char status; + struct sk_buff *skb; + + scc->stat.spints++; + + status = InReg(scc->ctrl,R1); /* read receiver status */ + + Inb(scc->data); /* throw away Rx byte */ + skb = scc->rx_buff; + + if(status & Rx_OVR) /* receiver overrun */ + { + scc->stat.rx_over++; /* count them */ + or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ + + if (skb != NULL) + kfree_skb(skb, FREE_READ); + scc->rx_buff = NULL; + } + + if(status & END_FR && skb != NULL) /* end of frame */ + { + /* CRC okay, frame ends on 8 bit boundary and received something ? */ + + if (!(status & CRC_ERR) && (status & 0xe) == RES8 && skb->len > 0) + { + /* ignore last received byte (first of the CRC bytes) */ + skb_trim(skb, skb->len-1); + scc_net_rx(scc, skb); + scc->rx_buff = NULL; + scc->stat.rxframes++; + } else { /* a bad frame */ + kfree_skb(skb, FREE_READ); + scc->rx_buff = NULL; + scc->stat.rxerrs++; + } + } + + Outb(scc->ctrl,ERR_RES); +} + + +/* ----> interrupt service routine for the Z8530 <---- */ + +static void scc_isr_dispatch(struct scc_channel *scc, int vector) +{ + switch (vector & VECTOR_MASK) + { + case TXINT: scc_txint(scc); break; + case EXINT: scc_exint(scc); break; + case RXINT: scc_rxint(scc); break; + case SPINT: scc_spint(scc); break; + } +} + +/* If the card has a latch for the interrupt vector (like the PA0HZP card) + use it to get the number of the chip that generated the int. + If not: poll all defined chips. + */ + +#define SCC_IRQTIMEOUT 30000 + +static void scc_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned char vector; + struct scc_channel *scc; + struct scc_ctrl *ctrl; + int k; + + scc_cli(irq); + + if (Vector_Latch) + { + for(k=0; k < SCC_IRQTIMEOUT; k++) + { + Outb(Vector_Latch, 0); /* Generate INTACK */ + + /* Read the vector */ + if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break; + if (vector & 0x01) break; + + scc=&SCC_Info[vector >> 3 ^ 0x01]; + if (!scc->dev) break; + + scc_isr_dispatch(scc, vector); + + OutReg(scc->ctrl,R0,RES_H_IUS); /* Reset Highest IUS */ + } + scc_sti(irq); + + if (k == SCC_IRQTIMEOUT) + printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n"); + + return; + } + + /* Find the SCC generating the interrupt by polling all attached SCCs + * reading RR3A (the interrupt pending register) + */ + + ctrl = SCC_ctrl; + while (ctrl->chan_A) + { + if (ctrl->irq != irq) + { + ctrl++; + continue; + } + + scc = NULL; + for (k = 0; InReg(ctrl->chan_A,R3) && k < SCC_IRQTIMEOUT; k++) + { + vector=InReg(ctrl->chan_B,R2); /* Read the vector */ + if (vector & 0x01) break; + + scc = &SCC_Info[vector >> 3 ^ 0x01]; + if (!scc->dev) break; + + scc_isr_dispatch(scc, vector); + } + + if (k == SCC_IRQTIMEOUT) + { + printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?!\n"); + break; + } + + /* This looks wierd and it is. At least the BayCom USCC doesn't + * use the Interrupt Daisy Chain, thus we'll have to start + * all over again to be sure not to miss an interrupt from + * (any of) the other chip(s)... + * Honestly, the situation *is* braindamaged... + */ + + if (scc != NULL) + { + OutReg(scc->ctrl,R0,RES_H_IUS); + ctrl = SCC_ctrl; + } else + ctrl++; + } + + scc_sti(irq); +} + + + +/* ******************************************************************** */ +/* * Init Channel */ +/* ******************************************************************** */ + + +/* ----> set SCC channel speed <---- */ + +extern __inline__ void set_brg(struct scc_channel *scc, unsigned int tc) +{ + cl(scc,R14,BRENABL); /* disable baudrate generator */ + wr(scc,R12,tc & 255); /* brg rate LOW */ + wr(scc,R13,tc >> 8); /* brg rate HIGH */ + or(scc,R14,BRENABL); /* enable baudrate generator */ +} + +extern __inline__ void set_speed(struct scc_channel *scc) +{ + disable_irq(scc->irq); + + if (scc->modem.speed > 0) /* paranoia... */ + set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2); + + enable_irq(scc->irq); +} + + +/* ----> initialize a SCC channel <---- */ + +extern __inline__ void init_brg(struct scc_channel *scc) +{ + wr(scc, R14, BRSRC); /* BRG source = PCLK */ + OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */ + OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */ +} + +/* + * Initialization according to the Z8530 manual (SGS-Thomson's version): + * + * 1. Modes and constants + * + * WR9 11000000 chip reset + * WR4 XXXXXXXX Tx/Rx control, async or sync mode + * WR1 0XX00X00 select W/REQ (optional) + * WR2 XXXXXXXX program interrupt vector + * WR3 XXXXXXX0 select Rx control + * WR5 XXXX0XXX select Tx control + * WR6 XXXXXXXX sync character + * WR7 XXXXXXXX sync character + * WR9 000X0XXX select interrupt control + * WR10 XXXXXXXX miscellaneous control (optional) + * WR11 XXXXXXXX clock control + * WR12 XXXXXXXX time constant lower byte (optional) + * WR13 XXXXXXXX time constant upper byte (optional) + * WR14 XXXXXXX0 miscellaneous control + * WR14 XXXSSSSS commands (optional) + * + * 2. Enables + * + * WR14 000SSSS1 baud rate enable + * WR3 SSSSSSS1 Rx enable + * WR5 SSSS1SSS Tx enable + * WR0 10000000 reset Tx CRG (optional) + * WR1 XSS00S00 DMA enable (optional) + * + * 3. Interrupt status + * + * WR15 XXXXXXXX enable external/status + * WR0 00010000 reset external status + * WR0 00010000 reset external status twice + * WR1 SSSXXSXX enable Rx, Tx and Ext/status + * WR9 000SXSSS enable master interrupt enable + * + * 1 = set to one, 0 = reset to zero + * X = user defined, S = same as previous init + * + * + * Note that the implementation differs in some points from above scheme. + * + */ + +static void init_channel(struct scc_channel *scc) +{ + del_timer(&scc->tx_t); + del_timer(&scc->tx_wdog); + + disable_irq(scc->irq); + + wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */ + wr(scc,R1,0); /* no W/REQ operation */ + wr(scc,R3,Rx8|RxCRC_ENAB); /* RX 8 bits/char, CRC, disabled */ + wr(scc,R5,Tx8|DTR|TxCRC_ENAB); /* TX 8 bits/char, disabled, DTR */ + wr(scc,R6,0); /* SDLC address zero (not used) */ + wr(scc,R7,FLAG); /* SDLC flag value */ + wr(scc,R9,VIS); /* vector includes status */ + wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */ + wr(scc,R14, 0); + + +/* set clock sources: + + CLK_DPLL: normal halfduplex operation + + RxClk: use DPLL + TxClk: use DPLL + TRxC mode DPLL output + + CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem) + + BayCom: others: + + TxClk = pin RTxC TxClk = pin TRxC + RxClk = pin TRxC RxClk = pin RTxC + + + CLK_DIVIDER: + RxClk = use DPLL + TxClk = pin RTxC + + BayCom: others: + pin TRxC = DPLL pin TRxC = BRG + (RxClk * 1) (RxClk * 32) +*/ + + + switch(scc->modem.clocksrc) + { + case CLK_DPLL: + wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP); + init_brg(scc); + break; + + case CLK_DIVIDER: + wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI); + init_brg(scc); + break; + + case CLK_EXTERNAL: + wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP); + OutReg(scc->ctrl, R14, DISDPLL); + break; + + } + + set_speed(scc); /* set baudrate */ + + if(scc->enhanced) + { + or(scc,R15,SHDLCE|FIFOE); /* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */ + wr(scc,R7,AUTOEOM); + } + + if((InReg(scc->ctrl,R0)) & DCD) /* DCD is now ON */ + { + if (scc->modem.clocksrc != CLK_EXTERNAL) + or(scc,R14, SEARCH); + + or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */ + } + + /* enable ABORT, DCD & SYNC/HUNT interrupts */ + + wr(scc,R15, BRKIE|TxUIE|DCDIE); + if (scc->kiss.softdcd) + or(scc,R15, SYNCIE); + + Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ + Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */ + + or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */ + + scc->status = InReg(scc->ctrl,R0); /* read initial status */ + + or(scc,R9,MIE); /* master interrupt enable */ + + scc_init_timer(scc); + + enable_irq(scc->irq); +} + + + + +/* ******************************************************************** */ +/* * SCC timer functions * */ +/* ******************************************************************** */ + + +/* ----> scc_key_trx sets the time constant for the baudrate + generator and keys the transmitter <---- */ + +static void scc_key_trx(struct scc_channel *scc, char tx) +{ + unsigned int time_const; + + if (scc->brand & PRIMUS) + Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0)); + + if (scc->modem.speed < 300) + scc->modem.speed = 1200; + + time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2; + + disable_irq(scc->irq); + + if (tx) + { + or(scc, R1, TxINT_ENAB); /* t_maxkeyup may have reset these */ + or(scc, R15, TxUIE); + } + + if (scc->modem.clocksrc == CLK_DPLL) + { /* 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 */ + wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR); + + or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */ + } else { + cl(scc,R5,RTS|TxENAB); + + set_brg(scc, time_const); /* reprogram baudrate generator */ + + /* 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 + } + } + + enable_irq(scc->irq); +} + + +/* ----> SCC timer interrupt handler and friends. <---- */ + +static void scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when) +{ + unsigned long flags; + + + save_flags(flags); + cli(); + + del_timer(&scc->tx_t); + + if (when == 0) + { + handler((unsigned long) scc); + } else + if (when != TIMER_OFF) + { + scc->tx_t.data = (unsigned long) scc; + scc->tx_t.function = handler; + scc->tx_t.expires = jiffies + (when*HZ)/100; + add_timer(&scc->tx_t); + } + + restore_flags(flags); +} + +static void scc_start_defer(struct scc_channel *scc) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + del_timer(&scc->tx_wdog); + + if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF) + { + scc->tx_wdog.data = (unsigned long) scc; + scc->tx_wdog.function = t_busy; + scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer; + add_timer(&scc->tx_wdog); + } + restore_flags(flags); +} + +static void scc_start_maxkeyup(struct scc_channel *scc) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + del_timer(&scc->tx_wdog); + + if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF) + { + scc->tx_wdog.data = (unsigned long) scc; + scc->tx_wdog.function = t_maxkeyup; + scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup; + add_timer(&scc->tx_wdog); + } + + restore_flags(flags); +} + +/* + * This is called from scc_txint() when there are no more frames to send. + * Not exactly a timer function, but it is a close friend of the family... + */ + +static void scc_tx_done(struct scc_channel *scc) +{ + /* + * trx remains keyed in fulldup mode 2 until t_idle expires. + */ + + switch (scc->kiss.fulldup) + { + case KISS_DUPLEX_LINK: + scc->stat.tx_state = TXS_IDLE2; + if (scc->kiss.idletime != TIMER_OFF) + scc_start_tx_timer(scc, t_idle, scc->kiss.idletime*100); + break; + case KISS_DUPLEX_OPTIMA: + scc_notify(scc, HWEV_ALL_SENT); + break; + default: + scc->stat.tx_state = TXS_BUSY; + scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); + } + + scc_unlock_dev(scc); +} + + +static unsigned char Rand = 17; + +extern __inline__ int is_grouped(struct scc_channel *scc) +{ + int k; + struct scc_channel *scc2; + unsigned char grp1, grp2; + + grp1 = scc->kiss.group; + + for (k = 0; k < (Nchips * 2); k++) + { + scc2 = &SCC_Info[k]; + grp2 = scc2->kiss.group; + + if (scc2 == scc || !(scc2->dev && grp2)) + continue; + + if ((grp1 & 0x3f) == (grp2 & 0x3f)) + { + if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) ) + return 1; + + if ( (grp1 & RXGROUP) && (scc2->status & DCD) ) + return 1; + } + } + return 0; +} + +/* DWAIT and SLOTTIME expired + * + * fulldup == 0: DCD is active or Rand > P-persistence: start t_busy timer + * else key trx and start txdelay + * fulldup == 1: key trx and start txdelay + * fulldup == 2: mintime expired, reset status or key trx and start txdelay + */ + +static void t_dwait(unsigned long channel) +{ + struct scc_channel *scc = (struct scc_channel *) channel; + + if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */ + { + if (skb_queue_len(&scc->tx_queue) == 0) /* nothing to send */ + { + scc->stat.tx_state = TXS_IDLE; + scc_unlock_dev(scc); /* t_maxkeyup locked it. */ + return; + } + + scc->stat.tx_state = TXS_BUSY; + } + + if (scc->kiss.fulldup == KISS_DUPLEX_HALF) + { + Rand = Rand * 17 + 31; + + if ( (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD)) || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) ) + { + scc_start_defer(scc); + scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime); + return ; + } + } + + if ( !(scc->wreg[R5] & RTS) ) + { + scc_key_trx(scc, TX_ON); + scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); + } else { + scc_start_tx_timer(scc, t_txdelay, 0); + } +} + + +/* TXDELAY expired + * + * kick transmission by a fake scc_txint(scc), start 'maxkeyup' watchdog. + */ + +static void t_txdelay(unsigned long channel) +{ + struct scc_channel *scc = (struct scc_channel *) channel; + + scc_start_maxkeyup(scc); + + if (scc->tx_buff == NULL) + { + disable_irq(scc->irq); + scc_txint(scc); + enable_irq(scc->irq); + } +} + + +/* TAILTIME expired + * + * switch off transmitter. If we were stopped by Maxkeyup restart + * transmission after 'mintime' seconds + */ + +static void t_tail(unsigned long channel) +{ + struct scc_channel *scc = (struct scc_channel *) channel; + unsigned long flags; + + save_flags(flags); + cli(); + + del_timer(&scc->tx_wdog); + scc_key_trx(scc, TX_OFF); + + restore_flags(flags); + + if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */ + { + scc->stat.tx_state = TXS_WAIT; + + if (scc->kiss.mintime != TIMER_OFF) /* try it again */ + scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); + else + scc_start_tx_timer(scc, t_dwait, 0); + return; + } + + scc->stat.tx_state = TXS_IDLE; + scc_unlock_dev(scc); +} + + +/* BUSY timeout + * + * throw away send buffers if DCD remains active too long. + */ + +static void t_busy(unsigned long channel) +{ + struct scc_channel *scc = (struct scc_channel *) channel; + + del_timer(&scc->tx_t); + scc_lock_dev(scc); + + scc_discard_buffers(scc); + + scc->stat.txerrs++; + scc->stat.tx_state = TXS_IDLE; + + scc_unlock_dev(scc); +} + +/* MAXKEYUP timeout + * + * this is our watchdog. + */ + +static void t_maxkeyup(unsigned long channel) +{ + struct scc_channel *scc = (struct scc_channel *) channel; + unsigned long flags; + + save_flags(flags); + cli(); + + /* + * let things settle down before we start to + * accept new data. + */ + + scc_lock_dev(scc); + scc_discard_buffers(scc); + + del_timer(&scc->tx_t); + + cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */ + cl(scc, R15, TxUIE); /* count it. */ + OutReg(scc->ctrl, R0, RES_Tx_P); + + restore_flags(flags); + + scc->stat.txerrs++; + scc->stat.tx_state = TXS_TIMEOUT; + scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); +} + +/* IDLE timeout + * + * in fulldup mode 2 it keys down the transmitter after 'idle' seconds + * of inactivity. We will not restart transmission before 'mintime' + * expires. + */ + +static void t_idle(unsigned long channel) +{ + struct scc_channel *scc = (struct scc_channel *) channel; + + del_timer(&scc->tx_wdog); + + scc_key_trx(scc, TX_OFF); + + if (scc->kiss.mintime != TIMER_OFF) + scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); + scc->stat.tx_state = TXS_WAIT; +} + +static void scc_init_timer(struct scc_channel *scc) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + scc->stat.tx_state = TXS_IDLE; + + restore_flags(flags); +} + + +/* ******************************************************************** */ +/* * Set/get L1 parameters * */ +/* ******************************************************************** */ + + +/* + * this will set the "hardware" parameters through KISS commands or ioctl() + */ + +#define CAST(x) (unsigned long)(x) + +static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg) +{ + int dcd; + + switch (cmd) + { + case PARAM_TXDELAY: scc->kiss.txdelay=arg; break; + case PARAM_PERSIST: scc->kiss.persist=arg; break; + case PARAM_SLOTTIME: scc->kiss.slottime=arg; break; + case PARAM_TXTAIL: scc->kiss.tailtime=arg; break; + case PARAM_FULLDUP: scc->kiss.fulldup=arg; break; + case PARAM_DTR: break; /* does someone need this? */ + case PARAM_GROUP: scc->kiss.group=arg; break; + case PARAM_IDLE: scc->kiss.idletime=arg; break; + case PARAM_MIN: scc->kiss.mintime=arg; break; + case PARAM_MAXKEY: scc->kiss.maxkeyup=arg; break; + case PARAM_WAIT: scc->kiss.waittime=arg; break; + case PARAM_MAXDEFER: scc->kiss.maxdefer=arg; break; + case PARAM_TX: scc->kiss.tx_inhibit=arg; break; + + case PARAM_SOFTDCD: + scc->kiss.softdcd=arg; + if (arg) + or(scc, R15, SYNCIE); + else + cl(scc, R15, SYNCIE); + break; + + case PARAM_SPEED: + if (arg < 256) + scc->modem.speed=arg*100; + else + scc->modem.speed=arg; + + if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */ + set_speed(scc); + break; + + case PARAM_RTS: + if ( !(scc->wreg[R5] & RTS) ) + { + if (arg != TX_OFF) + scc_key_trx(scc, TX_ON); + scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); + } else { + if (arg == TX_OFF) + { + scc->stat.tx_state = TXS_BUSY; + scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); + } + } + break; + + case PARAM_HWEVENT: + dcd = (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD)); + scc_notify(scc, dcd? HWEV_DCD_ON:HWEV_DCD_OFF); + break; + + default: return -EINVAL; + } + + return 0; +} + + + +static unsigned long scc_get_param(struct scc_channel *scc, unsigned int cmd) +{ + switch (cmd) + { + case PARAM_TXDELAY: return CAST(scc->kiss.txdelay); + case PARAM_PERSIST: return CAST(scc->kiss.persist); + case PARAM_SLOTTIME: return CAST(scc->kiss.slottime); + case PARAM_TXTAIL: return CAST(scc->kiss.tailtime); + case PARAM_FULLDUP: return CAST(scc->kiss.fulldup); + case PARAM_SOFTDCD: return CAST(scc->kiss.softdcd); + case PARAM_DTR: return CAST((scc->wreg[R5] & DTR)? 1:0); + case PARAM_RTS: return CAST((scc->wreg[R5] & RTS)? 1:0); + case PARAM_SPEED: return CAST(scc->modem.speed); + case PARAM_GROUP: return CAST(scc->kiss.group); + case PARAM_IDLE: return CAST(scc->kiss.idletime); + case PARAM_MIN: return CAST(scc->kiss.mintime); + case PARAM_MAXKEY: return CAST(scc->kiss.maxkeyup); + case PARAM_WAIT: return CAST(scc->kiss.waittime); + case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer); + case PARAM_TX: return CAST(scc->kiss.tx_inhibit); + default: return NO_SUCH_PARAM; + } + +} + +#undef CAST +#undef SVAL + +/* ******************************************************************* */ +/* * Send calibration pattern * */ +/* ******************************************************************* */ + +static void scc_stop_calibrate(unsigned long channel) +{ + struct scc_channel *scc = (struct scc_channel *) channel; + unsigned long flags; + + save_flags(flags); + cli(); + + del_timer(&scc->tx_wdog); + scc_key_trx(scc, TX_OFF); + wr(scc, R6, 0); + wr(scc, R7, FLAG); + Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ + Outb(scc->ctrl,RES_EXT_INT); + + scc_unlock_dev(scc); + + restore_flags(flags); +} + + +static void +scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + scc_lock_dev(scc); + scc_discard_buffers(scc); + + del_timer(&scc->tx_wdog); + + scc->tx_wdog.data = (unsigned long) scc; + scc->tx_wdog.function = scc_stop_calibrate; + scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup; + add_timer(&scc->tx_wdog); + + wr(scc, R6, 0); + wr(scc, R7, pattern); + + /* + * Don't know if this works. + * Damn, where is my Z8530 programming manual...? + */ + + Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ + Outb(scc->ctrl,RES_EXT_INT); + + scc_key_trx(scc, TX_ON); + + restore_flags(flags); +} + +/* ******************************************************************* */ +/* * Init channel structures, special HW, etc... * */ +/* ******************************************************************* */ + +/* + * Reset the Z8530s and setup special hardware + */ + +static void z8530_init(void) +{ + struct scc_channel *scc; + int chip, k; + unsigned long flags; + char *flag; + + + printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2); + + flag=" "; + for (k = 0; k < 16; k++) + if (Ivec[k].used) + { + printk("%s%d", flag, k); + flag=","; + } + printk("\n"); + + + /* reset and pre-init all chips in the system */ + for (chip = 0; chip < Nchips; chip++) + { + scc=&SCC_Info[2*chip]; + if (!scc->ctrl) continue; + + /* Special SCC cards */ + + if(scc->brand & EAGLE) /* this is an EAGLE card */ + Outb(scc->special,0x08); /* enable interrupt on the board */ + + if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/PRIMUS card */ + Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */ + + + /* Reset and pre-init Z8530 */ + + save_flags(flags); + cli(); + + Outb(scc->ctrl, 0); + OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */ + udelay(100); /* give it 'a bit' more time than required */ + wr(scc, R2, chip*16); /* interrupt vector */ + wr(scc, R9, VIS); /* vector includes status */ + + restore_flags(flags); + } + + + Driver_Initialized = 1; +} + +/* + * Allocate device structure, err, instance, and register driver + */ + +static int scc_net_setup(struct scc_channel *scc, unsigned char *name) +{ + unsigned char *buf; + struct device *dev; + + if (dev_get(name) != NULL) + { + printk(KERN_INFO "Z8530drv: device %s already exists.\n", name); + return -EEXIST; + } + + if ((scc->dev = (struct device *) kmalloc(sizeof(struct device), GFP_KERNEL)) == NULL) + return -ENOMEM; + + dev = scc->dev; + memset(dev, 0, sizeof(struct device)); + + buf = (unsigned char *) kmalloc(10, GFP_KERNEL); + strcpy(buf, name); + + dev->priv = (void *) scc; + dev->name = buf; + dev->init = scc_net_init; + + if (register_netdev(dev) != 0) + { + kfree(dev); + return -EIO; + } + + return 0; +} + + + +/* ******************************************************************** */ +/* * Network driver methods * */ +/* ******************************************************************** */ + +static unsigned char ax25_bcast[AX25_ADDR_LEN] = +{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; +static unsigned char ax25_nocall[AX25_ADDR_LEN] = +{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; + +/* ----> Initialize device <----- */ + +static int scc_net_init(struct device *dev) +{ + dev_init_buffers(dev); + + dev->tx_queue_len = 16; /* should be enough... */ + + dev->open = scc_net_open; + dev->stop = scc_net_close; + + dev->hard_start_xmit = scc_net_tx; + dev->hard_header = scc_net_header; + dev->rebuild_header = ax25_rebuild_header; + dev->set_mac_address = scc_net_set_mac_address; + dev->get_stats = scc_net_get_stats; + dev->do_ioctl = scc_net_ioctl; + + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); + + dev->flags = 0; + + dev->type = ARPHRD_AX25; + dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; + dev->mtu = AX25_DEF_PACLEN; + dev->addr_len = AX25_ADDR_LEN; + + return 0; +} + +/* ----> open network device <---- */ + +static int scc_net_open(struct device *dev) +{ + struct scc_channel *scc = (struct scc_channel *) dev->priv; + + if (scc == NULL || scc->magic != SCC_MAGIC) + return -ENODEV; + + if (!scc->init) + return -EINVAL; + + MOD_INC_USE_COUNT; + + scc->tx_buff = NULL; + skb_queue_head_init(&scc->tx_queue); + + init_channel(scc); + + dev->tbusy = 0; + dev->start = 1; + + return 0; +} + +/* ----> close network device <---- */ + +static int scc_net_close(struct device *dev) +{ + struct scc_channel *scc = (struct scc_channel *) dev->priv; + unsigned long flags; + + if (scc == NULL || scc->magic != SCC_MAGIC) + return -ENODEV; + + MOD_DEC_USE_COUNT; + + save_flags(flags); + cli(); + + Outb(scc->ctrl,0); /* Make sure pointer is written */ + wr(scc,R1,0); /* disable interrupts */ + wr(scc,R3,0); + + del_timer(&scc->tx_t); + del_timer(&scc->tx_wdog); + + restore_flags(flags); + + scc_discard_buffers(scc); + + dev->tbusy = 1; + dev->start = 0; + + return 0; +} + +/* ----> receive frame, called from scc_rxint() <---- */ + +static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) +{ + if (skb->len == 0) + { + kfree_skb(skb, FREE_READ); + return; + } + + scc->dev_stat.rx_packets++; + + skb->dev = scc->dev; + skb->protocol = htons(ETH_P_AX25); + skb->mac.raw = skb->data; + + netif_rx(skb); + return; +} + +/* ----> transmit frame <---- */ + +static int scc_net_tx(struct sk_buff *skb, struct device *dev) +{ + struct scc_channel *scc = (struct scc_channel *) dev->priv; + unsigned long flags; + char kisscmd; + + if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy) + { + dev_kfree_skb(skb, FREE_WRITE); + return 0; + } + + if (skb->len > scc->stat.bufsize || skb->len < 2) + { + scc->dev_stat.tx_dropped++; /* bogus frame */ + dev_kfree_skb(skb, FREE_WRITE); + return 0; + } + + scc->dev_stat.tx_packets++; + scc->stat.txframes++; + + kisscmd = *skb->data & 0x1f; + skb_pull(skb, 1); + + if (kisscmd) + { + scc_set_param(scc, kisscmd, *skb->data); + dev_kfree_skb(skb, FREE_WRITE); + return 0; + } + + save_flags(flags); + cli(); + + if (skb_queue_len(&scc->tx_queue) >= MAXQUEUE-1) + { + struct sk_buff *skb_del; + skb_del = __skb_dequeue(&scc->tx_queue); + dev_kfree_skb(skb_del, FREE_WRITE); + } + __skb_queue_tail(&scc->tx_queue, skb); + + dev->trans_start = jiffies; + + /* + * Start transmission if the trx state is idle or + * t_idle hasn't expired yet. Use dwait/persistance/slottime + * algorithm for normal halfduplex operation. + */ + + if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) + { + scc->stat.tx_state = TXS_BUSY; + if (scc->kiss.fulldup == KISS_DUPLEX_HALF) + scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime); + else + scc_start_tx_timer(scc, t_dwait, 0); + } + + restore_flags(flags); + + return 0; +} + +/* ----> ioctl functions <---- */ + +/* + * SIOCSCCCFG - configure driver arg: (struct scc_hw_config *) arg + * SIOCSCCINI - initialize driver arg: --- + * SIOCSCCCHANINI - initialize channel arg: (struct scc_modem *) arg + * SIOCSCCSMEM - set memory arg: (struct scc_mem_config *) arg + * SIOCSCCGKISS - get level 1 parameter arg: (struct scc_kiss_cmd *) arg + * SIOCSCCSKISS - set level 1 parameter arg: (struct scc_kiss_cmd *) arg + * SIOCSCCGSTAT - get driver status arg: (struct scc_stat *) arg + * SIOCSCCCAL - send calib. pattern arg: (struct scc_calibrate *) arg + */ + +static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + struct scc_kiss_cmd kiss_cmd; + struct scc_mem_config memcfg; + struct scc_hw_config hwcfg; + struct scc_calibrate cal; + int chan; + unsigned char device_name[10]; + void *arg; + struct scc_channel *scc; + + scc = (struct scc_channel *) dev->priv; + if (scc == NULL || scc->magic != SCC_MAGIC) + return -EINVAL; + + arg = (void *) ifr->ifr_data; + + if (!Driver_Initialized) + { + if (cmd == SIOCSCCCFG) + { + int found = 1; + + if (!suser()) return -EPERM; + if (!arg) return -EFAULT; + + if (Nchips >= MAXSCC) + return -EINVAL; + + if (copy_from_user(&hwcfg, arg, sizeof(hwcfg))) + return -EFAULT; + + if (hwcfg.irq == 2) hwcfg.irq = 9; + + if (!Ivec[hwcfg.irq].used && hwcfg.irq) + { + if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL)) + printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq); + else + Ivec[hwcfg.irq].used = 1; + } + + if (hwcfg.vector_latch) + Vector_Latch = hwcfg.vector_latch; + + if (hwcfg.clock == 0) + hwcfg.clock = DEFAULT_CLOCK; + +#ifndef DONT_CHECK + disable_irq(hwcfg.irq); + + check_region(scc->ctrl, 1); + Outb(hwcfg.ctrl_a, 0); + udelay(5); + OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */ + udelay(5); + + if (InReg(hwcfg.ctrl_a,R13) != 0x55) + found = 0; + + enable_irq(hwcfg.irq); +#endif + + if (found) + { + SCC_Info[2*Nchips ].ctrl = hwcfg.ctrl_a; + SCC_Info[2*Nchips ].data = hwcfg.data_a; + SCC_Info[2*Nchips ].irq = hwcfg.irq; + SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b; + SCC_Info[2*Nchips+1].data = hwcfg.data_b; + SCC_Info[2*Nchips+1].irq = hwcfg.irq; + + SCC_ctrl[Nchips].chan_A = hwcfg.ctrl_a; + SCC_ctrl[Nchips].chan_B = hwcfg.ctrl_b; + SCC_ctrl[Nchips].irq = hwcfg.irq; + } + + + for (chan = 0; chan < 2; chan++) + { + sprintf(device_name, "%s%i", SCC_DriverName, 2*Nchips+chan); + + SCC_Info[2*Nchips+chan].special = hwcfg.special; + SCC_Info[2*Nchips+chan].clock = hwcfg.clock; + SCC_Info[2*Nchips+chan].brand = hwcfg.brand; + SCC_Info[2*Nchips+chan].option = hwcfg.option; + SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc; + +#ifdef DONT_CHECK + printk(KERN_INFO "%s: data port = 0x%3.3x control port = 0x%3.3x\n", + device_name, + SCC_Info[2*Nchips+chan].data, + SCC_Info[2*Nchips+chan].ctrl); + +#else + printk(KERN_INFO "%s: data port = 0x%3.3lx control port = 0x%3.3lx -- %s\n", + device_name, + chan? hwcfg.data_b : hwcfg.data_a, + chan? hwcfg.ctrl_b : hwcfg.ctrl_a, + found? "found" : "missing"); +#endif + + if (found) + { + request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl"); + request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data"); + if (Nchips+chan != 0) + scc_net_setup(&SCC_Info[2*Nchips+chan], device_name); + } + } + + if (found) Nchips++; + + return 0; + } + + if (cmd == SIOCSCCINI) + { + if (!suser()) + return -EPERM; + + if (Nchips == 0) + return -EINVAL; + + z8530_init(); + return 0; + } + + return -EINVAL; /* confuse the user */ + } + + if (!scc->init) + { + if (cmd == SIOCSCCCHANINI) + { + if (!suser()) return -EPERM; + if (!arg) return -EINVAL; + + scc->stat.bufsize = BUFSIZE; + + if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem))) + return -EINVAL; + + /* default KISS Params */ + + if (scc->modem.speed < 4800) + { + scc->kiss.txdelay = 36; /* 360 ms */ + scc->kiss.persist = 42; /* 25% persistence */ /* was 25 */ + scc->kiss.slottime = 16; /* 160 ms */ + scc->kiss.tailtime = 4; /* minimal reasonable value */ + scc->kiss.fulldup = 0; /* CSMA */ + scc->kiss.waittime = 50; /* 500 ms */ + scc->kiss.maxkeyup = 10; /* 10 s */ + scc->kiss.mintime = 3; /* 3 s */ + scc->kiss.idletime = 30; /* 30 s */ + scc->kiss.maxdefer = 120; /* 2 min */ + scc->kiss.softdcd = 0; /* hardware dcd */ + } else { + scc->kiss.txdelay = 10; /* 100 ms */ + scc->kiss.persist = 64; /* 25% persistence */ /* was 25 */ + scc->kiss.slottime = 8; /* 160 ms */ + scc->kiss.tailtime = 1; /* minimal reasonable value */ + scc->kiss.fulldup = 0; /* CSMA */ + scc->kiss.waittime = 50; /* 500 ms */ + scc->kiss.maxkeyup = 7; /* 7 s */ + scc->kiss.mintime = 3; /* 3 s */ + scc->kiss.idletime = 30; /* 30 s */ + scc->kiss.maxdefer = 120; /* 2 min */ + scc->kiss.softdcd = 0; /* hardware dcd */ + } + + scc->tx_buff = NULL; + skb_queue_head_init(&scc->tx_queue); + scc->init = 1; + + return 0; + } + + return -EINVAL; + } + + switch(cmd) + { + case SIOCSCCRESERVED: + return -ENOIOCTLCMD; + + case SIOCSCCSMEM: + if (!suser()) return -EPERM; + if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) + return -EINVAL; + scc->stat.bufsize = memcfg.bufsize; + return 0; + + case SIOCSCCGSTAT: + if (!arg || copy_to_user(arg, &scc->stat, sizeof(scc->stat))) + return -EINVAL; + return 0; + + case SIOCSCCGKISS: + if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd))) + return -EINVAL; + kiss_cmd.param = scc_get_param(scc, kiss_cmd.command); + if (copy_to_user(arg, &kiss_cmd, sizeof(kiss_cmd))) + return -EINVAL; + return 0; + + case SIOCSCCSKISS: + if (!suser()) return -EPERM; + if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd))) + return -EINVAL; + return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param); + + case SIOCSCCCAL: + if (!suser()) return -EPERM; + if (!arg || copy_from_user(&cal, arg, sizeof(cal))) + return -EINVAL; + + scc_start_calibrate(scc, cal.time, cal.pattern); + return 0; + + default: + return -ENOIOCTLCMD; + + } + + return -EINVAL; +} + +/* ----> set interface callsign <---- */ + +static int scc_net_set_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa = (struct sockaddr *) addr; + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + return 0; +} + +/* ----> "hard" header <---- */ + +static int scc_net_header(struct sk_buff *skb, struct device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + return ax25_encapsulate(skb, dev, type, daddr, saddr, len); +} + +/* ----> get statistics <---- */ + +static struct net_device_stats *scc_net_get_stats(struct device *dev) +{ + struct scc_channel *scc = (struct scc_channel *) dev->priv; + + if (scc == NULL || scc->magic != SCC_MAGIC) + return NULL; + + scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over; + scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under; + scc->dev_stat.rx_fifo_errors = scc->stat.rx_over; + scc->dev_stat.tx_fifo_errors = scc->stat.tx_under; + + return &scc->dev_stat; +} + +/* ******************************************************************** */ +/* * dump statistics to /proc/net/z8530drv * */ +/* ******************************************************************** */ + + +static int scc_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + struct scc_channel *scc; + struct scc_kiss *kiss; + struct scc_stat *stat; + int len = 0; + off_t pos = 0; + off_t begin = 0; + int k; + + len += sprintf(buffer, "z8530drv-"VERSION"\n"); + + if (!Driver_Initialized) + { + len += sprintf(buffer+len, "not initialized\n"); + goto done; + } + + if (!Nchips) + { + len += sprintf(buffer+len, "chips missing\n"); + goto done; + } + + for (k = 0; k < Nchips*2; k++) + { + scc = &SCC_Info[k]; + stat = &scc->stat; + kiss = &scc->kiss; + + if (!scc->init) + continue; + + /* dev data ctrl irq clock brand enh vector special option + * baud nrz clocksrc softdcd bufsize + * rxints txints exints spints + * rcvd rxerrs over / xmit txerrs under / nospace bufsize + * txd pers slot tail ful wait min maxk idl defr txof grp + * W ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + * R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ## + */ + + len += sprintf(buffer+len, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n", + scc->dev->name, + scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand, + scc->enhanced, Vector_Latch, scc->special, + scc->option); + len += sprintf(buffer+len, "\t%lu %d %d %d %d\n", + scc->modem.speed, scc->modem.nrz, + scc->modem.clocksrc, kiss->softdcd, + stat->bufsize); + len += sprintf(buffer+len, "\t%lu %lu %lu %lu\n", + stat->rxints, stat->txints, stat->exints, stat->spints); + len += sprintf(buffer+len, "\t%lu %lu %d / %lu %lu %d / %d %d\n", + stat->rxframes, stat->rxerrs, stat->rx_over, + stat->txframes, stat->txerrs, stat->tx_under, + stat->nospace, stat->tx_state); + +#define K(x) kiss->x + len += sprintf(buffer+len, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n", + K(txdelay), K(persist), K(slottime), K(tailtime), + K(fulldup), K(waittime), K(mintime), K(maxkeyup), + K(idletime), K(maxdefer), K(tx_inhibit), K(group)); +#undef K +#ifdef SCC_DEBUG + { + int reg; + + len += sprintf(buffer+len, "\tW "); + for (reg = 0; reg < 16; reg++) + len += sprintf(buffer+len, "%2.2x ", scc->wreg[reg]); + len += sprintf(buffer+len, "\n"); + + len += sprintf(buffer+len, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1)); + for (reg = 3; reg < 8; reg++) + len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg)); + len += sprintf(buffer+len, "XX "); + for (reg = 9; reg < 16; reg++) + len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg)); + len += sprintf(buffer+len, "\n"); + } +#endif + len += sprintf(buffer+len, "\n"); + + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + + if (pos > offset + length) + break; + } + +done: + + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) len = length; + + return len; +} + +#ifdef CONFIG_PROC_FS + +struct proc_dir_entry scc_proc_dir_entry = +{ + PROC_NET_Z8530, 8, "z8530drv", S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, scc_net_get_info +}; + +#define scc_net_procfs_init() proc_net_register(&scc_proc_dir_entry); +#define scc_net_procfs_remove() proc_net_unregister(PROC_NET_Z8530); +#else +#define scc_net_procfs_init() +#define scc_net_procfs_remove() +#endif + + +/* ******************************************************************** */ +/* * Init SCC driver * */ +/* ******************************************************************** */ + +__initfunc(int scc_init (void)) +{ + int chip, chan, k, result; + char devname[10]; + + printk(KERN_INFO BANNER); + + memset(&SCC_ctrl, 0, sizeof(SCC_ctrl)); + + /* pre-init channel information */ + + for (chip = 0; chip < MAXSCC; chip++) + { + memset((char *) &SCC_Info[2*chip ], 0, sizeof(struct scc_channel)); + memset((char *) &SCC_Info[2*chip+1], 0, sizeof(struct scc_channel)); + + for (chan = 0; chan < 2; chan++) + SCC_Info[2*chip+chan].magic = SCC_MAGIC; + } + + for (k = 0; k < 16; k++) Ivec[k].used = 0; + + sprintf(devname,"%s0", SCC_DriverName); + + result = scc_net_setup(SCC_Info, devname); + if (result) + { + printk(KERN_ERR "z8530drv: cannot initialize module\n"); + return result; + } + + scc_net_procfs_init(); + + return 0; +} + +/* ******************************************************************** */ +/* * Module support * */ +/* ******************************************************************** */ + + +#ifdef MODULE +int init_module(void) +{ + int result = 0; + + result = scc_init(); + + if (result == 0) + printk(KERN_INFO "Copyright 1993,1997 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n"); + + return result; +} + +void cleanup_module(void) +{ + long flags; + io_port ctrl; + int k; + struct scc_channel *scc; + + save_flags(flags); + cli(); + + if (Nchips == 0) + unregister_netdev(SCC_Info[0].dev); + + for (k = 0; k < Nchips; k++) + if ( (ctrl = SCC_ctrl[k].chan_A) ) + { + Outb(ctrl, 0); + OutReg(ctrl,R9,FHWRES); /* force hardware reset */ + udelay(50); + } + + for (k = 0; k < Nchips*2; k++) + { + scc = &SCC_Info[k]; + if (scc) + { + release_region(scc->ctrl, 1); + release_region(scc->data, 1); + if (scc->dev) + { + unregister_netdev(scc->dev); + kfree(scc->dev); + } + } + } + + for (k=0; k < 16 ; k++) + if (Ivec[k].used) free_irq(k, NULL); + + restore_flags(flags); + + scc_net_procfs_remove(); +} +#endif diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/Makefile linux/drivers/net/hamradio/soundmodem/Makefile --- v2.1.70/linux/drivers/net/hamradio/soundmodem/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/Makefile Thu Sep 4 13:25:28 1997 @@ -0,0 +1,60 @@ +# +# Makefile for the soundmodem device driver. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +O_TARGET := soundmodem.o + +O_OBJS := sm.o +ifeq ($(CONFIG_SOUNDMODEM_SBC),y) +O_OBJS += sm_sbc.o +endif +ifeq ($(CONFIG_SOUNDMODEM_WSS),y) +O_OBJS += sm_wss.o +endif +ifeq ($(CONFIG_SOUNDMODEM_AFSK1200),y) +O_OBJS += sm_afsk1200.o +endif +ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_7),y) +O_OBJS += sm_afsk2400_7.o +endif +ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_8),y) +O_OBJS += sm_afsk2400_8.o +endif +ifeq ($(CONFIG_SOUNDMODEM_AFSK2666),y) +O_OBJS += sm_afsk2666.o +endif +ifeq ($(CONFIG_SOUNDMODEM_HAPN4800),y) +O_OBJS += sm_hapn4800.o +endif +ifeq ($(CONFIG_SOUNDMODEM_PSK4800),y) +O_OBJS += sm_psk4800.o +endif +ifeq ($(CONFIG_SOUNDMODEM_FSK9600),y) +O_OBJS += sm_fsk9600.o +endif + +M_OBJS := $(O_TARGET) + +all: all_targets +.PHONY: all + +gentbl: gentbl.c + $(HOSTCC) -Wall $< -o $@ -lm + +TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2400_8.h +TBLHDR += sm_tbl_afsk2666.h sm_tbl_psk4800.h +TBLHDR += sm_tbl_hapn4800.h sm_tbl_fsk9600.h + +$(TBLHDR): gentbl + ./gentbl + +fastdep: $(TBLHDR) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/gentbl.c linux/drivers/net/hamradio/soundmodem/gentbl.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/gentbl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/gentbl.c Tue Aug 5 09:49:51 1997 @@ -0,0 +1,676 @@ +/*****************************************************************************/ + +/* + * gentbl.c -- soundcard radio modem driver table generator. + * + * 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. + * + */ + +#include +#include +#include + +/* -------------------------------------------------------------------- */ + +static void gentbl_offscostab(FILE *f, unsigned int nbits) +{ + int i; + + fprintf(f, "\n/*\n * small cosine table in U8 format\n */\n" + "#define OFFSCOSTABBITS %u\n" + "#define OFFSCOSTABSIZE (1<>%d)&0x%x]\n\n", + 16-nbits, (1<>%d)&0x%x]\n" + "#define SIN(x) COS((x)+0xc000)\n\n", 16-nbits, + (1< max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 3 || j < 255) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "fsk9600: txfilt4: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + min = max = 0; + memset(c, 0, sizeof(c)); +#if 0 + memcpy(c+2, fsk96_tx_coeff_5, sizeof(fsk96_tx_coeff_5)); +#else + for (i = 0; i < 36; i++) + c[4+i] = sinc(1.2*((i-17.5)/5.0))*hamming(i/35.0)/4.5; +#endif + fprintf(f, "static unsigned char fsk96_txfilt_5[] = {\n\t"); + for (i = 0; i < 5; i++) { + for (j = 0; j < 256; j++) { + for (k = 1, s = 0, l = i; k < 256; k <<= 1) { + if (j & k) { + for (m = 0; m < 5; m++, l++) + s += c[l]; + } else { + for (m = 0; m < 5; m++, l++) + s -= c[l]; + } + } + s *= 0.75; + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 4 || j < 255) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "fsk9600: txfilt5: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); +} + +/* -------------------------------------------------------------------- */ + +#define AFSK26_SAMPLERATE 16000 + +#define AFSK26_NUMCAR 2 +#define AFSK26_FIRSTCAR 2000 +#define AFSK26_MSK_LEN 6 +#define AFSK26_RXOVER 2 + +#define AFSK26_DEMCORRLEN (2*AFSK26_MSK_LEN) + +#define AFSK26_WINDOW(x) ((1-cos(2.0*M_PI*(x)))/2.0) + +#define AFSK26_AMPL(x) (((x)?1.0:0.7)) + +#undef AFSK26_AMPL +#define AFSK26_AMPL(x) 1 + +static void gentbl_afsk2666(FILE *f) +{ + int i, j, k, l, o, v, sumi, sumq; + float window[AFSK26_DEMCORRLEN*AFSK26_RXOVER]; + int cfreq[AFSK26_NUMCAR]; + + fprintf(f, "\n/*\n * afsk2666 specific tables\n */\n" + "#define AFSK26_DEMCORRLEN %d\n" + "#define AFSK26_SAMPLERATE %d\n\n", AFSK26_DEMCORRLEN, + AFSK26_SAMPLERATE); + fprintf(f, "static const unsigned int afsk26_carfreq[%d] = { ", + AFSK26_NUMCAR); + for (i = 0; i < AFSK26_NUMCAR; i++) { + cfreq[i] = 0x10000*AFSK26_FIRSTCAR/AFSK26_SAMPLERATE+ + 0x10000*i/AFSK26_MSK_LEN/2; + fprintf(f, "0x%x", cfreq[i]); + if (i < AFSK26_NUMCAR-1) + fprintf(f, ", "); + } + fprintf(f, " };\n\n"); + for (i = 0; i < AFSK26_DEMCORRLEN*AFSK26_RXOVER; i++) + window[i] = AFSK26_WINDOW(((float)i)/(AFSK26_DEMCORRLEN* + AFSK26_RXOVER)) * 127.0; + fprintf(f, "\nstatic const struct {\n\t" + "int i[%d];\n\tint q[%d];\n} afsk26_dem_tables[%d][%d] = {\n", + AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER, AFSK26_NUMCAR); + for (o = AFSK26_RXOVER-1; o >= 0; o--) { + fprintf(f, "\t{\n"); + for (i = 0; i < AFSK26_NUMCAR; i++) { + j = cfreq[i]; + fprintf(f, "\t\t{{ "); + for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumi = 0; l >= 0; + l--, k = (k+j)&0xffffu) { + sumi += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]* + cos(M_PI*k/32768.0)); + fprintf(f, "%6d%s", v, l ? ", " : " }, { "); + } + for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumq = 0; l >= 0; + l--, k = (k+j)&0xffffu) { + sumq += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]* + sin(M_PI*k/32768.0)); + fprintf(f, "%6d%s", v, l ? ", " : " }}"); + } + if (i < 1) + fprintf(f, ","); + fprintf(f, "\n#define AFSK26_DEM_SUM_I_%d_%d %d\n" + "#define AFSK26_DEM_SUM_Q_%d_%d %d\n", + AFSK26_RXOVER-1-o, i, sumi, AFSK26_RXOVER-1-o, i, sumq); + } + fprintf(f, "\t}%s\n", o ? "," : ""); + } + fprintf(f, "};\n\n"); +} + +/* -------------------------------------------------------------------- */ + +#define ATAN_TABLEN 1024 + +static void gentbl_atantab(FILE *f) +{ + int i; + short x; + + fprintf(f, "\n/*\n" + " * arctan table (indexed by i/q; should really be indexed by i/(i+q)\n" + " */\n""#define ATAN_TABLEN %d\n\n" + "static const unsigned short atan_tab[ATAN_TABLEN+2] = {", + ATAN_TABLEN); + for (i = 0; i <= ATAN_TABLEN; i++) { + if (!(i & 7)) + fprintf(f, "\n\t"); + x = atan(i / (float)ATAN_TABLEN) / M_PI * 0x8000; + fprintf(f, "%6d, ", x); + } + fprintf(f, "%6d\n};\n\n", x); + +} + +/* -------------------------------------------------------------------- */ + +#define PSK48_TXF_OVERSAMPLING 5 +#define PSK48_TXF_NUMSAMPLES 16 +#define PSK48_RXF_LEN 64 + +static const float psk48_tx_coeff[80] = { + -0.000379, -0.000640, -0.000000, 0.000772, + 0.000543, -0.000629, -0.001187, -0.000000, + 0.001634, 0.001183, -0.001382, -0.002603, + -0.000000, 0.003481, 0.002472, -0.002828, + -0.005215, -0.000000, 0.006705, 0.004678, + -0.005269, -0.009584, -0.000000, 0.012065, + 0.008360, -0.009375, -0.017028, -0.000000, + 0.021603, 0.015123, -0.017229, -0.032012, + -0.000000, 0.043774, 0.032544, -0.040365, + -0.084963, -0.000000, 0.201161, 0.374060, + 0.374060, 0.201161, -0.000000, -0.084963, + -0.040365, 0.032544, 0.043774, -0.000000, + -0.032012, -0.017229, 0.015123, 0.021603, + -0.000000, -0.017028, -0.009375, 0.008360, + 0.012065, -0.000000, -0.009584, -0.005269, + 0.004678, 0.006705, -0.000000, -0.005215, + -0.002828, 0.002472, 0.003481, -0.000000, + -0.002603, -0.001382, 0.001183, 0.001634, + -0.000000, -0.001187, -0.000629, 0.000543, + 0.000772, -0.000000, -0.000640, -0.000379 +}; + +static const float psk48_rx_coeff[PSK48_RXF_LEN] = { + -0.000219, 0.000360, 0.000873, 0.001080, + 0.000747, -0.000192, -0.001466, -0.002436, + -0.002328, -0.000699, 0.002101, 0.004809, + 0.005696, 0.003492, -0.001633, -0.007660, + -0.011316, -0.009627, -0.001780, 0.009712, + 0.019426, 0.021199, 0.011342, -0.008583, + -0.030955, -0.044093, -0.036634, -0.002651, + 0.054742, 0.123101, 0.184198, 0.220219, + 0.220219, 0.184198, 0.123101, 0.054742, + -0.002651, -0.036634, -0.044093, -0.030955, + -0.008583, 0.011342, 0.021199, 0.019426, + 0.009712, -0.001780, -0.009627, -0.011316, + -0.007660, -0.001633, 0.003492, 0.005696, + 0.004809, 0.002101, -0.000699, -0.002328, + -0.002436, -0.001466, -0.000192, 0.000747, + 0.001080, 0.000873, 0.000360, -0.000219 +}; + +static void gentbl_psk4800(FILE *f) +{ + int i, j, k; + short x; + + fprintf(f, "\n/*\n * psk4800 specific tables\n */\n" + "#define PSK48_TXF_OVERSAMPLING %d\n" + "#define PSK48_TXF_NUMSAMPLES %d\n\n" + "#define PSK48_SAMPLERATE 8000\n" + "#define PSK48_CAR_FREQ 2000\n" + "#define PSK48_PSK_LEN 5\n" + "#define PSK48_RXF_LEN %u\n" + "#define PSK48_PHASEINC (0x10000*PSK48_CAR_FREQ/PSK48_SAMPLERATE)\n" + "#define PSK48_SPHASEINC (0x10000/(2*PSK48_PSK_LEN))\n\n" + "static const short psk48_tx_table[PSK48_TXF_OVERSAMPLING*" + "PSK48_TXF_NUMSAMPLES*8*2] = {", + PSK48_TXF_OVERSAMPLING, PSK48_TXF_NUMSAMPLES, PSK48_RXF_LEN); + for (i = 0; i < PSK48_TXF_OVERSAMPLING; i++) { + for (j = 0; j < PSK48_TXF_NUMSAMPLES; j++) { + fprintf(f, "\n\t"); + for (k = 0; k < 8; k++) { + x = 32767.0 * cos(k*M_PI/4.0) * + psk48_tx_coeff[j * PSK48_TXF_OVERSAMPLING + i]; + fprintf(f, "%6d, ", x); + } + fprintf(f, "\n\t"); + for (k = 0; k < 8; k++) { + x = 32767.0 * sin(k*M_PI/4.0) * + psk48_tx_coeff[j * PSK48_TXF_OVERSAMPLING + i]; + fprintf(f, "%6d", x); + if (k != 7 || j != PSK48_TXF_NUMSAMPLES-1 || + i != PSK48_TXF_OVERSAMPLING-1) + fprintf(f, ", "); + } + } + } + fprintf(f, "\n};\n\n"); + + fprintf(f, "static const short psk48_rx_coeff[PSK48_RXF_LEN] = {\n\t"); + for (i = 0; i < PSK48_RXF_LEN; i++) { + fprintf(f, "%6d", (int)(psk48_rx_coeff[i]*32767.0)); + if (i < PSK48_RXF_LEN-1) + fprintf(f, ",%s", (i & 7) == 7 ? "\n\t" : ""); + } + fprintf(f, "\n};\n\n"); +} + +/* -------------------------------------------------------------------- */ + +static void gentbl_hapn4800(FILE *f) +{ + int i, j, k, l; + float s; + float c[40]; + float min, max; + + fprintf(f, "\n/*\n * hapn4800 specific tables\n */\n\n"); + /* + * firstly generate tables for the FM transmitter modulator + */ + min = max = 0; + memset(c, 0, sizeof(c)); + for (i = 0; i < 24; i++) + c[8+i] = sinc(1.5*((i-11.5)/8.0))*hamming(i/23.0)/2.4; + for (i = 0; i < 24; i++) + c[i] -= c[i+8]; + fprintf(f, "static unsigned char hapn48_txfilt_8[] = {\n\t"); + for (i = 0; i < 8; i++) { + for (j = 0; j < 16; j++) { + for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 8) { + if (j & k) + s += c[l]; + else + s -= c[l]; + } + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 7 || j < 15) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "hapn4800: txfilt8: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + min = max = 0; + memset(c, 0, sizeof(c)); + for (i = 0; i < 30; i++) + c[10+i] = sinc(1.5*((i-14.5)/10.0))*hamming(i/29.0)/2.4; + for (i = 0; i < 30; i++) + c[i] -= c[i+10]; + fprintf(f, "static unsigned char hapn48_txfilt_10[] = {\n\t"); + for (i = 0; i < 10; i++) { + for (j = 0; j < 16; j++) { + for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 10) { + if (j & k) + s += c[l]; + else + s -= c[l]; + } + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 9 || j < 15) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "hapn4800: txfilt10: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + /* + * secondly generate tables for the PM transmitter modulator + */ + min = max = 0; + memset(c, 0, sizeof(c)); + for (i = 0; i < 25; i++) + c[i] = sinc(1.4*((i-12.0)/8.0))*hamming(i/24.0)/6.3; + for (i = 0; i < 25; i++) + for (j = 1; j < 8; j++) + c[i] += c[i+j]; + fprintf(f, "static unsigned char hapn48_txfilt_pm8[] = {\n\t"); + for (i = 0; i < 8; i++) { + for (j = 0; j < 16; j++) { + for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 8) { + if (j & k) + s += c[l]; + else + s -= c[l]; + } + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 7 || j < 15) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "hapn4800: txfiltpm8: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + min = max = 0; + memset(c, 0, sizeof(c)); + for (i = 0; i < 31; i++) + c[10+i] = sinc(1.4*((i-15.0)/10.0))*hamming(i/30.0)/7.9; + for (i = 0; i < 31; i++) + for (j = 1; j < 10; j++) + c[i] += c[i+j]; + fprintf(f, "static unsigned char hapn48_txfilt_pm10[] = {\n\t"); + for (i = 0; i < 10; i++) { + for (j = 0; j < 16; j++) { + for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 10) { + if (j & k) + s += c[l]; + else + s -= c[l]; + } + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 9 || j < 15) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "hapn4800: txfiltpm10: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + +} + +/* -------------------------------------------------------------------- */ + +#define AFSK24_SAMPLERATE 16000 +#define AFSK24_CORRLEN 14 + +static void gentbl_afsk2400(FILE *f, float tcm3105clk) +{ + int i, sum, v; + + fprintf(f, "\n/*\n * afsk2400 specific tables (tcm3105 clk %7fHz)\n */\n" + "#define AFSK24_TX_FREQ_LO %d\n" + "#define AFSK24_TX_FREQ_HI %d\n" + "#define AFSK24_BITPLL_INC %d\n" + "#define AFSK24_SAMPLERATE %d\n\n", tcm3105clk, + (int)(tcm3105clk/3694.0), (int)(tcm3105clk/2015.0), + 0x10000*2400/AFSK24_SAMPLERATE, AFSK24_SAMPLERATE); + +#define ARGLO(x) 2.0*M_PI*(double)x*(tcm3105clk/3694.0)/(double)AFSK24_SAMPLERATE +#define ARGHI(x) 2.0*M_PI*(double)x*(tcm3105clk/2015.0)/(double)AFSK24_SAMPLERATE +#define WINDOW(x) hamming((float)(x)/(AFSK24_CORRLEN-1.0)) + + fprintf(f, "static const int afsk24_tx_lo_i[] = {\n\t"); + for(sum = i = 0; i < AFSK24_CORRLEN; i++) { + sum += (v = 127.0*cos(ARGLO(i))*WINDOW(i)); + fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_I %d\n\n" + "static const int afsk24_tx_lo_q[] = {\n\t", sum); + for(sum = i = 0; i < AFSK24_CORRLEN; i++) { + sum += (v = 127.0*sin(ARGLO(i))*WINDOW(i)); + fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %d\n\n" + "static const int afsk24_tx_hi_i[] = {\n\t", sum); + for(sum = i = 0; i < AFSK24_CORRLEN; i++) { + sum += (v = 127.0*cos(ARGHI(i))*WINDOW(i)); + fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %d\n\n" + "static const int afsk24_tx_hi_q[] = {\n\t", sum); + for(sum = i = 0; i < AFSK24_CORRLEN; i++) { + sum += (v = 127.0*sin(ARGHI(i))*WINDOW(i)); + fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %d\n\n", sum); +#undef ARGLO +#undef ARGHI +#undef WINDOW +} + +/* -------------------------------------------------------------------- */ + +static char *progname; + +static void gentbl_banner(FILE *f) +{ + fprintf(f, "/*\n * THIS FILE IS GENERATED AUTOMATICALLY BY %s, " + "DO NOT EDIT!\n */\n\n", progname); +} + +/* -------------------------------------------------------------------- */ + +void main(int argc, char *argv[]) +{ + FILE *f; + + progname = argv[0]; + if (!(f = fopen("sm_tbl_afsk1200.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_offscostab(f, 6); + gentbl_costab(f, 6); + gentbl_afsk1200(f); + fclose(f); + if (!(f = fopen("sm_tbl_afsk2666.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_offscostab(f, 6); + gentbl_costab(f, 6); + gentbl_afsk2666(f); + fclose(f); + if (!(f = fopen("sm_tbl_psk4800.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_psk4800(f); + gentbl_costab(f, 8); + gentbl_atantab(f); + fclose(f); + if (!(f = fopen("sm_tbl_hapn4800.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_hapn4800(f); + fclose(f); + if (!(f = fopen("sm_tbl_fsk9600.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_fsk9600(f); + fclose(f); + if (!(f = fopen("sm_tbl_afsk2400_8.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_offscostab(f, 6); + gentbl_costab(f, 6); + gentbl_afsk2400(f, 8000000); + fclose(f); + if (!(f = fopen("sm_tbl_afsk2400_7.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_offscostab(f, 6); + gentbl_costab(f, 6); + gentbl_afsk2400(f, 7372800); + fclose(f); + exit(0); +} + + +/* -------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm.c Tue Aug 5 09:49:51 1997 @@ -0,0 +1,898 @@ +/*****************************************************************************/ + +/* + * sm.c -- soundcard 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. + * + * + * Command line options (insmod command line) + * + * mode mode string; eg. "wss:afsk1200" + * iobase base address of the soundcard; common values are 0x220 for sbc, + * 0x530 for wss + * irq interrupt number; common values are 7 or 5 for sbc, 11 for wss + * dma dma number; common values are 0 or 1 + * + * + * History: + * 0.1 21.09.96 Started + * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) + * 0.4 21.01.97 Separately compileable soundcard/modem modules + * 0.5 03.03.97 fixed LPT probing (check_lpt result was interpreted the wrong way round) + * 0.6 16.04.97 init code/data tagged + * 0.7 30.07.97 fixed halfduplex interrupt handlers/hotfix for CS423X + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sm.h" + +/* --------------------------------------------------------------------- */ + +/* + * 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 + +/* --------------------------------------------------------------------- */ + +/*static*/ const char sm_drvname[] = "soundmodem"; +static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1997 Thomas Sailer, HB9JNX/AE4WA\n" +KERN_INFO "soundmodem: version 0.7 compiled " __TIME__ " " __DATE__ "\n"; + +/* --------------------------------------------------------------------- */ + +/*static*/ const struct modem_tx_info *sm_modem_tx_table[] = { +#ifdef CONFIG_SOUNDMODEM_AFSK1200 + &sm_afsk1200_tx, +#endif /* CONFIG_SOUNDMODEM_AFSK1200 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2400_7 + &sm_afsk2400_7_tx, +#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2400_8 + &sm_afsk2400_8_tx, +#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2666 + &sm_afsk2666_tx, +#endif /* CONFIG_SOUNDMODEM_AFSK2666 */ +#ifdef CONFIG_SOUNDMODEM_PSK4800 + &sm_psk4800_tx, +#endif /* CONFIG_SOUNDMODEM_PSK4800 */ +#ifdef CONFIG_SOUNDMODEM_HAPN4800 + &sm_hapn4800_8_tx, + &sm_hapn4800_10_tx, + &sm_hapn4800_pm8_tx, + &sm_hapn4800_pm10_tx, +#endif /* CONFIG_SOUNDMODEM_HAPN4800 */ +#ifdef CONFIG_SOUNDMODEM_FSK9600 + &sm_fsk9600_4_tx, + &sm_fsk9600_5_tx, +#endif /* CONFIG_SOUNDMODEM_FSK9600 */ + NULL +}; + +/*static*/ const struct modem_rx_info *sm_modem_rx_table[] = { +#ifdef CONFIG_SOUNDMODEM_AFSK1200 + &sm_afsk1200_rx, +#endif /* CONFIG_SOUNDMODEM_AFSK1200 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2400_7 + &sm_afsk2400_7_rx, +#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2400_8 + &sm_afsk2400_8_rx, +#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2666 + &sm_afsk2666_rx, +#endif /* CONFIG_SOUNDMODEM_AFSK2666 */ +#ifdef CONFIG_SOUNDMODEM_PSK4800 + &sm_psk4800_rx, +#endif /* CONFIG_SOUNDMODEM_PSK4800 */ +#ifdef CONFIG_SOUNDMODEM_HAPN4800 + &sm_hapn4800_8_rx, + &sm_hapn4800_10_rx, + &sm_hapn4800_pm8_rx, + &sm_hapn4800_pm10_rx, +#endif /* CONFIG_SOUNDMODEM_HAPN4800 */ +#ifdef CONFIG_SOUNDMODEM_FSK9600 + &sm_fsk9600_4_rx, + &sm_fsk9600_5_rx, +#endif /* CONFIG_SOUNDMODEM_FSK9600 */ + NULL +}; + +static const struct hardware_info *sm_hardware_table[] = { +#ifdef CONFIG_SOUNDMODEM_SBC + &sm_hw_sbc, + &sm_hw_sbcfdx, +#endif /* CONFIG_SOUNDMODEM_SBC */ +#ifdef CONFIG_SOUNDMODEM_WSS + &sm_hw_wss, + &sm_hw_wssfdx, +#endif /* CONFIG_SOUNDMODEM_WSS */ + NULL +}; + +/* --------------------------------------------------------------------- */ + +#define NR_PORTS 4 + +/* --------------------------------------------------------------------- */ + +static struct device sm_device[NR_PORTS]; + +static struct { + char *mode; + int iobase, irq, dma, dma2, seriobase, pariobase, midiiobase; +} sm_ports[NR_PORTS] = { + { NULL, -1, 0, 0, 0, -1, -1, -1 }, +}; + +/* --------------------------------------------------------------------- */ + +#define UART_RBR(iobase) (iobase+0) +#define UART_THR(iobase) (iobase+0) +#define UART_IER(iobase) (iobase+1) +#define UART_IIR(iobase) (iobase+2) +#define UART_FCR(iobase) (iobase+2) +#define UART_LCR(iobase) (iobase+3) +#define UART_MCR(iobase) (iobase+4) +#define UART_LSR(iobase) (iobase+5) +#define UART_MSR(iobase) (iobase+6) +#define UART_SCR(iobase) (iobase+7) +#define UART_DLL(iobase) (iobase+0) +#define UART_DLM(iobase) (iobase+1) + +#define SER_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 LPT_EXTENT 3 + +#define MIDI_DATA(iobase) (iobase) +#define MIDI_STATUS(iobase) (iobase+1) +#define MIDI_READ_FULL 0x80 /* attention: negative logic!! */ +#define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */ + +#define MIDI_EXTENT 2 + +/* ---------------------------------------------------------------------- */ + +#define PARAM_TXDELAY 1 +#define PARAM_PERSIST 2 +#define PARAM_SLOTTIME 3 +#define PARAM_TXTAIL 4 +#define PARAM_FULLDUP 5 +#define PARAM_HARDWARE 6 +#define PARAM_RETURN 255 + +#define SP_SER 1 +#define SP_PAR 2 +#define SP_MIDI 4 + +/* --------------------------------------------------------------------- */ +/* + * ===================== port checking routines ======================== + */ + +/* + * returns 0 if ok and != 0 on error; + * the same behaviour as par96_check_lpt in baycom.c + */ + +/* + * returns 0 if ok and != 0 on error; + * the same behaviour as par96_check_lpt in baycom.c + */ + +static int check_lpt(unsigned int iobase) +{ + unsigned char b1,b2; + int i; + + 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; +} + +/* --------------------------------------------------------------------- */ + +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 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 }; + + if (iobase <= 0 || iobase > 0x1000-SER_EXTENT) + return c_uart_unknown; + if (check_region(iobase, SER_EXTENT)) + return c_uart_unknown; + b1 = inb(UART_MCR(iobase)); + outb(b1 | 0x10, UART_MCR(iobase)); /* loopback mode */ + b2 = inb(UART_MSR(iobase)); + outb(0x1a, UART_MCR(iobase)); + b3 = inb(UART_MSR(iobase)) & 0xf0; + outb(b1, UART_MCR(iobase)); /* restore old values */ + outb(b2, UART_MSR(iobase)); + if (b3 != 0x90) + return c_uart_unknown; + inb(UART_RBR(iobase)); + inb(UART_RBR(iobase)); + outb(0x01, UART_FCR(iobase)); /* enable FIFOs */ + u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3]; + if (u == c_uart_16450) { + outb(0x5a, UART_SCR(iobase)); + b1 = inb(UART_SCR(iobase)); + outb(0xa5, UART_SCR(iobase)); + b2 = inb(UART_SCR(iobase)); + if ((b1 != 0x5a) || (b2 != 0xa5)) + u = c_uart_8250; + } + return u; +} + +/* --------------------------------------------------------------------- */ + +static int check_midi(unsigned int iobase) +{ + unsigned long timeout; + unsigned long flags; + unsigned char b; + + if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT) + return 0; + if (check_region(iobase, MIDI_EXTENT)) + return 0; + timeout = jiffies + (HZ / 100); + while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) + if ((signed)(jiffies - timeout) > 0) + return 0; + save_flags(flags); + cli(); + outb(0xff, MIDI_DATA(iobase)); + b = inb(MIDI_STATUS(iobase)); + restore_flags(flags); + if (!(b & MIDI_WRITE_EMPTY)) + return 0; + while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) + if ((signed)(jiffies - timeout) > 0) + return 0; + return 1; +} + +/* --------------------------------------------------------------------- */ + +void sm_output_status(struct sm_state *sm) +{ + int invert_dcd = 0; + int invert_ptt = 0; + + int ptt = /*hdlcdrv_ptt(&sm->hdrv)*/(sm->dma.ptt_cnt > 0) ^ invert_ptt; + int dcd = (!!sm->hdrv.hdlcrx.dcd) ^ invert_dcd; + + if (sm->hdrv.ptt_out.flags & SP_SER) { + outb(dcd | (ptt << 1), UART_MCR(sm->hdrv.ptt_out.seriobase)); + outb(0x40 & (-ptt), UART_LCR(sm->hdrv.ptt_out.seriobase)); + } + if (sm->hdrv.ptt_out.flags & SP_PAR) { + outb(ptt | (dcd << 1), LPT_DATA(sm->hdrv.ptt_out.pariobase)); + } + if (sm->hdrv.ptt_out.flags & SP_MIDI && hdlcdrv_ptt(&sm->hdrv)) { + outb(0, MIDI_DATA(sm->hdrv.ptt_out.midiiobase)); + } +} + +/* --------------------------------------------------------------------- */ + +static void sm_output_open(struct sm_state *sm) +{ + enum uart u = c_uart_unknown; + + sm->hdrv.ptt_out.flags = 0; + if (sm->hdrv.ptt_out.seriobase > 0 && + sm->hdrv.ptt_out.seriobase <= 0x1000-SER_EXTENT && + ((u = check_uart(sm->hdrv.ptt_out.seriobase))) != c_uart_unknown) { + sm->hdrv.ptt_out.flags |= SP_SER; + request_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT, "sm ser ptt"); + outb(0, UART_IER(sm->hdrv.ptt_out.seriobase)); + /* 5 bits, 1 stop, no parity, no break, Div latch access */ + outb(0x80, UART_LCR(sm->hdrv.ptt_out.seriobase)); + outb(0, UART_DLM(sm->hdrv.ptt_out.seriobase)); + outb(1, UART_DLL(sm->hdrv.ptt_out.seriobase)); /* as fast as possible */ + /* LCR and MCR set by output_status */ + } + if (sm->hdrv.ptt_out.pariobase > 0 && + sm->hdrv.ptt_out.pariobase <= 0x1000-LPT_EXTENT && + !check_lpt(sm->hdrv.ptt_out.pariobase)) { + sm->hdrv.ptt_out.flags |= SP_PAR; + request_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT, "sm par ptt"); + } + if (sm->hdrv.ptt_out.midiiobase > 0 && + sm->hdrv.ptt_out.midiiobase <= 0x1000-MIDI_EXTENT && + check_midi(sm->hdrv.ptt_out.midiiobase)) { + sm->hdrv.ptt_out.flags |= SP_MIDI; + request_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT, + "sm midi ptt"); + } + sm_output_status(sm); + + printk(KERN_INFO "%s: ptt output:", sm_drvname); + if (sm->hdrv.ptt_out.flags & SP_SER) + printk(" serial interface at 0x%x, uart %s", sm->hdrv.ptt_out.seriobase, + uart_str[u]); + if (sm->hdrv.ptt_out.flags & SP_PAR) + printk(" parallel interface at 0x%x", sm->hdrv.ptt_out.pariobase); + if (sm->hdrv.ptt_out.flags & SP_MIDI) + printk(" mpu401 (midi) interface at 0x%x", sm->hdrv.ptt_out.midiiobase); + if (!sm->hdrv.ptt_out.flags) + printk(" none"); + printk("\n"); +} + +/* --------------------------------------------------------------------- */ + +static void sm_output_close(struct sm_state *sm) +{ + /* release regions used for PTT output */ + sm->hdrv.hdlctx.ptt = sm->hdrv.hdlctx.calibrate = 0; + sm_output_status(sm); + if (sm->hdrv.ptt_out.flags & SP_SER) + release_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT); + if (sm->hdrv.ptt_out.flags & SP_PAR) + release_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT); + if (sm->hdrv.ptt_out.flags & SP_MIDI) + release_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT); + sm->hdrv.ptt_out.flags = 0; +} + +/* --------------------------------------------------------------------- */ + +static int sm_open(struct device *dev); +static int sm_close(struct device *dev); +static int sm_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd); + +/* --------------------------------------------------------------------- */ + +static const struct hdlcdrv_ops sm_ops = { + sm_drvname, sm_drvinfo, sm_open, sm_close, sm_ioctl +}; + +/* --------------------------------------------------------------------- */ + +static int sm_open(struct device *dev) +{ + struct sm_state *sm; + int err; + + if (!dev || !dev->priv || + ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "sm_open: invalid device struct\n"); + return -EINVAL; + } + sm = (struct sm_state *)dev->priv; + + if (!sm->mode_tx || !sm->mode_rx || !sm->hwdrv || !sm->hwdrv->open) + return -ENODEV; + sm->hdrv.par.bitrate = sm->mode_rx->bitrate; + err = sm->hwdrv->open(dev, sm); + if (err) + return err; + sm_output_open(sm); + MOD_INC_USE_COUNT; + printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u dma2 %u\n", + sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name, + sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma, sm->hdrv.ptt_out.dma2); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sm_close(struct device *dev) +{ + struct sm_state *sm; + int err = -ENODEV; + + if (!dev || !dev->priv || + ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "sm_close: invalid device struct\n"); + return -EINVAL; + } + sm = (struct sm_state *)dev->priv; + + + if (sm->hwdrv && sm->hwdrv->close) + err = sm->hwdrv && sm->hwdrv->close(dev, sm); + sm_output_close(sm); + MOD_DEC_USE_COUNT; + printk(KERN_INFO "%s: close %s at iobase 0x%lx irq %u dma %u\n", + sm_drvname, sm->hwdrv->hw_name, dev->base_addr, dev->irq, dev->dma); + return err; +} + +/* --------------------------------------------------------------------- */ + +static int sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, ':'); + const struct hardware_info **hwp = sm_hardware_table; + + if (!cp) + cp = mode; + else { + *cp++ = '\0'; + while (hwp && (*hwp) && (*hwp)->hw_name && strcmp((*hwp)->hw_name, mode)) + hwp++; + if (!hwp || !*hwp || !(*hwp)->hw_name) + return -EINVAL; + if ((*hwp)->loc_storage > sizeof(sm->hw)) { + printk(KERN_ERR "%s: insufficient storage for hw driver %s (%d)\n", + sm_drvname, (*hwp)->hw_name, (*hwp)->loc_storage); + return -EINVAL; + } + sm->hwdrv = *hwp; + } + if (!*cp) + return 0; + if (sm->hwdrv && sm->hwdrv->sethw) + return sm->hwdrv->sethw(dev, sm, cp); + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int sm_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct sm_state *sm; + struct sm_ioctl bi; + unsigned long flags; + unsigned int newdiagmode; + unsigned int newdiagflags; + char *cp; + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp = sm_modem_rx_table; + const struct hardware_info **hwp = sm_hardware_table; + + if (!dev || !dev->priv || + ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "sm_ioctl: invalid device struct\n"); + return -EINVAL; + } + sm = (struct sm_state *)dev->priv; + + if (cmd != SIOCDEVPRIVATE) { + if (!sm->hwdrv || !sm->hwdrv->ioctl) + return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd); + return -ENOIOCTLCMD; + } + switch (hi->cmd) { + default: + if (sm->hwdrv && sm->hwdrv->ioctl) + return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd); + return -ENOIOCTLCMD; + + case HDLCDRVCTL_GETMODE: + cp = hi->data.modename; + if (sm->hwdrv && sm->hwdrv->hw_name) + cp += sprintf(cp, "%s:", sm->hwdrv->hw_name); + else + cp += sprintf(cp, ":"); + if (sm->mode_tx && sm->mode_tx->name) + cp += sprintf(cp, "%s", sm->mode_tx->name); + else + cp += sprintf(cp, ""); + if (!sm->mode_rx || !sm->mode_rx || + strcmp(sm->mode_rx->name, sm->mode_tx->name)) { + if (sm->mode_rx && sm->mode_rx->name) + cp += sprintf(cp, ",%s", sm->mode_rx->name); + else + cp += sprintf(cp, ","); + } + if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi))) + return -EFAULT; + return 0; + + case HDLCDRVCTL_SETMODE: + if (!suser() || dev->start) + return -EACCES; + hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; + return sethw(dev, sm, hi->data.modename); + + case HDLCDRVCTL_MODELIST: + cp = hi->data.modename; + while (*hwp) { + if ((*hwp)->hw_name) + cp += sprintf("%s:,", (*hwp)->hw_name); + hwp++; + } + while (*mtp) { + if ((*mtp)->name) + cp += sprintf(">%s,", (*mtp)->name); + mtp++; + } + while (*mrp) { + if ((*mrp)->name) + cp += sprintf("<%s,", (*mrp)->name); + mrp++; + } + cp[-1] = '\0'; + if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi))) + return -EFAULT; + return 0; + +#ifdef SM_DEBUG + case SMCTL_GETDEBUG: + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + bi.data.dbg.int_rate = sm->debug_vals.last_intcnt; + bi.data.dbg.mod_cycles = sm->debug_vals.mod_cyc; + bi.data.dbg.demod_cycles = sm->debug_vals.demod_cyc; + bi.data.dbg.dma_residue = sm->debug_vals.dma_residue; + sm->debug_vals.mod_cyc = sm->debug_vals.demod_cyc = + sm->debug_vals.dma_residue = 0; + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; +#endif /* SM_DEBUG */ + + case SMCTL_DIAGNOSE: + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + newdiagmode = bi.data.diag.mode; + newdiagflags = bi.data.diag.flags; + if (newdiagmode > SM_DIAGMODE_CONSTELLATION) + return -EINVAL; + bi.data.diag.mode = sm->diag.mode; + bi.data.diag.flags = sm->diag.flags; + bi.data.diag.samplesperbit = sm->mode_rx->sperbit; + if (sm->diag.mode != newdiagmode) { + save_flags(flags); + cli(); + sm->diag.ptr = -1; + sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID; + sm->diag.mode = newdiagmode; + restore_flags(flags); + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + } + if (sm->diag.ptr < 0 || sm->diag.mode == SM_DIAGMODE_OFF) { + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + } + if (bi.data.diag.datalen > DIAGDATALEN) + bi.data.diag.datalen = DIAGDATALEN; + if (sm->diag.ptr < bi.data.diag.datalen) { + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + } + if (copy_to_user(bi.data.diag.data, sm->diag.data, + bi.data.diag.datalen * sizeof(short))) + return -EFAULT; + bi.data.diag.flags |= SM_DIAGFLAG_VALID; + save_flags(flags); + cli(); + sm->diag.ptr = -1; + sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID; + sm->diag.mode = newdiagmode; + restore_flags(flags); + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + } +} + +/* --------------------------------------------------------------------- */ + +#ifdef __i386__ + +int sm_x86_capability = 0; + +__initfunc(static void i386_capability(void)) +{ + unsigned long flags; + unsigned long fl1; + union { + struct { + unsigned int ebx, edx, ecx; + } r; + unsigned char s[13]; + } id; + unsigned int eax; + + save_flags(flags); + flags |= 0x200000; + restore_flags(flags); + save_flags(flags); + fl1 = flags; + flags &= ~0x200000; + restore_flags(flags); + save_flags(flags); + if (!(fl1 & 0x200000) || (flags & 0x200000)) { + printk(KERN_WARNING "%s: cpu does not support CPUID\n", sm_drvname); + return; + } + __asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) : + "0" (0)); + id.s[12] = 0; + if (eax < 1) { + printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability " + "list\n", sm_drvname, id.s); + return; + } + printk(KERN_INFO "%s: cpu: vendor string %s ", sm_drvname, id.s); + __asm__ ("cpuid" : "=a" (eax), "=d" (sm_x86_capability) : "0" (1) : "ebx", "ecx"); + printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15, + eax & 15, sm_x86_capability); +} +#endif /* __i386__ */ + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE +__initfunc(static int sm_init(void)) +#else /* MODULE */ +__initfunc(int sm_init(void)) +#endif /* MODULE */ +{ + int i, j, found = 0; + char set_hw = 1; + struct sm_state *sm; + char ifname[HDLCDRV_IFNAMELEN]; + + printk(sm_drvinfo); +#ifdef __i386__ + i386_capability(); +#endif /* __i386__ */ + /* + * register net devices + */ + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = sm_device+i; + sprintf(ifname, "sm%d", i); + + if (!sm_ports[i].mode) + set_hw = 0; + if (!set_hw) + sm_ports[i].iobase = sm_ports[i].irq = 0; + j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), + ifname, sm_ports[i].iobase, + sm_ports[i].irq, sm_ports[i].dma); + if (!j) { + sm = (struct sm_state *)dev->priv; + sm->hdrv.ptt_out.dma2 = sm_ports[i].dma2; + sm->hdrv.ptt_out.seriobase = sm_ports[i].seriobase; + sm->hdrv.ptt_out.pariobase = sm_ports[i].pariobase; + sm->hdrv.ptt_out.midiiobase = sm_ports[i].midiiobase; + if (set_hw && sethw(dev, sm, sm_ports[i].mode)) + set_hw = 0; + found++; + } else { + printk(KERN_WARNING "%s: cannot register net device\n", + sm_drvname); + } + } + if (!found) + return -ENXIO; + return 0; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +/* + * command line settable parameters + */ +static char *mode = NULL; +static int iobase = -1; +static int irq = -1; +static int dma = -1; +static int dma2 = -1; +static int serio = 0; +static int pario = 0; +static int midiio = 0; + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600"); +MODULE_PARM(iobase, "i"); +MODULE_PARM_DESC(iobase, "soundmodem base address"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "soundmodem interrupt"); +MODULE_PARM(dma, "i"); +MODULE_PARM_DESC(dma, "soundmodem dma channel"); +MODULE_PARM(dma2, "i"); +MODULE_PARM_DESC(dma2, "soundmodem 2nd dma channel; full duplex only"); +MODULE_PARM(serio, "i"); +MODULE_PARM_DESC(serio, "soundmodem PTT output on serial port"); +MODULE_PARM(pario, "i"); +MODULE_PARM_DESC(pario, "soundmodem PTT output on parallel port"); +MODULE_PARM(midiio, "i"); +MODULE_PARM_DESC(midiio, "soundmodem PTT output on midi port"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Soundcard amateur radio modem driver"); + +#endif + +__initfunc(int init_module(void)) +{ + if (mode) { + if (iobase == -1) + iobase = (!strncmp(mode, "sbc", 3)) ? 0x220 : 0x530; + if (irq == -1) + irq = (!strncmp(mode, "sbc", 3)) ? 5 : 11; + if (dma == -1) + dma = 1; + } + sm_ports[0].mode = mode; + sm_ports[0].iobase = iobase; + sm_ports[0].irq = irq; + sm_ports[0].dma = dma; + sm_ports[0].dma2 = dma2; + sm_ports[0].seriobase = serio; + sm_ports[0].pariobase = pario; + sm_ports[0].midiiobase = midiio; + sm_ports[1].mode = NULL; + + return sm_init(); +} + +/* --------------------------------------------------------------------- */ + +void cleanup_module(void) +{ + int i; + + printk(KERN_INFO "sm: cleanup_module called\n"); + + for(i = 0; i < NR_PORTS; i++) { + struct device *dev = sm_device+i; + struct sm_state *sm = (struct sm_state *)dev->priv; + + if (sm) { + if (sm->hdrv.magic != HDLCDRV_MAGIC) + printk(KERN_ERR "sm: invalid magic in " + "cleanup_module\n"); + else + hdlcdrv_unregister_hdlcdrv(dev); + } + } +} + +#else /* MODULE */ +/* --------------------------------------------------------------------- */ +/* + * format: sm=io,irq,dma[,dma2[,serio[,pario]]],mode + * mode: hw:modem + * hw: sbc, wss, wssfdx + * modem: afsk1200, fsk9600 + */ + +__initfunc(void sm_setup(char *str, int *ints)) +{ + int i; + + for (i = 0; (i < NR_PORTS) && (sm_ports[i].mode); i++); + if ((i >= NR_PORTS) || (ints[0] < 3)) { + printk(KERN_INFO "%s: too many or invalid interface " + "specifications\n", sm_drvname); + return; + } + sm_ports[i].mode = str; + sm_ports[i].iobase = ints[1]; + sm_ports[i].irq = ints[2]; + sm_ports[i].dma = ints[3]; + sm_ports[i].dma2 = (ints[0] >= 4) ? ints[4] : 0; + sm_ports[i].seriobase = (ints[0] >= 5) ? ints[5] : 0; + sm_ports[i].pariobase = (ints[0] >= 6) ? ints[6] : 0; + sm_ports[i].midiiobase = (ints[0] >= 7) ? ints[7] : 0; + if (i < NR_PORTS-1) + sm_ports[i+1].mode = NULL; +} + +#endif /* MODULE */ +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm.h linux/drivers/net/hamradio/soundmodem/sm.h --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm.h Mon Jun 16 16:35:56 1997 @@ -0,0 +1,382 @@ +/*****************************************************************************/ + +/* + * sm.h -- soundcard radio modem driver internal header. + * + * 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. + * + */ + +#ifndef _SM_H +#define _SM_H + +/* ---------------------------------------------------------------------- */ + +#include +#include + +#define SM_DEBUG + +/* ---------------------------------------------------------------------- */ +/* + * Information that need to be kept for each board. + */ + +struct sm_state { + struct hdlcdrv_state hdrv; + + const struct modem_tx_info *mode_tx; + const struct modem_rx_info *mode_rx; + + const struct hardware_info *hwdrv; + + /* + * Hardware (soundcard) access routines state + */ + struct { + void *ibuf; + unsigned int ifragsz; + unsigned int ifragptr; + unsigned int i16bit; + void *obuf; + unsigned int ofragsz; + unsigned int ofragptr; + unsigned int o16bit; + int ptt_cnt; + } dma; + + union { + long hw[32/sizeof(long)]; + } hw; + + /* + * state of the modem code + */ + union { + long m[32/sizeof(long)]; + } m; + union { + long d[256/sizeof(long)]; + } d; + +#define DIAGDATALEN 64 + struct diag_data { + unsigned int mode; + unsigned int flags; + volatile int ptr; + short data[DIAGDATALEN]; + } diag; + + +#ifdef SM_DEBUG + struct debug_vals { + unsigned long last_jiffies; + unsigned cur_intcnt; + unsigned last_intcnt; + unsigned mod_cyc; + unsigned demod_cyc; + unsigned dma_residue; + } debug_vals; +#endif /* SM_DEBUG */ +}; + +/* ---------------------------------------------------------------------- */ +/* + * Mode definition structure + */ + +struct modem_tx_info { + const char *name; + unsigned int loc_storage; + int srate; + int bitrate; + void (*modulator_u8)(struct sm_state *, unsigned char *, unsigned int); + void (*modulator_s16)(struct sm_state *, short *, unsigned int); + void (*init)(struct sm_state *); +}; + +struct modem_rx_info { + const char *name; + unsigned int loc_storage; + int srate; + int bitrate; + unsigned int overlap; + unsigned int sperbit; + void (*demodulator_u8)(struct sm_state *, const unsigned char *, unsigned int); + void (*demodulator_s16)(struct sm_state *, const short *, unsigned int); + void (*init)(struct sm_state *); +}; + +/* ---------------------------------------------------------------------- */ +/* + * Soundcard driver definition structure + */ + +struct hardware_info { + char *hw_name; /* used for request_{region,irq,dma} */ + unsigned int loc_storage; + /* + * mode specific open/close + */ + int (*open)(struct device *, struct sm_state *); + int (*close)(struct device *, struct sm_state *); + int (*ioctl)(struct device *, struct sm_state *, struct ifreq *, + struct hdlcdrv_ioctl *, int); + int (*sethw)(struct device *, struct sm_state *, char *); +}; + +/* --------------------------------------------------------------------- */ + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +/* --------------------------------------------------------------------- */ + +extern const char sm_drvname[]; +extern const char sm_drvinfo[]; + +/* --------------------------------------------------------------------- */ +/* + * ===================== diagnostics stuff =============================== + */ + +extern inline void diag_trigger(struct sm_state *sm) +{ + if (sm->diag.ptr < 0) + if (!(sm->diag.flags & SM_DIAGFLAG_DCDGATE) || sm->hdrv.hdlcrx.dcd) + sm->diag.ptr = 0; +} + +/* --------------------------------------------------------------------- */ + +#define SHRT_MAX ((short)(((unsigned short)(~0U))>>1)) +#define SHRT_MIN (-SHRT_MAX-1) + +extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod) +{ + int val; + + if ((sm->diag.mode != SM_DIAGMODE_INPUT && + sm->diag.mode != SM_DIAGMODE_DEMOD) || + sm->diag.ptr >= DIAGDATALEN || sm->diag.ptr < 0) + return; + val = (sm->diag.mode == SM_DIAGMODE_DEMOD) ? valdemod : valinp; + /* clip */ + if (val > SHRT_MAX) + val = SHRT_MAX; + if (val < SHRT_MIN) + val = SHRT_MIN; + sm->diag.data[sm->diag.ptr++] = val; +} + +/* --------------------------------------------------------------------- */ + +extern inline void diag_add_one(struct sm_state *sm, int val) +{ + if ((sm->diag.mode != SM_DIAGMODE_INPUT && + sm->diag.mode != SM_DIAGMODE_DEMOD) || + sm->diag.ptr >= DIAGDATALEN || sm->diag.ptr < 0) + return; + /* clip */ + if (val > SHRT_MAX) + val = SHRT_MAX; + if (val < SHRT_MIN) + val = SHRT_MIN; + sm->diag.data[sm->diag.ptr++] = val; +} + +/* --------------------------------------------------------------------- */ + +static inline void diag_add_constellation(struct sm_state *sm, int vali, int valq) +{ + if ((sm->diag.mode != SM_DIAGMODE_CONSTELLATION) || + sm->diag.ptr >= DIAGDATALEN-1 || sm->diag.ptr < 0) + return; + /* clip */ + if (vali > SHRT_MAX) + vali = SHRT_MAX; + if (vali < SHRT_MIN) + vali = SHRT_MIN; + if (valq > SHRT_MAX) + valq = SHRT_MAX; + if (valq < SHRT_MIN) + valq = SHRT_MIN; + sm->diag.data[sm->diag.ptr++] = vali; + sm->diag.data[sm->diag.ptr++] = valq; +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== utility functions =============================== + */ + +extern inline unsigned int hweight32(unsigned int w) + __attribute__ ((unused)); +extern inline unsigned int hweight16(unsigned short w) + __attribute__ ((unused)); +extern inline unsigned int hweight8(unsigned char w) + __attribute__ ((unused)); + +extern inline unsigned int hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +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); +} + +extern inline unsigned int gcd(unsigned int x, unsigned int y) + __attribute__ ((unused)); +extern inline unsigned int lcm(unsigned int x, unsigned int y) + __attribute__ ((unused)); + +extern inline unsigned int gcd(unsigned int x, unsigned int y) +{ + for (;;) { + if (!x) + return y; + if (!y) + return x; + if (x > y) + x %= y; + else + y %= x; + } +} + +extern inline unsigned int lcm(unsigned int x, unsigned int y) +{ + return x * y / gcd(x, y); +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== profiling ======================================= + */ + + +#ifdef __i386__ + +extern int sm_x86_capability; + +#define HAS_RDTSC (sm_x86_capability & 0x10) + +/* + * only do 32bit cycle counter arithmetic; we hope we won't overflow :-) + * in fact, overflowing modems would require over 2THz clock speeds :-) + */ + +#define time_exec(var,cmd) \ +({ \ + if (HAS_RDTSC) { \ + unsigned int cnt1, cnt2, cnt3; \ + __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \ + cmd; \ + __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \ + var = cnt2-cnt1; \ + } else { \ + cmd; \ + } \ +}) + +#else /* __i386__ */ + +#define time_exec(var,cmd) cmd + +#endif /* __i386__ */ + +/* --------------------------------------------------------------------- */ + +extern const struct modem_tx_info sm_afsk1200_tx; +extern const struct modem_tx_info sm_afsk2400_7_tx; +extern const struct modem_tx_info sm_afsk2400_8_tx; +extern const struct modem_tx_info sm_afsk2666_tx; +extern const struct modem_tx_info sm_psk4800_tx; +extern const struct modem_tx_info sm_hapn4800_8_tx; +extern const struct modem_tx_info sm_hapn4800_10_tx; +extern const struct modem_tx_info sm_hapn4800_pm8_tx; +extern const struct modem_tx_info sm_hapn4800_pm10_tx; +extern const struct modem_tx_info sm_fsk9600_4_tx; +extern const struct modem_tx_info sm_fsk9600_5_tx; + +extern const struct modem_rx_info sm_afsk1200_rx; +extern const struct modem_rx_info sm_afsk2400_7_rx; +extern const struct modem_rx_info sm_afsk2400_8_rx; +extern const struct modem_rx_info sm_afsk2666_rx; +extern const struct modem_rx_info sm_psk4800_rx; +extern const struct modem_rx_info sm_hapn4800_8_rx; +extern const struct modem_rx_info sm_hapn4800_10_rx; +extern const struct modem_rx_info sm_hapn4800_pm8_rx; +extern const struct modem_rx_info sm_hapn4800_pm10_rx; +extern const struct modem_rx_info sm_fsk9600_4_rx; +extern const struct modem_rx_info sm_fsk9600_5_rx; + +extern const struct hardware_info sm_hw_sbc; +extern const struct hardware_info sm_hw_sbcfdx; +extern const struct hardware_info sm_hw_wss; +extern const struct hardware_info sm_hw_wssfdx; + +extern const struct modem_tx_info *sm_modem_tx_table[]; +extern const struct modem_rx_info *sm_modem_rx_table[]; +extern const struct hardware_info *sm_hardware_table[]; + +/* --------------------------------------------------------------------- */ + +void sm_output_status(struct sm_state *sm); +/*void sm_output_open(struct sm_state *sm);*/ +/*void sm_output_close(struct sm_state *sm);*/ + +/* --------------------------------------------------------------------- */ + +extern void inline sm_int_freq(struct sm_state *sm) +{ +#ifdef SM_DEBUG + unsigned long cur_jiffies = jiffies; + /* + * measure the interrupt frequency + */ + sm->debug_vals.cur_intcnt++; + if ((cur_jiffies - sm->debug_vals.last_jiffies) >= HZ) { + sm->debug_vals.last_jiffies = cur_jiffies; + sm->debug_vals.last_intcnt = sm->debug_vals.cur_intcnt; + sm->debug_vals.cur_intcnt = 0; + } +#endif /* SM_DEBUG */ +} + +/* --------------------------------------------------------------------- */ +#endif /* _SM_H */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_afsk1200.c linux/drivers/net/hamradio/soundmodem/sm_afsk1200.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_afsk1200.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm_afsk1200.c Mon Jun 16 16:35:56 1997 @@ -0,0 +1,272 @@ +/*****************************************************************************/ + +/* + * sm_afsk1200.c -- soundcard radio modem driver, 1200 baud AFSK modem + * + * 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. + * + */ + +#include "sm.h" +#include "sm_tbl_afsk1200.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_afsk12 { + unsigned int shreg; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; + unsigned char last_rxbit; +}; + +struct mod_state_afsk12 { + unsigned int shreg; + unsigned char tx_bit; + unsigned int bit_pll; + unsigned int dds_inc; + unsigned int txphase; +}; + +/* --------------------------------------------------------------------- */ + +static const int dds_inc[2] = { + AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE, + AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE +}; + +static void modulator_1200_u8(struct sm_state *sm, unsigned char *buf, + unsigned int buflen) +{ + struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m); + + for (; buflen > 0; buflen--) { + if (!((st->txphase++) & 7)) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + } + st->dds_inc = dds_inc[st->tx_bit & 1]; + *buf++ = OFFSCOS(st->bit_pll); + st->bit_pll += st->dds_inc; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_1200_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m); + + for (; buflen > 0; buflen--) { + if (!((st->txphase++) & 7)) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + } + st->dds_inc = dds_inc[st->tx_bit & 1]; + *buf++ = COS(st->bit_pll); + st->bit_pll += st->dds_inc; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum) +{ + int sum = -0x80 * csum; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + + sum >>= 7; + return sum * sum; +} + +extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum) +{ + int sum = 0; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + + sum >>= 15; + return sum * sum; +} + +extern __inline__ int do_filter_1200_u8(const unsigned char *buf) +{ + int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I); + sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q); + sum -= convolution8_u8(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I); + sum -= convolution8_u8(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q); + return sum; +} + +extern __inline__ int do_filter_1200_s16(const short *buf) +{ + int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I); + sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q); + sum -= convolution8_s16(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I); + sum -= convolution8_s16(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q); + return sum; +} + +/* --------------------------------------------------------------------- */ + +static const int pll_corr[2] = { -0x1000, 0x1000 }; + +static void demodulator_1200_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_1200_u8(buf); + st->dcd_shreg <<= 1; + st->bit_pll += 0x2000; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + st->bit_pll += pll_corr + [st->bit_pll < 0x9000]; + j = 4 * hweight8(st->dcd_shreg & 0x38) + - hweight16(st->dcd_shreg & 0x7c0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, (((int)*buf)-0x80) << 8, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_1200_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_1200_s16(buf); + st->dcd_shreg <<= 1; + st->bit_pll += 0x2000; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + st->bit_pll += pll_corr + [st->bit_pll < 0x9000]; + j = 4 * hweight8(st->dcd_shreg & 0x38) + - hweight16(st->dcd_shreg & 0x7c0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, *buf, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_1200(struct sm_state *sm) +{ + struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_afsk1200_tx = { + "afsk1200", sizeof(struct mod_state_afsk12), + AFSK12_SAMPLE_RATE, 1200, modulator_1200_u8, modulator_1200_s16, NULL +}; + +const struct modem_rx_info sm_afsk1200_rx = { + "afsk1200", sizeof(struct demod_state_afsk12), + AFSK12_SAMPLE_RATE, 1200, 8, AFSK12_SAMPLE_RATE/1200, + demodulator_1200_u8, demodulator_1200_s16, demod_init_1200 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c linux/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c Thu Sep 4 13:25:28 1997 @@ -0,0 +1,296 @@ +/*****************************************************************************/ + +/* + * sm_afsk2400_7.c -- soundcard radio modem driver, 2400 baud AFSK modem + * + * 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. + * + */ + +/* + * This driver is intended to be compatible with TCM3105 modems + * overclocked to 7.3728MHz. The mark and space frequencies therefore + * lie at 3658 and 1996 Hz. + * Note that I do _not_ recommend the building of such links, I provide + * this only for the users who live in the coverage area of such + * a "legacy" link. + */ + +#include "sm.h" +#include "sm_tbl_afsk2400_7.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_afsk24 { + unsigned int shreg; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; + unsigned char last_rxbit; +}; + +struct mod_state_afsk24 { + unsigned int shreg; + unsigned char tx_bit; + unsigned int bit_pll; + unsigned int tx_seq; + unsigned int phinc; +}; + +/* --------------------------------------------------------------------- */ + +static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE, + AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE }; + +static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (st->tx_seq < 0x5555) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + st->phinc = dds_inc[st->tx_bit & 1]; + } + st->tx_seq += 0x5555; + st->tx_seq &= 0xffff; + *buf = OFFSCOS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (st->tx_seq < 0x5555) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + st->phinc = dds_inc[st->tx_bit & 1]; + } + st->tx_seq += 0x5555; + st->tx_seq &= 0xffff; + *buf = COS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum) +{ + int sum = -0x80 * csum; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + sum += (st[-12] * coeff[12]); + sum += (st[-13] * coeff[13]); + + sum >>= 7; + return sum * sum; +} + +extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum) +{ + int sum = 0; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + sum += (st[-12] * coeff[12]); + sum += (st[-13] * coeff[13]); + + sum >>= 15; + return sum * sum; +} + +extern __inline__ int do_filter_2400_u8(const unsigned char *buf) +{ + int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); + sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); + sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); + sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); + return sum; +} + +extern __inline__ int do_filter_2400_s16(const short *buf) +{ + int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); + sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); + sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); + sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); + return sum; +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_2400_u8(buf); + st->dcd_shreg <<= 1; + st->bit_pll += AFSK24_BITPLL_INC; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) + st->bit_pll += AFSK24_BITPLL_INC/2; + else + st->bit_pll -= AFSK24_BITPLL_INC/2; + j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) + - hweight16(st->dcd_shreg & 0x1e0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, (((int)*buf)-0x80) << 8, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_2400_s16(buf); + st->dcd_shreg <<= 1; + st->bit_pll += AFSK24_BITPLL_INC; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) + st->bit_pll += AFSK24_BITPLL_INC/2; + else + st->bit_pll -= AFSK24_BITPLL_INC/2; + j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) + - hweight16(st->dcd_shreg & 0x1e0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, *buf, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_2400(struct sm_state *sm) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_afsk2400_7_tx = { + "afsk2400_7", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400, + modulator_2400_u8, modulator_2400_s16, NULL +}; + +const struct modem_rx_info sm_afsk2400_7_rx = { + "afsk2400_7", sizeof(struct demod_state_afsk24), + AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400, + demodulator_2400_u8, demodulator_2400_s16, demod_init_2400 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c linux/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c Thu Sep 4 13:25:28 1997 @@ -0,0 +1,296 @@ +/*****************************************************************************/ + +/* + * sm_afsk2400_8.c -- soundcard radio modem driver, 2400 baud AFSK modem + * + * 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. + * + */ + +/* + * This driver is intended to be compatible with TCM3105 modems + * overclocked to 8MHz. The mark and space frequencies therefore + * lie at 3970 and 2165 Hz. + * Note that I do _not_ recommend the building of such links, I provide + * this only for the users who live in the coverage area of such + * a "legacy" link. + */ + +#include "sm.h" +#include "sm_tbl_afsk2400_8.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_afsk24 { + unsigned int shreg; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; + unsigned char last_rxbit; +}; + +struct mod_state_afsk24 { + unsigned int shreg; + unsigned char tx_bit; + unsigned int bit_pll; + unsigned int tx_seq; + unsigned int phinc; +}; + +/* --------------------------------------------------------------------- */ + +static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE, + AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE }; + +static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (st->tx_seq < 0x5555) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + st->phinc = dds_inc[st->tx_bit & 1]; + } + st->tx_seq += 0x5555; + st->tx_seq &= 0xffff; + *buf = OFFSCOS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (st->tx_seq < 0x5555) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + st->phinc = dds_inc[st->tx_bit & 1]; + } + st->tx_seq += 0x5555; + st->tx_seq &= 0xffff; + *buf = COS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum) +{ + int sum = -0x80 * csum; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + sum += (st[-12] * coeff[12]); + sum += (st[-13] * coeff[13]); + + sum >>= 7; + return sum * sum; +} + +extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum) +{ + int sum = 0; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + sum += (st[-12] * coeff[12]); + sum += (st[-13] * coeff[13]); + + sum >>= 15; + return sum * sum; +} + +extern __inline__ int do_filter_2400_u8(const unsigned char *buf) +{ + int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); + sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); + sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); + sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); + return sum; +} + +extern __inline__ int do_filter_2400_s16(const short *buf) +{ + int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); + sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); + sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); + sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); + return sum; +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_2400_u8(buf); + st->dcd_shreg <<= 1; + st->bit_pll += AFSK24_BITPLL_INC; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) + st->bit_pll += AFSK24_BITPLL_INC/2; + else + st->bit_pll -= AFSK24_BITPLL_INC/2; + j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) + - hweight16(st->dcd_shreg & 0x1e0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, (((int)*buf)-0x80) << 8, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_2400_s16(buf); + st->dcd_shreg <<= 1; + st->bit_pll += AFSK24_BITPLL_INC; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) + st->bit_pll += AFSK24_BITPLL_INC/2; + else + st->bit_pll -= AFSK24_BITPLL_INC/2; + j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) + - hweight16(st->dcd_shreg & 0x1e0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, *buf, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_2400(struct sm_state *sm) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_afsk2400_8_tx = { + "afsk2400_8", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400, + modulator_2400_u8, modulator_2400_s16, NULL +}; + +const struct modem_rx_info sm_afsk2400_8_rx = { + "afsk2400_8", sizeof(struct demod_state_afsk24), + AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400, + demodulator_2400_u8, demodulator_2400_s16, demod_init_2400 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_fsk9600.c linux/drivers/net/hamradio/soundmodem/sm_fsk9600.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_fsk9600.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm_fsk9600.c Mon Jun 16 16:35:56 1997 @@ -0,0 +1,391 @@ +/*****************************************************************************/ + +/* + * sm_fsk9600.c -- soundcard radio modem driver, + * 9600 baud G3RUH compatible FSK modem + * + * 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. + * + */ + +#include "sm.h" +#include "sm_tbl_fsk9600.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_fsk96 { + unsigned int shreg; + unsigned long descram; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; +}; + +struct mod_state_fsk96 { + unsigned int shreg; + unsigned long scram; + unsigned char tx_bit; + unsigned char *txtbl; + unsigned int txphase; +}; + +/* --------------------------------------------------------------------- */ + +#define DESCRAM_TAP1 0x20000 +#define DESCRAM_TAP2 0x01000 +#define DESCRAM_TAP3 0x00001 + +#define DESCRAM_TAPSH1 17 +#define DESCRAM_TAPSH2 12 +#define DESCRAM_TAPSH3 0 + +#define SCRAM_TAP1 0x20000 /* X^17 */ +#define SCRAM_TAPN 0x00021 /* X^0+X^5 */ + +/* --------------------------------------------------------------------- */ + +static void modulator_9600_4_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); + + for (; buflen > 0; buflen--) { + if (!st->txphase++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff); + } + if (st->txphase >= 4) + st->txphase = 0; + *buf++ = *st->txtbl; + st->txtbl += 0x100; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_9600_4_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); + + for (; buflen > 0; buflen--) { + if (!st->txphase++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff); + } + if (st->txphase >= 4) + st->txphase = 0; + *buf++ = ((*st->txtbl)-0x80) << 8; + st->txtbl += 0x100; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_9600_4_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + unsigned char curbit; + unsigned int descx; + + for (; buflen > 0; buflen--, buf++) { + st->dcd_shreg <<= 1; + st->bit_pll += 0x4000; + curbit = (*buf >= 0x80); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < 0xa000]; + st->dcd_sum0 += 8 * hweight8(st->dcd_shreg & 0x0c) - + !!(st->dcd_shreg & 0x10); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, ((short)(*buf - 0x80)) << 8); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_9600_4_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + unsigned char curbit; + unsigned int descx; + + for (; buflen > 0; buflen--, buf++) { + st->dcd_shreg <<= 1; + st->bit_pll += 0x4000; + curbit = (*buf >= 0); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < 0xa000]; + st->dcd_sum0 += 8 * hweight8(st->dcd_shreg & 0x0c) - + !!(st->dcd_shreg & 0x10); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, *buf); + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_9600_5_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); + + for (; buflen > 0; buflen--) { + if (!st->txphase++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff); + } + if (st->txphase >= 5) + st->txphase = 0; + *buf++ = *st->txtbl; + st->txtbl += 0x100; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_9600_5_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); + + for (; buflen > 0; buflen--) { + if (!st->txphase++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff); + } + if (st->txphase >= 5) + st->txphase = 0; + *buf++ = ((*st->txtbl)-0x80)<<8; + st->txtbl += 0x100; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_9600_5_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + unsigned char curbit; + unsigned int descx; + + for (; buflen > 0; buflen--, buf++) { + st->dcd_shreg <<= 1; + st->bit_pll += 0x3333; + curbit = (*buf >= 0x80); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < 0x9999]; + st->dcd_sum0 += 16 * hweight8(st->dcd_shreg & 0x0c) - + hweight8(st->dcd_shreg & 0x70); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, ((short)(*buf - 0x80)) << 8); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_9600_5_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + unsigned char curbit; + unsigned int descx; + + for (; buflen > 0; buflen--, buf++) { + st->dcd_shreg <<= 1; + st->bit_pll += 0x3333; + curbit = (*buf >= 0); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < 0x9999]; + st->dcd_sum0 += 16 * hweight8(st->dcd_shreg & 0x0c) - + hweight8(st->dcd_shreg & 0x70); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, *buf); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_9600(struct sm_state *sm) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + + st->dcd_time = 240; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_fsk9600_4_tx = { + "fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600, + modulator_9600_4_u8, modulator_9600_4_s16, NULL +}; + +const struct modem_rx_info sm_fsk9600_4_rx = { + "fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 1, 4, + demodulator_9600_4_u8, demodulator_9600_4_s16, demod_init_9600 +}; + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_fsk9600_5_tx = { + "fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600, + modulator_9600_5_u8, modulator_9600_5_s16, NULL +}; + +const struct modem_rx_info sm_fsk9600_5_rx = { + "fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 1, 5, + demodulator_9600_5_u8, demodulator_9600_5_s16, demod_init_9600 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_hapn4800.c linux/drivers/net/hamradio/soundmodem/sm_hapn4800.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_hapn4800.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm_hapn4800.c Mon Jun 16 16:35:56 1997 @@ -0,0 +1,560 @@ +/*****************************************************************************/ + +/* + * sm_hapn4800.c -- soundcard radio modem driver, 4800 baud HAPN modem + * + * 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. + * + * + * This module implements a (hopefully) HAPN (Hamilton Area Packet + * Network) compatible 4800 baud modem. + * The HAPN modem uses kind of "duobinary signalling" (not really, + * duobinary signalling gives ... 0 0 -1 0 1 0 0 ... at the sampling + * instants, whereas HAPN signalling gives ... 0 0 -1 1 0 0 ..., see + * Proakis, Digital Communications). + * The code is untested. It is compatible with itself (i.e. it can decode + * the packets it sent), but I could not test if it is compatible with + * any "real" HAPN modem, since noone uses it in my region of the world. + * Feedback therefore welcome. + */ + +#include "sm.h" +#include "sm_tbl_hapn4800.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_hapn48 { + unsigned int shreg; + unsigned int bit_pll; + unsigned char last_bit; + unsigned char last_bit2; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; + int lvlhi, lvllo; +}; + +struct mod_state_hapn48 { + unsigned int shreg; + unsigned char tx_bit; + unsigned int tx_seq; + const unsigned char *tbl; +}; + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_10_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = ((*st->tbl)-0x80)<<8; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_8_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + st->tx_seq = 0; + *buf = ((*st->tbl)-0x80)<<8; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_pm10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_pm10_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = ((*st->tbl)-0x80)<<8; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_pm8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_pm8_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + st->tx_seq = 0; + *buf = ((*st->tbl)-0x80)<<8; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_hapn4800_10_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + static const int pll_corr[2] = { -0x800, 0x800 }; + int curst, cursync; + int inv; + + for (; buflen > 0; buflen--, buf++) { + inv = ((int)(buf[-2])-0x80) << 8; + st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ + st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ + if (inv > st->lvlhi) + st->lvlhi = inv; + if (inv < st->lvllo) + st->lvllo = inv; + if (buflen & 1) + st->dcd_shreg <<= 1; + st->bit_pll += 0x199a; + curst = cursync = 0; + if (inv > st->lvlhi >> 1) { + curst = 1; + cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && + buf[-2] > buf[-0] && buf[-2] > buf[-4]); + } else if (inv < st->lvllo >> 1) { + curst = -1; + cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && + buf[-2] < buf[-0] && buf[-2] < buf[-4]); + } + if (cursync) { + st->dcd_shreg |= cursync; + st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x8ccdu]; + st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x18c6318c) - + hweight32(st->dcd_shreg & 0xe739ce70); + } + hdlcdrv_channelbit(&sm->hdrv, cursync); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->last_bit2 = st->last_bit; + if (curst < 0) + st->last_bit = 0; + else if (curst > 0) + st->last_bit = 1; + st->shreg >>= 1; + st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, inv); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_hapn4800_10_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + static const int pll_corr[2] = { -0x800, 0x800 }; + int curst, cursync; + int inv; + + for (; buflen > 0; buflen--, buf++) { + inv = buf[-2]; + st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ + st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ + if (inv > st->lvlhi) + st->lvlhi = inv; + if (inv < st->lvllo) + st->lvllo = inv; + if (buflen & 1) + st->dcd_shreg <<= 1; + st->bit_pll += 0x199a; + curst = cursync = 0; + if (inv > st->lvlhi >> 1) { + curst = 1; + cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && + buf[-2] > buf[-0] && buf[-2] > buf[-4]); + } else if (inv < st->lvllo >> 1) { + curst = -1; + cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && + buf[-2] < buf[-0] && buf[-2] < buf[-4]); + } + if (cursync) { + st->dcd_shreg |= cursync; + st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x8ccdu]; + st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x18c6318c) - + hweight32(st->dcd_shreg & 0xe739ce70); + } + hdlcdrv_channelbit(&sm->hdrv, cursync); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->last_bit2 = st->last_bit; + if (curst < 0) + st->last_bit = 0; + else if (curst > 0) + st->last_bit = 1; + st->shreg >>= 1; + st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, inv); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_hapn4800_8_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + static const int pll_corr[2] = { -0x800, 0x800 }; + int curst, cursync; + int inv; + + for (; buflen > 0; buflen--, buf++) { + inv = ((int)(buf[-2])-0x80) << 8; + st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ + st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ + if (inv > st->lvlhi) + st->lvlhi = inv; + if (inv < st->lvllo) + st->lvllo = inv; + if (buflen & 1) + st->dcd_shreg <<= 1; + st->bit_pll += 0x2000; + curst = cursync = 0; + if (inv > st->lvlhi >> 1) { + curst = 1; + cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && + buf[-2] > buf[-0] && buf[-2] > buf[-4]); + } else if (inv < st->lvllo >> 1) { + curst = -1; + cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && + buf[-2] < buf[-0] && buf[-2] < buf[-4]); + } + if (cursync) { + st->dcd_shreg |= cursync; + st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x9000u]; + st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x44444444) - + hweight32(st->dcd_shreg & 0xbbbbbbbb); + } + hdlcdrv_channelbit(&sm->hdrv, cursync); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->last_bit2 = st->last_bit; + if (curst < 0) + st->last_bit = 0; + else if (curst > 0) + st->last_bit = 1; + st->shreg >>= 1; + st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, inv); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_hapn4800_8_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + static const int pll_corr[2] = { -0x800, 0x800 }; + int curst, cursync; + int inv; + + for (; buflen > 0; buflen--, buf++) { + inv = buf[-2]; + st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ + st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ + if (inv > st->lvlhi) + st->lvlhi = inv; + if (inv < st->lvllo) + st->lvllo = inv; + if (buflen & 1) + st->dcd_shreg <<= 1; + st->bit_pll += 0x2000; + curst = cursync = 0; + if (inv > st->lvlhi >> 1) { + curst = 1; + cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && + buf[-2] > buf[-0] && buf[-2] > buf[-4]); + } else if (inv < st->lvllo >> 1) { + curst = -1; + cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && + buf[-2] < buf[-0] && buf[-2] < buf[-4]); + } + if (cursync) { + st->dcd_shreg |= cursync; + st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x9000u]; + st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x44444444) - + hweight32(st->dcd_shreg & 0xbbbbbbbb); + } + hdlcdrv_channelbit(&sm->hdrv, cursync); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->last_bit2 = st->last_bit; + if (curst < 0) + st->last_bit = 0; + else if (curst > 0) + st->last_bit = 1; + st->shreg >>= 1; + st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, inv); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_hapn4800(struct sm_state *sm) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_hapn4800_8_tx = { + "hapn4800", sizeof(struct mod_state_hapn48), 38400, 4800, + modulator_hapn4800_8_u8, modulator_hapn4800_8_s16, NULL +}; + +const struct modem_rx_info sm_hapn4800_8_rx = { + "hapn4800", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8, + demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800 +}; + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_hapn4800_10_tx = { + "hapn4800", sizeof(struct mod_state_hapn48), 48000, 4800, + modulator_hapn4800_10_u8, modulator_hapn4800_10_s16, NULL +}; + +const struct modem_rx_info sm_hapn4800_10_rx = { + "hapn4800", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10, + demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800 +}; + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_hapn4800_pm8_tx = { + "hapn4800pm", sizeof(struct mod_state_hapn48), 38400, 4800, + modulator_hapn4800_pm8_u8, modulator_hapn4800_pm8_s16, NULL +}; + +const struct modem_rx_info sm_hapn4800_pm8_rx = { + "hapn4800pm", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8, + demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800 +}; + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_hapn4800_pm10_tx = { + "hapn4800pm", sizeof(struct mod_state_hapn48), 48000, 4800, + modulator_hapn4800_pm10_u8, modulator_hapn4800_pm10_s16, NULL +}; + +const struct modem_rx_info sm_hapn4800_pm10_rx = { + "hapn4800pm", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10, + demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_sbc.c linux/drivers/net/hamradio/soundmodem/sm_sbc.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_sbc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm_sbc.c Tue Aug 5 09:49:51 1997 @@ -0,0 +1,941 @@ +/*****************************************************************************/ + +/* + * sm_sbc.c -- soundcard radio modem driver soundblaster hardware 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sm.h" +#include "smdma.h" + +/* --------------------------------------------------------------------- */ + +/* + * 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 + +/* --------------------------------------------------------------------- */ + +struct sc_state_sbc { + unsigned char revhi, revlo; + unsigned char fmt[2]; + unsigned int sr[2]; +}; + +#define SCSTATE ((struct sc_state_sbc *)(&sm->hw)) + +/* --------------------------------------------------------------------- */ +/* + * the sbc converter's registers + */ +#define DSP_RESET(iobase) (iobase+0x6) +#define DSP_READ_DATA(iobase) (iobase+0xa) +#define DSP_WRITE_DATA(iobase) (iobase+0xc) +#define DSP_WRITE_STATUS(iobase) (iobase+0xc) +#define DSP_DATA_AVAIL(iobase) (iobase+0xe) +#define DSP_MIXER_ADDR(iobase) (iobase+0x4) +#define DSP_MIXER_DATA(iobase) (iobase+0x5) +#define DSP_INTACK_16BIT(iobase) (iobase+0xf) +#define SBC_EXTENT 16 + +/* --------------------------------------------------------------------- */ +/* + * SBC commands + */ +#define SBC_OUTPUT 0x14 +#define SBC_INPUT 0x24 +#define SBC_BLOCKSIZE 0x48 +#define SBC_HI_OUTPUT 0x91 +#define SBC_HI_INPUT 0x99 +#define SBC_LO_OUTPUT_AUTOINIT 0x1c +#define SBC_LO_INPUT_AUTOINIT 0x2c +#define SBC_HI_OUTPUT_AUTOINIT 0x90 +#define SBC_HI_INPUT_AUTOINIT 0x98 +#define SBC_IMMED_INT 0xf2 +#define SBC_GET_REVISION 0xe1 +#define ESS_GET_REVISION 0xe7 +#define SBC_SPEAKER_ON 0xd1 +#define SBC_SPEAKER_OFF 0xd3 +#define SBC_DMA_ON 0xd0 +#define SBC_DMA_OFF 0xd4 +#define SBC_SAMPLE_RATE 0x40 +#define SBC_SAMPLE_RATE_OUT 0x41 +#define SBC_SAMPLE_RATE_IN 0x42 +#define SBC_MONO_8BIT 0xa0 +#define SBC_MONO_16BIT 0xa4 +#define SBC_STEREO_8BIT 0xa8 +#define SBC_STEREO_16BIT 0xac + +#define SBC4_OUT8_AI 0xc6 +#define SBC4_IN8_AI 0xce +#define SBC4_MODE_UNS_MONO 0x00 +#define SBC4_MODE_SIGN_MONO 0x10 + +#define SBC4_OUT16_AI 0xb6 +#define SBC4_IN16_AI 0xbe + +/* --------------------------------------------------------------------- */ + +static int inline reset_dsp(struct device *dev) +{ + int i; + + outb(1, DSP_RESET(dev->base_addr)); + for (i = 0; i < 0x100; i++) + SLOW_DOWN_IO; + outb(0, DSP_RESET(dev->base_addr)); + for (i = 0; i < 0xffff; i++) + if (inb(DSP_DATA_AVAIL(dev->base_addr)) & 0x80) + if (inb(DSP_READ_DATA(dev->base_addr)) == 0xaa) + return 1; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static void inline write_dsp(struct device *dev, unsigned char data) +{ + int i; + + for (i = 0; i < 0xffff; i++) + if (!(inb(DSP_WRITE_STATUS(dev->base_addr)) & 0x80)) { + outb(data, DSP_WRITE_DATA(dev->base_addr)); + return; + } +} + +/* --------------------------------------------------------------------- */ + +static int inline read_dsp(struct device *dev, unsigned char *data) +{ + int i; + + if (!data) + return 0; + for (i = 0; i < 0xffff; i++) + if (inb(DSP_DATA_AVAIL(dev->base_addr)) & 0x80) { + *data = inb(DSP_READ_DATA(dev->base_addr)); + return 1; + } + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int config_resources(struct device *dev, struct sm_state *sm, int fdx) +{ + unsigned char irqreg = 0, dmareg = 0, realirq, realdma; + unsigned long flags; + + switch (dev->irq) { + case 2: + case 9: + irqreg |= 0x01; + break; + + case 5: + irqreg |= 0x02; + break; + + case 7: + irqreg |= 0x04; + break; + + case 10: + irqreg |= 0x08; + break; + + default: + return -ENODEV; + } + + switch (dev->dma) { + case 0: + dmareg |= 0x01; + break; + + case 1: + dmareg |= 0x02; + break; + + case 3: + dmareg |= 0x08; + break; + + default: + return -ENODEV; + } + + if (fdx) { + switch (sm->hdrv.ptt_out.dma2) { + case 5: + dmareg |= 0x20; + break; + + case 6: + dmareg |= 0x40; + break; + + case 7: + dmareg |= 0x80; + break; + + default: + return -ENODEV; + } + } + save_flags(flags); + cli(); + outb(0x80, DSP_MIXER_ADDR(dev->base_addr)); + outb(irqreg, DSP_MIXER_DATA(dev->base_addr)); + realirq = inb(DSP_MIXER_DATA(dev->base_addr)); + outb(0x81, DSP_MIXER_ADDR(dev->base_addr)); + outb(dmareg, DSP_MIXER_DATA(dev->base_addr)); + realdma = inb(DSP_MIXER_DATA(dev->base_addr)); + restore_flags(flags); + if ((~realirq) & irqreg || (~realdma) & dmareg) { + printk(KERN_ERR "%s: sbc resource registers cannot be set; PnP device " + "and IRQ/DMA specified wrongly?\n", sm_drvname); + return -EINVAL; + } + return 0; +} + +/* --------------------------------------------------------------------- */ + +static void inline sbc_int_ack_8bit(struct device *dev) +{ + inb(DSP_DATA_AVAIL(dev->base_addr)); +} + +/* --------------------------------------------------------------------- */ + +static void inline sbc_int_ack_16bit(struct device *dev) +{ + inb(DSP_INTACK_16BIT(dev->base_addr)); +} + +/* --------------------------------------------------------------------- */ + +static void setup_dma_dsp(struct device *dev, struct sm_state *sm, int send) +{ + unsigned long flags; + static const unsigned char sbcmode[2][2] = { + { SBC_LO_INPUT_AUTOINIT, SBC_LO_OUTPUT_AUTOINIT }, + { SBC_HI_INPUT_AUTOINIT, SBC_HI_OUTPUT_AUTOINIT } + }; + static const unsigned char sbc4mode[2] = { SBC4_IN8_AI, SBC4_OUT8_AI }; + static const unsigned char sbcskr[2] = { SBC_SPEAKER_OFF, SBC_SPEAKER_ON }; + unsigned int nsamps; + + send = !!send; + if (!reset_dsp(dev)) { + printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); + return; + } + save_flags(flags); + cli(); + sbc_int_ack_8bit(dev); + write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */ + write_dsp(dev, SCSTATE->fmt[send]); + write_dsp(dev, sbcskr[send]); + nsamps = dma_setup(sm, send, dev->dma) - 1; + sbc_int_ack_8bit(dev); + if (SCSTATE->revhi >= 4) { + write_dsp(dev, sbc4mode[send]); + write_dsp(dev, SBC4_MODE_UNS_MONO); + write_dsp(dev, nsamps & 0xff); + write_dsp(dev, nsamps >> 8); + } else { + write_dsp(dev, SBC_BLOCKSIZE); + write_dsp(dev, nsamps & 0xff); + write_dsp(dev, nsamps >> 8); + write_dsp(dev, sbcmode[SCSTATE->fmt[send] >= 180][send]); + /* hispeed mode if sample rate > 13kHz */ + } + restore_flags(flags); +} + +/* --------------------------------------------------------------------- */ + +static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct sm_state *sm = (struct sm_state *)dev->priv; + unsigned int curfrag; + + if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) + return; + cli(); + sbc_int_ack_8bit(dev); + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag); + enable_dma(dev->dma); + sm_int_freq(sm); + sti(); + if (sm->dma.ptt_cnt <= 0) { + dma_receive(sm, curfrag); + hdlcdrv_arbitrate(dev, &sm->hdrv); + if (hdlcdrv_ptt(&sm->hdrv)) { + /* starting to transmit */ + disable_dma(dev->dma); + hdlcdrv_transmitter(dev, &sm->hdrv); /* prefill HDLC buffer */ + dma_start_transmit(sm); + setup_dma_dsp(dev, sm, 1); + dma_transmit(sm); + } + } else if (dma_end_transmit(sm, curfrag)) { + /* stopping transmission */ + disable_dma(dev->dma); + sti(); + dma_init_receive(sm); + setup_dma_dsp(dev, sm, 0); + } else + dma_transmit(sm); + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); + +} + +/* --------------------------------------------------------------------- */ + +static int sbc_open(struct device *dev, struct sm_state *sm) +{ + int err; + unsigned int dmasz, u; + + if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) { + printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", + sizeof(struct sc_state_sbc), sizeof(sm->m)); + return -ENODEV; + } + if (!dev || !sm) + return -ENXIO; + if (dev->base_addr <= 0 || dev->base_addr > 0x1000-SBC_EXTENT || + dev->irq < 2 || dev->irq > 15 || dev->dma > 3) + return -ENXIO; + if (check_region(dev->base_addr, SBC_EXTENT)) + return -EACCES; + /* + * check if a card is available + */ + if (!reset_dsp(dev)) { + printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n", + sm_drvname, dev->base_addr); + return -ENODEV; + } + write_dsp(dev, SBC_GET_REVISION); + if (!read_dsp(dev, &SCSTATE->revhi) || + !read_dsp(dev, &SCSTATE->revlo)) + return -ENODEV; + printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, + SCSTATE->revhi, SCSTATE->revlo); + if (SCSTATE->revhi < 2) { + printk(KERN_ERR "%s: your card is an antiquity, at least DSP " + "rev 2.00 required\n", sm_drvname); + return -ENODEV; + } + if (SCSTATE->revhi < 3 && + (SCSTATE->fmt[0] >= 180 || SCSTATE->fmt[1] >= 180)) { + printk(KERN_ERR "%s: sbc io 0x%lx: DSP rev %d.%02d too " + "old, at least 3.00 required\n", sm_drvname, + dev->base_addr, SCSTATE->revhi, SCSTATE->revlo); + return -ENODEV; + } + if (SCSTATE->revhi >= 4 && + (err = config_resources(dev, sm, 0))) { + printk(KERN_ERR "%s: invalid IRQ and/or DMA specified\n", sm_drvname); + return err; + } + /* + * initialize some variables + */ + dma_init_receive(sm); + dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz; + u = NUM_FRAGMENTS * sm->dma.ofragsz; + if (u > dmasz) + dmasz = u; + if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA))) + return -ENOMEM; + dma_init_transmit(sm); + dma_init_receive(sm); + + memset(&sm->m, 0, sizeof(sm->m)); + memset(&sm->d, 0, sizeof(sm->d)); + if (sm->mode_tx->init) + sm->mode_tx->init(sm); + if (sm->mode_rx->init) + sm->mode_rx->init(sm); + + if (request_dma(dev->dma, sm->hwdrv->hw_name)) { + kfree_s(sm->dma.obuf, dmasz); + return -EBUSY; + } + if (request_irq(dev->irq, sbc_interrupt, SA_INTERRUPT, + sm->hwdrv->hw_name, dev)) { + free_dma(dev->dma); + kfree_s(sm->dma.obuf, dmasz); + return -EBUSY; + } + request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name); + setup_dma_dsp(dev, sm, 0); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sbc_close(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm) + return -EINVAL; + /* + * disable interrupts + */ + disable_dma(dev->dma); + reset_dsp(dev); + free_irq(dev->irq, dev); + free_dma(dev->dma); + release_region(dev->base_addr, SBC_EXTENT); + kfree(sm->dma.obuf); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, '.'); + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp; + + if (!strcmp(mode, "off")) { + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return 0; + } + if (cp) + *cp++ = '\0'; + else + cp = mode; + for (; *mtp; mtp++) { + if ((*mtp)->loc_storage > sizeof(sm->m)) { + printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", + sm_drvname, (*mtp)->name, (*mtp)->loc_storage); + continue; + } + if (!(*mtp)->name || strcmp((*mtp)->name, mode)) + continue; + if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100) + continue; + if (!(*mtp)->modulator_u8) + continue; + for (mrp = sm_modem_rx_table; *mrp; mrp++) { + if ((*mrp)->loc_storage > sizeof(sm->d)) { + printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", + sm_drvname, (*mrp)->name, (*mrp)->loc_storage); + continue; + } + if (!(*mrp)->demodulator_u8) + continue; + if ((*mrp)->name && !strcmp((*mrp)->name, cp) && + (*mrp)->srate >= 5000 && (*mrp)->srate <= 44100) { + sm->mode_tx = *mtp; + sm->mode_rx = *mrp; + SCSTATE->fmt[0] = 256-((1000000L+sm->mode_rx->srate/2)/ + sm->mode_rx->srate); + SCSTATE->fmt[1] = 256-((1000000L+sm->mode_tx->srate/2)/ + sm->mode_tx->srate); + sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; + sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; + if (sm->dma.ifragsz < sm->mode_rx->overlap) + sm->dma.ifragsz = sm->mode_rx->overlap; + sm->dma.i16bit = sm->dma.o16bit = 0; + return 0; + } + } + } + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int sbc_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct sm_ioctl bi; + unsigned long flags; + int i; + + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + + if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | + HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | + HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; + + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + + switch (bi.cmd) { + default: + return -ENOIOCTLCMD; + + case SMCTL_GETMIXER: + i = 0; + bi.data.mix.sample_rate = sm->mode_rx->srate; + bi.data.mix.bit_rate = sm->hdrv.par.bitrate; + bi.data.mix.mixer_type = SM_MIXER_INVALID; + switch (SCSTATE->revhi) { + case 2: + bi.data.mix.mixer_type = SM_MIXER_CT1335; + break; + case 3: + bi.data.mix.mixer_type = SM_MIXER_CT1345; + break; + case 4: + bi.data.mix.mixer_type = SM_MIXER_CT1745; + break; + } + if (bi.data.mix.mixer_type != SM_MIXER_INVALID && + bi.data.mix.reg < 0x80) { + save_flags(flags); + cli(); + outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); + bi.data.mix.data = inb(DSP_MIXER_DATA(dev->base_addr)); + restore_flags(flags); + i = 1; + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return i; + + case SMCTL_SETMIXER: + if (!suser()) + return -EACCES; + switch (SCSTATE->revhi) { + case 2: + if (bi.data.mix.mixer_type != SM_MIXER_CT1335) + return -EINVAL; + break; + case 3: + if (bi.data.mix.mixer_type != SM_MIXER_CT1345) + return -EINVAL; + break; + case 4: + if (bi.data.mix.mixer_type != SM_MIXER_CT1745) + return -EINVAL; + break; + default: + return -ENODEV; + } + if (bi.data.mix.reg >= 0x80) + return -EACCES; + save_flags(flags); + cli(); + outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); + outb(bi.data.mix.data, DSP_MIXER_DATA(dev->base_addr)); + restore_flags(flags); + return 0; + + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + +} + +/* --------------------------------------------------------------------- */ + +const struct hardware_info sm_hw_sbc = { + "sbc", sizeof(struct sc_state_sbc), + sbc_open, sbc_close, sbc_ioctl, sbc_sethw +}; + +/* --------------------------------------------------------------------- */ + +static void setup_dma_fdx_dsp(struct device *dev, struct sm_state *sm) +{ + unsigned long flags; + unsigned int isamps, osamps; + + if (!reset_dsp(dev)) { + printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); + return; + } + save_flags(flags); + cli(); + sbc_int_ack_8bit(dev); + sbc_int_ack_16bit(dev); + /* should eventually change to set rates individually by SBC_SAMPLE_RATE_{IN/OUT} */ + write_dsp(dev, SBC_SAMPLE_RATE_IN); + write_dsp(dev, SCSTATE->sr[0] >> 8); + write_dsp(dev, SCSTATE->sr[0] & 0xff); + write_dsp(dev, SBC_SAMPLE_RATE_OUT); + write_dsp(dev, SCSTATE->sr[1] >> 8); + write_dsp(dev, SCSTATE->sr[1] & 0xff); + write_dsp(dev, SBC_SPEAKER_ON); + if (sm->dma.o16bit) { + /* + * DMA channel 1 (8bit) does input (capture), + * DMA channel 2 (16bit) does output (playback) + */ + isamps = dma_setup(sm, 0, dev->dma) - 1; + osamps = dma_setup(sm, 1, sm->hdrv.ptt_out.dma2) - 1; + sbc_int_ack_8bit(dev); + sbc_int_ack_16bit(dev); + write_dsp(dev, SBC4_IN8_AI); + write_dsp(dev, SBC4_MODE_UNS_MONO); + write_dsp(dev, isamps & 0xff); + write_dsp(dev, isamps >> 8); + write_dsp(dev, SBC4_OUT16_AI); + write_dsp(dev, SBC4_MODE_SIGN_MONO); + write_dsp(dev, osamps & 0xff); + write_dsp(dev, osamps >> 8); + } else { + /* + * DMA channel 1 (8bit) does output (playback), + * DMA channel 2 (16bit) does input (capture) + */ + isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1; + osamps = dma_setup(sm, 1, dev->dma) - 1; + sbc_int_ack_8bit(dev); + sbc_int_ack_16bit(dev); + write_dsp(dev, SBC4_OUT8_AI); + write_dsp(dev, SBC4_MODE_UNS_MONO); + write_dsp(dev, osamps & 0xff); + write_dsp(dev, osamps >> 8); + write_dsp(dev, SBC4_IN16_AI); + write_dsp(dev, SBC4_MODE_SIGN_MONO); + write_dsp(dev, isamps & 0xff); + write_dsp(dev, isamps >> 8); + } + dma_init_receive(sm); + dma_init_transmit(sm); + restore_flags(flags); +} + +/* --------------------------------------------------------------------- */ + +static void sbcfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct sm_state *sm = (struct sm_state *)dev->priv; + unsigned char intsrc, pbint = 0, captint = 0; + unsigned int ocfrag, icfrag; + unsigned long flags; + + if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) + return; + save_flags(flags); + cli(); + outb(0x82, DSP_MIXER_ADDR(dev->base_addr)); + intsrc = inb(DSP_MIXER_DATA(dev->base_addr)); + if (intsrc & 0x01) { + sbc_int_ack_8bit(dev); + if (sm->dma.o16bit) { + captint = 1; + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + dma_ptr(sm, 0, dev->dma, &icfrag); + enable_dma(dev->dma); + } else { + pbint = 1; + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + dma_ptr(sm, 1, dev->dma, &ocfrag); + enable_dma(dev->dma); + } + } + if (intsrc & 0x02) { + sbc_int_ack_16bit(dev); + if (sm->dma.o16bit) { + pbint = 1; + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + dma_ptr(sm, 1, sm->hdrv.ptt_out.dma2, &ocfrag); + enable_dma(sm->hdrv.ptt_out.dma2); + } else { + captint = 1; + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag); + enable_dma(sm->hdrv.ptt_out.dma2); + } + } + restore_flags(flags); + sm_int_freq(sm); + sti(); + if (pbint) { + if (dma_end_transmit(sm, ocfrag)) + dma_clear_transmit(sm); + dma_transmit(sm); + } + if (captint) { + dma_receive(sm, icfrag); + hdlcdrv_arbitrate(dev, &sm->hdrv); + } + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); +} + +/* --------------------------------------------------------------------- */ + +static int sbcfdx_open(struct device *dev, struct sm_state *sm) +{ + int err; + + if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) { + printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", + sizeof(struct sc_state_sbc), sizeof(sm->m)); + return -ENODEV; + } + if (!dev || !sm) + return -ENXIO; + if (dev->base_addr <= 0 || dev->base_addr > 0x1000-SBC_EXTENT || + dev->irq < 2 || dev->irq > 15 || dev->dma > 3) + return -ENXIO; + if (check_region(dev->base_addr, SBC_EXTENT)) + return -EACCES; + /* + * check if a card is available + */ + if (!reset_dsp(dev)) { + printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n", + sm_drvname, dev->base_addr); + return -ENODEV; + } + write_dsp(dev, SBC_GET_REVISION); + if (!read_dsp(dev, &SCSTATE->revhi) || + !read_dsp(dev, &SCSTATE->revlo)) + return -ENODEV; + printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, + SCSTATE->revhi, SCSTATE->revlo); + if (SCSTATE->revhi < 4) { + printk(KERN_ERR "%s: at least DSP rev 4.00 required\n", sm_drvname); + return -ENODEV; + } + if ((err = config_resources(dev, sm, 1))) { + printk(KERN_ERR "%s: invalid IRQ and/or DMA specified\n", sm_drvname); + return err; + } + /* + * initialize some variables + */ + if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA))) + return -ENOMEM; + if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) { + kfree(sm->dma.ibuf); + return -ENOMEM; + } + dma_init_transmit(sm); + dma_init_receive(sm); + + memset(&sm->m, 0, sizeof(sm->m)); + memset(&sm->d, 0, sizeof(sm->d)); + if (sm->mode_tx->init) + sm->mode_tx->init(sm); + if (sm->mode_rx->init) + sm->mode_rx->init(sm); + + if (request_dma(dev->dma, sm->hwdrv->hw_name)) { + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); + return -EBUSY; + } + if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); + free_dma(dev->dma); + return -EBUSY; + } + if (request_irq(dev->irq, sbcfdx_interrupt, SA_INTERRUPT, + sm->hwdrv->hw_name, dev)) { + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); + free_dma(dev->dma); + free_dma(sm->hdrv.ptt_out.dma2); + return -EBUSY; + } + request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name); + setup_dma_fdx_dsp(dev, sm); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sbcfdx_close(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm) + return -EINVAL; + /* + * disable interrupts + */ + disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); + reset_dsp(dev); + free_irq(dev->irq, dev); + free_dma(dev->dma); + free_dma(sm->hdrv.ptt_out.dma2); + release_region(dev->base_addr, SBC_EXTENT); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sbcfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, '.'); + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp; + + if (!strcmp(mode, "off")) { + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return 0; + } + if (cp) + *cp++ = '\0'; + else + cp = mode; + for (; *mtp; mtp++) { + if ((*mtp)->loc_storage > sizeof(sm->m)) { + printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", + sm_drvname, (*mtp)->name, (*mtp)->loc_storage); + continue; + } + if (!(*mtp)->name || strcmp((*mtp)->name, mode)) + continue; + if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100) + continue; + for (mrp = sm_modem_rx_table; *mrp; mrp++) { + if ((*mrp)->loc_storage > sizeof(sm->d)) { + printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", + sm_drvname, (*mrp)->name, (*mrp)->loc_storage); + continue; + } + if ((*mrp)->name && !strcmp((*mrp)->name, cp) && + (*mtp)->srate >= 5000 && (*mtp)->srate <= 44100 && + (*mrp)->srate == (*mtp)->srate) { + sm->mode_tx = *mtp; + sm->mode_rx = *mrp; + SCSTATE->sr[0] = sm->mode_rx->srate; + SCSTATE->sr[1] = sm->mode_tx->srate; + sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; + sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; + if (sm->dma.ifragsz < sm->mode_rx->overlap) + sm->dma.ifragsz = sm->mode_rx->overlap; + if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_u8) { + sm->dma.i16bit = 1; + sm->dma.o16bit = 0; + sm->dma.ifragsz <<= 1; + } else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_s16) { + sm->dma.i16bit = 0; + sm->dma.o16bit = 1; + sm->dma.ofragsz <<= 1; + } else { + printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, + sm->mode_rx->name, sm->mode_tx->name); + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return -EINVAL; + } + return 0; + } + } + } + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int sbcfdx_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + + if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | + HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_DMA2 | HDLCDRV_PARMASK_SERIOBASE | + HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; + + return sbc_ioctl(dev, sm, ifr, hi, cmd); +} + +/* --------------------------------------------------------------------- */ + +const struct hardware_info sm_hw_sbcfdx = { + "sbcfdx", sizeof(struct sc_state_sbc), + sbcfdx_open, sbcfdx_close, sbcfdx_ioctl, sbcfdx_sethw +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_wss.c linux/drivers/net/hamradio/soundmodem/sm_wss.c --- v2.1.70/linux/drivers/net/hamradio/soundmodem/sm_wss.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/sm_wss.c Tue Aug 5 09:49:51 1997 @@ -0,0 +1,965 @@ +/*****************************************************************************/ + +/* + * sm_wss.c -- soundcard radio modem driver, WSS (half duplex) 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sm.h" +#include "smdma.h" + +/* --------------------------------------------------------------------- */ + +/* + * 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 + +/* --------------------------------------------------------------------- */ + +struct sc_state_wss { + unsigned char revwss, revid, revv, revcid; + unsigned char fmt[2]; + unsigned char crystal; +}; + +#define SCSTATE ((struct sc_state_wss *)(&sm->hw)) + +/* --------------------------------------------------------------------- */ + +#define WSS_CONFIG(iobase) (iobase+0) +#define WSS_STATUS(iobase) (iobase+3) +#define WSS_CODEC_IA(iobase) (iobase+4) +#define WSS_CODEC_ID(iobase) (iobase+5) +#define WSS_CODEC_STATUS(iobase) (iobase+6) +#define WSS_CODEC_DATA(iobase) (iobase+7) + +#define WSS_EXTENT 8 + +#define CS423X_HOTFIX + +/* --------------------------------------------------------------------- */ + +static void write_codec(struct device *dev, unsigned char idx, + unsigned char data) +{ + int timeout = 900000; + + /* wait until codec ready */ + while (timeout > 0 && inb(WSS_CODEC_IA(dev->base_addr)) & 0x80) + timeout--; + outb(idx, WSS_CODEC_IA(dev->base_addr)); + outb(data, WSS_CODEC_ID(dev->base_addr)); +} + + +/* --------------------------------------------------------------------- */ + +static unsigned char read_codec(struct device *dev, unsigned char idx) +{ + int timeout = 900000; + + /* wait until codec ready */ + while (timeout > 0 && inb(WSS_CODEC_IA(dev->base_addr)) & 0x80) + timeout--; + outb(idx & 0x1f, WSS_CODEC_IA(dev->base_addr)); + return inb(WSS_CODEC_ID(dev->base_addr)); +} + +/* --------------------------------------------------------------------- */ + +extern void inline wss_ack_int(struct device *dev) +{ + outb(0, WSS_CODEC_STATUS(dev->base_addr)); +} + +/* --------------------------------------------------------------------- */ + +static int wss_srate_tab[16] = { + 8000, 5510, 16000, 11025, 27420, 18900, 32000, 22050, + -1, 37800, -1, 44100, 48000, 33075, 9600, 6620 +}; + +static int wss_srate_index(int srate) +{ + int i; + + for (i = 0; i < (sizeof(wss_srate_tab)/sizeof(wss_srate_tab[0])); i++) + if (srate == wss_srate_tab[i] && wss_srate_tab[i] > 0) + return i; + return -1; +} + +/* --------------------------------------------------------------------- */ + +static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, unsigned char fmt, + unsigned char fmt2, char fdx, char fullcalib) +{ + unsigned long time; + unsigned long flags; + + save_flags(flags); + cli(); + /* Clock and data format register */ + write_codec(dev, 0x48, fmt); + if (SCSTATE->crystal) { + write_codec(dev, 0x5c, fmt2 & 0xf0); + /* MCE and interface config reg */ + write_codec(dev, 0x49, (fdx ? 0 : 0x4) | (fullcalib ? 0x18 : 0)); + } else + /* MCE and interface config reg */ + write_codec(dev, 0x49, fdx ? 0x8 : 0xc); + outb(0xb, WSS_CODEC_IA(dev->base_addr)); /* leave MCE */ + if (SCSTATE->crystal && !fullcalib) + return 0; + /* + * wait for ACI start + */ + time = 1000; + while (!(read_codec(dev, 0x0b) & 0x20)) + if (!(--time)) { + printk(KERN_WARNING "%s: ad1848 auto calibration timed out (1)\n", + sm_drvname); + restore_flags(flags); + return -1; + } + /* + * wait for ACI end + */ + sti(); + time = jiffies + HZ/4; + while ((read_codec(dev, 0x0b) & 0x20) && ((signed)(jiffies - time) < 0)); + restore_flags(flags); + if ((signed)(jiffies - time) >= 0) { + printk(KERN_WARNING "%s: ad1848 auto calibration timed out (2)\n", + sm_drvname); + return -1; + } + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wss_init_codec(struct device *dev, struct sm_state *sm, char fdx, + unsigned char src_l, unsigned char src_r, + int igain_l, int igain_r, + int ogain_l, int ogain_r) +{ + unsigned char tmp, reg0, reg1, reg6, reg7; + static const signed char irqtab[16] = + { -1, -1, 0x10, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20, -1, -1, + -1, -1 }; + static const signed char dmatab[4] = { 1, 2, -1, 3 }; + + tmp = inb(WSS_STATUS(dev->base_addr)); + if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x00 && + (tmp & 0x3f) != 0x0f) { + printk(KERN_WARNING "sm: WSS card id register not found, " + "address 0x%lx, ID register 0x%02x\n", + dev->base_addr, (int)tmp); + /* return -1; */ + SCSTATE->revwss = 0; + } else { + if ((tmp & 0x80) && ((dev->dma == 0) || + ((dev->irq >= 8) && (dev->irq != 9)))) { + printk(KERN_ERR "%s: WSS: DMA0 and/or IRQ8..IRQ15 " + "(except IRQ9) cannot be used on an 8bit " + "card\n", sm_drvname); + return -1; + } + if (dev->irq > 15 || irqtab[dev->irq] == -1) { + printk(KERN_ERR "%s: WSS: invalid interrupt %d\n", + sm_drvname, (int)dev->irq); + return -1; + } + if (dev->dma > 3 || dmatab[dev->dma] == -1) { + printk(KERN_ERR "%s: WSS: invalid dma channel %d\n", + sm_drvname, (int)dev->dma); + return -1; + } + tmp = irqtab[dev->irq] | dmatab[dev->dma]; + /* irq probe */ + outb((tmp & 0x38) | 0x40, WSS_CONFIG(dev->base_addr)); + if (!(inb(WSS_STATUS(dev->base_addr)) & 0x40)) { + outb(0, WSS_CONFIG(dev->base_addr)); + printk(KERN_ERR "%s: WSS: IRQ%d is not free!\n", + sm_drvname, dev->irq); + } + outb(tmp, WSS_CONFIG(dev->base_addr)); + SCSTATE->revwss = inb(WSS_STATUS(dev->base_addr)) & 0x3f; + } + /* + * initialize the codec + */ + if (igain_l < 0) + igain_l = 0; + if (igain_r < 0) + igain_r = 0; + if (ogain_l > 0) + ogain_l = 0; + if (ogain_r > 0) + ogain_r = 0; + reg0 = (src_l << 6) & 0xc0; + reg1 = (src_r << 6) & 0xc0; + if (reg0 == 0x80 && igain_l >= 20) { + reg0 |= 0x20; + igain_l -= 20; + } + if (reg1 == 0x80 && igain_r >= 20) { + reg1 |= 0x20; + igain_r -= 20; + } + if (igain_l > 23) + igain_l = 23; + if (igain_r > 23) + igain_r = 23; + reg0 |= igain_l * 2 / 3; + reg1 |= igain_r * 2 / 3; + reg6 = (ogain_l < -95) ? 0x80 : (ogain_l * (-2) / 3); + reg7 = (ogain_r < -95) ? 0x80 : (ogain_r * (-2) / 3); + write_codec(dev, 9, 0); + write_codec(dev, 0, 0x45); + if (read_codec(dev, 0) != 0x45) + goto codec_err; + write_codec(dev, 0, 0xaa); + if (read_codec(dev, 0) != 0xaa) + goto codec_err; + write_codec(dev, 12, 0x40); /* enable MODE2 */ + write_codec(dev, 16, 0); + write_codec(dev, 0, 0x45); + SCSTATE->crystal = (read_codec(dev, 16) != 0x45); + write_codec(dev, 0, 0xaa); + SCSTATE->crystal &= (read_codec(dev, 16) != 0xaa); + if (SCSTATE->crystal) { + SCSTATE->revcid = read_codec(dev, 0x19); + SCSTATE->revv = (SCSTATE->revcid >> 5) & 7; + SCSTATE->revcid &= 7; + write_codec(dev, 0x10, 0x80); /* maximum output level */ + write_codec(dev, 0x11, 0x02); /* xtal enable and no HPF */ + write_codec(dev, 0x12, 0x80); /* left line input control */ + write_codec(dev, 0x13, 0x80); /* right line input control */ + write_codec(dev, 0x16, 0); /* disable alternative freq sel */ + write_codec(dev, 0x1a, 0xe0); /* mono IO disable */ + write_codec(dev, 0x1b, 0x00); /* left out no att */ + write_codec(dev, 0x1d, 0x00); /* right out no att */ + } + + if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], SCSTATE->fmt[0], fdx, 1)) + goto codec_err; + + write_codec(dev, 0, reg0); /* left input control */ + write_codec(dev, 1, reg1); /* right input control */ + write_codec(dev, 2, 0x80); /* left aux#1 input control */ + write_codec(dev, 3, 0x80); /* right aux#1 input control */ + write_codec(dev, 4, 0x80); /* left aux#2 input control */ + write_codec(dev, 5, 0x80); /* right aux#2 input control */ + write_codec(dev, 6, reg6); /* left dac control */ + write_codec(dev, 7, reg7); /* right dac control */ + write_codec(dev, 0xa, 0x2); /* pin control register */ + write_codec(dev, 0xd, 0x0); /* digital mix control */ + SCSTATE->revid = read_codec(dev, 0xc) & 0xf; + /* + * print revisions + */ + if (SCSTATE->crystal) + printk(KERN_INFO "%s: Crystal CODEC ID %d, Chip revision %d, " + " Chip ID %d\n", sm_drvname, (int)SCSTATE->revid, + (int)SCSTATE->revv, (int)SCSTATE->revcid); + else + printk(KERN_INFO "%s: WSS revision %d, CODEC revision %d\n", + sm_drvname, (int)SCSTATE->revwss, + (int)SCSTATE->revid); + return 0; + codec_err: + outb(0, WSS_CONFIG(dev->base_addr)); + printk(KERN_ERR "%s: no WSS soundcard found at address 0x%lx\n", + sm_drvname, dev->base_addr); + return -1; +} + +/* --------------------------------------------------------------------- */ + +static void setup_dma_wss(struct device *dev, struct sm_state *sm, int send) +{ + unsigned long flags; + static const unsigned char codecmode[2] = { 0x0e, 0x0d }; + unsigned char oldcodecmode; + long abrt; + unsigned char fmt; + unsigned int numsamps; + + send = !!send; + fmt = SCSTATE->fmt[send]; + save_flags(flags); + cli(); + /* + * perform the final DMA sequence to disable the codec request + */ + oldcodecmode = read_codec(dev, 9); + write_codec(dev, 9, 0xc); /* disable codec */ + wss_ack_int(dev); + if (read_codec(dev, 11) & 0x10) { + dma_setup(sm, oldcodecmode & 1, dev->dma); + abrt = 0; + while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000)); + } +#ifdef CS423X_HOTFIX + if (read_codec(dev, 0x8) != fmt || SCSTATE->crystal) + wss_set_codec_fmt(dev, sm, fmt, fmt, 0, 0); +#else /* CS423X_HOTFIX */ + if (read_codec(dev, 0x8) != fmt) + wss_set_codec_fmt(dev, sm, fmt, fmt, 0, 0); +#endif /* CS423X_HOTFIX */ + numsamps = dma_setup(sm, send, dev->dma) - 1; + write_codec(dev, 15, numsamps & 0xff); + write_codec(dev, 14, numsamps >> 8); + write_codec(dev, 9, codecmode[send]); + restore_flags(flags); +} + +/* --------------------------------------------------------------------- */ + +static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct sm_state *sm = (struct sm_state *)dev->priv; + unsigned int curfrag; + unsigned int nums; + + if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || + sm->hdrv.magic != HDLCDRV_MAGIC) + return; + cli(); + wss_ack_int(dev); + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + nums = dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag) - 1; + write_codec(dev, 15, nums & 0xff); + write_codec(dev, 14, nums >> 8); + enable_dma(dev->dma); + sm_int_freq(sm); + sti(); + if (sm->dma.ptt_cnt <= 0) { + dma_receive(sm, curfrag); + hdlcdrv_arbitrate(dev, &sm->hdrv); + if (hdlcdrv_ptt(&sm->hdrv)) { + /* starting to transmit */ + disable_dma(dev->dma); + hdlcdrv_transmitter(dev, &sm->hdrv); /* prefill HDLC buffer */ + dma_start_transmit(sm); + setup_dma_wss(dev, sm, 1); + dma_transmit(sm); + } + } else if (dma_end_transmit(sm, curfrag)) { + /* stopping transmission */ + disable_dma(dev->dma); + dma_init_receive(sm); + setup_dma_wss(dev, sm, 0); + } else + dma_transmit(sm); + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); +} + +/* --------------------------------------------------------------------- */ + +static int wss_open(struct device *dev, struct sm_state *sm) +{ + unsigned int dmasz, u; + + if (sizeof(sm->m) < sizeof(struct sc_state_wss)) { + printk(KERN_ERR "sm wss: wss state too big: %d > %d\n", + sizeof(struct sc_state_wss), sizeof(sm->m)); + return -ENODEV; + } + if (!dev || !sm || !sm->mode_rx || !sm->mode_tx) + return -ENXIO; + if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || + dev->irq < 2 || dev->irq > 15 || dev->dma > 3) + return -ENXIO; + if (check_region(dev->base_addr, WSS_EXTENT)) + return -EACCES; + /* + * check if a card is available + */ + if (wss_init_codec(dev, sm, 0, 1, 1, 0, 0, -45, -45)) + return -ENODEV; + /* + * initialize some variables + */ + dma_init_receive(sm); + dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz; + u = NUM_FRAGMENTS * sm->dma.ofragsz; + if (u > dmasz) + dmasz = u; + if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA))) + return -ENOMEM; + dma_init_transmit(sm); + dma_init_receive(sm); + + memset(&sm->m, 0, sizeof(sm->m)); + memset(&sm->d, 0, sizeof(sm->d)); + if (sm->mode_tx->init) + sm->mode_tx->init(sm); + if (sm->mode_rx->init) + sm->mode_rx->init(sm); + + if (request_dma(dev->dma, sm->hwdrv->hw_name)) { + kfree_s(sm->dma.obuf, dmasz); + return -EBUSY; + } + if (request_irq(dev->irq, wss_interrupt, SA_INTERRUPT, + sm->hwdrv->hw_name, dev)) { + free_dma(dev->dma); + kfree_s(sm->dma.obuf, dmasz); + return -EBUSY; + } + request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); + setup_dma_wss(dev, sm, 0); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wss_close(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm) + return -EINVAL; + /* + * disable interrupts + */ + disable_dma(dev->dma); + write_codec(dev, 9, 0xc); /* disable codec */ + free_irq(dev->irq, dev); + free_dma(dev->dma); + release_region(dev->base_addr, WSS_EXTENT); + kfree(sm->dma.obuf); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wss_sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, '.'); + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp; + int i, j; + + if (!strcmp(mode, "off")) { + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return 0; + } + if (cp) + *cp++ = '\0'; + else + cp = mode; + for (; *mtp; mtp++) { + if ((*mtp)->loc_storage > sizeof(sm->m)) { + printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", + sm_drvname, (*mtp)->name, (*mtp)->loc_storage); + continue; + } + if (!(*mtp)->name || strcmp((*mtp)->name, mode)) + continue; + if ((i = wss_srate_index((*mtp)->srate)) < 0) + continue; + for (mrp = sm_modem_rx_table; *mrp; mrp++) { + if ((*mrp)->loc_storage > sizeof(sm->d)) { + printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", + sm_drvname, (*mrp)->name, (*mrp)->loc_storage); + continue; + } + if ((*mrp)->name && !strcmp((*mrp)->name, cp) && + ((j = wss_srate_index((*mrp)->srate)) >= 0)) { + sm->mode_tx = *mtp; + sm->mode_rx = *mrp; + SCSTATE->fmt[0] = j; + SCSTATE->fmt[1] = i; + sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; + sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; + if (sm->dma.ifragsz < sm->mode_rx->overlap) + sm->dma.ifragsz = sm->mode_rx->overlap; + /* prefer same data format if possible to minimize switching times */ + sm->dma.i16bit = sm->dma.o16bit = 2; + if (sm->mode_rx->srate == sm->mode_tx->srate) { + if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_s16) + sm->dma.i16bit = sm->dma.o16bit = 1; + else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_u8) + sm->dma.i16bit = sm->dma.o16bit = 0; + } + if (sm->dma.i16bit == 2) { + if (sm->mode_rx->demodulator_s16) + sm->dma.i16bit = 1; + else if (sm->mode_rx->demodulator_u8) + sm->dma.i16bit = 0; + } + if (sm->dma.o16bit == 2) { + if (sm->mode_tx->modulator_s16) + sm->dma.o16bit = 1; + else if (sm->mode_tx->modulator_u8) + sm->dma.o16bit = 0; + } + if (sm->dma.i16bit == 2 || sm->dma.o16bit == 2) { + printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, + sm->mode_rx->name, sm->mode_tx->name); + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return -EINVAL; + } +#ifdef __BIG_ENDIAN + /* big endian 16bit only works on crystal cards... */ + if (sm->dma.i16bit) { + SCSTATE->fmt[0] |= 0xc0; + sm->dma.ifragsz <<= 1; + } + if (sm->dma.o16bit) { + SCSTATE->fmt[1] |= 0xc0; + sm->dma.ofragsz <<= 1; + } +#else /* __BIG_ENDIAN */ + if (sm->dma.i16bit) { + SCSTATE->fmt[0] |= 0x40; + sm->dma.ifragsz <<= 1; + } + if (sm->dma.o16bit) { + SCSTATE->fmt[1] |= 0x40; + sm->dma.ofragsz <<= 1; + } +#endif /* __BIG_ENDIAN */ + return 0; + } + } + } + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int wss_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct sm_ioctl bi; + int i; + + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + + if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | + HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | + HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; + + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + + switch (bi.cmd) { + default: + return -ENOIOCTLCMD; + + case SMCTL_GETMIXER: + i = 0; + bi.data.mix.sample_rate = sm->mode_rx->srate; + bi.data.mix.bit_rate = sm->hdrv.par.bitrate; + bi.data.mix.mixer_type = SCSTATE->crystal ? + SM_MIXER_CRYSTAL : SM_MIXER_AD1848; + if (((SCSTATE->crystal ? 0x2c0c20fflu: 0x20fflu) + >> bi.data.mix.reg) & 1) { + bi.data.mix.data = read_codec(dev, bi.data.mix.reg); + i = 1; + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return i; + + case SMCTL_SETMIXER: + if (!suser()) + return -EACCES; + if ((bi.data.mix.mixer_type != SM_MIXER_CRYSTAL || + !SCSTATE->crystal) && + (bi.data.mix.mixer_type != SM_MIXER_AD1848 || + bi.data.mix.reg >= 0x10)) + return -EINVAL; + if (!((0x2c0c20fflu >> bi.data.mix.reg) & 1)) + return -EACCES; + write_codec(dev, bi.data.mix.reg, bi.data.mix.data); + return 0; + + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + +} + +/* --------------------------------------------------------------------- */ + +const struct hardware_info sm_hw_wss = { + "wss", sizeof(struct sc_state_wss), + wss_open, wss_close, wss_ioctl, wss_sethw +}; + +/* --------------------------------------------------------------------- */ + +static void setup_fdx_dma_wss(struct device *dev, struct sm_state *sm) +{ + unsigned long flags; + unsigned char oldcodecmode, codecdma; + long abrt; + unsigned int osamps, isamps; + + save_flags(flags); + cli(); + /* + * perform the final DMA sequence to disable the codec request + */ + oldcodecmode = read_codec(dev, 9); + write_codec(dev, 9, 0); /* disable codec DMA */ + wss_ack_int(dev); + if ((codecdma = read_codec(dev, 11)) & 0x10) { + dma_setup(sm, 1, dev->dma); + dma_setup(sm, 0, sm->hdrv.ptt_out.dma2); + abrt = 0; + while (((codecdma = read_codec(dev, 11)) & 0x10) || ((++abrt) >= 0x10000)); + } + wss_set_codec_fmt(dev, sm, SCSTATE->fmt[1], SCSTATE->fmt[0], 1, 1); + osamps = dma_setup(sm, 1, dev->dma) - 1; + isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1; + write_codec(dev, 15, osamps & 0xff); + write_codec(dev, 14, osamps >> 8); + if (SCSTATE->crystal) { + write_codec(dev, 31, isamps & 0xff); + write_codec(dev, 30, isamps >> 8); + } + write_codec(dev, 9, 3); + restore_flags(flags); +} + +/* --------------------------------------------------------------------- */ + +static void wssfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct sm_state *sm = (struct sm_state *)dev->priv; + unsigned long flags; + unsigned char cry_int_src; + unsigned icfrag, ocfrag, isamps, osamps; + + if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || + sm->hdrv.magic != HDLCDRV_MAGIC) + return; + save_flags(flags); + cli(); + if (SCSTATE->crystal) { + /* Crystal has an essentially different interrupt handler! */ + cry_int_src = read_codec(dev, 0x18); + wss_ack_int(dev); + if (cry_int_src & 0x10) { /* playback interrupt */ + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1; + write_codec(dev, 15, osamps & 0xff); + write_codec(dev, 14, osamps >> 8); + enable_dma(dev->dma); + } + if (cry_int_src & 0x20) { /* capture interrupt */ + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1; + write_codec(dev, 31, isamps & 0xff); + write_codec(dev, 30, isamps >> 8); + enable_dma(sm->hdrv.ptt_out.dma2); + } + restore_flags(flags); + sm_int_freq(sm); + sti(); + if (cry_int_src & 0x10) { + if (dma_end_transmit(sm, ocfrag)) + dma_clear_transmit(sm); + dma_transmit(sm); + } + if (cry_int_src & 0x20) { + dma_receive(sm, icfrag); + hdlcdrv_arbitrate(dev, &sm->hdrv); + } + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); + return; + } + wss_ack_int(dev); + disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(dev->dma); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1; + isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1; + write_codec(dev, 15, osamps & 0xff); + write_codec(dev, 14, osamps >> 8); + if (SCSTATE->crystal) { + write_codec(dev, 31, isamps & 0xff); + write_codec(dev, 30, isamps >> 8); + } + enable_dma(dev->dma); + enable_dma(sm->hdrv.ptt_out.dma2); + restore_flags(flags); + sm_int_freq(sm); + sti(); + if (dma_end_transmit(sm, ocfrag)) + dma_clear_transmit(sm); + dma_transmit(sm); + dma_receive(sm, icfrag); + hdlcdrv_arbitrate(dev, &sm->hdrv); + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); +} + +/* --------------------------------------------------------------------- */ + +static int wssfdx_open(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm || !sm->mode_rx || !sm->mode_tx) + return -ENXIO; + if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || + dev->irq < 2 || dev->irq > 15 || dev->dma > 3) + return -ENXIO; + if (check_region(dev->base_addr, WSS_EXTENT)) + return -EACCES; + /* + * check if a card is available + */ + if (wss_init_codec(dev, sm, 1, 1, 1, 0, 0, -45, -45)) + return -ENODEV; + /* + * initialize some variables + */ + if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA))) + return -ENOMEM; + if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) { + kfree(sm->dma.ibuf); + return -ENOMEM; + } + dma_init_transmit(sm); + dma_init_receive(sm); + + memset(&sm->m, 0, sizeof(sm->m)); + memset(&sm->d, 0, sizeof(sm->d)); + if (sm->mode_tx->init) + sm->mode_tx->init(sm); + if (sm->mode_rx->init) + sm->mode_rx->init(sm); + + if (request_dma(dev->dma, sm->hwdrv->hw_name)) { + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); + return -EBUSY; + } + if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); + free_dma(dev->dma); + return -EBUSY; + } + if (request_irq(dev->irq, wssfdx_interrupt, SA_INTERRUPT, + sm->hwdrv->hw_name, dev)) { + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); + free_dma(dev->dma); + free_dma(sm->hdrv.ptt_out.dma2); + return -EBUSY; + } + request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); + setup_fdx_dma_wss(dev, sm); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wssfdx_close(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm) + return -EINVAL; + /* + * disable interrupts + */ + disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); + write_codec(dev, 9, 0xc); /* disable codec */ + free_irq(dev->irq, dev); + free_dma(dev->dma); + free_dma(sm->hdrv.ptt_out.dma2); + release_region(dev->base_addr, WSS_EXTENT); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wssfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, '.'); + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp; + int i; + + if (!strcmp(mode, "off")) { + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return 0; + } + if (cp) + *cp++ = '\0'; + else + cp = mode; + for (; *mtp; mtp++) { + if ((*mtp)->loc_storage > sizeof(sm->m)) { + printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", + sm_drvname, (*mtp)->name, (*mtp)->loc_storage); + continue; + } + if (!(*mtp)->name || strcmp((*mtp)->name, mode)) + continue; + if ((i = wss_srate_index((*mtp)->srate)) < 0) + continue; + for (mrp = sm_modem_rx_table; *mrp; mrp++) { + if ((*mrp)->loc_storage > sizeof(sm->d)) { + printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", + sm_drvname, (*mrp)->name, (*mrp)->loc_storage); + continue; + } + if ((*mrp)->name && !strcmp((*mrp)->name, cp) && + (*mtp)->srate == (*mrp)->srate) { + sm->mode_tx = *mtp; + sm->mode_rx = *mrp; + SCSTATE->fmt[0] = SCSTATE->fmt[1] = i; + sm->dma.ifragsz = sm->dma.ofragsz = (sm->mode_rx->srate + 50)/100; + if (sm->dma.ifragsz < sm->mode_rx->overlap) + sm->dma.ifragsz = sm->mode_rx->overlap; + sm->dma.i16bit = sm->dma.o16bit = 2; + if (sm->mode_rx->demodulator_s16) { + sm->dma.i16bit = 1; + sm->dma.ifragsz <<= 1; +#ifdef __BIG_ENDIAN /* big endian 16bit only works on crystal cards... */ + SCSTATE->fmt[0] |= 0xc0; +#else /* __BIG_ENDIAN */ + SCSTATE->fmt[0] |= 0x40; +#endif /* __BIG_ENDIAN */ + } else if (sm->mode_rx->demodulator_u8) + sm->dma.i16bit = 0; + if (sm->mode_tx->modulator_s16) { + sm->dma.o16bit = 1; + sm->dma.ofragsz <<= 1; +#ifdef __BIG_ENDIAN /* big endian 16bit only works on crystal cards... */ + SCSTATE->fmt[1] |= 0xc0; +#else /* __BIG_ENDIAN */ + SCSTATE->fmt[1] |= 0x40; +#endif /* __BIG_ENDIAN */ + } else if (sm->mode_tx->modulator_u8) + sm->dma.o16bit = 0; + if (sm->dma.i16bit == 2 || sm->dma.o16bit == 2) { + printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, + sm->mode_rx->name, sm->mode_tx->name); + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return -EINVAL; + } + return 0; + } + } + } + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int wssfdx_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + + if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | + HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_DMA2 | + HDLCDRV_PARMASK_SERIOBASE | HDLCDRV_PARMASK_PARIOBASE | + HDLCDRV_PARMASK_MIDIIOBASE; + + return wss_ioctl(dev, sm, ifr, hi, cmd); +} + +/* --------------------------------------------------------------------- */ + +const struct hardware_info sm_hw_wssfdx = { + "wssfdx", sizeof(struct sc_state_wss), + wssfdx_open, wssfdx_close, wssfdx_ioctl, wssfdx_sethw +}; + +/* --------------------------------------------------------------------- */ + +#undef SCSTATE diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/soundmodem/smdma.h linux/drivers/net/hamradio/soundmodem/smdma.h --- v2.1.70/linux/drivers/net/hamradio/soundmodem/smdma.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/soundmodem/smdma.h Tue Aug 5 09:49:51 1997 @@ -0,0 +1,217 @@ +/*****************************************************************************/ + +/* + * smdma.h -- soundcard radio modem driver dma buffer routines. + * + * 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. + * + */ + +#ifndef _SMDMA_H +#define _SMDMA_H + +/* ---------------------------------------------------------------------- */ + +#include "sm.h" + +/* ---------------------------------------------------------------------- */ + +#define DMA_MODE_AUTOINIT 0x10 +#define NUM_FRAGMENTS 4 + +/* + * NOTE: make sure that hdlcdrv_hdlcbuffer contains enough space + * for the modulator to fill the whole DMA buffer without underrun + * at the highest possible baud rate, otherwise the TX state machine will + * not work correctly. That is (9k6 FSK): HDLCDRV_HDLCBUFFER > 6*NUM_FRAGMENTS + */ + +/* --------------------------------------------------------------------- */ +/* + * ===================== DMA buffer management =========================== + */ + +/* + * returns the number of samples per fragment + */ +extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr) +{ + if (send) { + disable_dma(dmanr); + clear_dma_ff(dmanr); + set_dma_mode(dmanr, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); + set_dma_addr(dmanr, virt_to_bus(sm->dma.obuf)); + set_dma_count(dmanr, sm->dma.ofragsz * NUM_FRAGMENTS); + enable_dma(dmanr); + if (sm->dma.o16bit) + return sm->dma.ofragsz/2; + return sm->dma.ofragsz; + } else { + disable_dma(dmanr); + clear_dma_ff(dmanr); + set_dma_mode(dmanr, DMA_MODE_READ | DMA_MODE_AUTOINIT); + set_dma_addr(dmanr, virt_to_bus(sm->dma.ibuf)); + set_dma_count(dmanr, sm->dma.ifragsz * NUM_FRAGMENTS); + enable_dma(dmanr); + if (sm->dma.i16bit) + return sm->dma.ifragsz/2; + return sm->dma.ifragsz; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr, + unsigned int *curfrag) +{ + unsigned int dmaptr, sz, frg, offs; + + dmaptr = get_dma_residue(dmanr); + if (send) { + sz = sm->dma.ofragsz * NUM_FRAGMENTS; + if (dmaptr == 0 || dmaptr > sz) + dmaptr = sz; + dmaptr--; + frg = dmaptr / sm->dma.ofragsz; + offs = (dmaptr % sm->dma.ofragsz) + 1; + *curfrag = NUM_FRAGMENTS - 1 - frg; +#ifdef SM_DEBUG + if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue) + sm->debug_vals.dma_residue = offs; +#endif /* SM_DEBUG */ + if (sm->dma.o16bit) + return offs/2; + return offs; + } else { + sz = sm->dma.ifragsz * NUM_FRAGMENTS; + if (dmaptr == 0 || dmaptr > sz) + dmaptr = sz; + dmaptr--; + frg = dmaptr / sm->dma.ifragsz; + offs = (dmaptr % sm->dma.ifragsz) + 1; + *curfrag = NUM_FRAGMENTS - 1 - frg; +#ifdef SM_DEBUG + if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue) + sm->debug_vals.dma_residue = offs; +#endif /* SM_DEBUG */ + if (sm->dma.i16bit) + return offs/2; + return offs; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag) +{ + unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS; + + sm->dma.ofragptr = curfrag; + if (sm->dma.ptt_cnt <= 0) { + sm->dma.ptt_cnt = 0; + return 0; + } + sm->dma.ptt_cnt -= diff; + if (sm->dma.ptt_cnt <= 0) { + sm->dma.ptt_cnt = 0; + return -1; + } + return 0; +} + +extern __inline__ void dma_transmit(struct sm_state *sm) +{ + void *p; + + while (sm->dma.ptt_cnt < NUM_FRAGMENTS && hdlcdrv_ptt(&sm->hdrv)) { + p = (unsigned char *)sm->dma.obuf + sm->dma.ofragsz * + ((sm->dma.ofragptr + sm->dma.ptt_cnt) % NUM_FRAGMENTS); + if (sm->dma.o16bit) { + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator_s16(sm, p, sm->dma.ofragsz/2)); + } else { + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator_u8(sm, p, sm->dma.ofragsz)); + } + sm->dma.ptt_cnt++; + } +} + +extern __inline__ void dma_init_transmit(struct sm_state *sm) +{ + sm->dma.ofragptr = 0; + sm->dma.ptt_cnt = 0; +} + +extern __inline__ void dma_start_transmit(struct sm_state *sm) +{ + sm->dma.ofragptr = 0; + if (sm->dma.o16bit) { + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator_s16(sm, sm->dma.obuf, sm->dma.ofragsz/2)); + } else { + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator_u8(sm, sm->dma.obuf, sm->dma.ofragsz)); + } + sm->dma.ptt_cnt = 1; +} + +extern __inline__ void dma_clear_transmit(struct sm_state *sm) +{ + sm->dma.ptt_cnt = 0; + memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS); +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag) +{ + void *p; + + while (sm->dma.ifragptr != curfrag) { + if (sm->dma.ifragptr) + p = (unsigned char *)sm->dma.ibuf + + sm->dma.ifragsz * sm->dma.ifragptr; + else { + p = (unsigned char *)sm->dma.ibuf + NUM_FRAGMENTS * sm->dma.ifragsz; + memcpy(p, sm->dma.ibuf, sm->dma.ifragsz); + } + if (sm->dma.o16bit) { + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator_s16(sm, p, sm->dma.ifragsz/2)); + } else { + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator_u8(sm, p, sm->dma.ifragsz)); + } + sm->dma.ifragptr = (sm->dma.ifragptr + 1) % NUM_FRAGMENTS; + } +} + +extern __inline__ void dma_init_receive(struct sm_state *sm) +{ + sm->dma.ifragptr = 0; +} + +/* --------------------------------------------------------------------- */ +#endif /* _SMDMA_H */ + + + diff -u --recursive --new-file v2.1.70/linux/drivers/net/hamradio/z8530.h linux/drivers/net/hamradio/z8530.h --- v2.1.70/linux/drivers/net/hamradio/z8530.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/z8530.h Tue Oct 29 05:33:39 1996 @@ -0,0 +1,243 @@ + +/* 8530 Serial Communications Controller Register definitions */ +#define FLAG 0x7e + +/* Write Register 0 */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 */ + +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ +#define INT_ERR_Rx 0x18 /* Int on error only */ + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register #2 (Interrupt Vector) */ + +/* Write Register 3 */ + +#define RxENABLE 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ + +/* Write Register 4 */ + +#define PAR_ENA 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xC0 /* x64 clock mode */ + +/* Write Register 5 */ + +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 8 (transmit buffer) */ + +/* Write Register 9 (Master interrupt control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (misc control bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (lower byte of baud rate generator time constant) */ + +/* Write Register 13 (upper byte of baud rate generator time constant) */ + +/* Write Register 14 (Misc control bits) */ +#define BRENABL 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (external/status interrupt control) */ +#define ZCIE 2 /* Zero count IE */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define CRC_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (channel b only) - Interrupt vector */ + +/* Read Register 3 (interrupt pending register) ch a only */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 8 (receive data register) */ + +/* Read Register 10 (misc status bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (lower byte of baud rate generator constant) */ + +/* Read Register 13 (upper byte of baud rate generator constant) */ + +/* Read Register 15 (value of WR 15) */ + +/* 8580/85180/85280 Enhanced SCC register definitions */ + +/* Write Register 7' (SDLC/HDLC Programmable Enhancements) */ +#define AUTOTXF 0x01 /* Auto Tx Flag */ +#define AUTOEOM 0x02 /* Auto EOM Latch Reset */ +#define AUTORTS 0x04 /* Auto RTS */ +#define TXDNRZI 0x08 /* TxD Pulled High in SDLC NRZI mode */ +#define FASTDTR 0x10 /* Fast DTR/REQ Mode */ +#define CRCCBCR 0x20 /* CRC Check Bytes Completely Received */ +#define EXTRDEN 0x40 /* Extended Read Enabled */ + +/* Write Register 15 (external/status interrupt control) */ +#define SHDLCE 1 /* SDLC/HDLC Enhancements Enable */ +#define FIFOE 4 /* FIFO Enable */ + +/* Read Register 6 (frame status FIFO) */ +#define BCLSB 0xff /* LSB of 14 bits count */ + +/* Read Register 7 (frame status FIFO) */ +#define BCMSB 0x3f /* MSB of 14 bits count */ +#define FDA 0x40 /* FIFO Data Available Status */ +#define FOY 0x80 /* FIFO Overflow Status */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c --- v2.1.70/linux/drivers/net/hdlcdrv.c Mon Dec 1 12:04:13 1997 +++ linux/drivers/net/hdlcdrv.c Wed Dec 31 16:00:00 1969 @@ -1,1024 +0,0 @@ -/*****************************************************************************/ - -/* - * hdlcdrv.c -- HDLC packet radio network 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. - * - * The driver was derived from Donald Beckers skeleton.c - * Written 1993-94 by Donald Becker. - * - * History: - * 0.1 21.09.96 Started - * 18.10.96 Changed to new user space access routines - * (copy_{to,from}_user) - * 0.2 21.11.96 various small changes - * 0.3 03.03.97 fixed (hopefully) IP not working with ax.25 as a module - * 0.4 16.04.97 init code/data tagged - * 0.5 30.07.97 made HDLC buffers bigger (solves a problem with the - * soundmodem driver) - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) -/* prototypes for ax25_encapsulate and ax25_rebuild_header */ -#include -#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ - -/* make genksyms happy */ -#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 < 0x20115 -extern __inline__ void dev_init_buffers(struct device *dev) -{ - int i; - for(i=0;ibuffs[i]); - } -} -#endif - -/* --------------------------------------------------------------------- */ - -#if LINUX_VERSION_CODE >= 0x20123 -#include -#else -#define __init -#define __initdata -#define __initfunc(x) x -#endif - -/* --------------------------------------------------------------------- */ - -#if LINUX_VERSION_CODE < 0x20125 -#define test_and_set_bit set_bit -#define test_and_clear_bit clear_bit -#endif - -/* --------------------------------------------------------------------- */ - -/* - * The name of the card. Is used for messages and in the requests for - * io regions, irqs and dma channels - */ - -static char ax25_bcast[AX25_ADDR_LEN] = -{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static char ax25_nocall[AX25_ADDR_LEN] = -{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - -/* --------------------------------------------------------------------- */ - -#define KISS_VERBOSE - -/* --------------------------------------------------------------------- */ - -#define PARAM_TXDELAY 1 -#define PARAM_PERSIST 2 -#define PARAM_SLOTTIME 3 -#define PARAM_TXTAIL 4 -#define PARAM_FULLDUP 5 -#define PARAM_HARDWARE 6 -#define PARAM_RETURN 255 - -/* --------------------------------------------------------------------- */ - -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#define max(a, b) (((a) > (b)) ? (a) : (b)) - -/* --------------------------------------------------------------------- */ -/* - * the CRC routines are stolen from WAMPES - * by Dieter Deyke - */ - -static const unsigned short crc_ccitt_table[] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -/*---------------------------------------------------------------------------*/ - -static inline void append_crc_ccitt(unsigned char *buffer, int len) -{ - unsigned int crc = 0xffff; - - for (;len>0;len--) - crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff]; - crc ^= 0xffff; - *buffer++ = crc; - *buffer++ = crc >> 8; -} - -/*---------------------------------------------------------------------------*/ - -static inline int check_crc_ccitt(const unsigned char *buf, int cnt) -{ - unsigned int crc = 0xffff; - - for (; cnt > 0; cnt--) - crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; - return (crc & 0xffff) == 0xf0b8; -} - -/*---------------------------------------------------------------------------*/ - -#if 0 -static int calc_crc_ccitt(const unsigned char *buf, int cnt) -{ - unsigned int crc = 0xffff; - - for (; cnt > 0; cnt--) - crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; - crc ^= 0xffff; - return (crc & 0xffff); -} -#endif - -/* ---------------------------------------------------------------------- */ - -#define tenms_to_2flags(s,tenms) ((tenms * s->par.bitrate) / 100 / 16) - -/* ---------------------------------------------------------------------- */ -/* - * The HDLC routines - */ - -static int hdlc_rx_add_bytes(struct hdlcdrv_state *s, unsigned int bits, - int num) -{ - int added = 0; - - while (s->hdlcrx.rx_state && num >= 8) { - if (s->hdlcrx.len >= sizeof(s->hdlcrx.buffer)) { - s->hdlcrx.rx_state = 0; - return 0; - } - *s->hdlcrx.bp++ = bits >> (32-num); - s->hdlcrx.len++; - num -= 8; - added += 8; - } - return added; -} - -static void hdlc_rx_flag(struct device *dev, struct hdlcdrv_state *s) -{ - struct sk_buff *skb; - int pkt_len; - unsigned char *cp; - - if (s->hdlcrx.len < 4) - return; - if (!check_crc_ccitt(s->hdlcrx.buffer, s->hdlcrx.len)) - return; - pkt_len = s->hdlcrx.len - 2 + 1; /* KISS kludge */ - if (!(skb = dev_alloc_skb(pkt_len))) { - printk("%s: memory squeeze, dropping packet\n", - s->ifname); - s->stats.rx_dropped++; - return; - } - skb->dev = dev; - cp = skb_put(skb, pkt_len); - *cp++ = 0; /* KISS kludge */ - memcpy(cp, s->hdlcrx.buffer, pkt_len - 1); - skb->protocol = htons(ETH_P_AX25); - skb->mac.raw = skb->data; - netif_rx(skb); - s->stats.rx_packets++; -} - -void hdlcdrv_receiver(struct device *dev, struct hdlcdrv_state *s) -{ - int i; - unsigned int mask1, mask2, mask3, mask4, mask5, mask6, word; - - if (!s || s->magic != HDLCDRV_MAGIC) - return; - if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx)) - return; - - while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) { - word = hdlcdrv_hbuf_get(&s->hdlcrx.hbuf); - -#ifdef HDLCDRV_DEBUG - hdlcdrv_add_bitbuffer_word(&s->bitbuf_hdlc, word); -#endif /* HDLCDRV_DEBUG */ - s->hdlcrx.bitstream >>= 16; - s->hdlcrx.bitstream |= word << 16; - s->hdlcrx.bitbuf >>= 16; - s->hdlcrx.bitbuf |= word << 16; - s->hdlcrx.numbits += 16; - for(i = 15, mask1 = 0x1fc00, mask2 = 0x1fe00, mask3 = 0x0fc00, - mask4 = 0x1f800, mask5 = 0xf800, mask6 = 0xffff; - i >= 0; - i--, mask1 <<= 1, mask2 <<= 1, mask3 <<= 1, mask4 <<= 1, - mask5 <<= 1, mask6 = (mask6 << 1) | 1) { - if ((s->hdlcrx.bitstream & mask1) == mask1) - s->hdlcrx.rx_state = 0; /* abort received */ - else if ((s->hdlcrx.bitstream & mask2) == mask3) { - /* flag received */ - if (s->hdlcrx.rx_state) { - hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf - << (8+i), - s->hdlcrx.numbits - -8-i); - hdlc_rx_flag(dev, s); - } - s->hdlcrx.len = 0; - s->hdlcrx.bp = s->hdlcrx.buffer; - s->hdlcrx.rx_state = 1; - s->hdlcrx.numbits = i; - } else if ((s->hdlcrx.bitstream & mask4) == mask5) { - /* stuffed bit */ - s->hdlcrx.numbits--; - s->hdlcrx.bitbuf = (s->hdlcrx.bitbuf & (~mask6)) | - ((s->hdlcrx.bitbuf & mask6) << 1); - } - } - s->hdlcrx.numbits -= hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf, - s->hdlcrx.numbits); - } - clear_bit(0, &s->hdlcrx.in_hdlc_rx); -} - -/* ---------------------------------------------------------------------- */ - -static void inline do_kiss_params(struct hdlcdrv_state *s, - unsigned char *data, unsigned long len) -{ - -#ifdef KISS_VERBOSE -#define PKP(a,b) printk(KERN_INFO "%s: channel params: " a "\n", s->ifname, b) -#else /* KISS_VERBOSE */ -#define PKP(a,b) -#endif /* KISS_VERBOSE */ - - if (len < 2) - return; - switch(data[0]) { - case PARAM_TXDELAY: - s->ch_params.tx_delay = data[1]; - PKP("TX delay = %ums", 10 * s->ch_params.tx_delay); - break; - case PARAM_PERSIST: - s->ch_params.ppersist = data[1]; - PKP("p persistence = %u", s->ch_params.ppersist); - break; - case PARAM_SLOTTIME: - s->ch_params.slottime = data[1]; - PKP("slot time = %ums", s->ch_params.slottime); - break; - case PARAM_TXTAIL: - s->ch_params.tx_tail = data[1]; - PKP("TX tail = %ums", s->ch_params.tx_tail); - break; - case PARAM_FULLDUP: - s->ch_params.fulldup = !!data[1]; - PKP("%s duplex", s->ch_params.fulldup ? "full" : "half"); - break; - default: - break; - } -#undef PKP -} - -/* ---------------------------------------------------------------------- */ - -void hdlcdrv_transmitter(struct device *dev, struct hdlcdrv_state *s) -{ - unsigned int mask1, mask2, mask3; - int i; - struct sk_buff *skb; - int pkt_len; - - if (!s || s->magic != HDLCDRV_MAGIC) - return; - if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx)) - return; - for (;;) { - if (s->hdlctx.numbits >= 16) { - if (hdlcdrv_hbuf_full(&s->hdlctx.hbuf)) { - clear_bit(0, &s->hdlctx.in_hdlc_tx); - return; - } - hdlcdrv_hbuf_put(&s->hdlctx.hbuf, s->hdlctx.bitbuf); - s->hdlctx.bitbuf >>= 16; - s->hdlctx.numbits -= 16; - } - switch (s->hdlctx.tx_state) { - default: - clear_bit(0, &s->hdlctx.in_hdlc_tx); - return; - case 0: - case 1: - if (s->hdlctx.numflags) { - s->hdlctx.numflags--; - s->hdlctx.bitbuf |= - 0x7e7e << s->hdlctx.numbits; - s->hdlctx.numbits += 16; - break; - } - if (s->hdlctx.tx_state == 1) { - clear_bit(0, &s->hdlctx.in_hdlc_tx); - return; - } - if (!(skb = skb_dequeue(&s->send_queue))) { - int flgs = tenms_to_2flags - (s, s->ch_params.tx_tail); - if (flgs < 2) - flgs = 2; - s->hdlctx.tx_state = 1; - s->hdlctx.numflags = flgs; - break; - } - if (skb->data[0] != 0) { - do_kiss_params(s, skb->data, skb->len); - dev_kfree_skb(skb, FREE_WRITE); - break; - } - pkt_len = skb->len-1; /* strip KISS byte */ - if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) { - s->hdlctx.tx_state = 0; - s->hdlctx.numflags = 1; - dev_kfree_skb(skb, FREE_WRITE); - break; - } - memcpy(s->hdlctx.buffer, skb->data+1, pkt_len); - dev_kfree_skb(skb, FREE_WRITE); - s->hdlctx.bp = s->hdlctx.buffer; - append_crc_ccitt(s->hdlctx.buffer, pkt_len); - s->hdlctx.len = pkt_len+2; /* the appended CRC */ - s->hdlctx.tx_state = 2; - s->hdlctx.bitstream = 0; - s->stats.tx_packets++; - break; - case 2: - if (!s->hdlctx.len) { - s->hdlctx.tx_state = 0; - s->hdlctx.numflags = 1; - break; - } - s->hdlctx.len--; - s->hdlctx.bitbuf |= *s->hdlctx.bp << - s->hdlctx.numbits; - s->hdlctx.bitstream >>= 8; - s->hdlctx.bitstream |= (*s->hdlctx.bp++) << 16; - mask1 = 0x1f000; - mask2 = 0x10000; - mask3 = 0xffffffff >> (31-s->hdlctx.numbits); - s->hdlctx.numbits += 8; - for(i = 0; i < 8; i++, mask1 <<= 1, mask2 <<= 1, - mask3 = (mask3 << 1) | 1) { - if ((s->hdlctx.bitstream & mask1) != mask1) - continue; - s->hdlctx.bitstream &= ~mask2; - s->hdlctx.bitbuf = - (s->hdlctx.bitbuf & mask3) | - ((s->hdlctx.bitbuf & - (~mask3)) << 1); - s->hdlctx.numbits++; - mask3 = (mask3 << 1) | 1; - } - break; - } - } -} - -/* ---------------------------------------------------------------------- */ - -static void start_tx(struct device *dev, struct hdlcdrv_state *s) -{ - s->hdlctx.tx_state = 0; - s->hdlctx.numflags = tenms_to_2flags(s, s->ch_params.tx_delay); - s->hdlctx.bitbuf = s->hdlctx.bitstream = s->hdlctx.numbits = 0; - hdlcdrv_transmitter(dev, s); - s->hdlctx.ptt = 1; - s->ptt_keyed++; -} - -/* ---------------------------------------------------------------------- */ - -static unsigned short random_seed; - -static inline unsigned short random_num(void) -{ - random_seed = 28629 * random_seed + 157; - return random_seed; -} - -/* ---------------------------------------------------------------------- */ - -void hdlcdrv_arbitrate(struct device *dev, struct hdlcdrv_state *s) -{ - if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt || - skb_queue_empty(&s->send_queue)) - return; - if (s->ch_params.fulldup) { - start_tx(dev, s); - return; - } - if (s->hdlcrx.dcd) { - s->hdlctx.slotcnt = s->ch_params.slottime; - return; - } - if ((--s->hdlctx.slotcnt) > 0) - return; - s->hdlctx.slotcnt = s->ch_params.slottime; - if ((random_num() % 256) > s->ch_params.ppersist) - return; - start_tx(dev, s); -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== network driver interface ========================= - */ - -static inline int hdlcdrv_paranoia_check(struct device *dev, - const char *routine) -{ - if (!dev || !dev->priv || - ((struct hdlcdrv_state *)dev->priv)->magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "hdlcdrv: bad magic number for hdlcdrv_state " - "struct in routine %s\n", routine); - return 1; - } - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int hdlcdrv_send_packet(struct sk_buff *skb, struct device *dev) -{ - struct hdlcdrv_state *sm; - - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_send_packet")) - return 0; - sm = (struct hdlcdrv_state *)dev->priv; - skb_queue_tail(&sm->send_queue, skb); - dev->trans_start = jiffies; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int hdlcdrv_set_mac_address(struct device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *)addr; - - /* addr is an AX.25 shifted ASCII mac address */ - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - return 0; -} - -/* --------------------------------------------------------------------- */ - -#if LINUX_VERSION_CODE >= 0x20119 -static struct net_device_stats *hdlcdrv_get_stats(struct device *dev) -#else -static struct enet_statistics *hdlcdrv_get_stats(struct device *dev) -#endif -{ - struct hdlcdrv_state *sm; - - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_get_stats")) - return NULL; - sm = (struct hdlcdrv_state *)dev->priv; - /* - * Get the current statistics. This may be called with the - * card open or closed. - */ - return &sm->stats; -} - -/* --------------------------------------------------------------------- */ -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ - -static int hdlcdrv_open(struct device *dev) -{ - struct hdlcdrv_state *s; - int i; - - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_open")) - return -EINVAL; - s = (struct hdlcdrv_state *)dev->priv; - - if (dev->start) - return 0; - if (!s->ops || !s->ops->open) - return -ENODEV; - - dev->start = 1; - /* - * initialise some variables - */ - s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; - s->hdlcrx.in_hdlc_rx = 0; - s->hdlcrx.rx_state = 0; - - s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; - s->hdlctx.in_hdlc_tx = 0; - s->hdlctx.tx_state = 1; - s->hdlctx.numflags = 0; - s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; - s->hdlctx.ptt = 0; - s->hdlctx.slotcnt = s->ch_params.slottime; - s->hdlctx.calibrate = 0; - - i = s->ops->open(dev); - if (i) { - dev->start = 0; - return i; - } - - dev->tbusy = 0; - dev->interrupt = 0; - - return 0; -} - -/* --------------------------------------------------------------------- */ -/* - * The inverse routine to hdlcdrv_open(). - */ - -static int hdlcdrv_close(struct device *dev) -{ - struct hdlcdrv_state *s; - struct sk_buff *skb; - int i = 0; - - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_close")) - return -EINVAL; - s = (struct hdlcdrv_state *)dev->priv; - - if (!dev->start) - return 0; - dev->start = 0; - dev->tbusy = 1; - - if (s->ops && s->ops->close) - i = s->ops->close(dev); - /* Free any buffers left in the hardware transmit queue */ - while ((skb = skb_dequeue(&s->send_queue))) - dev_kfree_skb(skb, FREE_WRITE); - return i; -} - -/* --------------------------------------------------------------------- */ - -static int hdlcdrv_ioctl(struct device *dev, struct ifreq *ifr, int cmd) -{ - struct hdlcdrv_state *s; - struct hdlcdrv_ioctl bi; - - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_ioctl")) - return -EINVAL; - s = (struct hdlcdrv_state *)dev->priv; - - if (cmd != SIOCDEVPRIVATE) { - if (s->ops && s->ops->ioctl) - return s->ops->ioctl(dev, ifr, &bi, cmd); - return -ENOIOCTLCMD; - } - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - - switch (bi.cmd) { - default: - if (s->ops && s->ops->ioctl) - return s->ops->ioctl(dev, ifr, &bi, cmd); - return -ENOIOCTLCMD; - - case HDLCDRVCTL_GETCHANNELPAR: - bi.data.cp.tx_delay = s->ch_params.tx_delay; - bi.data.cp.tx_tail = s->ch_params.tx_tail; - bi.data.cp.slottime = s->ch_params.slottime; - bi.data.cp.ppersist = s->ch_params.ppersist; - bi.data.cp.fulldup = s->ch_params.fulldup; - break; - - case HDLCDRVCTL_SETCHANNELPAR: - if (!suser()) - return -EACCES; - s->ch_params.tx_delay = bi.data.cp.tx_delay; - s->ch_params.tx_tail = bi.data.cp.tx_tail; - s->ch_params.slottime = bi.data.cp.slottime; - s->ch_params.ppersist = bi.data.cp.ppersist; - s->ch_params.fulldup = bi.data.cp.fulldup; - s->hdlctx.slotcnt = 1; - return 0; - - case HDLCDRVCTL_GETMODEMPAR: - bi.data.mp.iobase = dev->base_addr; - bi.data.mp.irq = dev->irq; - bi.data.mp.dma = dev->dma; - bi.data.mp.dma2 = s->ptt_out.dma2; - bi.data.mp.seriobase = s->ptt_out.seriobase; - bi.data.mp.pariobase = s->ptt_out.pariobase; - bi.data.mp.midiiobase = s->ptt_out.midiiobase; - break; - - case HDLCDRVCTL_SETMODEMPAR: - if ((!suser()) || dev->start) - return -EACCES; - dev->base_addr = bi.data.mp.iobase; - dev->irq = bi.data.mp.irq; - dev->dma = bi.data.mp.dma; - s->ptt_out.dma2 = bi.data.mp.dma2; - s->ptt_out.seriobase = bi.data.mp.seriobase; - s->ptt_out.pariobase = bi.data.mp.pariobase; - s->ptt_out.midiiobase = bi.data.mp.midiiobase; - return 0; - - case HDLCDRVCTL_GETSTAT: - bi.data.cs.ptt = hdlcdrv_ptt(s); - bi.data.cs.dcd = s->hdlcrx.dcd; - bi.data.cs.ptt_keyed = s->ptt_keyed; - bi.data.cs.tx_packets = s->stats.tx_packets; - bi.data.cs.tx_errors = s->stats.tx_errors; - bi.data.cs.rx_packets = s->stats.rx_packets; - bi.data.cs.rx_errors = s->stats.rx_errors; - break; - - case HDLCDRVCTL_OLDGETSTAT: - bi.data.ocs.ptt = hdlcdrv_ptt(s); - bi.data.ocs.dcd = s->hdlcrx.dcd; - bi.data.ocs.ptt_keyed = s->ptt_keyed; -#if LINUX_VERSION_CODE < 0x20100 - bi.data.ocs.stats = s->stats; -#endif - break; - - case HDLCDRVCTL_CALIBRATE: - s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16; - return 0; - - case HDLCDRVCTL_GETSAMPLES: -#ifndef HDLCDRV_DEBUG - return -EPERM; -#else /* HDLCDRV_DEBUG */ - if (s->bitbuf_channel.rd == s->bitbuf_channel.wr) - return -EAGAIN; - bi.data.bits = - s->bitbuf_channel.buffer[s->bitbuf_channel.rd]; - s->bitbuf_channel.rd = (s->bitbuf_channel.rd+1) % - sizeof(s->bitbuf_channel.buffer); - break; -#endif /* HDLCDRV_DEBUG */ - - case HDLCDRVCTL_GETBITS: -#ifndef HDLCDRV_DEBUG - return -EPERM; -#else /* HDLCDRV_DEBUG */ - if (s->bitbuf_hdlc.rd == s->bitbuf_hdlc.wr) - return -EAGAIN; - bi.data.bits = - s->bitbuf_hdlc.buffer[s->bitbuf_hdlc.rd]; - s->bitbuf_hdlc.rd = (s->bitbuf_hdlc.rd+1) % - sizeof(s->bitbuf_hdlc.buffer); - break; -#endif /* HDLCDRV_DEBUG */ - - case HDLCDRVCTL_DRIVERNAME: - if (s->ops && s->ops->drvname) { - strncpy(bi.data.drivername, s->ops->drvname, - sizeof(bi.data.drivername)); - break; - } - bi.data.drivername[0] = '\0'; - break; - - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -/* - * Check for a network adaptor of this type, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). - */ -static int hdlcdrv_probe(struct device *dev) -{ - const struct hdlcdrv_channel_params dflt_ch_params = { - 20, 2, 10, 40, 0 - }; - struct hdlcdrv_state *s; - - if (!dev) - return -ENXIO; - /* - * not a real probe! only initialize data structures - */ - s = (struct hdlcdrv_state *)dev->priv; - /* - * initialize the hdlcdrv_state struct - */ - s->ch_params = dflt_ch_params; - s->ptt_keyed = 0; - - s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; - s->hdlcrx.in_hdlc_rx = 0; - s->hdlcrx.rx_state = 0; - - s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; - s->hdlctx.in_hdlc_tx = 0; - s->hdlctx.tx_state = 1; - s->hdlctx.numflags = 0; - s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; - s->hdlctx.ptt = 0; - s->hdlctx.slotcnt = s->ch_params.slottime; - s->hdlctx.calibrate = 0; - -#ifdef HDLCDRV_DEBUG - s->bitbuf_channel.rd = s->bitbuf_channel.wr = 0; - s->bitbuf_channel.shreg = 0x80; - - s->bitbuf_hdlc.rd = s->bitbuf_hdlc.wr = 0; - s->bitbuf_hdlc.shreg = 0x80; -#endif /* HDLCDRV_DEBUG */ - - /* - * initialize the device struct - */ - dev->open = hdlcdrv_open; - dev->stop = hdlcdrv_close; - dev->do_ioctl = hdlcdrv_ioctl; - dev->hard_start_xmit = hdlcdrv_send_packet; - dev->get_stats = hdlcdrv_get_stats; - - /* Fill in the fields of the device structure */ - - dev_init_buffers(dev); - - skb_queue_head_init(&s->send_queue); - -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; -#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */ - dev->hard_header = NULL; - dev->rebuild_header = NULL; -#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ - dev->set_mac_address = hdlcdrv_set_mac_address; - - dev->type = ARPHRD_AX25; /* AF_AX25 device */ - 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; - - return 0; -} - -/* --------------------------------------------------------------------- */ - -int hdlcdrv_register_hdlcdrv(struct device *dev, const struct hdlcdrv_ops *ops, - unsigned int privsize, char *ifname, - unsigned int baseaddr, unsigned int irq, - unsigned int dma) -{ - struct hdlcdrv_state *s; - - if (!dev || !ops) - return -EACCES; - if (privsize < sizeof(struct hdlcdrv_state)) - privsize = sizeof(struct hdlcdrv_state); - memset(dev, 0, sizeof(struct device)); - if (!(s = dev->priv = kmalloc(privsize, GFP_KERNEL))) - return -ENOMEM; - /* - * initialize part of the hdlcdrv_state struct - */ - memset(s, 0, privsize); - s->magic = HDLCDRV_MAGIC; - strncpy(s->ifname, ifname, sizeof(s->ifname)); - s->ops = ops; - /* - * initialize part of the device struct - */ - dev->name = s->ifname; - dev->if_port = 0; - dev->init = hdlcdrv_probe; - dev->start = 0; - dev->tbusy = 1; - dev->base_addr = baseaddr; - dev->irq = irq; - dev->dma = dma; - if (register_netdev(dev)) { - printk(KERN_WARNING "hdlcdrv: cannot register net " - "device %s\n", s->ifname); - kfree(dev->priv); - return -ENXIO; - } - MOD_INC_USE_COUNT; - return 0; -} - -/* --------------------------------------------------------------------- */ - -int hdlcdrv_unregister_hdlcdrv(struct device *dev) -{ - struct hdlcdrv_state *s; - - if (!dev) - return -EINVAL; - if (!(s = (struct hdlcdrv_state *)dev->priv)) - return -EINVAL; - if (s->magic != HDLCDRV_MAGIC) - return -EINVAL; - if (dev->start && s->ops->close) - s->ops->close(dev); - unregister_netdev(dev); - kfree(s); - MOD_DEC_USE_COUNT; - return 0; -} - -/* --------------------------------------------------------------------- */ - -#if LINUX_VERSION_CODE >= 0x20115 - -EXPORT_SYMBOL(hdlcdrv_receiver); -EXPORT_SYMBOL(hdlcdrv_transmitter); -EXPORT_SYMBOL(hdlcdrv_arbitrate); -EXPORT_SYMBOL(hdlcdrv_register_hdlcdrv); -EXPORT_SYMBOL(hdlcdrv_unregister_hdlcdrv); - -#else - -static struct symbol_table hdlcdrv_syms = { -#include - X(hdlcdrv_receiver), - X(hdlcdrv_transmitter), - X(hdlcdrv_arbitrate), - X(hdlcdrv_register_hdlcdrv), - X(hdlcdrv_unregister_hdlcdrv), -#include -}; - -#endif - -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -#if LINUX_VERSION_CODE >= 0x20115 - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder"); - -#endif - -/* --------------------------------------------------------------------- */ - -__initfunc(int init_module(void)) -{ - printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n"); - printk(KERN_INFO "hdlcdrv: version 0.5 compiled " __TIME__ " " __DATE__ "\n"); -#if LINUX_VERSION_CODE < 0x20115 - register_symtab(&hdlcdrv_syms); -#endif - return 0; -} - -/* --------------------------------------------------------------------- */ - -void cleanup_module(void) -{ - printk(KERN_INFO "hdlcdrv: cleanup\n"); -} - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/mkiss.c linux/drivers/net/mkiss.c --- v2.1.70/linux/drivers/net/mkiss.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/mkiss.c Wed Dec 31 16:00:00 1969 @@ -1,1134 +0,0 @@ -/* - * MKISS Driver - * - * This module: - * This module 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 module implements the AX.25 protocol for kernel-based - * devices like TTYs. It interfaces between a raw TTY, and the - * kernel's AX.25 protocol layers, just like slip.c. - * AX.25 needs to be seperated from slip.c while slip.c is no - * longer a static kernel device since it is a module. - * This method clears the way to implement other kiss protocols - * like mkiss smack g8bpq ..... so far only mkiss is implemented. - * - * Hans Alblas - * - * History - * Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include - -#include "mkiss.h" - -#ifdef CONFIG_INET -#include -#include -#endif - -#ifdef MODULE -#define AX25_VERSION "AX25-MODULAR-NET3.019-NEWTTY" -#define min(a,b) (a < b ? a : b) -#else -#define AX25_VERSION "AX25-NET3.019-NEWTTY" -#endif - -#define NR_MKISS 4 -#define MKISS_SERIAL_TYPE_NORMAL 1 - -struct mkiss_channel { - int magic; /* magic word */ - int init; /* channel exists? */ - struct tty_struct *tty; /* link to tty control structure */ -}; - -typedef struct ax25_ctrl { - char if_name[8]; /* "ax0\0" .. "ax99999\0" */ - struct ax_disp ctrl; /* */ - struct device dev; /* the device */ -} ax25_ctrl_t; - -static ax25_ctrl_t **ax25_ctrls = NULL; - -int ax25_maxdev = AX25_MAXDEV; /* Can be overridden with insmod! */ - -static struct tty_ldisc ax_ldisc; -static struct tty_driver mkiss_driver; -static int mkiss_refcount; -static struct tty_struct *mkiss_table[NR_MKISS]; -static struct termios *mkiss_termios[NR_MKISS]; -static struct termios *mkiss_termios_locked[NR_MKISS]; -struct mkiss_channel MKISS_Info[NR_MKISS]; - -static int ax25_init(struct device *); -static int mkiss_init(void); -static int mkiss_write(struct tty_struct *, int, const unsigned char *, int); -static int kiss_esc(unsigned char *, unsigned char *, int); -static void kiss_unesc(struct ax_disp *, unsigned char); - -/* Find a free channel, and link in this `tty' line. */ -static inline struct ax_disp *ax_alloc(void) -{ - ax25_ctrl_t *axp; - int i; - - if (ax25_ctrls == NULL) /* Master array missing ! */ - return NULL; - - for (i = 0; i < ax25_maxdev; i++) { - axp = ax25_ctrls[i]; - - /* Not allocated ? */ - if (axp == NULL) - break; - - /* Not in use ? */ - if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags)) - break; - } - - /* Sorry, too many, all slots in use */ - if (i >= ax25_maxdev) - return NULL; - - /* If no channels are available, allocate one */ - if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) { - axp = ax25_ctrls[i]; - memset(axp, 0, sizeof(ax25_ctrl_t)); - - /* Initialize channel control data */ - set_bit(AXF_INUSE, &axp->ctrl.flags); - sprintf(axp->if_name, "ax%d", i++); - axp->ctrl.tty = NULL; - axp->dev.name = axp->if_name; - axp->dev.base_addr = i; - axp->dev.priv = (void *)&axp->ctrl; - axp->dev.next = NULL; - axp->dev.init = ax25_init; - } - - if (axp != NULL) { - /* - * register device so that it can be ifconfig'ed - * ax25_init() will be called as a side-effect - * SIDE-EFFECT WARNING: ax25_init() CLEARS axp->ctrl ! - */ - if (register_netdev(&axp->dev) == 0) { - /* (Re-)Set the INUSE bit. Very Important! */ - set_bit(AXF_INUSE, &axp->ctrl.flags); - axp->ctrl.dev = &axp->dev; - axp->dev.priv = (void *)&axp->ctrl; - - return &axp->ctrl; - } else { - clear_bit(AXF_INUSE,&axp->ctrl.flags); - printk(KERN_ERR "mkiss: ax_alloc() - register_netdev() failure.\n"); - } - } - - return NULL; -} - -/* Free an AX25 channel. */ -static inline void ax_free(struct ax_disp *ax) -{ - /* Free all AX25 frame buffers. */ - if (ax->rbuff) - kfree(ax->rbuff); - ax->rbuff = NULL; - if (ax->xbuff) - kfree(ax->xbuff); - ax->xbuff = NULL; - if (!test_and_clear_bit(AXF_INUSE, &ax->flags)) - printk(KERN_ERR "mkiss: %s: ax_free for already free unit.\n", ax->dev->name); -} - -static void ax_changedmtu(struct ax_disp *ax) -{ - struct device *dev = ax->dev; - unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; - int len; - unsigned long flags; - - len = dev->mtu * 2; - - /* - * allow for arrival of larger UDP packets, even if we say not to - * also fixes a bug in which SunOS sends 512-byte packets even with - * an MSS of 128 - */ - if (len < 576 * 2) - len = 576 * 2; - - xbuff = kmalloc(len + 4, GFP_ATOMIC); - rbuff = kmalloc(len + 4, GFP_ATOMIC); - - if (xbuff == NULL || rbuff == NULL) { - printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, MTU change cancelled.\n", - ax->dev->name); - dev->mtu = ax->mtu; - if (xbuff != NULL) - kfree(xbuff); - if (rbuff != NULL) - kfree(rbuff); - return; - } - - save_flags(flags); - cli(); - - oxbuff = ax->xbuff; - ax->xbuff = xbuff; - orbuff = ax->rbuff; - ax->rbuff = rbuff; - - if (ax->xleft) { - if (ax->xleft <= len) { - memcpy(ax->xbuff, ax->xhead, ax->xleft); - } else { - ax->xleft = 0; - ax->tx_dropped++; - } - } - - ax->xhead = ax->xbuff; - - if (ax->rcount) { - if (ax->rcount <= len) { - memcpy(ax->rbuff, orbuff, ax->rcount); - } else { - ax->rcount = 0; - ax->rx_over_errors++; - set_bit(AXF_ERROR, &ax->flags); - } - } - - ax->mtu = dev->mtu + 73; - ax->buffsize = len; - - restore_flags(flags); - - if (oxbuff != NULL) - kfree(oxbuff); - if (orbuff != NULL) - kfree(orbuff); -} - - -/* Set the "sending" flag. This must be atomic, hence the ASM. */ -static inline void ax_lock(struct ax_disp *ax) -{ - if (test_and_set_bit(0, (void *)&ax->dev->tbusy)) - printk(KERN_ERR "mkiss: %s: trying to lock already locked device!\n", ax->dev->name); -} - - -/* Clear the "sending" flag. This must be atomic, hence the ASM. */ -static inline void ax_unlock(struct ax_disp *ax) -{ - if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy)) - printk(KERN_ERR "mkiss: %s: trying to unlock already unlocked device!\n", ax->dev->name); -} - -/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ -static void ax_bump(struct ax_disp *ax) -{ - struct ax_disp *tmp_ax; - struct sk_buff *skb; - struct mkiss_channel *mkiss; - int count; - - tmp_ax = ax; - - if (ax->rbuff[0] > 0x0f) { - if (ax->mkiss != NULL) { - mkiss= ax->mkiss->tty->driver_data; - if (mkiss->magic == MKISS_DRIVER_MAGIC) - tmp_ax = ax->mkiss; - } - } - - count = ax->rcount; - - if ((skb = dev_alloc_skb(count)) == NULL) { - printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); - ax->rx_dropped++; - return; - } - - skb->dev = tmp_ax->dev; - memcpy(skb_put(skb,count), ax->rbuff, count); - skb->mac.raw = skb->data; - skb->protocol = htons(ETH_P_AX25); - netif_rx(skb); - tmp_ax->rx_packets++; -} - -/* Encapsulate one AX.25 packet and stuff into a TTY queue. */ -static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) -{ - unsigned char *p; - int actual, count; - struct mkiss_channel *mkiss = ax->tty->driver_data; - - if (ax->mtu != ax->dev->mtu + 73) /* Someone has been ifconfigging */ - ax_changedmtu(ax); - - if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ - len = ax->mtu; - printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name); - ax->tx_dropped++; - ax_unlock(ax); - return; - } - - p = icp; - - if (mkiss->magic != MKISS_DRIVER_MAGIC) { - count = kiss_esc(p, (unsigned char *)ax->xbuff, len); - ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - actual = ax->tty->driver.write(ax->tty, 0, ax->xbuff, count); - ax->tx_packets++; - ax->dev->trans_start = jiffies; - ax->xleft = count - actual; - ax->xhead = ax->xbuff + actual; - } else { - count = kiss_esc(p, (unsigned char *) ax->mkiss->xbuff, len); - ax->mkiss->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - actual = ax->mkiss->tty->driver.write(ax->mkiss->tty, 0, ax->mkiss->xbuff, count); - ax->tx_packets++; - ax->mkiss->dev->trans_start = jiffies; - ax->mkiss->xleft = count - actual; - ax->mkiss->xhead = ax->mkiss->xbuff + actual; - } -} - -/* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - */ -static void ax25_write_wakeup(struct tty_struct *tty) -{ - int actual; - struct ax_disp *ax = (struct ax_disp *)tty->disc_data; - struct mkiss_channel *mkiss; - - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC || !ax->dev->start) - return; - if (ax->xleft <= 0) { - /* Now serial buffer is almost free & we can start - * transmission of another packet - */ - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - - if (ax->mkiss != NULL) { - mkiss= ax->mkiss->tty->driver_data; - if (mkiss->magic == MKISS_DRIVER_MAGIC) - ax_unlock(ax->mkiss); - } - - ax_unlock(ax); - mark_bh(NET_BH); - return; - } - - actual = tty->driver.write(tty, 0, ax->xhead, ax->xleft); - ax->xleft -= actual; - ax->xhead += actual; -} - -/* Encapsulate an AX.25 packet and kick it into a TTY queue. */ -static int ax_xmit(struct sk_buff *skb, struct device *dev) -{ - struct ax_disp *ax = (struct ax_disp*)dev->priv; - struct mkiss_channel *mkiss = ax->tty->driver_data; - struct ax_disp *tmp_ax; - - tmp_ax = NULL; - - if (mkiss->magic == MKISS_DRIVER_MAGIC) { - if (skb->data[0] < 0x10) - skb->data[0] = skb->data[0] + 0x10; - tmp_ax = ax->mkiss; - } - - if (!dev->start) { - printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); - return 1; - } - - if (tmp_ax != NULL) - if (tmp_ax->dev->tbusy) - return 1; - - if (tmp_ax != NULL) - if (dev->tbusy) { - printk(KERN_ERR "mkiss: dev busy while serial dev is free\n"); - ax_unlock(ax); - } - - if (dev->tbusy) { - /* - * May be we must check transmitter timeout here ? - * 14 Oct 1994 Dmitry Gorodchanin. - */ - if (jiffies - dev->trans_start < 20 * HZ) { - /* 20 sec timeout not reached */ - return 1; - } - - printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, - (ax->tty->driver.chars_in_buffer(ax->tty) || ax->xleft) ? - "bad line quality" : "driver error"); - - ax->xleft = 0; - ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - ax_unlock(ax); - } - - /* We were not busy, so we are now... :-) */ - if (skb != NULL) { - ax_lock(ax); - if (tmp_ax != NULL) - ax_lock(tmp_ax); - ax_encaps(ax, skb->data, skb->len); - kfree_skb(skb, FREE_WRITE); - } - - return 0; -} - -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - -/* Return the frame type ID */ -static int ax_header(struct sk_buff *skb, struct device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) -{ -#ifdef CONFIG_INET - if (type != htons(ETH_P_AX25)) - return ax25_encapsulate(skb, dev, type, daddr, saddr, len); -#endif - return 0; -} - - -static int ax_rebuild_header(struct sk_buff *skb) -{ -#ifdef CONFIG_INET - return ax25_rebuild_header(skb); -#else - return 0; -#endif -} - -#endif /* CONFIG_{AX25,AX25_MODULE} */ - -/* Open the low-level part of the AX25 channel. Easy! */ -static int ax_open(struct device *dev) -{ - struct ax_disp *ax = (struct ax_disp*)dev->priv; - unsigned long len; - - if (ax->tty == NULL) - return -ENODEV; - - /* - * Allocate the frame buffers: - * - * rbuff Receive buffer. - * xbuff Transmit buffer. - * cbuff Temporary compression buffer. - */ - len = dev->mtu * 2; - - /* - * allow for arrival of larger UDP packets, even if we say not to - * also fixes a bug in which SunOS sends 512-byte packets even with - * an MSS of 128 - */ - if (len < 576 * 2) - len = 576 * 2; - - if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) - goto norbuff; - - if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) - goto noxbuff; - - ax->mtu = dev->mtu + 73; - ax->buffsize = len; - ax->rcount = 0; - ax->xleft = 0; - - ax->flags &= (1 << AXF_INUSE); /* Clear ESCAPE & ERROR flags */ - dev->tbusy = 0; - dev->start = 1; - - return 0; - - /* Cleanup */ - kfree(ax->xbuff); - -noxbuff: - kfree(ax->rbuff); - -norbuff: - return -ENOMEM; -} - - -/* Close the low-level part of the AX25 channel. Easy! */ -static int ax_close(struct device *dev) -{ - struct ax_disp *ax = (struct ax_disp*)dev->priv; - - if (ax->tty == NULL) - return -EBUSY; - - ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - - dev->tbusy = 1; - dev->start = 0; - - return 0; -} - -static int ax25_receive_room(struct tty_struct *tty) -{ - return 65536; /* We can handle an infinite amount of data. :-) */ -} - -/* - * Handle the 'receiver data ready' interrupt. - * This function is called by the 'tty_io' module in the kernel when - * a block of data has been received, which can now be decapsulated - * and sent on to the AX.25 layer for further processing. - */ -static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) -{ - struct ax_disp *ax = (struct ax_disp *)tty->disc_data; - - if (ax == NULL || ax->magic != AX25_MAGIC || !ax->dev->start) - return; - - /* - * Argh! mtu change time! - costs us the packet part received - * at the change - */ - if (ax->mtu != ax->dev->mtu + 73) - ax_changedmtu(ax); - - /* Read the characters out of the buffer */ - while (count--) { - if (fp != NULL && *fp++) { - if (!test_and_set_bit(AXF_ERROR, &ax->flags)) - ax->rx_errors++; - cp++; - continue; - } - - kiss_unesc(ax, *cp++); - } -} - -static int ax25_open(struct tty_struct *tty) -{ - struct ax_disp *ax = (struct ax_disp *)tty->disc_data; - struct ax_disp *tmp_ax; - struct mkiss_channel *mkiss; - int err, cnt; - - /* First make sure we're not already connected. */ - if (ax && ax->magic == AX25_MAGIC) - return -EEXIST; - - /* OK. Find a free AX25 channel to use. */ - if ((ax = ax_alloc()) == NULL) - return -ENFILE; - - ax->tty = tty; - tty->disc_data = ax; - - ax->mkiss = NULL; - tmp_ax = NULL; - - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - - /* Restore default settings */ - ax->dev->type = ARPHRD_AX25; - - /* Perform the low-level AX25 initialization. */ - if ((err = ax_open(ax->dev))) - return err; - - mkiss= ax->tty->driver_data; - - if (mkiss->magic == MKISS_DRIVER_MAGIC) { - for (cnt = 1; cnt < ax25_maxdev; cnt++) { - if (ax25_ctrls[cnt]) { - if (ax25_ctrls[cnt]->dev.start) { - if (ax == &ax25_ctrls[cnt]->ctrl) { - cnt--; - tmp_ax = &ax25_ctrls[cnt]->ctrl; - break; - } - } - } - } - } - - if (tmp_ax != NULL) { - ax->mkiss = tmp_ax; - tmp_ax->mkiss = ax; - } - - MOD_INC_USE_COUNT; - - /* Done. We have linked the TTY line to a channel. */ - return ax->dev->base_addr; -} - -static void ax25_close(struct tty_struct *tty) -{ - struct ax_disp *ax = (struct ax_disp *)tty->disc_data; - int mkiss ; - - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC) - return; - - mkiss = ax->mode; - if (ax->dev->flags & IFF_UP) - { - dev_lock_wait(); - dev_close(ax->dev); - dev_unlock_list(); - } - - tty->disc_data = 0; - ax->tty = NULL; - - /* VSV = very important to remove timers */ - ax_free(ax); - unregister_netdev(ax->dev); - - MOD_DEC_USE_COUNT; -} - - -static struct net_device_stats *ax_get_stats(struct device *dev) -{ - static struct net_device_stats stats; - struct ax_disp *ax = (struct ax_disp*)dev->priv; - - memset(&stats, 0, sizeof(struct net_device_stats)); - - stats.rx_packets = ax->rx_packets; - stats.tx_packets = ax->tx_packets; - stats.rx_dropped = ax->rx_dropped; - stats.tx_dropped = ax->tx_dropped; - stats.tx_errors = ax->tx_errors; - stats.rx_errors = ax->rx_errors; - stats.rx_over_errors = ax->rx_over_errors; - - return &stats; -} - - -/************************************************************************ - * STANDARD ENCAPSULATION * - ************************************************************************/ - -int kiss_esc(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; - - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - - *ptr++ = END; - - while (len-- > 0) { - switch (c = *s++) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; - } - } - - *ptr++ = END; - - return ptr - d; -} - -static void kiss_unesc(struct ax_disp *ax, unsigned char s) -{ - switch (s) { - case END: - /* drop keeptest bit = VSV */ - if (test_bit(AXF_KEEPTEST, &ax->flags)) - clear_bit(AXF_KEEPTEST, &ax->flags); - - if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) - ax_bump(ax); - - clear_bit(AXF_ESCAPE, &ax->flags); - ax->rcount = 0; - return; - - case ESC: - set_bit(AXF_ESCAPE, &ax->flags); - return; - case ESC_ESC: - if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) - s = ESC; - break; - case ESC_END: - if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) - s = END; - break; - } - - if (!test_bit(AXF_ERROR, &ax->flags)) { - if (ax->rcount < ax->buffsize) { - ax->rbuff[ax->rcount++] = s; - return; - } - - ax->rx_over_errors++; - set_bit(AXF_ERROR, &ax->flags); - } -} - - -int ax_set_mac_address(struct device *dev, void *addr) -{ - int err; - - if ((err = verify_area(VERIFY_READ, addr, AX25_ADDR_LEN)) != 0) - return err; - - /* addr is an AX.25 shifted ASCII mac address */ - copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN); - - return 0; -} - -static int ax_set_dev_mac_address(struct device *dev, void *addr) -{ - struct sockaddr *sa = addr; - - memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); - - return 0; -} - - -/* Perform I/O control on an active ax25 channel. */ -static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) -{ - struct ax_disp *ax = (struct ax_disp *)tty->disc_data; - int err; - unsigned int tmp; - - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC) - return -EINVAL; - - switch (cmd) { - case SIOCGIFNAME: - if ((err = verify_area(VERIFY_WRITE, arg, strlen(ax->dev->name) + 1)) != 0) - return err; - copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1); - return 0; - - case SIOCGIFENCAP: - if ((err = verify_area(VERIFY_WRITE, arg, sizeof(int))) != 0) - return err; - put_user(4, (int *)arg); - return 0; - - case SIOCSIFENCAP: - if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0) - return err; - get_user(tmp, (int *)arg); - ax->mode = tmp; - ax->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ - ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; - ax->dev->type = ARPHRD_AX25; - return 0; - - case SIOCSIFHWADDR: - return ax_set_mac_address(ax->dev, arg); - - default: - return -ENOIOCTLCMD; - } -} - -static int ax_open_dev(struct device *dev) -{ - struct ax_disp *ax = (struct ax_disp*)dev->priv; - - if (ax->tty==NULL) - return -ENODEV; - - return 0; -} - -/* Initialize AX25 control device -- register AX25 line discipline */ -__initfunc(int mkiss_init_ctrl_dev(void)) -{ - int status; - - if (ax25_maxdev < 4) ax25_maxdev = 4; /* Sanity */ - - if ((ax25_ctrls = kmalloc(sizeof(void*) * ax25_maxdev, GFP_KERNEL)) == NULL) { - printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array ! No mkiss available\n"); - return -ENOMEM; - } - - /* Clear the pointer array, we allocate devices when we need them */ - memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */ - - /* Fill in our line protocol discipline, and register it */ - memset(&ax_ldisc, 0, sizeof(ax_ldisc)); - ax_ldisc.magic = TTY_LDISC_MAGIC; - ax_ldisc.name = "mkiss"; - ax_ldisc.flags = 0; - ax_ldisc.open = ax25_open; - ax_ldisc.close = ax25_close; - ax_ldisc.read = NULL; - ax_ldisc.write = NULL; - ax_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long))ax25_disp_ioctl; - ax_ldisc.poll = NULL; - - ax_ldisc.receive_buf = ax25_receive_buf; - ax_ldisc.receive_room = ax25_receive_room; - ax_ldisc.write_wakeup = ax25_write_wakeup; - - if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) - printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status); - - mkiss_init(); - -#ifdef MODULE - return status; -#else - /* - * Return "not found", so that dev_init() will unlink - * the placeholder device entry for us. - */ - return ENODEV; -#endif -} - - -/* Initialize the driver. Called by network startup. */ - -static int ax25_init(struct device *dev) -{ - struct ax_disp *ax = (struct ax_disp*)dev->priv; - - static char ax25_bcast[AX25_ADDR_LEN] = - {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; - static char ax25_test[AX25_ADDR_LEN] = - {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; - - if (ax == NULL) /* Allocation failed ?? */ - return -ENODEV; - - /* Set up the "AX25 Control Block". (And clear statistics) */ - memset(ax, 0, sizeof (struct ax_disp)); - ax->magic = AX25_MAGIC; - ax->dev = dev; - - /* Finish setting up the DEVICE info. */ - dev->mtu = AX_MTU; - dev->hard_start_xmit = ax_xmit; - dev->open = ax_open_dev; - dev->stop = ax_close; - dev->get_stats = ax_get_stats; -#ifdef HAVE_SET_MAC_ADDR - dev->set_mac_address = ax_set_dev_mac_address; -#endif - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_AX25; - dev->tx_queue_len = 10; - - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); - -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - dev->hard_header = ax_header; - dev->rebuild_header = ax_rebuild_header; -#endif - - dev_init_buffers(dev); - - /* New-style flags. */ - dev->flags = 0; - - return 0; -} - -static int mkiss_open(struct tty_struct *tty, struct file *filp) -{ - struct mkiss_channel *mkiss; - int chan; - - chan = MINOR(tty->device) - tty->driver.minor_start; - - if (chan < 0 || chan >= NR_MKISS) - return -ENODEV; - - mkiss = &MKISS_Info[chan]; - - mkiss->magic = MKISS_DRIVER_MAGIC; - mkiss->init = 1; - mkiss->tty = tty; - - tty->driver_data = mkiss; - - tty->termios->c_iflag = IGNBRK | IGNPAR; - tty->termios->c_cflag = B9600 | CS8 | CLOCAL; - tty->termios->c_cflag &= ~CBAUD; - - return 0; -} - -static void mkiss_close(struct tty_struct *tty, struct file * filp) -{ - struct mkiss_channel *mkiss = tty->driver_data; - - if (mkiss == NULL || mkiss->magic != MKISS_DRIVER_MAGIC) - return; - - mkiss->tty = NULL; - mkiss->init = 0; - tty->stopped = 0; -} - -static int mkiss_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) -{ - return 0; -} - -static int mkiss_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) -{ - /* Ignore serial ioctl's */ - switch (cmd) { - case TCSBRK: - case TIOCMGET: - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - case TCSETS: - case TCSETSF: /* should flush first, but... */ - case TCSETSW: /* should wait until flush, but... */ - return 0; - default: - return -ENOIOCTLCMD; - } -} - - -static void mkiss_dummy(struct tty_struct *tty) -{ - struct mkiss_channel *mkiss = tty->driver_data; - - if (tty == NULL) - return; - - if (mkiss == NULL) - return; -} - -static void mkiss_dummy2(struct tty_struct *tty, unsigned char ch) -{ - struct mkiss_channel *mkiss = tty->driver_data; - - if (tty == NULL) - return; - - if (mkiss == NULL) - return; -} - - -static int mkiss_write_room(struct tty_struct * tty) -{ - struct mkiss_channel *mkiss = tty->driver_data; - - if (tty == NULL) - return 0; - - if (mkiss == NULL) - return 0; - - return 65536; /* We can handle an infinite amount of data. :-) */ -} - - -static int mkiss_chars_in_buffer(struct tty_struct *tty) -{ - struct mkiss_channel *mkiss = tty->driver_data; - - if (tty == NULL) - return 0; - - if (mkiss == NULL) - return 0; - - return 0; -} - - -static void mkiss_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - /* we don't do termios */ -} - -/* ******************************************************************** */ -/* * Init MKISS driver * */ -/* ******************************************************************** */ - -__initfunc(static int mkiss_init(void)) -{ - memset(&mkiss_driver, 0, sizeof(struct tty_driver)); - - mkiss_driver.magic = MKISS_DRIVER_MAGIC; - mkiss_driver.name = "mkiss"; - mkiss_driver.major = MKISS_MAJOR; - mkiss_driver.minor_start = 0; - mkiss_driver.num = NR_MKISS; - mkiss_driver.type = TTY_DRIVER_TYPE_SERIAL; - mkiss_driver.subtype = MKISS_SERIAL_TYPE_NORMAL; /* not needed */ - - mkiss_driver.init_termios = tty_std_termios; - mkiss_driver.init_termios.c_iflag = IGNBRK | IGNPAR; - mkiss_driver.init_termios.c_cflag = B9600 | CS8 | CLOCAL; - - mkiss_driver.flags = TTY_DRIVER_REAL_RAW; - mkiss_driver.refcount = &mkiss_refcount; - mkiss_driver.table = mkiss_table; - mkiss_driver.termios = (struct termios **)mkiss_termios; - mkiss_driver.termios_locked = (struct termios **)mkiss_termios_locked; - - mkiss_driver.ioctl = mkiss_ioctl; - mkiss_driver.open = mkiss_open; - mkiss_driver.close = mkiss_close; - mkiss_driver.write = mkiss_write; - mkiss_driver.write_room = mkiss_write_room; - mkiss_driver.chars_in_buffer = mkiss_chars_in_buffer; - mkiss_driver.set_termios = mkiss_set_termios; - - /* some unused functions */ - mkiss_driver.flush_buffer = mkiss_dummy; - mkiss_driver.throttle = mkiss_dummy; - mkiss_driver.unthrottle = mkiss_dummy; - mkiss_driver.stop = mkiss_dummy; - mkiss_driver.start = mkiss_dummy; - mkiss_driver.hangup = mkiss_dummy; - mkiss_driver.flush_chars = mkiss_dummy; - mkiss_driver.put_char = mkiss_dummy2; - - if (tty_register_driver(&mkiss_driver)) { - printk(KERN_ERR "mkiss: couldn't register Mkiss device\n"); - return -EIO; - } - - printk(KERN_INFO "AX.25 Multikiss device enabled\n"); - - return 0; -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -MODULE_PARM(ax25_maxdev, "i"); -MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices"); - -MODULE_AUTHOR("Hans Albas PE1AYX "); -MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); - -int init_module(void) -{ - return mkiss_init_ctrl_dev(); -} - -void cleanup_module(void) -{ - int i; - - if (ax25_ctrls != NULL) { - for (i = 0; i < ax25_maxdev; i++) { - if (ax25_ctrls[i]) { - /* - * VSV = if dev->start==0, then device - * unregistred while close proc. - */ - if (ax25_ctrls[i]->dev.start) - unregister_netdev(&(ax25_ctrls[i]->dev)); - - kfree(ax25_ctrls[i]); - ax25_ctrls[i] = NULL; - } - } - - kfree(ax25_ctrls); - ax25_ctrls = NULL; - } - - if ((i = tty_register_ldisc(N_AX25, NULL))) - printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i); - - if (tty_unregister_driver(&mkiss_driver)) /* remove devive */ - printk(KERN_ERR "mkiss: can't unregister MKISS device\n"); -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/mkiss.h linux/drivers/net/mkiss.h --- v2.1.70/linux/drivers/net/mkiss.h Sun Nov 10 09:12:56 1996 +++ linux/drivers/net/mkiss.h Wed Dec 31 16:00:00 1969 @@ -1,56 +0,0 @@ -/**************************************************************************** - * Defines for the Multi-KISS driver. - ****************************************************************************/ - -#define AX25_MAXDEV 16 /* MAX number of AX25 channels; - This can be overridden with - insmod -oax25_maxdev=nnn */ -#define AX_MTU 236 - -/* SLIP/KISS protocol characters. */ -#define END 0300 /* indicates end of frame */ -#define ESC 0333 /* indicates byte stuffing */ -#define ESC_END 0334 /* ESC ESC_END means END 'data' */ -#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ - -struct ax_disp { - int magic; - - /* Various fields. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct device *dev; /* easy for intr handling */ - struct ax_disp *mkiss; /* mkiss txport if mkiss channel*/ - - /* These are pointers to the malloc()ed frame buffers. */ - unsigned char *rbuff; /* receiver buffer */ - int rcount; /* received chars counter */ - unsigned char *xbuff; /* transmitter buffer */ - unsigned char *xhead; /* pointer to next byte to XMIT */ - int xleft; /* bytes left in XMIT queue */ - - /* SLIP interface statistics. */ - unsigned long rx_packets; /* inbound frames counter */ - unsigned long tx_packets; /* outbound frames counter */ - unsigned long rx_errors; /* Parity, etc. errors */ - unsigned long tx_errors; /* Planned stuff */ - unsigned long rx_dropped; /* No memory for skb */ - unsigned long tx_dropped; /* When MTU change */ - unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ - - /* Detailed SLIP statistics. */ - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ - - - unsigned char flags; /* Flag values/ mode etc */ -#define AXF_INUSE 0 /* Channel in use */ -#define AXF_ESCAPE 1 /* ESC received */ -#define AXF_ERROR 2 /* Parity, etc. error */ -#define AXF_KEEPTEST 3 /* Keepalive test flag */ -#define AXF_OUTWAIT 4 /* is outpacket was flag */ - - int mode; -}; - -#define AX25_MAGIC 0x5316 -#define MKISS_DRIVER_MAGIC 1215 diff -u --recursive --new-file v2.1.70/linux/drivers/net/pi2.c linux/drivers/net/pi2.c --- v2.1.70/linux/drivers/net/pi2.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/pi2.c Wed Dec 31 16:00:00 1969 @@ -1,1677 +0,0 @@ -/* - pi2.c: Driver for the Ottawa Amateur Radio Club PI and PI2 interface. - Copyright (c) 1994 David Perry - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2, as - published by the Free Software Foundation. - - 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. - - The file skeleton.c by Donald Becker was used as a starting point - for this driver. - - Revision History - - April 6, 1994 (dp) Created - version 0.0 ALPHA - April 10, 1994 (dp) Included cleanup, suggestions from J. P. Morrison. - version 0.1 ALPHA - April 13, 1994 (dp) Included address probing from JPM, autoirq - version 0.2 ALPHA - April 14, 1994 (ac) Sketched in the NET3 changes. - April 17, 1994 (dp) Finished the NET3 changes. Used init_etherdev() - instead of kmalloc() to ensure that DMA buffers will - reside under the 16 meg line. - version 0.4 ALPHA - April 18, 1994 (dp) Now using the kernel provided sk_buff handling functions. - Fixed a nasty problem with DMA. - version 0.5 ALPHA - June 6, 1994 (ac) Fixed to match the buffer locking changes. Added a hack to - fix a funny I see (search for HACK) and fixed the calls in - init() so it doesn't migrate module based ethernet cards up - to eth2 Took out the old module ideas as they are no longer - relevant to the PI driver. - July 16, 1994 (dp) Fixed the B channel rx overrun problem ac referred to - above. Also added a bit of a hack to improve the maximum - baud rate on the B channel (Search for STUFF2). Included - ioctl stuff from John Paul Morrison. version 0.6 ALPHA - Feb 9, 1995 (dp) Updated for 1.1.90 kernel - version 0.7 ALPHA - Apr 6, 1995 (ac) Tweaks for NET3 pre snapshot 002 AX.25 - April 23, 1995 (dp) Fixed ioctl so it works properly with piconfig program - when changing the baud rate or clock mode. - version 0.8 ALPHA - July 17, 1995 (ac) Finally polishing of AX25.030+ support - Oct 29, 1995 (ac) A couple of minor fixes before this, and this release changes - to the proper set_mac_address semantics which will break - a few programs I suspect. - Aug 18, 1996 (jsn) Converted to be used as a module. - Dec 13, 1996 (jsn) Fixed to match Linux networking changes. -*/ - -/* The following #define invokes a hack that will improve performance (baud) - for the B port. The up side is it makes 9600 baud work ok on the B port. - It may do 38400, depending on the host. The down side is it burns up - CPU cycles with ints locked for up to 1 character time, at the beginning - of each transmitted packet. If this causes you to lose sleep, #undefine it. -*/ - -/*#define STUFF2 1*/ - -/* The default configuration */ -#define PI_DMA 3 - -#define DEF_A_SPEED 0 /* 0 means external clock */ -#define DEF_A_TXDELAY 15 /* 15 mS transmit delay */ -#define DEF_A_PERSIST 128 /* 50% persistence */ -#define DEF_A_SLOTIME 15 /* 15 mS slot time */ -#define DEF_A_SQUELDELAY 1 /* 1 mS squelch delay - allows fcs and flag */ -#define DEF_A_CLOCKMODE 0 /* clock mode - 0 is normal */ - -#define DEF_B_SPEED 1200 /* 1200 baud */ -#define DEF_B_TXDELAY 40 /* 400 mS */ -#define DEF_B_PERSIST 128 /* 50% */ -#define DEF_B_SLOTIME 30 /* 300 mS */ -#define DEF_B_SQUELDELAY 3 /* 30 mS */ -#define DEF_B_CLOCKMODE 0 /* Normal clock mode */ - -/* The following #define is only really required for the PI card, not - the PI2 - but it's safer to leave it in. */ -#define REALLY_SLOW_IO 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "z8530.h" -#include - -struct mbuf { - struct mbuf *next; - int cnt; - char data[0]; -}; - -/* - * The actual devices we will use - */ - -/* - * PI device declarations. - */ - -static int pi0_preprobe(struct device *dev){return 0;} /* Dummy probe function */ -static struct device pi0a = { "pi0a", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pi0_preprobe }; -static struct device pi0b = { "pi0b", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pi0_preprobe }; - - -/* The number of low I/O ports used by the card. */ -#define PI_TOTAL_SIZE 8 - - -/* Index to functions, as function prototypes. */ - -static int pi_probe(struct device *dev, int card_type); -static int pi_open(struct device *dev); -static int pi_send_packet(struct sk_buff *skb, struct device *dev); -static void pi_interrupt(int reg_ptr, void *dev_id, struct pt_regs *regs); -static int pi_close(struct device *dev); -static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd); -static struct net_device_stats *pi_get_stats(struct device *dev); -static void rts(struct pi_local *lp, int x); -static void b_rxint(struct device *dev, struct pi_local *lp); -static void b_txint(struct pi_local *lp); -static void b_exint(struct pi_local *lp); -static void a_rxint(struct device *dev, struct pi_local *lp); -static void a_txint(struct pi_local *lp); -static void a_exint(struct pi_local *lp); -static char *get_dma_buffer(unsigned long *mem_ptr); -static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize); - -static char ax25_bcast[7] = -{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static char ax25_test[7] = -{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - -static int ext2_secrm_seed = 152; /* Random generator base */ - -extern inline unsigned char random(void) -{ - return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed - * 69069l + 1); -} - -extern inline void wrtscc(int cbase, int ctl, int sccreg, int val) -{ - /* assume caller disables interrupts! */ - outb_p(0, cbase + DMAEN); /* Disable DMA while we touch the scc */ - outb_p(sccreg, ctl); /* Select register */ - outb_p(val, ctl); /* Output value */ - outb_p(1, cbase + DMAEN); /* Enable DMA */ -} - -extern inline int rdscc(int cbase, int ctl, int sccreg) -{ - int retval; - - /* assume caller disables interrupts! */ - outb_p(0, cbase + DMAEN); /* Disable DMA while we touch the scc */ - outb_p(sccreg, ctl); /* Select register */ - retval = inb_p(ctl); - outb_p(1, cbase + DMAEN); /* Enable DMA */ - return retval; -} - -static void switchbuffers(struct pi_local *lp) -{ - if (lp->rcvbuf == lp->rxdmabuf1) - lp->rcvbuf = lp->rxdmabuf2; - else - lp->rcvbuf = lp->rxdmabuf1; -} - -static void hardware_send_packet(struct pi_local *lp, struct sk_buff *skb) -{ - char kickflag; - unsigned long flags; - - lp->stats.tx_packets++; - - save_flags(flags); - cli(); - kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL); - restore_flags(flags); - - skb_queue_tail(&lp->sndq, skb); - if (kickflag) - { - /* simulate interrupt to xmit */ - switch (lp->base & 2) - { - case 2: - a_txint(lp); /* process interrupt */ - break; - case 0: - save_flags(flags); - cli(); - if (lp->tstate == IDLE) - b_txint(lp); - restore_flags(flags); - break; - } - } -} - -static void setup_rx_dma(struct pi_local *lp) -{ - unsigned long flags; - int cmd; - unsigned long dma_abs; - unsigned dmachan; - - save_flags(flags); - cli(); - - dma_abs = (unsigned long) (lp->rcvbuf->data); - dmachan = lp->dmachan; - cmd = lp->base + CTL; - - if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf))) - panic("PI: RX buffer violates DMA boundary!"); - - /* Get ready for RX DMA */ - wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); - - disable_dma(dmachan); - clear_dma_ff(dmachan); - - /* Set DMA mode register to single transfers, incrementing address, - * auto init, writes - */ - set_dma_mode(dmachan, DMA_MODE_READ | 0x10); - set_dma_addr(dmachan, dma_abs); - set_dma_count(dmachan, lp->bufsiz); - enable_dma(dmachan); - - /* If a packet is already coming in, this line is supposed to - avoid receiving a partial packet. - */ - wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC); - - /* Enable RX dma */ - wrtscc(lp->cardbase, cmd, R1, - WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); - - restore_flags(flags); -} - -static void setup_tx_dma(struct pi_local *lp, int length) -{ - unsigned long dma_abs; - unsigned long flags; - unsigned long dmachan; - - save_flags(flags); - cli(); - - dmachan = lp->dmachan; - dma_abs = (unsigned long) (lp->txdmabuf); - - if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf))) - panic("PI: TX buffer violates DMA boundary!"); - - disable_dma(dmachan); - /* Set DMA mode register to single transfers, incrementing address, - * no auto init, reads - */ - set_dma_mode(dmachan, DMA_MODE_WRITE); - clear_dma_ff(dmachan); - set_dma_addr(dmachan, dma_abs); - /* output byte count */ - set_dma_count(dmachan, length); - - restore_flags(flags); -} - -static void tdelay(struct pi_local *lp, int time) -{ - int port; - unsigned int t1; - unsigned char sc; - - if (lp->base & 2) { /* If A channel */ - sc = SC1; - t1 = time; - port = lp->cardbase + TMR1; - } else { - sc = SC2; - t1 = 10 * time; /* 10s of milliseconds for the B channel */ - port = lp->cardbase + TMR2; - wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB); - } - - /* Setup timer sc */ - outb_p(sc | LSB_MSB | MODE0, lp->cardbase + TMRCMD); - - /* times 2 to make millisecs */ - outb_p((t1 << 1) & 0xFF, port); - outb_p((t1 >> 7) & 0xFF, port); - - /* Enable correct int for timeout */ - wrtscc(lp->cardbase, lp->base + CTL, R15, CTSIE); - wrtscc(lp->cardbase, lp->base + CTL, R0, RES_EXT_INT); -} - -static void a_txint(struct pi_local *lp) -{ - int cmd; - unsigned long flags; - - save_flags(flags); - cli(); - - cmd = CTL + lp->base; - - switch (lp->tstate) { - case IDLE: - /* Transmitter idle. Find a frame for transmission */ - if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { - rts(lp, OFF); - restore_flags(flags); - return; - } - /* If a buffer to send, we drop thru here */ - case DEFER: - /* we may have deferred prev xmit attempt */ - /* Check DCD - debounce it - * See Intel Microcommunications Handbook, p2-308 - */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { - lp->tstate = DEFER; - tdelay(lp, 100); - /* defer until DCD transition or timeout */ - wrtscc(lp->cardbase, cmd, R15, CTSIE | DCDIE); - restore_flags(flags); - return; - } - if (random() > lp->persist) { - lp->tstate = DEFER; - tdelay(lp, lp->slotime); - restore_flags(flags); - return; - } - /* Assert RTS early minimize collision window */ - wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); - rts(lp, ON); /* Transmitter on */ - lp->tstate = ST_TXDELAY; - tdelay(lp, lp->txdelay); - restore_flags(flags); - return; - default: - break; - } /* end switch(lp->state) */ - - restore_flags(flags); -} /*a_txint */ - -static void a_exint(struct pi_local *lp) -{ - unsigned long flags; - int cmd; - char st; - int length; - - save_flags(flags); - cli(); /* disable interrupts */ - - st = rdscc(lp->cardbase, lp->base + CTL, R0); /* Fetch status */ - - /* reset external status latch */ - wrtscc(lp->cardbase, CTL + lp->base, R0, RES_EXT_INT); - cmd = lp->base + CTL; - - if ((lp->rstate >= ACTIVE) && (st & BRK_ABRT)) { - setup_rx_dma(lp); - lp->rstate = ACTIVE; - } - switch (lp->tstate) { - case ACTIVE: - kfree_skb(lp->sndbuf, FREE_WRITE); - lp->sndbuf = NULL; - lp->tstate = FLAGOUT; - tdelay(lp, lp->squeldelay); - break; - case FLAGOUT: - if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { - /* Nothing to send - return to receive mode */ - lp->tstate = IDLE; - rts(lp, OFF); - restore_flags(flags); - return; - } - /* NOTE - fall through if more to send */ - case ST_TXDELAY: - /* Disable DMA chan */ - disable_dma(lp->dmachan); - - /* Set up for TX dma */ - wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); - - - /* Get all chars */ - /* Strip KISS control byte */ - length = lp->sndbuf->len - 1; - memcpy(lp->txdmabuf, &lp->sndbuf->data[1], length); - - - /* Setup DMA controller for tx */ - setup_tx_dma(lp, length); - - /* select transmit interrupts to enable */ - /* Allow DMA on chan */ - enable_dma(lp->dmachan); - - /* reset CRC, Txint pend*/ - wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC | RES_Tx_P); - - /* allow Underrun int only */ - wrtscc(lp->cardbase, cmd, R15, TxUIE); - - /* Enable TX DMA */ - wrtscc(lp->cardbase, cmd, R1, WT_RDY_ENAB | WT_FN_RDYFN | EXT_INT_ENAB); - - /* Send CRC on underrun */ - wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); - - - /* packet going out now */ - lp->tstate = ACTIVE; - break; - case DEFER: - /* we have deferred prev xmit attempt - * See Intel Microcommunications Handbook, p2-308 - */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { - lp->tstate = DEFER; - tdelay(lp, 100); - /* Defer until dcd transition or 100mS timeout */ - wrtscc(lp->cardbase, CTL + lp->base, R15, CTSIE | DCDIE); - restore_flags(flags); - return; - } - if (random() > lp->persist) { - lp->tstate = DEFER; - tdelay(lp, lp->slotime); - restore_flags(flags); - return; - } - /* Assert RTS early minimize collision window */ - wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); - rts(lp, ON); /* Transmitter on */ - lp->tstate = ST_TXDELAY; - tdelay(lp, lp->txdelay); - restore_flags(flags); - return; - } /* switch(lp->tstate) */ - - restore_flags(flags); -} /* a_exint() */ - -/* Receive interrupt handler for the A channel - */ -static void a_rxint(struct device *dev, struct pi_local *lp) -{ - unsigned long flags; - int cmd; - int bytecount; - char rse; - struct sk_buff *skb; - int sksize, pkt_len; - struct mbuf *cur_buf; - unsigned char *cfix; - - save_flags(flags); - cli(); /* disable interrupts */ - cmd = lp->base + CTL; - - rse = rdscc(lp->cardbase, cmd, R1); /* Get special condition bits from R1 */ - if (rse & Rx_OVR) - lp->rstate = RXERROR; - - if (rse & END_FR) { - /* If end of frame */ - /* figure length of frame from 8237 */ - clear_dma_ff(lp->dmachan); - bytecount = lp->bufsiz - get_dma_residue(lp->dmachan); - - if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (bytecount < 10)) { - if ((bytecount >= 10) && (rse & CRC_ERR)) { - lp->stats.rx_crc_errors++; - } - if (lp->rstate == RXERROR) { - lp->stats.rx_errors++; - lp->stats.rx_over_errors++; - } - /* Reset buffer pointers */ - lp->rstate = ACTIVE; - setup_rx_dma(lp); - } else { - /* Here we have a valid frame */ - /* Toss 2 crc bytes , add one for KISS */ - pkt_len = lp->rcvbuf->cnt = bytecount - 2 + 1; - - /* Get buffer for next frame */ - cur_buf = lp->rcvbuf; - switchbuffers(lp); - setup_rx_dma(lp); - - - /* Malloc up new buffer. */ - sksize = pkt_len; - - skb = dev_alloc_skb(sksize); - if (skb == NULL) { - printk(KERN_ERR "PI: %s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; - restore_flags(flags); - return; - } - skb->dev = dev; - - /* KISS kludge - prefix with a 0 byte */ - cfix=skb_put(skb,pkt_len); - *cfix++=0; - /* 'skb->data' points to the start of sk_buff data area. */ - memcpy(cfix, (char *) cur_buf->data, - pkt_len - 1); - skb->protocol=htons(ETH_P_AX25); - skb->mac.raw=skb->data; - netif_rx(skb); - lp->stats.rx_packets++; - } /* end good frame */ - } /* end EOF check */ - wrtscc(lp->cardbase, lp->base + CTL, R0, ERR_RES); /* error reset */ - restore_flags(flags); -} - -static void b_rxint(struct device *dev, struct pi_local *lp) -{ - unsigned long flags; - int cmd; - char rse; - struct sk_buff *skb; - int sksize; - int pkt_len; - unsigned char *cfix; - - save_flags(flags); - cli(); /* disable interrupts */ - cmd = CTL + lp->base; - - rse = rdscc(lp->cardbase, cmd, R1); /* get status byte from R1 */ - - if ((rdscc(lp->cardbase, cmd, R0)) & Rx_CH_AV) { - /* there is a char to be stored - * read special condition bits before reading the data char - */ - if (rse & Rx_OVR) { - /* Rx overrun - toss buffer */ - /* reset buffer pointers */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - - lp->rstate = RXERROR; /* set error flag */ - lp->stats.rx_errors++; - lp->stats.rx_over_errors++; - } else if (lp->rcvbuf->cnt >= lp->bufsiz) { - /* Too large -- toss buffer */ - /* reset buffer pointers */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - lp->rstate = TOOBIG;/* when set, chars are not stored */ - } - /* ok, we can store the received character now */ - if (lp->rstate == ACTIVE) { /* If no errors... */ - *lp->rcp++ = rdscc(lp->cardbase, cmd, R8); /* char to rcv buff */ - lp->rcvbuf->cnt++; /* bump count */ - } else { - /* got to empty FIFO */ - (void) rdscc(lp->cardbase, cmd, R8); - wrtscc(lp->cardbase, cmd, R0, ERR_RES); /* reset err latch */ - lp->rstate = ACTIVE; - } - } - if (rse & END_FR) { - /* END OF FRAME -- Make sure Rx was active */ - if (lp->rcvbuf->cnt > 0) { - if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (lp->rcvbuf->cnt < 10)) { - if ((lp->rcvbuf->cnt >= 10) && (rse & CRC_ERR)) { - lp->stats.rx_crc_errors++; - } - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - } else { - /* Here we have a valid frame */ - pkt_len = lp->rcvbuf->cnt -= 2; /* Toss 2 crc bytes */ - pkt_len += 1; /* Make room for KISS control byte */ - - /* Malloc up new buffer. */ - sksize = pkt_len; - skb = dev_alloc_skb(sksize); - if (skb == NULL) { - printk(KERN_ERR "PI: %s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; - restore_flags(flags); - return; - } - skb->dev = dev; - - /* KISS kludge - prefix with a 0 byte */ - cfix=skb_put(skb,pkt_len); - *cfix++=0; - /* 'skb->data' points to the start of sk_buff data area. */ - memcpy(cfix, lp->rcvbuf->data, pkt_len - 1); - skb->protocol=ntohs(ETH_P_AX25); - skb->mac.raw=skb->data; - netif_rx(skb); - lp->stats.rx_packets++; - /* packet queued - initialize buffer for next frame */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - - } /* end good frame queued */ - } /* end check for active receive upon EOF */ - lp->rstate = ACTIVE; /* and clear error status */ - } /* end EOF check */ - restore_flags(flags); -} - - -static void b_txint(struct pi_local *lp) -{ - unsigned long flags; - int cmd; - unsigned char c; - - save_flags(flags); - cli(); - cmd = CTL + lp->base; - - switch (lp->tstate) { - case CRCOUT: - lp->tstate = FLAGOUT; - tdelay(lp, lp->squeldelay); - restore_flags(flags); - return; - case IDLE: - /* Transmitter idle. Find a frame for transmission */ - if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { - /* Nothing to send - return to receive mode - * Tx OFF now - flag should have gone - */ - rts(lp, OFF); - - restore_flags(flags); - return; - } - lp->txptr = lp->sndbuf->data; - lp->txptr++; /* Ignore KISS control byte */ - lp->txcnt = (int) lp->sndbuf->len - 1; - /* If a buffer to send, we drop thru here */ - case DEFER: /* we may have deferred prev xmit attempt */ - /* Check DCD - debounce it */ - /* See Intel Microcommunications Handbook, p2-308 */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { - lp->tstate = DEFER; - tdelay(lp, 100); - /* defer until DCD transition or timeout */ - wrtscc(lp->cardbase, cmd, R15, CTSIE | DCDIE); - restore_flags(flags); - return; - } - if (random() > lp->persist) { - lp->tstate = DEFER; - tdelay(lp, lp->slotime); - restore_flags(flags); - return; - } - rts(lp, ON); /* Transmitter on */ - lp->tstate = ST_TXDELAY; - tdelay(lp, lp->txdelay); - restore_flags(flags); - return; - - case ACTIVE: - /* Here we are actively sending a frame */ - if (lp->txcnt--) { - c = *lp->txptr++; - /* next char is gone */ - wrtscc(lp->cardbase, cmd, R8, c); - /* stuffing a char satisfies Interrupt condition */ - } else { - /* No more to send */ - kfree_skb(lp->sndbuf, FREE_WRITE); - lp->sndbuf = NULL; - if ((rdscc(lp->cardbase, cmd, R0) & 0x40)) { - /* Did we underrun? */ - /* unexpected underrun */ - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); - lp->tstate = FLAGOUT; - tdelay(lp, lp->squeldelay); - restore_flags(flags); - return; - } - lp->tstate = UNDERRUN; /* Now we expect to underrun */ - /* Send flags on underrun */ - if (lp->speed) { /* If internally clocked */ - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); - } else { - wrtscc(lp->cardbase, cmd, R10, CRCPS); - } - wrtscc(lp->cardbase, cmd, R0, RES_Tx_P); /* reset Tx Int Pend */ - } - restore_flags(flags); - return; /* back to wait for interrupt */ - } /* end switch */ - restore_flags(flags); -} - -/* Pi SIO External/Status interrupts (for the B channel) - * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM. - * Receiver automatically goes to Hunt on an abort. - * - * If the Tx Underrun interrupt hits, change state and - * issue a reset command for it, and return. - */ -static void b_exint(struct pi_local *lp) -{ - unsigned long flags; - char st; - int cmd; - char c; - - cmd = CTL + lp->base; - save_flags(flags); - cli(); /* disable interrupts */ - st = rdscc(lp->cardbase, cmd, R0); /* Fetch status */ - /* reset external status latch */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - - - switch (lp->tstate) { - case ACTIVE: /* Unexpected underrun */ - kfree_skb(lp->sndbuf, FREE_WRITE); - lp->sndbuf = NULL; - wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); - lp->tstate = FLAGOUT; - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - tdelay(lp, lp->squeldelay); - restore_flags(flags); - return; - case UNDERRUN: - lp->tstate = CRCOUT; - restore_flags(flags); - return; - case FLAGOUT: - /* Find a frame for transmission */ - if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { - /* Nothing to send - return to receive mode - * Tx OFF now - flag should have gone - */ - rts(lp, OFF); - lp->tstate = IDLE; - restore_flags(flags); - return; - } - lp->txptr = lp->sndbuf->data; - lp->txptr++; /* Ignore KISS control byte */ - lp->txcnt = (int) lp->sndbuf->len - 1; - /* Get first char to send */ - lp->txcnt--; - c = *lp->txptr++; - wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC); /* reset for next frame */ - - /* Send abort on underrun */ - if (lp->speed) { /* If internally clocked */ - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI | ABUNDER); - } else { - wrtscc(lp->cardbase, cmd, R10, CRCPS | ABUNDER); - } - - wrtscc(lp->cardbase, cmd, R8, c); /* First char out now */ - wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); /* Reset end of message latch */ - -#ifdef STUFF2 - /* stuff an extra one if we can */ - if (lp->txcnt) { - lp->txcnt--; - c = *lp->txptr++; - /* Wait for tx buffer empty */ - while((rdscc(lp->cardbase, cmd, R0) & 0x04) == 0) - ; - wrtscc(lp->cardbase, cmd, R8, c); - } -#endif - - /* select transmit interrupts to enable */ - - wrtscc(lp->cardbase, cmd, R15, TxUIE); /* allow Underrun int only */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - wrtscc(lp->cardbase, cmd, R1, TxINT_ENAB | EXT_INT_ENAB); /* Tx/Ext ints */ - - lp->tstate = ACTIVE; /* char going out now */ - restore_flags(flags); - return; - - case DEFER: - /* Check DCD - debounce it - * See Intel Microcommunications Handbook, p2-308 - */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { - lp->tstate = DEFER; - tdelay(lp, 100); - /* defer until DCD transition or timeout */ - wrtscc(lp->cardbase, cmd, R15, CTSIE | DCDIE); - restore_flags(flags); - return; - } - if (random() > lp->persist) { - lp->tstate = DEFER; - tdelay(lp, lp->slotime); - restore_flags(flags); - return; - } - rts(lp, ON); /* Transmitter on */ - lp->tstate = ST_TXDELAY; - tdelay(lp, lp->txdelay); - restore_flags(flags); - return; - - case ST_TXDELAY: - - /* Get first char to send */ - lp->txcnt--; - c = *lp->txptr++; - wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC); /* reset for next frame */ - - /* Send abort on underrun */ - if (lp->speed) { /* If internally clocked */ - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI | ABUNDER); - } else { - wrtscc(lp->cardbase, cmd, R10, CRCPS | ABUNDER); - } - - wrtscc(lp->cardbase, cmd, R8, c); /* First char out now */ - wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); /* Reset end of message latch */ - -#ifdef STUFF2 - /* stuff an extra one if we can */ - if (lp->txcnt) { - lp->txcnt--; - c = *lp->txptr++; - /* Wait for tx buffer empty */ - while((rdscc(lp->cardbase, cmd, R0) & 0x04) == 0) - ; - wrtscc(lp->cardbase, cmd, R8, c); - } -#endif - - /* select transmit interrupts to enable */ - - wrtscc(lp->cardbase, cmd, R15, TxUIE); /* allow Underrun int only */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - /* Tx/Extern ints on */ - wrtscc(lp->cardbase, cmd, R1, TxINT_ENAB | EXT_INT_ENAB); - - lp->tstate = ACTIVE; /* char going out now */ - restore_flags(flags); - return; - } - - /* Receive Mode only - * This triggers when hunt mode is entered, & since an ABORT - * automatically enters hunt mode, we use that to clean up - * any waiting garbage - */ - if ((lp->rstate == ACTIVE) && (st & BRK_ABRT)) { - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; /* rewind on DCD transition */ - } - restore_flags(flags); -} - -/* Probe for a PI card. */ -/* This routine also initializes the timer chip */ - -__initfunc(static int hw_probe(int ioaddr)) -{ - int time = 1000; /* Number of milliseconds for test */ - unsigned long start_time, end_time; - - int base, tmr0, tmr1, tmrcmd; - int a = 1; - int b = 1; - - base = ioaddr & 0x3f0; - tmr0 = TMR0 + base; - tmr1 = TMR1 + base; - tmrcmd = TMRCMD + base; - - /* Set up counter chip timer 0 for 500 uS period square wave */ - /* assuming a 3.68 mhz clock for now */ - outb_p(SC0 | LSB_MSB | MODE3, tmrcmd); - outb_p(922 & 0xFF, tmr0); - outb_p(922 >> 8, tmr0); - - /* Setup timer control word for timer 1*/ - outb_p(SC1 | LSB_MSB | MODE0, tmrcmd); - outb_p((time << 1) & 0xFF, tmr1); - outb_p((time >> 7) & 0XFF, tmr1); - - /* wait until counter reg is loaded */ - do { - /* Latch count for reading */ - outb_p(SC1, tmrcmd); - a = inb_p(tmr1); - b = inb_p(tmr1); - } while (b == 0); - start_time = jiffies; - while (b != 0) { - /* Latch count for reading */ - outb_p(SC1, tmrcmd); - a = inb_p(tmr1); - b = inb_p(tmr1); - end_time = jiffies; - /* Don't wait forever - there may be no card here */ - if ((end_time - start_time) > 200) - return 0; /* No card found */ - } - end_time = jiffies; - /* 87 jiffies, for a 3.68 mhz clock, half that for a double speed clock */ - if ((end_time - start_time) > 65) { - return (1); /* PI card found */ - } else { - /* Faster crystal - tmr0 needs adjusting */ - /* Set up counter chip */ - /* 500 uS square wave */ - outb_p(SC0 | LSB_MSB | MODE3, tmrcmd); - outb_p(1844 & 0xFF, tmr0); - outb_p(1844 >> 8, tmr0); - return (2); /* PI2 card found */ - } -} - -static void rts(struct pi_local *lp, int x) -{ - int tc; - long br; - int cmd; - int dummy; - - /* assumes interrupts are off */ - cmd = CTL + lp->base; - - /* Reprogram BRG and turn on transmitter to send flags */ - if (x == ON) { /* Turn Tx ON and Receive OFF */ - /* Exints off first to avoid abort int */ - wrtscc(lp->cardbase, cmd, R15, 0); - wrtscc(lp->cardbase, cmd, R3, Rx8); /* Rx off */ - lp->rstate = IDLE; - if (cmd & 2) { /* if channel a */ - /* Set up for TX dma */ - wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); - } else { - wrtscc(lp->cardbase, cmd, R1, 0); /* No interrupts */ - } - - if (!lp->clockmode) { - if (lp->speed) { /* if internally clocked */ - br = lp->speed; /* get desired speed */ - tc = (lp->xtal / br) - 2; /* calc 1X BRG divisor */ - wrtscc(lp->cardbase, cmd, R12, tc & 0xFF); /* lower byte */ - wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xFF); /* upper byte */ - } - } - wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR); - /* Transmitter now on */ - } else { /* Tx OFF and Rx ON */ - lp->tstate = IDLE; - wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); /* TX off */ - - if (!lp->clockmode) { - if (lp->speed) { /* if internally clocked */ - /* Reprogram BRG for 32x clock for receive DPLL */ - /* BRG off, keep Pclk source */ - wrtscc(lp->cardbase, cmd, R14, BRSRC); - br = lp->speed; /* get desired speed */ - /* calc 32X BRG divisor */ - tc = ((lp->xtal / 32) / br) - 2; - wrtscc(lp->cardbase, cmd, R12, tc & 0xFF); /* lower byte */ - wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xFF); /* upper byte */ - /* SEARCH mode, BRG source */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); - /* Enable the BRG */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); - } - } - /* Flush rx fifo */ - wrtscc(lp->cardbase, cmd, R3, Rx8); /* Make sure rx is off */ - wrtscc(lp->cardbase, cmd, R0, ERR_RES); /* reset err latch */ - dummy = rdscc(lp->cardbase, cmd, R1); /* get status byte from R1 */ - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - - (void) rdscc(lp->cardbase, cmd, R8); - - /* Now, turn on the receiver and hunt for a flag */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | Rx8); - lp->rstate = ACTIVE; /* Normal state */ - - if (cmd & 2) { /* if channel a */ - setup_rx_dma(lp); - } else { - /* reset buffer pointers */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB)); - } - wrtscc(lp->cardbase, cmd, R15, BRKIE); /* allow ABORT int */ - } -} - -static void scc_init(struct device *dev) -{ - unsigned long flags; - struct pi_local *lp = (struct pi_local *) dev->priv; - - int tc; - long br; - register int cmd; - - /* Initialize 8530 channel for SDLC operation */ - - cmd = CTL + lp->base; - save_flags(flags); - cli(); - - switch (cmd & CHANA) { - case CHANA: - wrtscc(lp->cardbase, cmd, R9, CHRA); /* Reset channel A */ - wrtscc(lp->cardbase, cmd, R2, 0xff); /* Initialize interrupt vector */ - break; - default: - wrtscc(lp->cardbase, cmd, R9, CHRB); /* Reset channel B */ - break; - } - - /* Deselect all Rx and Tx interrupts */ - wrtscc(lp->cardbase, cmd, R1, 0); - - /* Turn off external interrupts (like CTS/CD) */ - wrtscc(lp->cardbase, cmd, R15, 0); - - /* X1 clock, SDLC mode */ - wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK); - - /* Tx/Rx parameters */ - if (lp->speed) { /* Use internal clocking */ - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); - if (!lp->clockmode) - /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */ - wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI); - else - /* Tx Clk from DPLL, Rcv Clk from DPLL, TRxC Outputs BRG */ - wrtscc(lp->cardbase, cmd, R11, TCDPLL | RCDPLL | TRxCBR | TRxCOI); - } else { /* Use external clocking */ - wrtscc(lp->cardbase, cmd, R10, CRCPS); - /* Tx Clk from Trxcl. Rcv Clk from Rtxcl, TRxC pin is input */ - wrtscc(lp->cardbase, cmd, R11, TCTRxCP); - } - - /* Null out SDLC start address */ - wrtscc(lp->cardbase, cmd, R6, 0); - - /* SDLC flag */ - wrtscc(lp->cardbase, cmd, R7, FLAG); - - /* Set up the Transmitter but don't enable it - * DTR, 8 bit TX chars only - */ - wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); - - /* Receiver initial setup */ - wrtscc(lp->cardbase, cmd, R3, Rx8); /* 8 bits/char */ - - /* Setting up BRG now - turn it off first */ - wrtscc(lp->cardbase, cmd, R14, BRSRC); /* BRG off, keep Pclk source */ - - /* set the 32x time constant for the BRG in Receive mode */ - - if (lp->speed) { - br = lp->speed; /* get desired speed */ - tc = ((lp->xtal / 32) / br) - 2; /* calc 32X BRG divisor */ - } else { - tc = 14; - } - - wrtscc(lp->cardbase, cmd, R12, tc & 0xFF); /* lower byte */ - wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xFF); /* upper byte */ - - /* Following subroutine sets up and ENABLES the receiver */ - rts(lp, OFF); /* TX OFF and RX ON */ - - if (lp->speed) { - /* DPLL frm BRG, BRG src PCLK */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR); - } else { - /* DPLL frm rtxc,BRG src PCLK */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | SSRTxC); - } - wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); /* SEARCH mode, keep BRG src */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); /* Enable the BRG */ - - if (!(cmd & 2)) /* if channel b */ - wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB)); - - wrtscc(lp->cardbase, cmd, R15, BRKIE); /* ABORT int */ - - /* Now, turn on the receiver and hunt for a flag */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | Rx8); - - restore_flags(flags); -} - -static void chipset_init(struct device *dev) -{ - int cardbase; - unsigned long flags; - - cardbase = dev->base_addr & 0x3f0; - - save_flags(flags); - cli(); - wrtscc(cardbase, dev->base_addr + CTL, R9, FHWRES); /* Hardware reset */ - /* Disable interrupts with master interrupt ctrl reg */ - wrtscc(cardbase, dev->base_addr + CTL, R9, 0); - restore_flags(flags); - -} - - -__initfunc(int pi_init(void)) -{ - int *port; - int ioaddr = 0; - int card_type = 0; - int ports[] = {0x380, 0x300, 0x320, 0x340, 0x360, 0x3a0, 0}; - - printk(KERN_INFO "PI: V0.8 ALPHA April 23 1995 David Perry (dp@hydra.carleton.ca)\n"); - - /* Only one card supported for now */ - for (port = &ports[0]; *port && !card_type; port++) { - ioaddr = *port; - - if (check_region(ioaddr, PI_TOTAL_SIZE) == 0) { - printk(KERN_INFO "PI: Probing for card at address %#3x\n",ioaddr); - card_type = hw_probe(ioaddr); - } - } - - switch (card_type) { - case 1: - printk(KERN_INFO "PI: Found a PI card at address %#3x\n", ioaddr); - break; - case 2: - printk(KERN_INFO "PI: Found a PI2 card at address %#3x\n", ioaddr); - break; - default: - printk(KERN_ERR "PI: ERROR: No card found\n"); - return -EIO; - } - - /* Link a couple of device structures into the chain */ - /* For the A port */ - /* Allocate space for 4 buffers even though we only need 3, - because one of them may cross a DMA page boundary and - be rejected by get_dma_buffer(). - */ - register_netdev(&pi0a); - - pi0a.priv = kmalloc(sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); - - pi0a.dma = PI_DMA; - pi0a.base_addr = ioaddr + 2; - pi0a.irq = 0; - - /* And the B port */ - register_netdev(&pi0b); - pi0b.base_addr = ioaddr; - pi0b.irq = 0; - - pi0b.priv = kmalloc(sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); - - /* Now initialize them */ - pi_probe(&pi0a, card_type); - pi_probe(&pi0b, card_type); - - pi0b.irq = pi0a.irq; /* IRQ is shared */ - - return 0; -} - -static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize) -{ - if (((addr & 0xffff) + dev_buffsize) <= 0x10000) - return 1; - else - return 0; -} - -static int pi_set_mac_address(struct device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *)addr; - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); /* addr is an AX.25 shifted ASCII */ - return 0; /* mac address */ -} - -/* Allocate a buffer which does not cross a DMA page boundary */ -static char * -get_dma_buffer(unsigned long *mem_ptr) -{ - char *ret; - - ret = (char *)*mem_ptr; - - if(!valid_dma_page(*mem_ptr, DMA_BUFF_SIZE + sizeof(struct mbuf))){ - *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); - ret = (char *)*mem_ptr; - } - *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); - return (ret); -} - -static int pi_probe(struct device *dev, int card_type) -{ - short ioaddr; - struct pi_local *lp; - unsigned long flags; - unsigned long mem_ptr; - - ioaddr = dev->base_addr; - - /* Initialize the device structure. */ - /* Must be done before chipset_init */ - /* Make certain the data structures used by the PI2 are aligned. */ - dev->priv = (void *) (((int) dev->priv + 7) & ~7); - lp = (struct pi_local *) dev->priv; - - memset(dev->priv, 0, sizeof(struct pi_local)); - - /* Allocate some buffers which do not cross DMA page boundaries */ - mem_ptr = (unsigned long) dev->priv + sizeof(struct pi_local); - lp->txdmabuf = get_dma_buffer(&mem_ptr); - lp->rxdmabuf1 = (struct mbuf *) get_dma_buffer(&mem_ptr); - lp->rxdmabuf2 = (struct mbuf *) get_dma_buffer(&mem_ptr); - - /* Initialize rx buffer */ - lp->rcvbuf = lp->rxdmabuf1; - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - - /* Initialize the transmit queue head structure */ - skb_queue_head_init(&lp->sndq); - - /* These need to be initialized before scc_init is called. */ - if (card_type == 1) - lp->xtal = (unsigned long) SINGLE / 2; - else - lp->xtal = (unsigned long) DOUBLE / 2; - lp->base = dev->base_addr; - lp->cardbase = dev->base_addr & 0x3f0; - if (dev->base_addr & CHANA) { - lp->speed = DEF_A_SPEED; - /* default channel access Params */ - lp->txdelay = DEF_A_TXDELAY; - lp->persist = DEF_A_PERSIST; - lp->slotime = DEF_A_SLOTIME; - lp->squeldelay = DEF_A_SQUELDELAY; - lp->clockmode = DEF_A_CLOCKMODE; - - } else { - lp->speed = DEF_B_SPEED; - /* default channel access Params */ - lp->txdelay = DEF_B_TXDELAY; - lp->persist = DEF_B_PERSIST; - lp->slotime = DEF_B_SLOTIME; - lp->squeldelay = DEF_B_SQUELDELAY; - lp->clockmode = DEF_B_CLOCKMODE; - } - lp->bufsiz = DMA_BUFF_SIZE; - lp->tstate = IDLE; - - chipset_init(dev); - - if (dev->base_addr & CHANA) { /* Do these things only for the A port */ - /* Note that a single IRQ services 2 devices (A and B channels) */ - - lp->dmachan = dev->dma; - if (lp->dmachan < 1 || lp->dmachan > 3) - printk(KERN_ERR "PI: DMA channel %d out of range\n", lp->dmachan); - - /* chipset_init() was already called */ - - if (dev->irq < 2) { - autoirq_setup(0); - save_flags(flags); - cli(); - wrtscc(lp->cardbase, CTL + lp->base, R1, EXT_INT_ENAB); - /* enable PI card interrupts */ - wrtscc(lp->cardbase, CTL + lp->base, R9, MIE | NV); - restore_flags(flags); - /* request a timer interrupt for 1 mS hence */ - tdelay(lp, 1); - /* 20 "jiffies" should be plenty of time... */ - dev->irq = autoirq_report(20); - if (!dev->irq) { - printk(KERN_ERR "PI: Failed to detect IRQ line.\n"); - } - save_flags(flags); - cli(); - wrtscc(lp->cardbase, dev->base_addr + CTL, R9, FHWRES); /* Hardware reset */ - /* Disable interrupts with master interrupt ctrl reg */ - wrtscc(lp->cardbase, dev->base_addr + CTL, R9, 0); - restore_flags(flags); - } - - printk(KERN_INFO "PI: Autodetected IRQ %d, assuming DMA %d.\n", - dev->irq, dev->dma); - - /* This board has jumpered interrupts. Snarf the interrupt vector - now. There is no point in waiting since no other device can use - the interrupt, and this marks the 'irqaction' as busy. */ - { - int irqval = request_irq(dev->irq, &pi_interrupt,0, "pi2", dev); - if (irqval) { - printk(KERN_ERR "PI: unable to get IRQ %d (irqval=%d).\n", - dev->irq, irqval); - return EAGAIN; - } - } - - /* Grab the region */ - request_region(ioaddr & 0x3f0, PI_TOTAL_SIZE, "pi2" ); - - - } /* Only for A port */ - dev->open = pi_open; - dev->stop = pi_close; - dev->do_ioctl = pi_ioctl; - dev->hard_start_xmit = pi_send_packet; - dev->get_stats = pi_get_stats; - - /* Fill in the fields of the device structure */ - - dev_init_buffers(dev); - -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; -#endif - - dev->set_mac_address = pi_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); - - /* New-style flags. */ - dev->flags = 0; - return 0; -} - -/* Open/initialize the board. This is called (in the current kernel) - sometime after booting when the 'ifconfig' program is run. - - This routine should set everything up anew at each open, even - registers that "should" only need to be set once at boot, so that - there is non-reboot way to recover if something goes wrong. - */ -static int pi_open(struct device *dev) -{ - unsigned long flags; - static first_time = 1; - - struct pi_local *lp = (struct pi_local *) dev->priv; - - if (dev->base_addr & 2) { /* if A channel */ - if (first_time) { - if (request_dma(dev->dma,"pi2")) { - free_irq(dev->irq, dev); - return -EAGAIN; - } - } - /* Reset the hardware here. */ - chipset_init(dev); - } - lp->tstate = IDLE; - - if (dev->base_addr & 2) { /* if A channel */ - scc_init(dev); /* Called once for each channel */ - scc_init(dev->next); - } - /* master interrupt enable */ - save_flags(flags); - cli(); - wrtscc(lp->cardbase, CTL + lp->base, R9, MIE | NV); - restore_flags(flags); - - lp->open_time = jiffies; - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - first_time = 0; - - MOD_INC_USE_COUNT; - - return 0; -} - -static int pi_send_packet(struct sk_buff *skb, struct device *dev) -{ - struct pi_local *lp = (struct pi_local *) dev->priv; - - hardware_send_packet(lp, skb); - dev->trans_start = jiffies; - - return 0; -} - -/* The typical workload of the driver: - Handle the network interface interrupts. */ -static void pi_interrupt(int reg_ptr, void *dev_id, struct pt_regs *regs) -{ -/* int irq = -(((struct pt_regs *) reg_ptr)->orig_eax + 2);*/ - struct pi_local *lp; - int st; - unsigned long flags; - -/* dev_b = dev_a->next; Relies on the order defined in Space.c */ - -#if 0 - if (dev_a == NULL) { - printk(KERN_ERR "PI: pi_interrupt(): irq %d for unknown device.\n", irq); - return; - } -#endif - /* Read interrupt status register (only valid from channel A) - * Process all pending interrupts in while loop - */ - lp = (struct pi_local *) pi0a.priv; /* Assume channel A */ - while ((st = rdscc(lp->cardbase, pi0a.base_addr | CHANA | CTL, R3)) != 0) { - if (st & CHBTxIP) { - /* Channel B Transmit Int Pending */ - lp = (struct pi_local *) pi0b.priv; - b_txint(lp); - } else if (st & CHARxIP) { - /* Channel A Rcv Interrupt Pending */ - lp = (struct pi_local *) pi0a.priv; - a_rxint(&pi0a, lp); - } else if (st & CHATxIP) { - /* Channel A Transmit Int Pending */ - lp = (struct pi_local *) pi0a.priv; - a_txint(lp); - } else if (st & CHAEXT) { - /* Channel A External Status Int */ - lp = (struct pi_local *) pi0a.priv; - a_exint(lp); - } else if (st & CHBRxIP) { - /* Channel B Rcv Interrupt Pending */ - lp = (struct pi_local *) pi0b.priv; - b_rxint(&pi0b, lp); - } else if (st & CHBEXT) { - /* Channel B External Status Int */ - lp = (struct pi_local *) pi0b.priv; - b_exint(lp); - } - /* Reset highest interrupt under service */ - save_flags(flags); - cli(); - wrtscc(lp->cardbase, lp->base + CTL, R0, RES_H_IUS); - restore_flags(flags); - } /* End of while loop on int processing */ - return; -} - -/* The inverse routine to pi_open(). */ -static int pi_close(struct device *dev) -{ - unsigned long flags; - struct pi_local *lp; - struct sk_buff *ptr; - - save_flags(flags); - cli(); - - lp = (struct pi_local *) dev->priv; - ptr = NULL; - - chipset_init(dev); /* reset the scc */ - disable_dma(lp->dmachan); - - lp->open_time = 0; - - dev->tbusy = 1; - dev->start = 0; - - /* Free any buffers left in the hardware transmit queue */ - while ((ptr = skb_dequeue(&lp->sndq)) != NULL) - kfree_skb(ptr, FREE_WRITE); - - restore_flags(flags); - - MOD_DEC_USE_COUNT; - - return 0; -} - -static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd) -{ - unsigned long flags; - struct pi_req rq; - struct pi_local *lp = (struct pi_local *) dev->priv; - - int ret = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct pi_req)); - if (ret) - return ret; - - if(cmd!=SIOCDEVPRIVATE) - return -EINVAL; - - copy_from_user(&rq, ifr->ifr_data, sizeof(struct pi_req)); - - switch (rq.cmd) { - case SIOCSPIPARAM: - - if (!suser()) - return -EPERM; - save_flags(flags); - cli(); - lp->txdelay = rq.txdelay; - lp->persist = rq.persist; - lp->slotime = rq.slotime; - lp->squeldelay = rq.squeldelay; - lp->clockmode = rq.clockmode; - lp->speed = rq.speed; - pi_open(&pi0a); /* both channels get reset %%% */ - restore_flags(flags); - ret = 0; - break; - - case SIOCSPIDMA: - - if (!suser()) - return -EPERM; - ret = 0; - if (dev->base_addr & 2) { /* if A channel */ - if (rq.dmachan < 1 || rq.dmachan > 3) - return -EINVAL; - save_flags(flags); - cli(); - pi_close(dev); - free_dma(lp->dmachan); - dev->dma = lp->dmachan = rq.dmachan; - if (request_dma(lp->dmachan,"pi2")) - ret = -EAGAIN; - pi_open(dev); - restore_flags(flags); - } - break; - - case SIOCSPIIRQ: - ret = -EINVAL; /* add this later */ - break; - - case SIOCGPIPARAM: - case SIOCGPIDMA: - case SIOCGPIIRQ: - - rq.speed = lp->speed; - rq.txdelay = lp->txdelay; - rq.persist = lp->persist; - rq.slotime = lp->slotime; - rq.squeldelay = lp->squeldelay; - rq.clockmode = lp->clockmode; - rq.dmachan = lp->dmachan; - rq.irq = dev->irq; - copy_to_user(ifr->ifr_data, &rq, sizeof(struct pi_req)); - ret = 0; - break; - - default: - ret = -EINVAL; - } - return ret; -} - -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *pi_get_stats(struct device *dev) -{ - struct pi_local *lp = (struct pi_local *) dev->priv; - - return &lp->stats; -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -MODULE_AUTHOR("David Perry "); -MODULE_DESCRIPTION("AX.25 driver for the Ottawa PI and PI/2 HDLC cards"); - -int init_module(void) -{ - return pi_init(); -} - -void cleanup_module(void) -{ - free_irq(pi0a.irq, &pi0a); /* IRQs and IO Ports are shared */ - release_region(pi0a.base_addr & 0x3f0, PI_TOTAL_SIZE); - - kfree(pi0a.priv); - pi0a.priv = NULL; - unregister_netdev(&pi0a); - - kfree(pi0b.priv); - pi0b.priv = NULL; - unregister_netdev(&pi0b); -} -#endif diff -u --recursive --new-file v2.1.70/linux/drivers/net/pt.c linux/drivers/net/pt.c --- v2.1.70/linux/drivers/net/pt.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/pt.c Wed Dec 31 16:00:00 1969 @@ -1,1778 +0,0 @@ -#undef PT_DEBUG 1 -/* - * pt.c: Linux device driver for the Gracilis PackeTwin. - * Copyright (c) 1995 Craig Small VK2XLZ (vk2xlz@vk2xlz.ampr.org.) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge MA 02139, USA. - * - * This driver is largely based upon the PI driver by David Perry. - * - * Revision History - * 23/02/95 cs Started again on driver, last one scrapped - * 27/02/95 cs Program works, we have chan A only. Tx stays on - * 28/02/95 cs Fix Tx problem (& TxUIE instead of | ) - * Fix Chan B Tx timer problem, used TMR2 instead of TMR1 - * 03/03/95 cs Painfully found out (after 3 days) SERIAL_CFG is write only - * created image of it and DMA_CFG - * 21/06/95 cs Upgraded to suit PI driver 0.8 ALPHA - * 22/08/95 cs Changed it all around to make it like pi driver - * 23/08/95 cs It now works, got caught again by TMR2 and we must have - * auto-enables for daughter boards. - * 07/10/95 cs Fixed for 1.3.30 (hopefully) - * 26/11/95 cs Fixed for 1.3.43, ala 29/10 for pi2.c by ac - * 21/12/95 cs Got rid of those nasty warnings when compiling, for 1.3.48 - * 08/08/96 jsn Convert to use as a module. Removed send_kiss, empty_scc and - * pt_loopback functions - they were unused. - * 13/12/96 jsn Fixed to match Linux networking changes. - */ - -/* - * default configuration of the PackeTwin, - * ie What Craig uses his PT for. - */ -#define PT_DMA 3 - -#define DEF_A_SPEED 4800 /* 4800 baud */ -#define DEF_A_TXDELAY 350 /* 350 mS */ -#define DEF_A_PERSIST 64 /* 25% persistence */ -#define DEF_A_SLOTIME 10 /* 10 mS */ -#define DEF_A_SQUELDELAY 30 /* 30 mS */ -#define DEF_A_CLOCKMODE 0 /* Normal clock mode */ -#define DEF_A_NRZI 1 /* NRZI mode */ - -#define DEF_B_SPEED 0 /* 0 means external clock */ -#define DEF_B_TXDELAY 250 /* 250 mS */ -#define DEF_B_PERSIST 64 /* 25% */ -#define DEF_B_SLOTIME 10 /* 10 mS */ -#define DEF_B_SQUELDELAY 30 /* 30 mS */ -#define DEF_B_CLOCKMODE 0 /* Normal clock mode ?!? */ -#define DEF_B_NRZI 1 /* NRZI mode */ - - -#define PARAM_TXDELAY 1 -#define PARAM_PERSIST 2 -#define PARAM_SLOTTIME 3 -#define PARAM_FULLDUP 5 -#define PARAM_HARDWARE 6 -#define PARAM_RETURN 255 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "z8530.h" -#include - -struct mbuf { - struct mbuf *next; - int cnt; - char data[0]; -}; - -/* - * The actual PT devices we will use - */ -static int pt0_preprobe(struct device *dev) {return 0;} /* Dummy probe function */ -static struct device pt0a = { "pt0a", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pt0_preprobe }; -static struct device pt0b = { "pt0b", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pt0_preprobe }; - -/* Ok, they shouldn't be here, but both channels share them */ -/* The Images of the Serial and DMA config registers */ -static unsigned char pt_sercfg = 0; -static unsigned char pt_dmacfg = 0; - -/* The number of IO ports used by the card */ -#define PT_TOTAL_SIZE 16 - -/* Index to functions, as function prototypes. */ - -static int pt_probe(struct device *dev); -static int pt_open(struct device *dev); -static int pt_send_packet(struct sk_buff *skb, struct device *dev); -static void pt_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int pt_close(struct device *dev); -static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd); -static struct net_device_stats *pt_get_stats(struct device *dev); -static void pt_rts(struct pt_local *lp, int x); -static void pt_rxisr(struct device *dev); -static void pt_txisr(struct pt_local *lp); -static void pt_exisr(struct pt_local *lp); -static void pt_tmrisr(struct pt_local *lp); -static char *get_dma_buffer(unsigned long *mem_ptr); -static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize); -static int hw_probe(int ioaddr); -static void tdelay(struct pt_local *lp, int time); -static void chipset_init(struct device *dev); - -static char ax25_bcast[7] = -{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static char ax25_test[7] = -{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - - - -static int ext2_secrm_seed = 152; - -static inline unsigned char random(void) -{ - return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed * 60691 + 1); -} - -static inline void wrtscc(int cbase, int ctl, int sccreg, unsigned char val) -{ - outb_p(sccreg, ctl); /* Select register */ - outb_p(val, ctl); /* Output value */ -} - -static inline unsigned char rdscc(int cbase, int ctl, int sccreg) -{ - unsigned char retval; - - outb_p(sccreg, ctl); /* Select register */ - retval = inb_p(ctl); - return retval; -} - -static void switchbuffers(struct pt_local *lp) -{ - if (lp->rcvbuf == lp->rxdmabuf1) - lp->rcvbuf = lp->rxdmabuf2; - else - lp->rcvbuf = lp->rxdmabuf1; -} - -static void hardware_send_packet(struct pt_local *lp, struct sk_buff *skb) -{ - char kickflag; - unsigned long flags; - char *ptr; - struct device *dev; - - /* First, let's see if this packet is actually a KISS packet */ - ptr = skb->data; - if (ptr[0] != 0 && skb->len >= 2) - { -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: Rx KISS... Control = %d, value = %d.\n", ptr[0], (skb->len > 1? ptr[1] : -1)); -#endif - /* Kludge to get device */ - if ((struct pt_local*)(&pt0b.priv) == lp) - dev = &pt0b; - else - dev = &pt0a; - switch(ptr[0]) - { - - case PARAM_TXDELAY: - /*TxDelay is in 10mS increments */ - lp->txdelay = ptr[1] * 10; - break; - case PARAM_PERSIST: - lp->persist = ptr[1]; - break; - case PARAM_SLOTTIME: - lp->slotime = ptr[1]; - break; - case PARAM_FULLDUP: - /* Yeah right, you wish! Fullduplex is a little while to - * go folks, but this is how you fire it up - */ - break; - /* Perhaps we should have txtail here?? */ - } /*switch */ - return; - } - - lp->stats.tx_packets++; - lp->stats.tx_bytes+=skb->len; - save_flags(flags); - cli(); - kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL); - restore_flags(flags); - -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: hardware_send_packet(): kickflag = %d (%d).\n", kickflag, lp->base & CHANA); -#endif - skb_queue_tail(&lp->sndq, skb); - if (kickflag) - { - /* Simulate interrupt to transmit */ - if (lp->dmachan) - pt_txisr(lp); - else - { - save_flags(flags); - cli(); - if (lp->tstate == IDLE) - pt_txisr(lp); - restore_flags(flags); - } - } -} /* hardware_send_packet() */ - -static void setup_rx_dma(struct pt_local *lp) -{ - unsigned long flags; - int cmd; - unsigned long dma_abs; - unsigned char dmachan; - - save_flags(flags); - cli(); - - dma_abs = (unsigned long) (lp->rcvbuf->data); - dmachan = lp->dmachan; - cmd = lp->base + CTL; - - if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf))) - panic("PI: RX buffer violates DMA boundary!"); - - /* Get ready for RX DMA */ - wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); - - disable_dma(dmachan); - clear_dma_ff(dmachan); - - /* - * Set DMA mode register to single transfers, incrementing address, - * auto init, writes - */ - - set_dma_mode(dmachan, DMA_MODE_READ | 0x10); - set_dma_addr(dmachan, dma_abs); - set_dma_count(dmachan, lp->bufsiz); - enable_dma(dmachan); - - /* - * If a packet is already coming in, this line is supposed to - * avoid receiving a partial packet. - */ - - wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC); - - /* Enable RX dma */ - wrtscc(lp->cardbase, cmd, R1, - WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB); - - restore_flags(flags); -} - -static void setup_tx_dma(struct pt_local *lp, int length) -{ - unsigned long dma_abs; - unsigned long flags; - unsigned long dmachan; - - save_flags(flags); - cli(); - - dmachan = lp->dmachan; - dma_abs = (unsigned long) (lp->txdmabuf); - - if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf))) - panic("PT: TX buffer violates DMA boundary!"); - - disable_dma(dmachan); - /* Set DMA mode register to single transfers, incrementing address, - * no auto init, reads - */ - set_dma_mode(dmachan, DMA_MODE_WRITE); - clear_dma_ff(dmachan); - set_dma_addr(dmachan, dma_abs); - /* output byte count */ - set_dma_count(dmachan, length); - - restore_flags(flags); -} - -/* - * This sets up all the registers in the SCC for the given channel - * based upon tsync_hwint() - */ -static void scc_init(struct device *dev) -{ - unsigned long flags; - struct pt_local *lp = (struct pt_local*) dev->priv; - register int cmd = lp->base + CTL; - int tc, br; - -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: scc_init(): (%d).\n", lp->base & CHANA); -#endif - save_flags(flags); - cli(); - - /* We may put something here to enable_escc */ - - if (cmd & CHANA) - { - wrtscc(lp->cardbase, cmd, R9, CHRA); /* Reset channel A */ - wrtscc(lp->cardbase, cmd, R2, 0xff); /* Initialise interrupt vector */ - } - else - wrtscc(lp->cardbase, cmd, R9, CHRB); /* Reset channel B */ - - /* Deselect all Rx and Tx interrupts */ - wrtscc(lp->cardbase, cmd, R1, 0); - - /* Turn off external interrupts (like CTS/CD) */ - wrtscc(lp->cardbase, cmd, R15, 0); - - /* X1 clock, SDLC mode */ - wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK); - - /* Preset CRC and set mode */ - if (lp->nrzi) - /* Preset Tx CRC, put into NRZI mode */ - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); - else - /* Preset Tx CRC, put into NRZ mode */ - wrtscc(lp->cardbase, cmd, R10, CRCPS); - - /* Tx/Rx parameters */ - if (lp->speed) /* Use internal clocking */ - /* Tx Clk from BRG. Rx Clk form DPLL, TRxC pin outputs DPLL */ - wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI); - else /* Use external clocking */ - { - /* Tx Clk from TRxCL. Rx Clk from RTxCL, TRxC pin if input */ - wrtscc(lp->cardbase, cmd, R11, TCTRxCP | RCRTxCP | TRxCBR); - wrtscc(lp->cardbase,cmd, R14, 0); /* wiz1 */ - } - - /* Null out SDLC start address */ - wrtscc(lp->cardbase, cmd, R6, 0); - - /* SDLC flag */ - wrtscc(lp->cardbase, cmd, R7, FLAG); - - /* Setup Tx but don't enable it */ - wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); - - /* Setup Rx */ - wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); - - /* Setup the BRG, turn it off first */ - wrtscc(lp->cardbase, cmd, R14, BRSRC); - - /* set the 32x time constant for the BRG in Rx mode */ - if (lp->speed) - { - br = lp->speed; - tc = ((lp->xtal / 32) / (br * 2)) - 2; - wrtscc(lp->cardbase, cmd, R12, tc & 0xff); /* lower byte */ - wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); /* upper byte */ - } - - /* Turn transmitter off, to setup stuff */ - pt_rts(lp, OFF); - - /* External clocking */ - if (lp->speed) - { - /* DPLL frm BRG, BRG src PCLK */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR); - wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); /* SEARCH mode, keep BRG src */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); /* Enable the BRG */ - - /* Turn off external clock port */ - if (lp->base & CHANA) - outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) ); - else - outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) ); - } - else - { - /* DPLL frm rtxc,BRG src PCLK */ - /* Turn on external clock port */ - if (lp->base & CHANA) - outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) ); - else - outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) ); - } - - if (!lp->dmachan) - wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB)); - - wrtscc(lp->cardbase, cmd, R15, BRKIE); /* ABORT int */ - - /* Turn on the DTR to tell modem we're alive */ - if (lp->base & CHANA) - outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) ); - else - outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) ); - - /* Now, turn on the receiver and hunt for a flag */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 ); - - restore_flags(flags); - -} /* scc_init() */ - -/* Resets the given channel and whole SCC if both channels off */ -static void chipset_init(struct device *dev) -{ - - struct pt_local *lp = (struct pt_local*) dev->priv; -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: chipset_init(): pt0a tstate = %d.\n", ((struct pt_local*)pt0a.priv)->tstate); - printk(KERN_DEBUG "PT: chipset_init(): pt0b tstate = %d.\n", ((struct pt_local*)pt0b.priv)->tstate); -#endif - /* Reset SCC if both channels are to be canned */ - if ( ((lp->base & CHANA) && !(pt_sercfg & PT_DTRB_ON)) || - (!(lp->base & CHANA) && !(pt_sercfg & PT_DTRA_ON)) ) - { - wrtscc(lp->cardbase, lp->base + CTL, R9, FHWRES); - /* Reset int and dma registers */ - outb_p((pt_sercfg = 0), lp->cardbase + SERIAL_CFG); - outb_p((pt_dmacfg = 0), lp->cardbase + DMA_CFG); -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: chipset_init() Resetting SCC, called by ch (%d).\n", lp->base & CHANA); -#endif - } - /* Reset individual channel */ - if (lp->base & CHANA) { - wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | DLC | NV | CHRA); - outb_p( (pt_sercfg &= ~PT_DTRA_ON), lp->cardbase + SERIAL_CFG); - } else { - wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | DLC | NV | CHRB); - outb_p( (pt_sercfg &= ~PT_DTRB_ON), lp->cardbase + SERIAL_CFG); - } -} /* chipset_init() */ - - - -__initfunc(int pt_init(void)) -{ - int *port; - int ioaddr = 0; - int card_type = 0; - int ports[] = - { 0x230, 0x240, 0x250, 0x260, 0x270, 0x280, 0x290, 0x2a0, - 0x2b0, 0x300, 0x330, 0x3f0, 0}; - - printk(KERN_INFO "PT: 0.41 ALPHA 07 October 1995 Craig Small (csmall@small.dropbear.id.au)\n"); - - for (port = &ports[0]; *port && !card_type; port++) { - ioaddr = *port; - - if (check_region(ioaddr, PT_TOTAL_SIZE) == 0) { - printk(KERN_INFO "PT: Probing for card at address %#3x\n", ioaddr); - card_type = hw_probe(ioaddr); - } - } - if (card_type) { - printk(KERN_INFO "PT: Found a PT at address %#3x\n",ioaddr); - } else { - printk(KERN_ERR "PT: ERROR: No card found.\n"); - return -EIO; - } - - /* - * Link a couple of device structures into the chain - * - * For the A port - * Allocate space for 4 buffers even though we only need 3, - * because one of them may cross a DMA page boundary and - * be rejected by get_dma_buffer(). - */ - register_netdev(&pt0a); - - pt0a.priv= kmalloc(sizeof(struct pt_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); - - pt0a.dma = 0; /* wizzer - no dma yet */ - pt0a.base_addr = ioaddr + CHANA; - pt0a.irq = 0; - - /* And B port */ - register_netdev(&pt0b); - - pt0b.priv= kmalloc(sizeof(struct pt_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); - - pt0b.base_addr = ioaddr + CHANB; - pt0b.irq = 0; - - /* Now initialise them */ - pt_probe(&pt0a); - pt_probe(&pt0b); - - pt0b.irq = pt0a.irq; /* IRQ is shared */ - - return 0; -} /* pt_init() */ - -/* - * Probe for PT card. Also initialises the timers - */ -__initfunc(static int hw_probe(int ioaddr)) -{ - int time = 1000; /* Number of milliseconds to test */ - int a = 1; - int b = 1; - unsigned long start_time, end_time; - - inb_p(ioaddr + TMR1CLR); - inb_p(ioaddr + TMR2CLR); - - /* Timer counter channel 0, 1mS period */ - outb_p(SC0 | LSB_MSB | MODE3, ioaddr + TMRCMD); - outb_p(0x00, ioaddr + TMR0); - outb_p(0x18, ioaddr + TMR0); - - /* Setup timer control word for timer 1 */ - outb_p(SC1 | LSB_MSB | MODE0, ioaddr + TMRCMD); - outb_p((time << 1) & 0xff, ioaddr + TMR1); - outb_p((time >> 7) & 0xff, ioaddr + TMR1); - - /* wait until counter reg is loaded */ - do { - /* Latch count for reading */ - outb_p(SC1, ioaddr + TMRCMD); - a = inb_p(ioaddr + TMR1); - b = inb_p(ioaddr + TMR1); - } while (b == 0); - start_time = jiffies; - while(b != 0) - { - /* Latch count for reading */ - outb_p(SC1, ioaddr + TMRCMD); - a = inb_p(ioaddr + TMR1); - b = inb_p(ioaddr + TMR1); - end_time = jiffies; - /* Don't wait forever - there may be no card here */ - if ((end_time - start_time) > 200) - { - inb_p(ioaddr + TMR1CLR); - return 0; - } - } - - /* Now fix the timers up for general operation */ - - /* Clear the timers */ - inb_p(ioaddr + TMR1CLR); - inb_p(ioaddr + TMR2CLR); - - outb_p(SC1 | LSB_MSB | MODE0, ioaddr + TMRCMD); - inb_p(ioaddr + TMR1CLR); - - outb_p(SC2 | LSB_MSB | MODE0, ioaddr + TMRCMD); - /* Should this be tmr1 or tmr2? wiz3*/ - inb_p(ioaddr + TMR1CLR); - - return 1; -} /* hw_probe() */ - - -static void pt_rts(struct pt_local *lp, int x) -{ - int tc; - long br; - int cmd = lp->base + CTL; -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_rts(): Transmitter status will be %d (%d).\n", x, lp->base & CHANA); -#endif - if (x == ON) { - /* Ex ints off to avoid int */ - wrtscc(lp->cardbase, cmd, R15, 0); - wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); /* Rx off */ - lp->rstate = IDLE; - - if(lp->dmachan) - { - /* Setup for Tx DMA */ - wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); - } else { - /* No interrupts */ - wrtscc(lp->cardbase, cmd, R1, 0); - } - - if (!lp->clockmode) - { - if (lp->speed) - { - br = lp->speed; - tc = (lp->xtal / (br * 2)) - 2; - wrtscc(lp->cardbase, cmd, R12, tc & 0xff); - wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); - } - } - /* Turn on Tx by raising RTS */ - wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR); - /* Transmitter on now */ - } else { /* turning off Tx */ - lp->tstate = IDLE; - - /* Turn off Tx by dropping RTS */ - wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); - if (!lp->clockmode) - { - if (lp->speed) /* internally clocked */ - { - /* Reprogram BRG from 32x clock for Rx DPLL */ - /* BRG off, keep PClk source */ - wrtscc(lp->cardbase, cmd, R14, BRSRC); - br = lp->speed; - tc = ((lp->xtal / 32) / (br * 2)) - 2; - wrtscc(lp->cardbase, cmd, R12, tc & 0xff); - wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); - - /* SEARCH mode, BRG source */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); - /* Enable the BRG */ - wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); - } - } - /* Flush Rx fifo */ - /* Turn Rx off */ - wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); - - /* Reset error latch */ - wrtscc(lp->cardbase, cmd, R0, ERR_RES); - - /* get status byte from R1 */ - (void) rdscc(lp->cardbase, cmd, R1); - - /* Read and dump data in queue */ - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - - /* Now, turn on Rx and hunt for a flag */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | AUTO_ENAB | Rx8 ); - - lp->rstate = ACTIVE; - - if (lp->dmachan) - { - setup_rx_dma(lp); - } else { - /* Reset buffer pointers */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - /* Allow aborts to interrupt us */ - wrtscc(lp->cardbase, cmd, R1, INT_ALL_Rx | EXT_INT_ENAB); - - } - wrtscc(lp->cardbase, cmd, R15, BRKIE ); - } -} /* pt_rts() */ - - -static int valid_dma_page(unsigned long addr, unsigned long dev_bufsize) -{ - if (((addr & 0xffff) + dev_bufsize) <= 0x10000) - return 1; - else - return 0; -} - -static int pt_set_mac_address(struct device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *)addr; - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); /* addr is an AX.25 shifted ASCII */ - return 0; /* mac address */ -} - - -/* Allocate a buffer which does not cross a DMA page boundary */ -static char * get_dma_buffer(unsigned long *mem_ptr) -{ - char *ret; - - ret = (char *) *mem_ptr; - - if (!valid_dma_page(*mem_ptr, DMA_BUFF_SIZE + sizeof(struct mbuf))) { - *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); - ret = (char *) *mem_ptr; - } - *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); - return (ret); -} /* get_dma_buffer() */ - - -/* - * Sets up all the structures for the PT device - */ -static int pt_probe(struct device *dev) -{ - short ioaddr; - struct pt_local *lp; - unsigned long flags; - unsigned long mem_ptr; - - ioaddr = dev->base_addr; - - /* - * Initialise the device structure. - * Must be done before chipset_init() - * Make sure data structures used by the PT are aligned - */ - dev->priv = (void *) (((int) dev->priv + 7) & ~7); - lp = (struct pt_local*) dev->priv; - - memset(dev->priv, 0, sizeof(struct pt_local)); - - /* Allocate some buffers which do not cross DMA boundaries */ - mem_ptr = (unsigned long) dev->priv + sizeof(struct pt_local); - lp->txdmabuf = get_dma_buffer(&mem_ptr); - lp->rxdmabuf1 = (struct mbuf *) get_dma_buffer(&mem_ptr); - lp->rxdmabuf2 = (struct mbuf *) get_dma_buffer(&mem_ptr); - - /* Initialise the Rx buffer */ - lp->rcvbuf = lp->rxdmabuf1; - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - - /* Initialise the transmit queue head structure */ - skb_queue_head_init(&lp->sndq); - - lp->base = dev->base_addr; - lp->cardbase = dev->base_addr & 0x3f0; - - /* These need to be initialised before scc_init() is called. - */ - lp->xtal = XTAL; - - if (dev->base_addr & CHANA) { - lp->speed = DEF_A_SPEED; - lp->txdelay = DEF_A_TXDELAY; - lp->persist = DEF_A_PERSIST; - lp->slotime = DEF_A_SLOTIME; - lp->squeldelay = DEF_A_SQUELDELAY; - lp->clockmode = DEF_A_CLOCKMODE; - lp->nrzi = DEF_A_NRZI; - } else { - lp->speed = DEF_B_SPEED; - lp->txdelay = DEF_B_TXDELAY; - lp->persist = DEF_B_PERSIST; - lp->slotime = DEF_B_SLOTIME; - lp->squeldelay = DEF_B_SQUELDELAY; - lp->clockmode = DEF_B_CLOCKMODE; - lp->nrzi = DEF_B_NRZI; - } - lp->bufsiz = DMA_BUFF_SIZE; - lp->tstate = IDLE; - - chipset_init(dev); - - if (dev->base_addr & CHANA) { - /* Note that a single IRQ services 2 devices (A and B channels) - */ - - /* - * We disable the dma for a while, we have to get ints working - * properly first!! - */ - lp->dmachan = 0; - - if (dev->irq < 2) { - autoirq_setup(0); - - /* Turn on PT interrupts */ - save_flags(flags); - cli(); - outb_p( pt_sercfg |= PT_EI, lp->cardbase + INT_CFG); - restore_flags(flags); - - /* Set a timer interrupt */ - tdelay(lp, 1); - dev->irq = autoirq_report(20); - - /* Turn off PT interrupts */ - save_flags(flags); - cli(); - outb_p( (pt_sercfg &= ~ PT_EI), lp->cardbase + INT_CFG); - restore_flags(flags); - - if (!dev->irq) { - printk(KERN_ERR "PT: ERROR: Failed to detect IRQ line, assuming IRQ7.\n"); - } - } - - printk(KERN_INFO "PT: Autodetected IRQ %d, assuming DMA %d\n", dev->irq, dev->dma); - - /* This board has jumpered interrupts. Snarf the interrupt vector - * now. There is no point in waiting since no other device can use - * the interrupt, and this marks the 'irqaction' as busy. - */ - { - int irqval = request_irq(dev->irq, &pt_interrupt,0, "pt", dev); - if (irqval) { - printk(KERN_ERR "PT: ERROR: Unable to get IRQ %d (irqval = %d).\n", - dev->irq, irqval); - return EAGAIN; - } - } - - /* Grab the region */ - request_region(ioaddr & 0x3f0, PT_TOTAL_SIZE, "pt" ); - } /* A port */ - dev->open = pt_open; - dev->stop = pt_close; - dev->do_ioctl = pt_ioctl; - dev->hard_start_xmit = pt_send_packet; - dev->get_stats = pt_get_stats; - - /* Fill in the fields of the device structure */ - dev_init_buffers(dev); - -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; -#endif - - dev->set_mac_address = pt_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 default */ - dev->addr_len = 7; /* sizeof an ax.25 address */ - memcpy(dev->broadcast, ax25_bcast, 7); - memcpy(dev->dev_addr, ax25_test, 7); - - /* New style flags */ - dev->flags = 0; - - return 0; -} /* pt_probe() */ - - -/* Open/initialise the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that 'should' only be set once at boot, so that there is - * a non-reboot way to recover if something goes wrong. - * derived from last half of tsync_attach() - */ -static int pt_open(struct device *dev) -{ - unsigned long flags; - struct pt_local *lp = dev->priv; - static first_time = 1; - - if (dev->base_addr & CHANA) - { - if (first_time) - { - if (request_dma(dev->dma, "pt")) - { - free_irq(dev->irq, dev); - return -EAGAIN; - } - } - - /* Reset hardware */ - chipset_init(dev); - } - lp->tstate = IDLE; - - if (dev->base_addr & CHANA) - { - scc_init(dev); - scc_init(dev->next); - } - /* Save a copy of register RR0 for comparing with later on */ - /* We always put 0 in zero count */ - lp->saved_RR0 = rdscc(lp->cardbase, lp->base + CTL, R0) & ~ZCOUNT; - - /* master interrupt enable */ - save_flags(flags); - cli(); - wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | NV); - outb_p( pt_sercfg |= PT_EI, lp->cardbase + INT_CFG); - restore_flags(flags); - - lp->open_time = jiffies; - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - first_time = 0; - - MOD_INC_USE_COUNT; - - return 0; -} /* pt_open() */ - -static int pt_send_packet(struct sk_buff *skb, struct device *dev) -{ - struct pt_local *lp = (struct pt_local *) dev->priv; - -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_send_packet(): (%d)\n", lp->base & CHANA); -#endif - hardware_send_packet(lp, skb); - dev->trans_start = jiffies; - - return 0; -} - - - -/* The inverse routine to pt_open() */ -static int pt_close(struct device *dev) -{ - unsigned long flags; - struct pt_local *lp = dev->priv; - struct sk_buff *ptr = NULL; - int cmd; - - cmd = lp->base + CTL; - - save_flags(flags); - cli(); - - /* Reset SCC or channel */ - chipset_init(dev); - disable_dma(lp->dmachan); - - lp->open_time = 0; - dev->tbusy = 1; - dev->start = 0; - - /* Free any buffers left in the hardware transmit queue */ - while ((ptr = skb_dequeue(&lp->sndq)) != NULL) - kfree_skb(ptr, FREE_WRITE); - - restore_flags(flags); - -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_close(): Closing down channel (%d).\n", lp->base & CHANA); -#endif - - MOD_DEC_USE_COUNT; - - return 0; -} /* pt_close() */ - - -static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd) -{ - unsigned long flags; - struct pt_req rq; - struct pt_local *lp = (struct pt_local *) dev->priv; - - int ret = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct pt_req)); - if (ret) - return ret; - - if (cmd != SIOCDEVPRIVATE) - return -EINVAL; - - copy_from_user(&rq, ifr->ifr_data, sizeof(struct pt_req)); - - switch (rq.cmd) { - case SIOCSPIPARAM: - - if (!suser()) - return -EPERM; - save_flags(flags); - cli(); - lp->txdelay = rq.txdelay; - lp->persist = rq.persist; - lp->slotime = rq.slotime; - lp->squeldelay = rq.squeldelay; - lp->clockmode = rq.clockmode; - lp->speed = rq.speed; - pt_open(&pt0a); - restore_flags(flags); - ret = 0; - break; - - case SIOCSPIDMA: - - if (!suser()) - return -EPERM; - ret = 0; - if (dev->base_addr & CHANA) { /* if A channel */ - if (rq.dmachan < 1 || rq.dmachan > 3) - return -EINVAL; - save_flags(flags); - cli(); - pt_close(dev); - free_dma(lp->dmachan); - dev->dma = lp->dmachan = rq.dmachan; - if (request_dma(lp->dmachan,"pt")) - ret = -EAGAIN; - pt_open(dev); - restore_flags(flags); - } - break; - - case SIOCSPIIRQ: - ret = -EINVAL; /* add this later */ - break; - - case SIOCGPIPARAM: - case SIOCGPIDMA: - case SIOCGPIIRQ: - - rq.speed = lp->speed; - rq.txdelay = lp->txdelay; - rq.persist = lp->persist; - rq.slotime = lp->slotime; - rq.squeldelay = lp->squeldelay; - rq.clockmode = lp->clockmode; - rq.dmachan = lp->dmachan; - rq.irq = dev->irq; - copy_to_user(ifr->ifr_data, &rq, sizeof(struct pt_req)); - ret = 0; - break; - - default: - ret = -EINVAL; - } - return ret; -} - -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ - -static struct net_device_stats *pt_get_stats(struct device *dev) -{ - struct pt_local *lp = (struct pt_local *) dev->priv; - return &lp->stats; -} - - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ - - -static void tdelay(struct pt_local *lp, int time) -{ - /* For some reason, we turn off the Tx interrupts here! */ - if (!lp->dmachan) - wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB); - - if (lp->base & CHANA) - { - outb_p(time & 0xff, lp->cardbase + TMR1); - outb_p((time >> 8)&0xff, lp->cardbase + TMR1); - } - else - { - outb_p(time & 0xff, lp->cardbase + TMR2); - outb_p((time >> 8)&0xff, lp->cardbase + TMR2); - } -} /* tdelay */ - - -static void pt_txisr(struct pt_local *lp) -{ - unsigned long flags; - int cmd; - unsigned char c; - - save_flags(flags); - cli(); - cmd = lp->base + CTL; - -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_txisr(): tstate = %d (%d).\n", lp->tstate, lp->base & CHANA); -#endif - - switch (lp->tstate) - { - case CRCOUT: - lp->tstate = FLAGOUT; - tdelay(lp, lp->squeldelay); - restore_flags(flags); - return; - - case IDLE: - /* Transmitter idle. Find a frame for transmission */ - if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) - { - /* Nothing to send - return to receive mode - * Tx off now - flag should have gone - */ - pt_rts(lp, OFF); - - restore_flags(flags); - return; - } - if (!lp->dmachan) - { - lp->txptr = lp->sndbuf->data; - lp->txptr++; /* Ignore KISS control byte */ - lp->txcnt = (int) lp->sndbuf->len - 1; - } - /* If a buffer to send, drop though here */ - - case DEFER: - /* Check DCD - debounce it */ - /* See Intel Microcommunications Handbook p2-308 */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) - { - lp->tstate = DEFER; - tdelay(lp, 100); - /* DEFER until DCD transition or timeout */ - wrtscc(lp->cardbase, cmd, R15, DCDIE); - restore_flags(flags); - return; - } - if (random() > lp->persist) - { - lp->tstate = DEFER; - tdelay(lp, lp->slotime); - restore_flags(flags); - return; - } - pt_rts(lp, ON); /* Tx on */ - if (lp->dmachan) - wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); - lp->tstate = ST_TXDELAY; - tdelay(lp, lp->txdelay); - restore_flags(flags); - return; - - case ACTIVE: - /* Here we are actively sending a frame */ - if (lp->txcnt--) - { - /* XLZ - checkout Gracilis PT code to see if the while - * loop is better or not. - */ - c = *lp->txptr++; - /* next char is gone */ - wrtscc(lp->cardbase, cmd, R8, c); - /* stuffing a char satisfies interrupt condition */ - } else { - /* No more to send */ - kfree_skb(lp->sndbuf, FREE_WRITE); - lp->sndbuf = NULL; - if ((rdscc(lp->cardbase, cmd, R0) & TxEOM)) - { - /* Did we underrun */ - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); - lp->tstate = FLAGOUT; - tdelay(lp, lp->squeldelay); - restore_flags(flags); - return; - } - lp->tstate = UNDERRUN; - /* Send flags on underrun */ - if (lp->nrzi) - { - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); - } else { - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZ); - } - /* Reset Tx interrupt pending */ - wrtscc(lp->cardbase, cmd, R0, RES_Tx_P); - } - restore_flags(flags); - return; - default: - printk(KERN_ERR "PT: pt_txisr(): Invalid tstate (%d) for chan %s.\n", lp->tstate, (cmd & CHANA? "A": "B") ); - pt_rts(lp, OFF); - lp->tstate = IDLE; - break; - } /*switch */ - restore_flags(flags); -} - -static void pt_rxisr(struct device *dev) -{ - struct pt_local *lp = (struct pt_local*) dev->priv; - int cmd = lp->base + CTL; - int bytecount; - unsigned long flags; - char rse; - struct sk_buff *skb; - int sksize, pkt_len; - struct mbuf *cur_buf = NULL; - unsigned char *cfix; - - save_flags(flags); - cli(); - - /* Get status byte from R1 */ - rse = rdscc(lp->cardbase, cmd, R1); - -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_rxisr(): R1 = %#3x. (%d)\n", rse, lp->base & CHANA); -#endif - - if (lp->dmachan && (rse & Rx_OVR)) - lp->rstate = RXERROR; - - if (rdscc(lp->cardbase, cmd, R0) & Rx_CH_AV && !lp->dmachan) - { - /* There is a char to be stored - * Read special condition bits before reading the data char - */ - if (rse & Rx_OVR) - { - /* Rx overrun - toss buffer */ - /* wind back the pointers */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - lp->rstate = RXERROR; - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; - } else if (lp->rcvbuf->cnt >= lp->bufsiz) - { - /* Too large packet - * wind back Rx buffer pointers - */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - lp->rstate = TOOBIG; - } - /* ok, we can store the Rx char if no errors */ - if (lp->rstate == ACTIVE) - { - *lp->rcp++ = rdscc(lp->cardbase, cmd, R8); - lp->rcvbuf->cnt++; - } else { - /* we got an error, dump the FIFO */ - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - - /* Reset error latch */ - wrtscc(lp->cardbase, cmd, R0, ERR_RES); - lp->rstate = ACTIVE; - - /* Resync the SCC */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); - - } - } - - if (rse & END_FR) - { -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_rxisr() Got end of a %u byte frame.\n", lp->rcvbuf->cnt); -#endif - if (lp->dmachan) - { - clear_dma_ff(lp->dmachan); - bytecount = lp->bufsiz - get_dma_residue(lp->dmachan); - } else { - bytecount = lp->rcvbuf->cnt; - } - - /* END OF FRAME - Make sure Rx was active */ - if (lp->rcvbuf->cnt > 0 || lp->dmachan) - { - if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (bytecount < 10)) - { - if ((bytecount >= 10) && (rse & CRC_ERR)) - { - lp->stats.rx_crc_errors++; - } - if (lp->dmachan) - { - if (lp->rstate == RXERROR) - { - lp->stats.rx_errors++; - lp->stats.rx_over_errors++; - } - lp->rstate = ACTIVE; - setup_rx_dma(lp); - } else { - /* wind back Rx buffer pointers */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - - /* Re-sync the SCC */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); - - } -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_rxisr() %s error.\n", (rse & CRC_ERR)? "CRC" : "state"); -#endif - } else { - /* We have a valid frame */ - if (lp->dmachan) - { - pkt_len = lp->rcvbuf->cnt = bytecount - 2 +1; - /* Get buffer for next frame */ - cur_buf = lp->rcvbuf; - switchbuffers(lp); - setup_rx_dma(lp); - } else { - pkt_len = lp->rcvbuf->cnt -= 2; /* Toss 2 CRC bytes */ - pkt_len += 1; /* make room for KISS control byte */ - } - - /* Malloc up new buffer */ - sksize = pkt_len; - skb = dev_alloc_skb(sksize); - if (skb == NULL) - { - printk(KERN_ERR "PT: %s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; - restore_flags(flags); - return; - } - skb->dev = dev; - - /* KISS kludge = prefix with a 0 byte */ - cfix=skb_put(skb,pkt_len); - *cfix++=0; - /* skb->data points to the start of sk_buff area */ - if (lp->dmachan) - memcpy(cfix, (char*)cur_buf->data, pkt_len - 1); - else - memcpy(cfix, lp->rcvbuf->data, pkt_len - 1); - skb->protocol = ntohs(ETH_P_AX25); - skb->mac.raw=skb->data; - lp->stats.rx_bytes+=skb->len; - netif_rx(skb); - lp->stats.rx_packets++; - if (!lp->dmachan) - { - /* packet queued - wind back buffer for next frame */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - } - } /* good frame */ - } /* check active Rx */ - /* Clear error status */ - lp->rstate = ACTIVE; - /* Reset error latch */ - } /* end EOF check */ - wrtscc(lp->cardbase, cmd, R0, ERR_RES); - restore_flags(flags); -} /* pt_rxisr() */ - -/* - * This handles the two timer interrupts. - * This is a real bugger, cause you have to rip it out of the pi's - * external status code. They use the CTS line or something. - */ -static void pt_tmrisr(struct pt_local *lp) -{ - unsigned long flags; - -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_tmrisr(): tstate = %d (%d).\n", lp->tstate, lp->base & CHANA); -#endif - - save_flags(flags); - cli(); - - - switch (lp->tstate) - { - /* Most of this stuff is in pt_exisr() */ - case FLAGOUT: - case ST_TXDELAY: - case DEFER: -/* case ACTIVE: - case UNDERRUN:*/ - pt_exisr(lp); - break; - - default: - if (lp->base & CHANA) - printk(KERN_ERR "PT: pt_tmrisr(): Invalid tstate %d for Channel A\n", lp->tstate); - else - printk(KERN_ERR "PT: pt_tmrisr(): Invalid tstate %d for Channel B\n", lp->tstate); - break; - } /* end switch */ - restore_flags(flags); -} /* pt_tmrisr() */ - - -/* - * This routine is called by the kernel when there is an interrupt for the - * PT. - */ -static void pt_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - /* It's a tad dodgy here, but we assume pt0a until proven otherwise */ - struct device *dev = &pt0a; - struct pt_local *lp = dev->priv; - unsigned char intreg; - unsigned char st; - register int cbase = dev->base_addr & 0x3f0; - unsigned long flags; - - /* Read the PT's interrupt register, this is not the SCC one! */ - intreg = inb_p(cbase + INT_REG); - while(( intreg & 0x07) != 0x07) { - /* Read interrupt register pending from Channel A */ - while ((st = rdscc(cbase, cbase + CHANA + CTL, R3)) != 0) - { - /* Read interrupt vector from R2, channel B */ -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_interrupt(): R3 = %#3x", st); -#endif -/* st = rdscc(lp->cardbase, cbase + CHANB + CTL, R2) & 0x0e;*/ -#ifdef PT_DEBUG - printk(KERN_DEBUG "PI: R2 = %#3x.\n", st); -#endif - if (st & CHARxIP) { - /* Channel A Rx */ - lp = (struct pt_local*)pt0a.priv; - pt_rxisr(&pt0a); - } else if (st & CHATxIP) { - /* Channel A Tx */ - lp = (struct pt_local*)pt0a.priv; - pt_txisr(lp); - } else if (st & CHAEXT) { - /* Channel A External Status */ - lp = (struct pt_local*)pt0a.priv; - pt_exisr(lp); - } else if (st & CHBRxIP) { - /* Channel B Rx */ - lp= (struct pt_local*)pt0b.priv; - pt_rxisr(&pt0b); - } else if (st & CHBTxIP) { - /* Channel B Tx */ - lp = (struct pt_local*)pt0b.priv; - pt_txisr(lp); - } else if (st & CHBEXT) { - /* Channel B External Status */ - lp = (struct pt_local*)pt0b.priv; - pt_exisr(lp); - } - /* Reset highest interrupt under service */ - save_flags(flags); - cli(); - wrtscc(lp->cardbase, lp->base + CTL, R0, RES_H_IUS); - restore_flags(flags); - } /* end of SCC ints */ - - if (!(intreg & PT_TMR1_MSK)) - { - /* Clear timer 1 */ - inb_p(cbase + TMR1CLR); - - pt_tmrisr( (struct pt_local*)pt0a.priv); - } - - if (!(intreg & PT_TMR2_MSK)) - { - /* Clear timer 2 */ - inb_p(cbase + TMR2CLR); - - pt_tmrisr( (struct pt_local*)pt0b.priv); - } - - /* Get the next PT interrupt vector */ - intreg = inb_p(cbase + INT_REG); - } /* while (intreg) */ -} /* pt_interrupt() */ - - -static void pt_exisr(struct pt_local *lp) -{ - unsigned long flags; - int cmd = lp->base + CTL; - unsigned char st; - char c; - int length; - - save_flags(flags); - cli(); - - /* Get external status */ - st = rdscc(lp->cardbase, cmd, R0); - -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: exisr(): R0 = %#3x tstate = %d (%d).\n", st, lp->tstate, lp->base & CHANA); -#endif - /* Reset external status latch */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - - if ((lp->rstate >= ACTIVE) && (st & BRK_ABRT) && lp->dmachan) - { - setup_rx_dma(lp); - lp->rstate = ACTIVE; - } - - switch (lp->tstate) - { - case ACTIVE: /* Unexpected underrun */ -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: exisr(): unexpected underrun detected.\n"); -#endif - kfree_skb(lp->sndbuf, FREE_WRITE); - lp->sndbuf = NULL; - if (!lp->dmachan) - { - wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - } - lp->tstate = FLAGOUT; - tdelay(lp, lp->squeldelay); - restore_flags(flags); - return; - case UNDERRUN: - lp->tstate = CRCOUT; - restore_flags(flags); - return; - case FLAGOUT: - /* squeldelay has timed out */ - /* Find a frame for transmission */ - if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) - { - /* Nothing to send - return to Rx mode */ - pt_rts(lp, OFF); - lp->tstate = IDLE; - restore_flags(flags); - return; - } - if (!lp->dmachan) - { - lp->txptr = lp->sndbuf->data; - lp->txptr++; /* Ignore KISS control byte */ - lp->txcnt = (int) lp->sndbuf->len - 1; - } - /* Fall through if we have a packet */ - - case ST_TXDELAY: - if (lp->dmachan) - { - /* Disable DMA chan */ - disable_dma(lp->dmachan); - - /* Set up for TX dma */ - wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); - - length = lp->sndbuf->len - 1; - memcpy(lp->txdmabuf, &lp->sndbuf->data[1], length); - - /* Setup DMA controller for Tx */ - setup_tx_dma(lp, length); - - enable_dma(lp->dmachan); - - /* Reset CRC, Txint pending */ - wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC | RES_Tx_P); - - /* Allow underrun only */ - wrtscc(lp->cardbase, cmd, R15, TxUIE); - - /* Enable TX DMA */ - wrtscc(lp->cardbase, cmd, R1, WT_RDY_ENAB | WT_FN_RDYFN | EXT_INT_ENAB); - - /* Send CRC on underrun */ - wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); - - lp->tstate = ACTIVE; - break; - } - /* Get first char to send */ - lp->txcnt--; - c = *lp->txptr++; - /* Reset CRC for next frame */ - wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC); - - /* send abort on underrun */ - if (lp->nrzi) - { - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI | ABUNDER); - } else { - wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZ | ABUNDER); - } - /* send first char */ - wrtscc(lp->cardbase, cmd, R8, c); - - /* Reset end of message latch */ - wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); - - /* stuff an extra one in */ -/* while ((rdscc(lp->cardbase, cmd, R0) & Tx_BUF_EMP) && lp->txcnt) - { - lp->txcnt--; - c = *lp->txptr++; - wrtscc(lp->cardbase, cmd, R8, c); - }*/ - - /* select Tx interrupts to enable */ - /* Allow underrun int only */ - wrtscc(lp->cardbase, cmd, R15, TxUIE); - - /* Reset external interrupts */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - - /* Tx and Rx ints enabled */ - wrtscc(lp->cardbase, cmd, R1, TxINT_ENAB | EXT_INT_ENAB); - - lp->tstate = ACTIVE; - restore_flags(flags); - return; - - /* slotime has timed out */ - case DEFER: - /* Check DCD - debounce it - * see Intel Microcommunications Handbook, p2-308 - */ - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); - if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) - { - lp->tstate = DEFER; - tdelay(lp, 100); - /* DEFER until DCD transition or timeout */ - wrtscc(lp->cardbase, cmd, R15, DCDIE); - restore_flags(flags); - return; - } - if (random() > lp->persist) - { - lp->tstate = DEFER; - tdelay(lp, lp->slotime); - restore_flags(flags); - return; - } - if (lp->dmachan) - wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); - pt_rts(lp, ON); /* Tx on */ - lp->tstate = ST_TXDELAY; - tdelay(lp, lp->txdelay); - restore_flags(flags); - return; - - /* Only for int driven parts */ - if (lp->dmachan) - { - restore_flags(flags); - return; - } - - } /* end switch */ - /* - * Rx mode only - * This triggers when hunt mode is entered, & since an ABORT - * automatically enters hunt mode, we use that to clean up - * any waiting garbage - */ - if ((lp->rstate == ACTIVE) && (st & BRK_ABRT) ) - { -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: exisr(): abort detected.\n"); -#endif - /* read and dump all of SCC Rx FIFO */ - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - (void) rdscc(lp->cardbase, cmd, R8); - - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - - /* Re-sync the SCC */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); - - } - - /* Check for DCD transitions */ - if ( (st & DCD) != (lp->saved_RR0 & DCD)) - { -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_exisr(): DCD is now %s.\n", (st & DCD)? "ON" : "OFF" ); -#endif - if (st & DCD) - { - /* Check that we don't already have some data */ - if (lp->rcvbuf->cnt > 0) - { -#ifdef PT_DEBUG - printk(KERN_DEBUG "PT: pt_exisr() dumping %u bytes from buffer.\n", lp->rcvbuf->cnt); -#endif - /* wind back buffers */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - } - } else { /* DCD off */ - - /* read and dump al SCC FIFO */ - (void)rdscc(lp->cardbase, cmd, R8); - (void)rdscc(lp->cardbase, cmd, R8); - (void)rdscc(lp->cardbase, cmd, R8); - - /* wind back buffers */ - lp->rcp = lp->rcvbuf->data; - lp->rcvbuf->cnt = 0; - - /* Re-sync the SCC */ - wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); - } - - } - /* Update the saved version of register RR) */ - lp->saved_RR0 = st &~ ZCOUNT; - restore_flags(flags); - -} /* pt_exisr() */ - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -MODULE_AUTHOR("Craig Small VK2XLZ "); -MODULE_DESCRIPTION("AX.25 driver for the Gracillis PacketTwin HDLC card"); - -int init_module(void) -{ - return pt_init(); -} - -void cleanup_module(void) -{ - free_irq(pt0a.irq, &pt0a); /* IRQs and IO Ports are shared */ - release_region(pt0a.base_addr & 0x3f0, PT_TOTAL_SIZE); - - kfree(pt0a.priv); - pt0a.priv = NULL; - unregister_netdev(&pt0a); - - kfree(pt0b.priv); - pt0b.priv = NULL; - unregister_netdev(&pt0b); -} -#endif diff -u --recursive --new-file v2.1.70/linux/drivers/net/scc.c linux/drivers/net/scc.c --- v2.1.70/linux/drivers/net/scc.c Mon Dec 1 12:04:13 1997 +++ linux/drivers/net/scc.c Wed Dec 31 16:00:00 1969 @@ -1,2257 +0,0 @@ -#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" - -/* - * Please use z8530drv-utils-3.0 with this version. - * ------------------ - */ - -/* - ******************************************************************** - * SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 * - ******************************************************************** - - - ******************************************************************** - - Copyright (c) 1993, 1997 Joerg Reuter DL1BKE - - portions (c) 1993 Guido ten Dolle PE1NNZ - - ******************************************************************** - - The driver and the programs in the archive are UNDER CONSTRUCTION. - The code is likely to fail, and so your kernel could --- even - a whole network. - - This driver is intended for Amateur Radio use. If you are running it - for commercial purposes, please drop me a note. I am nosy... - - ...BUT: - - ! You m u s t recognize the appropriate legislations of your country ! - ! before you connect a radio to the SCC board and start to transmit or ! - ! receive. The GPL allows you to use the d r i v e r, NOT the RADIO! ! - - For non-Amateur-Radio use please note that you might need a special - allowance/licence from the designer of the SCC Board and/or the - MODEM. - - This program is free software; you can redistribute it and/or modify - it under the terms of the (modified) GNU General Public License - delivered with the Linux kernel source. - - 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 find a copy of the GNU General Public License in - /usr/src/linux/COPYING; - - ******************************************************************** - - - Incomplete history of z8530drv: - ------------------------------- - - 940913 - started to write the driver, rescued most of my own - code (and Hans Alblas' memory buffer pool concept) from - an earlier project "sccdrv" which was initiated by - Guido ten Dolle. Not much of the old driver survived, - though. The first version I put my hands on was sccdrv1.3 - from August 1993. The memory buffer pool concept - appeared in an unauthorized sccdrv version (1.5) from - August 1994. - - 950131 - changed copyright notice to GPL without limitations. - - . - . - . - - 961005 - New semester, new driver... - - * KISS TNC emulator removed (TTY driver) - * Source moved to drivers/net/ - * Includes Z8530 defines from drivers/net/z8530.h - * Uses sk_buffer memory management - * Reduced overhead of /proc/net/z8530drv output - * Streamlined quite a lot things - * Invents brand new bugs... ;-) - - The move to version number 3.0 reflects theses changes. - You can use 'kissbridge' if you need a KISS TNC emulator. - - 961213 - Fixed for Linux networking changes. (G4KLX) - 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! - - NB -- if you find errors, change something, please let me know - first before you distribute it... And please don't touch - the version number. Just replace my callsign in - "v3.0.dl1bke" with your own. Just to avoid confusion... - - If you want to add your modification to the linux distribution - please (!) contact me first. - - New versions of the driver will be announced on the linux-hams - mailing list on vger.rutgers.edu. To subscribe send an e-mail - to majordomo@vger.rutgers.edu with the following line in - the body of the mail: - - subscribe linux-hams - - The content of the "Subject" field will be ignored. - - vy 73, - Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org - AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU - Internet: jreuter@poboxes.com - www : http://www.rat.de/jr -*/ - -/* ----------------------------------------------------------------------- */ - -#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 */ -#define MAXQUEUE 8 /* number of buffers we queue ourself */ -#undef DISABLE_ALL_INTS /* use cli()/sti() in ISR instead of */ - /* enable_irq()/disable_irq() */ -#undef SCC_DEBUG - -#define DEFAULT_CLOCK 4915200 /* default pclock if nothing is specified */ - -/* ----------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include "z8530.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -#endif - -int scc_init(void); - -static void t_dwait(unsigned long); -static void t_txdelay(unsigned long); -static void t_tail(unsigned long); -static void t_busy(unsigned long); -static void t_maxkeyup(unsigned long); -static void t_idle(unsigned long); -static void scc_tx_done(struct scc_channel *); -static void scc_start_tx_timer(struct scc_channel *, void (*)(unsigned long), unsigned long); -static void scc_start_maxkeyup(struct scc_channel *); -static void scc_start_defer(struct scc_channel *); - -static void z8530_init(void); - -static void init_channel(struct scc_channel *scc); -static void scc_key_trx (struct scc_channel *scc, char tx); -static void scc_isr(int irq, void *dev_id, struct pt_regs *regs); -static void scc_init_timer(struct scc_channel *scc); - -static int scc_net_setup(struct scc_channel *scc, unsigned char *name); -static int scc_net_init(struct device *dev); -static int scc_net_open(struct device *dev); -static int scc_net_close(struct device *dev); -static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb); -static int scc_net_tx(struct sk_buff *skb, struct device *dev); -static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd); -static int scc_net_set_mac_address(struct device *dev, void *addr); -static int scc_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); -static struct net_device_stats * scc_net_get_stats(struct device *dev); - -static unsigned char *SCC_DriverName = "scc"; - -static struct irqflags { unsigned char used : 1; } Ivec[16]; - -static struct scc_channel SCC_Info[2 * MAXSCC]; /* information per channel */ - -static struct scc_ctrl { - io_port chan_A; - io_port chan_B; - int irq; -} SCC_ctrl[MAXSCC+1]; - -static unsigned char Driver_Initialized = 0; -static int Nchips = 0; -static io_port Vector_Latch = 0; - -MODULE_AUTHOR("Joerg Reuter "); -MODULE_DESCRIPTION("Network Device Driver for Z8530 based HDLC cards for Amateur Packet Radio"); -MODULE_SUPPORTED_DEVICE("scc"); - -/* ******************************************************************** */ -/* * Port Access Functions * */ -/* ******************************************************************** */ - -/* These provide interrupt save 2-step access to the Z8530 registers */ - -extern __inline__ unsigned char InReg(io_port port, unsigned char reg) -{ - unsigned long flags; - unsigned char r; - - save_flags(flags); - cli(); -#ifdef SCC_LDELAY - Outb(port, reg); - udelay(SCC_LDELAY); - r=Inb(port); - udelay(SCC_LDELAY); -#else - Outb(port, reg); - r=Inb(port); -#endif - restore_flags(flags); - return r; -} - -extern __inline__ void OutReg(io_port port, unsigned char reg, unsigned char val) -{ - unsigned long flags; - - save_flags(flags); - cli(); -#ifdef SCC_LDELAY - Outb(port, reg); udelay(SCC_LDELAY); - Outb(port, val); udelay(SCC_LDELAY); -#else - Outb(port, reg); - Outb(port, val); -#endif - restore_flags(flags); -} - -extern __inline__ void wr(struct scc_channel *scc, unsigned char reg, - unsigned char val) -{ - OutReg(scc->ctrl, reg, (scc->wreg[reg] = val)); -} - -extern __inline__ void or(struct scc_channel *scc, unsigned char reg, unsigned char val) -{ - OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val)); -} - -extern __inline__ void cl(struct scc_channel *scc, unsigned char reg, unsigned char val) -{ - OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val)); -} - -#ifdef DISABLE_ALL_INTS -extern __inline__ void scc_cli(int irq) -{ cli(); } -extern __inline__ void scc_sti(int irq) -{ sti(); } -#else -static __inline__ void scc_cli(int irq) -{ disable_irq(irq); } -static __inline__ void scc_sti(int irq) -{ enable_irq(irq); } -#endif - -/* ******************************************************************** */ -/* * Some useful macros * */ -/* ******************************************************************** */ - - -extern __inline__ void scc_lock_dev(struct scc_channel *scc) -{ - scc->dev->tbusy = 1; -} - -extern __inline__ void scc_unlock_dev(struct scc_channel *scc) -{ - scc->dev->tbusy = 0; -} - -extern __inline__ void scc_discard_buffers(struct scc_channel *scc) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - if (scc->tx_buff != NULL) - { - dev_kfree_skb(scc->tx_buff, FREE_WRITE); - scc->tx_buff = NULL; - } - - while (skb_queue_len(&scc->tx_queue)) - dev_kfree_skb(skb_dequeue(&scc->tx_queue), FREE_WRITE); - - restore_flags(flags); -} - - - -/* ******************************************************************** */ -/* * Interrupt Service Routines * */ -/* ******************************************************************** */ - - -/* ----> subroutines for the interrupt handlers <---- */ - -extern __inline__ void scc_notify(struct scc_channel *scc, int event) -{ - struct sk_buff *skb; - char *bp; - - if (scc->kiss.fulldup != KISS_DUPLEX_OPTIMA) - return; - - skb = dev_alloc_skb(2); - if (skb != NULL) - { - bp = skb_put(skb, 2); - *bp++ = PARAM_HWEVENT; - *bp++ = event; - scc_net_rx(scc, skb); - } else - scc->stat.nospace++; -} - -extern __inline__ void flush_rx_FIFO(struct scc_channel *scc) -{ - int k; - - for (k=0; k<3; k++) - Inb(scc->data); - - if(scc->rx_buff != NULL) /* did we receive something? */ - { - scc->stat.rxerrs++; /* then count it as an error */ - kfree_skb(scc->rx_buff, FREE_READ); - scc->rx_buff = NULL; - } -} - - -/* ----> four different interrupt handlers for Tx, Rx, changing of */ -/* DCD/CTS and Rx/Tx errors */ - -/* Transmitter interrupt handler */ -extern __inline__ void scc_txint(struct scc_channel *scc) -{ - struct sk_buff *skb; - - scc->stat.txints++; - skb = scc->tx_buff; - - /* send first octet */ - - if (skb == NULL) - { - skb = skb_dequeue(&scc->tx_queue); - scc->tx_buff = skb; - scc_unlock_dev(scc); - - if (skb == NULL) - { - scc_tx_done(scc); - Outb(scc->ctrl, RES_Tx_P); - return; - } - - if (skb->len == 0) /* Paranoia... */ - { - dev_kfree_skb(skb, FREE_WRITE); - scc->tx_buff = NULL; - scc_tx_done(scc); - Outb(scc->ctrl, RES_Tx_P); - return; - } - - scc->stat.tx_state = TXS_ACTIVE; - - OutReg(scc->ctrl, R0, RES_Tx_CRC); - /* reset CRC generator */ - or(scc,R10,ABUNDER); /* re-install underrun protection */ - Outb(scc->data,*skb->data); /* send byte */ - skb_pull(skb, 1); - - if (!scc->enhanced) /* reset EOM latch */ - Outb(scc->ctrl,RES_EOM_L); - return; - } - - /* End Of Frame... */ - - if (skb->len == 0) - { - Outb(scc->ctrl, RES_Tx_P); /* reset pending int */ - cl(scc, R10, ABUNDER); /* send CRC */ - dev_kfree_skb(skb, FREE_WRITE); - scc->tx_buff = NULL; - scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */ - return; - } - - /* send octet */ - - Outb(scc->data,*skb->data); - skb_pull(skb, 1); -} - - -/* External/Status interrupt handler */ -extern __inline__ void scc_exint(struct scc_channel *scc) -{ - unsigned char status,changes,chg_and_stat; - - scc->stat.exints++; - - status = InReg(scc->ctrl,R0); - changes = status ^ scc->status; - chg_and_stat = changes & status; - - /* ABORT: generated whenever DCD drops while receiving */ - - if (chg_and_stat & BRK_ABRT) /* Received an ABORT */ - flush_rx_FIFO(scc); - - - /* DCD: on = start to receive packet, off = ABORT condition */ - /* (a successfully received packet generates a special condition int) */ - - if(changes & DCD) /* DCD input changed state */ - { - if(status & DCD) /* DCD is now ON */ - { - if (scc->modem.clocksrc != CLK_EXTERNAL) - OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */ - - or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */ - } else { /* DCD is now OFF */ - cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */ - flush_rx_FIFO(scc); - } - - if (!scc->kiss.softdcd) - scc_notify(scc, (status & DCD)? HWEV_DCD_ON:HWEV_DCD_OFF); - } - - /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */ - - if (changes & SYNC_HUNT) - { - if (scc->kiss.softdcd) - scc_notify(scc, (status & SYNC_HUNT)? HWEV_DCD_OFF:HWEV_DCD_ON); - else - cl(scc,R15,SYNCIE); /* oops, we were too lazy to disable this? */ - } - -#ifdef notdef - /* CTS: use external TxDelay (what's that good for?!) - * Anyway: If we _could_ use it (BayCom USCC uses CTS for - * own purposes) we _should_ use the "autoenable" feature - * of the Z8530 and not this interrupt... - */ - - if (chg_and_stat & CTS) /* CTS is now ON */ - { - if (scc->kiss.txdelay == 0) /* zero TXDELAY = wait for CTS */ - scc_start_tx_timer(scc, t_txdelay, 0); - } -#endif - - if (scc->stat.tx_state == TXS_ACTIVE && (status & TxEOM)) - { - scc->stat.tx_under++; /* oops, an underrun! count 'em */ - Outb(scc->ctrl, RES_EXT_INT); /* reset ext/status interrupts */ - - if (scc->tx_buff != NULL) - { - dev_kfree_skb(scc->tx_buff, FREE_WRITE); - scc->tx_buff = NULL; - } - - or(scc,R10,ABUNDER); - scc_start_tx_timer(scc, t_txdelay, 0); /* restart transmission */ - } - - scc->status = status; - Outb(scc->ctrl,RES_EXT_INT); -} - - -/* Receiver interrupt handler */ -extern __inline__ void scc_rxint(struct scc_channel *scc) -{ - struct sk_buff *skb; - - scc->stat.rxints++; - - if((scc->wreg[5] & RTS) && scc->kiss.fulldup == KISS_DUPLEX_HALF) - { - Inb(scc->data); /* discard char */ - or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ - return; - } - - skb = scc->rx_buff; - - if (skb == NULL) - { - skb = dev_alloc_skb(scc->stat.bufsize); - if (skb == NULL) - { - scc->dev_stat.rx_dropped++; - scc->stat.nospace++; - Inb(scc->data); - or(scc, R3, ENT_HM); - return; - } - - scc->rx_buff = skb; - *(skb_put(skb, 1)) = 0; /* KISS data */ - } - - if (skb->len >= scc->stat.bufsize) - { -#ifdef notdef - printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n"); -#endif - kfree_skb(skb, FREE_READ); - scc->rx_buff = NULL; - Inb(scc->data); - or(scc, R3, ENT_HM); - return; - } - - *(skb_put(skb, 1)) = Inb(scc->data); -} - - -/* Receive Special Condition interrupt handler */ -extern __inline__ void scc_spint(struct scc_channel *scc) -{ - unsigned char status; - struct sk_buff *skb; - - scc->stat.spints++; - - status = InReg(scc->ctrl,R1); /* read receiver status */ - - Inb(scc->data); /* throw away Rx byte */ - skb = scc->rx_buff; - - if(status & Rx_OVR) /* receiver overrun */ - { - scc->stat.rx_over++; /* count them */ - or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ - - if (skb != NULL) - kfree_skb(skb, FREE_READ); - scc->rx_buff = NULL; - } - - if(status & END_FR && skb != NULL) /* end of frame */ - { - /* CRC okay, frame ends on 8 bit boundary and received something ? */ - - if (!(status & CRC_ERR) && (status & 0xe) == RES8 && skb->len > 0) - { - /* ignore last received byte (first of the CRC bytes) */ - skb_trim(skb, skb->len-1); - scc_net_rx(scc, skb); - scc->rx_buff = NULL; - scc->stat.rxframes++; - } else { /* a bad frame */ - kfree_skb(skb, FREE_READ); - scc->rx_buff = NULL; - scc->stat.rxerrs++; - } - } - - Outb(scc->ctrl,ERR_RES); -} - - -/* ----> interrupt service routine for the Z8530 <---- */ - -static void scc_isr_dispatch(struct scc_channel *scc, int vector) -{ - switch (vector & VECTOR_MASK) - { - case TXINT: scc_txint(scc); break; - case EXINT: scc_exint(scc); break; - case RXINT: scc_rxint(scc); break; - case SPINT: scc_spint(scc); break; - } -} - -/* If the card has a latch for the interrupt vector (like the PA0HZP card) - use it to get the number of the chip that generated the int. - If not: poll all defined chips. - */ - -#define SCC_IRQTIMEOUT 30000 - -static void scc_isr(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned char vector; - struct scc_channel *scc; - struct scc_ctrl *ctrl; - int k; - - scc_cli(irq); - - if (Vector_Latch) - { - for(k=0; k < SCC_IRQTIMEOUT; k++) - { - Outb(Vector_Latch, 0); /* Generate INTACK */ - - /* Read the vector */ - if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break; - if (vector & 0x01) break; - - scc=&SCC_Info[vector >> 3 ^ 0x01]; - if (!scc->dev) break; - - scc_isr_dispatch(scc, vector); - - OutReg(scc->ctrl,R0,RES_H_IUS); /* Reset Highest IUS */ - } - scc_sti(irq); - - if (k == SCC_IRQTIMEOUT) - printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n"); - - return; - } - - /* Find the SCC generating the interrupt by polling all attached SCCs - * reading RR3A (the interrupt pending register) - */ - - ctrl = SCC_ctrl; - while (ctrl->chan_A) - { - if (ctrl->irq != irq) - { - ctrl++; - continue; - } - - scc = NULL; - for (k = 0; InReg(ctrl->chan_A,R3) && k < SCC_IRQTIMEOUT; k++) - { - vector=InReg(ctrl->chan_B,R2); /* Read the vector */ - if (vector & 0x01) break; - - scc = &SCC_Info[vector >> 3 ^ 0x01]; - if (!scc->dev) break; - - scc_isr_dispatch(scc, vector); - } - - if (k == SCC_IRQTIMEOUT) - { - printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?!\n"); - break; - } - - /* This looks wierd and it is. At least the BayCom USCC doesn't - * use the Interrupt Daisy Chain, thus we'll have to start - * all over again to be sure not to miss an interrupt from - * (any of) the other chip(s)... - * Honestly, the situation *is* braindamaged... - */ - - if (scc != NULL) - { - OutReg(scc->ctrl,R0,RES_H_IUS); - ctrl = SCC_ctrl; - } else - ctrl++; - } - - scc_sti(irq); -} - - - -/* ******************************************************************** */ -/* * Init Channel */ -/* ******************************************************************** */ - - -/* ----> set SCC channel speed <---- */ - -extern __inline__ void set_brg(struct scc_channel *scc, unsigned int tc) -{ - cl(scc,R14,BRENABL); /* disable baudrate generator */ - wr(scc,R12,tc & 255); /* brg rate LOW */ - wr(scc,R13,tc >> 8); /* brg rate HIGH */ - or(scc,R14,BRENABL); /* enable baudrate generator */ -} - -extern __inline__ void set_speed(struct scc_channel *scc) -{ - disable_irq(scc->irq); - - if (scc->modem.speed > 0) /* paranoia... */ - set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2); - - enable_irq(scc->irq); -} - - -/* ----> initialize a SCC channel <---- */ - -extern __inline__ void init_brg(struct scc_channel *scc) -{ - wr(scc, R14, BRSRC); /* BRG source = PCLK */ - OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */ - OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */ -} - -/* - * Initialization according to the Z8530 manual (SGS-Thomson's version): - * - * 1. Modes and constants - * - * WR9 11000000 chip reset - * WR4 XXXXXXXX Tx/Rx control, async or sync mode - * WR1 0XX00X00 select W/REQ (optional) - * WR2 XXXXXXXX program interrupt vector - * WR3 XXXXXXX0 select Rx control - * WR5 XXXX0XXX select Tx control - * WR6 XXXXXXXX sync character - * WR7 XXXXXXXX sync character - * WR9 000X0XXX select interrupt control - * WR10 XXXXXXXX miscellaneous control (optional) - * WR11 XXXXXXXX clock control - * WR12 XXXXXXXX time constant lower byte (optional) - * WR13 XXXXXXXX time constant upper byte (optional) - * WR14 XXXXXXX0 miscellaneous control - * WR14 XXXSSSSS commands (optional) - * - * 2. Enables - * - * WR14 000SSSS1 baud rate enable - * WR3 SSSSSSS1 Rx enable - * WR5 SSSS1SSS Tx enable - * WR0 10000000 reset Tx CRG (optional) - * WR1 XSS00S00 DMA enable (optional) - * - * 3. Interrupt status - * - * WR15 XXXXXXXX enable external/status - * WR0 00010000 reset external status - * WR0 00010000 reset external status twice - * WR1 SSSXXSXX enable Rx, Tx and Ext/status - * WR9 000SXSSS enable master interrupt enable - * - * 1 = set to one, 0 = reset to zero - * X = user defined, S = same as previous init - * - * - * Note that the implementation differs in some points from above scheme. - * - */ - -static void init_channel(struct scc_channel *scc) -{ - del_timer(&scc->tx_t); - del_timer(&scc->tx_wdog); - - disable_irq(scc->irq); - - wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */ - wr(scc,R1,0); /* no W/REQ operation */ - wr(scc,R3,Rx8|RxCRC_ENAB); /* RX 8 bits/char, CRC, disabled */ - wr(scc,R5,Tx8|DTR|TxCRC_ENAB); /* TX 8 bits/char, disabled, DTR */ - wr(scc,R6,0); /* SDLC address zero (not used) */ - wr(scc,R7,FLAG); /* SDLC flag value */ - wr(scc,R9,VIS); /* vector includes status */ - wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */ - wr(scc,R14, 0); - - -/* set clock sources: - - CLK_DPLL: normal halfduplex operation - - RxClk: use DPLL - TxClk: use DPLL - TRxC mode DPLL output - - CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem) - - BayCom: others: - - TxClk = pin RTxC TxClk = pin TRxC - RxClk = pin TRxC RxClk = pin RTxC - - - CLK_DIVIDER: - RxClk = use DPLL - TxClk = pin RTxC - - BayCom: others: - pin TRxC = DPLL pin TRxC = BRG - (RxClk * 1) (RxClk * 32) -*/ - - - switch(scc->modem.clocksrc) - { - case CLK_DPLL: - wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP); - init_brg(scc); - break; - - case CLK_DIVIDER: - wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI); - init_brg(scc); - break; - - case CLK_EXTERNAL: - wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP); - OutReg(scc->ctrl, R14, DISDPLL); - break; - - } - - set_speed(scc); /* set baudrate */ - - if(scc->enhanced) - { - or(scc,R15,SHDLCE|FIFOE); /* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */ - wr(scc,R7,AUTOEOM); - } - - if((InReg(scc->ctrl,R0)) & DCD) /* DCD is now ON */ - { - if (scc->modem.clocksrc != CLK_EXTERNAL) - or(scc,R14, SEARCH); - - or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */ - } - - /* enable ABORT, DCD & SYNC/HUNT interrupts */ - - wr(scc,R15, BRKIE|TxUIE|DCDIE); - if (scc->kiss.softdcd) - or(scc,R15, SYNCIE); - - Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ - Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */ - - or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */ - - scc->status = InReg(scc->ctrl,R0); /* read initial status */ - - or(scc,R9,MIE); /* master interrupt enable */ - - scc_init_timer(scc); - - enable_irq(scc->irq); -} - - - - -/* ******************************************************************** */ -/* * SCC timer functions * */ -/* ******************************************************************** */ - - -/* ----> scc_key_trx sets the time constant for the baudrate - generator and keys the transmitter <---- */ - -static void scc_key_trx(struct scc_channel *scc, char tx) -{ - unsigned int time_const; - - if (scc->brand & PRIMUS) - Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0)); - - if (scc->modem.speed < 300) - scc->modem.speed = 1200; - - time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2; - - disable_irq(scc->irq); - - if (tx) - { - or(scc, R1, TxINT_ENAB); /* t_maxkeyup may have reset these */ - or(scc, R15, TxUIE); - } - - if (scc->modem.clocksrc == CLK_DPLL) - { /* 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 */ - wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR); - - or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */ - } else { - cl(scc,R5,RTS|TxENAB); - - set_brg(scc, time_const); /* reprogram baudrate generator */ - - /* 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 - } - } - - enable_irq(scc->irq); -} - - -/* ----> SCC timer interrupt handler and friends. <---- */ - -static void scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when) -{ - unsigned long flags; - - - save_flags(flags); - cli(); - - del_timer(&scc->tx_t); - - if (when == 0) - { - handler((unsigned long) scc); - } else - if (when != TIMER_OFF) - { - scc->tx_t.data = (unsigned long) scc; - scc->tx_t.function = handler; - scc->tx_t.expires = jiffies + (when*HZ)/100; - add_timer(&scc->tx_t); - } - - restore_flags(flags); -} - -static void scc_start_defer(struct scc_channel *scc) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - del_timer(&scc->tx_wdog); - - if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF) - { - scc->tx_wdog.data = (unsigned long) scc; - scc->tx_wdog.function = t_busy; - scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer; - add_timer(&scc->tx_wdog); - } - restore_flags(flags); -} - -static void scc_start_maxkeyup(struct scc_channel *scc) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - del_timer(&scc->tx_wdog); - - if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF) - { - scc->tx_wdog.data = (unsigned long) scc; - scc->tx_wdog.function = t_maxkeyup; - scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup; - add_timer(&scc->tx_wdog); - } - - restore_flags(flags); -} - -/* - * This is called from scc_txint() when there are no more frames to send. - * Not exactly a timer function, but it is a close friend of the family... - */ - -static void scc_tx_done(struct scc_channel *scc) -{ - /* - * trx remains keyed in fulldup mode 2 until t_idle expires. - */ - - switch (scc->kiss.fulldup) - { - case KISS_DUPLEX_LINK: - scc->stat.tx_state = TXS_IDLE2; - if (scc->kiss.idletime != TIMER_OFF) - scc_start_tx_timer(scc, t_idle, scc->kiss.idletime*100); - break; - case KISS_DUPLEX_OPTIMA: - scc_notify(scc, HWEV_ALL_SENT); - break; - default: - scc->stat.tx_state = TXS_BUSY; - scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); - } - - scc_unlock_dev(scc); -} - - -static unsigned char Rand = 17; - -extern __inline__ int is_grouped(struct scc_channel *scc) -{ - int k; - struct scc_channel *scc2; - unsigned char grp1, grp2; - - grp1 = scc->kiss.group; - - for (k = 0; k < (Nchips * 2); k++) - { - scc2 = &SCC_Info[k]; - grp2 = scc2->kiss.group; - - if (scc2 == scc || !(scc2->dev && grp2)) - continue; - - if ((grp1 & 0x3f) == (grp2 & 0x3f)) - { - if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) ) - return 1; - - if ( (grp1 & RXGROUP) && (scc2->status & DCD) ) - return 1; - } - } - return 0; -} - -/* DWAIT and SLOTTIME expired - * - * fulldup == 0: DCD is active or Rand > P-persistence: start t_busy timer - * else key trx and start txdelay - * fulldup == 1: key trx and start txdelay - * fulldup == 2: mintime expired, reset status or key trx and start txdelay - */ - -static void t_dwait(unsigned long channel) -{ - struct scc_channel *scc = (struct scc_channel *) channel; - - if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */ - { - if (skb_queue_len(&scc->tx_queue) == 0) /* nothing to send */ - { - scc->stat.tx_state = TXS_IDLE; - scc_unlock_dev(scc); /* t_maxkeyup locked it. */ - return; - } - - scc->stat.tx_state = TXS_BUSY; - } - - if (scc->kiss.fulldup == KISS_DUPLEX_HALF) - { - Rand = Rand * 17 + 31; - - if ( (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD)) || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) ) - { - scc_start_defer(scc); - scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime); - return ; - } - } - - if ( !(scc->wreg[R5] & RTS) ) - { - scc_key_trx(scc, TX_ON); - scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); - } else { - scc_start_tx_timer(scc, t_txdelay, 0); - } -} - - -/* TXDELAY expired - * - * kick transmission by a fake scc_txint(scc), start 'maxkeyup' watchdog. - */ - -static void t_txdelay(unsigned long channel) -{ - struct scc_channel *scc = (struct scc_channel *) channel; - - scc_start_maxkeyup(scc); - - if (scc->tx_buff == NULL) - { - disable_irq(scc->irq); - scc_txint(scc); - enable_irq(scc->irq); - } -} - - -/* TAILTIME expired - * - * switch off transmitter. If we were stopped by Maxkeyup restart - * transmission after 'mintime' seconds - */ - -static void t_tail(unsigned long channel) -{ - struct scc_channel *scc = (struct scc_channel *) channel; - unsigned long flags; - - save_flags(flags); - cli(); - - del_timer(&scc->tx_wdog); - scc_key_trx(scc, TX_OFF); - - restore_flags(flags); - - if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */ - { - scc->stat.tx_state = TXS_WAIT; - - if (scc->kiss.mintime != TIMER_OFF) /* try it again */ - scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); - else - scc_start_tx_timer(scc, t_dwait, 0); - return; - } - - scc->stat.tx_state = TXS_IDLE; - scc_unlock_dev(scc); -} - - -/* BUSY timeout - * - * throw away send buffers if DCD remains active too long. - */ - -static void t_busy(unsigned long channel) -{ - struct scc_channel *scc = (struct scc_channel *) channel; - - del_timer(&scc->tx_t); - scc_lock_dev(scc); - - scc_discard_buffers(scc); - - scc->stat.txerrs++; - scc->stat.tx_state = TXS_IDLE; - - scc_unlock_dev(scc); -} - -/* MAXKEYUP timeout - * - * this is our watchdog. - */ - -static void t_maxkeyup(unsigned long channel) -{ - struct scc_channel *scc = (struct scc_channel *) channel; - unsigned long flags; - - save_flags(flags); - cli(); - - /* - * let things settle down before we start to - * accept new data. - */ - - scc_lock_dev(scc); - scc_discard_buffers(scc); - - del_timer(&scc->tx_t); - - cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */ - cl(scc, R15, TxUIE); /* count it. */ - OutReg(scc->ctrl, R0, RES_Tx_P); - - restore_flags(flags); - - scc->stat.txerrs++; - scc->stat.tx_state = TXS_TIMEOUT; - scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); -} - -/* IDLE timeout - * - * in fulldup mode 2 it keys down the transmitter after 'idle' seconds - * of inactivity. We will not restart transmission before 'mintime' - * expires. - */ - -static void t_idle(unsigned long channel) -{ - struct scc_channel *scc = (struct scc_channel *) channel; - - del_timer(&scc->tx_wdog); - - scc_key_trx(scc, TX_OFF); - - if (scc->kiss.mintime != TIMER_OFF) - scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); - scc->stat.tx_state = TXS_WAIT; -} - -static void scc_init_timer(struct scc_channel *scc) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - scc->stat.tx_state = TXS_IDLE; - - restore_flags(flags); -} - - -/* ******************************************************************** */ -/* * Set/get L1 parameters * */ -/* ******************************************************************** */ - - -/* - * this will set the "hardware" parameters through KISS commands or ioctl() - */ - -#define CAST(x) (unsigned long)(x) - -static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg) -{ - int dcd; - - switch (cmd) - { - case PARAM_TXDELAY: scc->kiss.txdelay=arg; break; - case PARAM_PERSIST: scc->kiss.persist=arg; break; - case PARAM_SLOTTIME: scc->kiss.slottime=arg; break; - case PARAM_TXTAIL: scc->kiss.tailtime=arg; break; - case PARAM_FULLDUP: scc->kiss.fulldup=arg; break; - case PARAM_DTR: break; /* does someone need this? */ - case PARAM_GROUP: scc->kiss.group=arg; break; - case PARAM_IDLE: scc->kiss.idletime=arg; break; - case PARAM_MIN: scc->kiss.mintime=arg; break; - case PARAM_MAXKEY: scc->kiss.maxkeyup=arg; break; - case PARAM_WAIT: scc->kiss.waittime=arg; break; - case PARAM_MAXDEFER: scc->kiss.maxdefer=arg; break; - case PARAM_TX: scc->kiss.tx_inhibit=arg; break; - - case PARAM_SOFTDCD: - scc->kiss.softdcd=arg; - if (arg) - or(scc, R15, SYNCIE); - else - cl(scc, R15, SYNCIE); - break; - - case PARAM_SPEED: - if (arg < 256) - scc->modem.speed=arg*100; - else - scc->modem.speed=arg; - - if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */ - set_speed(scc); - break; - - case PARAM_RTS: - if ( !(scc->wreg[R5] & RTS) ) - { - if (arg != TX_OFF) - scc_key_trx(scc, TX_ON); - scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); - } else { - if (arg == TX_OFF) - { - scc->stat.tx_state = TXS_BUSY; - scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); - } - } - break; - - case PARAM_HWEVENT: - dcd = (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD)); - scc_notify(scc, dcd? HWEV_DCD_ON:HWEV_DCD_OFF); - break; - - default: return -EINVAL; - } - - return 0; -} - - - -static unsigned long scc_get_param(struct scc_channel *scc, unsigned int cmd) -{ - switch (cmd) - { - case PARAM_TXDELAY: return CAST(scc->kiss.txdelay); - case PARAM_PERSIST: return CAST(scc->kiss.persist); - case PARAM_SLOTTIME: return CAST(scc->kiss.slottime); - case PARAM_TXTAIL: return CAST(scc->kiss.tailtime); - case PARAM_FULLDUP: return CAST(scc->kiss.fulldup); - case PARAM_SOFTDCD: return CAST(scc->kiss.softdcd); - case PARAM_DTR: return CAST((scc->wreg[R5] & DTR)? 1:0); - case PARAM_RTS: return CAST((scc->wreg[R5] & RTS)? 1:0); - case PARAM_SPEED: return CAST(scc->modem.speed); - case PARAM_GROUP: return CAST(scc->kiss.group); - case PARAM_IDLE: return CAST(scc->kiss.idletime); - case PARAM_MIN: return CAST(scc->kiss.mintime); - case PARAM_MAXKEY: return CAST(scc->kiss.maxkeyup); - case PARAM_WAIT: return CAST(scc->kiss.waittime); - case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer); - case PARAM_TX: return CAST(scc->kiss.tx_inhibit); - default: return NO_SUCH_PARAM; - } - -} - -#undef CAST -#undef SVAL - -/* ******************************************************************* */ -/* * Send calibration pattern * */ -/* ******************************************************************* */ - -static void scc_stop_calibrate(unsigned long channel) -{ - struct scc_channel *scc = (struct scc_channel *) channel; - unsigned long flags; - - save_flags(flags); - cli(); - - del_timer(&scc->tx_wdog); - scc_key_trx(scc, TX_OFF); - wr(scc, R6, 0); - wr(scc, R7, FLAG); - Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ - Outb(scc->ctrl,RES_EXT_INT); - - scc_unlock_dev(scc); - - restore_flags(flags); -} - - -static void -scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - scc_lock_dev(scc); - scc_discard_buffers(scc); - - del_timer(&scc->tx_wdog); - - scc->tx_wdog.data = (unsigned long) scc; - scc->tx_wdog.function = scc_stop_calibrate; - scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup; - add_timer(&scc->tx_wdog); - - wr(scc, R6, 0); - wr(scc, R7, pattern); - - /* - * Don't know if this works. - * Damn, where is my Z8530 programming manual...? - */ - - Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ - Outb(scc->ctrl,RES_EXT_INT); - - scc_key_trx(scc, TX_ON); - - restore_flags(flags); -} - -/* ******************************************************************* */ -/* * Init channel structures, special HW, etc... * */ -/* ******************************************************************* */ - -/* - * Reset the Z8530s and setup special hardware - */ - -static void z8530_init(void) -{ - struct scc_channel *scc; - int chip, k; - unsigned long flags; - char *flag; - - - printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2); - - flag=" "; - for (k = 0; k < 16; k++) - if (Ivec[k].used) - { - printk("%s%d", flag, k); - flag=","; - } - printk("\n"); - - - /* reset and pre-init all chips in the system */ - for (chip = 0; chip < Nchips; chip++) - { - scc=&SCC_Info[2*chip]; - if (!scc->ctrl) continue; - - /* Special SCC cards */ - - if(scc->brand & EAGLE) /* this is an EAGLE card */ - Outb(scc->special,0x08); /* enable interrupt on the board */ - - if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/PRIMUS card */ - Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */ - - - /* Reset and pre-init Z8530 */ - - save_flags(flags); - cli(); - - Outb(scc->ctrl, 0); - OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */ - udelay(100); /* give it 'a bit' more time than required */ - wr(scc, R2, chip*16); /* interrupt vector */ - wr(scc, R9, VIS); /* vector includes status */ - - restore_flags(flags); - } - - - Driver_Initialized = 1; -} - -/* - * Allocate device structure, err, instance, and register driver - */ - -static int scc_net_setup(struct scc_channel *scc, unsigned char *name) -{ - unsigned char *buf; - struct device *dev; - - if (dev_get(name) != NULL) - { - printk(KERN_INFO "Z8530drv: device %s already exists.\n", name); - return -EEXIST; - } - - if ((scc->dev = (struct device *) kmalloc(sizeof(struct device), GFP_KERNEL)) == NULL) - return -ENOMEM; - - dev = scc->dev; - memset(dev, 0, sizeof(struct device)); - - buf = (unsigned char *) kmalloc(10, GFP_KERNEL); - strcpy(buf, name); - - dev->priv = (void *) scc; - dev->name = buf; - dev->init = scc_net_init; - - if (register_netdev(dev) != 0) - { - kfree(dev); - return -EIO; - } - - return 0; -} - - - -/* ******************************************************************** */ -/* * Network driver methods * */ -/* ******************************************************************** */ - -static unsigned char ax25_bcast[AX25_ADDR_LEN] = -{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static unsigned char ax25_nocall[AX25_ADDR_LEN] = -{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - -/* ----> Initialize device <----- */ - -static int scc_net_init(struct device *dev) -{ - dev_init_buffers(dev); - - dev->tx_queue_len = 16; /* should be enough... */ - - dev->open = scc_net_open; - dev->stop = scc_net_close; - - dev->hard_start_xmit = scc_net_tx; - dev->hard_header = scc_net_header; - dev->rebuild_header = ax25_rebuild_header; - dev->set_mac_address = scc_net_set_mac_address; - dev->get_stats = scc_net_get_stats; - dev->do_ioctl = scc_net_ioctl; - - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); - - dev->flags = 0; - - dev->type = ARPHRD_AX25; - dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; - dev->mtu = AX25_DEF_PACLEN; - dev->addr_len = AX25_ADDR_LEN; - - return 0; -} - -/* ----> open network device <---- */ - -static int scc_net_open(struct device *dev) -{ - struct scc_channel *scc = (struct scc_channel *) dev->priv; - - if (scc == NULL || scc->magic != SCC_MAGIC) - return -ENODEV; - - if (!scc->init) - return -EINVAL; - - MOD_INC_USE_COUNT; - - scc->tx_buff = NULL; - skb_queue_head_init(&scc->tx_queue); - - init_channel(scc); - - dev->tbusy = 0; - dev->start = 1; - - return 0; -} - -/* ----> close network device <---- */ - -static int scc_net_close(struct device *dev) -{ - struct scc_channel *scc = (struct scc_channel *) dev->priv; - unsigned long flags; - - if (scc == NULL || scc->magic != SCC_MAGIC) - return -ENODEV; - - MOD_DEC_USE_COUNT; - - save_flags(flags); - cli(); - - Outb(scc->ctrl,0); /* Make sure pointer is written */ - wr(scc,R1,0); /* disable interrupts */ - wr(scc,R3,0); - - del_timer(&scc->tx_t); - del_timer(&scc->tx_wdog); - - restore_flags(flags); - - scc_discard_buffers(scc); - - dev->tbusy = 1; - dev->start = 0; - - return 0; -} - -/* ----> receive frame, called from scc_rxint() <---- */ - -static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) -{ - if (skb->len == 0) - { - kfree_skb(skb, FREE_READ); - return; - } - - scc->dev_stat.rx_packets++; - - skb->dev = scc->dev; - skb->protocol = htons(ETH_P_AX25); - skb->mac.raw = skb->data; - - netif_rx(skb); - return; -} - -/* ----> transmit frame <---- */ - -static int scc_net_tx(struct sk_buff *skb, struct device *dev) -{ - struct scc_channel *scc = (struct scc_channel *) dev->priv; - unsigned long flags; - char kisscmd; - - if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy) - { - dev_kfree_skb(skb, FREE_WRITE); - return 0; - } - - if (skb->len > scc->stat.bufsize || skb->len < 2) - { - scc->dev_stat.tx_dropped++; /* bogus frame */ - dev_kfree_skb(skb, FREE_WRITE); - return 0; - } - - scc->dev_stat.tx_packets++; - scc->stat.txframes++; - - kisscmd = *skb->data & 0x1f; - skb_pull(skb, 1); - - if (kisscmd) - { - scc_set_param(scc, kisscmd, *skb->data); - dev_kfree_skb(skb, FREE_WRITE); - return 0; - } - - save_flags(flags); - cli(); - - if (skb_queue_len(&scc->tx_queue) >= MAXQUEUE-1) - { - struct sk_buff *skb_del; - skb_del = __skb_dequeue(&scc->tx_queue); - dev_kfree_skb(skb_del, FREE_WRITE); - } - __skb_queue_tail(&scc->tx_queue, skb); - - dev->trans_start = jiffies; - - /* - * Start transmission if the trx state is idle or - * t_idle hasn't expired yet. Use dwait/persistance/slottime - * algorithm for normal halfduplex operation. - */ - - if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) - { - scc->stat.tx_state = TXS_BUSY; - if (scc->kiss.fulldup == KISS_DUPLEX_HALF) - scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime); - else - scc_start_tx_timer(scc, t_dwait, 0); - } - - restore_flags(flags); - - return 0; -} - -/* ----> ioctl functions <---- */ - -/* - * SIOCSCCCFG - configure driver arg: (struct scc_hw_config *) arg - * SIOCSCCINI - initialize driver arg: --- - * SIOCSCCCHANINI - initialize channel arg: (struct scc_modem *) arg - * SIOCSCCSMEM - set memory arg: (struct scc_mem_config *) arg - * SIOCSCCGKISS - get level 1 parameter arg: (struct scc_kiss_cmd *) arg - * SIOCSCCSKISS - set level 1 parameter arg: (struct scc_kiss_cmd *) arg - * SIOCSCCGSTAT - get driver status arg: (struct scc_stat *) arg - * SIOCSCCCAL - send calib. pattern arg: (struct scc_calibrate *) arg - */ - -static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd) -{ - struct scc_kiss_cmd kiss_cmd; - struct scc_mem_config memcfg; - struct scc_hw_config hwcfg; - struct scc_calibrate cal; - int chan; - unsigned char device_name[10]; - void *arg; - struct scc_channel *scc; - - scc = (struct scc_channel *) dev->priv; - if (scc == NULL || scc->magic != SCC_MAGIC) - return -EINVAL; - - arg = (void *) ifr->ifr_data; - - if (!Driver_Initialized) - { - if (cmd == SIOCSCCCFG) - { - int found = 1; - - if (!suser()) return -EPERM; - if (!arg) return -EFAULT; - - if (Nchips >= MAXSCC) - return -EINVAL; - - if (copy_from_user(&hwcfg, arg, sizeof(hwcfg))) - return -EFAULT; - - if (hwcfg.irq == 2) hwcfg.irq = 9; - - if (!Ivec[hwcfg.irq].used && hwcfg.irq) - { - if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL)) - printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq); - else - Ivec[hwcfg.irq].used = 1; - } - - if (hwcfg.vector_latch) - Vector_Latch = hwcfg.vector_latch; - - if (hwcfg.clock == 0) - hwcfg.clock = DEFAULT_CLOCK; - -#ifndef DONT_CHECK - disable_irq(hwcfg.irq); - - check_region(scc->ctrl, 1); - Outb(hwcfg.ctrl_a, 0); - udelay(5); - OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */ - udelay(5); - - if (InReg(hwcfg.ctrl_a,R13) != 0x55) - found = 0; - - enable_irq(hwcfg.irq); -#endif - - if (found) - { - SCC_Info[2*Nchips ].ctrl = hwcfg.ctrl_a; - SCC_Info[2*Nchips ].data = hwcfg.data_a; - SCC_Info[2*Nchips ].irq = hwcfg.irq; - SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b; - SCC_Info[2*Nchips+1].data = hwcfg.data_b; - SCC_Info[2*Nchips+1].irq = hwcfg.irq; - - SCC_ctrl[Nchips].chan_A = hwcfg.ctrl_a; - SCC_ctrl[Nchips].chan_B = hwcfg.ctrl_b; - SCC_ctrl[Nchips].irq = hwcfg.irq; - } - - - for (chan = 0; chan < 2; chan++) - { - sprintf(device_name, "%s%i", SCC_DriverName, 2*Nchips+chan); - - SCC_Info[2*Nchips+chan].special = hwcfg.special; - SCC_Info[2*Nchips+chan].clock = hwcfg.clock; - SCC_Info[2*Nchips+chan].brand = hwcfg.brand; - SCC_Info[2*Nchips+chan].option = hwcfg.option; - SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc; - -#ifdef DONT_CHECK - printk(KERN_INFO "%s: data port = 0x%3.3x control port = 0x%3.3x\n", - device_name, - SCC_Info[2*Nchips+chan].data, - SCC_Info[2*Nchips+chan].ctrl); - -#else - printk(KERN_INFO "%s: data port = 0x%3.3lx control port = 0x%3.3lx -- %s\n", - device_name, - chan? hwcfg.data_b : hwcfg.data_a, - chan? hwcfg.ctrl_b : hwcfg.ctrl_a, - found? "found" : "missing"); -#endif - - if (found) - { - request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl"); - request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data"); - if (Nchips+chan != 0) - scc_net_setup(&SCC_Info[2*Nchips+chan], device_name); - } - } - - if (found) Nchips++; - - return 0; - } - - if (cmd == SIOCSCCINI) - { - if (!suser()) - return -EPERM; - - if (Nchips == 0) - return -EINVAL; - - z8530_init(); - return 0; - } - - return -EINVAL; /* confuse the user */ - } - - if (!scc->init) - { - if (cmd == SIOCSCCCHANINI) - { - if (!suser()) return -EPERM; - if (!arg) return -EINVAL; - - scc->stat.bufsize = BUFSIZE; - - if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem))) - return -EINVAL; - - /* default KISS Params */ - - if (scc->modem.speed < 4800) - { - scc->kiss.txdelay = 36; /* 360 ms */ - scc->kiss.persist = 42; /* 25% persistence */ /* was 25 */ - scc->kiss.slottime = 16; /* 160 ms */ - scc->kiss.tailtime = 4; /* minimal reasonable value */ - scc->kiss.fulldup = 0; /* CSMA */ - scc->kiss.waittime = 50; /* 500 ms */ - scc->kiss.maxkeyup = 10; /* 10 s */ - scc->kiss.mintime = 3; /* 3 s */ - scc->kiss.idletime = 30; /* 30 s */ - scc->kiss.maxdefer = 120; /* 2 min */ - scc->kiss.softdcd = 0; /* hardware dcd */ - } else { - scc->kiss.txdelay = 10; /* 100 ms */ - scc->kiss.persist = 64; /* 25% persistence */ /* was 25 */ - scc->kiss.slottime = 8; /* 160 ms */ - scc->kiss.tailtime = 1; /* minimal reasonable value */ - scc->kiss.fulldup = 0; /* CSMA */ - scc->kiss.waittime = 50; /* 500 ms */ - scc->kiss.maxkeyup = 7; /* 7 s */ - scc->kiss.mintime = 3; /* 3 s */ - scc->kiss.idletime = 30; /* 30 s */ - scc->kiss.maxdefer = 120; /* 2 min */ - scc->kiss.softdcd = 0; /* hardware dcd */ - } - - scc->tx_buff = NULL; - skb_queue_head_init(&scc->tx_queue); - scc->init = 1; - - return 0; - } - - return -EINVAL; - } - - switch(cmd) - { - case SIOCSCCRESERVED: - return -ENOIOCTLCMD; - - case SIOCSCCSMEM: - if (!suser()) return -EPERM; - if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) - return -EINVAL; - scc->stat.bufsize = memcfg.bufsize; - return 0; - - case SIOCSCCGSTAT: - if (!arg || copy_to_user(arg, &scc->stat, sizeof(scc->stat))) - return -EINVAL; - return 0; - - case SIOCSCCGKISS: - if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd))) - return -EINVAL; - kiss_cmd.param = scc_get_param(scc, kiss_cmd.command); - if (copy_to_user(arg, &kiss_cmd, sizeof(kiss_cmd))) - return -EINVAL; - return 0; - - case SIOCSCCSKISS: - if (!suser()) return -EPERM; - if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd))) - return -EINVAL; - return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param); - - case SIOCSCCCAL: - if (!suser()) return -EPERM; - if (!arg || copy_from_user(&cal, arg, sizeof(cal))) - return -EINVAL; - - scc_start_calibrate(scc, cal.time, cal.pattern); - return 0; - - default: - return -ENOIOCTLCMD; - - } - - return -EINVAL; -} - -/* ----> set interface callsign <---- */ - -static int scc_net_set_mac_address(struct device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *) addr; - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - return 0; -} - -/* ----> "hard" header <---- */ - -static int scc_net_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - return ax25_encapsulate(skb, dev, type, daddr, saddr, len); -} - -/* ----> get statistics <---- */ - -static struct net_device_stats *scc_net_get_stats(struct device *dev) -{ - struct scc_channel *scc = (struct scc_channel *) dev->priv; - - if (scc == NULL || scc->magic != SCC_MAGIC) - return NULL; - - scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over; - scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under; - scc->dev_stat.rx_fifo_errors = scc->stat.rx_over; - scc->dev_stat.tx_fifo_errors = scc->stat.tx_under; - - return &scc->dev_stat; -} - -/* ******************************************************************** */ -/* * dump statistics to /proc/net/z8530drv * */ -/* ******************************************************************** */ - - -static int scc_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - struct scc_channel *scc; - struct scc_kiss *kiss; - struct scc_stat *stat; - int len = 0; - off_t pos = 0; - off_t begin = 0; - int k; - - len += sprintf(buffer, "z8530drv-"VERSION"\n"); - - if (!Driver_Initialized) - { - len += sprintf(buffer+len, "not initialized\n"); - goto done; - } - - if (!Nchips) - { - len += sprintf(buffer+len, "chips missing\n"); - goto done; - } - - for (k = 0; k < Nchips*2; k++) - { - scc = &SCC_Info[k]; - stat = &scc->stat; - kiss = &scc->kiss; - - if (!scc->init) - continue; - - /* dev data ctrl irq clock brand enh vector special option - * baud nrz clocksrc softdcd bufsize - * rxints txints exints spints - * rcvd rxerrs over / xmit txerrs under / nospace bufsize - * txd pers slot tail ful wait min maxk idl defr txof grp - * W ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## - * R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ## - */ - - len += sprintf(buffer+len, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n", - scc->dev->name, - scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand, - scc->enhanced, Vector_Latch, scc->special, - scc->option); - len += sprintf(buffer+len, "\t%lu %d %d %d %d\n", - scc->modem.speed, scc->modem.nrz, - scc->modem.clocksrc, kiss->softdcd, - stat->bufsize); - len += sprintf(buffer+len, "\t%lu %lu %lu %lu\n", - stat->rxints, stat->txints, stat->exints, stat->spints); - len += sprintf(buffer+len, "\t%lu %lu %d / %lu %lu %d / %d %d\n", - stat->rxframes, stat->rxerrs, stat->rx_over, - stat->txframes, stat->txerrs, stat->tx_under, - stat->nospace, stat->tx_state); - -#define K(x) kiss->x - len += sprintf(buffer+len, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n", - K(txdelay), K(persist), K(slottime), K(tailtime), - K(fulldup), K(waittime), K(mintime), K(maxkeyup), - K(idletime), K(maxdefer), K(tx_inhibit), K(group)); -#undef K -#ifdef SCC_DEBUG - { - int reg; - - len += sprintf(buffer+len, "\tW "); - for (reg = 0; reg < 16; reg++) - len += sprintf(buffer+len, "%2.2x ", scc->wreg[reg]); - len += sprintf(buffer+len, "\n"); - - len += sprintf(buffer+len, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1)); - for (reg = 3; reg < 8; reg++) - len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg)); - len += sprintf(buffer+len, "XX "); - for (reg = 9; reg < 16; reg++) - len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg)); - len += sprintf(buffer+len, "\n"); - } -#endif - len += sprintf(buffer+len, "\n"); - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; - } - -done: - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) len = length; - - return len; -} - -#ifdef CONFIG_PROC_FS - -struct proc_dir_entry scc_proc_dir_entry = -{ - PROC_NET_Z8530, 8, "z8530drv", S_IFREG | S_IRUGO, 1, 0, 0, 0, - &proc_net_inode_operations, scc_net_get_info -}; - -#define scc_net_procfs_init() proc_net_register(&scc_proc_dir_entry); -#define scc_net_procfs_remove() proc_net_unregister(PROC_NET_Z8530); -#else -#define scc_net_procfs_init() -#define scc_net_procfs_remove() -#endif - - -/* ******************************************************************** */ -/* * Init SCC driver * */ -/* ******************************************************************** */ - -__initfunc(int scc_init (void)) -{ - int chip, chan, k, result; - char devname[10]; - - printk(KERN_INFO BANNER); - - memset(&SCC_ctrl, 0, sizeof(SCC_ctrl)); - - /* pre-init channel information */ - - for (chip = 0; chip < MAXSCC; chip++) - { - memset((char *) &SCC_Info[2*chip ], 0, sizeof(struct scc_channel)); - memset((char *) &SCC_Info[2*chip+1], 0, sizeof(struct scc_channel)); - - for (chan = 0; chan < 2; chan++) - SCC_Info[2*chip+chan].magic = SCC_MAGIC; - } - - for (k = 0; k < 16; k++) Ivec[k].used = 0; - - sprintf(devname,"%s0", SCC_DriverName); - - result = scc_net_setup(SCC_Info, devname); - if (result) - { - printk(KERN_ERR "z8530drv: cannot initialize module\n"); - return result; - } - - scc_net_procfs_init(); - - return 0; -} - -/* ******************************************************************** */ -/* * Module support * */ -/* ******************************************************************** */ - - -#ifdef MODULE -int init_module(void) -{ - int result = 0; - - result = scc_init(); - - if (result == 0) - printk(KERN_INFO "Copyright 1993,1997 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n"); - - return result; -} - -void cleanup_module(void) -{ - long flags; - io_port ctrl; - int k; - struct scc_channel *scc; - - save_flags(flags); - cli(); - - if (Nchips == 0) - unregister_netdev(SCC_Info[0].dev); - - for (k = 0; k < Nchips; k++) - if ( (ctrl = SCC_ctrl[k].chan_A) ) - { - Outb(ctrl, 0); - OutReg(ctrl,R9,FHWRES); /* force hardware reset */ - udelay(50); - } - - for (k = 0; k < Nchips*2; k++) - { - scc = &SCC_Info[k]; - if (scc) - { - release_region(scc->ctrl, 1); - release_region(scc->data, 1); - if (scc->dev) - { - unregister_netdev(scc->dev); - kfree(scc->dev); - } - } - } - - for (k=0; k < 16 ; k++) - if (Ivec[k].used) free_irq(k, NULL); - - restore_flags(flags); - - scc_net_procfs_remove(); -} -#endif diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/Makefile linux/drivers/net/soundmodem/Makefile --- v2.1.70/linux/drivers/net/soundmodem/Makefile Thu Sep 4 17:07:30 1997 +++ linux/drivers/net/soundmodem/Makefile Wed Dec 31 16:00:00 1969 @@ -1,60 +0,0 @@ -# -# Makefile for the soundmodem device driver. -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now inherited from the -# parent makes.. -# - -O_TARGET := soundmodem.o - -O_OBJS := sm.o -ifeq ($(CONFIG_SOUNDMODEM_SBC),y) -O_OBJS += sm_sbc.o -endif -ifeq ($(CONFIG_SOUNDMODEM_WSS),y) -O_OBJS += sm_wss.o -endif -ifeq ($(CONFIG_SOUNDMODEM_AFSK1200),y) -O_OBJS += sm_afsk1200.o -endif -ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_7),y) -O_OBJS += sm_afsk2400_7.o -endif -ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_8),y) -O_OBJS += sm_afsk2400_8.o -endif -ifeq ($(CONFIG_SOUNDMODEM_AFSK2666),y) -O_OBJS += sm_afsk2666.o -endif -ifeq ($(CONFIG_SOUNDMODEM_HAPN4800),y) -O_OBJS += sm_hapn4800.o -endif -ifeq ($(CONFIG_SOUNDMODEM_PSK4800),y) -O_OBJS += sm_psk4800.o -endif -ifeq ($(CONFIG_SOUNDMODEM_FSK9600),y) -O_OBJS += sm_fsk9600.o -endif - -M_OBJS := $(O_TARGET) - -all: all_targets -.PHONY: all - -gentbl: gentbl.c - $(HOSTCC) -Wall $< -o $@ -lm - -TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2400_8.h -TBLHDR += sm_tbl_afsk2666.h sm_tbl_psk4800.h -TBLHDR += sm_tbl_hapn4800.h sm_tbl_fsk9600.h - -$(TBLHDR): gentbl - ./gentbl - -fastdep: $(TBLHDR) - -include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/gentbl.c linux/drivers/net/soundmodem/gentbl.c --- v2.1.70/linux/drivers/net/soundmodem/gentbl.c Mon Aug 11 14:47:04 1997 +++ linux/drivers/net/soundmodem/gentbl.c Wed Dec 31 16:00:00 1969 @@ -1,676 +0,0 @@ -/*****************************************************************************/ - -/* - * gentbl.c -- soundcard radio modem driver table generator. - * - * 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. - * - */ - -#include -#include -#include - -/* -------------------------------------------------------------------- */ - -static void gentbl_offscostab(FILE *f, unsigned int nbits) -{ - int i; - - fprintf(f, "\n/*\n * small cosine table in U8 format\n */\n" - "#define OFFSCOSTABBITS %u\n" - "#define OFFSCOSTABSIZE (1<>%d)&0x%x]\n\n", - 16-nbits, (1<>%d)&0x%x]\n" - "#define SIN(x) COS((x)+0xc000)\n\n", 16-nbits, - (1< max) - max = s; - if (s < min) - min = s; - fprintf(f, "%4d", (int)(128+127*s)); - if (i < 3 || j < 255) - fprintf(f, ",%s", (j & 7) == 7 - ? "\n\t" : ""); - } - } - fprintf(stderr, "fsk9600: txfilt4: min = %f; max = %f\n", min, max); - fprintf(f, "\n};\n\n"); - min = max = 0; - memset(c, 0, sizeof(c)); -#if 0 - memcpy(c+2, fsk96_tx_coeff_5, sizeof(fsk96_tx_coeff_5)); -#else - for (i = 0; i < 36; i++) - c[4+i] = sinc(1.2*((i-17.5)/5.0))*hamming(i/35.0)/4.5; -#endif - fprintf(f, "static unsigned char fsk96_txfilt_5[] = {\n\t"); - for (i = 0; i < 5; i++) { - for (j = 0; j < 256; j++) { - for (k = 1, s = 0, l = i; k < 256; k <<= 1) { - if (j & k) { - for (m = 0; m < 5; m++, l++) - s += c[l]; - } else { - for (m = 0; m < 5; m++, l++) - s -= c[l]; - } - } - s *= 0.75; - if (s > max) - max = s; - if (s < min) - min = s; - fprintf(f, "%4d", (int)(128+127*s)); - if (i < 4 || j < 255) - fprintf(f, ",%s", (j & 7) == 7 - ? "\n\t" : ""); - } - } - fprintf(stderr, "fsk9600: txfilt5: min = %f; max = %f\n", min, max); - fprintf(f, "\n};\n\n"); -} - -/* -------------------------------------------------------------------- */ - -#define AFSK26_SAMPLERATE 16000 - -#define AFSK26_NUMCAR 2 -#define AFSK26_FIRSTCAR 2000 -#define AFSK26_MSK_LEN 6 -#define AFSK26_RXOVER 2 - -#define AFSK26_DEMCORRLEN (2*AFSK26_MSK_LEN) - -#define AFSK26_WINDOW(x) ((1-cos(2.0*M_PI*(x)))/2.0) - -#define AFSK26_AMPL(x) (((x)?1.0:0.7)) - -#undef AFSK26_AMPL -#define AFSK26_AMPL(x) 1 - -static void gentbl_afsk2666(FILE *f) -{ - int i, j, k, l, o, v, sumi, sumq; - float window[AFSK26_DEMCORRLEN*AFSK26_RXOVER]; - int cfreq[AFSK26_NUMCAR]; - - fprintf(f, "\n/*\n * afsk2666 specific tables\n */\n" - "#define AFSK26_DEMCORRLEN %d\n" - "#define AFSK26_SAMPLERATE %d\n\n", AFSK26_DEMCORRLEN, - AFSK26_SAMPLERATE); - fprintf(f, "static const unsigned int afsk26_carfreq[%d] = { ", - AFSK26_NUMCAR); - for (i = 0; i < AFSK26_NUMCAR; i++) { - cfreq[i] = 0x10000*AFSK26_FIRSTCAR/AFSK26_SAMPLERATE+ - 0x10000*i/AFSK26_MSK_LEN/2; - fprintf(f, "0x%x", cfreq[i]); - if (i < AFSK26_NUMCAR-1) - fprintf(f, ", "); - } - fprintf(f, " };\n\n"); - for (i = 0; i < AFSK26_DEMCORRLEN*AFSK26_RXOVER; i++) - window[i] = AFSK26_WINDOW(((float)i)/(AFSK26_DEMCORRLEN* - AFSK26_RXOVER)) * 127.0; - fprintf(f, "\nstatic const struct {\n\t" - "int i[%d];\n\tint q[%d];\n} afsk26_dem_tables[%d][%d] = {\n", - AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER, AFSK26_NUMCAR); - for (o = AFSK26_RXOVER-1; o >= 0; o--) { - fprintf(f, "\t{\n"); - for (i = 0; i < AFSK26_NUMCAR; i++) { - j = cfreq[i]; - fprintf(f, "\t\t{{ "); - for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumi = 0; l >= 0; - l--, k = (k+j)&0xffffu) { - sumi += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]* - cos(M_PI*k/32768.0)); - fprintf(f, "%6d%s", v, l ? ", " : " }, { "); - } - for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumq = 0; l >= 0; - l--, k = (k+j)&0xffffu) { - sumq += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]* - sin(M_PI*k/32768.0)); - fprintf(f, "%6d%s", v, l ? ", " : " }}"); - } - if (i < 1) - fprintf(f, ","); - fprintf(f, "\n#define AFSK26_DEM_SUM_I_%d_%d %d\n" - "#define AFSK26_DEM_SUM_Q_%d_%d %d\n", - AFSK26_RXOVER-1-o, i, sumi, AFSK26_RXOVER-1-o, i, sumq); - } - fprintf(f, "\t}%s\n", o ? "," : ""); - } - fprintf(f, "};\n\n"); -} - -/* -------------------------------------------------------------------- */ - -#define ATAN_TABLEN 1024 - -static void gentbl_atantab(FILE *f) -{ - int i; - short x; - - fprintf(f, "\n/*\n" - " * arctan table (indexed by i/q; should really be indexed by i/(i+q)\n" - " */\n""#define ATAN_TABLEN %d\n\n" - "static const unsigned short atan_tab[ATAN_TABLEN+2] = {", - ATAN_TABLEN); - for (i = 0; i <= ATAN_TABLEN; i++) { - if (!(i & 7)) - fprintf(f, "\n\t"); - x = atan(i / (float)ATAN_TABLEN) / M_PI * 0x8000; - fprintf(f, "%6d, ", x); - } - fprintf(f, "%6d\n};\n\n", x); - -} - -/* -------------------------------------------------------------------- */ - -#define PSK48_TXF_OVERSAMPLING 5 -#define PSK48_TXF_NUMSAMPLES 16 -#define PSK48_RXF_LEN 64 - -static const float psk48_tx_coeff[80] = { - -0.000379, -0.000640, -0.000000, 0.000772, - 0.000543, -0.000629, -0.001187, -0.000000, - 0.001634, 0.001183, -0.001382, -0.002603, - -0.000000, 0.003481, 0.002472, -0.002828, - -0.005215, -0.000000, 0.006705, 0.004678, - -0.005269, -0.009584, -0.000000, 0.012065, - 0.008360, -0.009375, -0.017028, -0.000000, - 0.021603, 0.015123, -0.017229, -0.032012, - -0.000000, 0.043774, 0.032544, -0.040365, - -0.084963, -0.000000, 0.201161, 0.374060, - 0.374060, 0.201161, -0.000000, -0.084963, - -0.040365, 0.032544, 0.043774, -0.000000, - -0.032012, -0.017229, 0.015123, 0.021603, - -0.000000, -0.017028, -0.009375, 0.008360, - 0.012065, -0.000000, -0.009584, -0.005269, - 0.004678, 0.006705, -0.000000, -0.005215, - -0.002828, 0.002472, 0.003481, -0.000000, - -0.002603, -0.001382, 0.001183, 0.001634, - -0.000000, -0.001187, -0.000629, 0.000543, - 0.000772, -0.000000, -0.000640, -0.000379 -}; - -static const float psk48_rx_coeff[PSK48_RXF_LEN] = { - -0.000219, 0.000360, 0.000873, 0.001080, - 0.000747, -0.000192, -0.001466, -0.002436, - -0.002328, -0.000699, 0.002101, 0.004809, - 0.005696, 0.003492, -0.001633, -0.007660, - -0.011316, -0.009627, -0.001780, 0.009712, - 0.019426, 0.021199, 0.011342, -0.008583, - -0.030955, -0.044093, -0.036634, -0.002651, - 0.054742, 0.123101, 0.184198, 0.220219, - 0.220219, 0.184198, 0.123101, 0.054742, - -0.002651, -0.036634, -0.044093, -0.030955, - -0.008583, 0.011342, 0.021199, 0.019426, - 0.009712, -0.001780, -0.009627, -0.011316, - -0.007660, -0.001633, 0.003492, 0.005696, - 0.004809, 0.002101, -0.000699, -0.002328, - -0.002436, -0.001466, -0.000192, 0.000747, - 0.001080, 0.000873, 0.000360, -0.000219 -}; - -static void gentbl_psk4800(FILE *f) -{ - int i, j, k; - short x; - - fprintf(f, "\n/*\n * psk4800 specific tables\n */\n" - "#define PSK48_TXF_OVERSAMPLING %d\n" - "#define PSK48_TXF_NUMSAMPLES %d\n\n" - "#define PSK48_SAMPLERATE 8000\n" - "#define PSK48_CAR_FREQ 2000\n" - "#define PSK48_PSK_LEN 5\n" - "#define PSK48_RXF_LEN %u\n" - "#define PSK48_PHASEINC (0x10000*PSK48_CAR_FREQ/PSK48_SAMPLERATE)\n" - "#define PSK48_SPHASEINC (0x10000/(2*PSK48_PSK_LEN))\n\n" - "static const short psk48_tx_table[PSK48_TXF_OVERSAMPLING*" - "PSK48_TXF_NUMSAMPLES*8*2] = {", - PSK48_TXF_OVERSAMPLING, PSK48_TXF_NUMSAMPLES, PSK48_RXF_LEN); - for (i = 0; i < PSK48_TXF_OVERSAMPLING; i++) { - for (j = 0; j < PSK48_TXF_NUMSAMPLES; j++) { - fprintf(f, "\n\t"); - for (k = 0; k < 8; k++) { - x = 32767.0 * cos(k*M_PI/4.0) * - psk48_tx_coeff[j * PSK48_TXF_OVERSAMPLING + i]; - fprintf(f, "%6d, ", x); - } - fprintf(f, "\n\t"); - for (k = 0; k < 8; k++) { - x = 32767.0 * sin(k*M_PI/4.0) * - psk48_tx_coeff[j * PSK48_TXF_OVERSAMPLING + i]; - fprintf(f, "%6d", x); - if (k != 7 || j != PSK48_TXF_NUMSAMPLES-1 || - i != PSK48_TXF_OVERSAMPLING-1) - fprintf(f, ", "); - } - } - } - fprintf(f, "\n};\n\n"); - - fprintf(f, "static const short psk48_rx_coeff[PSK48_RXF_LEN] = {\n\t"); - for (i = 0; i < PSK48_RXF_LEN; i++) { - fprintf(f, "%6d", (int)(psk48_rx_coeff[i]*32767.0)); - if (i < PSK48_RXF_LEN-1) - fprintf(f, ",%s", (i & 7) == 7 ? "\n\t" : ""); - } - fprintf(f, "\n};\n\n"); -} - -/* -------------------------------------------------------------------- */ - -static void gentbl_hapn4800(FILE *f) -{ - int i, j, k, l; - float s; - float c[40]; - float min, max; - - fprintf(f, "\n/*\n * hapn4800 specific tables\n */\n\n"); - /* - * firstly generate tables for the FM transmitter modulator - */ - min = max = 0; - memset(c, 0, sizeof(c)); - for (i = 0; i < 24; i++) - c[8+i] = sinc(1.5*((i-11.5)/8.0))*hamming(i/23.0)/2.4; - for (i = 0; i < 24; i++) - c[i] -= c[i+8]; - fprintf(f, "static unsigned char hapn48_txfilt_8[] = {\n\t"); - for (i = 0; i < 8; i++) { - for (j = 0; j < 16; j++) { - for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 8) { - if (j & k) - s += c[l]; - else - s -= c[l]; - } - if (s > max) - max = s; - if (s < min) - min = s; - fprintf(f, "%4d", (int)(128+127*s)); - if (i < 7 || j < 15) - fprintf(f, ",%s", (j & 7) == 7 - ? "\n\t" : ""); - } - } - fprintf(stderr, "hapn4800: txfilt8: min = %f; max = %f\n", min, max); - fprintf(f, "\n};\n\n"); - min = max = 0; - memset(c, 0, sizeof(c)); - for (i = 0; i < 30; i++) - c[10+i] = sinc(1.5*((i-14.5)/10.0))*hamming(i/29.0)/2.4; - for (i = 0; i < 30; i++) - c[i] -= c[i+10]; - fprintf(f, "static unsigned char hapn48_txfilt_10[] = {\n\t"); - for (i = 0; i < 10; i++) { - for (j = 0; j < 16; j++) { - for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 10) { - if (j & k) - s += c[l]; - else - s -= c[l]; - } - if (s > max) - max = s; - if (s < min) - min = s; - fprintf(f, "%4d", (int)(128+127*s)); - if (i < 9 || j < 15) - fprintf(f, ",%s", (j & 7) == 7 - ? "\n\t" : ""); - } - } - fprintf(stderr, "hapn4800: txfilt10: min = %f; max = %f\n", min, max); - fprintf(f, "\n};\n\n"); - /* - * secondly generate tables for the PM transmitter modulator - */ - min = max = 0; - memset(c, 0, sizeof(c)); - for (i = 0; i < 25; i++) - c[i] = sinc(1.4*((i-12.0)/8.0))*hamming(i/24.0)/6.3; - for (i = 0; i < 25; i++) - for (j = 1; j < 8; j++) - c[i] += c[i+j]; - fprintf(f, "static unsigned char hapn48_txfilt_pm8[] = {\n\t"); - for (i = 0; i < 8; i++) { - for (j = 0; j < 16; j++) { - for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 8) { - if (j & k) - s += c[l]; - else - s -= c[l]; - } - if (s > max) - max = s; - if (s < min) - min = s; - fprintf(f, "%4d", (int)(128+127*s)); - if (i < 7 || j < 15) - fprintf(f, ",%s", (j & 7) == 7 - ? "\n\t" : ""); - } - } - fprintf(stderr, "hapn4800: txfiltpm8: min = %f; max = %f\n", min, max); - fprintf(f, "\n};\n\n"); - min = max = 0; - memset(c, 0, sizeof(c)); - for (i = 0; i < 31; i++) - c[10+i] = sinc(1.4*((i-15.0)/10.0))*hamming(i/30.0)/7.9; - for (i = 0; i < 31; i++) - for (j = 1; j < 10; j++) - c[i] += c[i+j]; - fprintf(f, "static unsigned char hapn48_txfilt_pm10[] = {\n\t"); - for (i = 0; i < 10; i++) { - for (j = 0; j < 16; j++) { - for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 10) { - if (j & k) - s += c[l]; - else - s -= c[l]; - } - if (s > max) - max = s; - if (s < min) - min = s; - fprintf(f, "%4d", (int)(128+127*s)); - if (i < 9 || j < 15) - fprintf(f, ",%s", (j & 7) == 7 - ? "\n\t" : ""); - } - } - fprintf(stderr, "hapn4800: txfiltpm10: min = %f; max = %f\n", min, max); - fprintf(f, "\n};\n\n"); - -} - -/* -------------------------------------------------------------------- */ - -#define AFSK24_SAMPLERATE 16000 -#define AFSK24_CORRLEN 14 - -static void gentbl_afsk2400(FILE *f, float tcm3105clk) -{ - int i, sum, v; - - fprintf(f, "\n/*\n * afsk2400 specific tables (tcm3105 clk %7fHz)\n */\n" - "#define AFSK24_TX_FREQ_LO %d\n" - "#define AFSK24_TX_FREQ_HI %d\n" - "#define AFSK24_BITPLL_INC %d\n" - "#define AFSK24_SAMPLERATE %d\n\n", tcm3105clk, - (int)(tcm3105clk/3694.0), (int)(tcm3105clk/2015.0), - 0x10000*2400/AFSK24_SAMPLERATE, AFSK24_SAMPLERATE); - -#define ARGLO(x) 2.0*M_PI*(double)x*(tcm3105clk/3694.0)/(double)AFSK24_SAMPLERATE -#define ARGHI(x) 2.0*M_PI*(double)x*(tcm3105clk/2015.0)/(double)AFSK24_SAMPLERATE -#define WINDOW(x) hamming((float)(x)/(AFSK24_CORRLEN-1.0)) - - fprintf(f, "static const int afsk24_tx_lo_i[] = {\n\t"); - for(sum = i = 0; i < AFSK24_CORRLEN; i++) { - sum += (v = 127.0*cos(ARGLO(i))*WINDOW(i)); - fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); - } - fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_I %d\n\n" - "static const int afsk24_tx_lo_q[] = {\n\t", sum); - for(sum = i = 0; i < AFSK24_CORRLEN; i++) { - sum += (v = 127.0*sin(ARGLO(i))*WINDOW(i)); - fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); - } - fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %d\n\n" - "static const int afsk24_tx_hi_i[] = {\n\t", sum); - for(sum = i = 0; i < AFSK24_CORRLEN; i++) { - sum += (v = 127.0*cos(ARGHI(i))*WINDOW(i)); - fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); - } - fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %d\n\n" - "static const int afsk24_tx_hi_q[] = {\n\t", sum); - for(sum = i = 0; i < AFSK24_CORRLEN; i++) { - sum += (v = 127.0*sin(ARGHI(i))*WINDOW(i)); - fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); - } - fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %d\n\n", sum); -#undef ARGLO -#undef ARGHI -#undef WINDOW -} - -/* -------------------------------------------------------------------- */ - -static char *progname; - -static void gentbl_banner(FILE *f) -{ - fprintf(f, "/*\n * THIS FILE IS GENERATED AUTOMATICALLY BY %s, " - "DO NOT EDIT!\n */\n\n", progname); -} - -/* -------------------------------------------------------------------- */ - -void main(int argc, char *argv[]) -{ - FILE *f; - - progname = argv[0]; - if (!(f = fopen("sm_tbl_afsk1200.h", "w"))) - exit(1); - gentbl_banner(f); - gentbl_offscostab(f, 6); - gentbl_costab(f, 6); - gentbl_afsk1200(f); - fclose(f); - if (!(f = fopen("sm_tbl_afsk2666.h", "w"))) - exit(1); - gentbl_banner(f); - gentbl_offscostab(f, 6); - gentbl_costab(f, 6); - gentbl_afsk2666(f); - fclose(f); - if (!(f = fopen("sm_tbl_psk4800.h", "w"))) - exit(1); - gentbl_banner(f); - gentbl_psk4800(f); - gentbl_costab(f, 8); - gentbl_atantab(f); - fclose(f); - if (!(f = fopen("sm_tbl_hapn4800.h", "w"))) - exit(1); - gentbl_banner(f); - gentbl_hapn4800(f); - fclose(f); - if (!(f = fopen("sm_tbl_fsk9600.h", "w"))) - exit(1); - gentbl_banner(f); - gentbl_fsk9600(f); - fclose(f); - if (!(f = fopen("sm_tbl_afsk2400_8.h", "w"))) - exit(1); - gentbl_banner(f); - gentbl_offscostab(f, 6); - gentbl_costab(f, 6); - gentbl_afsk2400(f, 8000000); - fclose(f); - if (!(f = fopen("sm_tbl_afsk2400_7.h", "w"))) - exit(1); - gentbl_banner(f); - gentbl_offscostab(f, 6); - gentbl_costab(f, 6); - gentbl_afsk2400(f, 7372800); - fclose(f); - exit(0); -} - - -/* -------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm.c linux/drivers/net/soundmodem/sm.c --- v2.1.70/linux/drivers/net/soundmodem/sm.c Mon Aug 11 14:47:04 1997 +++ linux/drivers/net/soundmodem/sm.c Wed Dec 31 16:00:00 1969 @@ -1,898 +0,0 @@ -/*****************************************************************************/ - -/* - * sm.c -- soundcard 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. - * - * - * Command line options (insmod command line) - * - * mode mode string; eg. "wss:afsk1200" - * iobase base address of the soundcard; common values are 0x220 for sbc, - * 0x530 for wss - * irq interrupt number; common values are 7 or 5 for sbc, 11 for wss - * dma dma number; common values are 0 or 1 - * - * - * History: - * 0.1 21.09.96 Started - * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) - * 0.4 21.01.97 Separately compileable soundcard/modem modules - * 0.5 03.03.97 fixed LPT probing (check_lpt result was interpreted the wrong way round) - * 0.6 16.04.97 init code/data tagged - * 0.7 30.07.97 fixed halfduplex interrupt handlers/hotfix for CS423X - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sm.h" - -/* --------------------------------------------------------------------- */ - -/* - * 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 - -/* --------------------------------------------------------------------- */ - -/*static*/ const char sm_drvname[] = "soundmodem"; -static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1997 Thomas Sailer, HB9JNX/AE4WA\n" -KERN_INFO "soundmodem: version 0.7 compiled " __TIME__ " " __DATE__ "\n"; - -/* --------------------------------------------------------------------- */ - -/*static*/ const struct modem_tx_info *sm_modem_tx_table[] = { -#ifdef CONFIG_SOUNDMODEM_AFSK1200 - &sm_afsk1200_tx, -#endif /* CONFIG_SOUNDMODEM_AFSK1200 */ -#ifdef CONFIG_SOUNDMODEM_AFSK2400_7 - &sm_afsk2400_7_tx, -#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */ -#ifdef CONFIG_SOUNDMODEM_AFSK2400_8 - &sm_afsk2400_8_tx, -#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */ -#ifdef CONFIG_SOUNDMODEM_AFSK2666 - &sm_afsk2666_tx, -#endif /* CONFIG_SOUNDMODEM_AFSK2666 */ -#ifdef CONFIG_SOUNDMODEM_PSK4800 - &sm_psk4800_tx, -#endif /* CONFIG_SOUNDMODEM_PSK4800 */ -#ifdef CONFIG_SOUNDMODEM_HAPN4800 - &sm_hapn4800_8_tx, - &sm_hapn4800_10_tx, - &sm_hapn4800_pm8_tx, - &sm_hapn4800_pm10_tx, -#endif /* CONFIG_SOUNDMODEM_HAPN4800 */ -#ifdef CONFIG_SOUNDMODEM_FSK9600 - &sm_fsk9600_4_tx, - &sm_fsk9600_5_tx, -#endif /* CONFIG_SOUNDMODEM_FSK9600 */ - NULL -}; - -/*static*/ const struct modem_rx_info *sm_modem_rx_table[] = { -#ifdef CONFIG_SOUNDMODEM_AFSK1200 - &sm_afsk1200_rx, -#endif /* CONFIG_SOUNDMODEM_AFSK1200 */ -#ifdef CONFIG_SOUNDMODEM_AFSK2400_7 - &sm_afsk2400_7_rx, -#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */ -#ifdef CONFIG_SOUNDMODEM_AFSK2400_8 - &sm_afsk2400_8_rx, -#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */ -#ifdef CONFIG_SOUNDMODEM_AFSK2666 - &sm_afsk2666_rx, -#endif /* CONFIG_SOUNDMODEM_AFSK2666 */ -#ifdef CONFIG_SOUNDMODEM_PSK4800 - &sm_psk4800_rx, -#endif /* CONFIG_SOUNDMODEM_PSK4800 */ -#ifdef CONFIG_SOUNDMODEM_HAPN4800 - &sm_hapn4800_8_rx, - &sm_hapn4800_10_rx, - &sm_hapn4800_pm8_rx, - &sm_hapn4800_pm10_rx, -#endif /* CONFIG_SOUNDMODEM_HAPN4800 */ -#ifdef CONFIG_SOUNDMODEM_FSK9600 - &sm_fsk9600_4_rx, - &sm_fsk9600_5_rx, -#endif /* CONFIG_SOUNDMODEM_FSK9600 */ - NULL -}; - -static const struct hardware_info *sm_hardware_table[] = { -#ifdef CONFIG_SOUNDMODEM_SBC - &sm_hw_sbc, - &sm_hw_sbcfdx, -#endif /* CONFIG_SOUNDMODEM_SBC */ -#ifdef CONFIG_SOUNDMODEM_WSS - &sm_hw_wss, - &sm_hw_wssfdx, -#endif /* CONFIG_SOUNDMODEM_WSS */ - NULL -}; - -/* --------------------------------------------------------------------- */ - -#define NR_PORTS 4 - -/* --------------------------------------------------------------------- */ - -static struct device sm_device[NR_PORTS]; - -static struct { - char *mode; - int iobase, irq, dma, dma2, seriobase, pariobase, midiiobase; -} sm_ports[NR_PORTS] = { - { NULL, -1, 0, 0, 0, -1, -1, -1 }, -}; - -/* --------------------------------------------------------------------- */ - -#define UART_RBR(iobase) (iobase+0) -#define UART_THR(iobase) (iobase+0) -#define UART_IER(iobase) (iobase+1) -#define UART_IIR(iobase) (iobase+2) -#define UART_FCR(iobase) (iobase+2) -#define UART_LCR(iobase) (iobase+3) -#define UART_MCR(iobase) (iobase+4) -#define UART_LSR(iobase) (iobase+5) -#define UART_MSR(iobase) (iobase+6) -#define UART_SCR(iobase) (iobase+7) -#define UART_DLL(iobase) (iobase+0) -#define UART_DLM(iobase) (iobase+1) - -#define SER_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 LPT_EXTENT 3 - -#define MIDI_DATA(iobase) (iobase) -#define MIDI_STATUS(iobase) (iobase+1) -#define MIDI_READ_FULL 0x80 /* attention: negative logic!! */ -#define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */ - -#define MIDI_EXTENT 2 - -/* ---------------------------------------------------------------------- */ - -#define PARAM_TXDELAY 1 -#define PARAM_PERSIST 2 -#define PARAM_SLOTTIME 3 -#define PARAM_TXTAIL 4 -#define PARAM_FULLDUP 5 -#define PARAM_HARDWARE 6 -#define PARAM_RETURN 255 - -#define SP_SER 1 -#define SP_PAR 2 -#define SP_MIDI 4 - -/* --------------------------------------------------------------------- */ -/* - * ===================== port checking routines ======================== - */ - -/* - * returns 0 if ok and != 0 on error; - * the same behaviour as par96_check_lpt in baycom.c - */ - -/* - * returns 0 if ok and != 0 on error; - * the same behaviour as par96_check_lpt in baycom.c - */ - -static int check_lpt(unsigned int iobase) -{ - unsigned char b1,b2; - int i; - - 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; -} - -/* --------------------------------------------------------------------- */ - -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 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 }; - - if (iobase <= 0 || iobase > 0x1000-SER_EXTENT) - return c_uart_unknown; - if (check_region(iobase, SER_EXTENT)) - return c_uart_unknown; - b1 = inb(UART_MCR(iobase)); - outb(b1 | 0x10, UART_MCR(iobase)); /* loopback mode */ - b2 = inb(UART_MSR(iobase)); - outb(0x1a, UART_MCR(iobase)); - b3 = inb(UART_MSR(iobase)) & 0xf0; - outb(b1, UART_MCR(iobase)); /* restore old values */ - outb(b2, UART_MSR(iobase)); - if (b3 != 0x90) - return c_uart_unknown; - inb(UART_RBR(iobase)); - inb(UART_RBR(iobase)); - outb(0x01, UART_FCR(iobase)); /* enable FIFOs */ - u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3]; - if (u == c_uart_16450) { - outb(0x5a, UART_SCR(iobase)); - b1 = inb(UART_SCR(iobase)); - outb(0xa5, UART_SCR(iobase)); - b2 = inb(UART_SCR(iobase)); - if ((b1 != 0x5a) || (b2 != 0xa5)) - u = c_uart_8250; - } - return u; -} - -/* --------------------------------------------------------------------- */ - -static int check_midi(unsigned int iobase) -{ - unsigned long timeout; - unsigned long flags; - unsigned char b; - - if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT) - return 0; - if (check_region(iobase, MIDI_EXTENT)) - return 0; - timeout = jiffies + (HZ / 100); - while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) - if ((signed)(jiffies - timeout) > 0) - return 0; - save_flags(flags); - cli(); - outb(0xff, MIDI_DATA(iobase)); - b = inb(MIDI_STATUS(iobase)); - restore_flags(flags); - if (!(b & MIDI_WRITE_EMPTY)) - return 0; - while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) - if ((signed)(jiffies - timeout) > 0) - return 0; - return 1; -} - -/* --------------------------------------------------------------------- */ - -void sm_output_status(struct sm_state *sm) -{ - int invert_dcd = 0; - int invert_ptt = 0; - - int ptt = /*hdlcdrv_ptt(&sm->hdrv)*/(sm->dma.ptt_cnt > 0) ^ invert_ptt; - int dcd = (!!sm->hdrv.hdlcrx.dcd) ^ invert_dcd; - - if (sm->hdrv.ptt_out.flags & SP_SER) { - outb(dcd | (ptt << 1), UART_MCR(sm->hdrv.ptt_out.seriobase)); - outb(0x40 & (-ptt), UART_LCR(sm->hdrv.ptt_out.seriobase)); - } - if (sm->hdrv.ptt_out.flags & SP_PAR) { - outb(ptt | (dcd << 1), LPT_DATA(sm->hdrv.ptt_out.pariobase)); - } - if (sm->hdrv.ptt_out.flags & SP_MIDI && hdlcdrv_ptt(&sm->hdrv)) { - outb(0, MIDI_DATA(sm->hdrv.ptt_out.midiiobase)); - } -} - -/* --------------------------------------------------------------------- */ - -static void sm_output_open(struct sm_state *sm) -{ - enum uart u = c_uart_unknown; - - sm->hdrv.ptt_out.flags = 0; - if (sm->hdrv.ptt_out.seriobase > 0 && - sm->hdrv.ptt_out.seriobase <= 0x1000-SER_EXTENT && - ((u = check_uart(sm->hdrv.ptt_out.seriobase))) != c_uart_unknown) { - sm->hdrv.ptt_out.flags |= SP_SER; - request_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT, "sm ser ptt"); - outb(0, UART_IER(sm->hdrv.ptt_out.seriobase)); - /* 5 bits, 1 stop, no parity, no break, Div latch access */ - outb(0x80, UART_LCR(sm->hdrv.ptt_out.seriobase)); - outb(0, UART_DLM(sm->hdrv.ptt_out.seriobase)); - outb(1, UART_DLL(sm->hdrv.ptt_out.seriobase)); /* as fast as possible */ - /* LCR and MCR set by output_status */ - } - if (sm->hdrv.ptt_out.pariobase > 0 && - sm->hdrv.ptt_out.pariobase <= 0x1000-LPT_EXTENT && - !check_lpt(sm->hdrv.ptt_out.pariobase)) { - sm->hdrv.ptt_out.flags |= SP_PAR; - request_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT, "sm par ptt"); - } - if (sm->hdrv.ptt_out.midiiobase > 0 && - sm->hdrv.ptt_out.midiiobase <= 0x1000-MIDI_EXTENT && - check_midi(sm->hdrv.ptt_out.midiiobase)) { - sm->hdrv.ptt_out.flags |= SP_MIDI; - request_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT, - "sm midi ptt"); - } - sm_output_status(sm); - - printk(KERN_INFO "%s: ptt output:", sm_drvname); - if (sm->hdrv.ptt_out.flags & SP_SER) - printk(" serial interface at 0x%x, uart %s", sm->hdrv.ptt_out.seriobase, - uart_str[u]); - if (sm->hdrv.ptt_out.flags & SP_PAR) - printk(" parallel interface at 0x%x", sm->hdrv.ptt_out.pariobase); - if (sm->hdrv.ptt_out.flags & SP_MIDI) - printk(" mpu401 (midi) interface at 0x%x", sm->hdrv.ptt_out.midiiobase); - if (!sm->hdrv.ptt_out.flags) - printk(" none"); - printk("\n"); -} - -/* --------------------------------------------------------------------- */ - -static void sm_output_close(struct sm_state *sm) -{ - /* release regions used for PTT output */ - sm->hdrv.hdlctx.ptt = sm->hdrv.hdlctx.calibrate = 0; - sm_output_status(sm); - if (sm->hdrv.ptt_out.flags & SP_SER) - release_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT); - if (sm->hdrv.ptt_out.flags & SP_PAR) - release_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT); - if (sm->hdrv.ptt_out.flags & SP_MIDI) - release_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT); - sm->hdrv.ptt_out.flags = 0; -} - -/* --------------------------------------------------------------------- */ - -static int sm_open(struct device *dev); -static int sm_close(struct device *dev); -static int sm_ioctl(struct device *dev, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd); - -/* --------------------------------------------------------------------- */ - -static const struct hdlcdrv_ops sm_ops = { - sm_drvname, sm_drvinfo, sm_open, sm_close, sm_ioctl -}; - -/* --------------------------------------------------------------------- */ - -static int sm_open(struct device *dev) -{ - struct sm_state *sm; - int err; - - if (!dev || !dev->priv || - ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "sm_open: invalid device struct\n"); - return -EINVAL; - } - sm = (struct sm_state *)dev->priv; - - if (!sm->mode_tx || !sm->mode_rx || !sm->hwdrv || !sm->hwdrv->open) - return -ENODEV; - sm->hdrv.par.bitrate = sm->mode_rx->bitrate; - err = sm->hwdrv->open(dev, sm); - if (err) - return err; - sm_output_open(sm); - MOD_INC_USE_COUNT; - printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u dma2 %u\n", - sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name, - sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma, sm->hdrv.ptt_out.dma2); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int sm_close(struct device *dev) -{ - struct sm_state *sm; - int err = -ENODEV; - - if (!dev || !dev->priv || - ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "sm_close: invalid device struct\n"); - return -EINVAL; - } - sm = (struct sm_state *)dev->priv; - - - if (sm->hwdrv && sm->hwdrv->close) - err = sm->hwdrv && sm->hwdrv->close(dev, sm); - sm_output_close(sm); - MOD_DEC_USE_COUNT; - printk(KERN_INFO "%s: close %s at iobase 0x%lx irq %u dma %u\n", - sm_drvname, sm->hwdrv->hw_name, dev->base_addr, dev->irq, dev->dma); - return err; -} - -/* --------------------------------------------------------------------- */ - -static int sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, ':'); - const struct hardware_info **hwp = sm_hardware_table; - - if (!cp) - cp = mode; - else { - *cp++ = '\0'; - while (hwp && (*hwp) && (*hwp)->hw_name && strcmp((*hwp)->hw_name, mode)) - hwp++; - if (!hwp || !*hwp || !(*hwp)->hw_name) - return -EINVAL; - if ((*hwp)->loc_storage > sizeof(sm->hw)) { - printk(KERN_ERR "%s: insufficient storage for hw driver %s (%d)\n", - sm_drvname, (*hwp)->hw_name, (*hwp)->loc_storage); - return -EINVAL; - } - sm->hwdrv = *hwp; - } - if (!*cp) - return 0; - if (sm->hwdrv && sm->hwdrv->sethw) - return sm->hwdrv->sethw(dev, sm, cp); - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int sm_ioctl(struct device *dev, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct sm_state *sm; - struct sm_ioctl bi; - unsigned long flags; - unsigned int newdiagmode; - unsigned int newdiagflags; - char *cp; - const struct modem_tx_info **mtp = sm_modem_tx_table; - const struct modem_rx_info **mrp = sm_modem_rx_table; - const struct hardware_info **hwp = sm_hardware_table; - - if (!dev || !dev->priv || - ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "sm_ioctl: invalid device struct\n"); - return -EINVAL; - } - sm = (struct sm_state *)dev->priv; - - if (cmd != SIOCDEVPRIVATE) { - if (!sm->hwdrv || !sm->hwdrv->ioctl) - return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd); - return -ENOIOCTLCMD; - } - switch (hi->cmd) { - default: - if (sm->hwdrv && sm->hwdrv->ioctl) - return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd); - return -ENOIOCTLCMD; - - case HDLCDRVCTL_GETMODE: - cp = hi->data.modename; - if (sm->hwdrv && sm->hwdrv->hw_name) - cp += sprintf(cp, "%s:", sm->hwdrv->hw_name); - else - cp += sprintf(cp, ":"); - if (sm->mode_tx && sm->mode_tx->name) - cp += sprintf(cp, "%s", sm->mode_tx->name); - else - cp += sprintf(cp, ""); - if (!sm->mode_rx || !sm->mode_rx || - strcmp(sm->mode_rx->name, sm->mode_tx->name)) { - if (sm->mode_rx && sm->mode_rx->name) - cp += sprintf(cp, ",%s", sm->mode_rx->name); - else - cp += sprintf(cp, ","); - } - if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_SETMODE: - if (!suser() || dev->start) - return -EACCES; - hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; - return sethw(dev, sm, hi->data.modename); - - case HDLCDRVCTL_MODELIST: - cp = hi->data.modename; - while (*hwp) { - if ((*hwp)->hw_name) - cp += sprintf("%s:,", (*hwp)->hw_name); - hwp++; - } - while (*mtp) { - if ((*mtp)->name) - cp += sprintf(">%s,", (*mtp)->name); - mtp++; - } - while (*mrp) { - if ((*mrp)->name) - cp += sprintf("<%s,", (*mrp)->name); - mrp++; - } - cp[-1] = '\0'; - if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi))) - return -EFAULT; - return 0; - -#ifdef SM_DEBUG - case SMCTL_GETDEBUG: - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - bi.data.dbg.int_rate = sm->debug_vals.last_intcnt; - bi.data.dbg.mod_cycles = sm->debug_vals.mod_cyc; - bi.data.dbg.demod_cycles = sm->debug_vals.demod_cyc; - bi.data.dbg.dma_residue = sm->debug_vals.dma_residue; - sm->debug_vals.mod_cyc = sm->debug_vals.demod_cyc = - sm->debug_vals.dma_residue = 0; - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; -#endif /* SM_DEBUG */ - - case SMCTL_DIAGNOSE: - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - newdiagmode = bi.data.diag.mode; - newdiagflags = bi.data.diag.flags; - if (newdiagmode > SM_DIAGMODE_CONSTELLATION) - return -EINVAL; - bi.data.diag.mode = sm->diag.mode; - bi.data.diag.flags = sm->diag.flags; - bi.data.diag.samplesperbit = sm->mode_rx->sperbit; - if (sm->diag.mode != newdiagmode) { - save_flags(flags); - cli(); - sm->diag.ptr = -1; - sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID; - sm->diag.mode = newdiagmode; - restore_flags(flags); - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } - if (sm->diag.ptr < 0 || sm->diag.mode == SM_DIAGMODE_OFF) { - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } - if (bi.data.diag.datalen > DIAGDATALEN) - bi.data.diag.datalen = DIAGDATALEN; - if (sm->diag.ptr < bi.data.diag.datalen) { - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } - if (copy_to_user(bi.data.diag.data, sm->diag.data, - bi.data.diag.datalen * sizeof(short))) - return -EFAULT; - bi.data.diag.flags |= SM_DIAGFLAG_VALID; - save_flags(flags); - cli(); - sm->diag.ptr = -1; - sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID; - sm->diag.mode = newdiagmode; - restore_flags(flags); - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } -} - -/* --------------------------------------------------------------------- */ - -#ifdef __i386__ - -int sm_x86_capability = 0; - -__initfunc(static void i386_capability(void)) -{ - unsigned long flags; - unsigned long fl1; - union { - struct { - unsigned int ebx, edx, ecx; - } r; - unsigned char s[13]; - } id; - unsigned int eax; - - save_flags(flags); - flags |= 0x200000; - restore_flags(flags); - save_flags(flags); - fl1 = flags; - flags &= ~0x200000; - restore_flags(flags); - save_flags(flags); - if (!(fl1 & 0x200000) || (flags & 0x200000)) { - printk(KERN_WARNING "%s: cpu does not support CPUID\n", sm_drvname); - return; - } - __asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) : - "0" (0)); - id.s[12] = 0; - if (eax < 1) { - printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability " - "list\n", sm_drvname, id.s); - return; - } - printk(KERN_INFO "%s: cpu: vendor string %s ", sm_drvname, id.s); - __asm__ ("cpuid" : "=a" (eax), "=d" (sm_x86_capability) : "0" (1) : "ebx", "ecx"); - printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15, - eax & 15, sm_x86_capability); -} -#endif /* __i386__ */ - -/* --------------------------------------------------------------------- */ - -#ifdef MODULE -__initfunc(static int sm_init(void)) -#else /* MODULE */ -__initfunc(int sm_init(void)) -#endif /* MODULE */ -{ - int i, j, found = 0; - char set_hw = 1; - struct sm_state *sm; - char ifname[HDLCDRV_IFNAMELEN]; - - printk(sm_drvinfo); -#ifdef __i386__ - i386_capability(); -#endif /* __i386__ */ - /* - * register net devices - */ - for (i = 0; i < NR_PORTS; i++) { - struct device *dev = sm_device+i; - sprintf(ifname, "sm%d", i); - - if (!sm_ports[i].mode) - set_hw = 0; - if (!set_hw) - sm_ports[i].iobase = sm_ports[i].irq = 0; - j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), - ifname, sm_ports[i].iobase, - sm_ports[i].irq, sm_ports[i].dma); - if (!j) { - sm = (struct sm_state *)dev->priv; - sm->hdrv.ptt_out.dma2 = sm_ports[i].dma2; - sm->hdrv.ptt_out.seriobase = sm_ports[i].seriobase; - sm->hdrv.ptt_out.pariobase = sm_ports[i].pariobase; - sm->hdrv.ptt_out.midiiobase = sm_ports[i].midiiobase; - if (set_hw && sethw(dev, sm, sm_ports[i].mode)) - set_hw = 0; - found++; - } else { - printk(KERN_WARNING "%s: cannot register net device\n", - sm_drvname); - } - } - if (!found) - return -ENXIO; - return 0; -} - -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -/* - * command line settable parameters - */ -static char *mode = NULL; -static int iobase = -1; -static int irq = -1; -static int dma = -1; -static int dma2 = -1; -static int serio = 0; -static int pario = 0; -static int midiio = 0; - -#if LINUX_VERSION_CODE >= 0x20115 - -MODULE_PARM(mode, "s"); -MODULE_PARM_DESC(mode, "soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600"); -MODULE_PARM(iobase, "i"); -MODULE_PARM_DESC(iobase, "soundmodem base address"); -MODULE_PARM(irq, "i"); -MODULE_PARM_DESC(irq, "soundmodem interrupt"); -MODULE_PARM(dma, "i"); -MODULE_PARM_DESC(dma, "soundmodem dma channel"); -MODULE_PARM(dma2, "i"); -MODULE_PARM_DESC(dma2, "soundmodem 2nd dma channel; full duplex only"); -MODULE_PARM(serio, "i"); -MODULE_PARM_DESC(serio, "soundmodem PTT output on serial port"); -MODULE_PARM(pario, "i"); -MODULE_PARM_DESC(pario, "soundmodem PTT output on parallel port"); -MODULE_PARM(midiio, "i"); -MODULE_PARM_DESC(midiio, "soundmodem PTT output on midi port"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Soundcard amateur radio modem driver"); - -#endif - -__initfunc(int init_module(void)) -{ - if (mode) { - if (iobase == -1) - iobase = (!strncmp(mode, "sbc", 3)) ? 0x220 : 0x530; - if (irq == -1) - irq = (!strncmp(mode, "sbc", 3)) ? 5 : 11; - if (dma == -1) - dma = 1; - } - sm_ports[0].mode = mode; - sm_ports[0].iobase = iobase; - sm_ports[0].irq = irq; - sm_ports[0].dma = dma; - sm_ports[0].dma2 = dma2; - sm_ports[0].seriobase = serio; - sm_ports[0].pariobase = pario; - sm_ports[0].midiiobase = midiio; - sm_ports[1].mode = NULL; - - return sm_init(); -} - -/* --------------------------------------------------------------------- */ - -void cleanup_module(void) -{ - int i; - - printk(KERN_INFO "sm: cleanup_module called\n"); - - for(i = 0; i < NR_PORTS; i++) { - struct device *dev = sm_device+i; - struct sm_state *sm = (struct sm_state *)dev->priv; - - if (sm) { - if (sm->hdrv.magic != HDLCDRV_MAGIC) - printk(KERN_ERR "sm: invalid magic in " - "cleanup_module\n"); - else - hdlcdrv_unregister_hdlcdrv(dev); - } - } -} - -#else /* MODULE */ -/* --------------------------------------------------------------------- */ -/* - * format: sm=io,irq,dma[,dma2[,serio[,pario]]],mode - * mode: hw:modem - * hw: sbc, wss, wssfdx - * modem: afsk1200, fsk9600 - */ - -__initfunc(void sm_setup(char *str, int *ints)) -{ - int i; - - for (i = 0; (i < NR_PORTS) && (sm_ports[i].mode); i++); - if ((i >= NR_PORTS) || (ints[0] < 3)) { - printk(KERN_INFO "%s: too many or invalid interface " - "specifications\n", sm_drvname); - return; - } - sm_ports[i].mode = str; - sm_ports[i].iobase = ints[1]; - sm_ports[i].irq = ints[2]; - sm_ports[i].dma = ints[3]; - sm_ports[i].dma2 = (ints[0] >= 4) ? ints[4] : 0; - sm_ports[i].seriobase = (ints[0] >= 5) ? ints[5] : 0; - sm_ports[i].pariobase = (ints[0] >= 6) ? ints[6] : 0; - sm_ports[i].midiiobase = (ints[0] >= 7) ? ints[7] : 0; - if (i < NR_PORTS-1) - sm_ports[i+1].mode = NULL; -} - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm.h linux/drivers/net/soundmodem/sm.h --- v2.1.70/linux/drivers/net/soundmodem/sm.h Mon Jun 16 16:35:56 1997 +++ linux/drivers/net/soundmodem/sm.h Wed Dec 31 16:00:00 1969 @@ -1,382 +0,0 @@ -/*****************************************************************************/ - -/* - * sm.h -- soundcard radio modem driver internal header. - * - * 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. - * - */ - -#ifndef _SM_H -#define _SM_H - -/* ---------------------------------------------------------------------- */ - -#include -#include - -#define SM_DEBUG - -/* ---------------------------------------------------------------------- */ -/* - * Information that need to be kept for each board. - */ - -struct sm_state { - struct hdlcdrv_state hdrv; - - const struct modem_tx_info *mode_tx; - const struct modem_rx_info *mode_rx; - - const struct hardware_info *hwdrv; - - /* - * Hardware (soundcard) access routines state - */ - struct { - void *ibuf; - unsigned int ifragsz; - unsigned int ifragptr; - unsigned int i16bit; - void *obuf; - unsigned int ofragsz; - unsigned int ofragptr; - unsigned int o16bit; - int ptt_cnt; - } dma; - - union { - long hw[32/sizeof(long)]; - } hw; - - /* - * state of the modem code - */ - union { - long m[32/sizeof(long)]; - } m; - union { - long d[256/sizeof(long)]; - } d; - -#define DIAGDATALEN 64 - struct diag_data { - unsigned int mode; - unsigned int flags; - volatile int ptr; - short data[DIAGDATALEN]; - } diag; - - -#ifdef SM_DEBUG - struct debug_vals { - unsigned long last_jiffies; - unsigned cur_intcnt; - unsigned last_intcnt; - unsigned mod_cyc; - unsigned demod_cyc; - unsigned dma_residue; - } debug_vals; -#endif /* SM_DEBUG */ -}; - -/* ---------------------------------------------------------------------- */ -/* - * Mode definition structure - */ - -struct modem_tx_info { - const char *name; - unsigned int loc_storage; - int srate; - int bitrate; - void (*modulator_u8)(struct sm_state *, unsigned char *, unsigned int); - void (*modulator_s16)(struct sm_state *, short *, unsigned int); - void (*init)(struct sm_state *); -}; - -struct modem_rx_info { - const char *name; - unsigned int loc_storage; - int srate; - int bitrate; - unsigned int overlap; - unsigned int sperbit; - void (*demodulator_u8)(struct sm_state *, const unsigned char *, unsigned int); - void (*demodulator_s16)(struct sm_state *, const short *, unsigned int); - void (*init)(struct sm_state *); -}; - -/* ---------------------------------------------------------------------- */ -/* - * Soundcard driver definition structure - */ - -struct hardware_info { - char *hw_name; /* used for request_{region,irq,dma} */ - unsigned int loc_storage; - /* - * mode specific open/close - */ - int (*open)(struct device *, struct sm_state *); - int (*close)(struct device *, struct sm_state *); - int (*ioctl)(struct device *, struct sm_state *, struct ifreq *, - struct hdlcdrv_ioctl *, int); - int (*sethw)(struct device *, struct sm_state *, char *); -}; - -/* --------------------------------------------------------------------- */ - -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#define max(a, b) (((a) > (b)) ? (a) : (b)) - -/* --------------------------------------------------------------------- */ - -extern const char sm_drvname[]; -extern const char sm_drvinfo[]; - -/* --------------------------------------------------------------------- */ -/* - * ===================== diagnostics stuff =============================== - */ - -extern inline void diag_trigger(struct sm_state *sm) -{ - if (sm->diag.ptr < 0) - if (!(sm->diag.flags & SM_DIAGFLAG_DCDGATE) || sm->hdrv.hdlcrx.dcd) - sm->diag.ptr = 0; -} - -/* --------------------------------------------------------------------- */ - -#define SHRT_MAX ((short)(((unsigned short)(~0U))>>1)) -#define SHRT_MIN (-SHRT_MAX-1) - -extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod) -{ - int val; - - if ((sm->diag.mode != SM_DIAGMODE_INPUT && - sm->diag.mode != SM_DIAGMODE_DEMOD) || - sm->diag.ptr >= DIAGDATALEN || sm->diag.ptr < 0) - return; - val = (sm->diag.mode == SM_DIAGMODE_DEMOD) ? valdemod : valinp; - /* clip */ - if (val > SHRT_MAX) - val = SHRT_MAX; - if (val < SHRT_MIN) - val = SHRT_MIN; - sm->diag.data[sm->diag.ptr++] = val; -} - -/* --------------------------------------------------------------------- */ - -extern inline void diag_add_one(struct sm_state *sm, int val) -{ - if ((sm->diag.mode != SM_DIAGMODE_INPUT && - sm->diag.mode != SM_DIAGMODE_DEMOD) || - sm->diag.ptr >= DIAGDATALEN || sm->diag.ptr < 0) - return; - /* clip */ - if (val > SHRT_MAX) - val = SHRT_MAX; - if (val < SHRT_MIN) - val = SHRT_MIN; - sm->diag.data[sm->diag.ptr++] = val; -} - -/* --------------------------------------------------------------------- */ - -static inline void diag_add_constellation(struct sm_state *sm, int vali, int valq) -{ - if ((sm->diag.mode != SM_DIAGMODE_CONSTELLATION) || - sm->diag.ptr >= DIAGDATALEN-1 || sm->diag.ptr < 0) - return; - /* clip */ - if (vali > SHRT_MAX) - vali = SHRT_MAX; - if (vali < SHRT_MIN) - vali = SHRT_MIN; - if (valq > SHRT_MAX) - valq = SHRT_MAX; - if (valq < SHRT_MIN) - valq = SHRT_MIN; - sm->diag.data[sm->diag.ptr++] = vali; - sm->diag.data[sm->diag.ptr++] = valq; -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== utility functions =============================== - */ - -extern inline unsigned int hweight32(unsigned int w) - __attribute__ ((unused)); -extern inline unsigned int hweight16(unsigned short w) - __attribute__ ((unused)); -extern inline unsigned int hweight8(unsigned char w) - __attribute__ ((unused)); - -extern inline unsigned int hweight32(unsigned int w) -{ - unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); - res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); - return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); -} - -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); -} - -extern inline unsigned int gcd(unsigned int x, unsigned int y) - __attribute__ ((unused)); -extern inline unsigned int lcm(unsigned int x, unsigned int y) - __attribute__ ((unused)); - -extern inline unsigned int gcd(unsigned int x, unsigned int y) -{ - for (;;) { - if (!x) - return y; - if (!y) - return x; - if (x > y) - x %= y; - else - y %= x; - } -} - -extern inline unsigned int lcm(unsigned int x, unsigned int y) -{ - return x * y / gcd(x, y); -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== profiling ======================================= - */ - - -#ifdef __i386__ - -extern int sm_x86_capability; - -#define HAS_RDTSC (sm_x86_capability & 0x10) - -/* - * only do 32bit cycle counter arithmetic; we hope we won't overflow :-) - * in fact, overflowing modems would require over 2THz clock speeds :-) - */ - -#define time_exec(var,cmd) \ -({ \ - if (HAS_RDTSC) { \ - unsigned int cnt1, cnt2, cnt3; \ - __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \ - cmd; \ - __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \ - var = cnt2-cnt1; \ - } else { \ - cmd; \ - } \ -}) - -#else /* __i386__ */ - -#define time_exec(var,cmd) cmd - -#endif /* __i386__ */ - -/* --------------------------------------------------------------------- */ - -extern const struct modem_tx_info sm_afsk1200_tx; -extern const struct modem_tx_info sm_afsk2400_7_tx; -extern const struct modem_tx_info sm_afsk2400_8_tx; -extern const struct modem_tx_info sm_afsk2666_tx; -extern const struct modem_tx_info sm_psk4800_tx; -extern const struct modem_tx_info sm_hapn4800_8_tx; -extern const struct modem_tx_info sm_hapn4800_10_tx; -extern const struct modem_tx_info sm_hapn4800_pm8_tx; -extern const struct modem_tx_info sm_hapn4800_pm10_tx; -extern const struct modem_tx_info sm_fsk9600_4_tx; -extern const struct modem_tx_info sm_fsk9600_5_tx; - -extern const struct modem_rx_info sm_afsk1200_rx; -extern const struct modem_rx_info sm_afsk2400_7_rx; -extern const struct modem_rx_info sm_afsk2400_8_rx; -extern const struct modem_rx_info sm_afsk2666_rx; -extern const struct modem_rx_info sm_psk4800_rx; -extern const struct modem_rx_info sm_hapn4800_8_rx; -extern const struct modem_rx_info sm_hapn4800_10_rx; -extern const struct modem_rx_info sm_hapn4800_pm8_rx; -extern const struct modem_rx_info sm_hapn4800_pm10_rx; -extern const struct modem_rx_info sm_fsk9600_4_rx; -extern const struct modem_rx_info sm_fsk9600_5_rx; - -extern const struct hardware_info sm_hw_sbc; -extern const struct hardware_info sm_hw_sbcfdx; -extern const struct hardware_info sm_hw_wss; -extern const struct hardware_info sm_hw_wssfdx; - -extern const struct modem_tx_info *sm_modem_tx_table[]; -extern const struct modem_rx_info *sm_modem_rx_table[]; -extern const struct hardware_info *sm_hardware_table[]; - -/* --------------------------------------------------------------------- */ - -void sm_output_status(struct sm_state *sm); -/*void sm_output_open(struct sm_state *sm);*/ -/*void sm_output_close(struct sm_state *sm);*/ - -/* --------------------------------------------------------------------- */ - -extern void inline sm_int_freq(struct sm_state *sm) -{ -#ifdef SM_DEBUG - unsigned long cur_jiffies = jiffies; - /* - * measure the interrupt frequency - */ - sm->debug_vals.cur_intcnt++; - if ((cur_jiffies - sm->debug_vals.last_jiffies) >= HZ) { - sm->debug_vals.last_jiffies = cur_jiffies; - sm->debug_vals.last_intcnt = sm->debug_vals.cur_intcnt; - sm->debug_vals.cur_intcnt = 0; - } -#endif /* SM_DEBUG */ -} - -/* --------------------------------------------------------------------- */ -#endif /* _SM_H */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm_afsk1200.c linux/drivers/net/soundmodem/sm_afsk1200.c --- v2.1.70/linux/drivers/net/soundmodem/sm_afsk1200.c Mon Jun 16 16:35:56 1997 +++ linux/drivers/net/soundmodem/sm_afsk1200.c Wed Dec 31 16:00:00 1969 @@ -1,272 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_afsk1200.c -- soundcard radio modem driver, 1200 baud AFSK modem - * - * 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. - * - */ - -#include "sm.h" -#include "sm_tbl_afsk1200.h" - -/* --------------------------------------------------------------------- */ - -struct demod_state_afsk12 { - unsigned int shreg; - unsigned int bit_pll; - unsigned char last_sample; - unsigned int dcd_shreg; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned int dcd_time; - unsigned char last_rxbit; -}; - -struct mod_state_afsk12 { - unsigned int shreg; - unsigned char tx_bit; - unsigned int bit_pll; - unsigned int dds_inc; - unsigned int txphase; -}; - -/* --------------------------------------------------------------------- */ - -static const int dds_inc[2] = { - AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE, - AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE -}; - -static void modulator_1200_u8(struct sm_state *sm, unsigned char *buf, - unsigned int buflen) -{ - struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m); - - for (; buflen > 0; buflen--) { - if (!((st->txphase++) & 7)) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; - st->shreg >>= 1; - } - st->dds_inc = dds_inc[st->tx_bit & 1]; - *buf++ = OFFSCOS(st->bit_pll); - st->bit_pll += st->dds_inc; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_1200_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m); - - for (; buflen > 0; buflen--) { - if (!((st->txphase++) & 7)) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; - st->shreg >>= 1; - } - st->dds_inc = dds_inc[st->tx_bit & 1]; - *buf++ = COS(st->bit_pll); - st->bit_pll += st->dds_inc; - } -} - -/* --------------------------------------------------------------------- */ - -extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum) -{ - int sum = -0x80 * csum; - - sum += (st[0] * coeff[0]); - sum += (st[-1] * coeff[1]); - sum += (st[-2] * coeff[2]); - sum += (st[-3] * coeff[3]); - sum += (st[-4] * coeff[4]); - sum += (st[-5] * coeff[5]); - sum += (st[-6] * coeff[6]); - sum += (st[-7] * coeff[7]); - - sum >>= 7; - return sum * sum; -} - -extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum) -{ - int sum = 0; - - sum += (st[0] * coeff[0]); - sum += (st[-1] * coeff[1]); - sum += (st[-2] * coeff[2]); - sum += (st[-3] * coeff[3]); - sum += (st[-4] * coeff[4]); - sum += (st[-5] * coeff[5]); - sum += (st[-6] * coeff[6]); - sum += (st[-7] * coeff[7]); - - sum >>= 15; - return sum * sum; -} - -extern __inline__ int do_filter_1200_u8(const unsigned char *buf) -{ - int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I); - sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q); - sum -= convolution8_u8(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I); - sum -= convolution8_u8(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q); - return sum; -} - -extern __inline__ int do_filter_1200_s16(const short *buf) -{ - int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I); - sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q); - sum -= convolution8_s16(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I); - sum -= convolution8_s16(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q); - return sum; -} - -/* --------------------------------------------------------------------- */ - -static const int pll_corr[2] = { -0x1000, 0x1000 }; - -static void demodulator_1200_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); - int j; - int sum; - unsigned char newsample; - - for (; buflen > 0; buflen--, buf++) { - sum = do_filter_1200_u8(buf); - st->dcd_shreg <<= 1; - st->bit_pll += 0x2000; - newsample = (sum > 0); - if (st->last_sample ^ newsample) { - st->last_sample = newsample; - st->dcd_shreg |= 1; - st->bit_pll += pll_corr - [st->bit_pll < 0x9000]; - j = 4 * hweight8(st->dcd_shreg & 0x38) - - hweight16(st->dcd_shreg & 0x7c0); - st->dcd_sum0 += j; - } - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 120; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->shreg >>= 1; - st->shreg |= (!(st->last_rxbit ^ - st->last_sample)) << 16; - st->last_rxbit = st->last_sample; - diag_trigger(sm); - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - } - diag_add(sm, (((int)*buf)-0x80) << 8, sum); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_1200_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); - int j; - int sum; - unsigned char newsample; - - for (; buflen > 0; buflen--, buf++) { - sum = do_filter_1200_s16(buf); - st->dcd_shreg <<= 1; - st->bit_pll += 0x2000; - newsample = (sum > 0); - if (st->last_sample ^ newsample) { - st->last_sample = newsample; - st->dcd_shreg |= 1; - st->bit_pll += pll_corr - [st->bit_pll < 0x9000]; - j = 4 * hweight8(st->dcd_shreg & 0x38) - - hweight16(st->dcd_shreg & 0x7c0); - st->dcd_sum0 += j; - } - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 120; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->shreg >>= 1; - st->shreg |= (!(st->last_rxbit ^ - st->last_sample)) << 16; - st->last_rxbit = st->last_sample; - diag_trigger(sm); - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - } - diag_add(sm, *buf, sum); - } -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_1200(struct sm_state *sm) -{ - struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); - - st->dcd_time = 120; - st->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_afsk1200_tx = { - "afsk1200", sizeof(struct mod_state_afsk12), - AFSK12_SAMPLE_RATE, 1200, modulator_1200_u8, modulator_1200_s16, NULL -}; - -const struct modem_rx_info sm_afsk1200_rx = { - "afsk1200", sizeof(struct demod_state_afsk12), - AFSK12_SAMPLE_RATE, 1200, 8, AFSK12_SAMPLE_RATE/1200, - demodulator_1200_u8, demodulator_1200_s16, demod_init_1200 -}; - -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm_afsk2400_7.c linux/drivers/net/soundmodem/sm_afsk2400_7.c --- v2.1.70/linux/drivers/net/soundmodem/sm_afsk2400_7.c Thu Sep 4 17:07:30 1997 +++ linux/drivers/net/soundmodem/sm_afsk2400_7.c Wed Dec 31 16:00:00 1969 @@ -1,296 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_afsk2400_7.c -- soundcard radio modem driver, 2400 baud AFSK modem - * - * 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. - * - */ - -/* - * This driver is intended to be compatible with TCM3105 modems - * overclocked to 7.3728MHz. The mark and space frequencies therefore - * lie at 3658 and 1996 Hz. - * Note that I do _not_ recommend the building of such links, I provide - * this only for the users who live in the coverage area of such - * a "legacy" link. - */ - -#include "sm.h" -#include "sm_tbl_afsk2400_7.h" - -/* --------------------------------------------------------------------- */ - -struct demod_state_afsk24 { - unsigned int shreg; - unsigned int bit_pll; - unsigned char last_sample; - unsigned int dcd_shreg; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned int dcd_time; - unsigned char last_rxbit; -}; - -struct mod_state_afsk24 { - unsigned int shreg; - unsigned char tx_bit; - unsigned int bit_pll; - unsigned int tx_seq; - unsigned int phinc; -}; - -/* --------------------------------------------------------------------- */ - -static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE, - AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE }; - -static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (st->tx_seq < 0x5555) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; - st->shreg >>= 1; - st->phinc = dds_inc[st->tx_bit & 1]; - } - st->tx_seq += 0x5555; - st->tx_seq &= 0xffff; - *buf = OFFSCOS(st->bit_pll); - st->bit_pll += st->phinc; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (st->tx_seq < 0x5555) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; - st->shreg >>= 1; - st->phinc = dds_inc[st->tx_bit & 1]; - } - st->tx_seq += 0x5555; - st->tx_seq &= 0xffff; - *buf = COS(st->bit_pll); - st->bit_pll += st->phinc; - } -} - -/* --------------------------------------------------------------------- */ - -extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum) -{ - int sum = -0x80 * csum; - - sum += (st[0] * coeff[0]); - sum += (st[-1] * coeff[1]); - sum += (st[-2] * coeff[2]); - sum += (st[-3] * coeff[3]); - sum += (st[-4] * coeff[4]); - sum += (st[-5] * coeff[5]); - sum += (st[-6] * coeff[6]); - sum += (st[-7] * coeff[7]); - sum += (st[-8] * coeff[8]); - sum += (st[-9] * coeff[9]); - sum += (st[-10] * coeff[10]); - sum += (st[-11] * coeff[11]); - sum += (st[-12] * coeff[12]); - sum += (st[-13] * coeff[13]); - - sum >>= 7; - return sum * sum; -} - -extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum) -{ - int sum = 0; - - sum += (st[0] * coeff[0]); - sum += (st[-1] * coeff[1]); - sum += (st[-2] * coeff[2]); - sum += (st[-3] * coeff[3]); - sum += (st[-4] * coeff[4]); - sum += (st[-5] * coeff[5]); - sum += (st[-6] * coeff[6]); - sum += (st[-7] * coeff[7]); - sum += (st[-8] * coeff[8]); - sum += (st[-9] * coeff[9]); - sum += (st[-10] * coeff[10]); - sum += (st[-11] * coeff[11]); - sum += (st[-12] * coeff[12]); - sum += (st[-13] * coeff[13]); - - sum >>= 15; - return sum * sum; -} - -extern __inline__ int do_filter_2400_u8(const unsigned char *buf) -{ - int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); - sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); - sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); - sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); - return sum; -} - -extern __inline__ int do_filter_2400_s16(const short *buf) -{ - int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); - sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); - sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); - sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); - return sum; -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); - int j; - int sum; - unsigned char newsample; - - for (; buflen > 0; buflen--, buf++) { - sum = do_filter_2400_u8(buf); - st->dcd_shreg <<= 1; - st->bit_pll += AFSK24_BITPLL_INC; - newsample = (sum > 0); - if (st->last_sample ^ newsample) { - st->last_sample = newsample; - st->dcd_shreg |= 1; - if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) - st->bit_pll += AFSK24_BITPLL_INC/2; - else - st->bit_pll -= AFSK24_BITPLL_INC/2; - j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) - - hweight16(st->dcd_shreg & 0x1e0); - st->dcd_sum0 += j; - } - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 120; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->shreg >>= 1; - st->shreg |= (!(st->last_rxbit ^ - st->last_sample)) << 16; - st->last_rxbit = st->last_sample; - diag_trigger(sm); - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - } - diag_add(sm, (((int)*buf)-0x80) << 8, sum); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); - int j; - int sum; - unsigned char newsample; - - for (; buflen > 0; buflen--, buf++) { - sum = do_filter_2400_s16(buf); - st->dcd_shreg <<= 1; - st->bit_pll += AFSK24_BITPLL_INC; - newsample = (sum > 0); - if (st->last_sample ^ newsample) { - st->last_sample = newsample; - st->dcd_shreg |= 1; - if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) - st->bit_pll += AFSK24_BITPLL_INC/2; - else - st->bit_pll -= AFSK24_BITPLL_INC/2; - j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) - - hweight16(st->dcd_shreg & 0x1e0); - st->dcd_sum0 += j; - } - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 120; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->shreg >>= 1; - st->shreg |= (!(st->last_rxbit ^ - st->last_sample)) << 16; - st->last_rxbit = st->last_sample; - diag_trigger(sm); - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - } - diag_add(sm, *buf, sum); - } -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_2400(struct sm_state *sm) -{ - struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); - - st->dcd_time = 120; - st->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_afsk2400_7_tx = { - "afsk2400_7", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400, - modulator_2400_u8, modulator_2400_s16, NULL -}; - -const struct modem_rx_info sm_afsk2400_7_rx = { - "afsk2400_7", sizeof(struct demod_state_afsk24), - AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400, - demodulator_2400_u8, demodulator_2400_s16, demod_init_2400 -}; - -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm_afsk2400_8.c linux/drivers/net/soundmodem/sm_afsk2400_8.c --- v2.1.70/linux/drivers/net/soundmodem/sm_afsk2400_8.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/net/soundmodem/sm_afsk2400_8.c Wed Dec 31 16:00:00 1969 @@ -1,296 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_afsk2400_8.c -- soundcard radio modem driver, 2400 baud AFSK modem - * - * 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. - * - */ - -/* - * This driver is intended to be compatible with TCM3105 modems - * overclocked to 8MHz. The mark and space frequencies therefore - * lie at 3970 and 2165 Hz. - * Note that I do _not_ recommend the building of such links, I provide - * this only for the users who live in the coverage area of such - * a "legacy" link. - */ - -#include "sm.h" -#include "sm_tbl_afsk2400_8.h" - -/* --------------------------------------------------------------------- */ - -struct demod_state_afsk24 { - unsigned int shreg; - unsigned int bit_pll; - unsigned char last_sample; - unsigned int dcd_shreg; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned int dcd_time; - unsigned char last_rxbit; -}; - -struct mod_state_afsk24 { - unsigned int shreg; - unsigned char tx_bit; - unsigned int bit_pll; - unsigned int tx_seq; - unsigned int phinc; -}; - -/* --------------------------------------------------------------------- */ - -static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE, - AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE }; - -static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (st->tx_seq < 0x5555) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; - st->shreg >>= 1; - st->phinc = dds_inc[st->tx_bit & 1]; - } - st->tx_seq += 0x5555; - st->tx_seq &= 0xffff; - *buf = OFFSCOS(st->bit_pll); - st->bit_pll += st->phinc; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (st->tx_seq < 0x5555) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; - st->shreg >>= 1; - st->phinc = dds_inc[st->tx_bit & 1]; - } - st->tx_seq += 0x5555; - st->tx_seq &= 0xffff; - *buf = COS(st->bit_pll); - st->bit_pll += st->phinc; - } -} - -/* --------------------------------------------------------------------- */ - -extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum) -{ - int sum = -0x80 * csum; - - sum += (st[0] * coeff[0]); - sum += (st[-1] * coeff[1]); - sum += (st[-2] * coeff[2]); - sum += (st[-3] * coeff[3]); - sum += (st[-4] * coeff[4]); - sum += (st[-5] * coeff[5]); - sum += (st[-6] * coeff[6]); - sum += (st[-7] * coeff[7]); - sum += (st[-8] * coeff[8]); - sum += (st[-9] * coeff[9]); - sum += (st[-10] * coeff[10]); - sum += (st[-11] * coeff[11]); - sum += (st[-12] * coeff[12]); - sum += (st[-13] * coeff[13]); - - sum >>= 7; - return sum * sum; -} - -extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum) -{ - int sum = 0; - - sum += (st[0] * coeff[0]); - sum += (st[-1] * coeff[1]); - sum += (st[-2] * coeff[2]); - sum += (st[-3] * coeff[3]); - sum += (st[-4] * coeff[4]); - sum += (st[-5] * coeff[5]); - sum += (st[-6] * coeff[6]); - sum += (st[-7] * coeff[7]); - sum += (st[-8] * coeff[8]); - sum += (st[-9] * coeff[9]); - sum += (st[-10] * coeff[10]); - sum += (st[-11] * coeff[11]); - sum += (st[-12] * coeff[12]); - sum += (st[-13] * coeff[13]); - - sum >>= 15; - return sum * sum; -} - -extern __inline__ int do_filter_2400_u8(const unsigned char *buf) -{ - int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); - sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); - sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); - sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); - return sum; -} - -extern __inline__ int do_filter_2400_s16(const short *buf) -{ - int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); - sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); - sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); - sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); - return sum; -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); - int j; - int sum; - unsigned char newsample; - - for (; buflen > 0; buflen--, buf++) { - sum = do_filter_2400_u8(buf); - st->dcd_shreg <<= 1; - st->bit_pll += AFSK24_BITPLL_INC; - newsample = (sum > 0); - if (st->last_sample ^ newsample) { - st->last_sample = newsample; - st->dcd_shreg |= 1; - if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) - st->bit_pll += AFSK24_BITPLL_INC/2; - else - st->bit_pll -= AFSK24_BITPLL_INC/2; - j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) - - hweight16(st->dcd_shreg & 0x1e0); - st->dcd_sum0 += j; - } - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 120; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->shreg >>= 1; - st->shreg |= (!(st->last_rxbit ^ - st->last_sample)) << 16; - st->last_rxbit = st->last_sample; - diag_trigger(sm); - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - } - diag_add(sm, (((int)*buf)-0x80) << 8, sum); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); - int j; - int sum; - unsigned char newsample; - - for (; buflen > 0; buflen--, buf++) { - sum = do_filter_2400_s16(buf); - st->dcd_shreg <<= 1; - st->bit_pll += AFSK24_BITPLL_INC; - newsample = (sum > 0); - if (st->last_sample ^ newsample) { - st->last_sample = newsample; - st->dcd_shreg |= 1; - if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) - st->bit_pll += AFSK24_BITPLL_INC/2; - else - st->bit_pll -= AFSK24_BITPLL_INC/2; - j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) - - hweight16(st->dcd_shreg & 0x1e0); - st->dcd_sum0 += j; - } - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 120; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->shreg >>= 1; - st->shreg |= (!(st->last_rxbit ^ - st->last_sample)) << 16; - st->last_rxbit = st->last_sample; - diag_trigger(sm); - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - } - diag_add(sm, *buf, sum); - } -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_2400(struct sm_state *sm) -{ - struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); - - st->dcd_time = 120; - st->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_afsk2400_8_tx = { - "afsk2400_8", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400, - modulator_2400_u8, modulator_2400_s16, NULL -}; - -const struct modem_rx_info sm_afsk2400_8_rx = { - "afsk2400_8", sizeof(struct demod_state_afsk24), - AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400, - demodulator_2400_u8, demodulator_2400_s16, demod_init_2400 -}; - -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm_fsk9600.c linux/drivers/net/soundmodem/sm_fsk9600.c --- v2.1.70/linux/drivers/net/soundmodem/sm_fsk9600.c Mon Jun 16 16:35:56 1997 +++ linux/drivers/net/soundmodem/sm_fsk9600.c Wed Dec 31 16:00:00 1969 @@ -1,391 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_fsk9600.c -- soundcard radio modem driver, - * 9600 baud G3RUH compatible FSK modem - * - * 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. - * - */ - -#include "sm.h" -#include "sm_tbl_fsk9600.h" - -/* --------------------------------------------------------------------- */ - -struct demod_state_fsk96 { - unsigned int shreg; - unsigned long descram; - unsigned int bit_pll; - unsigned char last_sample; - unsigned int dcd_shreg; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned int dcd_time; -}; - -struct mod_state_fsk96 { - unsigned int shreg; - unsigned long scram; - unsigned char tx_bit; - unsigned char *txtbl; - unsigned int txphase; -}; - -/* --------------------------------------------------------------------- */ - -#define DESCRAM_TAP1 0x20000 -#define DESCRAM_TAP2 0x01000 -#define DESCRAM_TAP3 0x00001 - -#define DESCRAM_TAPSH1 17 -#define DESCRAM_TAPSH2 12 -#define DESCRAM_TAPSH3 0 - -#define SCRAM_TAP1 0x20000 /* X^17 */ -#define SCRAM_TAPN 0x00021 /* X^0+X^5 */ - -/* --------------------------------------------------------------------- */ - -static void modulator_9600_4_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); - - for (; buflen > 0; buflen--) { - if (!st->txphase++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->scram = (st->scram << 1) | (st->scram & 1); - st->scram ^= !(st->shreg & 1); - st->shreg >>= 1; - if (st->scram & (SCRAM_TAP1 << 1)) - st->scram ^= SCRAM_TAPN << 1; - st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); - st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff); - } - if (st->txphase >= 4) - st->txphase = 0; - *buf++ = *st->txtbl; - st->txtbl += 0x100; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_9600_4_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); - - for (; buflen > 0; buflen--) { - if (!st->txphase++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->scram = (st->scram << 1) | (st->scram & 1); - st->scram ^= !(st->shreg & 1); - st->shreg >>= 1; - if (st->scram & (SCRAM_TAP1 << 1)) - st->scram ^= SCRAM_TAPN << 1; - st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); - st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff); - } - if (st->txphase >= 4) - st->txphase = 0; - *buf++ = ((*st->txtbl)-0x80) << 8; - st->txtbl += 0x100; - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_9600_4_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); - static const int pll_corr[2] = { -0x1000, 0x1000 }; - unsigned char curbit; - unsigned int descx; - - for (; buflen > 0; buflen--, buf++) { - st->dcd_shreg <<= 1; - st->bit_pll += 0x4000; - curbit = (*buf >= 0x80); - if (st->last_sample ^ curbit) { - st->dcd_shreg |= 1; - st->bit_pll += pll_corr[st->bit_pll < 0xa000]; - st->dcd_sum0 += 8 * hweight8(st->dcd_shreg & 0x0c) - - !!(st->dcd_shreg & 0x10); - } - st->last_sample = curbit; - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 240; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->descram = (st->descram << 1) | curbit; - descx = st->descram ^ (st->descram >> 1); - descx ^= ((descx >> DESCRAM_TAPSH1) ^ - (descx >> DESCRAM_TAPSH2)); - st->shreg >>= 1; - st->shreg |= (!(descx & 1)) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, ((short)(*buf - 0x80)) << 8); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_9600_4_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); - static const int pll_corr[2] = { -0x1000, 0x1000 }; - unsigned char curbit; - unsigned int descx; - - for (; buflen > 0; buflen--, buf++) { - st->dcd_shreg <<= 1; - st->bit_pll += 0x4000; - curbit = (*buf >= 0); - if (st->last_sample ^ curbit) { - st->dcd_shreg |= 1; - st->bit_pll += pll_corr[st->bit_pll < 0xa000]; - st->dcd_sum0 += 8 * hweight8(st->dcd_shreg & 0x0c) - - !!(st->dcd_shreg & 0x10); - } - st->last_sample = curbit; - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 240; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->descram = (st->descram << 1) | curbit; - descx = st->descram ^ (st->descram >> 1); - descx ^= ((descx >> DESCRAM_TAPSH1) ^ - (descx >> DESCRAM_TAPSH2)); - st->shreg >>= 1; - st->shreg |= (!(descx & 1)) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, *buf); - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_9600_5_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); - - for (; buflen > 0; buflen--) { - if (!st->txphase++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->scram = (st->scram << 1) | (st->scram & 1); - st->scram ^= !(st->shreg & 1); - st->shreg >>= 1; - if (st->scram & (SCRAM_TAP1 << 1)) - st->scram ^= SCRAM_TAPN << 1; - st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); - st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff); - } - if (st->txphase >= 5) - st->txphase = 0; - *buf++ = *st->txtbl; - st->txtbl += 0x100; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_9600_5_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); - - for (; buflen > 0; buflen--) { - if (!st->txphase++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->scram = (st->scram << 1) | (st->scram & 1); - st->scram ^= !(st->shreg & 1); - st->shreg >>= 1; - if (st->scram & (SCRAM_TAP1 << 1)) - st->scram ^= SCRAM_TAPN << 1; - st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); - st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff); - } - if (st->txphase >= 5) - st->txphase = 0; - *buf++ = ((*st->txtbl)-0x80)<<8; - st->txtbl += 0x100; - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_9600_5_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); - static const int pll_corr[2] = { -0x1000, 0x1000 }; - unsigned char curbit; - unsigned int descx; - - for (; buflen > 0; buflen--, buf++) { - st->dcd_shreg <<= 1; - st->bit_pll += 0x3333; - curbit = (*buf >= 0x80); - if (st->last_sample ^ curbit) { - st->dcd_shreg |= 1; - st->bit_pll += pll_corr[st->bit_pll < 0x9999]; - st->dcd_sum0 += 16 * hweight8(st->dcd_shreg & 0x0c) - - hweight8(st->dcd_shreg & 0x70); - } - st->last_sample = curbit; - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 240; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->descram = (st->descram << 1) | curbit; - descx = st->descram ^ (st->descram >> 1); - descx ^= ((descx >> DESCRAM_TAPSH1) ^ - (descx >> DESCRAM_TAPSH2)); - st->shreg >>= 1; - st->shreg |= (!(descx & 1)) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, ((short)(*buf - 0x80)) << 8); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_9600_5_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); - static const int pll_corr[2] = { -0x1000, 0x1000 }; - unsigned char curbit; - unsigned int descx; - - for (; buflen > 0; buflen--, buf++) { - st->dcd_shreg <<= 1; - st->bit_pll += 0x3333; - curbit = (*buf >= 0); - if (st->last_sample ^ curbit) { - st->dcd_shreg |= 1; - st->bit_pll += pll_corr[st->bit_pll < 0x9999]; - st->dcd_sum0 += 16 * hweight8(st->dcd_shreg & 0x0c) - - hweight8(st->dcd_shreg & 0x70); - } - st->last_sample = curbit; - hdlcdrv_channelbit(&sm->hdrv, st->last_sample); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 240; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->descram = (st->descram << 1) | curbit; - descx = st->descram ^ (st->descram >> 1); - descx ^= ((descx >> DESCRAM_TAPSH1) ^ - (descx >> DESCRAM_TAPSH2)); - st->shreg >>= 1; - st->shreg |= (!(descx & 1)) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, *buf); - } -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_9600(struct sm_state *sm) -{ - struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); - - st->dcd_time = 240; - st->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_fsk9600_4_tx = { - "fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600, - modulator_9600_4_u8, modulator_9600_4_s16, NULL -}; - -const struct modem_rx_info sm_fsk9600_4_rx = { - "fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 1, 4, - demodulator_9600_4_u8, demodulator_9600_4_s16, demod_init_9600 -}; - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_fsk9600_5_tx = { - "fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600, - modulator_9600_5_u8, modulator_9600_5_s16, NULL -}; - -const struct modem_rx_info sm_fsk9600_5_rx = { - "fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 1, 5, - demodulator_9600_5_u8, demodulator_9600_5_s16, demod_init_9600 -}; - -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm_hapn4800.c linux/drivers/net/soundmodem/sm_hapn4800.c --- v2.1.70/linux/drivers/net/soundmodem/sm_hapn4800.c Mon Jun 16 16:35:56 1997 +++ linux/drivers/net/soundmodem/sm_hapn4800.c Wed Dec 31 16:00:00 1969 @@ -1,560 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_hapn4800.c -- soundcard radio modem driver, 4800 baud HAPN modem - * - * 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. - * - * - * This module implements a (hopefully) HAPN (Hamilton Area Packet - * Network) compatible 4800 baud modem. - * The HAPN modem uses kind of "duobinary signalling" (not really, - * duobinary signalling gives ... 0 0 -1 0 1 0 0 ... at the sampling - * instants, whereas HAPN signalling gives ... 0 0 -1 1 0 0 ..., see - * Proakis, Digital Communications). - * The code is untested. It is compatible with itself (i.e. it can decode - * the packets it sent), but I could not test if it is compatible with - * any "real" HAPN modem, since noone uses it in my region of the world. - * Feedback therefore welcome. - */ - -#include "sm.h" -#include "sm_tbl_hapn4800.h" - -/* --------------------------------------------------------------------- */ - -struct demod_state_hapn48 { - unsigned int shreg; - unsigned int bit_pll; - unsigned char last_bit; - unsigned char last_bit2; - unsigned int dcd_shreg; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned int dcd_time; - int lvlhi, lvllo; -}; - -struct mod_state_hapn48 { - unsigned int shreg; - unsigned char tx_bit; - unsigned int tx_seq; - const unsigned char *tbl; -}; - -/* --------------------------------------------------------------------- */ - -static void modulator_hapn4800_10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = ((st->tx_bit << 1) | - (st->tx_bit & 1)); - st->tx_bit ^= (!(st->shreg & 1)); - st->shreg >>= 1; - st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf); - } - if (st->tx_seq >= 10) - st->tx_seq = 0; - *buf = *st->tbl; - st->tbl += 0x10; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_hapn4800_10_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = ((st->tx_bit << 1) | - (st->tx_bit & 1)); - st->tx_bit ^= (!(st->shreg & 1)); - st->shreg >>= 1; - st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf); - } - if (st->tx_seq >= 10) - st->tx_seq = 0; - *buf = ((*st->tbl)-0x80)<<8; - st->tbl += 0x10; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_hapn4800_8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); - st->tx_bit ^= !(st->shreg & 1); - st->shreg >>= 1; - st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf); - } - if (st->tx_seq >= 8) - st->tx_seq = 0; - *buf = *st->tbl; - st->tbl += 0x10; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_hapn4800_8_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); - st->tx_bit ^= !(st->shreg & 1); - st->shreg >>= 1; - st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf); - } - if (st->tx_seq >= 8) - st->tx_seq = 0; - *buf = ((*st->tbl)-0x80)<<8; - st->tbl += 0x10; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_hapn4800_pm10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = ((st->tx_bit << 1) | - (st->tx_bit & 1)); - st->tx_bit ^= (!(st->shreg & 1)); - st->shreg >>= 1; - st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf); - } - if (st->tx_seq >= 10) - st->tx_seq = 0; - *buf = *st->tbl; - st->tbl += 0x10; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_hapn4800_pm10_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = ((st->tx_bit << 1) | - (st->tx_bit & 1)); - st->tx_bit ^= (!(st->shreg & 1)); - st->shreg >>= 1; - st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf); - } - if (st->tx_seq >= 10) - st->tx_seq = 0; - *buf = ((*st->tbl)-0x80)<<8; - st->tbl += 0x10; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_hapn4800_pm8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); - st->tx_bit ^= !(st->shreg & 1); - st->shreg >>= 1; - st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf); - } - if (st->tx_seq >= 8) - st->tx_seq = 0; - *buf = *st->tbl; - st->tbl += 0x10; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_hapn4800_pm8_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); - st->tx_bit ^= !(st->shreg & 1); - st->shreg >>= 1; - st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf); - } - if (st->tx_seq >= 8) - st->tx_seq = 0; - *buf = ((*st->tbl)-0x80)<<8; - st->tbl += 0x10; - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_hapn4800_10_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); - static const int pll_corr[2] = { -0x800, 0x800 }; - int curst, cursync; - int inv; - - for (; buflen > 0; buflen--, buf++) { - inv = ((int)(buf[-2])-0x80) << 8; - st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ - st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ - if (inv > st->lvlhi) - st->lvlhi = inv; - if (inv < st->lvllo) - st->lvllo = inv; - if (buflen & 1) - st->dcd_shreg <<= 1; - st->bit_pll += 0x199a; - curst = cursync = 0; - if (inv > st->lvlhi >> 1) { - curst = 1; - cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && - buf[-2] > buf[-0] && buf[-2] > buf[-4]); - } else if (inv < st->lvllo >> 1) { - curst = -1; - cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && - buf[-2] < buf[-0] && buf[-2] < buf[-4]); - } - if (cursync) { - st->dcd_shreg |= cursync; - st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x8ccdu]; - st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x18c6318c) - - hweight32(st->dcd_shreg & 0xe739ce70); - } - hdlcdrv_channelbit(&sm->hdrv, cursync); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 240; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->last_bit2 = st->last_bit; - if (curst < 0) - st->last_bit = 0; - else if (curst > 0) - st->last_bit = 1; - st->shreg >>= 1; - st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, inv); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_hapn4800_10_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); - static const int pll_corr[2] = { -0x800, 0x800 }; - int curst, cursync; - int inv; - - for (; buflen > 0; buflen--, buf++) { - inv = buf[-2]; - st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ - st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ - if (inv > st->lvlhi) - st->lvlhi = inv; - if (inv < st->lvllo) - st->lvllo = inv; - if (buflen & 1) - st->dcd_shreg <<= 1; - st->bit_pll += 0x199a; - curst = cursync = 0; - if (inv > st->lvlhi >> 1) { - curst = 1; - cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && - buf[-2] > buf[-0] && buf[-2] > buf[-4]); - } else if (inv < st->lvllo >> 1) { - curst = -1; - cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && - buf[-2] < buf[-0] && buf[-2] < buf[-4]); - } - if (cursync) { - st->dcd_shreg |= cursync; - st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x8ccdu]; - st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x18c6318c) - - hweight32(st->dcd_shreg & 0xe739ce70); - } - hdlcdrv_channelbit(&sm->hdrv, cursync); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 240; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->last_bit2 = st->last_bit; - if (curst < 0) - st->last_bit = 0; - else if (curst > 0) - st->last_bit = 1; - st->shreg >>= 1; - st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, inv); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_hapn4800_8_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); - static const int pll_corr[2] = { -0x800, 0x800 }; - int curst, cursync; - int inv; - - for (; buflen > 0; buflen--, buf++) { - inv = ((int)(buf[-2])-0x80) << 8; - st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ - st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ - if (inv > st->lvlhi) - st->lvlhi = inv; - if (inv < st->lvllo) - st->lvllo = inv; - if (buflen & 1) - st->dcd_shreg <<= 1; - st->bit_pll += 0x2000; - curst = cursync = 0; - if (inv > st->lvlhi >> 1) { - curst = 1; - cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && - buf[-2] > buf[-0] && buf[-2] > buf[-4]); - } else if (inv < st->lvllo >> 1) { - curst = -1; - cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && - buf[-2] < buf[-0] && buf[-2] < buf[-4]); - } - if (cursync) { - st->dcd_shreg |= cursync; - st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x9000u]; - st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x44444444) - - hweight32(st->dcd_shreg & 0xbbbbbbbb); - } - hdlcdrv_channelbit(&sm->hdrv, cursync); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 240; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->last_bit2 = st->last_bit; - if (curst < 0) - st->last_bit = 0; - else if (curst > 0) - st->last_bit = 1; - st->shreg >>= 1; - st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, inv); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_hapn4800_8_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); - static const int pll_corr[2] = { -0x800, 0x800 }; - int curst, cursync; - int inv; - - for (; buflen > 0; buflen--, buf++) { - inv = buf[-2]; - st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ - st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ - if (inv > st->lvlhi) - st->lvlhi = inv; - if (inv < st->lvllo) - st->lvllo = inv; - if (buflen & 1) - st->dcd_shreg <<= 1; - st->bit_pll += 0x2000; - curst = cursync = 0; - if (inv > st->lvlhi >> 1) { - curst = 1; - cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && - buf[-2] > buf[-0] && buf[-2] > buf[-4]); - } else if (inv < st->lvllo >> 1) { - curst = -1; - cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && - buf[-2] < buf[-0] && buf[-2] < buf[-4]); - } - if (cursync) { - st->dcd_shreg |= cursync; - st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x9000u]; - st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x44444444) - - hweight32(st->dcd_shreg & 0xbbbbbbbb); - } - hdlcdrv_channelbit(&sm->hdrv, cursync); - if ((--st->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + - st->dcd_sum1 + - st->dcd_sum2) < 0); - st->dcd_sum2 = st->dcd_sum1; - st->dcd_sum1 = st->dcd_sum0; - st->dcd_sum0 = 2; /* slight bias */ - st->dcd_time = 240; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffff; - st->last_bit2 = st->last_bit; - if (curst < 0) - st->last_bit = 0; - else if (curst > 0) - st->last_bit = 1; - st->shreg >>= 1; - st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, inv); - } -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_hapn4800(struct sm_state *sm) -{ - struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); - - st->dcd_time = 120; - st->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_hapn4800_8_tx = { - "hapn4800", sizeof(struct mod_state_hapn48), 38400, 4800, - modulator_hapn4800_8_u8, modulator_hapn4800_8_s16, NULL -}; - -const struct modem_rx_info sm_hapn4800_8_rx = { - "hapn4800", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8, - demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800 -}; - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_hapn4800_10_tx = { - "hapn4800", sizeof(struct mod_state_hapn48), 48000, 4800, - modulator_hapn4800_10_u8, modulator_hapn4800_10_s16, NULL -}; - -const struct modem_rx_info sm_hapn4800_10_rx = { - "hapn4800", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10, - demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800 -}; - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_hapn4800_pm8_tx = { - "hapn4800pm", sizeof(struct mod_state_hapn48), 38400, 4800, - modulator_hapn4800_pm8_u8, modulator_hapn4800_pm8_s16, NULL -}; - -const struct modem_rx_info sm_hapn4800_pm8_rx = { - "hapn4800pm", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8, - demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800 -}; - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_hapn4800_pm10_tx = { - "hapn4800pm", sizeof(struct mod_state_hapn48), 48000, 4800, - modulator_hapn4800_pm10_u8, modulator_hapn4800_pm10_s16, NULL -}; - -const struct modem_rx_info sm_hapn4800_pm10_rx = { - "hapn4800pm", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10, - demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800 -}; - -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm_sbc.c linux/drivers/net/soundmodem/sm_sbc.c --- v2.1.70/linux/drivers/net/soundmodem/sm_sbc.c Mon Aug 11 14:47:04 1997 +++ linux/drivers/net/soundmodem/sm_sbc.c Wed Dec 31 16:00:00 1969 @@ -1,941 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_sbc.c -- soundcard radio modem driver soundblaster hardware 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "sm.h" -#include "smdma.h" - -/* --------------------------------------------------------------------- */ - -/* - * 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 - -/* --------------------------------------------------------------------- */ - -struct sc_state_sbc { - unsigned char revhi, revlo; - unsigned char fmt[2]; - unsigned int sr[2]; -}; - -#define SCSTATE ((struct sc_state_sbc *)(&sm->hw)) - -/* --------------------------------------------------------------------- */ -/* - * the sbc converter's registers - */ -#define DSP_RESET(iobase) (iobase+0x6) -#define DSP_READ_DATA(iobase) (iobase+0xa) -#define DSP_WRITE_DATA(iobase) (iobase+0xc) -#define DSP_WRITE_STATUS(iobase) (iobase+0xc) -#define DSP_DATA_AVAIL(iobase) (iobase+0xe) -#define DSP_MIXER_ADDR(iobase) (iobase+0x4) -#define DSP_MIXER_DATA(iobase) (iobase+0x5) -#define DSP_INTACK_16BIT(iobase) (iobase+0xf) -#define SBC_EXTENT 16 - -/* --------------------------------------------------------------------- */ -/* - * SBC commands - */ -#define SBC_OUTPUT 0x14 -#define SBC_INPUT 0x24 -#define SBC_BLOCKSIZE 0x48 -#define SBC_HI_OUTPUT 0x91 -#define SBC_HI_INPUT 0x99 -#define SBC_LO_OUTPUT_AUTOINIT 0x1c -#define SBC_LO_INPUT_AUTOINIT 0x2c -#define SBC_HI_OUTPUT_AUTOINIT 0x90 -#define SBC_HI_INPUT_AUTOINIT 0x98 -#define SBC_IMMED_INT 0xf2 -#define SBC_GET_REVISION 0xe1 -#define ESS_GET_REVISION 0xe7 -#define SBC_SPEAKER_ON 0xd1 -#define SBC_SPEAKER_OFF 0xd3 -#define SBC_DMA_ON 0xd0 -#define SBC_DMA_OFF 0xd4 -#define SBC_SAMPLE_RATE 0x40 -#define SBC_SAMPLE_RATE_OUT 0x41 -#define SBC_SAMPLE_RATE_IN 0x42 -#define SBC_MONO_8BIT 0xa0 -#define SBC_MONO_16BIT 0xa4 -#define SBC_STEREO_8BIT 0xa8 -#define SBC_STEREO_16BIT 0xac - -#define SBC4_OUT8_AI 0xc6 -#define SBC4_IN8_AI 0xce -#define SBC4_MODE_UNS_MONO 0x00 -#define SBC4_MODE_SIGN_MONO 0x10 - -#define SBC4_OUT16_AI 0xb6 -#define SBC4_IN16_AI 0xbe - -/* --------------------------------------------------------------------- */ - -static int inline reset_dsp(struct device *dev) -{ - int i; - - outb(1, DSP_RESET(dev->base_addr)); - for (i = 0; i < 0x100; i++) - SLOW_DOWN_IO; - outb(0, DSP_RESET(dev->base_addr)); - for (i = 0; i < 0xffff; i++) - if (inb(DSP_DATA_AVAIL(dev->base_addr)) & 0x80) - if (inb(DSP_READ_DATA(dev->base_addr)) == 0xaa) - return 1; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static void inline write_dsp(struct device *dev, unsigned char data) -{ - int i; - - for (i = 0; i < 0xffff; i++) - if (!(inb(DSP_WRITE_STATUS(dev->base_addr)) & 0x80)) { - outb(data, DSP_WRITE_DATA(dev->base_addr)); - return; - } -} - -/* --------------------------------------------------------------------- */ - -static int inline read_dsp(struct device *dev, unsigned char *data) -{ - int i; - - if (!data) - return 0; - for (i = 0; i < 0xffff; i++) - if (inb(DSP_DATA_AVAIL(dev->base_addr)) & 0x80) { - *data = inb(DSP_READ_DATA(dev->base_addr)); - return 1; - } - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int config_resources(struct device *dev, struct sm_state *sm, int fdx) -{ - unsigned char irqreg = 0, dmareg = 0, realirq, realdma; - unsigned long flags; - - switch (dev->irq) { - case 2: - case 9: - irqreg |= 0x01; - break; - - case 5: - irqreg |= 0x02; - break; - - case 7: - irqreg |= 0x04; - break; - - case 10: - irqreg |= 0x08; - break; - - default: - return -ENODEV; - } - - switch (dev->dma) { - case 0: - dmareg |= 0x01; - break; - - case 1: - dmareg |= 0x02; - break; - - case 3: - dmareg |= 0x08; - break; - - default: - return -ENODEV; - } - - if (fdx) { - switch (sm->hdrv.ptt_out.dma2) { - case 5: - dmareg |= 0x20; - break; - - case 6: - dmareg |= 0x40; - break; - - case 7: - dmareg |= 0x80; - break; - - default: - return -ENODEV; - } - } - save_flags(flags); - cli(); - outb(0x80, DSP_MIXER_ADDR(dev->base_addr)); - outb(irqreg, DSP_MIXER_DATA(dev->base_addr)); - realirq = inb(DSP_MIXER_DATA(dev->base_addr)); - outb(0x81, DSP_MIXER_ADDR(dev->base_addr)); - outb(dmareg, DSP_MIXER_DATA(dev->base_addr)); - realdma = inb(DSP_MIXER_DATA(dev->base_addr)); - restore_flags(flags); - if ((~realirq) & irqreg || (~realdma) & dmareg) { - printk(KERN_ERR "%s: sbc resource registers cannot be set; PnP device " - "and IRQ/DMA specified wrongly?\n", sm_drvname); - return -EINVAL; - } - return 0; -} - -/* --------------------------------------------------------------------- */ - -static void inline sbc_int_ack_8bit(struct device *dev) -{ - inb(DSP_DATA_AVAIL(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -static void inline sbc_int_ack_16bit(struct device *dev) -{ - inb(DSP_INTACK_16BIT(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -static void setup_dma_dsp(struct device *dev, struct sm_state *sm, int send) -{ - unsigned long flags; - static const unsigned char sbcmode[2][2] = { - { SBC_LO_INPUT_AUTOINIT, SBC_LO_OUTPUT_AUTOINIT }, - { SBC_HI_INPUT_AUTOINIT, SBC_HI_OUTPUT_AUTOINIT } - }; - static const unsigned char sbc4mode[2] = { SBC4_IN8_AI, SBC4_OUT8_AI }; - static const unsigned char sbcskr[2] = { SBC_SPEAKER_OFF, SBC_SPEAKER_ON }; - unsigned int nsamps; - - send = !!send; - if (!reset_dsp(dev)) { - printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); - return; - } - save_flags(flags); - cli(); - sbc_int_ack_8bit(dev); - write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */ - write_dsp(dev, SCSTATE->fmt[send]); - write_dsp(dev, sbcskr[send]); - nsamps = dma_setup(sm, send, dev->dma) - 1; - sbc_int_ack_8bit(dev); - if (SCSTATE->revhi >= 4) { - write_dsp(dev, sbc4mode[send]); - write_dsp(dev, SBC4_MODE_UNS_MONO); - write_dsp(dev, nsamps & 0xff); - write_dsp(dev, nsamps >> 8); - } else { - write_dsp(dev, SBC_BLOCKSIZE); - write_dsp(dev, nsamps & 0xff); - write_dsp(dev, nsamps >> 8); - write_dsp(dev, sbcmode[SCSTATE->fmt[send] >= 180][send]); - /* hispeed mode if sample rate > 13kHz */ - } - restore_flags(flags); -} - -/* --------------------------------------------------------------------- */ - -static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned int curfrag; - - if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) - return; - cli(); - sbc_int_ack_8bit(dev); - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag); - enable_dma(dev->dma); - sm_int_freq(sm); - sti(); - if (sm->dma.ptt_cnt <= 0) { - dma_receive(sm, curfrag); - hdlcdrv_arbitrate(dev, &sm->hdrv); - if (hdlcdrv_ptt(&sm->hdrv)) { - /* starting to transmit */ - disable_dma(dev->dma); - hdlcdrv_transmitter(dev, &sm->hdrv); /* prefill HDLC buffer */ - dma_start_transmit(sm); - setup_dma_dsp(dev, sm, 1); - dma_transmit(sm); - } - } else if (dma_end_transmit(sm, curfrag)) { - /* stopping transmission */ - disable_dma(dev->dma); - sti(); - dma_init_receive(sm); - setup_dma_dsp(dev, sm, 0); - } else - dma_transmit(sm); - sm_output_status(sm); - hdlcdrv_transmitter(dev, &sm->hdrv); - hdlcdrv_receiver(dev, &sm->hdrv); - -} - -/* --------------------------------------------------------------------- */ - -static int sbc_open(struct device *dev, struct sm_state *sm) -{ - int err; - unsigned int dmasz, u; - - if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) { - printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", - sizeof(struct sc_state_sbc), sizeof(sm->m)); - return -ENODEV; - } - if (!dev || !sm) - return -ENXIO; - if (dev->base_addr <= 0 || dev->base_addr > 0x1000-SBC_EXTENT || - dev->irq < 2 || dev->irq > 15 || dev->dma > 3) - return -ENXIO; - if (check_region(dev->base_addr, SBC_EXTENT)) - return -EACCES; - /* - * check if a card is available - */ - if (!reset_dsp(dev)) { - printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n", - sm_drvname, dev->base_addr); - return -ENODEV; - } - write_dsp(dev, SBC_GET_REVISION); - if (!read_dsp(dev, &SCSTATE->revhi) || - !read_dsp(dev, &SCSTATE->revlo)) - return -ENODEV; - printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, - SCSTATE->revhi, SCSTATE->revlo); - if (SCSTATE->revhi < 2) { - printk(KERN_ERR "%s: your card is an antiquity, at least DSP " - "rev 2.00 required\n", sm_drvname); - return -ENODEV; - } - if (SCSTATE->revhi < 3 && - (SCSTATE->fmt[0] >= 180 || SCSTATE->fmt[1] >= 180)) { - printk(KERN_ERR "%s: sbc io 0x%lx: DSP rev %d.%02d too " - "old, at least 3.00 required\n", sm_drvname, - dev->base_addr, SCSTATE->revhi, SCSTATE->revlo); - return -ENODEV; - } - if (SCSTATE->revhi >= 4 && - (err = config_resources(dev, sm, 0))) { - printk(KERN_ERR "%s: invalid IRQ and/or DMA specified\n", sm_drvname); - return err; - } - /* - * initialize some variables - */ - dma_init_receive(sm); - dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz; - u = NUM_FRAGMENTS * sm->dma.ofragsz; - if (u > dmasz) - dmasz = u; - if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA))) - return -ENOMEM; - dma_init_transmit(sm); - dma_init_receive(sm); - - memset(&sm->m, 0, sizeof(sm->m)); - memset(&sm->d, 0, sizeof(sm->d)); - if (sm->mode_tx->init) - sm->mode_tx->init(sm); - if (sm->mode_rx->init) - sm->mode_rx->init(sm); - - if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(sm->dma.obuf, dmasz); - return -EBUSY; - } - if (request_irq(dev->irq, sbc_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - free_dma(dev->dma); - kfree_s(sm->dma.obuf, dmasz); - return -EBUSY; - } - request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name); - setup_dma_dsp(dev, sm, 0); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int sbc_close(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm) - return -EINVAL; - /* - * disable interrupts - */ - disable_dma(dev->dma); - reset_dsp(dev); - free_irq(dev->irq, dev); - free_dma(dev->dma); - release_region(dev->base_addr, SBC_EXTENT); - kfree(sm->dma.obuf); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, '.'); - const struct modem_tx_info **mtp = sm_modem_tx_table; - const struct modem_rx_info **mrp; - - if (!strcmp(mode, "off")) { - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return 0; - } - if (cp) - *cp++ = '\0'; - else - cp = mode; - for (; *mtp; mtp++) { - if ((*mtp)->loc_storage > sizeof(sm->m)) { - printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", - sm_drvname, (*mtp)->name, (*mtp)->loc_storage); - continue; - } - if (!(*mtp)->name || strcmp((*mtp)->name, mode)) - continue; - if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100) - continue; - if (!(*mtp)->modulator_u8) - continue; - for (mrp = sm_modem_rx_table; *mrp; mrp++) { - if ((*mrp)->loc_storage > sizeof(sm->d)) { - printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", - sm_drvname, (*mrp)->name, (*mrp)->loc_storage); - continue; - } - if (!(*mrp)->demodulator_u8) - continue; - if ((*mrp)->name && !strcmp((*mrp)->name, cp) && - (*mrp)->srate >= 5000 && (*mrp)->srate <= 44100) { - sm->mode_tx = *mtp; - sm->mode_rx = *mrp; - SCSTATE->fmt[0] = 256-((1000000L+sm->mode_rx->srate/2)/ - sm->mode_rx->srate); - SCSTATE->fmt[1] = 256-((1000000L+sm->mode_tx->srate/2)/ - sm->mode_tx->srate); - sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; - sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; - if (sm->dma.ifragsz < sm->mode_rx->overlap) - sm->dma.ifragsz = sm->mode_rx->overlap; - sm->dma.i16bit = sm->dma.o16bit = 0; - return 0; - } - } - } - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int sbc_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct sm_ioctl bi; - unsigned long flags; - int i; - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | - HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | - HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; - - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - - switch (bi.cmd) { - default: - return -ENOIOCTLCMD; - - case SMCTL_GETMIXER: - i = 0; - bi.data.mix.sample_rate = sm->mode_rx->srate; - bi.data.mix.bit_rate = sm->hdrv.par.bitrate; - bi.data.mix.mixer_type = SM_MIXER_INVALID; - switch (SCSTATE->revhi) { - case 2: - bi.data.mix.mixer_type = SM_MIXER_CT1335; - break; - case 3: - bi.data.mix.mixer_type = SM_MIXER_CT1345; - break; - case 4: - bi.data.mix.mixer_type = SM_MIXER_CT1745; - break; - } - if (bi.data.mix.mixer_type != SM_MIXER_INVALID && - bi.data.mix.reg < 0x80) { - save_flags(flags); - cli(); - outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); - bi.data.mix.data = inb(DSP_MIXER_DATA(dev->base_addr)); - restore_flags(flags); - i = 1; - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return i; - - case SMCTL_SETMIXER: - if (!suser()) - return -EACCES; - switch (SCSTATE->revhi) { - case 2: - if (bi.data.mix.mixer_type != SM_MIXER_CT1335) - return -EINVAL; - break; - case 3: - if (bi.data.mix.mixer_type != SM_MIXER_CT1345) - return -EINVAL; - break; - case 4: - if (bi.data.mix.mixer_type != SM_MIXER_CT1745) - return -EINVAL; - break; - default: - return -ENODEV; - } - if (bi.data.mix.reg >= 0x80) - return -EACCES; - save_flags(flags); - cli(); - outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); - outb(bi.data.mix.data, DSP_MIXER_DATA(dev->base_addr)); - restore_flags(flags); - return 0; - - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -const struct hardware_info sm_hw_sbc = { - "sbc", sizeof(struct sc_state_sbc), - sbc_open, sbc_close, sbc_ioctl, sbc_sethw -}; - -/* --------------------------------------------------------------------- */ - -static void setup_dma_fdx_dsp(struct device *dev, struct sm_state *sm) -{ - unsigned long flags; - unsigned int isamps, osamps; - - if (!reset_dsp(dev)) { - printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); - return; - } - save_flags(flags); - cli(); - sbc_int_ack_8bit(dev); - sbc_int_ack_16bit(dev); - /* should eventually change to set rates individually by SBC_SAMPLE_RATE_{IN/OUT} */ - write_dsp(dev, SBC_SAMPLE_RATE_IN); - write_dsp(dev, SCSTATE->sr[0] >> 8); - write_dsp(dev, SCSTATE->sr[0] & 0xff); - write_dsp(dev, SBC_SAMPLE_RATE_OUT); - write_dsp(dev, SCSTATE->sr[1] >> 8); - write_dsp(dev, SCSTATE->sr[1] & 0xff); - write_dsp(dev, SBC_SPEAKER_ON); - if (sm->dma.o16bit) { - /* - * DMA channel 1 (8bit) does input (capture), - * DMA channel 2 (16bit) does output (playback) - */ - isamps = dma_setup(sm, 0, dev->dma) - 1; - osamps = dma_setup(sm, 1, sm->hdrv.ptt_out.dma2) - 1; - sbc_int_ack_8bit(dev); - sbc_int_ack_16bit(dev); - write_dsp(dev, SBC4_IN8_AI); - write_dsp(dev, SBC4_MODE_UNS_MONO); - write_dsp(dev, isamps & 0xff); - write_dsp(dev, isamps >> 8); - write_dsp(dev, SBC4_OUT16_AI); - write_dsp(dev, SBC4_MODE_SIGN_MONO); - write_dsp(dev, osamps & 0xff); - write_dsp(dev, osamps >> 8); - } else { - /* - * DMA channel 1 (8bit) does output (playback), - * DMA channel 2 (16bit) does input (capture) - */ - isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1; - osamps = dma_setup(sm, 1, dev->dma) - 1; - sbc_int_ack_8bit(dev); - sbc_int_ack_16bit(dev); - write_dsp(dev, SBC4_OUT8_AI); - write_dsp(dev, SBC4_MODE_UNS_MONO); - write_dsp(dev, osamps & 0xff); - write_dsp(dev, osamps >> 8); - write_dsp(dev, SBC4_IN16_AI); - write_dsp(dev, SBC4_MODE_SIGN_MONO); - write_dsp(dev, isamps & 0xff); - write_dsp(dev, isamps >> 8); - } - dma_init_receive(sm); - dma_init_transmit(sm); - restore_flags(flags); -} - -/* --------------------------------------------------------------------- */ - -static void sbcfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned char intsrc, pbint = 0, captint = 0; - unsigned int ocfrag, icfrag; - unsigned long flags; - - if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) - return; - save_flags(flags); - cli(); - outb(0x82, DSP_MIXER_ADDR(dev->base_addr)); - intsrc = inb(DSP_MIXER_DATA(dev->base_addr)); - if (intsrc & 0x01) { - sbc_int_ack_8bit(dev); - if (sm->dma.o16bit) { - captint = 1; - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - dma_ptr(sm, 0, dev->dma, &icfrag); - enable_dma(dev->dma); - } else { - pbint = 1; - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - dma_ptr(sm, 1, dev->dma, &ocfrag); - enable_dma(dev->dma); - } - } - if (intsrc & 0x02) { - sbc_int_ack_16bit(dev); - if (sm->dma.o16bit) { - pbint = 1; - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - dma_ptr(sm, 1, sm->hdrv.ptt_out.dma2, &ocfrag); - enable_dma(sm->hdrv.ptt_out.dma2); - } else { - captint = 1; - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag); - enable_dma(sm->hdrv.ptt_out.dma2); - } - } - restore_flags(flags); - sm_int_freq(sm); - sti(); - if (pbint) { - if (dma_end_transmit(sm, ocfrag)) - dma_clear_transmit(sm); - dma_transmit(sm); - } - if (captint) { - dma_receive(sm, icfrag); - hdlcdrv_arbitrate(dev, &sm->hdrv); - } - sm_output_status(sm); - hdlcdrv_transmitter(dev, &sm->hdrv); - hdlcdrv_receiver(dev, &sm->hdrv); -} - -/* --------------------------------------------------------------------- */ - -static int sbcfdx_open(struct device *dev, struct sm_state *sm) -{ - int err; - - if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) { - printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", - sizeof(struct sc_state_sbc), sizeof(sm->m)); - return -ENODEV; - } - if (!dev || !sm) - return -ENXIO; - if (dev->base_addr <= 0 || dev->base_addr > 0x1000-SBC_EXTENT || - dev->irq < 2 || dev->irq > 15 || dev->dma > 3) - return -ENXIO; - if (check_region(dev->base_addr, SBC_EXTENT)) - return -EACCES; - /* - * check if a card is available - */ - if (!reset_dsp(dev)) { - printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n", - sm_drvname, dev->base_addr); - return -ENODEV; - } - write_dsp(dev, SBC_GET_REVISION); - if (!read_dsp(dev, &SCSTATE->revhi) || - !read_dsp(dev, &SCSTATE->revlo)) - return -ENODEV; - printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, - SCSTATE->revhi, SCSTATE->revlo); - if (SCSTATE->revhi < 4) { - printk(KERN_ERR "%s: at least DSP rev 4.00 required\n", sm_drvname); - return -ENODEV; - } - if ((err = config_resources(dev, sm, 1))) { - printk(KERN_ERR "%s: invalid IRQ and/or DMA specified\n", sm_drvname); - return err; - } - /* - * initialize some variables - */ - if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA))) - return -ENOMEM; - if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) { - kfree(sm->dma.ibuf); - return -ENOMEM; - } - dma_init_transmit(sm); - dma_init_receive(sm); - - memset(&sm->m, 0, sizeof(sm->m)); - memset(&sm->d, 0, sizeof(sm->d)); - if (sm->mode_tx->init) - sm->mode_tx->init(sm); - if (sm->mode_rx->init) - sm->mode_rx->init(sm); - - if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree(sm->dma.ibuf); - kfree(sm->dma.obuf); - return -EBUSY; - } - if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { - kfree(sm->dma.ibuf); - kfree(sm->dma.obuf); - free_dma(dev->dma); - return -EBUSY; - } - if (request_irq(dev->irq, sbcfdx_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - kfree(sm->dma.ibuf); - kfree(sm->dma.obuf); - free_dma(dev->dma); - free_dma(sm->hdrv.ptt_out.dma2); - return -EBUSY; - } - request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name); - setup_dma_fdx_dsp(dev, sm); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int sbcfdx_close(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm) - return -EINVAL; - /* - * disable interrupts - */ - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - reset_dsp(dev); - free_irq(dev->irq, dev); - free_dma(dev->dma); - free_dma(sm->hdrv.ptt_out.dma2); - release_region(dev->base_addr, SBC_EXTENT); - kfree(sm->dma.ibuf); - kfree(sm->dma.obuf); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int sbcfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, '.'); - const struct modem_tx_info **mtp = sm_modem_tx_table; - const struct modem_rx_info **mrp; - - if (!strcmp(mode, "off")) { - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return 0; - } - if (cp) - *cp++ = '\0'; - else - cp = mode; - for (; *mtp; mtp++) { - if ((*mtp)->loc_storage > sizeof(sm->m)) { - printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", - sm_drvname, (*mtp)->name, (*mtp)->loc_storage); - continue; - } - if (!(*mtp)->name || strcmp((*mtp)->name, mode)) - continue; - if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100) - continue; - for (mrp = sm_modem_rx_table; *mrp; mrp++) { - if ((*mrp)->loc_storage > sizeof(sm->d)) { - printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", - sm_drvname, (*mrp)->name, (*mrp)->loc_storage); - continue; - } - if ((*mrp)->name && !strcmp((*mrp)->name, cp) && - (*mtp)->srate >= 5000 && (*mtp)->srate <= 44100 && - (*mrp)->srate == (*mtp)->srate) { - sm->mode_tx = *mtp; - sm->mode_rx = *mrp; - SCSTATE->sr[0] = sm->mode_rx->srate; - SCSTATE->sr[1] = sm->mode_tx->srate; - sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; - sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; - if (sm->dma.ifragsz < sm->mode_rx->overlap) - sm->dma.ifragsz = sm->mode_rx->overlap; - if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_u8) { - sm->dma.i16bit = 1; - sm->dma.o16bit = 0; - sm->dma.ifragsz <<= 1; - } else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_s16) { - sm->dma.i16bit = 0; - sm->dma.o16bit = 1; - sm->dma.ofragsz <<= 1; - } else { - printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, - sm->mode_rx->name, sm->mode_tx->name); - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return -EINVAL; - } - return 0; - } - } - } - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int sbcfdx_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | - HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_DMA2 | HDLCDRV_PARMASK_SERIOBASE | - HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; - - return sbc_ioctl(dev, sm, ifr, hi, cmd); -} - -/* --------------------------------------------------------------------- */ - -const struct hardware_info sm_hw_sbcfdx = { - "sbcfdx", sizeof(struct sc_state_sbc), - sbcfdx_open, sbcfdx_close, sbcfdx_ioctl, sbcfdx_sethw -}; - -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/sm_wss.c linux/drivers/net/soundmodem/sm_wss.c --- v2.1.70/linux/drivers/net/soundmodem/sm_wss.c Mon Aug 11 14:47:04 1997 +++ linux/drivers/net/soundmodem/sm_wss.c Wed Dec 31 16:00:00 1969 @@ -1,965 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_wss.c -- soundcard radio modem driver, WSS (half duplex) 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "sm.h" -#include "smdma.h" - -/* --------------------------------------------------------------------- */ - -/* - * 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 - -/* --------------------------------------------------------------------- */ - -struct sc_state_wss { - unsigned char revwss, revid, revv, revcid; - unsigned char fmt[2]; - unsigned char crystal; -}; - -#define SCSTATE ((struct sc_state_wss *)(&sm->hw)) - -/* --------------------------------------------------------------------- */ - -#define WSS_CONFIG(iobase) (iobase+0) -#define WSS_STATUS(iobase) (iobase+3) -#define WSS_CODEC_IA(iobase) (iobase+4) -#define WSS_CODEC_ID(iobase) (iobase+5) -#define WSS_CODEC_STATUS(iobase) (iobase+6) -#define WSS_CODEC_DATA(iobase) (iobase+7) - -#define WSS_EXTENT 8 - -#define CS423X_HOTFIX - -/* --------------------------------------------------------------------- */ - -static void write_codec(struct device *dev, unsigned char idx, - unsigned char data) -{ - int timeout = 900000; - - /* wait until codec ready */ - while (timeout > 0 && inb(WSS_CODEC_IA(dev->base_addr)) & 0x80) - timeout--; - outb(idx, WSS_CODEC_IA(dev->base_addr)); - outb(data, WSS_CODEC_ID(dev->base_addr)); -} - - -/* --------------------------------------------------------------------- */ - -static unsigned char read_codec(struct device *dev, unsigned char idx) -{ - int timeout = 900000; - - /* wait until codec ready */ - while (timeout > 0 && inb(WSS_CODEC_IA(dev->base_addr)) & 0x80) - timeout--; - outb(idx & 0x1f, WSS_CODEC_IA(dev->base_addr)); - return inb(WSS_CODEC_ID(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -extern void inline wss_ack_int(struct device *dev) -{ - outb(0, WSS_CODEC_STATUS(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -static int wss_srate_tab[16] = { - 8000, 5510, 16000, 11025, 27420, 18900, 32000, 22050, - -1, 37800, -1, 44100, 48000, 33075, 9600, 6620 -}; - -static int wss_srate_index(int srate) -{ - int i; - - for (i = 0; i < (sizeof(wss_srate_tab)/sizeof(wss_srate_tab[0])); i++) - if (srate == wss_srate_tab[i] && wss_srate_tab[i] > 0) - return i; - return -1; -} - -/* --------------------------------------------------------------------- */ - -static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, unsigned char fmt, - unsigned char fmt2, char fdx, char fullcalib) -{ - unsigned long time; - unsigned long flags; - - save_flags(flags); - cli(); - /* Clock and data format register */ - write_codec(dev, 0x48, fmt); - if (SCSTATE->crystal) { - write_codec(dev, 0x5c, fmt2 & 0xf0); - /* MCE and interface config reg */ - write_codec(dev, 0x49, (fdx ? 0 : 0x4) | (fullcalib ? 0x18 : 0)); - } else - /* MCE and interface config reg */ - write_codec(dev, 0x49, fdx ? 0x8 : 0xc); - outb(0xb, WSS_CODEC_IA(dev->base_addr)); /* leave MCE */ - if (SCSTATE->crystal && !fullcalib) - return 0; - /* - * wait for ACI start - */ - time = 1000; - while (!(read_codec(dev, 0x0b) & 0x20)) - if (!(--time)) { - printk(KERN_WARNING "%s: ad1848 auto calibration timed out (1)\n", - sm_drvname); - restore_flags(flags); - return -1; - } - /* - * wait for ACI end - */ - sti(); - time = jiffies + HZ/4; - while ((read_codec(dev, 0x0b) & 0x20) && ((signed)(jiffies - time) < 0)); - restore_flags(flags); - if ((signed)(jiffies - time) >= 0) { - printk(KERN_WARNING "%s: ad1848 auto calibration timed out (2)\n", - sm_drvname); - return -1; - } - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wss_init_codec(struct device *dev, struct sm_state *sm, char fdx, - unsigned char src_l, unsigned char src_r, - int igain_l, int igain_r, - int ogain_l, int ogain_r) -{ - unsigned char tmp, reg0, reg1, reg6, reg7; - static const signed char irqtab[16] = - { -1, -1, 0x10, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20, -1, -1, - -1, -1 }; - static const signed char dmatab[4] = { 1, 2, -1, 3 }; - - tmp = inb(WSS_STATUS(dev->base_addr)); - if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x00 && - (tmp & 0x3f) != 0x0f) { - printk(KERN_WARNING "sm: WSS card id register not found, " - "address 0x%lx, ID register 0x%02x\n", - dev->base_addr, (int)tmp); - /* return -1; */ - SCSTATE->revwss = 0; - } else { - if ((tmp & 0x80) && ((dev->dma == 0) || - ((dev->irq >= 8) && (dev->irq != 9)))) { - printk(KERN_ERR "%s: WSS: DMA0 and/or IRQ8..IRQ15 " - "(except IRQ9) cannot be used on an 8bit " - "card\n", sm_drvname); - return -1; - } - if (dev->irq > 15 || irqtab[dev->irq] == -1) { - printk(KERN_ERR "%s: WSS: invalid interrupt %d\n", - sm_drvname, (int)dev->irq); - return -1; - } - if (dev->dma > 3 || dmatab[dev->dma] == -1) { - printk(KERN_ERR "%s: WSS: invalid dma channel %d\n", - sm_drvname, (int)dev->dma); - return -1; - } - tmp = irqtab[dev->irq] | dmatab[dev->dma]; - /* irq probe */ - outb((tmp & 0x38) | 0x40, WSS_CONFIG(dev->base_addr)); - if (!(inb(WSS_STATUS(dev->base_addr)) & 0x40)) { - outb(0, WSS_CONFIG(dev->base_addr)); - printk(KERN_ERR "%s: WSS: IRQ%d is not free!\n", - sm_drvname, dev->irq); - } - outb(tmp, WSS_CONFIG(dev->base_addr)); - SCSTATE->revwss = inb(WSS_STATUS(dev->base_addr)) & 0x3f; - } - /* - * initialize the codec - */ - if (igain_l < 0) - igain_l = 0; - if (igain_r < 0) - igain_r = 0; - if (ogain_l > 0) - ogain_l = 0; - if (ogain_r > 0) - ogain_r = 0; - reg0 = (src_l << 6) & 0xc0; - reg1 = (src_r << 6) & 0xc0; - if (reg0 == 0x80 && igain_l >= 20) { - reg0 |= 0x20; - igain_l -= 20; - } - if (reg1 == 0x80 && igain_r >= 20) { - reg1 |= 0x20; - igain_r -= 20; - } - if (igain_l > 23) - igain_l = 23; - if (igain_r > 23) - igain_r = 23; - reg0 |= igain_l * 2 / 3; - reg1 |= igain_r * 2 / 3; - reg6 = (ogain_l < -95) ? 0x80 : (ogain_l * (-2) / 3); - reg7 = (ogain_r < -95) ? 0x80 : (ogain_r * (-2) / 3); - write_codec(dev, 9, 0); - write_codec(dev, 0, 0x45); - if (read_codec(dev, 0) != 0x45) - goto codec_err; - write_codec(dev, 0, 0xaa); - if (read_codec(dev, 0) != 0xaa) - goto codec_err; - write_codec(dev, 12, 0x40); /* enable MODE2 */ - write_codec(dev, 16, 0); - write_codec(dev, 0, 0x45); - SCSTATE->crystal = (read_codec(dev, 16) != 0x45); - write_codec(dev, 0, 0xaa); - SCSTATE->crystal &= (read_codec(dev, 16) != 0xaa); - if (SCSTATE->crystal) { - SCSTATE->revcid = read_codec(dev, 0x19); - SCSTATE->revv = (SCSTATE->revcid >> 5) & 7; - SCSTATE->revcid &= 7; - write_codec(dev, 0x10, 0x80); /* maximum output level */ - write_codec(dev, 0x11, 0x02); /* xtal enable and no HPF */ - write_codec(dev, 0x12, 0x80); /* left line input control */ - write_codec(dev, 0x13, 0x80); /* right line input control */ - write_codec(dev, 0x16, 0); /* disable alternative freq sel */ - write_codec(dev, 0x1a, 0xe0); /* mono IO disable */ - write_codec(dev, 0x1b, 0x00); /* left out no att */ - write_codec(dev, 0x1d, 0x00); /* right out no att */ - } - - if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], SCSTATE->fmt[0], fdx, 1)) - goto codec_err; - - write_codec(dev, 0, reg0); /* left input control */ - write_codec(dev, 1, reg1); /* right input control */ - write_codec(dev, 2, 0x80); /* left aux#1 input control */ - write_codec(dev, 3, 0x80); /* right aux#1 input control */ - write_codec(dev, 4, 0x80); /* left aux#2 input control */ - write_codec(dev, 5, 0x80); /* right aux#2 input control */ - write_codec(dev, 6, reg6); /* left dac control */ - write_codec(dev, 7, reg7); /* right dac control */ - write_codec(dev, 0xa, 0x2); /* pin control register */ - write_codec(dev, 0xd, 0x0); /* digital mix control */ - SCSTATE->revid = read_codec(dev, 0xc) & 0xf; - /* - * print revisions - */ - if (SCSTATE->crystal) - printk(KERN_INFO "%s: Crystal CODEC ID %d, Chip revision %d, " - " Chip ID %d\n", sm_drvname, (int)SCSTATE->revid, - (int)SCSTATE->revv, (int)SCSTATE->revcid); - else - printk(KERN_INFO "%s: WSS revision %d, CODEC revision %d\n", - sm_drvname, (int)SCSTATE->revwss, - (int)SCSTATE->revid); - return 0; - codec_err: - outb(0, WSS_CONFIG(dev->base_addr)); - printk(KERN_ERR "%s: no WSS soundcard found at address 0x%lx\n", - sm_drvname, dev->base_addr); - return -1; -} - -/* --------------------------------------------------------------------- */ - -static void setup_dma_wss(struct device *dev, struct sm_state *sm, int send) -{ - unsigned long flags; - static const unsigned char codecmode[2] = { 0x0e, 0x0d }; - unsigned char oldcodecmode; - long abrt; - unsigned char fmt; - unsigned int numsamps; - - send = !!send; - fmt = SCSTATE->fmt[send]; - save_flags(flags); - cli(); - /* - * perform the final DMA sequence to disable the codec request - */ - oldcodecmode = read_codec(dev, 9); - write_codec(dev, 9, 0xc); /* disable codec */ - wss_ack_int(dev); - if (read_codec(dev, 11) & 0x10) { - dma_setup(sm, oldcodecmode & 1, dev->dma); - abrt = 0; - while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000)); - } -#ifdef CS423X_HOTFIX - if (read_codec(dev, 0x8) != fmt || SCSTATE->crystal) - wss_set_codec_fmt(dev, sm, fmt, fmt, 0, 0); -#else /* CS423X_HOTFIX */ - if (read_codec(dev, 0x8) != fmt) - wss_set_codec_fmt(dev, sm, fmt, fmt, 0, 0); -#endif /* CS423X_HOTFIX */ - numsamps = dma_setup(sm, send, dev->dma) - 1; - write_codec(dev, 15, numsamps & 0xff); - write_codec(dev, 14, numsamps >> 8); - write_codec(dev, 9, codecmode[send]); - restore_flags(flags); -} - -/* --------------------------------------------------------------------- */ - -static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned int curfrag; - unsigned int nums; - - if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || - sm->hdrv.magic != HDLCDRV_MAGIC) - return; - cli(); - wss_ack_int(dev); - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - nums = dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag) - 1; - write_codec(dev, 15, nums & 0xff); - write_codec(dev, 14, nums >> 8); - enable_dma(dev->dma); - sm_int_freq(sm); - sti(); - if (sm->dma.ptt_cnt <= 0) { - dma_receive(sm, curfrag); - hdlcdrv_arbitrate(dev, &sm->hdrv); - if (hdlcdrv_ptt(&sm->hdrv)) { - /* starting to transmit */ - disable_dma(dev->dma); - hdlcdrv_transmitter(dev, &sm->hdrv); /* prefill HDLC buffer */ - dma_start_transmit(sm); - setup_dma_wss(dev, sm, 1); - dma_transmit(sm); - } - } else if (dma_end_transmit(sm, curfrag)) { - /* stopping transmission */ - disable_dma(dev->dma); - dma_init_receive(sm); - setup_dma_wss(dev, sm, 0); - } else - dma_transmit(sm); - sm_output_status(sm); - hdlcdrv_transmitter(dev, &sm->hdrv); - hdlcdrv_receiver(dev, &sm->hdrv); -} - -/* --------------------------------------------------------------------- */ - -static int wss_open(struct device *dev, struct sm_state *sm) -{ - unsigned int dmasz, u; - - if (sizeof(sm->m) < sizeof(struct sc_state_wss)) { - printk(KERN_ERR "sm wss: wss state too big: %d > %d\n", - sizeof(struct sc_state_wss), sizeof(sm->m)); - return -ENODEV; - } - if (!dev || !sm || !sm->mode_rx || !sm->mode_tx) - return -ENXIO; - if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || - dev->irq < 2 || dev->irq > 15 || dev->dma > 3) - return -ENXIO; - if (check_region(dev->base_addr, WSS_EXTENT)) - return -EACCES; - /* - * check if a card is available - */ - if (wss_init_codec(dev, sm, 0, 1, 1, 0, 0, -45, -45)) - return -ENODEV; - /* - * initialize some variables - */ - dma_init_receive(sm); - dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz; - u = NUM_FRAGMENTS * sm->dma.ofragsz; - if (u > dmasz) - dmasz = u; - if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA))) - return -ENOMEM; - dma_init_transmit(sm); - dma_init_receive(sm); - - memset(&sm->m, 0, sizeof(sm->m)); - memset(&sm->d, 0, sizeof(sm->d)); - if (sm->mode_tx->init) - sm->mode_tx->init(sm); - if (sm->mode_rx->init) - sm->mode_rx->init(sm); - - if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(sm->dma.obuf, dmasz); - return -EBUSY; - } - if (request_irq(dev->irq, wss_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - free_dma(dev->dma); - kfree_s(sm->dma.obuf, dmasz); - return -EBUSY; - } - request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); - setup_dma_wss(dev, sm, 0); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wss_close(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm) - return -EINVAL; - /* - * disable interrupts - */ - disable_dma(dev->dma); - write_codec(dev, 9, 0xc); /* disable codec */ - free_irq(dev->irq, dev); - free_dma(dev->dma); - release_region(dev->base_addr, WSS_EXTENT); - kfree(sm->dma.obuf); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wss_sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, '.'); - const struct modem_tx_info **mtp = sm_modem_tx_table; - const struct modem_rx_info **mrp; - int i, j; - - if (!strcmp(mode, "off")) { - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return 0; - } - if (cp) - *cp++ = '\0'; - else - cp = mode; - for (; *mtp; mtp++) { - if ((*mtp)->loc_storage > sizeof(sm->m)) { - printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", - sm_drvname, (*mtp)->name, (*mtp)->loc_storage); - continue; - } - if (!(*mtp)->name || strcmp((*mtp)->name, mode)) - continue; - if ((i = wss_srate_index((*mtp)->srate)) < 0) - continue; - for (mrp = sm_modem_rx_table; *mrp; mrp++) { - if ((*mrp)->loc_storage > sizeof(sm->d)) { - printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", - sm_drvname, (*mrp)->name, (*mrp)->loc_storage); - continue; - } - if ((*mrp)->name && !strcmp((*mrp)->name, cp) && - ((j = wss_srate_index((*mrp)->srate)) >= 0)) { - sm->mode_tx = *mtp; - sm->mode_rx = *mrp; - SCSTATE->fmt[0] = j; - SCSTATE->fmt[1] = i; - sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; - sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; - if (sm->dma.ifragsz < sm->mode_rx->overlap) - sm->dma.ifragsz = sm->mode_rx->overlap; - /* prefer same data format if possible to minimize switching times */ - sm->dma.i16bit = sm->dma.o16bit = 2; - if (sm->mode_rx->srate == sm->mode_tx->srate) { - if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_s16) - sm->dma.i16bit = sm->dma.o16bit = 1; - else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_u8) - sm->dma.i16bit = sm->dma.o16bit = 0; - } - if (sm->dma.i16bit == 2) { - if (sm->mode_rx->demodulator_s16) - sm->dma.i16bit = 1; - else if (sm->mode_rx->demodulator_u8) - sm->dma.i16bit = 0; - } - if (sm->dma.o16bit == 2) { - if (sm->mode_tx->modulator_s16) - sm->dma.o16bit = 1; - else if (sm->mode_tx->modulator_u8) - sm->dma.o16bit = 0; - } - if (sm->dma.i16bit == 2 || sm->dma.o16bit == 2) { - printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, - sm->mode_rx->name, sm->mode_tx->name); - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return -EINVAL; - } -#ifdef __BIG_ENDIAN - /* big endian 16bit only works on crystal cards... */ - if (sm->dma.i16bit) { - SCSTATE->fmt[0] |= 0xc0; - sm->dma.ifragsz <<= 1; - } - if (sm->dma.o16bit) { - SCSTATE->fmt[1] |= 0xc0; - sm->dma.ofragsz <<= 1; - } -#else /* __BIG_ENDIAN */ - if (sm->dma.i16bit) { - SCSTATE->fmt[0] |= 0x40; - sm->dma.ifragsz <<= 1; - } - if (sm->dma.o16bit) { - SCSTATE->fmt[1] |= 0x40; - sm->dma.ofragsz <<= 1; - } -#endif /* __BIG_ENDIAN */ - return 0; - } - } - } - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int wss_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct sm_ioctl bi; - int i; - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | - HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | - HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; - - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - - switch (bi.cmd) { - default: - return -ENOIOCTLCMD; - - case SMCTL_GETMIXER: - i = 0; - bi.data.mix.sample_rate = sm->mode_rx->srate; - bi.data.mix.bit_rate = sm->hdrv.par.bitrate; - bi.data.mix.mixer_type = SCSTATE->crystal ? - SM_MIXER_CRYSTAL : SM_MIXER_AD1848; - if (((SCSTATE->crystal ? 0x2c0c20fflu: 0x20fflu) - >> bi.data.mix.reg) & 1) { - bi.data.mix.data = read_codec(dev, bi.data.mix.reg); - i = 1; - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return i; - - case SMCTL_SETMIXER: - if (!suser()) - return -EACCES; - if ((bi.data.mix.mixer_type != SM_MIXER_CRYSTAL || - !SCSTATE->crystal) && - (bi.data.mix.mixer_type != SM_MIXER_AD1848 || - bi.data.mix.reg >= 0x10)) - return -EINVAL; - if (!((0x2c0c20fflu >> bi.data.mix.reg) & 1)) - return -EACCES; - write_codec(dev, bi.data.mix.reg, bi.data.mix.data); - return 0; - - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -const struct hardware_info sm_hw_wss = { - "wss", sizeof(struct sc_state_wss), - wss_open, wss_close, wss_ioctl, wss_sethw -}; - -/* --------------------------------------------------------------------- */ - -static void setup_fdx_dma_wss(struct device *dev, struct sm_state *sm) -{ - unsigned long flags; - unsigned char oldcodecmode, codecdma; - long abrt; - unsigned int osamps, isamps; - - save_flags(flags); - cli(); - /* - * perform the final DMA sequence to disable the codec request - */ - oldcodecmode = read_codec(dev, 9); - write_codec(dev, 9, 0); /* disable codec DMA */ - wss_ack_int(dev); - if ((codecdma = read_codec(dev, 11)) & 0x10) { - dma_setup(sm, 1, dev->dma); - dma_setup(sm, 0, sm->hdrv.ptt_out.dma2); - abrt = 0; - while (((codecdma = read_codec(dev, 11)) & 0x10) || ((++abrt) >= 0x10000)); - } - wss_set_codec_fmt(dev, sm, SCSTATE->fmt[1], SCSTATE->fmt[0], 1, 1); - osamps = dma_setup(sm, 1, dev->dma) - 1; - isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1; - write_codec(dev, 15, osamps & 0xff); - write_codec(dev, 14, osamps >> 8); - if (SCSTATE->crystal) { - write_codec(dev, 31, isamps & 0xff); - write_codec(dev, 30, isamps >> 8); - } - write_codec(dev, 9, 3); - restore_flags(flags); -} - -/* --------------------------------------------------------------------- */ - -static void wssfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned long flags; - unsigned char cry_int_src; - unsigned icfrag, ocfrag, isamps, osamps; - - if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || - sm->hdrv.magic != HDLCDRV_MAGIC) - return; - save_flags(flags); - cli(); - if (SCSTATE->crystal) { - /* Crystal has an essentially different interrupt handler! */ - cry_int_src = read_codec(dev, 0x18); - wss_ack_int(dev); - if (cry_int_src & 0x10) { /* playback interrupt */ - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1; - write_codec(dev, 15, osamps & 0xff); - write_codec(dev, 14, osamps >> 8); - enable_dma(dev->dma); - } - if (cry_int_src & 0x20) { /* capture interrupt */ - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1; - write_codec(dev, 31, isamps & 0xff); - write_codec(dev, 30, isamps >> 8); - enable_dma(sm->hdrv.ptt_out.dma2); - } - restore_flags(flags); - sm_int_freq(sm); - sti(); - if (cry_int_src & 0x10) { - if (dma_end_transmit(sm, ocfrag)) - dma_clear_transmit(sm); - dma_transmit(sm); - } - if (cry_int_src & 0x20) { - dma_receive(sm, icfrag); - hdlcdrv_arbitrate(dev, &sm->hdrv); - } - sm_output_status(sm); - hdlcdrv_transmitter(dev, &sm->hdrv); - hdlcdrv_receiver(dev, &sm->hdrv); - return; - } - wss_ack_int(dev); - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(dev->dma); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1; - isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1; - write_codec(dev, 15, osamps & 0xff); - write_codec(dev, 14, osamps >> 8); - if (SCSTATE->crystal) { - write_codec(dev, 31, isamps & 0xff); - write_codec(dev, 30, isamps >> 8); - } - enable_dma(dev->dma); - enable_dma(sm->hdrv.ptt_out.dma2); - restore_flags(flags); - sm_int_freq(sm); - sti(); - if (dma_end_transmit(sm, ocfrag)) - dma_clear_transmit(sm); - dma_transmit(sm); - dma_receive(sm, icfrag); - hdlcdrv_arbitrate(dev, &sm->hdrv); - sm_output_status(sm); - hdlcdrv_transmitter(dev, &sm->hdrv); - hdlcdrv_receiver(dev, &sm->hdrv); -} - -/* --------------------------------------------------------------------- */ - -static int wssfdx_open(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm || !sm->mode_rx || !sm->mode_tx) - return -ENXIO; - if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || - dev->irq < 2 || dev->irq > 15 || dev->dma > 3) - return -ENXIO; - if (check_region(dev->base_addr, WSS_EXTENT)) - return -EACCES; - /* - * check if a card is available - */ - if (wss_init_codec(dev, sm, 1, 1, 1, 0, 0, -45, -45)) - return -ENODEV; - /* - * initialize some variables - */ - if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA))) - return -ENOMEM; - if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) { - kfree(sm->dma.ibuf); - return -ENOMEM; - } - dma_init_transmit(sm); - dma_init_receive(sm); - - memset(&sm->m, 0, sizeof(sm->m)); - memset(&sm->d, 0, sizeof(sm->d)); - if (sm->mode_tx->init) - sm->mode_tx->init(sm); - if (sm->mode_rx->init) - sm->mode_rx->init(sm); - - if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree(sm->dma.ibuf); - kfree(sm->dma.obuf); - return -EBUSY; - } - if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { - kfree(sm->dma.ibuf); - kfree(sm->dma.obuf); - free_dma(dev->dma); - return -EBUSY; - } - if (request_irq(dev->irq, wssfdx_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - kfree(sm->dma.ibuf); - kfree(sm->dma.obuf); - free_dma(dev->dma); - free_dma(sm->hdrv.ptt_out.dma2); - return -EBUSY; - } - request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); - setup_fdx_dma_wss(dev, sm); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wssfdx_close(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm) - return -EINVAL; - /* - * disable interrupts - */ - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - write_codec(dev, 9, 0xc); /* disable codec */ - free_irq(dev->irq, dev); - free_dma(dev->dma); - free_dma(sm->hdrv.ptt_out.dma2); - release_region(dev->base_addr, WSS_EXTENT); - kfree(sm->dma.ibuf); - kfree(sm->dma.obuf); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wssfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, '.'); - const struct modem_tx_info **mtp = sm_modem_tx_table; - const struct modem_rx_info **mrp; - int i; - - if (!strcmp(mode, "off")) { - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return 0; - } - if (cp) - *cp++ = '\0'; - else - cp = mode; - for (; *mtp; mtp++) { - if ((*mtp)->loc_storage > sizeof(sm->m)) { - printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", - sm_drvname, (*mtp)->name, (*mtp)->loc_storage); - continue; - } - if (!(*mtp)->name || strcmp((*mtp)->name, mode)) - continue; - if ((i = wss_srate_index((*mtp)->srate)) < 0) - continue; - for (mrp = sm_modem_rx_table; *mrp; mrp++) { - if ((*mrp)->loc_storage > sizeof(sm->d)) { - printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", - sm_drvname, (*mrp)->name, (*mrp)->loc_storage); - continue; - } - if ((*mrp)->name && !strcmp((*mrp)->name, cp) && - (*mtp)->srate == (*mrp)->srate) { - sm->mode_tx = *mtp; - sm->mode_rx = *mrp; - SCSTATE->fmt[0] = SCSTATE->fmt[1] = i; - sm->dma.ifragsz = sm->dma.ofragsz = (sm->mode_rx->srate + 50)/100; - if (sm->dma.ifragsz < sm->mode_rx->overlap) - sm->dma.ifragsz = sm->mode_rx->overlap; - sm->dma.i16bit = sm->dma.o16bit = 2; - if (sm->mode_rx->demodulator_s16) { - sm->dma.i16bit = 1; - sm->dma.ifragsz <<= 1; -#ifdef __BIG_ENDIAN /* big endian 16bit only works on crystal cards... */ - SCSTATE->fmt[0] |= 0xc0; -#else /* __BIG_ENDIAN */ - SCSTATE->fmt[0] |= 0x40; -#endif /* __BIG_ENDIAN */ - } else if (sm->mode_rx->demodulator_u8) - sm->dma.i16bit = 0; - if (sm->mode_tx->modulator_s16) { - sm->dma.o16bit = 1; - sm->dma.ofragsz <<= 1; -#ifdef __BIG_ENDIAN /* big endian 16bit only works on crystal cards... */ - SCSTATE->fmt[1] |= 0xc0; -#else /* __BIG_ENDIAN */ - SCSTATE->fmt[1] |= 0x40; -#endif /* __BIG_ENDIAN */ - } else if (sm->mode_tx->modulator_u8) - sm->dma.o16bit = 0; - if (sm->dma.i16bit == 2 || sm->dma.o16bit == 2) { - printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, - sm->mode_rx->name, sm->mode_tx->name); - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return -EINVAL; - } - return 0; - } - } - } - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int wssfdx_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | - HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_DMA2 | - HDLCDRV_PARMASK_SERIOBASE | HDLCDRV_PARMASK_PARIOBASE | - HDLCDRV_PARMASK_MIDIIOBASE; - - return wss_ioctl(dev, sm, ifr, hi, cmd); -} - -/* --------------------------------------------------------------------- */ - -const struct hardware_info sm_hw_wssfdx = { - "wssfdx", sizeof(struct sc_state_wss), - wssfdx_open, wssfdx_close, wssfdx_ioctl, wssfdx_sethw -}; - -/* --------------------------------------------------------------------- */ - -#undef SCSTATE diff -u --recursive --new-file v2.1.70/linux/drivers/net/soundmodem/smdma.h linux/drivers/net/soundmodem/smdma.h --- v2.1.70/linux/drivers/net/soundmodem/smdma.h Mon Aug 11 14:47:04 1997 +++ linux/drivers/net/soundmodem/smdma.h Wed Dec 31 16:00:00 1969 @@ -1,217 +0,0 @@ -/*****************************************************************************/ - -/* - * smdma.h -- soundcard radio modem driver dma buffer routines. - * - * 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. - * - */ - -#ifndef _SMDMA_H -#define _SMDMA_H - -/* ---------------------------------------------------------------------- */ - -#include "sm.h" - -/* ---------------------------------------------------------------------- */ - -#define DMA_MODE_AUTOINIT 0x10 -#define NUM_FRAGMENTS 4 - -/* - * NOTE: make sure that hdlcdrv_hdlcbuffer contains enough space - * for the modulator to fill the whole DMA buffer without underrun - * at the highest possible baud rate, otherwise the TX state machine will - * not work correctly. That is (9k6 FSK): HDLCDRV_HDLCBUFFER > 6*NUM_FRAGMENTS - */ - -/* --------------------------------------------------------------------- */ -/* - * ===================== DMA buffer management =========================== - */ - -/* - * returns the number of samples per fragment - */ -extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr) -{ - if (send) { - disable_dma(dmanr); - clear_dma_ff(dmanr); - set_dma_mode(dmanr, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); - set_dma_addr(dmanr, virt_to_bus(sm->dma.obuf)); - set_dma_count(dmanr, sm->dma.ofragsz * NUM_FRAGMENTS); - enable_dma(dmanr); - if (sm->dma.o16bit) - return sm->dma.ofragsz/2; - return sm->dma.ofragsz; - } else { - disable_dma(dmanr); - clear_dma_ff(dmanr); - set_dma_mode(dmanr, DMA_MODE_READ | DMA_MODE_AUTOINIT); - set_dma_addr(dmanr, virt_to_bus(sm->dma.ibuf)); - set_dma_count(dmanr, sm->dma.ifragsz * NUM_FRAGMENTS); - enable_dma(dmanr); - if (sm->dma.i16bit) - return sm->dma.ifragsz/2; - return sm->dma.ifragsz; - } -} - -/* --------------------------------------------------------------------- */ - -extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr, - unsigned int *curfrag) -{ - unsigned int dmaptr, sz, frg, offs; - - dmaptr = get_dma_residue(dmanr); - if (send) { - sz = sm->dma.ofragsz * NUM_FRAGMENTS; - if (dmaptr == 0 || dmaptr > sz) - dmaptr = sz; - dmaptr--; - frg = dmaptr / sm->dma.ofragsz; - offs = (dmaptr % sm->dma.ofragsz) + 1; - *curfrag = NUM_FRAGMENTS - 1 - frg; -#ifdef SM_DEBUG - if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue) - sm->debug_vals.dma_residue = offs; -#endif /* SM_DEBUG */ - if (sm->dma.o16bit) - return offs/2; - return offs; - } else { - sz = sm->dma.ifragsz * NUM_FRAGMENTS; - if (dmaptr == 0 || dmaptr > sz) - dmaptr = sz; - dmaptr--; - frg = dmaptr / sm->dma.ifragsz; - offs = (dmaptr % sm->dma.ifragsz) + 1; - *curfrag = NUM_FRAGMENTS - 1 - frg; -#ifdef SM_DEBUG - if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue) - sm->debug_vals.dma_residue = offs; -#endif /* SM_DEBUG */ - if (sm->dma.i16bit) - return offs/2; - return offs; - } -} - -/* --------------------------------------------------------------------- */ - -extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag) -{ - unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS; - - sm->dma.ofragptr = curfrag; - if (sm->dma.ptt_cnt <= 0) { - sm->dma.ptt_cnt = 0; - return 0; - } - sm->dma.ptt_cnt -= diff; - if (sm->dma.ptt_cnt <= 0) { - sm->dma.ptt_cnt = 0; - return -1; - } - return 0; -} - -extern __inline__ void dma_transmit(struct sm_state *sm) -{ - void *p; - - while (sm->dma.ptt_cnt < NUM_FRAGMENTS && hdlcdrv_ptt(&sm->hdrv)) { - p = (unsigned char *)sm->dma.obuf + sm->dma.ofragsz * - ((sm->dma.ofragptr + sm->dma.ptt_cnt) % NUM_FRAGMENTS); - if (sm->dma.o16bit) { - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator_s16(sm, p, sm->dma.ofragsz/2)); - } else { - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator_u8(sm, p, sm->dma.ofragsz)); - } - sm->dma.ptt_cnt++; - } -} - -extern __inline__ void dma_init_transmit(struct sm_state *sm) -{ - sm->dma.ofragptr = 0; - sm->dma.ptt_cnt = 0; -} - -extern __inline__ void dma_start_transmit(struct sm_state *sm) -{ - sm->dma.ofragptr = 0; - if (sm->dma.o16bit) { - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator_s16(sm, sm->dma.obuf, sm->dma.ofragsz/2)); - } else { - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator_u8(sm, sm->dma.obuf, sm->dma.ofragsz)); - } - sm->dma.ptt_cnt = 1; -} - -extern __inline__ void dma_clear_transmit(struct sm_state *sm) -{ - sm->dma.ptt_cnt = 0; - memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS); -} - -/* --------------------------------------------------------------------- */ - -extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag) -{ - void *p; - - while (sm->dma.ifragptr != curfrag) { - if (sm->dma.ifragptr) - p = (unsigned char *)sm->dma.ibuf + - sm->dma.ifragsz * sm->dma.ifragptr; - else { - p = (unsigned char *)sm->dma.ibuf + NUM_FRAGMENTS * sm->dma.ifragsz; - memcpy(p, sm->dma.ibuf, sm->dma.ifragsz); - } - if (sm->dma.o16bit) { - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator_s16(sm, p, sm->dma.ifragsz/2)); - } else { - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator_u8(sm, p, sm->dma.ifragsz)); - } - sm->dma.ifragptr = (sm->dma.ifragptr + 1) % NUM_FRAGMENTS; - } -} - -extern __inline__ void dma_init_receive(struct sm_state *sm) -{ - sm->dma.ifragptr = 0; -} - -/* --------------------------------------------------------------------- */ -#endif /* _SMDMA_H */ - - - diff -u --recursive --new-file v2.1.70/linux/drivers/net/z8530.h linux/drivers/net/z8530.h --- v2.1.70/linux/drivers/net/z8530.h Tue Oct 29 05:33:39 1996 +++ linux/drivers/net/z8530.h Wed Dec 31 16:00:00 1969 @@ -1,243 +0,0 @@ - -/* 8530 Serial Communications Controller Register definitions */ -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ -#define INT_ERR_Rx 0x18 /* Int on error only */ - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENABLE 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ - -/* Write Register 4 */ - -#define PAR_ENA 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENABL 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define ZCIE 2 /* Zero count IE */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define CRC_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ - -/* 8580/85180/85280 Enhanced SCC register definitions */ - -/* Write Register 7' (SDLC/HDLC Programmable Enhancements) */ -#define AUTOTXF 0x01 /* Auto Tx Flag */ -#define AUTOEOM 0x02 /* Auto EOM Latch Reset */ -#define AUTORTS 0x04 /* Auto RTS */ -#define TXDNRZI 0x08 /* TxD Pulled High in SDLC NRZI mode */ -#define FASTDTR 0x10 /* Fast DTR/REQ Mode */ -#define CRCCBCR 0x20 /* CRC Check Bytes Completely Received */ -#define EXTRDEN 0x40 /* Extended Read Enabled */ - -/* Write Register 15 (external/status interrupt control) */ -#define SHDLCE 1 /* SDLC/HDLC Enhancements Enable */ -#define FIFOE 4 /* FIFO Enable */ - -/* Read Register 6 (frame status FIFO) */ -#define BCLSB 0xff /* LSB of 14 bits count */ - -/* Read Register 7 (frame status FIFO) */ -#define BCMSB 0x3f /* MSB of 14 bits count */ -#define FDA 0x40 /* FIFO Data Available Status */ -#define FOY 0x80 /* FIFO Overflow Status */ diff -u --recursive --new-file v2.1.70/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.1.70/linux/drivers/pci/pci.c Mon Dec 1 12:04:13 1997 +++ linux/drivers/pci/pci.c Thu Dec 4 12:58:01 1997 @@ -60,9 +60,11 @@ DEVICE( NCR, NCR_53C895, "53c895"), DEVICE( NCR, NCR_53C885, "53c885"), DEVICE( NCR, NCR_53C875, "53c875"), + DEVICE( NCR, NCR_53C876, "53c876"), DEVICE( ATI, ATI_68800, "68800AX"), DEVICE( ATI, ATI_215CT222, "215CT222"), DEVICE( ATI, ATI_210888CX, "210888CX"), + DEVICE( ATI, ATI_215GB, "Mach64 GB"), DEVICE( ATI, ATI_215GP, "Mach64 GP (Rage Pro)"), DEVICE( ATI, ATI_215GT, "Mach64 GT (Rage II)"), DEVICE( ATI, ATI_215GTB, "Mach64 GT (Rage II)"), @@ -72,7 +74,9 @@ DEVICE( VLSI, VLSI_82C593, "82C593-FC1"), DEVICE( VLSI, VLSI_82C594, "82C594-AFC2"), DEVICE( VLSI, VLSI_82C597, "82C597-AFC2"), - DEVICE( VLSI, VLSI_VAS96011, "VAS96011 PowerPC"), + DEVICE( VLSI, VLSI_82C541, "82C541 Lynx"), + DEVICE( VLSI, VLSI_82C543, "82C543 Lynx ISA"), + DEVICE( VLSI, VLSI_VAS96011, "VAS96011 (Golden Gate II)"), DEVICE( ADL, ADL_2301, "2301"), DEVICE( NS, NS_87415, "87415"), DEVICE( NS, NS_87410, "87410"), @@ -108,6 +112,7 @@ DEVICE( CIRRUS, CIRRUS_7543, "CL 7543"), DEVICE( CIRRUS, CIRRUS_7541, "CL 7541"), DEVICE( IBM, IBM_FIRE_CORAL, "Fire Coral"), + DEVICE( IBM, IBM_TR, "Token Ring"), DEVICE( IBM, IBM_82G2675, "82G2675"), DEVICE( IBM, IBM_82351, "82351"), DEVICE( WD, WD_7197, "WD 7197"), @@ -116,6 +121,7 @@ DEVICE( TRIDENT, TRIDENT_9420, "TG 9420"), DEVICE( TRIDENT, TRIDENT_9440, "TG 9440"), DEVICE( TRIDENT, TRIDENT_9660, "TG 9660"), + DEVICE( TRIDENT, TRIDENT_9750, "Image 975"), DEVICE( AI, AI_M1435, "M1435"), DEVICE( MATROX, MATROX_MGA_2, "Atlas PX2085"), DEVICE( MATROX, MATROX_MIL, "Millennium"), @@ -127,6 +133,7 @@ DEVICE( CT, CT_65550, "65550"), DEVICE( CT, CT_65554, "65554"), DEVICE( MIRO, MIRO_36050, "ZR36050"), + DEVICE( NEC, NEC_PCX2, "PowerVR PCX2"), DEVICE( FD, FD_36C70, "TMC-18C30"), DEVICE( SI, SI_6201, "6201"), DEVICE( SI, SI_6202, "6202"), @@ -139,6 +146,7 @@ DEVICE( SI, SI_5511, "85C5511"), DEVICE( SI, SI_5513, "85C5513"), DEVICE( SI, SI_5571, "5571"), + DEVICE( SI, SI_5597, "5597"), DEVICE( SI, SI_7001, "7001"), DEVICE( HP, HP_J2585A, "J2585A"), DEVICE( HP, HP_J2585B, "J2585B (Lassen)"), @@ -149,12 +157,17 @@ DEVICE( OPTI, OPTI_82C557, "82C557"), DEVICE( OPTI, OPTI_82C558, "82C558"), DEVICE( OPTI, OPTI_82C621, "82C621"), + DEVICE( OPTI, OPTI_82C700, "82C700"), + DEVICE( OPTI, OPTI_82C701, "82C701 FireStar Plus"), + DEVICE( OPTI, OPTI_82C814, "82C814 Firebridge 1"), DEVICE( OPTI, OPTI_82C822, "82C822"), DEVICE( SGS, SGS_2000, "STG 2000X"), DEVICE( SGS, SGS_1764, "STG 1764X"), DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC"), DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER, "MultiMaster"), DEVICE( BUSLOGIC, BUSLOGIC_FLASHPOINT, "FlashPoint"), + DEVICE( TI, TI_TVP4010, "TVP4010 Permedia"), + DEVICE( TI, TI_TVP4020, "TVP4020 Permedia 2"), DEVICE( TI, TI_PCI1130, "PCI1130"), DEVICE( TI, TI_PCI1131, "PCI1131"), DEVICE( OAK, OAK_OTI107, "OTI107"), @@ -229,9 +242,11 @@ DEVICE( AL, AL_M4803, "M4803"), DEVICE( AL, AL_M5219, "M5219"), DEVICE( AL, AL_M5229, "M5229 TXpro"), + DEVICE( SURECOM, SURECOM_NE34, "NE-34PCI LAN"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2070, "Magicgraph NM2070"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"), DEVICE( ASP, ASP_ABP940, "ABP940"), DEVICE( ASP, ASP_ABP940U, "ABP940U"), DEVICE( CERN, CERN_SPSB_PMC, "STAR/RD24 SCI-PCI (PMC)"), @@ -301,6 +316,7 @@ DEVICE( ALLIANCE, ALLIANCE_PROMOTIO, "Promotion-6410"), DEVICE( ALLIANCE, ALLIANCE_PROVIDEO, "Provideo"), DEVICE( ALLIANCE, ALLIANCE_AT24, "AT24"), + DEVICE( ALLIANCE, ALLIANCE_AT3D, "AT3D"), DEVICE( VMIC, VMIC_VME, "VMIVME-7587"), DEVICE( DIGI, DIGI_RIGHTSWITCH, "RightSwitch SE-6"), DEVICE( MUTECH, MUTECH_MV1000, "MV-1000"), @@ -310,9 +326,11 @@ DEVICE( ZEITNET, ZEITNET_1221, "1221"), DEVICE( ZEITNET, ZEITNET_1225, "1225"), DEVICE( OMEGA, OMEGA_82C092G, "82C092G"), + DEVICE( LITEON, LITEON_LNE100TX,"LNE100TX"), DEVICE( NP, NP_PCI_FDDI, "NP-PCI"), DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"), DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"), + DEVICE( AURAVISION, AURAVISION_VXP524,"VXP524"), DEVICE( IKON, IKON_10115, "10115 Greensheet"), DEVICE( IKON, IKON_10117, "10117 Greensheet"), DEVICE( ZORAN, ZORAN_36057, "ZR36057"), @@ -336,7 +354,7 @@ DEVICE( OPTIBASE, OPTIBASE_VQUEST,"VideoQuest"), DEVICE( ENSONIQ, ENSONIQ_AUDIOPCI,"AudioPCI"), DEVICE( PICTUREL, PICTUREL_PCIVST,"PCIVST"), - DEVICE( NVIDIA, NVIDIA_RIVA128, "Riva 128"), + DEVICE( NVIDIA_SGS, NVIDIA_SGS_RIVA128, "Riva 128"), DEVICE( SYMPHONY, SYMPHONY_101, "82C101"), DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"), DEVICE( 3DLABS, 3DLABS_300SX, "GLINT 300SX"), @@ -390,11 +408,14 @@ DEVICE( INTEL, INTEL_82371AB, "82371AB PIIX4 IDE"), DEVICE( INTEL, INTEL_82371AB_2,"82371AB PIIX4 USB"), DEVICE( INTEL, INTEL_82371AB_3,"82371AB PIIX4 ACPI"), + DEVICE( INTEL, INTEL_82443LX_0,"440LX - 82443LX PAC Host"), + DEVICE( INTEL, INTEL_82443LX_1,"440LX - 82443LX PAC AGP"), DEVICE( INTEL, INTEL_P6, "Orion P6"), DEVICE( INTEL, INTEL_82450GX, "82450GX Orion P6"), DEVICE( KTI, KTI_ET32P2, "ET32P2"), DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"), + DEVICE( ADAPTEC, ADAPTEC_5800, "AIC-5800"), DEVICE( ADAPTEC, ADAPTEC_7860, "AIC-7860"), DEVICE( ADAPTEC, ADAPTEC_7861, "AIC-7861"), DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"), @@ -402,6 +423,7 @@ DEVICE( ADAPTEC, ADAPTEC_7872, "AIC-7872"), DEVICE( ADAPTEC, ADAPTEC_7873, "AIC-7873"), DEVICE( ADAPTEC, ADAPTEC_7874, "AIC-7874"), + DEVICE( ADAPTEC, ADAPTEC_7895, "AIC-7895U"), DEVICE( ADAPTEC, ADAPTEC_7880, "AIC-7880U"), DEVICE( ADAPTEC, ADAPTEC_7881, "AIC-7881U"), DEVICE( ADAPTEC, ADAPTEC_7882, "AIC-7882U"), @@ -610,7 +632,7 @@ case PCI_VENDOR_ID_NCR: return "NCR"; case PCI_VENDOR_ID_ATI: return "ATI"; case PCI_VENDOR_ID_VLSI: return "VLSI"; - case PCI_VENDOR_ID_ADL: return "Advance Logic"; + case PCI_VENDOR_ID_ADL: return "Avance Logic"; case PCI_VENDOR_ID_NS: return "NS"; case PCI_VENDOR_ID_TSENG: return "Tseng'Lab"; case PCI_VENDOR_ID_WEITEK: return "Weitek"; @@ -661,9 +683,11 @@ case PCI_VENDOR_ID_SMC: return "SMC"; case PCI_VENDOR_ID_AL: return "Acer Labs"; case PCI_VENDOR_ID_MITSUBISHI: return "Mitsubishi"; + case PCI_VENDOR_ID_SURECOM: return "Surecom"; case PCI_VENDOR_ID_NEOMAGIC: return "Neomagic"; case PCI_VENDOR_ID_ASP: return "Advanced System Products"; case PCI_VENDOR_ID_CERN: return "CERN"; + case PCI_VENDOR_ID_NVIDIA: return "NVidia"; case PCI_VENDOR_ID_IMS: return "IMS"; case PCI_VENDOR_ID_TEKRAM2: return "Tekram"; case PCI_VENDOR_ID_TUNDRA: return "Tundra"; @@ -688,8 +712,10 @@ case PCI_VENDOR_ID_RICOH: return "Ricoh"; case PCI_VENDOR_ID_ZEITNET: return "ZeitNet"; case PCI_VENDOR_ID_OMEGA: return "Omega Micro"; + case PCI_VENDOR_ID_LITEON: return "LiteOn"; case PCI_VENDOR_ID_NP: return "Network Peripherals"; case PCI_VENDOR_ID_SPECIALIX: return "Specialix"; + case PCI_VENDOR_ID_AURAVISION: return "Auravision"; case PCI_VENDOR_ID_IKON: return "Ikon"; case PCI_VENDOR_ID_ZORAN: return "Zoran"; case PCI_VENDOR_ID_COMPEX: return "Compex"; @@ -700,7 +726,7 @@ case PCI_VENDOR_ID_OPTIBASE: return "Optibase"; case PCI_VENDOR_ID_ENSONIQ: return "Ensoniq"; case PCI_VENDOR_ID_PICTUREL: return "Picture Elements"; - case PCI_VENDOR_ID_NVIDIA: return "NVidia/SGS Thomson"; + case PCI_VENDOR_ID_NVIDIA_SGS: return "NVidia/SGS Thomson"; case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; case PCI_VENDOR_ID_TEKRAM: return "Tekram"; case PCI_VENDOR_ID_3DLABS: return "3Dlabs"; diff -u --recursive --new-file v2.1.70/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg --- v2.1.70/linux/drivers/scsi/aic7xxx/aic7xxx.reg Thu Aug 14 20:49:16 1997 +++ linux/drivers/scsi/aic7xxx/aic7xxx.reg Tue Dec 2 20:41:21 1997 @@ -1079,10 +1079,26 @@ CUR_SCBID { size 1 } + ARG_1 { + size 1 + mask SEND_MSG 0x80 + mask SEND_SENSE 0x40 + mask SEND_REJ 0x20 + alias RETURN_1 + } /* * Running count of commands placed in * the QOUTFIFO. This is cleared by the * kernel driver every FIFODEPTH commands. + * + * NOTE: These scratch RAM registers are overlaying SCSICONF + * and SCSICONF2 and are only used on cards that are + * capable of SCB paging. Currently, only the PCI + * controllers can do this, which is good because the + * AIC-7770 based controllers use the SCSICONF register + * to control termination. In other words, do not + * destroy the contents of SCSICONF and SCSICONF2 for + * AIC-7770 based controllers. */ CMDOUTCNT { size 1 @@ -1094,13 +1110,6 @@ FIFODEPTH { size 1 } - ARG_1 { - size 1 - mask SEND_MSG 0x80 - mask SEND_SENSE 0x40 - mask SEND_REJ 0x20 - alias RETURN_1 - } /* * These are reserved registers in the card's scratch ram. Some of * the values are specified in the AHA2742 technical reference manual @@ -1108,6 +1117,11 @@ */ SCSICONF { address 0x05a + size 1 + bit RESET_SCSI 0x40 + } + SCSICONF2 { + address 0x05b size 1 bit RESET_SCSI 0x40 } diff -u --recursive --new-file v2.1.70/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.1.70/linux/drivers/scsi/aic7xxx.c Thu Aug 14 20:49:16 1997 +++ linux/drivers/scsi/aic7xxx.c Tue Dec 2 20:41:21 1997 @@ -147,6 +147,8 @@ #define ALL_TARGETS -1 #define ALL_CHANNELS '\0' #define ALL_LUNS -1 +#define MAX_TARGETS 16 +#define MAX_LUNS 8 #ifndef TRUE # define TRUE 1 #endif @@ -301,7 +303,7 @@ #ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE typedef struct { - char tag_commands[16]; /* Allow for wide/twin channel adapters. */ + unsigned char tag_commands[16]; /* Allow for wide/twin channel adapters. */ } adapter_tag_info_t; /* @@ -871,7 +873,7 @@ long r_total; /* total reads */ long r_total512; /* 512 byte blocks read */ long r_bins[10]; /* binned reads */ - } stats[2][16][8]; /* channel, target, lun */ + } stats[MAX_TARGETS][MAX_LUNS]; /* [(channel << 3)|target][lun] */ #endif /* AIC7XXX_PROC_STATS */ }; @@ -969,6 +971,7 @@ * IO, we'll use them then. * ***************************************************************************/ + static inline unsigned char aic_inb(struct aic7xxx_host *p, long port) { @@ -992,15 +995,24 @@ { if (p->maddr != NULL) { +#ifdef __alpha__ + int i; + + for (i=0; i < size; i++) + { + p->maddr[port] = valp[i]; + } +#else __asm __volatile(" cld; 1: lodsb; movb %%al,(%0); loop 1b" : : - "r" ((p)->maddr + (port)), - "S" ((valp)), "c" ((size)) : + "r" (p->maddr + port), + "S" (valp), "c" (size) : "%esi", "%ecx", "%eax"); +#endif } else { @@ -1439,7 +1451,7 @@ * If the offset is 0, then the device is requesting asynchronous * transfers. */ - if ((*period >= aic7xxx_syncrates[i].period) && *offset != 0) + if ((*period <= aic7xxx_syncrates[i - 1].period) && *offset != 0) { for (i = 0; i < num_aic7xxx_syncrates; i++) { @@ -1970,21 +1982,46 @@ if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0) { unsigned short mask; + int message_error = FALSE; mask = 0x01 << TARGET_INDEX(scb->cmd); + + /* + * Check to see if we get an invalid message or a message error + * after failing to negotiate a wide or sync transfer message. + */ + if ((scb->flags & SCB_SENSE) && + ((scb->cmd->sense_buffer[12] == 0x43) || /* INVALID_MESSAGE */ + (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR */ + { + message_error = TRUE; + } + if (scb->flags & SCB_MSGOUT_WDTR) { p->wdtr_pending &= ~mask; + if (message_error) + { + p->needwdtr &= ~mask; + p->needwdtr_copy &= ~mask; + } } if (scb->flags & SCB_MSGOUT_SDTR) { p->sdtr_pending &= ~mask; + if (message_error) + { + p->needsdtr &= ~mask; + p->needsdtr_copy &= ~mask; + } } } aic7xxx_free_scb(p, scb); aic7xxx_queue_cmd_complete(p, cmd); #ifdef AIC7XXX_PROC_STATS + if ( (cmd->cmnd[0] != TEST_UNIT_READY) && + (cmd->cmnd[0] != INQUIRY) ) { int actual; @@ -2000,7 +2037,7 @@ long *ptr; int x; - sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07]; + sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7]; sp->xfers++; if (cmd->request.cmd == WRITE) @@ -3088,6 +3125,8 @@ } else { + int send_reject = FALSE; + /* * Send our own WDTR in reply. */ @@ -3110,14 +3149,25 @@ { bus_width = BUS_8_BIT; scratch &= 0x7F; /* XXX - FreeBSD doesn't do this. */ + send_reject = TRUE; } break; default: break; } - aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width); - outb(SEND_MSG, p->base + RETURN_1); + if (send_reject) + { + outb(SEND_REJ, p->base + RETURN_1); + printk(KERN_WARNING "scsi%d: Target %d, channel %c, initiating " + "wide negotiation on a narrow bus - rejecting!", + p->host_no, target, channel); + } + else + { + aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width); + outb(SEND_MSG, p->base + RETURN_1); + } } p->needwdtr &= ~target_mask; outb(scratch, p->base + TARG_SCRATCH + scratch_offset); @@ -4062,7 +4112,7 @@ #ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE device->queue_depth = default_depth; #else - if (p->instance > NUMBER(aic7xxx_tag_info)) + if (p->instance >= NUMBER(aic7xxx_tag_info)) { device->queue_depth = default_depth; } @@ -5022,7 +5072,7 @@ scbq_init(&p->scb_data->free_scbs); scbq_init(&p->waiting_scbs); - for (i = 0; i <= NUMBER(p->device_status); i++) + for (i = 0; i < NUMBER(p->device_status); i++) { p->device_status[i].commands_sent = 0; p->device_status[i].flags = 0; @@ -5305,8 +5355,17 @@ */ outb(p->qcntmask, p->base + QCNTMASK); - outb(p->qfullcount, p->base + FIFODEPTH); - outb(0, p->base + CMDOUTCNT); + /* + * Set FIFO depth and command out count. These are only used when + * paging is enabled and should not be touched for AIC-7770 based + * adapters; FIFODEPTH and CMDOUTCNT overlay SCSICONF and SCSICONF+1 + * which are used to control termination. + */ + if (p->flags & PAGE_ENABLED) + { + outb(p->qfullcount, p->base + FIFODEPTH); + outb(0, p->base + CMDOUTCNT); + } /* * We don't have any waiting selections or disconnected SCBs. @@ -5537,7 +5596,6 @@ { case AIC_7770: /* None of these adapters have seeproms. */ case AIC_7771: - case AIC_7850: case AIC_7855: break; @@ -5545,6 +5603,7 @@ have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray); break; + case AIC_7850: /* The 2910B is a 7850 with a seeprom. */ case AIC_7861: case AIC_7870: case AIC_7871: @@ -5654,7 +5713,11 @@ scsi_conf = (p->scsi_id & 0x7); if (sc->adapter_control & CFSPARITY) scsi_conf |= ENSPCHK; - if (sc->adapter_control & CFRESETB) + /* + * The 7850 controllers with a seeprom, do not honor the CFRESETB + * flag in the seeprom. Assume that we want to reset the SCSI bus. + */ + if ((sc->adapter_control & CFRESETB) || (p->chip_class == AIC_7850)) scsi_conf |= RESET_SCSI; if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x)) @@ -5721,7 +5784,7 @@ * a NULL entry to indicate that no prior hosts have * been found/registered for that IRQ. */ - for (i = 0; i <= NUMBER(aic7xxx_boards); i++) + for (i = 0; i < NUMBER(aic7xxx_boards); i++) { aic7xxx_boards[i] = NULL; } @@ -5787,6 +5850,14 @@ hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */ outb(hcntrl | PAUSE, base + HCNTRL); + p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL); + if (p == NULL) + { + printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n"); + continue; + } + aic7xxx_chip_reset(p); + irq = inb(INTDEF + base) & 0x0F; switch (irq) { @@ -5800,19 +5871,14 @@ default: printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ " - "level, ignoring.\n"); + "level %d, ignoring.\n", irq); irq = 0; + aic7xxx_free(p); break; } if (irq != 0) { - p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL); - if (p == NULL) - { - printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n"); - continue; - } p->irq = irq & 0x0F; p->chip_class = AIC_777x; #ifdef AIC7XXX_PAGE_ENABLE @@ -5823,7 +5889,6 @@ { p->flags |= EXTENDED_TRANSLATION; } - aic7xxx_chip_reset(p); switch (p->chip_type) { @@ -5985,7 +6050,6 @@ flags = 0; switch (aic7xxx_pci_devices[i].chip_type) { - case AIC_7850: case AIC_7855: flags |= USE_DEFAULTS; break; @@ -6887,7 +6951,7 @@ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); base = p->base; channel = cmd->channel ? 'B': 'A'; - tindex = (cmd->channel << 4) | cmd->target; + tindex = TARGET_INDEX(cmd); #ifdef 0 /* AIC7XXX_DEBUG_ABORT */ if (scb != NULL) @@ -7128,4 +7192,3 @@ * tab-width: 8 * End: */ - diff -u --recursive --new-file v2.1.70/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c --- v2.1.70/linux/drivers/scsi/aic7xxx_proc.c Mon Aug 11 14:47:05 1997 +++ linux/drivers/scsi/aic7xxx_proc.c Tue Dec 2 20:41:21 1997 @@ -21,13 +21,15 @@ * o Modified from the EATA-DMA /proc support. * o Additional support for device block statistics provided by * Matthew Jacob. + * o Correction of overflow by Heinz Mauelshagen + * o Adittional corrections by Doug Ledford * * Dean W. Gehnert, deang@teleport.com, 05/01/96 * * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ *-M*************************************************************************/ -#define BLS buffer + len + size +#define BLS (&aic7xxx_buffer[size]) #define HDRB \ " < 512 512-1K 1-2K 2-4K 4-8K 8-16K 16-32K 32-64K 64-128K >128K" @@ -49,6 +51,13 @@ # define proc_debug(fmt, args...) #endif /* PROC_DEBUG */ +static int aic7xxx_buffer_size = 0; +static char *aic7xxx_buffer = NULL; +static const char *bus_names[] = { "Single", "Twin", "Wide" }; +static const char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x", + "AIC-787x", "AIC-788x" }; + + /*+F************************************************************************* * Function: * aic7xxx_set_info @@ -63,6 +72,7 @@ return (-ENOSYS); /* Currently this is a no-op */ } + /*+F************************************************************************* * Function: * aic7xxx_proc_info @@ -71,20 +81,18 @@ * Return information to handle /proc support for the driver. *-F*************************************************************************/ int -aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, + int hostno, int inout) { struct Scsi_Host *HBAptr; struct aic7xxx_host *p; - int i; - int found = FALSE; - int size = 0; - int len = 0; - off_t begin = 0; - off_t pos = 0; - static char *bus_names[] = { "Single", "Twin", "Wide" }; - static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x", - "AIC-787x", "AIC-788x" }; + int found = FALSE; + int size = 0; + unsigned char i; +#ifdef AIC7XXX_PROC_STATS + struct aic7xxx_xferstats *sp; + unsigned char target, lun; +#endif HBAptr = NULL; for (i=0; i < NUMBER(aic7xxx_boards); i++) @@ -118,9 +126,15 @@ if (HBAptr == NULL) { - size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno); - len += size; pos = begin + len; size = 0; - goto stop_output; + size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + if (size > length) + { + return (size); + } + else + { + return (length); + } } if (inout == TRUE) /* Has data been written to the file? */ @@ -130,21 +144,49 @@ p = (struct aic7xxx_host *) HBAptr->hostdata; + /* + * It takes roughly 1K of space to hold all relevant card info, not + * counting any proc stats, so we start out with a 1.5k buffer size and + * if proc_stats is defined, then we sweep the stats structure to see + * how many drives we will be printing out for and add 384 bytes per + * device with active stats. + */ + + size = 1536; +#ifdef AIC7XXX_PROC_STATS + for (target = 0; target < MAX_TARGETS; target++) + { + for (lun = 0; lun < MAX_LUNS; lun++) + { + if (p->stats[target][lun].xfers != 0) + size += 384; + } + } +#endif + if (aic7xxx_buffer_size != size) + { + if (aic7xxx_buffer != NULL) + { + kfree(aic7xxx_buffer); + aic7xxx_buffer_size = 0; + } + aic7xxx_buffer = kmalloc(size, GFP_KERNEL); + } + if (aic7xxx_buffer == NULL) + { + size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n", + __LINE__); + return size; + } + aic7xxx_buffer_size = size; + + size = 0; size += sprintf(BLS, "Adaptec AIC7xxx driver version: "); size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION)); size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION)); #if 0 size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER)); #endif - if (size > 512) - printk(KERN_CRIT "aic7xxx: possible overflow at first position\n"); - len += size; pos = begin + len; size = 0; - if (pos < offset) - { - begin = pos; - len = 0; - } - size += sprintf(BLS, "\n"); size += sprintf(BLS, "Compile Options:\n"); #ifdef AIC7XXX_RESET_DELAY @@ -168,30 +210,19 @@ #else size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); #endif - if (size > 512) - printk(KERN_CRIT "aic7xxx: possible overflow at second position\n"); - len += size; pos = begin + len; size = 0; - if (pos < offset) - { - begin = pos; - len = 0; - } - else if (pos >= offset + length) - goto stop_output; - size += sprintf(BLS, "\n"); size += sprintf(BLS, "Adapter Configuration:\n"); - size += sprintf(BLS, " SCSI Adapter: %s\n", + size += sprintf(BLS, " SCSI Adapter: %s\n", board_names[p->chip_type]); - size += sprintf(BLS, " (%s chipset)\n", + size += sprintf(BLS, " (%s chipset)\n", chip_names[p->chip_class]); - size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]); - size += sprintf(BLS, " Base IO: %#.4x\n", p->base); - size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase); - size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); - size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n", + size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]); + size += sprintf(BLS, " Base IO: %#.4x\n", p->base); + size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase); + size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); + size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs); - size += sprintf(BLS, " Interrupts: %d", p->isr_count); + size += sprintf(BLS, " Interrupts: %d", p->isr_count); if (p->chip_class == AIC_777x) { size += sprintf(BLS, " %s\n", @@ -201,102 +232,81 @@ { size += sprintf(BLS, "\n"); } - size += sprintf(BLS, " Serial EEPROM: %s\n", + size += sprintf(BLS, " Serial EEPROM: %s\n", (p->flags & HAVE_SEEPROM) ? "True" : "False"); - size += sprintf(BLS, " Extended Translation: %sabled\n", + size += sprintf(BLS, " Extended Translation: %sabled\n", (p->flags & EXTENDED_TRANSLATION) ? "En" : "Dis"); - size += sprintf(BLS, " SCSI Bus Reset: %sabled\n", + size += sprintf(BLS, " SCSI Bus Reset: %sabled\n", aic7xxx_no_reset ? "Dis" : "En"); - size += sprintf(BLS, " Ultra SCSI: %sabled\n", + size += sprintf(BLS, " Ultra SCSI: %sabled\n", (p->flags & ULTRA_ENABLED) ? "En" : "Dis"); - size += sprintf(BLS, " Target Disconnect: %sabled\n", - p->discenable ? "En" : "Dis"); - if (size > 512) - printk(KERN_CRIT "aic7xxx: possible overflow at third position\n"); - len += size; pos = begin + len; size = 0; - if (pos < offset) - { - begin = pos; - len = 0; - } - else if (pos >= offset + length) - goto stop_output; - + size += sprintf(BLS, "Disconnect Enable Flags: 0x%x\n", p->discenable); + #ifdef AIC7XXX_PROC_STATS + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Statistics:\n"); + for (target = 0; target < MAX_TARGETS; target++) { - struct aic7xxx_xferstats *sp; - int channel, target, lun; - - /* - * XXX: Need to fix this to avoid overflow... - * Fixed - gordo. - */ - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Statistics:\n"); - for (channel = 0; channel < 2; channel++) + for (lun = 0; lun < MAX_LUNS; lun++) { - for (target = 0; target < 16; target++) + sp = &p->stats[target][lun]; + if (sp->xfers == 0) { - for (lun = 0; lun < 8; lun++) - { - sp = &p->stats[channel][target][lun]; - if (sp->xfers == 0) - { - continue; - } - size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n", - 'A' + channel, target, lun); - size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n", - sp->xfers, sp->r_total, sp->w_total); - size += sprintf(BLS, "blks(512) rd=%ld; blks(512) wr=%ld\n", - sp->r_total512, sp->w_total512); - size += sprintf(BLS, "%s\n", HDRB); - size += sprintf(BLS, " Reads:"); - size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->r_bins[0], - sp->r_bins[1], sp->r_bins[2], sp->r_bins[3]); - size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->r_bins[4], - sp->r_bins[5], sp->r_bins[6], sp->r_bins[7]); - size += sprintf(BLS, "%6ld %6ld\n", sp->r_bins[8], - sp->r_bins[9]); - size += sprintf(BLS, "Writes:"); - size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->w_bins[0], - sp->w_bins[1], sp->w_bins[2], sp->w_bins[3]); - size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->w_bins[4], - sp->w_bins[5], sp->w_bins[6], sp->w_bins[7]); - size += sprintf(BLS, "%6ld %6ld\n", sp->w_bins[8], - sp->w_bins[9]); - size += sprintf(BLS, "\n"); - } - if (size > 512) - printk(KERN_CRIT "aic7xxx: possible overflow at loop %d:%d\n", target, lun); - len += size; pos = begin + len; size = 0; - if (pos < offset) - { - begin = pos; - len = 0; - } - else if (pos >= offset + length) - goto stop_output; + continue; } + if (p->bus_type == AIC_TWIN) + { + size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n", + 'A' + (target >> 3), (target & 0x7), lun); + } + else + { + size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n", + 'A', target, lun); + } + size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n", + sp->xfers, sp->r_total, sp->w_total); + size += sprintf(BLS, "blks(512) rd=%ld; blks(512) wr=%ld\n", + sp->r_total512, sp->w_total512); + size += sprintf(BLS, "%s\n", HDRB); + size += sprintf(BLS, " Reads:"); + for (i = 0; i < NUMBER(sp->r_bins); i++) + { + size += sprintf(BLS, "%6ld ", sp->r_bins[i]); + } + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Writes:"); + for (i = 0; i < NUMBER(sp->w_bins); i++) + { + size += sprintf(BLS, "%6ld ", sp->w_bins[i]); + } + size += sprintf(BLS, "\n\n"); } } #endif /* AIC7XXX_PROC_STATS */ -stop_output: - proc_debug("2pos: %ld offset: %ld len: %d\n", pos, offset, len); - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len < 0) + if (size >= aic7xxx_buffer_size) { - len = 0; /* off end of file */ + printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n"); } - else if (len > length) + + if (offset > size - 1) { - len = length; /* Ending slop */ + kfree(aic7xxx_buffer); + aic7xxx_buffer = NULL; + aic7xxx_buffer_size = length = 0; + *start = NULL; } - proc_debug("3pos: %ld offset: %ld len: %d\n", pos, offset, len); - - return (len); + else + { + *start = &aic7xxx_buffer[offset]; /* Start of wanted data */ + if (size - offset < length) + { + length = size - offset; + } + } + + return (length); } /* diff -u --recursive --new-file v2.1.70/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h --- v2.1.70/linux/drivers/scsi/aic7xxx_reg.h Thu Aug 14 20:49:16 1997 +++ linux/drivers/scsi/aic7xxx_reg.h Tue Dec 2 20:41:21 1997 @@ -30,6 +30,13 @@ #define ACTNEGEN 0x02 #define STPWEN 0x01 +#define SCSISIGI 0x03 +#define ATNI 0x10 +#define SELI 0x08 +#define BSYI 0x04 +#define REQI 0x02 +#define ACKI 0x01 + #define SCSISIGO 0x03 #define CDO 0x80 #define IOO 0x40 @@ -40,13 +47,6 @@ #define REQO 0x02 #define ACKO 0x01 -#define SCSISIGI 0x03 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 - #define SCSIRATE 0x04 #define WIDEXFER 0x80 #define SXFR 0x70 @@ -252,24 +252,26 @@ #define CUR_SCBID 0x58 -#define CMDOUTCNT 0x59 +#define ARG_1 0x59 +#define RETURN_1 0x59 +#define SEND_MSG 0x80 +#define SEND_SENSE 0x40 +#define SEND_REJ 0x20 #define SCSICONF 0x5a -#define RESET_SCSI 0x40 -#define FIFODEPTH 0x5a +#define CMDOUTCNT 0x5a -#define ARG_1 0x5b -#define RETURN_1 0x5b -#define SEND_MSG 0x80 -#define SEND_SENSE 0x40 -#define SEND_REJ 0x20 +#define SCSICONF2 0x5b +#define RESET_SCSI 0x40 + +#define FIFODEPTH 0x5b #define HOSTCONF 0x5d #define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 #define BIOSDISABLED 0x30 +#define BIOSMODE 0x30 #define CHANNEL_B_PRIMARY 0x08 #define SEQCTL 0x60 @@ -313,16 +315,16 @@ #define STACK 0x6f -#define BCTL 0x84 -#define ACE 0x08 -#define ENABLE 0x01 - #define DSCOMMAND 0x84 #define CACHETHEN 0x80 #define DPARCKEN 0x40 #define MPARCKEN 0x20 #define EXTREQLCK 0x10 +#define BCTL 0x84 +#define ACE 0x08 +#define ENABLE 0x01 + #define BUSTIME 0x85 #define BOFF 0xf0 #define BON 0x0f @@ -372,18 +374,18 @@ #define BAD_PHASE 0x01 #define SEQINT 0x01 -#define CLRINT 0x92 -#define CLRBRKADRINT 0x08 -#define CLRSCSIINT 0x04 -#define CLRCMDINT 0x02 -#define CLRSEQINT 0x01 - #define ERROR 0x92 #define PARERR 0x08 #define ILLOPCODE 0x04 #define ILLSADDR 0x02 #define ILLHADDR 0x01 +#define CLRINT 0x92 +#define CLRBRKADRINT 0x08 +#define CLRSCSIINT 0x04 +#define CLRCMDINT 0x02 +#define CLRSEQINT 0x01 + #define DFCNTRL 0x93 #define DFSTATUS 0x94 @@ -408,6 +410,8 @@ #define QOUTCNT 0x9e +#define SCB_BASE 0xa0 + #define SCB_CONTROL 0xa0 #define MK_MESSAGE 0x80 #define DISCENB 0x40 @@ -417,8 +421,6 @@ #define DISCONNECTED 0x04 #define SCB_TAG_TYPE 0x03 -#define SCB_BASE 0xa0 - #define SCB_TCL 0xa1 #define TID 0xf0 #define SELBUSB 0x08 @@ -464,10 +466,10 @@ #define DI_2840 0x01 -#define BUS_8_BIT 0x00 -#define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 #define MAX_OFFSET_16BIT 0x08 +#define BUS_8_BIT 0x00 #define SCB_LIST_NULL 0xff #define SG_SIZEOF 0x08 +#define MAX_OFFSET_8BIT 0x0f #define BUS_32_BIT 0x02 +#define BUS_16_BIT 0x01 diff -u --recursive --new-file v2.1.70/linux/drivers/scsi/aic7xxx_seq.h linux/drivers/scsi/aic7xxx_seq.h --- v2.1.70/linux/drivers/scsi/aic7xxx_seq.h Thu Aug 14 20:49:16 1997 +++ linux/drivers/scsi/aic7xxx_seq.h Tue Dec 2 20:41:21 1997 @@ -26,8 +26,8 @@ 0x50, 0x6a, 0x60, 0x00, 0xff, 0x90, 0x4a, 0x02, 0x00, 0xa1, 0xa1, 0x17, - 0xff, 0x6c, 0x5b, 0x02, - 0xff, 0x5b, 0x27, 0x1c, + 0xff, 0x6c, 0x59, 0x02, + 0xff, 0x59, 0x27, 0x1c, 0xff, 0x4a, 0x90, 0x02, 0x00, 0x65, 0xaa, 0x17, 0x00, 0x6a, 0x52, 0x17, @@ -37,7 +37,7 @@ 0x00, 0x65, 0xbb, 0x17, 0x10, 0x6a, 0x60, 0x00, 0x00, 0x65, 0x03, 0x10, - 0xff, 0x5b, 0x90, 0x02, + 0xff, 0x59, 0x90, 0x02, 0xff, 0x58, 0xb3, 0x02, 0x10, 0x6a, 0x60, 0x00, 0x00, 0x65, 0x03, 0x10, @@ -217,7 +217,7 @@ 0x00, 0xb9, 0x77, 0x17, 0xff, 0xa2, 0xda, 0x1e, 0x71, 0x6a, 0x91, 0x00, - 0x40, 0x5b, 0xda, 0x18, + 0x40, 0x59, 0xda, 0x18, 0xff, 0xb9, 0xb3, 0x02, 0x00, 0x65, 0xe7, 0x10, 0x20, 0xa0, 0xe0, 0x1a, @@ -226,9 +226,9 @@ 0x00, 0xa1, 0xa1, 0x17, 0xff, 0x49, 0x6d, 0x02, 0xff, 0x4a, 0x90, 0x02, - 0xff, 0x5a, 0x64, 0x02, - 0x00, 0x59, 0xe1, 0x1c, - 0x01, 0x59, 0x59, 0x06, + 0xff, 0x5b, 0x64, 0x02, + 0x00, 0x5a, 0xe1, 0x1c, + 0x01, 0x5a, 0x5a, 0x06, 0xff, 0xb9, 0x9d, 0x02, 0x02, 0x6a, 0x91, 0x00, 0x08, 0xa0, 0xe7, 0x1e, @@ -255,8 +255,8 @@ 0xff, 0x66, 0x66, 0x06, 0xff, 0x64, 0xf7, 0x1a, 0x41, 0x6a, 0x91, 0x00, - 0x20, 0x5b, 0xcd, 0x1c, - 0x80, 0x5b, 0xcf, 0x18, + 0x20, 0x59, 0xcd, 0x1c, + 0x80, 0x59, 0xcf, 0x18, 0x10, 0x4c, 0x03, 0x00, 0x00, 0x65, 0xcf, 0x10, 0x04, 0xa0, 0xa0, 0x00, @@ -276,10 +276,10 @@ 0x07, 0x64, 0x64, 0x02, 0x00, 0x42, 0x42, 0x00, 0x00, 0x42, 0xa1, 0x17, - 0xff, 0x6c, 0x5b, 0x02, - 0xff, 0x5b, 0x28, 0x19, - 0xff, 0x5b, 0x18, 0x1d, - 0xff, 0x5b, 0x90, 0x02, + 0xff, 0x6c, 0x59, 0x02, + 0xff, 0x59, 0x28, 0x19, + 0xff, 0x59, 0x18, 0x1d, + 0xff, 0x59, 0x90, 0x02, 0x04, 0xa0, 0x2d, 0x1f, 0x00, 0x65, 0x2a, 0x11, 0xff, 0x06, 0x6a, 0x02, @@ -289,11 +289,11 @@ 0xe0, 0x4c, 0x2d, 0x19, 0x20, 0x12, 0x2d, 0x19, 0x20, 0x41, 0x41, 0x00, - 0x5b, 0x6a, 0x3a, 0x17, + 0x59, 0x6a, 0x3a, 0x17, 0xff, 0x3f, 0x64, 0x02, - 0x00, 0x5b, 0x65, 0x06, + 0x00, 0x59, 0x65, 0x06, 0x00, 0x65, 0x2d, 0x13, - 0xff, 0x5b, 0x90, 0x02, + 0xff, 0x59, 0x90, 0x02, 0xff, 0x42, 0x64, 0x02, 0x00, 0xa1, 0x2d, 0x19, 0x20, 0xa0, 0x2d, 0x1f, @@ -341,7 +341,7 @@ 0x40, 0x41, 0x4e, 0x1b, 0x21, 0x6a, 0x91, 0x01, 0xff, 0x65, 0x90, 0x02, - 0xff, 0x5b, 0x64, 0x02, + 0xff, 0x59, 0x64, 0x02, 0x00, 0xb9, 0x56, 0x19, 0x04, 0xa0, 0x60, 0x1b, 0x01, 0x65, 0x65, 0x06, @@ -349,7 +349,7 @@ 0x00, 0x65, 0x52, 0x19, 0x00, 0x6a, 0xad, 0x17, 0x0d, 0x6a, 0x3d, 0x00, - 0x00, 0x5b, 0x77, 0x17, + 0x00, 0x59, 0x77, 0x17, 0xff, 0xa8, 0x5e, 0x1f, 0x10, 0xa0, 0xa0, 0x00, 0x08, 0xa0, 0x4e, 0x1f, diff -u --recursive --new-file v2.1.70/linux/fs/affs/Changes linux/fs/affs/Changes --- v2.1.70/linux/fs/affs/Changes Thu Jul 17 10:06:06 1997 +++ linux/fs/affs/Changes Tue Dec 2 22:25:07 1997 @@ -12,15 +12,95 @@ apparently not causing the failure, as directory reads basically work (but all files are of size 0). Alas, I've got no alpha to debug. :-( -- If an affs mounted filesystem is exported via - nfs, it cannot be written to. - As soon as I have my network up and running, I'll - try to fix this. + - The partition checker (drivers/block/genhd.c) doesn't work with devices which have 256 byte blocks (some very old SCSI drives). +- The feature to automatically make the fs clean + might leave a trashed file system with the + bitmap flag set valid. + +- The blocks from deleted directories are + sometimes reclaimed only at umount time. + Please direct bug reports to: hjw@zvw.de + +Version 3.6 +----------- + +- dentry changes. (Thanks to Jes Sorensen for his help.) + +- Fixed bug in balloc(): Superblock was not set dirty after + the bitmap was changed, so the bitmap wasn't sync'd. + +- Fixed nasty bug in find_new_zone(): If the current + zone number was zero, the loop didn't terminate, + causing a solid lock-up. + +- Removed support for old-style directory reads. + +- Fixed bug in add_entry(): When doing a sorted insert, + the pointer to the next entry in the hash chain wasn't + correctly byte-swapped. Since most of the users of the + affs use it on a 68k, they didn't notice. But why did + I not find this during my tests? + +- Fixed some oversights (version wasn't updated on some + directory changes). + +- Handling of hard links rewritten. To the VFS + they appear now as normal unix links. They are + now resolved only once in lookup(). The backside + is that unlink(), rename() and rmdir() have to + be smart about them, but the result is worth the + effort. This also led to some code cleanup. + +- Changed name type to unsigned char; the test for + invalid filenames didn't work correctly. + (Thanks to Michael Krause for pointing at this.) + +- Changed mapping of executable flag. + +- Changed all network byte-order macros to the + recommended ones. + +- Added a remount function, so attempts to remount + a dircache filesystem or one with errors read/write + can be trapped. Previously, ro remounts didn't + flush the super block, and rw remounts didn't + create allocation zones ... + +- Call shrink_dcache_parent() in rmdir(). + (Thanks to Bill Hawes.) + +- Permission checks in unlink(). + +- Allow mounting of volumes with superfluous + bitmap pointers read only, also allows them + to be remounted read/write. + +- Owner/Group defaults now to the fs user (i.e. + the one that mounted it) instead of root. This + obsoletes the mount options uid and gid. + +- Argument to volume option could overflow the + name buffer. It is now silently truncated to + 30 characters. (Damnit! This kind of bug + is too embarrassing.) + +- Split inode.c into 2 files, the superblock + routines desperately wanted their own file. + +- truncate() didn't allocate an extension block + cache. If a file was extended by means of + truncate(), this led to an Oops. + +- fsuser is now checked last. + +- rename() will not ignore changes in filename + casing any more (though mv(1) still won't allow + you to do "mv oldname OldName"). Version 3.5 ----------- diff -u --recursive --new-file v2.1.70/linux/fs/affs/Makefile linux/fs/affs/Makefile --- v2.1.70/linux/fs/affs/Makefile Mon May 6 02:44:31 1996 +++ linux/fs/affs/Makefile Tue Dec 2 22:25:07 1997 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := affs.o -O_OBJS := namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o +O_OBJS := super.o namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.70/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c --- v2.1.70/linux/fs/affs/amigaffs.c Thu Jul 17 10:06:06 1997 +++ linux/fs/affs/amigaffs.c Tue Dec 2 22:25:07 1997 @@ -8,6 +8,7 @@ * Please send bug reports to: hjw@zvw.de */ +#define DEBUG 0 #include #include #include @@ -30,7 +31,7 @@ pointed to by FH_DATA. The length of the name is returned. */ int -affs_get_file_name(int bsize, void *fh_data, char **name) +affs_get_file_name(int bsize, void *fh_data, unsigned char **name) { struct file_end *file_end; @@ -42,100 +43,142 @@ *name = "***BAD_FILE***"; return 14; } - *name = (char *)&file_end->file_name[1]; + *name = (unsigned char *)&file_end->file_name[1]; return file_end->file_name[0]; } -/* Find the predecessor in the hash chain */ +/* Insert a header block (file) into the directory (next). + * This routine assumes that the caller has the superblock locked. + */ int -affs_fix_hash_pred(struct inode *startino, int startoffset, s32 key, s32 newkey) +affs_insert_hash(unsigned long next, struct buffer_head *file, struct inode *inode) { - struct buffer_head *bh = NULL; - s32 nextkey; - s32 ptype, stype; - int retval; + struct buffer_head *bh; + s32 ino; + int offset; + + offset = affs_hash_name(FILE_END(file->b_data,inode)->file_name+1, + FILE_END(file->b_data,inode)->file_name[0], + AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6; + ino = be32_to_cpu(((struct dir_front *)file->b_data)->own_key); + + pr_debug("AFFS: insert_hash(dir_ino=%lu,ino=%d)\n",next,ino); + + FILE_END(file->b_data,inode)->parent = cpu_to_be32(next); - nextkey = startino->i_ino; - retval = -ENOENT; - lock_super(startino->i_sb); while (1) { - pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n",nextkey,startoffset); - if (nextkey == 0) + if (!(bh = affs_bread(inode->i_dev,next,AFFS_I2BSIZE(inode)))) + return -EIO; + next = be32_to_cpu(((s32 *)bh->b_data)[offset]); + if (!next || next > ino) break; - if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino)))) + offset = AFFS_I2BSIZE(inode) / 4 - 4; + affs_brelse(bh); + } + + DIR_END(file->b_data,inode)->hash_chain = cpu_to_be32(next); + ((s32 *)bh->b_data)[offset] = cpu_to_be32(ino); + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + + return 0; +} +/* Remove a header block from it's hash table (directory). + * 'inode' may be any inode on the partition, it's only + * used for calculating the block size and superblock + * reference. + */ + +int +affs_remove_hash(struct buffer_head *dbh, struct inode *inode) +{ + s32 ownkey; + s32 key; + s32 ptype; + s32 stype; + int offset; + int retval; + struct buffer_head *bh; + + ownkey = be32_to_cpu(((struct dir_front *)dbh->b_data)->own_key); + key = be32_to_cpu(FILE_END(dbh->b_data,inode)->parent); + offset = affs_hash_name(FILE_END(dbh->b_data,inode)->file_name+1, + FILE_END(dbh->b_data,inode)->file_name[0], + AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6; + pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n",key,ownkey,offset-6); + retval = -ENOENT; + + lock_super(inode->i_sb); + while (key) { + if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) { + retval = -EIO; break; - if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype) + } + if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR && stype != ST_LINKFILE && stype != ST_LINKDIR && stype != ST_ROOT && stype != ST_SOFTLINK)) { - affs_error(startino->i_sb,"affs_fix_hash_pred", - "Bad block in link chain (ptype=%d, stype=%d)",ptype,stype); + affs_error(inode->i_sb,"affs_remove_hash", + "Bad block in hash chain (key=%d, ptype=%d, stype=%d, ownkey=%d)", + key,ptype,stype,ownkey); affs_brelse(bh); + retval = -EINVAL; break; } - nextkey = htonl(((s32 *)bh->b_data)[startoffset]); - if (nextkey == key) { - ((s32 *)bh->b_data)[startoffset] = newkey; - affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); + key = be32_to_cpu(((s32 *)bh->b_data)[offset]); + if (ownkey == key) { + ((s32 *)bh->b_data)[offset] = FILE_END(dbh->b_data,inode)->hash_chain; + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); retval = 0; break; } affs_brelse(bh); - startoffset = AFFS_I2BSIZE(startino) / 4 - 4; + offset = AFFS_I2BSIZE(inode) / 4 - 4; } - unlock_super(startino->i_sb); + unlock_super(inode->i_sb); return retval; } -/* Remove inode from link chain */ +/* Remove header from link chain */ int -affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey) +affs_remove_link(struct buffer_head *dbh, struct inode *inode) { - struct buffer_head *bh = NULL; - s32 nextkey; - int offset; - s32 etype = 0; - s32 ptype, stype; int retval; - - offset = AFFS_I2BSIZE(startino) / 4 - 10; - nextkey = startino->i_ino; - retval = -ENOENT; - lock_super(startino->i_sb); - while (1) { - if (nextkey == 0) - break; - pr_debug("AFFS: find_link_pred(): next key=%d\n",nextkey); - if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino)))) - break; - if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype) - || ptype != T_SHORT) { - affs_brelse(bh); + s32 key; + s32 ownkey; + s32 ptype; + s32 stype; + struct buffer_head *bh; + + ownkey = be32_to_cpu((DIR_FRONT(dbh)->own_key)); + key = be32_to_cpu(FILE_END(dbh->b_data,inode)->original); + retval = -ENOENT; + + pr_debug("AFFS: remove_link(link=%d, original=%d)\n",ownkey,key); + + lock_super(inode->i_sb); + while (key) { + if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) { + retval = -EIO; break; } - if (!etype) { - if (stype != ST_FILE && stype != ST_USERDIR) { - affs_brelse(bh); - break; - } - if (stype == ST_FILE) - etype = ST_LINKFILE; - else - etype = ST_LINKDIR; - } else if (stype != etype) { + if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)) { + affs_error(inode->i_sb,"affs_remove_link","Checksum error (block %d)",key); affs_brelse(bh); - retval = -EPERM; + retval = -EINVAL; break; } - nextkey = htonl(((s32 *)bh->b_data)[offset]); - if (nextkey == key) { - FILE_END(bh->b_data,startino)->link_chain = newkey; - affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); + key = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain); + if (ownkey == key) { + FILE_END(bh->b_data,inode)->link_chain = + FILE_END(dbh->b_data,inode)->link_chain; + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); retval = 0; @@ -143,10 +186,102 @@ } affs_brelse(bh); } - unlock_super(startino->i_sb); + unlock_super(inode->i_sb); + return retval; } +/* Remove a filesystem object. If the object to be removed has + * links to it, one of the links must be changed to inherit + * the file or directory. As above, any inode will do. + * The buffer will not be freed. If the header is a link, the + * block will be marked as free. + * This function returns a negative error number in case of + * an error, else 0 if the inode is to be deleted or 1 if not. + */ + +int +affs_remove_header(struct buffer_head *bh, struct inode *inode) +{ + struct buffer_head *link_bh; + struct inode *dir; + unsigned long link_ino; + unsigned long orig_ino; + unsigned int dir_ino; + int error; + + pr_debug("AFFS: remove_header(key=%ld)\n",be32_to_cpu(DIR_FRONT(bh)->own_key)); + + /* Mark directory as changed. We do this before anything else, + * as it must be done anyway and doesn't hurt even if an + * error occures later. + */ + dir = iget(inode->i_sb,be32_to_cpu(FILE_END(bh->b_data,inode)->parent)); + if (!dir) + return -EIO; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_version++; + mark_inode_dirty(dir); + iput(dir); + + orig_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->original); + if (orig_ino) { /* This is just a link. Nothing much to do. */ + pr_debug(" Removing link.\n"); + if ((error = affs_remove_link(bh,inode))) + return error; + if ((error = affs_remove_hash(bh,inode))) + return error; + affs_free_block(inode->i_sb,be32_to_cpu(DIR_FRONT(bh)->own_key)); + return 1; + } + + link_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain); + if (link_ino) { /* This is the complicated case. Yuck. */ + pr_debug(" Removing original with links to it.\n"); + /* Unlink the object and its first link from their directories. */ + if ((error = affs_remove_hash(bh,inode))) + return error; + if (!(link_bh = affs_bread(inode->i_dev,link_ino,AFFS_I2BSIZE(inode)))) + return -EIO; + if ((error = affs_remove_hash(link_bh,inode))) { + affs_brelse(link_bh); + return error; + } + /* Fix link chain. */ + if ((error = affs_remove_link(link_bh,inode))) { + affs_brelse(link_bh); + return error; + } + /* Rename link to object. */ + memcpy(FILE_END(bh->b_data,inode)->file_name, + FILE_END(link_bh->b_data,inode)->file_name,32); + /* Insert object into dir the link was in. */ + dir_ino = be32_to_cpu(FILE_END(link_bh->b_data,inode)->parent); + if ((error = affs_insert_hash(dir_ino,bh,inode))) { + affs_brelse(link_bh); + return error; + } + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(link_bh); + affs_free_block(inode->i_sb,link_ino); + /* Mark the link's parent dir as changed, too. */ + if (!(dir = iget(inode->i_sb,dir_ino))) + return -EIO; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_version++; + mark_inode_dirty(dir); + iput(dir); + return 1; + } + /* Plain file/dir. This is the simplest case. */ + pr_debug(" Removing plain file/dir.\n"); + if ((error = affs_remove_hash(bh,inode))) + return error; + return 0; +} + + /* Checksum a block, do various consistency checks and optionally return the blocks type number. DATA points to the block. If their pointers are non-null, *PTYPE and *STYPE are set to the primary and secondary @@ -162,14 +297,14 @@ bsize /= 4; if (ptype) - *ptype = htonl(((s32 *)data)[0]); + *ptype = be32_to_cpu(((s32 *)data)[0]); if (stype) - *stype = htonl(((s32 *)data)[bsize - 1]); + *stype = be32_to_cpu(((s32 *)data)[bsize - 1]); sum = 0; p = data; while (bsize--) - sum += htonl(*p++); + sum += be32_to_cpu(*p++); return sum; } @@ -180,9 +315,9 @@ u32 cs; cs = affs_checksum_block(bsize,data,NULL,NULL); - ocs = htonl (((u32 *)data)[cspos]); + ocs = be32_to_cpu(((u32 *)data)[cspos]); ocs -= cs; - ((u32 *)data)[cspos] = htonl(ocs); + ((u32 *)data)[cspos] = be32_to_cpu(ocs); } void @@ -191,7 +326,7 @@ u32 days; u32 minute; - secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60); + secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60); if (secs < 0) secs = 0; days = secs / 86400; @@ -199,9 +334,9 @@ minute = secs / 60; secs -= minute * 60; - ds->ds_Days = htonl(days); - ds->ds_Minute = htonl(minute); - ds->ds_Tick = htonl(secs * 50); + ds->ds_Days = be32_to_cpu(days); + ds->ds_Minute = be32_to_cpu(minute); + ds->ds_Tick = be32_to_cpu(secs * 50); } int @@ -268,6 +403,7 @@ if (!(sb->s_flags & MS_RDONLY)) printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n"); sb->s_flags |= MS_RDONLY; + sb->u.affs_sb.s_flags |= SF_READONLY; /* Don't allow to remount rw */ } void @@ -279,6 +415,50 @@ vsprintf(ErrorBuffer,fmt,args); va_end(args); - printk(KERN_WARNING "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev), + printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n",kdevname(sb->s_dev), function,ErrorBuffer); +} + +/* Check if the name is valid for a affs object. */ + +int +affs_check_name(const unsigned char *name, int len) +{ + int i; + + if (len > 30) +#ifdef AFFS_NO_TRUNCATE + return -ENAMETOOLONG; +#else + len = 30; +#endif + + for (i = 0; i < len; i++) { + if (name[i] < ' ' || name[i] == ':' + || (name[i] > 0x7e && name[i] < 0xa0)) + return -EINVAL; + } + + return 0; +} + +/* This function copies name to bstr, with at most 30 + * characters length. The bstr will be prepended by + * a length byte. + * NOTE: The name will must be already checked by + * affs_check_name()! + */ + +int +affs_copy_name(unsigned char *bstr, const unsigned char *name) +{ + int len; + + for (len = 0; len < 30; len++) { + bstr[len + 1] = name[len]; + if (name[len] == '\0') + break; + } + bstr[0] = len; + return len; } diff -u --recursive --new-file v2.1.70/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c --- v2.1.70/linux/fs/affs/bitmap.c Tue May 13 22:41:13 1997 +++ linux/fs/affs/bitmap.c Tue Dec 2 22:25:07 1997 @@ -91,7 +91,7 @@ block); else { sb->u.affs_sb.s_alloc[zone_no].az_free++; - ((u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((u32 *)bm->bm_bh->b_data)[0]) - blk); + ((u32 *)bm->bm_bh->b_data)[0] = cpu_to_be32(be32_to_cpu(((u32 *)bm->bm_bh->b_data)[0]) - blk); mark_buffer_dirty(bm->bm_bh,1); sb->s_dirt = 1; } @@ -136,7 +136,7 @@ fwb = zone->z_bm->bm_firstblk + (i - 1) * 32; lock_super(sb); zone->z_start = i; - w = ~htonl(bm[i]); + w = ~be32_to_cpu(bm[i]); fb = find_first_zero_bit(&w,32); if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) { unlock_super(sb); @@ -163,10 +163,11 @@ az->az_free--; } } - w = ~w - htonl(bm[i]); - bm[0] = ntohl(htonl(bm[0]) + w); + w = ~w - be32_to_cpu(bm[i]); + bm[0] = cpu_to_be32(be32_to_cpu(bm[0]) + w); unlock_super(sb); mark_buffer_dirty(zone->z_bm->bm_bh,1); + sb->s_dirt = 1; zone->z_lru_time = jiffies; return block; @@ -208,8 +209,6 @@ } while (1) { - if (i >= sb->u.affs_sb.s_num_az) - i = 0; az = &sb->u.affs_sb.s_alloc[i]; if (!az->az_count) { if (az->az_free > min) { @@ -223,7 +222,9 @@ lusers = az->az_count; bestused = i; } - if (++i == zone->z_az_no) { /* Seen all */ + if (++i >= sb->u.affs_sb.s_num_az) + i = 0; + if (i == zone->z_az_no) { /* Seen all */ if (bestno >= 0) { i = bestno; } else { @@ -279,7 +280,7 @@ } init_block: if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { - affs_error(inode->i_sb,"new_header","Cannot read block %d",block); + affs_error(inode->i_sb,"new_header","Cannot get block %d",block); return 0; } memset(bh->b_data,0,AFFS_I2BSIZE(inode)); @@ -357,7 +358,7 @@ init_block: if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) { - affs_error(inode->i_sb,"new_data","Cannot read block %d",block); + affs_error(inode->i_sb,"new_data","Cannot get block %d",block); return 0; } memset(bh->b_data,0,sb->s_blocksize); diff -u --recursive --new-file v2.1.70/linux/fs/affs/dir.c linux/fs/affs/dir.c --- v2.1.70/linux/fs/affs/dir.c Sat Oct 25 02:44:17 1997 +++ linux/fs/affs/dir.c Tue Dec 2 22:25:07 1997 @@ -13,6 +13,7 @@ * */ +#define DEBUG 0 #include #include #include @@ -24,8 +25,7 @@ #include static int affs_readdir(struct file *, void *, filldir_t); -static ssize_t affs_dir_read(struct file * filp, char * buf, - size_t count, loff_t *ppos); +static ssize_t affs_dir_read(struct file *, char *, size_t, loff_t *); static struct file_operations affs_dir_operations = { NULL, /* lseek - default */ @@ -55,11 +55,15 @@ NULL, /* mknod */ affs_rename, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL /* permissions */ + NULL, /* permissions */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ }; static ssize_t @@ -76,15 +80,14 @@ int hash_pos; int chain_pos; unsigned long ino; - unsigned long old; int stored; - char *name; - struct buffer_head *dir_bh; - struct buffer_head *fh_bh; - struct inode *dir; - struct inode *inode = filp->f_dentry->d_inode; + unsigned char *name; + struct buffer_head *dir_bh; + struct buffer_head *fh_bh; + struct inode *dir; + struct inode *inode = filp->f_dentry->d_inode; - pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos); + pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos); if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; @@ -93,8 +96,7 @@ dir_bh = NULL; fh_bh = NULL; dir = NULL; - old = filp->f_pos & 0x80000000; - filp->f_pos &= 0x7FFFFFFF; + ino = inode->i_ino; if (filp->f_pos == 0) { filp->private_data = (void *)0; @@ -106,18 +108,11 @@ } if (filp->f_pos == 1) { if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) { - filp->f_pos |= 0x80000000; return stored; } filp->f_pos = 2; stored++; } - - /* Read original if this is a link */ - ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino; - if (!(dir = iget(inode->i_sb,ino))) - return stored; - chain_pos = (filp->f_pos - 2) & 0xffff; hash_pos = (filp->f_pos - 2) >> 16; if (chain_pos == 0xffff) { @@ -126,27 +121,29 @@ hash_pos++; filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; } - if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode)))) + if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino, + AFFS_I2BSIZE(inode)))) goto readdir_done; - while (!stored || !old) { + while (1) { while (hash_pos < AFFS_I2HSIZE(inode) && !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]) hash_pos++; if (hash_pos >= AFFS_I2HSIZE(inode)) - goto readdir_done; + break; - i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]); + i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]); j = chain_pos; + /* If the directory hasn't changed since the last call to readdir(), * we can jump directly to where we left off. */ - if (filp->private_data && filp->f_version == dir->i_version) { + if (filp->private_data && filp->f_version == inode->i_version) { i = (s32)filp->private_data; j = 0; pr_debug("AFFS: readdir() left off=%d\n",i); } - filp->f_version = dir->i_version; + filp->f_version = inode->i_version; pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos); while (i) { if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) { @@ -154,7 +151,7 @@ goto readdir_done; } ino = i; - i = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain); + i = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain); if (j == 0) break; affs_brelse(fh_bh); @@ -163,7 +160,7 @@ } if (fh_bh) { namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name); - pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%d\n", + pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n", namelen,name,ino,i); filp->private_data = (void *)ino; if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0) @@ -182,10 +179,8 @@ } readdir_done: - filp->f_pos |= old; affs_brelse(dir_bh); affs_brelse(fh_bh); - iput(dir); pr_debug("AFFS: readdir()=%d\n",stored); return stored; } diff -u --recursive --new-file v2.1.70/linux/fs/affs/file.c linux/fs/affs/file.c --- v2.1.70/linux/fs/affs/file.c Sat Oct 25 02:44:17 1997 +++ linux/fs/affs/file.c Tue Dec 2 22:25:07 1997 @@ -36,13 +36,10 @@ #endif static int affs_bmap(struct inode *inode, int block); -static struct buffer_head * affs_getblock(struct inode *inode, s32 block); -static ssize_t affs_file_read_ofs(struct file *filp, char *buf, - size_t count, loff_t *ppos); -static ssize_t affs_file_write(struct file *filp, const char *buf, - size_t count, loff_t *ppos); -static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, - size_t count, loff_t *ppos); +static struct buffer_head *affs_getblock(struct inode *inode, s32 block); +static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos); +static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos); +static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cnt, loff_t *ppos); static int affs_release_file(struct inode *inode, struct file *filp); static int alloc_ext_cache(struct inode *inode); @@ -56,7 +53,11 @@ generic_file_mmap, /* mmap */ NULL, /* no special open */ affs_release_file, /* release */ - file_fsync /* brute force, but works */ + file_fsync, /* brute force, but works */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ }; struct inode_operations affs_file_inode_operations = { @@ -71,12 +72,15 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ affs_bmap, /* bmap */ affs_truncate, /* truncate */ NULL, /* permission */ - NULL /* smap */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ }; static struct file_operations affs_file_operations_ofs = { @@ -89,7 +93,11 @@ NULL, /* mmap */ NULL, /* no special open */ affs_release_file, /* release */ - file_fsync /* brute force, but works */ + file_fsync, /* brute force, but works */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ }; struct inode_operations affs_file_inode_operations_ofs = { @@ -104,12 +112,15 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ affs_truncate, /* truncate */ NULL, /* permission */ - NULL /* smap */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ }; #define AFFS_ISINDEX(x) ((x < 129) || \ @@ -255,7 +266,7 @@ /* Try to find the requested key in the cache. * In order to speed this up as much as possible, - * the cache line lookup is done in a seperate + * the cache line lookup is done in a separate * step. */ @@ -306,7 +317,7 @@ affs_brelse(bh); return 0; } - nkey = htonl(FILE_END(bh->b_data,inode)->extension); + nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); if (block < AFFS_I2HSIZE(inode)) { /* Fill cache as much as possible */ if (keycount) { @@ -314,7 +325,7 @@ keycount = keycount < AFFS_I2HSIZE(inode) - block ? keycount : AFFS_I2HSIZE(inode) - block; for (i = 0; i < keycount; i++) - kc->kc_keys[i] = htonl(AFFS_BLOCK(bh->b_data,inode,block + i)); + kc->kc_keys[i] = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block + i)); kc->kc_last = kc->kc_first + i - 1; } break; @@ -331,11 +342,20 @@ kc->kc_this_key = key; kc->kc_this_seq = ext; kc->kc_next_key = nkey; - key = htonl(AFFS_BLOCK(bh->b_data,inode,block)); + key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block)); affs_brelse(bh); return key; } +/* With the affs, getting a random block from a file is not + * a simple business. Since this fs does not allow holes, + * it may be neccessary to allocate all the missing blocks + * inbetween, as well as some new extension blocks. The OFS + * is even worse: All data blocks contain pointers to the + * next ones, so you have to fix [n-1] after allocating [n]. + * What a mess. + */ + static struct buffer_head * affs_getblock(struct inode *inode, s32 block) { @@ -368,7 +388,7 @@ pt = ext ? T_LIST : T_SHORT; pbh = NULL; - for (;;) { + for (;;) { /* Loop over header block and extension blocks */ bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); if (!bh) return NULL; @@ -379,12 +399,12 @@ affs_brelse(bh); return NULL; } - j = htonl(((struct file_front *)bh->b_data)->block_count); + j = be32_to_cpu(((struct file_front *)bh->b_data)->block_count); cf = 0; while (j < AFFS_I2HSIZE(inode) && j <= block) { if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) { if (j > 0) - pbh = affs_bread(inode->i_dev,ntohl(AFFS_BLOCK(bh->b_data,inode,j - 1)), + pbh = affs_bread(inode->i_dev,cpu_to_be32(AFFS_BLOCK(bh->b_data,inode,j - 1)), AFFS_I2BSIZE(inode)); else pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock); @@ -406,7 +426,7 @@ continue; } unlock_super(inode->i_sb); - AFFS_BLOCK(bh->b_data,inode,j) = ntohl(nkey); + AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey); if (ofs) { ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode)); if (!ebh) { @@ -417,12 +437,12 @@ break; } inode->u.affs_i.i_lastblock++; - DATA_FRONT(ebh)->primary_type = ntohl(T_DATA); - DATA_FRONT(ebh)->header_key = ntohl(inode->i_ino); - DATA_FRONT(ebh)->sequence_number = ntohl(inode->u.affs_i.i_lastblock + 1); + DATA_FRONT(ebh)->primary_type = cpu_to_be32(T_DATA); + DATA_FRONT(ebh)->header_key = cpu_to_be32(inode->i_ino); + DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1); if (pbh) { - DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2BSIZE(inode) - 24); - DATA_FRONT(pbh)->next_data = ntohl(nkey); + DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24); + DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey); affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5); mark_buffer_dirty(pbh,0); mark_buffer_dirty(ebh,0); @@ -437,7 +457,7 @@ if (pt == T_SHORT) ((struct file_front *)bh->b_data)->first_data = AFFS_BLOCK(bh->b_data,inode,0); - ((struct file_front *)bh->b_data)->block_count = ntohl(j); + ((struct file_front *)bh->b_data)->block_count = cpu_to_be32(j); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); } @@ -453,7 +473,7 @@ } block -= AFFS_I2HSIZE(inode); - key = htonl(FILE_END(bh->b_data,inode)->extension); + key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); if (!key) { key = affs_new_header(inode); if (!key) { @@ -465,12 +485,12 @@ affs_free_block(inode->i_sb,key); return NULL; } - ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST); - ((struct file_front *)ebh->b_data)->own_key = ntohl(key); - FILE_END(ebh->b_data,inode)->secondary_type = ntohl(ST_FILE); - FILE_END(ebh->b_data,inode)->parent = ntohl(inode->i_ino); + ((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST); + ((struct file_front *)ebh->b_data)->own_key = cpu_to_be32(key); + FILE_END(ebh->b_data,inode)->secondary_type = cpu_to_be32(ST_FILE); + FILE_END(ebh->b_data,inode)->parent = cpu_to_be32(inode->i_ino); affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5); - FILE_END(bh->b_data,inode)->extension = ntohl(key); + FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); @@ -487,8 +507,8 @@ } kc->kc_this_key = key; kc->kc_this_seq = ext; - kc->kc_next_key = htonl(FILE_END(bh->b_data,inode)->extension); - key = htonl(AFFS_BLOCK(bh->b_data,inode,block)); + kc->kc_next_key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); + key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block)); affs_brelse(bh); if (!key) return NULL; @@ -499,14 +519,15 @@ static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; - char *start; - ssize_t left, offset, size, sector; - ssize_t blocksize; - struct buffer_head *bh; - void *data; + struct inode *inode = filp->f_dentry->d_inode; + char *start; + ssize_t left, offset, size, sector; + ssize_t blocksize; + struct buffer_head *bh; + void *data; - pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)*ppos,count); + pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino, + (unsigned long)*ppos,count); if (!inode) { affs_error(inode->i_sb,"file_read_ofs","Inode = NULL"); @@ -553,40 +574,25 @@ ssize_t c; ssize_t blocksize; struct buffer_head *bh; - struct inode *ino; char *p; - /* Not that I wanted to be POSIX compliant ... */ if (!count) return 0; pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, - (unsigned long)*ppos,count); + (unsigned long)*ppos,count); - ino = NULL; if (!inode) { affs_error(inode->i_sb,"file_write","Inode = NULL"); return -EINVAL; } - if (inode->u.affs_i.i_original) { - ino = iget(inode->i_sb,inode->u.affs_i.i_original); - if (!ino) { - affs_error(inode->i_sb,"file_write", - "Could not follow link from inode %lu to %d", - inode->i_ino,inode->u.affs_i.i_original); - return -EINVAL; - } - inode = ino; - } if (!S_ISREG(inode->i_mode)) { affs_error(inode->i_sb,"file_write", "Trying to write to non-regular file (mode=%07o)", inode->i_mode); - iput(inode); return -EINVAL; } if (!inode->u.affs_i.i_ec) { if (alloc_ext_cache(inode)) { - iput(inode); return -ENOMEM; } } @@ -617,8 +623,14 @@ break; } } - p = (pos % blocksize) + bh->b_data; - copy_from_user(p,buf,c); + p = (pos % blocksize) + bh->b_data; + c -= copy_from_user(p,buf,c); + if (!c) { + affs_brelse(bh); + if (!written) + written = -EFAULT; + break; + } update_vm_cache(inode,pos,p,c); mark_buffer_uptodate(bh,1); mark_buffer_dirty(bh,0); @@ -630,22 +642,20 @@ if (pos > inode->i_size) inode->i_size = pos; inode->i_mtime = inode->i_ctime = CURRENT_TIME; - *ppos = pos; + *ppos = pos; mark_inode_dirty(inode); - iput(ino); return written; } static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; off_t pos; ssize_t written; ssize_t c; ssize_t blocksize; struct buffer_head *bh; - struct inode *ino; char *p; pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, @@ -657,24 +667,17 @@ affs_error(inode->i_sb,"file_write_ofs","Inode = NULL"); return -EINVAL; } - ino = NULL; - if (inode->u.affs_i.i_original) { - ino = iget(inode->i_sb,inode->u.affs_i.i_original); - if (!ino) { - affs_error(inode->i_sb,"file_write_ofs", - "Could not follow link from inode %lu to %d", - inode->i_ino,inode->u.affs_i.i_original); - return -EINVAL; - } - inode = ino; - } if (!S_ISREG(inode->i_mode)) { affs_error(inode->i_sb,"file_write_ofs", "Trying to write to non-regular file (mode=%07o)", inode->i_mode); - iput(inode); return -EINVAL; } + if (!inode->u.affs_i.i_ec) { + if (alloc_ext_cache(inode)) { + return -ENOMEM; + } + } if (filp->f_flags & O_APPEND) pos = inode->i_size; else @@ -703,14 +706,20 @@ break; } } - p = (pos % blocksize) + bh->b_data + 24; - copy_from_user(p,buf,c); + p = (pos % blocksize) + bh->b_data + 24; + c -= copy_from_user(p,buf,c); + if (!c) { + affs_brelse(bh); + if (!written) + written = -EFAULT; + break; + } update_vm_cache(inode,pos,p,c); pos += c; buf += c; written += c; - DATA_FRONT(bh)->data_size = ntohl(htonl(DATA_FRONT(bh)->data_size) + c); + DATA_FRONT(bh)->data_size = cpu_to_be32(be32_to_cpu(DATA_FRONT(bh)->data_size) + c); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_uptodate(bh,1); mark_buffer_dirty(bh,0); @@ -721,7 +730,6 @@ *ppos = pos; inode->i_mtime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); - iput(ino); return written; } @@ -730,7 +738,6 @@ { struct buffer_head *bh; struct buffer_head *ebh; - struct inode *ino; struct affs_zone *zone; int first; int block; @@ -745,20 +752,16 @@ pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size); - ino = NULL; - if (inode->u.affs_i.i_original) { - ino = iget(inode->i_sb,inode->u.affs_i.i_original); - if (!ino) { - affs_error(inode->i_sb,"truncate","Cannot follow link from %lu to %d", - inode->i_ino,inode->u.affs_i.i_original); - return; - } - inode = ino; - } blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0); first = (inode->i_size + blocksize - 1) / blocksize; if (inode->u.affs_i.i_lastblock < first - 1) { - bh = affs_getblock(inode,first - 1); + if (!inode->u.affs_i.i_ec) { + if (alloc_ext_cache(inode)) { + /* Fine! No way to indicate an error. What can we do? */ + return; + } + } + bh = affs_getblock(inode,first - 1); while (inode->u.affs_i.i_pa_cnt) { /* Free any preallocated blocks */ affs_free_block(inode->i_sb, @@ -778,12 +781,11 @@ inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1); } else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) { rem = inode->i_size % blocksize; - DATA_FRONT(bh)->data_size = ntohl(rem ? rem : blocksize); + DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : blocksize); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,0); } affs_brelse(bh); - iput(ino); return; } ekey = inode->i_ino; @@ -794,8 +796,8 @@ affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey); break; } - ptype = htonl(((struct file_front *)bh->b_data)->primary_type); - stype = htonl(FILE_END(bh->b_data,inode)->secondary_type); + ptype = be32_to_cpu(((struct file_front *)bh->b_data)->primary_type); + stype = be32_to_cpu(FILE_END(bh->b_data,inode)->secondary_type); if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE && LINK_END(bh->b_data,inode)->original == 0) { pr_debug("AFFS: truncate(): dumping link\n"); @@ -812,7 +814,7 @@ freethis = first == 0 && ekey != inode->i_ino; for (block = first; block < AFFS_I2HSIZE(inode); block++) { keyp = &AFFS_BLOCK(bh->b_data,inode,block); - key = htonl(*keyp); + key = be32_to_cpu(*keyp); if (key) { *keyp = 0; affs_free_block(inode->i_sb,key); @@ -822,18 +824,18 @@ } } keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension; - key = htonl(*keyp); + key = be32_to_cpu(*keyp); if (first <= AFFS_I2HSIZE(inode)) { - ((struct file_front *)bh->b_data)->block_count = htonl(first); + ((struct file_front *)bh->b_data)->block_count = be32_to_cpu(first); first = 0; *keyp = 0; if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) && first > 0) { - block = htonl(AFFS_BLOCK(bh->b_data,inode,first - 1)); + block = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,first - 1)); if ((ebh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { if(!(affs_checksum_block(AFFS_I2BSIZE(inode),ebh->b_data, &ptype,NULL))) { rem = inode->i_size % blocksize; - rem = ntohl(rem ? blocksize : rem); + rem = cpu_to_be32(rem ? blocksize : rem); ((struct data_front *)ebh->b_data)->data_size = rem; ((struct data_front *)ebh->b_data)->next_data = 0; affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5); @@ -866,7 +868,6 @@ } } - iput(ino); } static int @@ -899,6 +900,8 @@ { s32 key; int i; + + pr_debug("AFFS: alloc_ext_cache(ino=%lu)\n",inode->i_ino); lock_super(inode->i_sb); if (!inode->u.affs_i.i_ec) { diff -u --recursive --new-file v2.1.70/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v2.1.70/linux/fs/affs/inode.c Thu Sep 11 09:02:23 1997 +++ linux/fs/affs/inode.c Tue Dec 2 22:25:07 1997 @@ -10,7 +10,7 @@ * (C) 1991 Linus Torvalds - minix filesystem */ -#include +#define DEBUG 0 #include #include #include @@ -30,106 +30,17 @@ #include #include -/* AmigaOS allows file names with up to 30 characters length. - * Names longer than that will be silently truncated. If you - * want to disallow this, comment out the following #define. - * Creating filesystem objects with longer names will then - * result in an error (ENAMETOOLONG). - */ -/*#define NO_TRUNCATE */ - extern int *blk_size[]; extern struct timezone sys_tz; #define MIN(a,b) (((a)<(b))?(a):(b)) -static int affs_notify_change(struct inode *inode, struct iattr *attr); -static void affs_put_inode(struct inode *inode); -static void affs_read_inode(struct inode *inode); -static void affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); -static void affs_write_inode(struct inode *inode); - -static void -affs_put_super(struct super_block *sb) -{ - int i; - - pr_debug("affs_put_super()\n"); - - lock_super(sb); - for (i = 0; i < sb->u.affs_sb.s_bm_count; i++) - affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh); - if (!(sb->s_flags & MS_RDONLY)) { - ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1); - secs_to_datestamp(CURRENT_TIME, - &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); - affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); - } - - if (sb->u.affs_sb.s_flags & SF_PREFIX) - kfree(sb->u.affs_sb.s_prefix); - kfree(sb->u.affs_sb.s_bitmap); - affs_brelse(sb->u.affs_sb.s_root_bh); - - /* I'm not happy with this. It would be better to save the previous - * value of this devices blksize_size[][] in the super block and - * restore it here, but with the affs superblock being quite large - * already ... - */ - set_blocksize(sb->s_dev,BLOCK_SIZE); - - sb->s_dev = 0; - unlock_super(sb); - MOD_DEC_USE_COUNT; - return; -} - -static void -affs_write_super(struct super_block *sb) -{ - int i, clean = 2; - - if (!(sb->s_flags & MS_RDONLY)) { - lock_super(sb); - for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) { - if (sb->u.affs_sb.s_bitmap[i].bm_bh) { - if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) { - clean = 0; - break; - } - } - } - unlock_super(sb); - ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(clean); - secs_to_datestamp(CURRENT_TIME, - &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); - affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); - sb->s_dirt = !clean; /* redo until bitmap synced */ - } else - sb->s_dirt = 0; - - pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean); -} - -static struct super_operations affs_sops = { - affs_read_inode, - affs_notify_change, - affs_write_inode, - affs_put_inode, - affs_put_super, - affs_write_super, - affs_statfs, - NULL /* remount */ -}; - unsigned long affs_parent_ino(struct inode *dir) { int root_ino = (dir->i_sb->u.affs_sb.s_root_block); - if (!S_ISDIR (dir->i_mode)) { + if (!S_ISDIR(dir->i_mode)) { affs_error(dir->i_sb,"parent_ino","Trying to get parent of non-directory"); return root_ino; } @@ -138,524 +49,10 @@ return dir->u.affs_i.i_parent; } -static int -parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root, - int *blocksize, char **prefix, char *volume, unsigned long *mount_opts) -{ - char *this_char, *value; - int f; - - /* Fill in defaults */ - - *uid = 0; - *gid = 0; - *reserved = 2; - *root = -1; - *blocksize = -1; - *prefix = "/"; - volume[0] = ':'; - volume[1] = 0; - *mount_opts = 0; - if (!options) - return 1; - for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { - f = 0; - if ((value = strchr(this_char,'=')) != NULL) - *value++ = 0; - if (!strcmp(this_char,"protect")) { - if (value) { - printk("AFFS: Option protect does not take an argument\n"); - return 0; - } - *mount_opts |= SF_IMMUTABLE; - } - else if (!strcmp(this_char,"verbose")) { - if (value) { - printk("AFFS: Option verbose does not take an argument\n"); - return 0; - } - *mount_opts |= SF_VERBOSE; - } - else if ((f = !strcmp(this_char,"uid")) || !strcmp(this_char,"setuid")) { - if (!value) - *uid = current->uid; - else if (!*value) { - printk("AFFS: Argument for uid option missing\n"); - return 0; - } else { - *uid = simple_strtoul(value,&value,0); - if (*value) - return 0; - if (!f) - *mount_opts |= SF_SETUID; - } - } - else if ((f = !strcmp(this_char,"gid")) || !strcmp(this_char,"setgid")) { - if (!value) - *gid = current->gid; - else if (!*value) { - printk("AFFS: Argument for gid option missing\n"); - return 0; - } else { - *gid = simple_strtoul(value,&value,0); - if (*value) - return 0; - if (!f) - *mount_opts |= SF_SETGID; - } - } - else if (!strcmp(this_char,"prefix")) { - if (!value) { - printk("AFFS: The prefix option requires an argument\n"); - return 0; - } - *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL); - if (!*prefix) - return 0; - strcpy(*prefix,value); - *mount_opts |= SF_PREFIX; - } - else if (!strcmp(this_char,"volume")) { - if (!value) { - printk("AFFS: The volume option requires an argument\n"); - return 0; - } - if (strlen(value) > 30) - value[30] = 0; - strcpy(volume,value); - } - else if (!strcmp(this_char,"mode")) { - if (!value || !*value) { - printk("AFFS: The mode option requires an argument\n"); - return 0; - } - *mode = simple_strtoul(value,&value,8) & 0777; - if (*value) - return 0; - *mount_opts |= SF_SETMODE; - } - else if (!strcmp(this_char,"reserved")) { - if (!value || !*value) { - printk("AFFS: The reserved option requires an argument\n"); - return 0; - } - *reserved = simple_strtoul(value,&value,0); - if (*value) - return 0; - } - else if (!strcmp(this_char,"root")) { - if (!value || !*value) { - printk("AFFS: The root option requires an argument\n"); - return 0; - } - *root = simple_strtoul(value,&value,0); - if (*value) - return 0; - } - else if (!strcmp(this_char,"bs")) { - if (!value || !*value) { - printk("AFFS: The bs option requires an argument\n"); - return 0; - } - *blocksize = simple_strtoul(value,&value,0); - if (*value) - return 0; - if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048 - && *blocksize != 4096) { - printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n"); - return 0; - } - } - /* Silently ignore the quota options */ - else if (!strcmp (this_char, "grpquota") - || !strcmp (this_char, "noquota") - || !strcmp (this_char, "quota") - || !strcmp (this_char, "usrquota")) - ; - else { - printk("AFFS: Unrecognized mount option %s\n", this_char); - return 0; - } - } - return 1; -} - -/* This function definitely needs to be split up. Some fine day I'll - * hopefully have the guts to do so. Until then: sorry for the mess. - */ - -static struct super_block * -affs_read_super(struct super_block *s,void *data, int silent) -{ - struct buffer_head *bh = NULL; - struct buffer_head *bb; - kdev_t dev = s->s_dev; - s32 root_block; - int size; - u32 chksum; - u32 *bm; - s32 ptype, stype; - int mapidx; - int num_bm; - int i, j; - s32 key; - int blocksize; - uid_t uid; - gid_t gid; - int reserved; - int az_no; - unsigned long mount_flags; - unsigned long offset; - - pr_debug("affs_read_super(%s)\n",data ? (const char *)data : "no options"); - - MOD_INC_USE_COUNT; - - if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, - &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) { - s->s_dev = 0; - printk(KERN_ERR "AFFS: Error parsing options\n"); - MOD_DEC_USE_COUNT; - return NULL; - } - lock_super(s); - - /* Get the size of the device in 512-byte blocks. - * If we later see that the partition uses bigger - * blocks, we will have to change it. - */ - - size = blksize_size[MAJOR(dev)][MINOR(dev)]; - size = (size ? size : BLOCK_SIZE) / 512 * blk_size[MAJOR(dev)][MINOR(dev)]; - - s->u.affs_sb.s_bitmap = NULL; - s->u.affs_sb.s_root_bh = NULL; - s->u.affs_sb.s_flags = mount_flags; - s->u.affs_sb.s_mode = i; - s->u.affs_sb.s_uid = uid; - s->u.affs_sb.s_gid = gid; - - if (size == 0) { - s->s_dev = 0; - unlock_super(s); - printk(KERN_ERR "AFFS: Could not determine device size\n"); - goto out; - } - s->u.affs_sb.s_partition_size = size; - s->u.affs_sb.s_reserved = reserved; - - /* Try to find root block. Its location depends on the block size. */ - - s->u.affs_sb.s_hashsize = 0; - if (blocksize > 0) { - i = blocksize; - j = blocksize; - } else { - i = 512; - j = 4096; - } - for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) { - if (root_block < 0) - s->u.affs_sb.s_root_block = (reserved + size - 1) / 2; - else - s->u.affs_sb.s_root_block = root_block; - set_blocksize(dev,blocksize); - - /* The root block location that was calculated above is not - * correct if the partition size is an odd number of 512- - * byte blocks, which will be rounded down to a number of - * 1024-byte blocks, and if there were an even number of - * reserved blocks. Ideally, all partition checkers should - * report the real number of blocks of the real blocksize, - * but since this just cannot be done, we have to try to - * find the root block anyways. In the above case, it is one - * block behind the calculated one. So we check this one, too. - */ - for (num_bm = 0; num_bm < 2; num_bm++) { - pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, " - "size=%d blocks, %d reserved\n",kdevname(dev),blocksize, - s->u.affs_sb.s_root_block + num_bm,size,reserved); - bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize); - if (!bh) { - printk(KERN_ERR "AFFS: Cannot read root block\n"); - goto out; - } - if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) && - ptype == T_SHORT && stype == ST_ROOT) { - s->s_blocksize = blocksize; - s->u.affs_sb.s_hashsize = blocksize / 4 - 56; - s->u.affs_sb.s_root_block += num_bm; - key = 1; - break; - } - } - if (key) - break; - affs_brelse(bh); - bh = NULL; - } - if (!key) { - affs_brelse(bh); - if (!silent) - printk(KERN_ERR "AFFS: Cannot find a valid root block on device %s\n", - kdevname(dev)); - goto out; - } - root_block = s->u.affs_sb.s_root_block; - - s->u.affs_sb.s_partition_size = size; - s->s_blocksize_bits = blocksize == 512 ? 9 : - blocksize == 1024 ? 10 : - blocksize == 2048 ? 11 : 12; - - /* Find out which kind of FS we have */ - bb = affs_bread(dev,0,s->s_blocksize); - if (bb) { - chksum = htonl(*(u32 *)bb->b_data); - - /* Dircache filesystems are compatible with non-dircache ones - * when reading. As long as they aren't supported, writing is - * not recommended. - */ - if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS - || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) { - printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n", - kdevname(dev)); - s->s_flags |= MS_RDONLY; - } - switch (chksum) { - case MUFS_FS: - case MUFS_INTLFFS: - s->u.affs_sb.s_flags |= SF_MUFS; - /* fall thru */ - case FS_INTLFFS: - s->u.affs_sb.s_flags |= SF_INTL; - break; - case MUFS_DCFFS: - case MUFS_FFS: - s->u.affs_sb.s_flags |= SF_MUFS; - break; - case FS_DCFFS: - case FS_FFS: - break; - case MUFS_OFS: - s->u.affs_sb.s_flags |= SF_MUFS; - /* fall thru */ - case FS_OFS: - s->u.affs_sb.s_flags |= SF_OFS; - break; - case MUFS_DCOFS: - case MUFS_INTLOFS: - s->u.affs_sb.s_flags |= SF_MUFS; - case FS_DCOFS: - case FS_INTLOFS: - s->u.affs_sb.s_flags |= SF_INTL | SF_OFS; - break; - default: - printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", - kdevname(dev),chksum); - affs_brelse(bb); - goto out; - } - affs_brelse(bb); - } else { - printk(KERN_ERR "AFFS: Cannot read boot block\n"); - goto out; - } - if (mount_flags & SF_VERBOSE) { - chksum = ntohl(chksum); - printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n", - GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0], - &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1], - (char *)&chksum,((char *)&chksum)[3] + '0',blocksize); - } - - s->s_magic = AFFS_SUPER_MAGIC; - s->s_flags |= MS_NODEV | MS_NOSUID; - - /* Keep super block in cache */ - if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) { - printk(KERN_ERR "AFFS: Cannot read root block\n"); - goto out; - } - - /* Allocate space for bitmaps, zones and others */ - - size = s->u.affs_sb.s_partition_size - reserved; - num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32); - az_no = (size + AFFS_ZONE_SIZE - 1) / (AFFS_ZONE_SIZE - 32); - ptype = num_bm * sizeof(struct affs_bm_info) + - az_no * sizeof(struct affs_alloc_zone) + - MAX_ZONES * sizeof(struct affs_zone); - pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype); - if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) { - printk(KERN_ERR "AFFS: Not enough memory\n"); - goto out; - } - memset(s->u.affs_sb.s_bitmap,0,ptype); - - s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm]; - s->u.affs_sb.s_alloc = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES]; - s->u.affs_sb.s_num_az = az_no; - - mapidx = 0; - - if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) { - if (!(s->s_flags & MS_RDONLY)) { - printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n", - kdevname(dev)); - s->s_flags |= MS_RDONLY; - } - affs_brelse(bh); - bh = NULL; - goto nobitmap; - } - - /* The following section is ugly, I know. Especially because of the - * reuse of some variables that are not named properly. - */ - - key = root_block; - ptype = s->s_blocksize / 4 - 49; - stype = ptype + 25; - offset = s->u.affs_sb.s_reserved; - az_no = 0; - while (bh) { - bm = (u32 *)bh->b_data; - for (i = ptype; i < stype && bm[i]; i++, mapidx++) { - if (mapidx >= num_bm) { - printk(KERN_ERR "AFFS: Not enough bitmap space!?\n"); - goto out; - } - bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize); - if (bb) { - if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) && - !(s->s_flags & MS_RDONLY)) { - printk(KERN_WARNING "AFFS: Bitmap (%d,key=%lu) invalid - " - "mounting %s read only.\n",mapidx,htonl(bm[i]), - kdevname(dev)); - s->s_flags |= MS_RDONLY; - } - /* Mark unused bits in the last word as allocated */ - if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */ - ptype = size / 32 + 1; /* word number */ - key = size & 0x1F; /* used bits */ - if (key) { - chksum = ntohl(0x7FFFFFFF >> (31 - key)); - ((u32 *)bb->b_data)[ptype] &= chksum; - affs_fix_checksum(s->s_blocksize,bb->b_data,0); - mark_buffer_dirty(bb,1); - } - ptype = (size + 31) & ~0x1F; - size = 0; - s->u.affs_sb.s_flags |= SF_BM_VALID; - } else { - ptype = s->s_blocksize * 8 - 32; - size -= ptype; - } - s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset; - s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL; - s->u.affs_sb.s_bitmap[mapidx].bm_key = htonl(bm[i]); - s->u.affs_sb.s_bitmap[mapidx].bm_count = 0; - offset += ptype; - - for (j = 0; ptype > 0; j++, az_no++, ptype -= key) { - key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */ - s->u.affs_sb.s_alloc[az_no].az_size = key / 32; - s->u.affs_sb.s_alloc[az_no].az_free = - affs_count_free_bits(key / 8,bb->b_data + - j * (AFFS_ZONE_SIZE / 8) + 4); - } - affs_brelse(bb); - } else { - printk(KERN_ERR "AFFS: Cannot read bitmap\n"); - goto out; - } - } - key = htonl(bm[stype]); /* Next block of bitmap pointers */ - ptype = 0; - stype = s->s_blocksize / 4 - 1; - affs_brelse(bh); - if (key) { - if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) { - printk(KERN_ERR "AFFS: Cannot read bitmap extension\n"); - goto out; - } - } else - bh = NULL; - } - if (mapidx != num_bm) { - printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm); - goto out; - } -nobitmap: - s->u.affs_sb.s_bm_count = mapidx; - - /* set up enough so that it can read an inode */ - - s->s_dev = dev; - s->s_op = &affs_sops; - s->s_root = d_alloc_root(iget(s,root_block),NULL); - s->s_dirt = 1; - unlock_super(s); - - if (!(s->s_root)) { - s->s_dev = 0; - printk(KERN_ERR "AFFS: get root inode failed\n"); - MOD_DEC_USE_COUNT; - return NULL; - } - - /* create data zones if the fs is mounted r/w */ - - if (!(s->s_flags & MS_RDONLY)) { - ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_root->d_inode)->bm_flag = 0; - secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data, - s->s_root->d_inode)->disk_altered); - affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(s->u.affs_sb.s_root_bh,1); - affs_make_zones(s); - } - - pr_debug("AFFS: s_flags=%lX\n",s->s_flags); - return s; - - out: /* Kick out for various error conditions */ - affs_brelse (bh); - affs_brelse(s->u.affs_sb.s_root_bh); - if (s->u.affs_sb.s_bitmap) - kfree(s->u.affs_sb.s_bitmap); - set_blocksize(dev,BLOCK_SIZE); - s->s_dev = 0; - unlock_super(s); - MOD_DEC_USE_COUNT; - return NULL; -} - -static void -affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) -{ - int free; - struct statfs tmp; - - pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size, - sb->u.affs_sb.s_reserved); - - free = affs_count_free_blocks(sb); - tmp.f_type = AFFS_SUPER_MAGIC; - tmp.f_bsize = sb->s_blocksize; - tmp.f_blocks = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved; - tmp.f_bfree = free; - tmp.f_bavail = free; - tmp.f_files = 0; - tmp.f_ffree = 0; - copy_to_user(buf,&tmp,bufsiz); -} - -static void +void affs_read_inode(struct inode *inode) { - struct buffer_head *bh, *lbh; + struct buffer_head *bh; struct file_front *file_front; struct file_end *file_end; s32 block; @@ -665,7 +62,6 @@ pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino); - lbh = NULL; block = inode->i_ino; if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { affs_error(inode->i_sb,"read_inode","Cannot read block %d",block); @@ -680,10 +76,10 @@ file_front = (struct file_front *)bh->b_data; file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode)); - prot = (htonl(file_end->protect) & ~0x10) ^ FIBF_OWNER; + prot = (be32_to_cpu(file_end->protect) & ~0x10) ^ FIBF_OWNER; inode->u.affs_i.i_protect = prot; - inode->u.affs_i.i_parent = htonl(file_end->parent); + inode->u.affs_i.i_parent = be32_to_cpu(file_end->parent); inode->u.affs_i.i_original = 0; inode->u.affs_i.i_zone = 0; inode->u.affs_i.i_hlink = 0; @@ -702,31 +98,28 @@ if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID) inode->i_uid = inode->i_sb->u.affs_sb.s_uid; - else { - id = htons(file_end->owner_uid); - if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) { - if (id == 0 || id == 0xFFFF) - id ^= ~0; - } + id = be16_to_cpu(file_end->owner_uid); + if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETUID) + inode->i_uid = inode->i_sb->u.affs_sb.s_uid; + else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS) + inode->i_uid = 0; + else inode->i_uid = id; - } - if (inode->i_sb->u.affs_sb.s_flags & SF_SETGID) + + id = be16_to_cpu(file_end->owner_gid); + if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETGID) inode->i_gid = inode->i_sb->u.affs_sb.s_gid; - else { - id = htons(file_end->owner_gid); - if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) { - if (id == 0 || id == 0xFFFF) - id ^= ~0; - } + else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS) + inode->i_gid = 0; + else inode->i_gid = id; - } - switch (htonl(file_end->secondary_type)) { + switch (be32_to_cpu(file_end->secondary_type)) { case ST_ROOT: inode->i_uid = inode->i_sb->u.affs_sb.s_uid; inode->i_gid = inode->i_sb->u.affs_sb.s_gid; case ST_USERDIR: - if (htonl(file_end->secondary_type) == ST_USERDIR || + if (be32_to_cpu(file_end->secondary_type) == ST_USERDIR || inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) { if (inode->i_mode & S_IRUSR) inode->i_mode |= S_IXUSR; @@ -740,25 +133,16 @@ inode->i_size = 0; break; case ST_LINKDIR: - inode->u.affs_i.i_original = htonl(file_end->original); - inode->u.affs_i.i_hlink = 1; - inode->i_mode |= S_IFDIR; - inode->i_size = 0; - break; + affs_error(inode->i_sb,"read_inode","inode is LINKDIR"); + affs_brelse(bh); + return; case ST_LINKFILE: - inode->u.affs_i.i_original = htonl(file_end->original); - inode->u.affs_i.i_hlink = 1; - if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original, - AFFS_I2BSIZE(inode)))) { - affs_brelse(bh); - affs_error(inode->i_sb,"read_inode","Cannot read block %lu", - inode->i_ino); - return; - } - file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode)); + affs_error(inode->i_sb,"read_inode","inode is LINKFILE"); + affs_brelse(bh); + return; case ST_FILE: inode->i_mode |= S_IFREG; - inode->i_size = htonl(file_end->byte_size); + inode->i_size = be32_to_cpu(file_end->byte_size); if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) block = AFFS_I2BSIZE(inode) - 24; else @@ -772,13 +156,12 @@ } inode->i_mtime = inode->i_atime = inode->i_ctime - = (htonl(file_end->created.ds_Days) * (24 * 60 * 60) + - htonl(file_end->created.ds_Minute) * 60 + - htonl(file_end->created.ds_Tick) / 50 + + = (be32_to_cpu(file_end->created.ds_Days) * (24 * 60 * 60) + + be32_to_cpu(file_end->created.ds_Minute) * 60 + + be32_to_cpu(file_end->created.ds_Tick) / 50 + ((8 * 365 + 2) * 24 * 60 * 60)) + sys_tz.tz_minuteswest * 60; affs_brelse(bh); - affs_brelse(lbh); inode->i_op = NULL; if (S_ISREG(inode->i_mode)) { @@ -793,7 +176,7 @@ inode->i_op = &affs_symlink_inode_operations; } -static void +void affs_write_inode(struct inode *inode) { struct buffer_head *bh; @@ -810,11 +193,11 @@ return; } file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode)); - if (file_end->secondary_type == htonl(ST_ROOT)) { + if (file_end->secondary_type == be32_to_cpu(ST_ROOT)) { secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered); } else { - file_end->protect = ntohl(inode->u.affs_i.i_protect ^ FIBF_OWNER); - file_end->byte_size = ntohl(inode->i_size); + file_end->protect = cpu_to_be32(inode->u.affs_i.i_protect ^ FIBF_OWNER); + file_end->byte_size = cpu_to_be32(inode->i_size); secs_to_datestamp(inode->i_mtime,&file_end->created); if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) { uid = inode->i_uid; @@ -826,9 +209,9 @@ gid = inode->i_gid ^ ~0; } if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) - file_end->owner_uid = ntohs(uid); + file_end->owner_uid = cpu_to_be16(uid); if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) - file_end->owner_gid = ntohs(gid); + file_end->owner_gid = cpu_to_be16(gid); } } affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); @@ -836,7 +219,7 @@ brelse(bh); } -static int +int affs_notify_change(struct inode *inode, struct iattr *attr) { int error; @@ -864,19 +247,23 @@ return 0; } -static void +void affs_put_inode(struct inode *inode) { pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink); lock_super(inode->i_sb); if (inode->u.affs_i.i_ec) { + pr_debug("AFFS: freeing ext cache\n"); free_page((unsigned long)inode->u.affs_i.i_ec); inode->u.affs_i.i_ec = NULL; } unlock_super(inode->i_sb); - if (inode->i_nlink) { - return; - } +} + +void +affs_delete_inode(struct inode *inode) +{ + pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink); inode->i_size = 0; if (S_ISREG(inode->i_mode) && !inode->u.affs_i.i_hlink) affs_truncate(inode); @@ -916,15 +303,15 @@ inode->i_blksize = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->u.affs_i.i_original = 0; - inode->u.affs_i.i_parent = dir->i_ino; - inode->u.affs_i.i_zone = 0; - inode->u.affs_i.i_hlink = 0; - inode->u.affs_i.i_pa_cnt = 0; - inode->u.affs_i.i_pa_next = 0; - inode->u.affs_i.i_pa_last = 0; - inode->u.affs_i.i_ec = NULL; - inode->u.affs_i.i_lastblock = -1; + inode->u.affs_i.i_original = 0; + inode->u.affs_i.i_parent = dir->i_ino; + inode->u.affs_i.i_zone = 0; + inode->u.affs_i.i_hlink = 0; + inode->u.affs_i.i_pa_cnt = 0; + inode->u.affs_i.i_pa_next = 0; + inode->u.affs_i.i_pa_last = 0; + inode->u.affs_i.i_ec = NULL; + inode->u.affs_i.i_lastblock = -1; insert_inode_hash(inode); mark_inode_dirty(inode); @@ -934,23 +321,27 @@ int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, - const char *name, int len, int type) + struct dentry *dentry, int type) { struct buffer_head *dir_bh; struct buffer_head *inode_bh; struct buffer_head *link_bh; - struct buffer_head *ibh; int retval; - int i; - s32 next; + const unsigned char *name = dentry->d_name.name; + int len = dentry->d_name.len; - pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d\n",dir->i_ino,inode->i_ino, + pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d)\n",dir->i_ino,inode->i_ino, len,name,type); - dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); - inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); - link_bh = NULL; - retval = -EIO; + if ((retval = affs_check_name(name,len))) + return retval; + if (len > 30) + len = 30; + + dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); + inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); + link_bh = NULL; + retval = -EIO; if (!dir_bh || !inode_bh) goto addentry_done; if (link) { @@ -958,57 +349,21 @@ if (!link_bh) goto addentry_done; } - ((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT); - ((struct dir_front *)inode_bh->b_data)->own_key = ntohl(inode->i_ino); - - retval = -ENAMETOOLONG; - if (len > 30) -#ifdef NO_TRUNCATE - goto addentry_done; -#else - len = 30; -#endif - - /* Check if name is valid */ - retval = -EINVAL; - for (i = 0; i < len; i++) { - if (name[i] < ' ' || name[i] == ':' - || ((unsigned char)name[i] > 0x7e && (unsigned char)name[i] < 0xa0)) - goto addentry_done; - } - retval = 0; - DIR_END(inode_bh->b_data,inode)->dir_name[0] = len; + ((struct dir_front *)inode_bh->b_data)->primary_type = cpu_to_be32(T_SHORT); + ((struct dir_front *)inode_bh->b_data)->own_key = cpu_to_be32(inode->i_ino); + DIR_END(inode_bh->b_data,inode)->dir_name[0] = len; strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len); - DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type); - DIR_END(inode_bh->b_data,inode)->parent = ntohl(dir->i_ino); - - i = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir)) + 6; - next = dir->i_ino; - - /* Alas, we have to search the insertion point with a locked sb */ + DIR_END(inode_bh->b_data,inode)->secondary_type = cpu_to_be32(type); + DIR_END(inode_bh->b_data,inode)->parent = cpu_to_be32(dir->i_ino); lock_super(inode->i_sb); - while (1) { - if (!(ibh = affs_bread(dir->i_dev,next,AFFS_I2BSIZE(dir)))) - goto addentry_done; - next = htonl(((s32 *)ibh->b_data)[i]); - if (!next || next > inode->i_ino) - break; - i = AFFS_I2BSIZE(dir) / 4 - 4; - affs_brelse(ibh); - } - - DIR_END(inode_bh->b_data,inode)->hash_chain = next; - ((s32 *)ibh->b_data)[i] = ntohl(inode->i_ino); - affs_fix_checksum(AFFS_I2BSIZE(dir),ibh->b_data,5); - mark_buffer_dirty(ibh,1); - affs_brelse(ibh); + retval = affs_insert_hash(dir->i_ino,inode_bh,dir); if (link_bh) { - LINK_END(inode_bh->b_data,inode)->original = ntohl(link->i_ino); + LINK_END(inode_bh->b_data,inode)->original = cpu_to_be32(link->i_ino); LINK_END(inode_bh->b_data,inode)->link_chain = FILE_END(link_bh->b_data,link)->link_chain; - FILE_END(link_bh->b_data,link)->link_chain = ntohl(inode->i_ino); + FILE_END(link_bh->b_data,link)->link_chain = cpu_to_be32(inode->i_ino); affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5); link->i_version = ++event; mark_inode_dirty(link); @@ -1032,32 +387,3 @@ return retval; } - -static struct file_system_type affs_fs_type = { - "affs", - FS_REQUIRES_DEV, - affs_read_super, - NULL -}; - -__initfunc(int init_affs_fs(void)) -{ - return register_filesystem(&affs_fs_type); -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -int -init_module(void) -{ - return register_filesystem(&affs_fs_type); -} - -void -cleanup_module(void) -{ - unregister_filesystem(&affs_fs_type); -} - -#endif diff -u --recursive --new-file v2.1.70/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v2.1.70/linux/fs/affs/namei.c Mon Aug 18 18:19:46 1997 +++ linux/fs/affs/namei.c Tue Dec 2 22:25:07 1997 @@ -8,6 +8,7 @@ * (C) 1991 Linus Torvalds - minix filesystem */ +#define DEBUG 0 #include #include #include @@ -20,8 +21,6 @@ #include -static int affs_fixup(struct buffer_head *bh, struct inode *inode); - /* Simple toupper() for DOS\1 */ static inline unsigned int @@ -45,7 +44,7 @@ */ static int -affs_match(const char *name, int len, const char *compare, int dlen, int intl) +affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl) { if (!compare) return 0; @@ -62,14 +61,14 @@ return 0; if (intl) { while (dlen--) { - if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF)) + if (affs_intl_toupper(*name) != affs_intl_toupper(*compare)) return 0; name++; compare++; } } else { while (dlen--) { - if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF)) + if (affs_toupper(*name) != affs_toupper(*compare)) return 0; name++; compare++; @@ -79,7 +78,7 @@ } int -affs_hash_name(const char *name, int len, int intl, int hashsize) +affs_hash_name(const unsigned char *name, int len, int intl, int hashsize) { unsigned int i, x; @@ -97,14 +96,15 @@ } static struct buffer_head * -affs_find_entry(struct inode *dir, const char *name, int namelen, - unsigned long *ino) +affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino) { - struct buffer_head *bh; - int intl; - s32 key; + struct buffer_head *bh; + int intl; + s32 key; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; - pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name); + pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name); intl = AFFS_I2FSTYPE(dir); bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); @@ -123,7 +123,7 @@ key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir))); for (;;) { - char *cname; + unsigned char *cname; int cnamelen; affs_brelse(bh); @@ -137,154 +137,127 @@ cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname); if (affs_match(name,namelen,cname,cnamelen,intl)) break; - key = htonl(FILE_END(bh->b_data,dir)->hash_chain); + key = be32_to_cpu(FILE_END(bh->b_data,dir)->hash_chain); } *ino = key; return bh; } int -affs_lookup(struct inode *dir, const char *name, int len, struct inode **result) +affs_lookup(struct inode *dir, struct dentry *dentry) { - int res; - unsigned long ino; - struct buffer_head *bh; - - pr_debug("AFFS: lookup(%.*s)\n",len,name); + unsigned long ino; + struct buffer_head *bh; + struct inode *inode; - *result = NULL; - if (!dir) - return -ENOENT; + pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name); - res = -ENOENT; - if (S_ISDIR(dir->i_mode)) { - if ((bh = affs_find_entry(dir,name,len,&ino))) { - if (FILE_END(bh->b_data,dir)->original) - ino = htonl(FILE_END(bh->b_data,dir)->original); - affs_brelse(bh); - if ((*result = iget(dir->i_sb,ino))) - res = 0; - else - res = -EACCES; - } + inode = NULL; + bh = affs_find_entry(dir,dentry,&ino); + if (bh) { + if (FILE_END(bh->b_data,dir)->original) + ino = be32_to_cpu(FILE_END(bh->b_data,dir)->original); + affs_brelse(bh); + inode = iget(dir->i_sb,ino); + if (!inode) + return -EACCES; } - iput(dir); - return res; + d_add(dentry,inode); + return 0; } int -affs_unlink(struct inode *dir, const char *name, int len) +affs_unlink(struct inode *dir, struct dentry *dentry) { int retval; struct buffer_head *bh; unsigned long ino; struct inode *inode; - pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name); + pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name); bh = NULL; - inode = NULL; retval = -ENOENT; - if (!(bh = affs_find_entry(dir,name,len,&ino))) { - goto unlink_done; - } - if (!(inode = iget(dir->i_sb,ino))) { + if (!dir) goto unlink_done; - } - if (S_ISDIR(inode->i_mode)) { - retval = -EPERM; + if (!(bh = affs_find_entry(dir,dentry,&ino))) goto unlink_done; - } - if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir), - AFFS_I2HSIZE(dir)) + 6,ino, - FILE_END(bh->b_data,dir)->hash_chain))) + inode = dentry->d_inode; + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) goto unlink_done; - - if ((retval = affs_fixup(bh,inode))) + if (current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid && !fsuser()) goto unlink_done; - inode->i_nlink=0; - mark_inode_dirty(inode); + if ((retval = affs_remove_header(bh,inode)) < 0) + goto unlink_done; + + inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_version = ++event; - mark_inode_dirty(dir); + mark_inode_dirty(inode); + retval = 0; + d_delete(dentry); unlink_done: affs_brelse(bh); - iput(inode); - iput(dir); return retval; } int -affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result) +affs_create(struct inode *dir, struct dentry *dentry, int mode) { struct inode *inode; int error; - pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); + pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len, + dentry->d_name.name,mode); - *result = NULL; - if (!dir || !dir->i_sb) { - iput(dir); - return -EINVAL; - } + if (!dir) + return -ENOENT; inode = affs_new_inode(dir); - if (!inode) { - iput (dir); + if (!inode) return -ENOSPC; - } - inode->i_mode = mode; + + pr_debug(" -- ino=%lu\n",inode->i_ino); if (dir->i_sb->u.affs_sb.s_flags & SF_OFS) inode->i_op = &affs_file_inode_operations_ofs; else inode->i_op = &affs_file_inode_operations; - error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE); + error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE); if (error) { - iput(dir); inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); - return -ENOSPC; + return error; } + inode->i_mode = mode; inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); - - iput(dir); - *result = inode; + dir->i_version = ++event; + mark_inode_dirty(dir); + d_instantiate(dentry,inode); return 0; } int -affs_mkdir(struct inode *dir, const char *name, int len, int mode) +affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct inode *inode; - struct buffer_head *bh; - unsigned long i; int error; - pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); + pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name,mode); - if (!dir || !dir->i_sb) { - iput(dir); - return -EINVAL; - } - bh = affs_find_entry(dir,name,len,&i); - if (bh) { - affs_brelse(bh); - iput(dir); - return -EEXIST; - } inode = affs_new_inode(dir); - if (!inode) { - iput (dir); + if (!inode) return -ENOSPC; - } + inode->i_op = &affs_dir_inode_operations; - error = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR); + error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR); if (error) { - iput(dir); inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); @@ -292,9 +265,9 @@ } inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); - - iput(dir); - iput(inode); + dir->i_version = ++event; + mark_inode_dirty(dir); + d_instantiate(dentry,inode); return 0; } @@ -310,26 +283,29 @@ } int -affs_rmdir(struct inode *dir, const char *name, int len) +affs_rmdir(struct inode *dir, struct dentry *dentry) { int retval; unsigned long ino; struct inode *inode; struct buffer_head *bh; - pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name); + pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name); inode = NULL; + bh = NULL; retval = -ENOENT; - if (!(bh = affs_find_entry(dir,name,len,&ino))) { + if (!dir) goto rmdir_done; - } - if (!(inode = iget(dir->i_sb,ino))) { + if (!(bh = affs_find_entry(dir,dentry,&ino))) goto rmdir_done; - } + + inode = dentry->d_inode; + retval = -EPERM; - if (!fsuser() && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + if (current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid && !fsuser()) goto rmdir_done; if (inode->i_dev != dir->i_dev) goto rmdir_done; @@ -339,6 +315,11 @@ retval = -ENOTDIR; goto rmdir_done; } + down(&inode->i_sem); + if (dentry->d_count > 1) { + shrink_dcache_parent(dentry); + } + up(&inode->i_sem); if (!empty_dir(bh,AFFS_I2HSIZE(inode))) { retval = -ENOTEMPTY; goto rmdir_done; @@ -347,28 +328,21 @@ retval = -EBUSY; goto rmdir_done; } - if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir), - AFFS_I2HSIZE(dir)) + 6,ino, - FILE_END(bh->b_data,dir)->hash_chain))) + if ((retval = affs_remove_header(bh,inode)) < 0) goto rmdir_done; - - if ((retval = affs_fixup(bh,inode))) - goto rmdir_done; - - inode->i_nlink=0; - mark_inode_dirty(inode); + + inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_version = ++event; - mark_inode_dirty(dir); + retval = 0; + mark_inode_dirty(inode); + d_delete(dentry); rmdir_done: - iput(dir); - iput(inode); affs_brelse(bh); return retval; } int -affs_symlink(struct inode *dir, const char *name, int len, const char *symname) +affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct buffer_head *bh; struct inode *inode; @@ -377,20 +351,19 @@ int i, maxlen; char c, lc; - pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname); + pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name,symname); maxlen = 4 * AFFS_I2HSIZE(dir) - 1; inode = affs_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } + inode->i_op = &affs_symlink_inode_operations; inode->i_mode = S_IFLNK | 0777; inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); if (!bh) { - iput(dir); inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); @@ -427,157 +400,135 @@ mark_buffer_dirty(bh,1); affs_brelse(bh); mark_inode_dirty(inode); - bh = affs_find_entry(dir,name,len,&tmp); + bh = affs_find_entry(dir,dentry,&tmp); if (bh) { inode->i_nlink = 0; iput(inode); affs_brelse(bh); - iput(dir); return -EEXIST; } - i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK); + i = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK); if (i) { inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); affs_brelse(bh); - iput(dir); return i; } - iput(dir); - iput(inode); + dir->i_version = ++event; + d_instantiate(dentry,inode); return 0; } int -affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len) +affs_link(struct inode *oldinode, struct inode *dir, struct dentry *dentry) { struct inode *inode; struct buffer_head *bh; unsigned long i; int error; - pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name); + pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name); - bh = affs_find_entry(dir,name,len,&i); + bh = affs_find_entry(dir,dentry,&i); if (bh) { affs_brelse(bh); - iput(oldinode); - iput(dir); return -EEXIST; } - if (oldinode->u.affs_i.i_hlink) { - i = oldinode->u.affs_i.i_original; - iput(oldinode); - oldinode = iget(dir->i_sb,i); - if (!oldinode) { - affs_error(oldinode->i_sb,"link","Cannot get original from link"); - iput(dir); - return -ENOENT; - } + if (oldinode->u.affs_i.i_hlink) { /* Cannot happen */ + affs_warning(dir->i_sb,"link","Impossible link to link"); + return -EINVAL; } - inode = affs_new_inode(dir); - if (!inode) { - iput(oldinode); - iput(dir); + if (!(inode = affs_new_inode(dir))) return -ENOSPC; - } + inode->i_op = oldinode->i_op; - inode->i_mode = oldinode->i_mode; - inode->i_uid = oldinode->i_uid; - inode->i_gid = oldinode->i_gid; - inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); + inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode); inode->u.affs_i.i_original = oldinode->i_ino; inode->u.affs_i.i_hlink = 1; + inode->i_mtime = oldinode->i_mtime; if (S_ISDIR(oldinode->i_mode)) - error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR); + error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKDIR); else - error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE); - if (error) { + error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKFILE); + if (error) inode->i_nlink = 0; - mark_inode_dirty(inode); + else { + dir->i_version = ++event; + mark_inode_dirty(oldinode); + oldinode->i_count++; + d_instantiate(dentry,oldinode); } - iput(dir); + mark_inode_dirty(inode); iput(inode); - iput(oldinode); return error; } +/* This is copied from the ext2 fs. No need to reinvent the wheel. */ + static int -subdir(struct inode *new_inode, struct inode *old_inode) +subdir(struct dentry * new_dentry, struct dentry * old_dentry) { - int ino; - int result; + int result; - new_inode->i_count++; - result = 0; - for (;;) { - if (new_inode == old_inode) { - result = 1; - break; - } - if (new_inode->i_dev != old_inode->i_dev) - break; - ino = new_inode->i_ino; - if (affs_lookup(new_inode,"..",2,&new_inode)) - break; - if (new_inode->i_ino == ino) - break; - } - iput(new_inode); - return result; + result = 0; + for (;;) { + if (new_dentry != old_dentry) { + struct dentry * parent = new_dentry->d_parent; + if (parent == new_dentry) + break; + new_dentry = parent; + continue; + } + result = 1; + break; + } + return result; } -/* I'm afraid this might not be race proof. Maybe next time. */ - int -affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) +affs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { - struct inode *old_inode; - struct inode *new_inode; + struct inode *old_inode = old_dentry->d_inode; + struct inode *new_inode = new_dentry->d_inode; struct buffer_head *old_bh; struct buffer_head *new_bh; unsigned long old_ino; unsigned long new_ino; int retval; - pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name, - new_dir->i_ino,new_len,new_name); + pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p) )\n", + old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode, + new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode); - if (new_len > 30) - new_len = 30; - goto start_up; -retry: - affs_brelse(old_bh); - affs_brelse(new_bh); - iput(new_inode); - iput(old_inode); - current->counter = 0; - schedule(); -start_up: - old_inode = new_inode = NULL; - old_bh = new_bh = NULL; - retval = -ENOENT; + if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len))) + return retval; - old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino); + new_bh = NULL; + retval = -ENOENT; + old_bh = affs_find_entry(old_dir,old_dentry,&old_ino); if (!old_bh) goto end_rename; - old_inode = iget(old_dir->i_sb,old_ino); - if (!old_inode) + + new_bh = affs_find_entry(new_dir,new_dentry,&new_ino); + if (new_bh && !new_inode) { + affs_error(old_inode->i_sb,"affs_rename", + "No inode for entry found (key=%lu)\n",new_ino); goto end_rename; - new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino); - if (new_bh) { - new_inode = iget(new_dir->i_sb,new_ino); - if (!new_inode) { /* What does this mean? */ - affs_brelse(new_bh); - new_bh = NULL; - } } - if (new_inode == old_inode) { /* Won't happen */ + if (new_inode == old_inode) { + if (old_ino == new_ino) { /* Filename might have changed case */ + retval = new_dentry->d_name.len < 31 ? new_dentry->d_name.len : 30; + strncpy(DIR_END(old_bh->b_data,old_inode)->dir_name + 1, + new_dentry->d_name.name,retval); + DIR_END(old_bh->b_data,old_inode)->dir_name[0] = retval; + goto new_checksum; + } retval = 0; goto end_rename; } @@ -586,13 +537,13 @@ if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir,old_inode)) + if (subdir(new_dentry,old_dentry)) goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode))) goto end_rename; retval = -EBUSY; - if (new_inode->i_count > 1) + if (new_dentry->d_count > 1) goto end_rename; } if (S_ISDIR(old_inode->i_mode)) { @@ -600,142 +551,43 @@ if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir,old_inode)) + if (subdir(new_dentry,old_dentry)) goto end_rename; if (affs_parent_ino(old_inode) != old_dir->i_ino) goto end_rename; } - /* Unlink destination if existent */ + /* Unlink destination if it already exists */ if (new_inode) { - if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len, - AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6, - new_ino, - FILE_END(new_bh->b_data,new_dir)->hash_chain))) - goto retry; - if ((retval = affs_fixup(new_bh,new_inode))) - goto retry; - mark_buffer_dirty(new_bh,1); - new_dir->i_version = ++event; - mark_inode_dirty(new_dir); - new_inode->i_nlink = 0; + if ((retval = affs_remove_header(new_bh,new_dir)) < 0) + goto end_rename; + new_inode->i_nlink = retval; mark_inode_dirty(new_inode); + if (new_inode->i_ino == new_ino) + new_inode->i_nlink = 0; } - retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir), - AFFS_I2HSIZE(old_dir)) + 6,old_ino, - FILE_END(old_bh->b_data,old_dir)->hash_chain); - if (retval) - goto retry; - - retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len, - htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type)); + /* Remove header from its parent directory. */ + if ((retval = affs_remove_hash(old_bh,old_dir))) + goto end_rename; + /* And insert it into the new directory with the new name. */ + affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name); + if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir))) + goto end_rename; +new_checksum: + affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5); - new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime + = old_dir->i_mtime = CURRENT_TIME; new_dir->i_version = ++event; old_dir->i_version = ++event; + retval = 0; mark_inode_dirty(new_dir); mark_inode_dirty(old_dir); mark_buffer_dirty(old_bh,1); + d_move(old_dentry,new_dentry); end_rename: affs_brelse(old_bh); affs_brelse(new_bh); - iput(new_inode); - iput(old_inode); - iput(old_dir); - iput(new_dir); return retval; -} - -static int -affs_fixup(struct buffer_head *bh, struct inode *inode) -{ - s32 key, link_key; - s32 type; - struct buffer_head *nbh; - struct inode *ofinode; - - type = htonl(FILE_END(bh->b_data,inode)->secondary_type); - if (type == ST_LINKFILE || type == ST_LINKDIR) { - key = htonl(LINK_END(bh->b_data,inode)->original); - LINK_END(bh->b_data,inode)->original = 0; - if (!key) { - affs_error(inode->i_sb,"fixup","Hard link without original: ino=%lu", - inode->i_ino); - return -ENOENT; - } - if (!(ofinode = iget(inode->i_sb,key))) - return -ENOENT; - type = affs_fix_link_pred(ofinode,inode->i_ino, - FILE_END(bh->b_data,inode)->link_chain); - iput(ofinode); - return type; - } else if (type == ST_FILE || type == ST_USERDIR) { - if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) { - /* Get first link, turn it to a file */ - if (!(ofinode = iget(inode->i_sb,key))) { - affs_error(inode->i_sb,"fixup","Cannot read block %d",key); - return -ENOENT; - } - if (!ofinode->u.affs_i.i_hlink) { - affs_error(inode->i_sb,"fixup", - "First link to %lu (%d) is not a link", - inode->i_ino,key); - iput(ofinode); - return -ENOENT; - } - if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) { - affs_error(inode->i_sb,"fixup","Cannot read block %d",key); - iput(ofinode); - return -ENOENT; - } - lock_super(inode->i_sb); - memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208); - FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)-> - byte_size; - FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)-> - extension; - FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)-> - secondary_type; - FILE_END(nbh->b_data,inode)->original = 0; - - ofinode->u.affs_i.i_original = 0; - ofinode->u.affs_i.i_hlink = 0; - ofinode->i_size = inode->i_size; - ofinode->i_uid = inode->i_uid; - ofinode->i_gid = inode->i_gid; - mark_inode_dirty(ofinode); - link_key = ofinode->i_ino; - - /* Let all remaining links point to the new file */ - while (1) { - affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5); - mark_buffer_dirty(nbh,1); - key = htonl(FILE_END(nbh->b_data,inode)->link_chain); - affs_brelse(nbh); - iput(ofinode); - if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) - break; - if ((ofinode = iget(inode->i_sb,key))) { - if (!ofinode->u.affs_i.i_hlink) - affs_error(inode->i_sb,"fixup", - "Inode %d in link chain is not a link", - key); - ofinode->u.affs_i.i_original = link_key; - mark_inode_dirty(ofinode); - FILE_END(nbh->b_data,inode)->original = htonl(link_key); - } else - affs_error(inode->i_sb,"fixup","Cannot read block %d",key); - } - /* Turn old inode to a link */ - inode->u.affs_i.i_hlink = 1; - unlock_super(inode->i_sb); - } - return 0; - } else if (type == ST_SOFTLINK) { - return 0; - } else { - affs_error(inode->i_sb,"fixup","Bad secondary type (%d)",type); - return -EBADF; - } } diff -u --recursive --new-file v2.1.70/linux/fs/affs/super.c linux/fs/affs/super.c --- v2.1.70/linux/fs/affs/super.c Wed Dec 31 16:00:00 1969 +++ linux/fs/affs/super.c Tue Dec 2 22:25:07 1997 @@ -0,0 +1,691 @@ +/* + * linux/fs/affs/inode.c + * + * (c) 1996 Hans-Joachim Widmaier - Rewritten + * + * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + */ + +#define DEBUG 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int *blk_size[]; +extern struct timezone sys_tz; + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +static int affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); +static int affs_remount (struct super_block *sb, int *flags, char *data); + +static void +affs_put_super(struct super_block *sb) +{ + int i; + + pr_debug("affs_put_super()\n"); + + lock_super(sb); + for (i = 0; i < sb->u.affs_sb.s_bm_count; i++) + affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh); + if (!(sb->s_flags & MS_RDONLY)) { + ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = be32_to_cpu(1); + secs_to_datestamp(CURRENT_TIME, + &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); + affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); + mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + } + + if (sb->u.affs_sb.s_prefix) + kfree(sb->u.affs_sb.s_prefix); + kfree(sb->u.affs_sb.s_bitmap); + affs_brelse(sb->u.affs_sb.s_root_bh); + + /* I'm not happy with this. It would be better to save the previous + * value of this devices blksize_size[][] in the super block and + * restore it here, but with the affs superblock being quite large + * already ... + */ + set_blocksize(sb->s_dev,BLOCK_SIZE); + + sb->s_dev = 0; + unlock_super(sb); + MOD_DEC_USE_COUNT; + return; +} + +static void +affs_write_super(struct super_block *sb) +{ + int i, clean = 2; + + if (!(sb->s_flags & MS_RDONLY)) { + lock_super(sb); + for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) { + if (sb->u.affs_sb.s_bitmap[i].bm_bh) { + if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) { + clean = 0; + break; + } + } + } + unlock_super(sb); + ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = be32_to_cpu(clean); + secs_to_datestamp(CURRENT_TIME, + &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); + affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); + mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + sb->s_dirt = !clean; /* redo until bitmap synced */ + } else + sb->s_dirt = 0; + + pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean); +} + +static struct super_operations affs_sops = { + affs_read_inode, + affs_write_inode, + affs_put_inode, + affs_delete_inode, + affs_notify_change, + affs_put_super, + affs_write_super, + affs_statfs, + affs_remount +}; + +static int +parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root, + int *blocksize, char **prefix, char *volume, unsigned long *mount_opts) +{ + char *this_char, *value; + int f; + + /* Fill in defaults */ + + *uid = current->uid; + *gid = current->gid; + *reserved = 2; + *root = -1; + *blocksize = -1; + volume[0] = ':'; + volume[1] = 0; + *mount_opts = 0; + if (!options) + return 1; + for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { + f = 0; + if ((value = strchr(this_char,'=')) != NULL) + *value++ = 0; + if (!strcmp(this_char,"protect")) { + if (value) { + printk("AFFS: Option protect does not take an argument\n"); + return 0; + } + *mount_opts |= SF_IMMUTABLE; + } else if (!strcmp(this_char,"verbose")) { + if (value) { + printk("AFFS: Option verbose does not take an argument\n"); + return 0; + } + *mount_opts |= SF_VERBOSE; + } else if ((f = !strcmp(this_char,"setuid")) || !strcmp(this_char,"setgid")) { + if (value) { + if (!*value) { + printk("AFFS: Argument for set[ug]id option missing\n"); + return 0; + } else { + (f ? *uid : *gid) = simple_strtoul(value,&value,0); + if (*value) { + printk("AFFS: Bad set[ug]id argument\n"); + return 0; + } + *mount_opts |= f ? SF_SETUID : SF_SETGID; + } + } + } else if (!strcmp(this_char,"prefix")) { + if (!value || !*value) { + printk("AFFS: The prefix option requires an argument\n"); + return 0; + } + if (*prefix) /* Free any previous prefix */ + kfree(*prefix); + *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL); + if (!*prefix) + return 0; + strcpy(*prefix,value); + *mount_opts |= SF_PREFIX; + } else if (!strcmp(this_char,"volume")) { + if (!value || !*value) { + printk("AFFS: The volume option requires an argument\n"); + return 0; + } + if (strlen(value) > 30) + value[30] = 0; + strncpy(volume,value,30); + } else if (!strcmp(this_char,"mode")) { + if (!value || !*value) { + printk("AFFS: The mode option requires an argument\n"); + return 0; + } + *mode = simple_strtoul(value,&value,8) & 0777; + if (*value) + return 0; + *mount_opts |= SF_SETMODE; + } else if (!strcmp(this_char,"reserved")) { + if (!value || !*value) { + printk("AFFS: The reserved option requires an argument\n"); + return 0; + } + *reserved = simple_strtoul(value,&value,0); + if (*value) + return 0; + } else if (!strcmp(this_char,"root")) { + if (!value || !*value) { + printk("AFFS: The root option requires an argument\n"); + return 0; + } + *root = simple_strtoul(value,&value,0); + if (*value) + return 0; + } else if (!strcmp(this_char,"bs")) { + if (!value || !*value) { + printk("AFFS: The bs option requires an argument\n"); + return 0; + } + *blocksize = simple_strtoul(value,&value,0); + if (*value) + return 0; + if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048 + && *blocksize != 4096) { + printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n"); + return 0; + } + } else if (!strcmp (this_char, "grpquota") + || !strcmp (this_char, "noquota") + || !strcmp (this_char, "quota") + || !strcmp (this_char, "usrquota")) + /* Silently ignore the quota options */ + ; + else { + printk("AFFS: Unrecognized mount option %s\n", this_char); + return 0; + } + } + return 1; +} + +/* This function definitely needs to be split up. Some fine day I'll + * hopefully have the guts to do so. Until then: sorry for the mess. + */ + +static struct super_block * +affs_read_super(struct super_block *s,void *data, int silent) +{ + struct buffer_head *bh = NULL; + struct buffer_head *bb; + struct inode *root_inode; + kdev_t dev = s->s_dev; + s32 root_block; + int size; + u32 chksum; + u32 *bm; + s32 ptype, stype; + int mapidx; + int num_bm; + int i, j; + s32 key; + int blocksize; + uid_t uid; + gid_t gid; + int reserved; + int az_no; + int bmalt = 0; + unsigned long mount_flags; + unsigned long offset; + + pr_debug("affs_read_super(%s)\n",data ? (const char *)data : "no options"); + + MOD_INC_USE_COUNT; + + s->u.affs_sb.s_prefix = NULL; + if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, + &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) { + s->s_dev = 0; + printk(KERN_ERR "AFFS: Error parsing options\n"); + MOD_DEC_USE_COUNT; + return NULL; + } + lock_super(s); + + /* Get the size of the device in 512-byte blocks. + * If we later see that the partition uses bigger + * blocks, we will have to change it. + */ + + size = blksize_size[MAJOR(dev)][MINOR(dev)]; + size = (size ? size : BLOCK_SIZE) / 512 * blk_size[MAJOR(dev)][MINOR(dev)]; + + s->u.affs_sb.s_bitmap = NULL; + s->u.affs_sb.s_root_bh = NULL; + s->u.affs_sb.s_flags = mount_flags; + s->u.affs_sb.s_mode = i; + s->u.affs_sb.s_uid = uid; + s->u.affs_sb.s_gid = gid; + + if (size == 0) { + s->s_dev = 0; + unlock_super(s); + printk(KERN_ERR "AFFS: Could not determine device size\n"); + goto out; + } + s->u.affs_sb.s_partition_size = size; + s->u.affs_sb.s_reserved = reserved; + + /* Try to find root block. Its location depends on the block size. */ + + s->u.affs_sb.s_hashsize = 0; + if (blocksize > 0) { + i = blocksize; + j = blocksize; + } else { + i = 512; + j = 4096; + } + for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) { + if (root_block < 0) + s->u.affs_sb.s_root_block = (reserved + size - 1) / 2; + else + s->u.affs_sb.s_root_block = root_block; + set_blocksize(dev,blocksize); + + /* The root block location that was calculated above is not + * correct if the partition size is an odd number of 512- + * byte blocks, which will be rounded down to a number of + * 1024-byte blocks, and if there were an even number of + * reserved blocks. Ideally, all partition checkers should + * report the real number of blocks of the real blocksize, + * but since this just cannot be done, we have to try to + * find the root block anyways. In the above case, it is one + * block behind the calculated one. So we check this one, too. + */ + for (num_bm = 0; num_bm < 2; num_bm++) { + pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, " + "size=%d blocks, %d reserved\n",kdevname(dev),blocksize, + s->u.affs_sb.s_root_block + num_bm,size,reserved); + bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize); + if (!bh) { + printk(KERN_ERR "AFFS: Cannot read root block\n"); + goto out; + } + if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) && + ptype == T_SHORT && stype == ST_ROOT) { + s->s_blocksize = blocksize; + s->u.affs_sb.s_hashsize = blocksize / 4 - 56; + s->u.affs_sb.s_root_block += num_bm; + key = 1; + break; + } + } + if (key) + break; + affs_brelse(bh); + bh = NULL; + } + if (!key) { + affs_brelse(bh); + if (!silent) + printk(KERN_ERR "AFFS: Cannot find a valid root block on device %s\n", + kdevname(dev)); + goto out; + } + root_block = s->u.affs_sb.s_root_block; + + s->u.affs_sb.s_partition_size = size; + s->s_blocksize_bits = blocksize == 512 ? 9 : + blocksize == 1024 ? 10 : + blocksize == 2048 ? 11 : 12; + + /* Find out which kind of FS we have */ + bb = affs_bread(dev,0,s->s_blocksize); + if (bb) { + chksum = be32_to_cpu(*(u32 *)bb->b_data); + + /* Dircache filesystems are compatible with non-dircache ones + * when reading. As long as they aren't supported, writing is + * not recommended. + */ + if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS + || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) { + printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n", + kdevname(dev)); + s->s_flags |= MS_RDONLY; + s->u.affs_sb.s_flags |= SF_READONLY; + } + switch (chksum) { + case MUFS_FS: + case MUFS_INTLFFS: + s->u.affs_sb.s_flags |= SF_MUFS; + /* fall thru */ + case FS_INTLFFS: + s->u.affs_sb.s_flags |= SF_INTL; + break; + case MUFS_DCFFS: + case MUFS_FFS: + s->u.affs_sb.s_flags |= SF_MUFS; + break; + case FS_DCFFS: + case FS_FFS: + break; + case MUFS_OFS: + s->u.affs_sb.s_flags |= SF_MUFS; + /* fall thru */ + case FS_OFS: + s->u.affs_sb.s_flags |= SF_OFS; + break; + case MUFS_DCOFS: + case MUFS_INTLOFS: + s->u.affs_sb.s_flags |= SF_MUFS; + case FS_DCOFS: + case FS_INTLOFS: + s->u.affs_sb.s_flags |= SF_INTL | SF_OFS; + break; + default: + printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", + kdevname(dev),chksum); + affs_brelse(bb); + goto out; + } + affs_brelse(bb); + } else { + printk(KERN_ERR "AFFS: Cannot read boot block\n"); + goto out; + } + if (mount_flags & SF_VERBOSE) { + chksum = cpu_to_be32(chksum); + printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n", + GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0], + &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1], + (char *)&chksum,((char *)&chksum)[3] + '0',blocksize); + } + + s->s_magic = AFFS_SUPER_MAGIC; + s->s_flags |= MS_NODEV | MS_NOSUID; + + /* Keep super block in cache */ + if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) { + printk(KERN_ERR "AFFS: Cannot read root block\n"); + goto out; + } + + /* Allocate space for bitmaps, zones and others */ + + size = s->u.affs_sb.s_partition_size - reserved; + num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32); + az_no = (size + AFFS_ZONE_SIZE - 1) / (AFFS_ZONE_SIZE - 32); + ptype = num_bm * sizeof(struct affs_bm_info) + + az_no * sizeof(struct affs_alloc_zone) + + MAX_ZONES * sizeof(struct affs_zone); + pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype); + if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) { + printk(KERN_ERR "AFFS: Not enough memory\n"); + goto out; + } + memset(s->u.affs_sb.s_bitmap,0,ptype); + + s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm]; + s->u.affs_sb.s_alloc = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES]; + s->u.affs_sb.s_num_az = az_no; + + mapidx = 0; + + if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) { + if (!(s->s_flags & MS_RDONLY)) { + printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n", + kdevname(dev)); + s->s_flags |= MS_RDONLY; + } + affs_brelse(bh); + bh = NULL; + goto nobitmap; + } + + /* The following section is ugly, I know. Especially because of the + * reuse of some variables that are not named properly. + */ + + key = root_block; + ptype = s->s_blocksize / 4 - 49; + stype = ptype + 25; + offset = s->u.affs_sb.s_reserved; + az_no = 0; + while (bh) { + bm = (u32 *)bh->b_data; + for (i = ptype; i < stype && bm[i]; i++, mapidx++) { + if (mapidx >= num_bm) { + printk(KERN_ERR "AFFS: Extraneous bitmap pointer - " + "mounting %s read only.\n",kdevname(dev)); + s->s_flags |= MS_RDONLY; + s->u.affs_sb.s_flags |= SF_READONLY; + continue; + } + bb = affs_bread(s->s_dev,be32_to_cpu(bm[i]),s->s_blocksize); + if (bb) { + if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) && + !(s->s_flags & MS_RDONLY)) { + printk(KERN_WARNING "AFFS: Bitmap (%d,key=%lu) invalid - " + "mounting %s read only.\n",mapidx,be32_to_cpu(bm[i]), + kdevname(dev)); + s->s_flags |= MS_RDONLY; + s->u.affs_sb.s_flags |= SF_READONLY; + } + /* Mark unused bits in the last word as allocated */ + if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */ + ptype = size / 32 + 1; /* word number */ + key = size & 0x1F; /* used bits */ + if (key && !(s->s_flags & MS_RDONLY)) { + chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key)); + ((u32 *)bb->b_data)[ptype] &= chksum; + affs_fix_checksum(s->s_blocksize,bb->b_data,0); + mark_buffer_dirty(bb,1); + bmalt = 1; + } + ptype = (size + 31) & ~0x1F; + size = 0; + s->u.affs_sb.s_flags |= SF_BM_VALID; + } else { + ptype = s->s_blocksize * 8 - 32; + size -= ptype; + } + s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset; + s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL; + s->u.affs_sb.s_bitmap[mapidx].bm_key = be32_to_cpu(bm[i]); + s->u.affs_sb.s_bitmap[mapidx].bm_count = 0; + offset += ptype; + + for (j = 0; ptype > 0; j++, az_no++, ptype -= key) { + key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */ + s->u.affs_sb.s_alloc[az_no].az_size = key / 32; + s->u.affs_sb.s_alloc[az_no].az_free = + affs_count_free_bits(key / 8,bb->b_data + + j * (AFFS_ZONE_SIZE / 8) + 4); + } + affs_brelse(bb); + } else { + printk(KERN_ERR "AFFS: Cannot read bitmap\n"); + goto out; + } + } + key = be32_to_cpu(bm[stype]); /* Next block of bitmap pointers */ + ptype = 0; + stype = s->s_blocksize / 4 - 1; + affs_brelse(bh); + if (key) { + if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) { + printk(KERN_ERR "AFFS: Cannot read bitmap extension\n"); + goto out; + } + } else + bh = NULL; + } + if (mapidx < num_bm) { + printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm); + goto out; + } +nobitmap: + s->u.affs_sb.s_bm_count = num_bm; + + /* set up enough so that it can read an inode */ + + s->s_dev = dev; + s->s_op = &affs_sops; + s->s_dirt = 1; + root_inode = iget(s,root_block); + s->s_root = d_alloc_root(root_inode,NULL); + unlock_super(s); + + if (!(s->s_root)) { + s->s_dev = 0; + affs_brelse(s->u.affs_sb.s_root_bh); + printk(KERN_ERR "AFFS: get root inode failed\n"); + MOD_DEC_USE_COUNT; + return NULL; + } + + /* Record date of last change if the bitmap was truncated and + * create data zones if the volume is writable. + */ + + if (!(s->s_flags & MS_RDONLY)) { + if (bmalt) { + secs_to_datestamp(CURRENT_TIME,&ROOT_END( + s->u.affs_sb.s_root_bh->b_data,root_inode)->disk_altered); + affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5); + mark_buffer_dirty(s->u.affs_sb.s_root_bh,1); + } + affs_make_zones(s); + } + + pr_debug("AFFS: s_flags=%lX\n",s->s_flags); + return s; + + out: /* Kick out for various error conditions */ + affs_brelse (bh); + affs_brelse(s->u.affs_sb.s_root_bh); + if (s->u.affs_sb.s_bitmap) + kfree(s->u.affs_sb.s_bitmap); + set_blocksize(dev,BLOCK_SIZE); + s->s_dev = 0; + unlock_super(s); + MOD_DEC_USE_COUNT; + return NULL; +} + +static int +affs_remount(struct super_block *sb, int *flags, char *data) +{ + int blocksize; + uid_t uid; + gid_t gid; + int mode; + int reserved; + int root_block; + unsigned long mount_flags; + unsigned long read_only = sb->u.affs_sb.s_flags & SF_READONLY; + + pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data); + + if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block, + &blocksize,&sb->u.affs_sb.s_prefix,sb->u.affs_sb.s_volume,&mount_flags)) + return -EINVAL; + sb->u.affs_sb.s_flags = mount_flags | read_only; + sb->u.affs_sb.s_mode = mode; + sb->u.affs_sb.s_uid = uid; + sb->u.affs_sb.s_gid = gid; + + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + if (*flags & MS_RDONLY) { + sb->s_dirt = 1; + while (sb->s_dirt) + affs_write_super(sb); + sb->s_flags |= MS_RDONLY; + } else if (!(sb->u.affs_sb.s_flags & SF_READONLY)) { + sb->s_flags &= ~MS_RDONLY; + affs_make_zones(sb); + } else { + affs_warning(sb,"remount","Cannot remount fs read/write because of errors"); + return -EINVAL; + } + return 0; +} + +static int +affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +{ + int free; + struct statfs tmp; + + pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size, + sb->u.affs_sb.s_reserved); + + free = affs_count_free_blocks(sb); + tmp.f_type = AFFS_SUPER_MAGIC; + tmp.f_bsize = sb->s_blocksize; + tmp.f_blocks = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved; + tmp.f_bfree = free; + tmp.f_bavail = free; + tmp.f_files = 0; + tmp.f_ffree = 0; + return copy_to_user(buf,&tmp,bufsiz) ? -EFAULT : 0; +} + +static struct file_system_type affs_fs_type = { + "affs", + FS_REQUIRES_DEV, + affs_read_super, + NULL +}; + +__initfunc(int init_affs_fs(void)) +{ + return register_filesystem(&affs_fs_type); +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +int +init_module(void) +{ + return register_filesystem(&affs_fs_type); +} + +void +cleanup_module(void) +{ + unregister_filesystem(&affs_fs_type); +} + +#endif diff -u --recursive --new-file v2.1.70/linux/fs/affs/symlink.c linux/fs/affs/symlink.c --- v2.1.70/linux/fs/affs/symlink.c Mon Jun 16 16:35:56 1997 +++ linux/fs/affs/symlink.c Tue Dec 2 22:25:07 1997 @@ -19,7 +19,8 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) -static int affs_readlink(struct inode *, char *, int); +static int affs_readlink(struct inode *, char *, int); +static struct dentry *affs_follow_link(struct inode *inode, struct dentry *base); struct inode_operations affs_symlink_inode_operations = { NULL, /* no file-operations */ @@ -33,9 +34,13 @@ NULL, /* mknod */ NULL, /* rename */ affs_readlink, /* readlink */ + affs_follow_link, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL /* smap */ }; static int @@ -46,21 +51,24 @@ int i, j; char c; char lc; + char *pf; pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen); bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); - i = 0; - j = 0; if (!bh) { - affs_error(inode->i_sb,"readlink","Cannot read block %lu\n",inode->i_ino); - goto symlink_end; + affs_warning(inode->i_sb,"follow_link","Unable to read i-node block %lu\n", + inode->i_ino); + return -EIO; } lf = (struct slink_front *)bh->b_data; lc = 0; + i = 0; + j = 0; + pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/"; if (strchr(lf->symname,':')) { /* Handle assign or volume name */ - while (i < buflen && (c = inode->i_sb->u.affs_sb.s_prefix[i])) { + while (i < buflen && (c = pf[i])) { put_user(c,buffer++); i++; } @@ -84,8 +92,64 @@ lc = c; i++, j++; } -symlink_end: - iput(inode); affs_brelse(bh); return i; } + +static struct dentry * +affs_follow_link(struct inode *inode, struct dentry *base) +{ + struct buffer_head *bh; + struct slink_front *lf; + char *buffer; + int i, j; + char c; + char lc; + char *pf; + + pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino); + + if (!(buffer = kmalloc(1024,GFP_KERNEL))) { + dput(base); + return ERR_PTR(-ENOSPC); + } + bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); + if (!bh) { + affs_warning(inode->i_sb,"follow_link","Unable to read i-node block %lu\n", + inode->i_ino); + kfree(buffer); + dput(base); + return ERR_PTR(-EIO); + } + i = 0; + j = 0; + lf = (struct slink_front *)bh->b_data; + lc = 0; + pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/"; + + if (strchr(lf->symname,':')) { /* Handle assign or volume name */ + while (i < 1023 && (c = pf[i])) + buffer[i++] = c; + while (i < 1023 && lf->symname[j] != ':') + buffer[i++] = lf->symname[j++]; + if (i < 1023) + buffer[i++] = '/'; + j++; + lc = '/'; + } + while (i < 1023 && (c = lf->symname[j])) { + if (c == '/' && lc == '/' && i < 1020) { /* parent dir */ + buffer[i++] = '.'; + buffer[i++] = '.'; + } + buffer[i++] = c; + lc = c; + j++; + } + buffer[i] = '\0'; + affs_brelse(bh); + base = lookup_dentry(buffer,base,1); + kfree(buffer); + return base; +} + diff -u --recursive --new-file v2.1.70/linux/fs/coda/sysctl.c linux/fs/coda/sysctl.c --- v2.1.70/linux/fs/coda/sysctl.c Tue Dec 2 16:45:20 1997 +++ linux/fs/coda/sysctl.c Wed Dec 3 17:15:04 1997 @@ -1,5 +1,4 @@ /* sysctl entries for Coda! */ -#include #include #include #include diff -u --recursive --new-file v2.1.70/linux/fs/fat/file.c linux/fs/fat/file.c --- v2.1.70/linux/fs/fat/file.c Sat Oct 25 02:44:17 1997 +++ linux/fs/fat/file.c Wed Dec 3 04:24:29 1997 @@ -155,7 +155,7 @@ /* Read a file into user space */ -ssize_t fat_file_read( +static ssize_t fat_file_read_text( struct file *filp, char *buf, size_t count, @@ -270,6 +270,17 @@ return buf-start; } +ssize_t fat_file_read( + struct file *filp, + char *buf, + size_t count, + loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + if (!MSDOS_I(inode)->i_binary) + return fat_file_read_text(filp, buf, count, ppos); + return generic_file_read(filp, buf, count, ppos); +} /* Write to a file either from user space */ diff -u --recursive --new-file v2.1.70/linux/fs/isofs/namei.c linux/fs/isofs/namei.c --- v2.1.70/linux/fs/isofs/namei.c Sat Oct 25 02:44:17 1997 +++ linux/fs/isofs/namei.c Wed Dec 3 04:24:29 1997 @@ -66,7 +66,7 @@ unsigned char bufbits = ISOFS_BUFFER_BITS(dir); unsigned int block, i, f_pos, offset, inode_number = 0; /* shut gcc up */ - struct buffer_head * bh; + struct buffer_head * bh , * retval = NULL; unsigned int old_offset; int dlen, match; char * dpnt; @@ -86,7 +86,7 @@ block = isofs_bmap(dir,f_pos >> bufbits); if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL; - + while (f_pos < dir->i_size) { /* if de is in kmalloc'd memory, do not point to the @@ -118,13 +118,14 @@ + ISOFS_BLOCK_SIZE); } brelse(bh); + bh = NULL; if (f_pos >= dir->i_size) - return 0; + break; block = isofs_bmap(dir,f_pos>>bufbits); if (!block || !(bh = bread(dir->i_dev,block,bufsize))) - return NULL; + break; continue; /* Will kick out if past end of directory */ } @@ -145,7 +146,7 @@ block = isofs_bmap(dir,f_pos>>bufbits); if (!block || !(bh_next = bread(dir->i_dev,block,bufsize))) - return NULL; + break; de = (struct iso_directory_record *) kmalloc(offset - old_offset, GFP_KERNEL); @@ -162,14 +163,14 @@ if (dir->i_sb->u.isofs_sb.s_rock || dir->i_sb->u.isofs_sb.s_joliet_level) { - page = (unsigned char *) - __get_free_page(GFP_KERNEL); - if (!page) return NULL; + if (! page) { + page = (unsigned char *) + __get_free_page(GFP_KERNEL); + if (!page) break; + } } if (dir->i_sb->u.isofs_sb.s_rock && ((i = get_rock_ridge_filename(de, page, dir)))) { - if (i == -1) - goto out;/* Relocated deep directory */ dlen = i; dpnt = page; #ifdef CONFIG_JOLIET @@ -203,8 +204,6 @@ { match = isofs_match(namelen,name,dpnt,dlen); } - - if (page) free_page((unsigned long) page); if (match) { if(inode_number == -1) { /* Should only happen for the '..' entry */ @@ -213,16 +212,16 @@ find_rock_ridge_relocation(de,dir)); } *ino = inode_number; - if(de_not_in_buf) - kfree(de); - return bh; + retval = bh; + bh = NULL; + break; } } - out: - brelse(bh); + if (page) free_page((unsigned long) page); + if (bh) brelse(bh); if(de_not_in_buf) kfree(de); - return NULL; + return retval; } int isofs_lookup(struct inode * dir, struct dentry * dentry) diff -u --recursive --new-file v2.1.70/linux/fs/locks.c linux/fs/locks.c --- v2.1.70/linux/fs/locks.c Sat Oct 25 02:44:17 1997 +++ linux/fs/locks.c Tue Dec 2 22:20:18 1997 @@ -402,11 +402,11 @@ switch (flock.l_type) { case F_RDLCK: - if (!(filp->f_mode & 1)) + if (!(filp->f_mode & FMODE_READ)) return (-EBADF); break; case F_WRLCK: - if (!(filp->f_mode & 2)) + if (!(filp->f_mode & FMODE_WRITE)) return (-EBADF); break; case F_UNLCK: diff -u --recursive --new-file v2.1.70/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.1.70/linux/fs/nfs/dir.c Sat Nov 29 11:25:12 1997 +++ linux/fs/nfs/dir.c Thu Dec 4 09:49:48 1997 @@ -1144,7 +1144,7 @@ */ if (!list_empty(&new_dentry->d_hash)) { d_drop(new_dentry); - rehash = 1; + rehash = update; } error = nfs_proc_rename(NFS_SERVER(old_dir), NFS_FH(old_dir), old_dentry->d_name.name, diff -u --recursive --new-file v2.1.70/linux/fs/nfs/file.c linux/fs/nfs/file.c --- v2.1.70/linux/fs/nfs/file.c Sat Nov 1 11:04:27 1997 +++ linux/fs/nfs/file.c Wed Dec 3 17:18:42 1997 @@ -113,7 +113,8 @@ ssize_t result; dfprintk(VFS, "nfs: read(%x/%ld, %lu@%lu)\n", - inode->i_dev, inode->i_ino, count, + inode->i_dev, inode->i_ino, + (unsigned long) count, (unsigned long) *ppos); result = nfs_revalidate_inode(NFS_SERVER(inode), inode); @@ -167,7 +168,7 @@ dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n", inode->i_dev, inode->i_ino, inode->i_count, - count, (unsigned long) *ppos); + (unsigned long) count, (unsigned long) *ppos); if (!inode) { printk("nfs_file_write: inode = NULL\n"); diff -u --recursive --new-file v2.1.70/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.1.70/linux/fs/nfsd/nfssvc.c Mon Dec 1 12:04:14 1997 +++ linux/fs/nfsd/nfssvc.c Wed Dec 3 15:28:25 1997 @@ -165,7 +165,7 @@ for (signo = 1; signo <= _NSIG; signo++) if (sigismember(¤t->signal, signo) && - !sigismember(¤t->signal, signo)) + !sigismember(¤t->blocked, signo)) break; printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo); } diff -u --recursive --new-file v2.1.70/linux/fs/proc/proc_tty.c linux/fs/proc/proc_tty.c --- v2.1.70/linux/fs/proc/proc_tty.c Thu Mar 27 14:40:06 1997 +++ linux/fs/proc/proc_tty.c Wed Dec 3 15:21:57 1997 @@ -49,8 +49,10 @@ case TTY_DRIVER_TYPE_SYSTEM: if (p->subtype == SYSTEM_TYPE_TTY) type = "system:/dev/tty"; - else if (p->subtype == SYSTEM_TYPE_CONSOLE) + else if (p->subtype == SYSTEM_TYPE_SYSCONS) type = "system:console"; + else if (p->subtype == SYSTEM_TYPE_CONSOLE) + type = "system:vtmaster"; else type = "system"; break; diff -u --recursive --new-file v2.1.70/linux/fs/ufs/Makefile linux/fs/ufs/Makefile --- v2.1.70/linux/fs/ufs/Makefile Mon Apr 22 00:59:39 1996 +++ linux/fs/ufs/Makefile Wed Dec 3 06:18:33 1997 @@ -9,7 +9,7 @@ O_TARGET := ufs.o O_OBJS := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \ - ufs_super.o ufs_symlink.o + ufs_super.o ufs_symlink.o ufs_swab.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.70/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c --- v2.1.70/linux/fs/ufs/ufs_dir.c Thu Sep 11 09:02:24 1997 +++ linux/fs/ufs/ufs_dir.c Wed Dec 3 06:18:33 1997 @@ -6,12 +6,13 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_dir.c,v 1.10 1997/06/05 01:29:06 davem Exp $ + * swab support by Francois-Rene Rideau 19970406 * */ #include -#include + +#include "ufs_swab.h" /* * This is blatantly stolen from ext2fs @@ -26,12 +27,18 @@ struct buffer_head * bh; struct ufs_direct * de; struct super_block * sb; + int de_reclen; + __u32 s_flags, bytesex; + /* Isn't that already done but the upper layer??? */ if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; + sb = inode->i_sb; + s_flags = sb->u.ufs_sb.s_flags; + bytesex = s_flags & UFS_BYTESEX; - if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + if (s_flags & UFS_DEBUG) { printk("ufs_readdir: ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos); ufs_print_inode(inode); @@ -48,7 +55,8 @@ bh = bread (sb->s_dev, blk, sb->s_blocksize); if (!bh) { /* XXX - error - skip to the next block */ - printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n", + printk("ufs_readdir: " + "dir inode %lu has a hole at offset %lu\n", inode->i_ino, (unsigned long int)filp->f_pos); filp->f_pos += sb->s_blocksize - offset; continue; @@ -61,7 +69,7 @@ * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ufs_direct *) + de = (struct ufs_direct *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this @@ -69,28 +77,30 @@ * least that it is non-zero. A * failure will be detected in the * dirent test below. */ - if (ufs_swab16(de->d_reclen) < 1) + de_reclen = SWAB16(de->d_reclen); + if (de_reclen < 1) break; - i += ufs_swab16(de->d_reclen); + i += de_reclen; } offset = i; filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset; filp->f_version = inode->i_version; } - - while (!error && filp->f_pos < inode->i_size + + while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ufs_direct *) (bh->b_data + offset); /* XXX - put in a real ufs_check_dir_entry() */ - if ((ufs_swab16(de->d_reclen) == 0) - || (ufs_swab16(de->d_namlen) == 0)) { + if ((de->d_reclen == 0) || (de->d_namlen == 0)) { + /* SWAB16() was unneeded -- compare to 0 */ filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse(bh); return stored; } #if 0 if (!ext2_check_dir_entry ("ext2_readdir", inode, de, + /* XXX - beware about de having to be swabped somehow */ bh, offset)) { /* On error, skip the f_pos to the next block. */ @@ -100,8 +110,9 @@ return stored; } #endif /* XXX */ - offset += ufs_swab16(de->d_reclen); - if (ufs_swab32(de->d_ino)) { + offset += SWAB16(de->d_reclen); + if (de->d_ino) { + /* SWAB16() was unneeded -- compare to 0 */ /* We might block in the next section * if the data destination is * currently swapped out. So, use a @@ -110,18 +121,18 @@ * during the copy operation. */ unsigned long version = inode->i_version; - if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + if (s_flags & UFS_DEBUG) { printk("ufs_readdir: filldir(%s,%u)\n", - de->d_name, ufs_swab32(de->d_ino)); + de->d_name, SWAB32(de->d_ino)); } - error = filldir(dirent, de->d_name, ufs_swab16(de->d_namlen), filp->f_pos, ufs_swab32(de->d_ino)); + error = filldir(dirent, de->d_name, SWAB16(de->d_namlen), filp->f_pos, SWAB32(de->d_ino)); if (error) break; if (version != inode->i_version) goto revalidate; stored ++; } - filp->f_pos += ufs_swab16(de->d_reclen); + filp->f_pos += SWAB16(de->d_reclen); } offset = 0; brelse (bh); @@ -140,7 +151,7 @@ NULL, /* read */ NULL, /* write */ ufs_readdir, /* readdir */ - NULL, /* poll */ + NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ diff -u --recursive --new-file v2.1.70/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c --- v2.1.70/linux/fs/ufs/ufs_file.c Thu Jul 17 10:06:08 1997 +++ linux/fs/ufs/ufs_file.c Wed Dec 3 06:18:33 1997 @@ -18,7 +18,7 @@ generic_file_read, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* poll */ + NULL, /* select */ NULL, /* ioctl */ generic_file_mmap, /* mmap */ NULL, /* open */ diff -u --recursive --new-file v2.1.70/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c --- v2.1.70/linux/fs/ufs/ufs_inode.c Thu Jul 17 10:06:08 1997 +++ linux/fs/ufs/ufs_inode.c Wed Dec 3 06:18:33 1997 @@ -6,7 +6,8 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_inode.c,v 1.9 1997/07/17 02:24:14 davem Exp $ + * Clean swab support on 19970406 + * by Francois-Rene Rideau * */ @@ -14,6 +15,8 @@ #include #include +#include "ufs_swab.h" + void ufs_print_inode(struct inode * inode) { printk("ino %lu mode 0%6.6o lk %d uid %d gid %d" @@ -41,14 +44,14 @@ { struct buffer_head *bh; int tmp; - + __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; /* XXX Split in fsize big blocks (Can't bread 8Kb). */ tmp = nr >> (inode->i_sb->u.ufs_sb.s_fshift - 2); bh = bread (inode->i_dev, block + tmp, inode->i_sb->u.ufs_sb.s_fsize); if (!bh) return 0; nr &= ~(inode->i_sb->u.ufs_sb.s_fmask) >> 2; - tmp = ufs_swab32(((__u32 *)bh->b_data)[nr]); + tmp = SWAB32(((__u32 *)bh->b_data)[nr]); brelse (bh); return tmp; } @@ -113,6 +116,7 @@ struct super_block * sb; struct ufs_inode * ufsip; struct buffer_head * bh; + __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; sb = inode->i_sb; @@ -144,8 +148,8 @@ /* * Copy data to the in-core inode. */ - inode->i_mode = ufs_swab16(ufsip->ui_mode); - inode->i_nlink = ufs_swab16(ufsip->ui_nlink); + inode->i_mode = SWAB16(ufsip->ui_mode); + inode->i_nlink = SWAB16(ufsip->ui_nlink); if (inode->i_nlink == 0) { /* XXX */ printk("ufs_read_inode: zero nlink ino %lu dev %u/%u\n", @@ -158,7 +162,7 @@ MAJOR(inode->i_dev), MINOR(inode->i_dev)); } /* XXX - debugging */ - if (ufs_swab32(ufsip->ui_gen) == 0) { + if (SWAB32(ufsip->ui_gen) == 0) { printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n", inode->i_ino, ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + @@ -172,33 +176,33 @@ * random users can't get at these files, since they get dynamically * "chown()ed" to root. */ - if (ufs_swab16(ufsip->ui_suid) == UFS_USEEFT) { + if (SWAB16(ufsip->ui_suid) == UFS_USEEFT) { /* EFT */ inode->i_uid = 0; printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n", - ufs_swab32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), + SWAB32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), inode->i_uid); } else { - inode->i_uid = ufs_swab16(ufsip->ui_suid); + inode->i_uid = SWAB16(ufsip->ui_suid); } - if (ufs_swab16(ufsip->ui_sgid) == UFS_USEEFT) { + if (SWAB16(ufsip->ui_sgid) == UFS_USEEFT) { /* EFT */ inode->i_gid = 0; printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n", - ufs_swab32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), + SWAB32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), inode->i_gid); } else { - inode->i_gid = ufs_swab16(ufsip->ui_sgid); + inode->i_gid = SWAB16(ufsip->ui_sgid); } /* - * Linux i_size is 32 bits, so some files on a UFS filesystem may not + * Linux i_size is 32 bits on most architectures, + * so some files on a UFS filesystem may not * be readable. I let people access the first 32 bits worth of them. * for the rw code, we may want to mark these inodes as read-only. * XXX - bug Linus to make i_size a __u64 instead of a __u32. */ - inode->u.ufs_i.i_size = ((__u64)(ufs_swab32(ufsip->ui_size.val[0]))<<32) | - (__u64)(ufs_swab32(ufsip->ui_size.val[1])); + inode->u.ufs_i.i_size = SWAB64(ufsip->ui_size); /* KRR - Just type cast inode->u.ufs_i.i_size into off_t and * worry about overflow later */ @@ -210,11 +214,11 @@ * want to keep this data, but for the moment I think I'll just write * zeros for these fields when writing out inodes. */ - inode->i_atime = ufsip->ui_atime.tv_sec; - inode->i_mtime = ufsip->ui_mtime.tv_sec; - inode->i_ctime = ufsip->ui_ctime.tv_sec; + inode->i_atime = SWAB32(ufsip->ui_atime.tv_sec); + inode->i_mtime = SWAB32(ufsip->ui_mtime.tv_sec); + inode->i_ctime = SWAB32(ufsip->ui_ctime.tv_sec); inode->i_blksize = sb->u.ufs_sb.s_fsize; - inode->i_blocks = ufs_swab32(ufsip->ui_blocks); + inode->i_blocks = SWAB32(ufsip->ui_blocks); inode->i_version = ++event; /* see linux/kernel/sched.c */ if (S_ISREG(inode->i_mode)) { @@ -246,11 +250,11 @@ int i; for (i = 0; i < UFS_NDADDR; i++) { - inode->u.ufs_i.i_data[i] = ufs_swab32(ufsip->ui_db[i]); + inode->u.ufs_i.i_data[i] = SWAB32(ufsip->ui_db[i]); } for (i = 0; i < UFS_NINDIR; i++) { inode->u.ufs_i.i_data[UFS_IND_BLOCK + i] = - ufs_swab32(ufsip->ui_ib[i]); + SWAB32(ufsip->ui_ib[i]); } } @@ -261,18 +265,17 @@ * the code. */ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - inode->i_rdev = (kdev_t)((__u64)(ufs_swab32(ufsip->ui_db[0]))<<32) | - (__u64)(ufs_swab32(ufsip->ui_db[1])); + inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_db); } /* XXX - implement fast and slow symlinks */ - inode->u.ufs_i.i_flags = ufs_swab32(ufsip->ui_flags); - inode->u.ufs_i.i_gen = ufs_swab32(ufsip->ui_gen); /* XXX - is this i_version? */ - inode->u.ufs_i.i_shadow = ufs_swab32(ufsip->ui_shadow); /* XXX */ - inode->u.ufs_i.i_uid = ufs_swab32(ufsip->ui_uid); - inode->u.ufs_i.i_gid = ufs_swab32(ufsip->ui_gid); - inode->u.ufs_i.i_oeftflag = ufs_swab32(ufsip->ui_oeftflag); + inode->u.ufs_i.i_flags = SWAB32(ufsip->ui_flags); + inode->u.ufs_i.i_gen = SWAB32(ufsip->ui_gen); /* XXX - is this i_version? */ + inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_shadow); /* XXX */ + inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_uid); + inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_gid); + inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_oeftflag); brelse(bh); @@ -307,4 +310,3 @@ return; } - diff -u --recursive --new-file v2.1.70/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c --- v2.1.70/linux/fs/ufs/ufs_namei.c Mon Aug 4 16:25:39 1997 +++ linux/fs/ufs/ufs_namei.c Wed Dec 3 06:18:33 1997 @@ -6,48 +6,62 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_namei.c,v 1.9 1997/07/22 06:40:12 davem Exp $ + * Clean swab support by Francois-Rene Rideau 19970406 + * Ported to 2.1.62 by Francois-Rene Rideau 19971109 * */ #include #include - #include +#include "ufs_swab.h" /* * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. * stolen from ext2fs */ -static int ufs_match (int len, const char * const name, struct ufs_direct * d) +static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 bytesex) { if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */ return 0; /* * "" means "." ---> so paths like "/usr/lib//libc.a" work */ - if (!len && (ufs_swab16(d->d_namlen) == 1) && (d->d_name[0] == '.') && - (d->d_name[1] == '\0')) - return 1; - if (len != ufs_swab16(d->d_namlen)) + if (!len && (SWAB16(d->d_namlen) == 1) && (d->d_name[0] == '.') && + (d->d_name[1] == '\0')) + return 1; + if (len != SWAB16(d->d_namlen)) return 0; return !memcmp(name, d->d_name, len); } -/* XXX - this is a mess, especially for endianity */ -int ufs_lookup (struct inode * dir, struct qstr *qname, - struct inode ** result) +int ufs_lookup (struct inode *dir, struct dentry *dentry) { + /* XXX - this is all fucked up! */ + /* XXX - and it's been broken since linux has this new dentry interface: + * allows reading of files, but screws the whole dcache, even outside + * of the ufs partition, so that umount'ing won't suffice to fix it -- + * reboot needed + */ unsigned long int lfragno, fragno; struct buffer_head * bh; struct ufs_direct * d; - const char *name = qname->name; - int len = qname->len; + const char *name = dentry->d_name.name; + int len = dentry->d_name.len; + __u32 bytesex; + struct inode *inode; + + /* XXX - isn't that already done by the upper layer? */ + if (!dir || !S_ISDIR(dir->i_mode)) + return -EBADF; + + bytesex = dir->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) printk("Passed name: %s\nPassed length: %d\n", name, len); - /* + + /* debugging hacks: * Touching /xyzzy in a filesystem toggles debugging messages. */ if ((len == 5) && !(memcmp(name, "xyzzy", len)) && @@ -56,8 +70,8 @@ printk("UFS debugging %s\n", (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ? "on": "off"); - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } /* @@ -69,8 +83,8 @@ printk("UFS inode debugging %s\n", (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ? "on": "off"); - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) && @@ -79,8 +93,8 @@ printk("UFS namei debugging %s\n", (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ? "on": "off"); - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) && @@ -89,10 +103,13 @@ printk("UFS symlink debugging %s\n", (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ? "on": "off"); - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } + + /* Now for the real thing */ + if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) { printk("ufs_lookup: called for ino %lu name %s\n", dir->i_ino, name); @@ -109,21 +126,22 @@ } if (fragno == 0) { /* XXX - bug bug bug */ - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize); if (bh == NULL) { - printk("ufs_lookup: bread failed: ino %lu, lfragno %lu", + printk("ufs_lookup: bread failed: " + "ino %lu, lfragno %lu", dir->i_ino, lfragno); - iput(dir); return(-EIO); } d = (struct ufs_direct *)(bh->b_data); - while (((char *)d - bh->b_data + ufs_swab16(d->d_reclen)) <= + while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <= dir->i_sb->s_blocksize) { /* XXX - skip block if d_reclen or d_namlen is 0 */ - if ((ufs_swab16(d->d_reclen) == 0) || (ufs_swab16(d->d_namlen) == 0)) { + if ((d->d_reclen == 0) || (d->d_namlen == 0)) { + /* no need to SWAB16(): test against 0 */ if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { printk("ufs_lookup: skipped space in directory, ino %lu\n", dir->i_ino); @@ -131,32 +149,43 @@ break; } if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { - printk("lfragno 0x%lx direct d 0x%x d_ino %u " - "d_reclen %u d_namlen %u d_name `%s'\n", - lfragno, (unsigned int)((unsigned long)d), - ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen), - ufs_swab16(d->d_namlen), d->d_name); + printk("lfragno 0x%lx " + "direct d 0x%x " + "d_ino %u " + "d_reclen %u " + "d_namlen %u d_name `%s'\n", + lfragno, + (unsigned int)((unsigned long)d), + SWAB32(d->d_ino), + SWAB16(d->d_reclen), + SWAB16(d->d_namlen),d->d_name); } - if ((ufs_swab16(d->d_namlen) == len) && + if ((SWAB16(d->d_namlen) == len) && /* XXX - don't use strncmp() - see ext2fs */ - (ufs_match(len, name, d))) { + (ufs_match(len, name, d, bytesex))) { /* We have a match */ - *result = iget(dir->i_sb, ufs_swab32(d->d_ino)); - brelse(bh); - iput(dir); +/* XXX - I only superficially understand how things work, + * so use at your own risk... -- Fare' + */ + inode = iget(dir->i_sb, SWAB32(d->d_ino)); + brelse(bh); + if(!inode) { return -EACCES; } + d_add(dentry,inode); return(0); } else { /* XXX - bounds checking */ if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { - printk("ufs_lookup: wanted (%s,%d) got (%s,%d)\n", - name, len, d->d_name, ufs_swab16(d->d_namlen)); + printk("ufs_lookup: " + "wanted (%s,%d) got (%s,%d)\n", + name, len, + d->d_name, SWAB16(d->d_namlen)); } } - d = (struct ufs_direct *)((char *)d + ufs_swab16(d->d_reclen)); + d = (struct ufs_direct *)((char *)d + SWAB16(d->d_reclen)); } brelse(bh); } - iput(dir); - return(-ENOENT); + not_found: + d_add(dentry,NULL); + return(0); } - diff -u --recursive --new-file v2.1.70/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c --- v2.1.70/linux/fs/ufs/ufs_super.c Thu Jul 17 10:06:08 1997 +++ linux/fs/ufs/ufs_super.c Wed Dec 3 06:18:33 1997 @@ -8,8 +8,6 @@ * * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * - * $Id: ufs_super.c,v 1.25 1997/07/17 02:24:15 davem Exp $ - * */ /* @@ -18,30 +16,31 @@ * * Module usage counts added on 96/04/29 by * Gertjan van Wingerde + * + * Clean swab support on 19970406 by + * Francois-Rene Rideau */ -#include #include #include #include #include #include -#include - #include -int ufs_need_swab = 0; +#include "ufs_swab.h" struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent); void ufs_put_super (struct super_block * sb); -void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize); +int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize); static struct super_operations ufs_super_ops = { ufs_read_inode, - NULL, /* notify_change() */ NULL, /* XXX - ufs_write_inode() */ ufs_put_inode, + NULL, /* XXX - ufs_delete_inode() */ + NULL, /* notify_change() */ ufs_put_super, NULL, /* XXX - ufs_write_super() */ ufs_statfs, @@ -55,7 +54,8 @@ NULL }; -__initfunc(int init_ufs_fs(void)) +int +init_ufs_fs(void) { return(register_filesystem(&ufs_fs_type)); } @@ -113,8 +113,9 @@ struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent) { - struct ufs_superblock * usb; + struct ufs_superblock * usb; /* normalized to local byteorder */ struct buffer_head * bh1, *bh2; + __u32 bytesex = 0; /* sb->s_dev and sb->s_flags are set by our caller * data is the mystery argument to sys_mount() @@ -132,9 +133,7 @@ if (!(bh1 = bread(sb->s_dev, UFS_SBLOCK/BLOCK_SIZE, BLOCK_SIZE)) || !(bh2 = bread(sb->s_dev, (UFS_SBLOCK + BLOCK_SIZE)/BLOCK_SIZE, BLOCK_SIZE))) { - if (bh1) { - brelse(bh1); - } + brelse(bh1); printk ("ufs_read_super: unable to read superblock\n"); goto ufs_read_super_lose; @@ -156,32 +155,35 @@ brelse(bh1); brelse(bh2); - ufs_need_swab = 0; - sb->s_magic = ufs_swab32(usb->fs_magic); - if (sb->s_magic != UFS_MAGIC) { - ufs_need_swab = 1; - sb->s_magic = ufs_swab32(usb->fs_magic); - if (sb->s_magic != UFS_MAGIC) { - printk ("ufs_read_super: bad magic number 0x%8.8lx " - "on dev %d/%d\n", sb->s_magic, + switch (le32_to_cpup(&usb->fs_magic)) { + case UFS_MAGIC: + bytesex = UFS_LITTLE_ENDIAN; + ufs_superblock_le_to_cpus(usb); + break; + case UFS_CIGAM: + bytesex = UFS_BIG_ENDIAN; + ufs_superblock_be_to_cpus(usb); + break; + /* usb is now normalized to local byteorder */ + default: + printk ("ufs_read_super: bad magic number 0x%8.8x " + "on dev %d/%d\n", usb->fs_magic, MAJOR(sb->s_dev), MINOR(sb->s_dev)); - goto ufs_read_super_lose; - } } /* We found a UFS filesystem on this device. */ /* XXX - parse args */ - if (ufs_swab32(usb->fs_bsize) != UFS_BSIZE) { - printk("ufs_read_super: fs_bsize %d != %d\n", ufs_swab32(usb->fs_bsize), + if (usb->fs_bsize != UFS_BSIZE) { + printk("ufs_read_super: fs_bsize %d != %d\n", usb->fs_bsize, UFS_BSIZE); goto ufs_read_super_lose; } - if (ufs_swab32(usb->fs_fsize) != UFS_FSIZE) { - printk("ufs_read_super: fs_fsize %d != %d\n", ufs_swab32(usb->fs_fsize), + if (usb->fs_fsize != UFS_FSIZE) { + printk("ufs_read_super: fs_fsize %d != %d\n", usb->fs_fsize, UFS_FSIZE); goto ufs_read_super_lose; } @@ -190,7 +192,7 @@ printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt); #endif - if (ufs_swab32(usb->fs_state) == UFS_FSOK - ufs_swab32(usb->fs_time)) { + if (usb->fs_state == UFS_FSOK - usb->fs_time) { switch(usb->fs_clean) { case UFS_FSCLEAN: #ifdef DEBUG_UFS_SUPER @@ -225,35 +227,35 @@ /* XXX - sanity check sb fields */ /* KRR - Why are we not using fs_bsize for blocksize? */ - sb->s_blocksize = ufs_swab32(usb->fs_fsize); - sb->s_blocksize_bits = ufs_swab32(usb->fs_fshift); + sb->s_blocksize = usb->fs_fsize; + sb->s_blocksize_bits = usb->fs_fshift; /* XXX - sb->s_lock */ sb->s_op = &ufs_super_ops; sb->dq_op = 0; /* XXX */ - /* KRR - defined above - sb->s_magic = usb->fs_magic; */ + sb->s_magic = usb->fs_magic; /* sb->s_time */ /* sb->s_wait */ /* XXX - sb->u.ufs_sb */ sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */ - sb->u.ufs_sb.s_flags = 0; - sb->u.ufs_sb.s_ncg = ufs_swab32(usb->fs_ncg); - sb->u.ufs_sb.s_ipg = ufs_swab32(usb->fs_ipg); - sb->u.ufs_sb.s_fpg = ufs_swab32(usb->fs_fpg); - sb->u.ufs_sb.s_fsize = ufs_swab32(usb->fs_fsize); - sb->u.ufs_sb.s_fmask = ufs_swab32(usb->fs_fmask); - sb->u.ufs_sb.s_fshift = ufs_swab32(usb->fs_fshift); - sb->u.ufs_sb.s_bsize = ufs_swab32(usb->fs_bsize); - sb->u.ufs_sb.s_bmask = ufs_swab32(usb->fs_bmask); - sb->u.ufs_sb.s_bshift = ufs_swab32(usb->fs_bshift); - sb->u.ufs_sb.s_iblkno = ufs_swab32(usb->fs_iblkno); - sb->u.ufs_sb.s_dblkno = ufs_swab32(usb->fs_dblkno); - sb->u.ufs_sb.s_cgoffset = ufs_swab32(usb->fs_cgoffset); - sb->u.ufs_sb.s_cgmask = ufs_swab32(usb->fs_cgmask); - sb->u.ufs_sb.s_inopb = ufs_swab32(usb->fs_inopb); - sb->u.ufs_sb.s_lshift = ufs_swab32(usb->fs_bshift) - ufs_swab32(usb->fs_fshift); - sb->u.ufs_sb.s_lmask = ~((ufs_swab32(usb->fs_fmask) - ufs_swab32(usb->fs_bmask)) - >> ufs_swab32(usb->fs_fshift)); - sb->u.ufs_sb.s_fsfrag = ufs_swab32(usb->fs_frag); /* XXX - rename this later */ + sb->u.ufs_sb.s_flags = bytesex | UFS_DEBUG_INITIAL ; + sb->u.ufs_sb.s_ncg = usb->fs_ncg; + sb->u.ufs_sb.s_ipg = usb->fs_ipg; + sb->u.ufs_sb.s_fpg = usb->fs_fpg; + sb->u.ufs_sb.s_fsize = usb->fs_fsize; + sb->u.ufs_sb.s_fmask = usb->fs_fmask; + sb->u.ufs_sb.s_fshift = usb->fs_fshift; + sb->u.ufs_sb.s_bsize = usb->fs_bsize; + sb->u.ufs_sb.s_bmask = usb->fs_bmask; + sb->u.ufs_sb.s_bshift = usb->fs_bshift; + sb->u.ufs_sb.s_iblkno = usb->fs_iblkno; + sb->u.ufs_sb.s_dblkno = usb->fs_dblkno; + sb->u.ufs_sb.s_cgoffset = usb->fs_cgoffset; + sb->u.ufs_sb.s_cgmask = usb->fs_cgmask; + sb->u.ufs_sb.s_inopb = usb->fs_inopb; + sb->u.ufs_sb.s_lshift = usb->fs_bshift - usb->fs_fshift; + sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask) + >> usb->fs_fshift); + sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */ sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL); #ifdef DEBUG_UFS_SUPER @@ -285,6 +287,7 @@ sb->s_dev = 0; /* XXX - free allocated kernel memory */ + /* includes freeing usb page */ unlock_super (sb); MOD_DEC_USE_COUNT; @@ -292,11 +295,12 @@ return; } -void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) +int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) { struct statfs tmp; struct statfs *sp = &tmp; struct ufs_superblock *fsb = sb->u.ufs_sb.s_raw_sb; + /* fsb was already normalized during mounting */ unsigned long used, avail; if (sb->u.ufs_sb.s_flags & UFS_DEBUG) { @@ -305,13 +309,13 @@ sp->f_type = sb->s_magic; sp->f_bsize = sb->s_blocksize; - sp->f_blocks = ufs_swab32(fsb->fs_dsize); - sp->f_bfree = ufs_swab32(fsb->fs_cstotal.cs_nbfree) * - ufs_swab32(fsb->fs_frag) + - ufs_swab32(fsb->fs_cstotal.cs_nffree); + sp->f_blocks = fsb->fs_dsize; + sp->f_bfree = fsb->fs_cstotal.cs_nbfree * + fsb->fs_frag + + fsb->fs_cstotal.cs_nffree; avail = sp->f_blocks - (sp->f_blocks / 100) * - ufs_swab32(fsb->fs_minfree); + fsb->fs_minfree; used = sp->f_blocks - sp->f_bfree; if (avail > used) sp->f_bavail = avail - used; @@ -319,11 +323,10 @@ sp->f_bavail = 0; sp->f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg; - sp->f_ffree = ufs_swab32(fsb->fs_cstotal.cs_nifree); - sp->f_fsid.val[0] = ufs_swab32(fsb->fs_id[0]); - sp->f_fsid.val[1] = ufs_swab32(fsb->fs_id[1]); + sp->f_ffree = fsb->fs_cstotal.cs_nifree; + sp->f_fsid.val[0] = fsb->fs_id[0]; + sp->f_fsid.val[1] = fsb->fs_id[1]; sp->f_namelen = UFS_MAXNAMLEN; - copy_to_user(buf, sp, bufsiz); - return; + return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0; } diff -u --recursive --new-file v2.1.70/linux/fs/ufs/ufs_swab.c linux/fs/ufs/ufs_swab.c --- v2.1.70/linux/fs/ufs/ufs_swab.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/ufs_swab.c Wed Dec 3 06:18:33 1997 @@ -0,0 +1,138 @@ +/* + * linux/fs/ufs/ufs_swab.c + * + * Copyright (C) 1997 + * Francois-Rene Rideau + * + */ + +/* + * For inspiration, you might wanna check sys/ufs/ffs/fs.h from whateverBSD + * + * NOTES + * 19970406 - Fare + * 1) I began from old very preliminary 2.0.x sources, + * but it was underfeatured; + * I later saw that 2.1.1 sources had a *global* UFS byteswap flag. + * EVIL: imagine that a swabbed partition be mounted + * while a non-swabbed partition are active (that sucks!) + * I merged that source tree with mine. + * 2) I hope no one is using obNNUUXXIIous byteorder. + * That's the only thing I might have broken, + * though I rather think it's a fix: + * instead of __u64 like BSD, + * the former driver used an explicitly bigendian array of __u32! + * 3) I provide a few macros that use GCC C Extensions. + * Port to other compilers would require avoiding them. + * in any case, 64 bit (long long) support is required, + * unless you're ready to workaround + * 4) the swab routines below depend on the precise name and order + * of the structure elements. Watch out any modification in ufs_fs.h!!! + * 5) putting byteswapping stuff in ufs_swab* seems cleaner to me. + * 6) These sources should work with both 2.0 and 2.1 kernels... + * + * 19971013 - Fare + * 1) Ported to 2.1.57 + * 2) instead of byteswapping, use [bl]e_to_cpu: + * it might be that we run on a VAX! + * + * HOWTO continue adding swab support: + * basically, anywhere metadata is bread() (i.e. mapped to block device), + * data should either be SWAB()ed on the fly, + * or copied to a buffer and globally bswap_ufs_*() there. + * + */ + +#include +#include "ufs_swab.h" + +static __inline__ void n_be16_to_cpus(__u16*p,unsigned n) { +#ifndef __BIG_ENDIAN + unsigned i; + for(i=0;imember))-(char*)(p))) +#define __length_since(p,member) \ + ((unsigned)(sizeof(*p)-__length_before(p,member))) +#define __length_between(p,begin,after_end) \ + ((unsigned)(__length_before(p,after_end)-__length_before(p,begin))) +#define be32_to_cpus__between(s,begin,after_end) \ + n_be32_to_cpus((__u32*)&((s).begin), \ + __length_between(&s,begin,after_end)/4) +#define le32_to_cpus__between(s,begin,after_end) \ + n_le32_to_cpus((__u32*)&((s).begin), \ + __length_between(&s,begin,after_end)/4) +#define be32_to_cpus__since(s,begin) \ + n_be32_to_cpus((__u32*)&((s).begin), \ + __length_since(&s,begin)/4) +#define le32_to_cpus__since(s,begin) \ + n_le32_to_cpus((__u32*)&((s).begin), \ + __length_since(&s,begin)/4) +#define be16_to_cpus__between(s,begin,after_end) \ + n_be16_to_cpus((__u16*)&((s).begin), \ + __length_between(&s,begin,after_end)/2) +#define le16_to_cpus__between(s,begin,after_end) \ + n_le16_to_cpus((__u16*)&((s).begin), \ + __length_between(&s,begin,after_end)/2) + +/* + * Here are the whole-structure swabping routines... + */ + +extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb) { +#ifndef __BIG_ENDIAN + be32_to_cpus__between(*usb,fs_link,fs_fmod); + /* XXX - I dunno what to do w/ fs_csp, + * but it is unused by the current code, so that's ok for now. + */ + be32_to_cpus(&usb->fs_cpc); + be16_to_cpus__between(*usb,fs_opostbl,fs_sparecon); + be32_to_cpus__between(*usb,fs_sparecon,fs_qbmask); + be64_to_cpus(&usb->fs_qbmask); + be64_to_cpus(&usb->fs_qfmask); + be32_to_cpus__between(*usb,fs_postblformat,fs_magic); +#endif +} +extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb) { +#ifndef __LITTLE_ENDIAN + le32_to_cpus__between(*usb,fs_link,fs_fmod); + /* XXX - I dunno what to do w/ fs_csp, + * but it is unused by the current code, so that's ok for now. + */ + le32_to_cpus(&usb->fs_cpc); + le16_to_cpus__between(*usb,fs_opostbl,fs_sparecon); + le32_to_cpus__between(*usb,fs_sparecon,fs_qbmask); + le64_to_cpus(&usb->fs_qbmask); + le64_to_cpus(&usb->fs_qfmask); + le32_to_cpus__between(*usb,fs_postblformat,fs_magic); +#endif +} diff -u --recursive --new-file v2.1.70/linux/fs/ufs/ufs_swab.h linux/fs/ufs/ufs_swab.h --- v2.1.70/linux/fs/ufs/ufs_swab.h Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/ufs_swab.h Wed Dec 3 06:18:33 1997 @@ -0,0 +1,59 @@ +/* + * linux/fs/ufs/ufs_swab.h + * + * Copyright (C) 1997 + * Francois-Rene Rideau + * + */ + +#ifndef _UFS_SWAB_H +#define _UFS_SWAB_H + + +/* + * Notes: + * (1) HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes + * in case there are ufs implementations that have strange bytesexes, + * you'll need to modify code here as well as in ufs_super.c and ufs_fs.h + * to support them. + * (2) for a read/write ufs driver, we should distinguish + * between byteswapping for read or write accesses! + */ + +#include +#include + +/* + * These are only valid inside ufs routines, + * after bytesex has been initialized to sb->u.ufs_sb.s_flags&UFS_BYTESEX + */ +#define SWAB16(x) ufs_swab16(bytesex,x) +#define SWAB32(x) ufs_swab32(bytesex,x) +#define SWAB64(x) ufs_swab64(bytesex,x) + +extern __inline__ __const__ __u16 ufs_swab16(__u32 bytesex, __u16 x) { + if (bytesex == UFS_LITTLE_ENDIAN) { + return le16_to_cpu(x); + } else { + return be16_to_cpu(x); + } +} +extern __inline__ __const__ __u32 ufs_swab32(__u32 bytesex, __u32 x) { + if (bytesex == UFS_LITTLE_ENDIAN) { + return le32_to_cpu(x); + } else { + return be32_to_cpu(x); + } +} +extern __inline__ __const__ __u64 ufs_swab64(__u32 bytesex, __u64 x) { + if (bytesex == UFS_LITTLE_ENDIAN) { + return le64_to_cpu(x); + } else { + return be64_to_cpu(x); + } +} + +extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb); +extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb); + +#endif /* _UFS_SWAB_H */ diff -u --recursive --new-file v2.1.70/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c --- v2.1.70/linux/fs/ufs/ufs_symlink.c Mon Jun 16 16:35:59 1997 +++ linux/fs/ufs/ufs_symlink.c Wed Dec 3 06:18:33 1997 @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_symlink.c,v 1.9 1997/06/05 01:29:11 davem Exp $ + * Ported to 2.1.62 by Francois-Rene Rideau 19971109 * */ @@ -16,6 +16,8 @@ #include +extern int ufs_bmap (struct inode *, int); + static int ufs_readlink(struct inode * inode, char * buffer, int buflen) { @@ -30,6 +32,10 @@ inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); } + if (!S_ISLNK(inode->i_mode)) { + return -EINVAL; + } + if (buflen > inode->i_sb->s_blocksize - 1) buflen = inode->i_sb->s_blocksize - 1; if (inode->i_blocks) { @@ -38,16 +44,16 @@ if (inode->i_sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) { printk("ufs_readlink: bmap got %lu for ino %lu\n", block, inode->i_ino); - } + } bh = bread(inode->i_dev, block, BLOCK_SIZE); if (!bh) { - iput (inode); printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n", inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); return 0; } link = bh->b_data; + /* no need to bswap */ } else { link = (char *)&(inode->u.ufs_i.i_data[0]); @@ -57,18 +63,54 @@ i++; put_user (c, buffer++); } - iput (inode); - if (bh) - brelse (bh); + brelse (bh); return i; } +/* + * XXX - blatantly stolen from minix fs + */ +static struct dentry * +ufs_follow_link(struct inode * inode, struct dentry * base) +{ + unsigned long int block; + struct buffer_head * bh = NULL; + char * link; + + if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { + printk("ufs_follow_link: called on ino %lu dev %u/%u\n", + inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); + } + + if (inode->i_blocks) { + /* read the link from disk */ + /* XXX - error checking */ + block = ufs_bmap(inode, 0); + bh = bread(inode->i_dev, block, BLOCK_SIZE); + if (bh == NULL) { + printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n", + inode->i_ino, MAJOR(inode->i_dev), + MINOR(inode->i_dev)); + dput(base); + return ERR_PTR(-EIO); + } + link = bh->b_data; + } else { + /* fast symlink */ + link = (char *)&(inode->u.ufs_i.i_data[0]); + } + base = lookup_dentry(link, base, 1); + brelse (bh); + return base; +} + + static struct file_operations ufs_symlink_operations = { NULL, /* lseek */ NULL, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* poll */ + NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ @@ -90,12 +132,11 @@ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ - ufs_readlink, /* readlink */ + &ufs_readlink, /* readlink */ + &ufs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ - NULL, /* smap */ }; - diff -u --recursive --new-file v2.1.70/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.1.70/linux/fs/vfat/namei.c Sat Nov 1 11:04:27 1997 +++ linux/fs/vfat/namei.c Wed Dec 3 04:24:29 1997 @@ -5,7 +5,7 @@ * * Windows95/Windows NT compatible extended MSDOS filesystem * by Gordon Chaffee Copyright (C) 1995. Send bug reports for the - * VFAT filesystem to . Specify + * VFAT filesystem to . Specify * what file operation caused you trouble and if you can duplicate * the problem, send a script that demonstrates it. */ @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -38,12 +39,6 @@ # define CHECK_STACK check_stack(__FILE__, __LINE__) #endif -/* - * XXX: It would be better to use the tolower from linux/ctype.h, - * but _ctype is needed and it is not exported. - */ -#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c)) - struct vfat_find_info { const char *name; int len; @@ -229,10 +224,15 @@ /* MS-DOS "device special files" */ -static const char *reserved_names[] = { - "CON ","PRN ","NUL ","AUX ", - "LPT1 ","LPT2 ","LPT3 ","LPT4 ", - "COM1 ","COM2 ","COM3 ","COM4 ", +static const char *reserved3_names[] = { + "con ", "prn ", "nul ", "aux ", NULL +}; + +static const char *reserved4_names[] = { + "com1 ", "com2 ", "com3 ", "com4 ", "com5 ", + "com6 ", "com7 ", "com8 ", "com9 ", + "lpt1 ", "lpt2 ", "lpt3 ", "lpt4 ", "lpt5 ", + "lpt6 ", "lpt7 ", "lpt8 ", "lpt9 ", NULL }; @@ -245,16 +245,32 @@ int find_long,int new_filename,int is_dir, struct slot_info *sinfo_out); -/* Checks the validity of an long MS-DOS filename */ +static int strnicmp(const char *s1, const char *s2, int len) +{ + int n = 0; + while (*s1 && *s2 && (tolower(*s1) == tolower(*s2))) { + s1++; s2++; n++; + if (n == len) return 0; + } + if (*s1 == 0 && *s2 == 0) return 0; + if (*s1 && *s2) { + if (*s1 > *s2) return 1; + return -1; + } + if (*s1) return 1; + return -1; +} + +/* Checks the validity of a long MS-DOS filename */ /* Returns negative number on error, 0 for a normal * return, and 1 for . or .. */ static int vfat_valid_longname(const char *name, int len, int dot_dirs, int xlate) { - const char **reserved; + const char **reserved, *walk; unsigned char c; - int i; + int i, baselen; if (IS_FREE(name)) return -EINVAL; if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) { @@ -271,9 +287,21 @@ return -EINVAL; } } - if (len == 3 || len == 4) { - for (reserved = reserved_names; *reserved; reserved++) - if (!strncmp(name,*reserved,8)) return -EINVAL; + if (len < 3) return 0; + + for (walk = name; *walk != 0 && *walk != '.'; walk++); + baselen = walk - name; + + if (baselen == 3) { + for (reserved = reserved3_names; *reserved; reserved++) { + if (!strnicmp(name,*reserved,baselen)) + return -EINVAL; + } + } else if (baselen == 4) { + for (reserved = reserved4_names; *reserved; reserved++) { + if (!strnicmp(name,*reserved,baselen)) + return -EINVAL; + } } return 0; } @@ -284,6 +312,7 @@ const char *walk, **reserved; unsigned char c; int space; + int baselen; if (IS_FREE(name)) return -EINVAL; if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) { @@ -312,7 +341,9 @@ if (c != '.') return -EINVAL; } while (c != '.' && len--) c = *walk++; + baselen = walk - name; if (c == '.') { + baselen--; if (len >= 4) return -EINVAL; while (len > 0 && walk-name < (MSDOS_NAME+1)) { c = *walk++; @@ -329,8 +360,13 @@ if (space) return -EINVAL; if (len) return -EINVAL; } - for (reserved = reserved_names; *reserved; reserved++) - if (!strncmp(name,*reserved,8)) return -EINVAL; + if (baselen == 3) { + for (reserved = reserved3_names; *reserved; reserved++) + if (!strnicmp(name,*reserved,baselen)) return -EINVAL; + } else if (baselen == 4) { + for (reserved = reserved4_names; *reserved; reserved++) + if (!strnicmp(name,*reserved,baselen)) return -EINVAL; + } return 0; } @@ -341,7 +377,7 @@ */ static int vfat_format_name(const char *name,int len,char *res, - int dot_dirs,int utf8) + int dot_dirs,int utf8) { char *walk; const char **reserved; @@ -396,8 +432,10 @@ if (len) return -EINVAL; } while (walk-res < MSDOS_NAME) *walk++ = ' '; - for (reserved = reserved_names; *reserved; reserved++) - if (!strncmp(res,*reserved,8)) return -EINVAL; + for (reserved = reserved3_names; *reserved; reserved++) + if (!strnicmp(res,*reserved,8)) return -EINVAL; + for (reserved = reserved4_names; *reserved; reserved++) + if (!strnicmp(res,*reserved,8)) return -EINVAL; return 0; } @@ -605,8 +643,8 @@ /* Directory slots of busy deleted files aren't available yet. */ done = !MSDOS_I(inode)->i_busy; /* PRINTK(("inode %d still busy\n", ino)); */ + iput(inode); } - iput(inode); } if (done) { row++; @@ -995,7 +1033,6 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry) { int res; - struct inode *next; struct slot_info sinfo; struct inode *result; @@ -1014,7 +1051,7 @@ if (!result->i_sb || (result->i_sb->s_magic != MSDOS_SUPER_MAGIC)) { /* crossed a mount point into a non-msdos fs */ - d_add(dentry,result); + d_add(dentry,NULL); return 0; } if (MSDOS_I(result)->i_busy) { /* mkdir in progress */ @@ -1023,18 +1060,7 @@ return 0; } PRINTK (("vfat_lookup 6\n")); - while (MSDOS_I(result)->i_old) { - next = MSDOS_I(result)->i_old; - iput(result); - if (!(result = iget(next->i_sb,next->i_ino))) { - fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen"); - iput(dir); - return -ENOENT; - } - } - PRINTK (("vfat_lookup 7\n")); d_add(dentry,result); - PRINTK (("vfat_lookup 8\n")); return 0; } @@ -1091,10 +1117,12 @@ result=NULL; fat_lock_creation(); res = vfat_create_entry(dir,&dentry->d_name,0,&result); - if (res < 0) PRINTK(("vfat_create: unable to get new entry\n")); - fat_unlock_creation(); - d_instantiate(dentry,result); + if (res < 0) { + PRINTK(("vfat_create: unable to get new entry\n")); + } else { + d_instantiate(dentry,result); + } return res; } @@ -1123,9 +1151,10 @@ de->adate = de->cdate = de->date; de->size = 0; fat_mark_buffer_dirty(sb, bh, 1); - if ((dot = iget(dir->i_sb,ino)) != NULL) - vfat_read_inode(dot); - if (!dot) return -EIO; + dot = iget(dir->i_sb,ino); + if (!dot) + return -EIO; + vfat_read_inode(dot); dot->i_mtime = dot->i_atime = CURRENT_TIME; mark_inode_dirty(dot); if (isdot) { @@ -1192,8 +1221,15 @@ struct buffer_head *bh; struct msdos_dir_entry *de; - if (dir->i_count > 1) + /* + * Prune any child dentries, then verify that + * the directory is empty and not in use. + */ + shrink_dcache_sb(sb); /* should be child prune */ + + if (dir->i_count > 1) { return -EBUSY; + } if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */ pos = 0; bh = NULL; @@ -1288,7 +1324,6 @@ for (i = sinfo->long_slots; i > 0; --i) { res = fat_get_entry(dir, &offset, bh, &de); if (res < 0) { - printk("vfat_remove_entry: problem 1\n"); continue; } de->name[0] = DELETED_FLAG; @@ -1306,24 +1341,17 @@ struct buffer_head *bh; struct slot_info sinfo; - bh = NULL; - res = -EPERM; - if (dentry->d_name.name[0] == '.' && - (dentry->d_name.len == 1 || (dentry->d_name.len == 2 && - dentry->d_name.name[1] == '.'))) - goto rmdir_done; res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo); if (res >= 0 && sinfo.total_slots > 0) { + bh = NULL; res = vfat_remove_entry(dir,&sinfo,&bh,dentry,1,0); if (res > 0) { res = 0; } dir->i_version = ++event; + if (bh) fat_brelse(sb, bh); } - -rmdir_done: - fat_brelse(sb, bh); return res; } @@ -1331,9 +1359,10 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry) { int res; - res = vfat_rmdirx(dir, dentry); - d_delete(dentry); + if (res >= 0) { + d_delete(dentry); + } return res; } @@ -1357,7 +1386,7 @@ } } - fat_brelse(sb, bh); + if (bh) fat_brelse(sb, bh); return res; } @@ -1394,7 +1423,9 @@ int res; res = vfat_unlinkx (dir,dentry,1); - d_delete(dentry); + if (res >= 0) { + d_delete(dentry); + } return res; } @@ -1633,22 +1664,3 @@ } #endif /* ifdef MODULE */ - - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff -u --recursive --new-file v2.1.70/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h --- v2.1.70/linux/include/asm-alpha/byteorder.h Mon Jun 16 16:35:59 1997 +++ linux/include/asm-alpha/byteorder.h Wed Dec 3 06:18:17 1997 @@ -1,36 +1,13 @@ #ifndef _ALPHA_BYTEORDER_H #define _ALPHA_BYTEORDER_H -#undef ntohl -#undef ntohs -#undef htonl -#undef htons - -#ifndef __LITTLE_ENDIAN -#define __LITTLE_ENDIAN 1234 -#endif - -#ifndef __LITTLE_ENDIAN_BITFIELD -#define __LITTLE_ENDIAN_BITFIELD -#endif - -extern unsigned int ntohl(unsigned int); -extern unsigned short int ntohs(unsigned short int); -extern unsigned int htonl(unsigned int); -extern unsigned short int htons(unsigned short int); - -extern unsigned int __ntohl(unsigned int); -extern unsigned short int __ntohs(unsigned short int); +#include #ifdef __GNUC__ -extern unsigned int __constant_ntohl(unsigned int); -extern unsigned short int __constant_ntohs(unsigned short int); - -extern __inline__ unsigned int -__ntohl(unsigned int x) +static __inline__ __const__ __u32 ___arch__swab32(__u32 x) { - unsigned int t1, t2, t3; + __u64 t1, t2, t3; /* Break the final or's out of the block so that gcc can schedule them at will. Further, use add not or so that @@ -51,17 +28,10 @@ return t3 + t2 + t1; } -#define __constant_ntohl(x) \ - ((unsigned int)((((x) & 0x000000ff) << 24) | \ - (((x) & 0x0000ff00) << 8) | \ - (((x) & 0x00ff0000) >> 8) | \ - (((x) & 0xff000000) >> 24))) - -extern __inline__ unsigned short int -__ntohs(unsigned short int x) +static __inline__ __const__ __u16 ___arch__swab16(__u16 x) { - unsigned short int t1, t2; - + __u64 t1, t2; + __asm__( "insbl %2,1,%1 # %1 = bb00\n\t" "extbl %2,1,%0 # %0 = 00aa" @@ -70,99 +40,13 @@ return t1 | t2; } -#define __constant_ntohs(x) \ -((unsigned short int)((((x) & 0x00ff) << 8) | \ - (((x) & 0xff00) >> 8))) - -#define __htonl(x) __ntohl(x) -#define __htons(x) __ntohs(x) -#define __constant_htonl(x) __constant_ntohl(x) -#define __constant_htons(x) __constant_ntohs(x) - -#ifdef __OPTIMIZE__ -# define ntohl(x) \ -(__builtin_constant_p((long)(x)) ? \ - __constant_ntohl((x)) : \ - __ntohl((x))) -# define ntohs(x) \ -(__builtin_constant_p((short)(x)) ? \ - __constant_ntohs((x)) : \ - __ntohs((x))) -# define htonl(x) \ -(__builtin_constant_p((long)(x)) ? \ - __constant_htonl((x)) : \ - __htonl((x))) -# define htons(x) \ -(__builtin_constant_p((short)(x)) ? \ - __constant_htons((x)) : \ - __htons((x))) -#endif /* __OPTIMIZE__ */ +#define __arch__swab32(x) ___arch__swab32(x) +#define __arch__swab16(x) ___arch__swab16(x) #endif /* __GNUC__ */ -#ifdef __KERNEL__ - -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ -#define cpu_to_le32(x) (x) -#define cpu_to_le16(x) (x) - -#define cpu_to_be32(x) htonl((x)) -#define cpu_to_be16(x) htons((x)) - -/* The same, but returns converted value from the location pointer by addr. */ -extern __inline__ __u16 cpu_to_le16p(__u16 *addr) -{ - return cpu_to_le16(*addr); -} - -extern __inline__ __u32 cpu_to_le32p(__u32 *addr) -{ - return cpu_to_le32(*addr); -} - -extern __inline__ __u16 cpu_to_be16p(__u16 *addr) -{ - return cpu_to_be16(*addr); -} - -extern __inline__ __u32 cpu_to_be32p(__u32 *addr) -{ - return cpu_to_be32(*addr); -} - -/* The same, but do the conversion in situ, ie. put the value back to addr. */ -#define cpu_to_le16s(x) do { } while (0) -#define cpu_to_le32s(x) do { } while (0) - -extern __inline__ void cpu_to_be16s(__u16 *addr) -{ - *addr = cpu_to_be16(*addr); -} - -extern __inline__ void cpu_to_be32s(__u32 *addr) -{ - *addr = cpu_to_be32(*addr); -} - -/* Convert from specified byte order, to CPU byte order. */ -#define le16_to_cpu(x) cpu_to_le16(x) -#define le32_to_cpu(x) cpu_to_le32(x) -#define be16_to_cpu(x) cpu_to_be16(x) -#define be32_to_cpu(x) cpu_to_be32(x) - -#define le16_to_cpup(x) cpu_to_le16p(x) -#define le32_to_cpup(x) cpu_to_le32p(x) -#define be16_to_cpup(x) cpu_to_be16p(x) -#define be32_to_cpup(x) cpu_to_be32p(x) - -#define le16_to_cpus(x) cpu_to_le16s(x) -#define le32_to_cpus(x) cpu_to_le32s(x) -#define be16_to_cpus(x) cpu_to_be16s(x) -#define be32_to_cpus(x) cpu_to_be32s(x) +#define __BYTEORDER_HAS_U64__ -#endif /* __KERNEL__ */ +#include #endif /* _ALPHA_BYTEORDER_H */ diff -u --recursive --new-file v2.1.70/linux/include/asm-alpha/ioctls.h linux/include/asm-alpha/ioctls.h --- v2.1.70/linux/include/asm-alpha/ioctls.h Thu Jun 26 12:33:39 1997 +++ linux/include/asm-alpha/ioctls.h Thu Dec 4 13:09:01 1997 @@ -85,6 +85,7 @@ #define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff -u --recursive --new-file v2.1.70/linux/include/asm-alpha/siginfo.h linux/include/asm-alpha/siginfo.h --- v2.1.70/linux/include/asm-alpha/siginfo.h Mon Dec 1 12:04:14 1997 +++ linux/include/asm-alpha/siginfo.h Tue Dec 2 16:26:07 1997 @@ -120,7 +120,7 @@ * SIGSEGV si_codes */ #define SEGV_MAPERR 1 /* address not mapped to object */ -#define SRGV_ACCERR 2 /* invalid permissions for mapped object */ +#define SEGV_ACCERR 2 /* invalid permissions for mapped object */ #define NSIGSEGV 2 /* diff -u --recursive --new-file v2.1.70/linux/include/asm-i386/byteorder.h linux/include/asm-i386/byteorder.h --- v2.1.70/linux/include/asm-i386/byteorder.h Mon Jul 7 16:02:01 1997 +++ linux/include/asm-i386/byteorder.h Thu Dec 4 13:35:39 1997 @@ -1,36 +1,16 @@ #ifndef _I386_BYTEORDER_H #define _I386_BYTEORDER_H -#undef ntohl -#undef ntohs -#undef htonl -#undef htons +#include -#ifndef __LITTLE_ENDIAN -#define __LITTLE_ENDIAN 1234 -#endif - -#ifndef __LITTLE_ENDIAN_BITFIELD -#define __LITTLE_ENDIAN_BITFIELD -#endif +#ifdef __GNUC__ /* For avoiding bswap on i386 */ #ifdef __KERNEL__ #include #endif -extern unsigned long int ntohl(unsigned long int); -extern unsigned short int ntohs(unsigned short int); -extern unsigned long int htonl(unsigned long int); -extern unsigned short int htons(unsigned short int); - -extern __inline__ unsigned long int __ntohl(unsigned long int); -extern __inline__ unsigned short int __ntohs(unsigned short int); -extern __inline__ unsigned long int __constant_ntohl(unsigned long int); -extern __inline__ unsigned short int __constant_ntohs(unsigned short int); - -extern __inline__ unsigned long int -__ntohl(unsigned long int x) +static __inline__ __const__ __u32 ___arch__swab32(__u32 x) { #if defined(__KERNEL__) && !defined(CONFIG_M386) __asm__("bswap %0" : "=r" (x) : "0" (x)); @@ -40,115 +20,28 @@ "xchgb %b0,%h0" /* swap higher bytes */ :"=q" (x) : "0" (x)); -#endif - return x; -} - -#define __constant_ntohl(x) \ - ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ - (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ - (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ - (((unsigned long int)(x) & 0xff000000U) >> 24))) - -extern __inline__ unsigned short int -__ntohs(unsigned short int x) -{ - __asm__("xchgb %b0,%h0" /* swap bytes */ - : "=q" (x) - : "0" (x)); - return x; -} - -#define __constant_ntohs(x) \ - ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ - (((unsigned short int)(x) & 0xff00) >> 8))) \ - -#define __htonl(x) __ntohl(x) -#define __htons(x) __ntohs(x) -#define __constant_htonl(x) __constant_ntohl(x) -#define __constant_htons(x) __constant_ntohs(x) - -#ifdef __OPTIMIZE__ -# define ntohl(x) \ -(__builtin_constant_p((long)(x)) ? \ - __constant_ntohl((x)) : \ - __ntohl((x))) -# define ntohs(x) \ -(__builtin_constant_p((short)(x)) ? \ - __constant_ntohs((x)) : \ - __ntohs((x))) -# define htonl(x) \ -(__builtin_constant_p((long)(x)) ? \ - __constant_htonl((x)) : \ - __htonl((x))) -# define htons(x) \ -(__builtin_constant_p((short)(x)) ? \ - __constant_htons((x)) : \ - __htons((x))) #endif - -#ifdef __KERNEL__ -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ -#define cpu_to_le32(x) (x) -#define cpu_to_le16(x) (x) - -#define cpu_to_be32(x) htonl((x)) -#define cpu_to_be16(x) htons((x)) - -/* The same, but returns converted value from the location pointer by addr. */ -extern __inline__ __u16 cpu_to_le16p(__u16 *addr) -{ - return cpu_to_le16(*addr); -} - -extern __inline__ __u32 cpu_to_le32p(__u32 *addr) -{ - return cpu_to_le32(*addr); -} - -extern __inline__ __u16 cpu_to_be16p(__u16 *addr) -{ - return cpu_to_be16(*addr); + return x; } -extern __inline__ __u32 cpu_to_be32p(__u32 *addr) +static __inline__ __const__ __u16 ___arch__swab16(__u16 x) { - return cpu_to_be32(*addr); + __asm__("xchgb %b0,%h0" /* swap bytes */ \ + : "=q" (x) \ + : "0" (x)); \ + return x; } -/* The same, but do the conversion in situ, ie. put the value back to addr. */ -#define cpu_to_le16s(x) do { } while (0) -#define cpu_to_le32s(x) do { } while (0) +#define __arch__swab32(x) ___arch__swab32(x) +#define __arch__swab16(x) ___arch__swab16(x) -extern __inline__ void cpu_to_be16s(__u16 *addr) -{ - *addr = cpu_to_be16(*addr); -} - -extern __inline__ void cpu_to_be32s(__u32 *addr) -{ - *addr = cpu_to_be32(*addr); -} +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif -/* Convert from specified byte order, to CPU byte order. */ -#define le16_to_cpu(x) cpu_to_le16(x) -#define le32_to_cpu(x) cpu_to_le32(x) -#define be16_to_cpu(x) cpu_to_be16(x) -#define be32_to_cpu(x) cpu_to_be32(x) - -#define le16_to_cpup(x) cpu_to_le16p(x) -#define le32_to_cpup(x) cpu_to_le32p(x) -#define be16_to_cpup(x) cpu_to_be16p(x) -#define be32_to_cpup(x) cpu_to_be32p(x) - -#define le16_to_cpus(x) cpu_to_le16s(x) -#define le32_to_cpus(x) cpu_to_le32s(x) -#define be16_to_cpus(x) cpu_to_be16s(x) -#define be32_to_cpus(x) cpu_to_be32s(x) +#endif /* __GNUC__ */ -#endif /* __KERNEL__ */ +#include -#endif +#endif /* _I386_BYTEORDER_H */ diff -u --recursive --new-file v2.1.70/linux/include/asm-i386/ioctls.h linux/include/asm-i386/ioctls.h --- v2.1.70/linux/include/asm-i386/ioctls.h Thu Jun 26 12:33:39 1997 +++ linux/include/asm-i386/ioctls.h Thu Dec 4 13:09:01 1997 @@ -46,6 +46,7 @@ #define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -u --recursive --new-file v2.1.70/linux/include/asm-i386/siginfo.h linux/include/asm-i386/siginfo.h --- v2.1.70/linux/include/asm-i386/siginfo.h Mon Dec 1 12:04:14 1997 +++ linux/include/asm-i386/siginfo.h Tue Dec 2 16:26:00 1997 @@ -120,7 +120,7 @@ * SIGSEGV si_codes */ #define SEGV_MAPERR 1 /* address not mapped to object */ -#define SRGV_ACCERR 2 /* invalid permissions for mapped object */ +#define SEGV_ACCERR 2 /* invalid permissions for mapped object */ #define NSIGSEGV 2 /* diff -u --recursive --new-file v2.1.70/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h --- v2.1.70/linux/include/asm-m68k/bitops.h Sat May 24 09:10:24 1997 +++ linux/include/asm-m68k/bitops.h Wed Dec 3 06:18:17 1997 @@ -257,19 +257,7 @@ return (p - addr) * 32 + res; } -/* Byte swapping. */ -extern __inline__ unsigned short -swab16 (unsigned short val) -{ - return (val << 8) | (val >> 8); -} - -extern __inline__ unsigned int -swab32 (unsigned int val) -{ - __asm__ ("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val)); - return val; -} +/* Byte swapping (swab16 and swab32) is now in asm/byteorder.h . */ #endif /* _M68K_BITOPS_H */ diff -u --recursive --new-file v2.1.70/linux/include/asm-m68k/byteorder.h linux/include/asm-m68k/byteorder.h --- v2.1.70/linux/include/asm-m68k/byteorder.h Mon Jun 16 16:36:00 1997 +++ linux/include/asm-m68k/byteorder.h Wed Dec 3 06:18:17 1997 @@ -1,137 +1,24 @@ #ifndef _M68K_BYTEORDER_H #define _M68K_BYTEORDER_H -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#endif - -#ifndef __BIG_ENDIAN_BITFIELD -#define __BIG_ENDIAN_BITFIELD -#endif - -#ifdef __KERNEL__ #include -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ +#ifdef __GNUC__ -extern __inline__ __u16 __swab16 (__u16 val) +static __inline__ __const__ __u32 ___arch__swab32(__u32 val) { - return (val << 8) | (val >> 8); -} - -extern __inline__ __u32 __constant_swab32 (__u32 val) -{ - return (val << 24) | ((val << 8) & 0xff0000) | - ((val >> 8) & 0xff00) | (val >> 24); -} - -extern __inline__ __u32 __swab32 (__u32 val) -{ - __asm__ ("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val)); + __asm__("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val)); return val; } - -/* Convert from CPU byte order, to specified byte order. */ -#define cpu_to_le16(__val) __swab16(__val) -#define cpu_to_le32(__val) \ -(__builtin_constant_p(__val) ? __constant_swab32(__val) : __swab32(__val)) -#define cpu_to_be16(x) (x) -#define cpu_to_be32(x) (x) - -/* The same, but returns converted value from the location pointer by addr. */ -extern __inline__ __u16 cpu_to_le16p(__u16 *addr) -{ - return cpu_to_le16(*addr); -} - -extern __inline__ __u32 cpu_to_le32p(__u32 *addr) -{ - return cpu_to_le32(*addr); -} - -extern __inline__ __u16 cpu_to_be16p(__u16 *addr) -{ - return cpu_to_be16(*addr); -} - -extern __inline__ __u32 cpu_to_be32p(__u32 *addr) -{ - return cpu_to_be32(*addr); -} - -/* The same, but do the conversion in situ, ie. put the value back to addr. */ -extern __inline__ void cpu_to_le16s(__u16 *addr) -{ - *addr = cpu_to_le16(*addr); -} - -extern __inline__ void cpu_to_le32s(__u32 *addr) -{ - *addr = cpu_to_le32(*addr); -} - -#define cpu_to_be16s(x) do { } while (0) -#define cpu_to_be32s(x) do { } while (0) - -/* Convert from specified byte order, to CPU byte order. */ -#define le16_to_cpu(x) cpu_to_le16(x) -#define le32_to_cpu(x) cpu_to_le32(x) -#define be16_to_cpu(x) cpu_to_be16(x) -#define be32_to_cpu(x) cpu_to_be32(x) - -#define le16_to_cpup(x) cpu_to_le16p(x) -#define le32_to_cpup(x) cpu_to_le32p(x) -#define be16_to_cpup(x) cpu_to_be16p(x) -#define be32_to_cpup(x) cpu_to_be32p(x) - -#define le16_to_cpus(x) cpu_to_le16s(x) -#define le32_to_cpus(x) cpu_to_le32s(x) -#define be16_to_cpus(x) cpu_to_be16s(x) -#define be32_to_cpus(x) cpu_to_be32s(x) +#define __arch__swab32(x) ___arch__swab32(x) #endif -#undef ntohl -#undef ntohs -#undef htonl -#undef htons - -extern unsigned long int ntohl(unsigned long int); -extern unsigned short int ntohs(unsigned short int); -extern unsigned long int htonl(unsigned long int); -extern unsigned short int htons(unsigned short int); - -extern __inline__ unsigned long int __ntohl(unsigned long int); -extern __inline__ unsigned short int __ntohs(unsigned short int); - -extern __inline__ unsigned long int -__ntohl(unsigned long int x) -{ - return x; -} - -extern __inline__ unsigned short int -__ntohs(unsigned short int x) -{ - return x; -} - -#define __htonl(x) __ntohl(x) -#define __htons(x) __ntohs(x) - -#define __constant_htonl(x) (x) -#define __constant_htons(x) (x) -#define __constant_ntohl(x) (x) -#define __constant_ntohs(x) (x) - -#ifdef __OPTIMIZE__ -#define ntohl(x) __ntohl(x) -#define ntohs(x) __ntohs(x) -#define htonl(x) __htonl(x) -#define htons(x) __htons(x) +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ #endif -#endif +#include + +#endif /* _M68K_BYTEORDER_H */ diff -u --recursive --new-file v2.1.70/linux/include/asm-m68k/ioctls.h linux/include/asm-m68k/ioctls.h --- v2.1.70/linux/include/asm-m68k/ioctls.h Thu Jun 26 12:33:39 1997 +++ linux/include/asm-m68k/ioctls.h Thu Dec 4 13:09:01 1997 @@ -46,6 +46,7 @@ #define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff -u --recursive --new-file v2.1.70/linux/include/asm-mips/byteorder.h linux/include/asm-mips/byteorder.h --- v2.1.70/linux/include/asm-mips/byteorder.h Mon Aug 4 16:25:39 1997 +++ linux/include/asm-mips/byteorder.h Wed Dec 3 06:18:17 1997 @@ -1,175 +1,14 @@ -/* - * Functions depending of the byteorder. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1995, 1996, 1997 by Ralf Baechle - * - * $Id: byteorder.h,v 1.6 1997/07/20 15:15:01 ralf Exp $ - */ -#ifndef __ASM_MIPS_BYTEORDER_H -#define __ASM_MIPS_BYTEORDER_H +#ifndef _MIPS_BYTEORDER_H +#define _MIPS_BYTEORDER_H -#define __swap32(x) \ - ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ - (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ - (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ - (((unsigned long int)(x) & 0xff000000U) >> 24))) -#define __swap16(x) \ - ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ - (((unsigned short int)(x) & 0xff00) >> 8))) +#include #if defined (__MIPSEB__) - -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#endif - -#ifndef __BIG_ENDIAN_BITFIELD -#define __BIG_ENDIAN_BITFIELD -#endif - -#define __constant_ntohl(x) (x) -#define __constant_ntohs(x) (x) -#define __constant_htonl(x) (x) -#define __constant_htons(x) (x) - -#elif defined (__MIPSEL__) - -#ifndef __LITTLE_ENDIAN -#define __LITTLE_ENDIAN 1234 -#endif - -#ifndef __LITTLE_ENDIAN_BITFIELD -#define __LITTLE_ENDIAN_BITFIELD -#endif - -#define __constant_ntohl(x) __swap32(x) -#define __constant_ntohs(x) __swap16(x) -#define __constant_htonl(x) __swap32(x) -#define __constant_htons(x) __swap16(x) - -#endif /* defined(__MIPSEL_) */ - -#ifdef __KERNEL__ - -#if defined (__MIPSEB__) - -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ -#define cpu_to_le32(x) __swap32((x)) -#define le32_to_cpu(x) __swap32((x)) -#define cpu_to_le16(x) __swap16((x)) -#define le16_to_cpu(x) __swap16((x)) - -#define cpu_to_be32(x) (x) -#define be32_to_cpu(x) (x) -#define cpu_to_be16(x) (x) -#define be16_to_cpu(x) (x) - +# include #elif defined (__MIPSEL__) - -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ -#define cpu_to_le32(x) (x) -#define le32_to_cpu(x) (x) -#define cpu_to_le16(x) (x) -#define le16_to_cpu(x) (x) - -#define cpu_to_be32(x) __swap32((x)) -#define be32_to_cpu(x) __swap32((x)) -#define cpu_to_be16(x) __swap16((x)) -#define be16_to_cpu(x) __swap16((x)) - +# include #else -#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" +# error What's that? MIPS, but neither MIPSEB, nor MIPSEL??? #endif -/* The same, but returns converted value from the location pointer by addr. */ -extern __inline__ __u16 cpu_to_le16p(__u16 *addr) -{ - return cpu_to_le16(*addr); -} - -extern __inline__ __u32 cpu_to_le32p(__u32 *addr) -{ - return cpu_to_le32(*addr); -} - -extern __inline__ __u16 cpu_to_be16p(__u16 *addr) -{ - return cpu_to_be16(*addr); -} - -extern __inline__ __u32 cpu_to_be32p(__u32 *addr) -{ - return cpu_to_be32(*addr); -} - -#define le16_to_cpup(x) cpu_to_le16p(x) -#define le32_to_cpup(x) cpu_to_le32p(x) -#define be16_to_cpup(x) cpu_to_be16p(x) -#define be32_to_cpup(x) cpu_to_be32p(x) - - -/* The same, but do the conversion in situ, ie. put the value back to addr. */ -extern __inline__ void cpu_to_le16s(__u16 *addr) -{ - *addr = cpu_to_le16(*addr); -} - -extern __inline__ void cpu_to_le32s(__u32 *addr) -{ - *addr = cpu_to_le32(*addr); -} - -extern __inline__ void cpu_to_be16s(__u16 *addr) -{ - *addr = cpu_to_be16(*addr); -} - -extern __inline__ void cpu_to_be32s(__u32 *addr) -{ - *addr = cpu_to_be32(*addr); -} - -#define le16_to_cpus(x) cpu_to_le16s(x) -#define le32_to_cpus(x) cpu_to_le32s(x) -#define be16_to_cpus(x) cpu_to_be16s(x) -#define be32_to_cpus(x) cpu_to_be32s(x) - -#endif /* __KERNEL__ */ - -extern unsigned long int ntohl(unsigned long int __x); -extern unsigned short int ntohs(unsigned short int __x); -extern unsigned short int htons(unsigned short int __x); -extern unsigned long int htonl(unsigned long int __x); - - -extern __inline__ unsigned long int ntohl(unsigned long int __x) -{ - return __constant_ntohl(__x); -} - -extern __inline__ unsigned short int ntohs(unsigned short int __x) -{ - return __constant_ntohs(__x); -} - -extern __inline__ unsigned long int htonl(unsigned long int __x) -{ - return __constant_htonl(__x); -} - -extern __inline__ unsigned short int htons(unsigned short int __x) -{ - return __constant_htons(__x); -} - -#endif /* __ASM_MIPS_BYTEORDER_H */ +#endif /* _MIPS_BYTEORDER_H */ diff -u --recursive --new-file v2.1.70/linux/include/asm-mips/ioctls.h linux/include/asm-mips/ioctls.h --- v2.1.70/linux/include/asm-mips/ioctls.h Mon Aug 4 16:25:39 1997 +++ linux/include/asm-mips/ioctls.h Thu Dec 4 13:09:01 1997 @@ -98,6 +98,7 @@ #define TIOCTTYGSTRUCT 0x5487 /* For debugging only */ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCSERCONFIG 0x5488 #define TIOCSERGWILD 0x5489 diff -u --recursive --new-file v2.1.70/linux/include/asm-ppc/byteorder.h linux/include/asm-ppc/byteorder.h --- v2.1.70/linux/include/asm-ppc/byteorder.h Mon Aug 18 18:19:46 1997 +++ linux/include/asm-ppc/byteorder.h Wed Dec 3 06:18:17 1997 @@ -3,31 +3,8 @@ #include -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#endif - -#ifndef __BIG_ENDIAN_BITFIELD -#define __BIG_ENDIAN_BITFIELD -#endif - -#define ntohl(x) ((unsigned long)(x)) -#define ntohs(x) ((unsigned short)(x)) -#define htonl(x) ((unsigned long)(x)) -#define htons(x) ((unsigned short)(x)) - -#define __htonl(x) ntohl(x) -#define __htons(x) ntohs(x) - -#define __constant_ntohs(x) ntohs(x) -#define __constant_ntohl(x) ntohl(x) -#define __constant_htonl(x) ntohl(x) -#define __constant_htons(x) ntohs(x) - -#ifdef __KERNEL__ -/* - * 16 and 32 bit little-endian loads and stores. - */ +#ifdef __GNUC__ + extern inline unsigned ld_le16(volatile unsigned short *addr) { unsigned val; @@ -55,16 +32,10 @@ } #if 0 -extern __inline__ __u16 cpu_to_le16(__u16 value) -{ - return ld_le16(&value); -} -extern __inline__ __u32 cpu_to_le32(__u32 value) -{ - return ld_le32(&value); -} +# define __arch_swab16(x) ld_le16(&x) +# define __arch_swab32(x) ld_le32(&x) #else -extern __inline__ __u16 cpu_to_le16(__u16 value) +static __inline__ __const__ __u16 ___arch__swab16(__u16 value) { __u16 result; @@ -73,7 +44,8 @@ : "r" (value), "0" (value >> 8)); return result; } -extern __inline__ __u32 cpu_to_le32(__u32 value) + +static __inline__ __const__ __u32 ___arch__swab32(__u32 value) { __u32 result; @@ -84,68 +56,20 @@ : "r" (value), "0" (value >> 24)); return result; } +#define __arch__swab32(x) ___arch__swab32(x) +#define __arch__swab16(x) ___arch__swab16(x) #endif /* 0 */ -#define cpu_to_be16(x) (x) -#define cpu_to_be32(x) (x) - /* The same, but returns converted value from the location pointer by addr. */ -extern __inline__ __u16 cpu_to_le16p(__u16 *addr) -{ - return ld_le16(addr); -} - -extern __inline__ __u32 cpu_to_le32p(__u32 *addr) -{ - return ld_le32(addr); -} - -extern __inline__ __u16 cpu_to_be16p(__u16 *addr) -{ - return *addr; -} - -extern __inline__ __u32 cpu_to_be32p(__u32 *addr) -{ - return *addr; -} +#define __arch_swab16p(addr) ld_le16(addr) +#define __arch_swab32p(addr) ld_le32(addr) /* The same, but do the conversion in situ, ie. put the value back to addr. */ -extern __inline__ void cpu_to_le16s(__u16 *addr) -{ - st_le16(addr,*addr); -} - -extern __inline__ void cpu_to_le32s(__u32 *addr) -{ - st_le32(addr,*addr); -} - -#define cpu_to_be16s(x) do { } while (0) -#define cpu_to_be32s(x) do { } while (0) - -/* Convert from specified byte order, to CPU byte order. */ -#define le16_to_cpu(x) cpu_to_le16(x) -#define le32_to_cpu(x) cpu_to_le32(x) -#define be16_to_cpu(x) cpu_to_be16(x) -#define be32_to_cpu(x) cpu_to_be32(x) - -#define le16_to_cpup(x) cpu_to_le16p(x) -#define le32_to_cpup(x) cpu_to_le32p(x) -#define be16_to_cpup(x) cpu_to_be16p(x) -#define be32_to_cpup(x) cpu_to_be32p(x) - -#define le16_to_cpus(x) cpu_to_le16s(x) -#define le32_to_cpus(x) cpu_to_le32s(x) -#define be16_to_cpus(x) cpu_to_be16s(x) -#define be32_to_cpus(x) cpu_to_be32s(x) - - -#endif /* __KERNEL__ */ -#endif /* !(_PPC_BYTEORDER_H) */ - - - +#define __arch_swab16s(addr) st_le16(addr,*addr) +#define __arch_swab32s(addr) st_le32(addr,*addr) +#endif /* __GNUC__ */ +#include +#endif /* _PPC_BYTEORDER_H */ diff -u --recursive --new-file v2.1.70/linux/include/asm-ppc/ioctls.h linux/include/asm-ppc/ioctls.h --- v2.1.70/linux/include/asm-ppc/ioctls.h Mon Aug 18 18:19:47 1997 +++ linux/include/asm-ppc/ioctls.h Thu Dec 4 13:09:01 1997 @@ -85,6 +85,7 @@ #define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff -u --recursive --new-file v2.1.70/linux/include/asm-sparc/byteorder.h linux/include/asm-sparc/byteorder.h --- v2.1.70/linux/include/asm-sparc/byteorder.h Mon Jun 16 16:36:00 1997 +++ linux/include/asm-sparc/byteorder.h Wed Dec 3 06:18:17 1997 @@ -1,93 +1,13 @@ -/* $Id: byteorder.h,v 1.14 1997/05/28 11:35:38 jj Exp $ */ #ifndef _SPARC_BYTEORDER_H #define _SPARC_BYTEORDER_H -#define ntohl(x) ((unsigned long int)(x)) -#define ntohs(x) ((unsigned short int)(x)) -#define htonl(x) ((unsigned long int)(x)) -#define htons(x) ((unsigned short int)(x)) +#include -/* Some programs depend upon these being around. */ -#define __constant_ntohl(x) ((unsigned long int)(x)) -#define __constant_ntohs(x) ((unsigned short int)(x)) -#define __constant_htonl(x) ((unsigned long int)(x)) -#define __constant_htons(x) ((unsigned short int)(x)) - -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#endif - -#ifndef __BIG_ENDIAN_BITFIELD -#define __BIG_ENDIAN_BITFIELD +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ #endif -#ifdef __KERNEL__ - -/* Convert from CPU byte order, to specified byte order. */ -extern __inline__ __u16 cpu_to_le16(__u16 value) -{ - return (value >> 8) | (value << 8); -} - -extern __inline__ __u32 cpu_to_le32(__u32 value) -{ - return((value>>24) | ((value>>8)&0xff00) | - ((value<<8)&0xff0000) | (value<<24)); -} -#define cpu_to_be16(x) (x) -#define cpu_to_be32(x) (x) - -/* The same, but returns converted value from the location pointer by addr. */ -extern __inline__ __u16 cpu_to_le16p(__u16 *addr) -{ - return cpu_to_le16(*addr); -} - -extern __inline__ __u32 cpu_to_le32p(__u32 *addr) -{ - return cpu_to_le32(*addr); -} - -extern __inline__ __u16 cpu_to_be16p(__u16 *addr) -{ - return cpu_to_be16(*addr); -} - -extern __inline__ __u32 cpu_to_be32p(__u32 *addr) -{ - return cpu_to_be32(*addr); -} - -/* The same, but do the conversion in situ, ie. put the value back to addr. */ -extern __inline__ void cpu_to_le16s(__u16 *addr) -{ - *addr = cpu_to_le16(*addr); -} - -extern __inline__ void cpu_to_le32s(__u32 *addr) -{ - *addr = cpu_to_le32(*addr); -} - -#define cpu_to_be16s(x) do { } while (0) -#define cpu_to_be32s(x) do { } while (0) - -/* Convert from specified byte order, to CPU byte order. */ -#define le16_to_cpu(x) cpu_to_le16(x) -#define le32_to_cpu(x) cpu_to_le32(x) -#define be16_to_cpu(x) cpu_to_be16(x) -#define be32_to_cpu(x) cpu_to_be32(x) - -#define le16_to_cpup(x) cpu_to_le16p(x) -#define le32_to_cpup(x) cpu_to_le32p(x) -#define be16_to_cpup(x) cpu_to_be16p(x) -#define be32_to_cpup(x) cpu_to_be32p(x) - -#define le16_to_cpus(x) cpu_to_le16s(x) -#define le32_to_cpus(x) cpu_to_le32s(x) -#define be16_to_cpus(x) cpu_to_be16s(x) -#define be32_to_cpus(x) cpu_to_be32s(x) - -#endif /* __KERNEL__ */ +#include -#endif /* !(_SPARC_BYTEORDER_H) */ +#endif /* _SPARC_BYTEORDER_H */ diff -u --recursive --new-file v2.1.70/linux/include/asm-sparc/ioctls.h linux/include/asm-sparc/ioctls.h --- v2.1.70/linux/include/asm-sparc/ioctls.h Mon Jul 7 08:18:55 1997 +++ linux/include/asm-sparc/ioctls.h Thu Dec 4 13:09:01 1997 @@ -74,6 +74,7 @@ #define TIOCSPGRP _IOW('t', 130, int) #define TIOCGPGRP _IOR('t', 131, int) #define TIOCSCTTY _IO('t', 132) +#define TIOCGSID _IOR('t', 133, int) /* Little f */ #define FIOCLEX _IO('f', 1) diff -u --recursive --new-file v2.1.70/linux/include/asm-sparc64/byteorder.h linux/include/asm-sparc64/byteorder.h --- v2.1.70/linux/include/asm-sparc64/byteorder.h Thu Jun 26 12:33:40 1997 +++ linux/include/asm-sparc64/byteorder.h Wed Dec 3 06:18:17 1997 @@ -1,129 +1,46 @@ -/* $Id: byteorder.h,v 1.6 1997/06/14 17:35:07 davem Exp $ */ #ifndef _SPARC64_BYTEORDER_H #define _SPARC64_BYTEORDER_H +#include #include -#define ntohl(x) ((unsigned long int)(x)) -#define ntohs(x) ((unsigned short int)(x)) -#define htonl(x) ((unsigned long int)(x)) -#define htons(x) ((unsigned short int)(x)) - -/* Some programs depend upon these being around. */ -#define __constant_ntohl(x) ((unsigned long int)(x)) -#define __constant_ntohs(x) ((unsigned short int)(x)) -#define __constant_htonl(x) ((unsigned long int)(x)) -#define __constant_htons(x) ((unsigned short int)(x)) - -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#endif - -#ifndef __BIG_ENDIAN_BITFIELD -#define __BIG_ENDIAN_BITFIELD -#endif +#ifdef __GNUC__ -#ifdef __KERNEL__ - -/* Convert from CPU byte order, to specified byte order. */ -extern __inline__ __u16 cpu_to_le16(__u16 value) -{ - return (value >> 8) | (value << 8); -} - -extern __inline__ __u32 cpu_to_le32(__u32 value) -{ - return((value>>24) | ((value>>8)&0xff00) | - ((value<<8)&0xff0000) | (value<<24)); -} - -extern __inline__ __u64 cpu_to_le64(__u64 value) -{ - return (((value>>56) & 0x00000000000000ffUL) | - ((value>>40) & 0x000000000000ff00UL) | - ((value>>24) & 0x0000000000ff0000UL) | - ((value>>8) & 0x00000000ff000000UL) | - ((value<<8) & 0x000000ff00000000UL) | - ((value<<24) & 0x0000ff0000000000UL) | - ((value<<40) & 0x00ff000000000000UL) | - ((value<<56) & 0xff00000000000000UL)); -} -#define cpu_to_be16(x) (x) -#define cpu_to_be32(x) (x) -#define cpu_to_be64(x) (x) - -/* The same, but returns converted value from the location pointer by addr. */ -extern __inline__ __u16 cpu_to_le16p(__u16 *addr) +static __inline__ __u16 ___arch__swab16p(__u16 *addr) { __u16 ret; + __asm__ __volatile__ ("lduha [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL)); return ret; } -extern __inline__ __u32 cpu_to_le32p(__u32 *addr) +static __inline__ __u32 ___arch__swab32p(__u32 *addr) { __u32 ret; + __asm__ __volatile__ ("lduwa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL)); return ret; } -extern __inline__ __u64 cpu_to_le64p(__u64 *addr) -{ +static __inline__ __u64 ___arch__swab64p(__u64 *addr) { __u64 ret; + __asm__ __volatile__ ("ldxa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL)); return ret; } -extern __inline__ __u16 cpu_to_be16p(__u16 *addr) { return *addr; } -extern __inline__ __u32 cpu_to_be32p(__u32 *addr) { return *addr; } -extern __inline__ __u64 cpu_to_be64p(__u64 *addr) { return *addr; } - -/* The same, but do the conversion in situ, ie. put the value back to addr. */ -extern __inline__ void cpu_to_le16s(__u16 *addr) -{ - *addr = cpu_to_le16p(addr); -} -extern __inline__ void cpu_to_le32s(__u32 *addr) -{ - *addr = cpu_to_le32p(addr); -} +#define __arch__swab16p(x) ___arch__swab16p(x) +#define __arch__swab32p(x) ___arch__swab32p(x) +#define __arch__swab64p(x) ___arch__swab64p(x) -extern __inline__ void cpu_to_le64s(__u64 *addr) -{ - *addr = cpu_to_le64p(addr); -} -#define cpu_to_be16s(x) do { } while (0) -#define cpu_to_be32s(x) do { } while (0) -#define cpu_to_be64s(x) do { } while (0) - -/* Convert from specified byte order, to CPU byte order. */ -#define le16_to_cpu(x) cpu_to_le16(x) -#define le32_to_cpu(x) cpu_to_le32(x) -#define le64_to_cpu(x) cpu_to_le64(x) -#define be16_to_cpu(x) cpu_to_be16(x) -#define be32_to_cpu(x) cpu_to_be32(x) -#define be64_to_cpu(x) cpu_to_be64(x) - -#define le16_to_cpup(x) cpu_to_le16p(x) -#define le32_to_cpup(x) cpu_to_le32p(x) -#define le64_to_cpup(x) cpu_to_le64p(x) -#define be16_to_cpup(x) cpu_to_be16p(x) -#define be32_to_cpup(x) cpu_to_be32p(x) -#define be64_to_cpup(x) cpu_to_be64p(x) - -#define le16_to_cpus(x) cpu_to_le16s(x) -#define le32_to_cpus(x) cpu_to_le32s(x) -#define le64_to_cpus(x) cpu_to_le64s(x) -#define be16_to_cpus(x) cpu_to_be16s(x) -#define be32_to_cpus(x) cpu_to_be32s(x) -#define be64_to_cpus(x) cpu_to_be64s(x) +#define __BYTEORDER_HAS_U64__ -#endif /* __KERNEL__ */ +#include -#endif /* !(_SPARC64_BYTEORDER_H) */ +#endif /* _SPARC64_BYTEORDER_H */ diff -u --recursive --new-file v2.1.70/linux/include/asm-sparc64/ioctls.h linux/include/asm-sparc64/ioctls.h --- v2.1.70/linux/include/asm-sparc64/ioctls.h Mon Aug 18 18:19:47 1997 +++ linux/include/asm-sparc64/ioctls.h Thu Dec 4 13:09:01 1997 @@ -75,6 +75,7 @@ #define TIOCSPGRP _IOW('t', 130, int) #define TIOCGPGRP _IOR('t', 131, int) #define TIOCSCTTY _IO('t', 132) +#define TIOCGSID _IOR('t', 133, int) /* Little f */ #define FIOCLEX _IO('f', 1) diff -u --recursive --new-file v2.1.70/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h --- v2.1.70/linux/include/linux/affs_fs.h Mon Jun 16 16:36:00 1997 +++ linux/include/linux/affs_fs.h Tue Dec 2 22:25:07 1997 @@ -27,23 +27,26 @@ u32 ds_Tick; }; - /* --- Prototypes ----------------------------------------------------------------------------- */ /* amigaffs.c */ extern int affs_get_key_entry(int bsize, void *data, int entry_pos); -extern int affs_get_file_name(int bsize, void *fh_data, char **name); +extern int affs_get_file_name(int bsize, void *fh_data, unsigned char **name); extern u32 affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype); extern void affs_fix_checksum(int bsize, void *data, int cspos); extern void secs_to_datestamp(time_t secs, struct DateStamp *ds); extern int prot_to_mode(unsigned int prot); extern u32 mode_to_prot(int mode); -extern int affs_fix_hash_pred(struct inode *startino, int startoffset, - s32 key, s32 newkey); -extern int affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey); +extern int affs_insert_hash(unsigned long dir_ino, struct buffer_head *header, + struct inode *inode); +extern int affs_remove_hash(struct buffer_head *bh, struct inode *inode); +extern int affs_remove_link(struct buffer_head *bh, struct inode *inode); +extern int affs_remove_header(struct buffer_head *bh, struct inode *inode); extern void affs_error(struct super_block *sb, const char *function, const char *fmt, ...); extern void affs_warning(struct super_block *sb, const char *function, const char *fmt, ...); +extern int affs_check_name(const unsigned char *name, int len); +extern int affs_copy_name(unsigned char *bstr, const unsigned char *name); /* bitmap. c */ @@ -56,39 +59,44 @@ /* namei.c */ -extern int affs_hash_name(const char *name, int len, int intl, int hashsize); -extern int affs_lookup(struct inode *dir,const char *name, int len, - struct inode **result); -extern int affs_unlink(struct inode *dir, const char *name, int len); -extern int affs_create(struct inode *dir, const char *name, int len, int mode, - struct inode **result); -extern int affs_mkdir(struct inode *dir, const char *name, int len, int mode); -extern int affs_rmdir(struct inode *dir, const char *name, int len); +extern int affs_hash_name(const unsigned char *name, int len, int intl, int hashsize); +extern int affs_lookup(struct inode *dir, struct dentry *dentry); +extern int affs_unlink(struct inode *dir, struct dentry *dentry); +extern int affs_create(struct inode *dir, struct dentry *dentry, int mode); +extern int affs_mkdir(struct inode *dir, struct dentry *dentry, int mode); +extern int affs_rmdir(struct inode *dir, struct dentry *dentry); extern int affs_link(struct inode *oldinode, struct inode *dir, - const char *name, int len); -extern int affs_symlink(struct inode *dir, const char *name, int len, - const char *symname); -extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len); + struct dentry *dentry); +extern int affs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname); +extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); /* inode.c */ -extern struct buffer_head *affs_bread(kdev_t dev, int block, int size); -extern void affs_brelse(struct buffer_head *buf); -extern unsigned long affs_parent_ino(struct inode *dir); -extern struct inode *affs_new_inode(const struct inode *dir); -extern int affs_add_entry(struct inode *dir, struct inode *link, - struct inode *inode, const char *name, - int len, s32 type); +extern struct buffer_head *affs_bread(kdev_t dev, int block, int size); +extern void affs_brelse(struct buffer_head *buf); +extern unsigned long affs_parent_ino(struct inode *dir); +extern struct inode *affs_new_inode(const struct inode *dir); +extern int affs_notify_change(struct inode *inode, struct iattr *attr); +extern int affs_add_entry(struct inode *dir, struct inode *link, + struct inode *inode, struct dentry *dentry, s32 type); +extern void affs_put_inode(struct inode *inode); +extern void affs_delete_inode(struct inode *inode); +extern void affs_read_inode(struct inode *inode); +extern void affs_write_inode(struct inode *inode); + +/* super.c */ + +extern int affs_fs(void); /* file.c */ -extern void affs_truncate(struct inode *); -extern void affs_truncate_ofs(struct inode *); +extern void affs_truncate(struct inode *); /* dir.c */ -extern void affs_dir_truncate(struct inode *); +extern void affs_dir_truncate(struct inode *); /* jump tables */ @@ -99,5 +107,4 @@ extern struct inode_operations affs_chrdev_inode_operations; extern struct inode_operations affs_blkdev_inode_operations; -extern int init_affs_fs(void); #endif diff -u --recursive --new-file v2.1.70/linux/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h --- v2.1.70/linux/include/linux/affs_fs_sb.h Tue May 13 22:41:18 1997 +++ linux/include/linux/affs_fs_sb.h Tue Dec 2 22:25:07 1997 @@ -68,5 +68,6 @@ #define SF_OFS 0x0200 /* Old filesystem */ #define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */ #define SF_VERBOSE 0x0800 /* Talk about fs when mounting */ +#define SF_READONLY 0x1000 /* Don't allow to remount rw */ #endif diff -u --recursive --new-file v2.1.70/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h --- v2.1.70/linux/include/linux/amigaffs.h Tue May 13 22:41:18 1997 +++ linux/include/linux/amigaffs.h Tue Dec 2 22:25:07 1997 @@ -4,10 +4,18 @@ #include #include +/* AmigaOS allows file names with up to 30 characters length. + * Names longer than that will be silently truncated. If you + * want to disallow this, comment out the following #define. + * Creating filesystem objects with longer names will then + * result in an error (ENAMETOOLONG). + */ +/*#define AFFS_NO_TRUNCATE */ + /* Ugly macros make the code more pretty. */ #define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st)))) -#define AFFS_GET_HASHENTRY(data,hashkey) htonl(((struct dir_front *)data)->hashtable[hashkey]) +#define AFFS_GET_HASHENTRY(data,hashkey) be32_to_cpu(((struct dir_front *)data)->hashtable[hashkey]) #define AFFS_BLOCK(data,ino,blk) ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-(blk)] #define FILE_END(p,i) GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i)) @@ -16,6 +24,7 @@ #define LINK_END(p,i) GET_END_PTR(struct hlink_end,p,AFFS_I2BSIZE(i)) #define ROOT_END_S(p,s) GET_END_PTR(struct root_end,p,(s)->s_blocksize) #define DATA_FRONT(bh) ((struct data_front *)(bh)->b_data) +#define DIR_FRONT(bh) ((struct dir_front *)(bh)->b_data) /* Only for easier debugging if need be */ #define affs_bread bread @@ -206,14 +215,14 @@ #define AFFS_UMAYWRITE(prot) (((prot) & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE)) #define AFFS_UMAYREAD(prot) ((prot) & FIBF_READ) -#define AFFS_UMAYEXECUTE(prot) (((prot) & (FIBF_SCRIPT|FIBF_READ)) == (FIBF_SCRIPT|FIBF_READ)) +#define AFFS_UMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE) #define AFFS_GMAYWRITE(prot) (((prot)&(FIBF_GRP_WRITE|FIBF_GRP_DELETE))==\ (FIBF_GRP_WRITE|FIBF_GRP_DELETE)) #define AFFS_GMAYREAD(prot) ((prot) & FIBF_GRP_READ) -#define AFFS_GMAYEXECUTE(prot) (((prot)&(FIBF_SCRIPT|FIBF_GRP_READ))==(FIBF_SCRIPT|FIBF_GRP_READ)) +#define AFFS_GMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE) #define AFFS_OMAYWRITE(prot) (((prot)&(FIBF_OTR_WRITE|FIBF_OTR_DELETE))==\ (FIBF_OTR_WRITE|FIBF_OTR_DELETE)) #define AFFS_OMAYREAD(prot) ((prot) & FIBF_OTR_READ) -#define AFFS_OMAYEXECUTE(prot) (((prot)&(FIBF_SCRIPT|FIBF_OTR_READ))==(FIBF_SCRIPT|FIBF_OTR_READ)) +#define AFFS_OMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE) #endif diff -u --recursive --new-file v2.1.70/linux/include/linux/byteorder_big_endian.h linux/include/linux/byteorder_big_endian.h --- v2.1.70/linux/include/linux/byteorder_big_endian.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/byteorder_big_endian.h Wed Dec 3 06:18:17 1997 @@ -0,0 +1,54 @@ +#ifndef _LINUX_BYTEORDER_BIG_ENDIAN_H +#define _LINUX_BYTEORDER_BIG_ENDIAN_H + +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN 4321 +#endif +#ifndef __BIG_ENDIAN_BITFIELD +#define __BIG_ENDIAN_BITFIELD +#endif + +#define __constant_htonl(x) ((__u32)(x)) +#define __constant_ntohl(x) ((__u32)(x)) +#define __constant_htons(x) ((__u16)(x)) +#define __constant_ntohs(x) ((__u16)(x)) +#define __cpu_to_le64(x) __swab64((x)) +#define __le64_to_cpu(x) __swab64((x)) +#define __cpu_to_le32(x) __swab32((x)) +#define __le32_to_cpu(x) __swab32((x)) +#define __cpu_to_le16(x) __swab16((x)) +#define __le16_to_cpu(x) __swab16((x)) +#define __cpu_to_be64(x) ((__u64)(x)) +#define __be64_to_cpu(x) ((__u64)(x)) +#define __cpu_to_be32(x) ((__u32)(x)) +#define __be32_to_cpu(x) ((__u32)(x)) +#define __cpu_to_be16(x) ((__u16)(x)) +#define __be16_to_cpu(x) ((__u16)(x)) +#define __cpu_to_le64p(x) __swab64p((x)) +#define __le64_to_cpup(x) __swab64p((x)) +#define __cpu_to_le32p(x) __swab32p((x)) +#define __le32_to_cpup(x) __swab32p((x)) +#define __cpu_to_le16p(x) __swab16p((x)) +#define __le16_to_cpup(x) __swab16p((x)) +#define __cpu_to_be64p(x) (*(__u64*)(x)) +#define __be64_to_cpup(x) (*(__u64*)(x)) +#define __cpu_to_be32p(x) (*(__u32*)(x)) +#define __be32_to_cpup(x) (*(__u32*)(x)) +#define __cpu_to_be16p(x) (*(__u16*)(x)) +#define __be16_to_cpup(x) (*(__u16*)(x)) +#define __cpu_to_le64s(x) __swab64s((x)) +#define __le64_to_cpus(x) __swab64s((x)) +#define __cpu_to_le32s(x) __swab32s((x)) +#define __le32_to_cpus(x) __swab32s((x)) +#define __cpu_to_le16s(x) __swab16s((x)) +#define __le16_to_cpus(x) __swab16s((x)) +#define __cpu_to_be64s(x) do {} while (0) +#define __be64_to_cpus(x) do {} while (0) +#define __cpu_to_be32s(x) do {} while (0) +#define __be32_to_cpus(x) do {} while (0) +#define __cpu_to_be16s(x) do {} while (0) +#define __be16_to_cpus(x) do {} while (0) + +#include + +#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_H */ diff -u --recursive --new-file v2.1.70/linux/include/linux/byteorder_generic.h linux/include/linux/byteorder_generic.h --- v2.1.70/linux/include/linux/byteorder_generic.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/byteorder_generic.h Wed Dec 3 17:13:31 1997 @@ -0,0 +1,298 @@ +#ifndef _LINUX_BYTEORDER_GENERIC_H +#define _LINUX_BYTEORDER_GENERIC_H + +/* + * linux/byteorder_generic.h + * Generic Byteswap support + * + * Francois-Rene Rideau 19970707 + * gathered all the good ideas from all asm-foo/byteorder.h into one file, + * cleaned them up. + * I hope it is compliant with non-GCC compilers. + * I decided to put __BYTEORDER_HAS_U64__ in byteorder.h, + * because I wasn't sure it would be ok to put it in types.h + * Upgraded it to 2.1.43 + * Francois-Rene Rideau 19971012 + * Upgraded it to 2.1.57 + * to please Linus T., replaced huge #ifdef's between little/big endian + * by nestedly #include'd files. + * + * TODO: + * = Regular kernel maintainers could also replace all these manual + * byteswap macros that remain, disseminated among drivers, + * after some grep or the sources... + * = Linus might want to rename all these macros and files to fit his taste, + * to fit his personal naming scheme. + * = it seems that many drivers would also appreciate + * nybble swapping support... + * = every architecture could add their byteswap macro in asm/byteorder.h + * see how some architectures already do (i386, alpha, ppc, etc) + */ + +/* + * This file is included by both and + * . People porting from machines with + * bizarre bytedisorder (like the VAX?) will have to write a different one. + * Actually, this file mostly does byteswapping, and could be named + * or rather than + * + */ + +/* + * The following macros are to be defined by : + * + * Conversion of long and short int between network and host format + * ntohl(__u32 x) + * ntohs(__u16 x) + * htonl(__u32 x) + * htons(__u16 x) + * It seems that some programs (which? where? or perhaps a standard? POSIX?) + * might like the above to be functions, not macros (why?). + * if that's true, then detect them, and take measures. + * Anyway, the measure is: define only ___ntohl as a macro instead, + * and in a separate file, have + * unsigned long inline ntohl(x){return ___ntohl(x);} + * + * The same for constant arguments + * __constant_ntohl(__u32 x) + * __constant_ntohs(__u16 x) + * __constant_htonl(__u32 x) + * __constant_htons(__u16 x) + * + * Conversion of XX-bit integers (16- 32- or 64-) + * between native cpu format and little/big endian format + * 64-bit stuff only defined for proper architectures + * cpu_to_[bl]eXX(__uXX x) + * [bl]eXX_to_cpu(__uXX x) + * + * The same, but takes a pointer to the value to convert + * cpu_to_[bl]eXXp(__uXX x) + * [bl]eXX_to_cpup(__uXX x) + * + * The same, but change in situ + * cpu_to_[bl]eXXs(__uXX x) + * [bl]eXX_to_cpus(__uXX x) + * + * Byteswapping, independently from cpu endianness + * swabXX[ps]?(foo) + * + * + * See asm-foo/byteorder.h for examples of how to provide + * architecture-optimized versions + * + */ + +#include + +/* + * Generic byte swapping routines. We fall back on + * these if we don't have any optimized code, and + * when we have constants that we want the compiler + * to byte swap for us.. + */ +#define ___swab16(x) \ + ((__u16)( \ + (((__u16)(x) & 0x00ffU) << 8) | \ + (((__u16)(x) & 0xff00U) >> 8) )) +#define ___swab32(x) \ + ((__u32)( \ + (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ + (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ + (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ + (((__u32)(x) & (__u32)0xff000000UL) >> 24) )) +#define ___swab64(x) \ + ((__u64)( \ + (__u64)(((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \ + (__u64)(((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \ + (__u64)(((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \ + (__u64)(((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) | \ + (__u64)(((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) | \ + (__u64)(((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ + (__u64)(((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \ + (__u64)(((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56) )) + +/* + * These do constant folding - this allows the + * compiler to do any constants at compile + * time. Any architecture inline asm optimizations + * would be pessimizations. + */ +#define __swab16(x) \ + (__builtin_constant_p((__u16)(x)) ? \ + ___swab16((x)) : __fswab16((x))) +#define __swab32(x) \ + (__builtin_constant_p((__u32)(x)) ? \ + ___swab32((x)) : __fswab32((x))) +#define __swab64(x) \ + (__builtin_constant_p((__u64)(x)) ? \ + ___swab64((x)) : __fswab64((x))) + + +/* + * provide defaults when no architecture-specific optimization is detected + */ +#ifndef __arch__swab16 +# define __arch__swab16(x) ___swab16(x) +#endif +#ifndef __arch__swab32 +# define __arch__swab32(x) ___swab32(x) +#endif +#ifndef __arch__swab64 +# define __arch__swab64(x) ___swab64(x) +#endif + +#ifndef __arch__swab16p +# define __arch__swab16p(x) __swab16(*(x)) +#endif +#ifndef __arch__swab32p +# define __arch__swab32p(x) __swab32(*(x)) +#endif +#ifndef __arch__swab64p +# define __arch__swab64p(x) __swab64(*(x)) +#endif + +#ifndef __arch__swab16s +# define __arch__swab16s(x) *(x) = __swab16p((x)) +#endif +#ifndef __arch__swab32s +# define __arch__swab32s(x) *(x) = __swab32p((x)) +#endif +#ifndef __arch__swab64s +# define __arch__swab64s(x) *(x) = __swab64p((x)) +#endif + + +extern __inline__ __const__ __u16 __fswab16(__u16 x) +{ + return __arch__swab16(x); +} +extern __inline__ __u16 __swab16p(__u16 *x) +{ + return __arch__swab16p(x); +} +extern __inline__ void __swab16s(__u16 *addr) +{ + __arch__swab16s(addr); +} + +extern __inline__ __const__ __u32 __fswab32(__u32 x) +{ + return __arch__swab32(x); +} +extern __inline__ __u32 __swab32p(__u32 *x) +{ + return __arch__swab32p(x); +} +extern __inline__ void __swab32s(__u32 *addr) +{ + __arch__swab32s(addr); +} + +#ifdef __BYTEORDER_HAS_U64__ +extern __inline__ __const__ __u64 __fswab64(__u64 x) +{ +# ifdef __SWAB_64_THRU_32__ + __u32 h = x >> 32; + __u32 l = x & ((1ULL<<32)-1); + return (((__u64)__swab32(l)) << 32) | ((__u64)(__swab32(h))); +# else + return __arch__swab64(x); +# endif +} +extern __inline__ __u64 __swab64p(__u64 *x) +{ + return __arch__swab64p(x); +} +extern __inline__ void __swab64s(__u64 *addr) +{ + __arch__swab64s(addr); +} +#endif /* __BYTEORDER_HAS_U64__ */ + +#if defined(__KERNEL__) || defined(__REQUIRE_CPU_TO_XX) +#define swab16 __swab16 +#define swab32 __swab32 +#define swab64 __swab64 +#define swab16p __swab16p +#define swab32p __swab32p +#define swab64p __swab64p +#define swab16s __swab16s +#define swab32s __swab32s +#define swab64s __swab64s +#define cpu_to_le64 __cpu_to_le64 +#define le64_to_cpu __le64_to_cpu +#define cpu_to_le32 __cpu_to_le32 +#define le32_to_cpu __le32_to_cpu +#define cpu_to_le16 __cpu_to_le16 +#define le16_to_cpu __le16_to_cpu +#define cpu_to_be64 __cpu_to_be64 +#define be64_to_cpu __be64_to_cpu +#define cpu_to_be32 __cpu_to_be32 +#define be32_to_cpu __be32_to_cpu +#define cpu_to_be16 __cpu_to_be16 +#define be16_to_cpu __be16_to_cpu +#define cpu_to_le64p __cpu_to_le64p +#define le64_to_cpup __le64_to_cpup +#define cpu_to_le32p __cpu_to_le32p +#define le32_to_cpup __le32_to_cpup +#define cpu_to_le16p __cpu_to_le16p +#define le16_to_cpup __le16_to_cpup +#define cpu_to_be64p __cpu_to_be64p +#define be64_to_cpup __be64_to_cpup +#define cpu_to_be32p __cpu_to_be32p +#define be32_to_cpup __be32_to_cpup +#define cpu_to_be16p __cpu_to_be16p +#define be16_to_cpup __be16_to_cpup +#define cpu_to_le64s __cpu_to_le64s +#define le64_to_cpus __le64_to_cpus +#define cpu_to_le32s __cpu_to_le32s +#define le32_to_cpus __le32_to_cpus +#define cpu_to_le16s __cpu_to_le16s +#define le16_to_cpus __le16_to_cpus +#define cpu_to_be64s __cpu_to_be64s +#define be64_to_cpus __be64_to_cpus +#define cpu_to_be32s __cpu_to_be32s +#define be32_to_cpus __be32_to_cpus +#define cpu_to_be16s __cpu_to_be16s +#define be16_to_cpus __be16_to_cpus +#endif + +/* + * Handle ntohl and suches. These have various compatibility + * issues - like we want to give the prototype even though we + * also have a macro for them in case some strange program + * wants to take the address of the thing or something.. + * + * Note that these traditionally return a "long", even though + * long is often 64-bit these days.. Thus the casts. + * + * They have to be macros in order to do the constant folding + * correctly - if the argument passed into a inline function + * it is no longer constant according to gcc.. + */ + +#undef ntohl +#undef ntohs +#undef htonl +#undef htons + +/* + * Do the prototypes. Somebody might want to take the + * address or some such sick thing.. + */ +extern unsigned long int ntohl(unsigned long int); +extern unsigned short int ntohs(unsigned short int); +extern unsigned long int htonl(unsigned long int); +extern unsigned short int htons(unsigned short int); + +#define ___htonl(x) __cpu_to_be32(x) +#define ___htons(x) __cpu_to_be16(x) +#define ___ntohl(x) __be32_to_cpu(x) +#define ___ntohs(x) __be16_to_cpu(x) + +#define htonl(x) ((unsigned long)___htonl(x)) +#define htons(x) ___htons(x) +#define ntohl(x) ((unsigned long)___ntohl(x)) +#define ntohs(x) ___ntohs(x) + +#endif /* _LINUX_BYTEORDER_H */ diff -u --recursive --new-file v2.1.70/linux/include/linux/byteorder_little_endian.h linux/include/linux/byteorder_little_endian.h --- v2.1.70/linux/include/linux/byteorder_little_endian.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/byteorder_little_endian.h Wed Dec 3 17:14:28 1997 @@ -0,0 +1,54 @@ +#ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H +#define _LINUX_BYTEORDER_LITTLE_ENDIAN_H + +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN 1234 +#endif +#ifndef __LITTLE_ENDIAN_BITFIELD +#define __LITTLE_ENDIAN_BITFIELD +#endif + +#define __constant_htonl(x) ___swab32((x)) +#define __constant_ntohl(x) ___swab32((x)) +#define __constant_htons(x) ___swab16((x)) +#define __constant_ntohs(x) ___swab16((x)) +#define __cpu_to_le64(x) ((__u64)(x)) +#define __le64_to_cpu(x) ((__u64)(x)) +#define __cpu_to_le32(x) ((__u32)(x)) +#define __le32_to_cpu(x) ((__u32)(x)) +#define __cpu_to_le16(x) ((__u16)(x)) +#define __le16_to_cpu(x) ((__u16)(x)) +#define __cpu_to_be64(x) __swab64((x)) +#define __be64_to_cpu(x) __swab64((x)) +#define __cpu_to_be32(x) __swab32((x)) +#define __be32_to_cpu(x) __swab32((x)) +#define __cpu_to_be16(x) __swab16((x)) +#define __be16_to_cpu(x) __swab16((x)) +#define __cpu_to_le64p(x) (*(__u64*)(x)) +#define __le64_to_cpup(x) (*(__u64*)(x)) +#define __cpu_to_le32p(x) (*(__u32*)(x)) +#define __le32_to_cpup(x) (*(__u32*)(x)) +#define __cpu_to_le16p(x) (*(__u16*)(x)) +#define __le16_to_cpup(x) (*(__u16*)(x)) +#define __cpu_to_be64p(x) __swab64p((x)) +#define __be64_to_cpup(x) __swab64p((x)) +#define __cpu_to_be32p(x) __swab32p((x)) +#define __be32_to_cpup(x) __swab32p((x)) +#define __cpu_to_be16p(x) __swab16p((x)) +#define __be16_to_cpup(x) __swab16p((x)) +#define __cpu_to_le64s(x) do {} while (0) +#define __le64_to_cpus(x) do {} while (0) +#define __cpu_to_le32s(x) do {} while (0) +#define __le32_to_cpus(x) do {} while (0) +#define __cpu_to_le16s(x) do {} while (0) +#define __le16_to_cpus(x) do {} while (0) +#define __cpu_to_be64s(x) __swab64s((x)) +#define __be64_to_cpus(x) __swab64s((x)) +#define __cpu_to_be32s(x) __swab32s((x)) +#define __be32_to_cpus(x) __swab32s((x)) +#define __cpu_to_be16s(x) __swab16s((x)) +#define __be16_to_cpus(x) __swab16s((x)) + +#include + +#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */ diff -u --recursive --new-file v2.1.70/linux/include/linux/byteorder_vaxendian.h linux/include/linux/byteorder_vaxendian.h --- v2.1.70/linux/include/linux/byteorder_vaxendian.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/byteorder_vaxendian.h Wed Dec 3 06:18:17 1997 @@ -0,0 +1,94 @@ +#ifndef _LINUX_BYTEORDER_VAX_ENDIAN_H +#define _LINUX_BYTEORDER_VAX_ENDIAN_H + +/* + * Could have been named NUXI-endian + * This file isn't operational. + * It's the beginning of what vaxlinux implementers will have to do. + * I just hope we won't have to write standardized cpu_to_ve32() and suches! + * little endian is 1234; bigendian is 4321; vaxendian is 3412 + * But what does a __u64 look like: is it 34127856 or 78563412 ??? + * I don't dare imagine! + */ + +#ifndef __VAX_ENDIAN +#define __VAX_ENDIAN 3412 +#endif +#ifndef __VAX_ENDIAN_BITFIELD +#define __VAX_ENDIAN_BITFIELD +#endif + +#define ___swahw32(x) \ + ((__u32)( \ + (((__u32)(x) & (__u32)0x0000ffffUL) << 16) | \ + (((__u32)(x) & (__u32)0xffff0000UL) >> 16) )) +#define ___swahb32(x) \ + ((__u32)( \ + (((__u32)(x) & (__u32)0x00ff00ffUL) << 16) | \ + (((__u32)(x) & (__u32)0xff00ff00UL) >> 16) )) + + +#ifndef __arch__swahw32 +# define __arch__swahw32(x) ___swahw32(x) +#endif +#ifndef __arch__swahb32 +# define __arch__swahb32(x) ___swahb32(x) +#endif +#ifndef __arch__swahw32p +# define __arch__swahw32p(x) __swahw32(*(x)) +#endif +#ifndef __arch__swahb32p +# define __arch__swahb32p(x) __swahb32(*(x)) +#endif +#ifndef __arch__swahw32s +# define __arch__swahw32s(x) *(x) = __swahw32p((x)) +#endif +#ifndef __arch__swahb32s +# define __arch__swahb32s(x) *(x) = __swahb32p((x)) +#endif + + +#define __constant_htonl(x) ___swahb32((x)) +#define __constant_ntohl(x) ___swahb32((x)) +#define __constant_htons(x) ___swab16((x)) +#define __constant_ntohs(x) ___swab16((x)) +#define __cpu_to_le64(x) I DON'T KNOW +#define __le64_to_cpu(x) I DON'T KNOW +#define __cpu_to_le32(x) ___swahw32((x)) +#define __le32_to_cpu(x) ___swahw32((x)) +#define __cpu_to_le16(x) ((__u16)(x) +#define __le16_to_cpu(x) ((__u16)(x) +#define __cpu_to_be64(x) I DON'T KNOW +#define __be64_to_cpu(x) I DON'T KNOW +#define __cpu_to_be32(x) __swahb32((x)) +#define __be32_to_cpu(x) __swahb32((x)) +#define __cpu_to_be16(x) __swab16((x)) +#define __be16_to_cpu(x) __swab16((x)) +#define __cpu_to_le64p(x) I DON'T KNOW +#define __le64_to_cpup(x) I DON'T KNOW +#define __cpu_to_le32p(x) ___swahw32p((x)) +#define __le32_to_cpup(x) ___swahw32p((x)) +#define __cpu_to_le16p(x) (*(__u16*)(x)) +#define __le16_to_cpup(x) (*(__u16*)(x)) +#define __cpu_to_be64p(x) I DON'T KNOW +#define __be64_to_cpup(x) I DON'T KNOW +#define __cpu_to_be32p(x) __swahb32p((x)) +#define __be32_to_cpup(x) __swahb32p((x)) +#define __cpu_to_be16p(x) __swab16p((x)) +#define __be16_to_cpup(x) __swab16p((x)) +#define __cpu_to_le64s(x) I DON'T KNOW +#define __le64_to_cpus(x) I DON'T KNOW +#define __cpu_to_le32s(x) ___swahw32s((x)) +#define __le32_to_cpus(x) ___swahw32s((x)) +#define __cpu_to_le16s(x) do {} while (0) +#define __le16_to_cpus(x) do {} while (0) +#define __cpu_to_be64s(x) I DON'T KNOW +#define __be64_to_cpus(x) I DON'T KNOW +#define __cpu_to_be32s(x) __swahb32s((x)) +#define __be32_to_cpus(x) __swahb32s((x)) +#define __cpu_to_be16s(x) __swab16s((x)) +#define __be16_to_cpus(x) __swab16s((x)) + +#include + +#endif /* _LINUX_BYTEORDER_VAX_ENDIAN_H */ diff -u --recursive --new-file v2.1.70/linux/include/linux/coda_psdev.h linux/include/linux/coda_psdev.h --- v2.1.70/linux/include/linux/coda_psdev.h Tue Dec 2 16:45:20 1997 +++ linux/include/linux/coda_psdev.h Wed Dec 3 17:35:33 1997 @@ -4,8 +4,6 @@ #define CODA_PSDEV_MAJOR 67 #define MAX_CODADEVS 5 /* how many do we allow */ -#include - extern struct vcomm psdev_vcomm[]; #define CODA_SUPER_MAGIC 0x73757245 diff -u --recursive --new-file v2.1.70/linux/include/linux/console.h linux/include/linux/console.h --- v2.1.70/linux/include/linux/console.h Tue May 13 22:41:18 1997 +++ linux/include/linux/console.h Wed Dec 3 15:21:57 1997 @@ -62,36 +62,40 @@ struct tty_struct; int tioclinux(struct tty_struct *tty, unsigned long arg); -/* The interface for /dev/console(s) and printk output */ - -struct console +/* + * Array of consoles built from command line options (console=) + */ +struct console_cmdline { - /* - * This function should not return before the string is written. - */ - void (*write)(const char*, unsigned); - - /* To unblank the console in case of panic */ - void (*unblank)(void); + char name[8]; /* Name of the driver */ + int index; /* Minor dev. to use */ + char *options; /* Options for the driver */ +}; +#define MAX_CMDLINECONSOLES 8 +extern struct console_cmdline console_list[MAX_CMDLINECONSOLES]; - /* - * Only the console that was registered last with wait_key != - * NULL will be used. This blocks until there is a character - * to give back, it does not schedule. - */ - void (*wait_key)(void); +/* + * The interface for a console, or any other device that + * wants to capture console messages (printer driver?) + */ - /* - * Return the device to use when opening /dev/console. Only the - * last registered console will do. - */ - int (*device)(void); +#define CON_PRINTBUFFER (1) +#define CON_FIRST (2) +#define CON_ENABLED (4) - /* - * For a linked list of consoles for multiple output. Any console - * not at the head of the list is used only for output. - */ - struct console *next; +struct console +{ + char name[8]; + void (*write)(struct console *, const char *, unsigned); + int (*read)(struct console *, const char *, unsigned); + kdev_t (*device)(struct console *); + int (*wait_key)(struct console *); + void (*unblank)(void); + void (*setup)(struct console *, char *); + short flags; + short index; + int cflag; + struct console *next; }; extern void register_console(struct console *); diff -u --recursive --new-file v2.1.70/linux/include/linux/netrom.h linux/include/linux/netrom.h --- v2.1.70/linux/include/linux/netrom.h Thu May 29 21:53:11 1997 +++ linux/include/linux/netrom.h Thu Dec 4 13:12:39 1997 @@ -7,7 +7,6 @@ #ifndef NETROM_KERNEL_H #define NETROM_KERNEL_H -#define PF_NETROM AF_NETROM #define NETROM_MTU 236 #define NETROM_T1 1 diff -u --recursive --new-file v2.1.70/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.70/linux/include/linux/pci.h Mon Dec 1 12:04:15 1997 +++ linux/include/linux/pci.h Thu Dec 4 12:58:01 1997 @@ -241,11 +241,13 @@ #define PCI_DEVICE_ID_NCR_53C895 0x000c #define PCI_DEVICE_ID_NCR_53C885 0x000d #define PCI_DEVICE_ID_NCR_53C875 0x000f +#define PCI_DEVICE_ID_NCR_53C876 0x008f #define PCI_VENDOR_ID_ATI 0x1002 #define PCI_DEVICE_ID_ATI_68800 0x4158 #define PCI_DEVICE_ID_ATI_215CT222 0x4354 #define PCI_DEVICE_ID_ATI_210888CX 0x4358 +#define PCI_DEVICE_ID_ATI_215GB 0x4742 #define PCI_DEVICE_ID_ATI_215GP 0x4750 #define PCI_DEVICE_ID_ATI_215GT 0x4754 #define PCI_DEVICE_ID_ATI_215GTB 0x4755 @@ -257,6 +259,8 @@ #define PCI_DEVICE_ID_VLSI_82C593 0x0006 #define PCI_DEVICE_ID_VLSI_82C594 0x0007 #define PCI_DEVICE_ID_VLSI_82C597 0x0009 +#define PCI_DEVICE_ID_VLSI_82C541 0x000c +#define PCI_DEVICE_ID_VLSI_82C543 0x000d #define PCI_DEVICE_ID_VLSI_VAS96011 0x0702 #define PCI_VENDOR_ID_ADL 0x1005 @@ -307,6 +311,7 @@ #define PCI_VENDOR_ID_IBM 0x1014 #define PCI_DEVICE_ID_IBM_FIRE_CORAL 0x000a +#define PCI_DEVICE_ID_IBM_TR 0x0018 #define PCI_DEVICE_ID_IBM_82G2675 0x001d #define PCI_DEVICE_ID_IBM_82351 0x0022 @@ -321,6 +326,7 @@ #define PCI_DEVICE_ID_TRIDENT_9420 0x9420 #define PCI_DEVICE_ID_TRIDENT_9440 0x9440 #define PCI_DEVICE_ID_TRIDENT_9660 0x9660 +#define PCI_DEVICE_ID_TRIDENT_9750 0x9750 #define PCI_VENDOR_ID_AI 0x1025 #define PCI_DEVICE_ID_AI_M1435 0x1435 @@ -342,6 +348,7 @@ #define PCI_DEVICE_ID_MIRO_36050 0x5601 #define PCI_VENDOR_ID_NEC 0x1033 +#define PCI_DEVICE_ID_NEC_PCX2 0x0046 #define PCI_VENDOR_ID_FD 0x1036 #define PCI_DEVICE_ID_FD_36C70 0x0000 @@ -358,12 +365,16 @@ #define PCI_DEVICE_ID_SI_5511 0x5511 #define PCI_DEVICE_ID_SI_5513 0x5513 #define PCI_DEVICE_ID_SI_5571 0x5571 +#define PCI_DEVICE_ID_SI_5597 0x5597 #define PCI_DEVICE_ID_SI_7001 0x7001 #define PCI_VENDOR_ID_HP 0x103c #define PCI_DEVICE_ID_HP_J2585A 0x1030 #define PCI_DEVICE_ID_HP_J2585B 0x1031 +#define PCI_VENDOR_ID_HOLTEK 0x9412 +#define PCI_DEVICE_ID_HOLTEK_6565 0x6565 + #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 #define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001 @@ -376,6 +387,9 @@ #define PCI_DEVICE_ID_OPTI_82C557 0xc557 #define PCI_DEVICE_ID_OPTI_82C558 0xc558 #define PCI_DEVICE_ID_OPTI_82C621 0xc621 +#define PCI_DEVICE_ID_OPTI_82C700 0xc700 +#define PCI_DEVICE_ID_OPTI_82C701 0xc701 +#define PCI_DEVICE_ID_OPTI_82C814 0xc814 #define PCI_DEVICE_ID_OPTI_82C822 0xc822 #define PCI_VENDOR_ID_SGS 0x104a @@ -388,6 +402,8 @@ #define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130 #define PCI_VENDOR_ID_TI 0x104c +#define PCI_DEVICE_ID_TI_TVP4010 0x3d04 +#define PCI_DEVICE_ID_TI_TVP4020 0x3d07 #define PCI_DEVICE_ID_TI_PCI1130 0xac12 #define PCI_DEVICE_ID_TI_PCI1131 0xac15 @@ -518,10 +534,14 @@ #define PCI_VENDOR_ID_MITSUBISHI 0x10ba +#define PCI_VENDOR_ID_SURECOM 0x10bd +#define PCI_DEVICE_ID_SURECOM_NE34 0x0e34 + #define PCI_VENDOR_ID_NEOMAGIC 0x10c8 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2070 0x0001 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003 +#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004 #define PCI_VENDOR_ID_ASP 0x10cd #define PCI_DEVICE_ID_ASP_ABP940 0x1200 @@ -531,6 +551,8 @@ #define PCI_DEVICE_ID_CERN_SPSB_PMC 0x0001 #define PCI_DEVICE_ID_CERN_SPSB_PCI 0x0002 +#define PCI_VENDOR_ID_NVIDIA 0x10de + #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_8849 0x8849 @@ -627,6 +649,7 @@ #define PCI_DEVICE_ID_ALLIANCE_PROMOTIO 0x3210 #define PCI_DEVICE_ID_ALLIANCE_PROVIDEO 0x6422 #define PCI_DEVICE_ID_ALLIANCE_AT24 0x6424 +#define PCI_DEVICE_ID_ALLIANCE_AT3D 0x643d #define PCI_VENDOR_ID_VMIC 0x114a #define PCI_DEVICE_ID_VMIC_VME 0x7587 @@ -653,6 +676,9 @@ #define PCI_VENDOR_ID_OMEGA 0x119b #define PCI_DEVICE_ID_OMEGA_82C092G 0x1221 +#define PCI_VENDOR_ID_LITEON 0x11ad +#define PCI_DEVICE_ID_LITEON_LNE100TX 0x0002 + #define PCI_VENDOR_ID_NP 0x11bc #define PCI_DEVICE_ID_NP_PCI_FDDI 0x0001 @@ -660,6 +686,9 @@ #define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000 #define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 +#define PCI_VENDOR_ID_AURAVISION 0x11d1 +#define PCI_DEVICE_ID_AURAVISION_VXP524 0x01f7 + #define PCI_VENDOR_ID_IKON 0x11d5 #define PCI_DEVICE_ID_IKON_10115 0x0115 #define PCI_DEVICE_ID_IKON_10117 0x0117 @@ -703,8 +732,8 @@ #define PCI_VENDOR_ID_PICTUREL 0x12c5 #define PCI_DEVICE_ID_PICTUREL_PCIVST 0x0081 -#define PCI_VENDOR_ID_NVIDIA 0x12d2 -#define PCI_DEVICE_ID_NVIDIA_RIVA128 0x0018 +#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2 +#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018 #define PCI_VENDOR_ID_SYMPHONY 0x1c1c #define PCI_DEVICE_ID_SYMPHONY_101 0x0001 @@ -772,6 +801,8 @@ #define PCI_DEVICE_ID_INTEL_82371AB 0x7111 #define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 #define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 +#define PCI_DEVICE_ID_INTEL_82443LX_0 0x7180 +#define PCI_DEVICE_ID_INTEL_82443LX_1 0x7181 #define PCI_DEVICE_ID_INTEL_P6 0x84c4 #define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 @@ -781,6 +812,7 @@ #define PCI_VENDOR_ID_ADAPTEC 0x9004 #define PCI_DEVICE_ID_ADAPTEC_7850 0x5078 #define PCI_DEVICE_ID_ADAPTEC_7855 0x5578 +#define PCI_DEVICE_ID_ADAPTEC_5800 0x5800 #define PCI_DEVICE_ID_ADAPTEC_7860 0x6078 #define PCI_DEVICE_ID_ADAPTEC_7861 0x6178 #define PCI_DEVICE_ID_ADAPTEC_7870 0x7078 @@ -788,6 +820,7 @@ #define PCI_DEVICE_ID_ADAPTEC_7872 0x7278 #define PCI_DEVICE_ID_ADAPTEC_7873 0x7378 #define PCI_DEVICE_ID_ADAPTEC_7874 0x7478 +#define PCI_DEVICE_ID_ADAPTEC_7895 0x7895 #define PCI_DEVICE_ID_ADAPTEC_7880 0x8078 #define PCI_DEVICE_ID_ADAPTEC_7881 0x8178 #define PCI_DEVICE_ID_ADAPTEC_7882 0x8278 diff -u --recursive --new-file v2.1.70/linux/include/linux/rose.h linux/include/linux/rose.h --- v2.1.70/linux/include/linux/rose.h Sat Nov 29 11:25:12 1997 +++ linux/include/linux/rose.h Thu Dec 4 13:12:39 1997 @@ -7,7 +7,6 @@ #ifndef ROSE_KERNEL_H #define ROSE_KERNEL_H -#define PF_ROSE AF_ROSE #define ROSE_MTU 251 #define ROSE_DEFER 1 diff -u --recursive --new-file v2.1.70/linux/include/linux/scc.h linux/include/linux/scc.h --- v2.1.70/linux/include/linux/scc.h Mon Dec 1 12:04:15 1997 +++ linux/include/linux/scc.h Wed Dec 3 17:35:22 1997 @@ -3,6 +3,8 @@ #ifndef _SCC_H #define _SCC_H +#include + /* selection of hardware types */ #define PA0HZP 0x00 /* hardware type for PA0HZP SCC card and compatible */ diff -u --recursive --new-file v2.1.70/linux/include/linux/time.h linux/include/linux/time.h --- v2.1.70/linux/include/linux/time.h Mon Dec 1 12:04:15 1997 +++ linux/include/linux/time.h Wed Dec 3 04:24:29 1997 @@ -15,7 +15,7 @@ * change timeval to jiffies, trying to avoid the * most obvious overflows.. */ -static inline unsigned long +static __inline__ unsigned long timespec_to_jiffies(struct timespec *value) { unsigned long sec = value->tv_sec; @@ -28,7 +28,7 @@ return HZ * sec + nsec; } -static inline void +static __inline__ void jiffies_to_timespec(unsigned long jiffies, struct timespec *value) { value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ); diff -u --recursive --new-file v2.1.70/linux/include/linux/tty_driver.h linux/include/linux/tty_driver.h --- v2.1.70/linux/include/linux/tty_driver.h Wed Nov 26 16:24:03 1997 +++ linux/include/linux/tty_driver.h Thu Dec 4 13:35:40 1997 @@ -207,10 +207,12 @@ #define TTY_DRIVER_TYPE_SERIAL 0x0003 #define TTY_DRIVER_TYPE_PTY 0x0004 #define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */ +#define TTY_DRIVER_TYPE_SYSCONS 0x0006 /* system subtypes (magic, used by tty_io.c) */ #define SYSTEM_TYPE_TTY 0x0001 #define SYSTEM_TYPE_CONSOLE 0x0002 +#define SYSTEM_TYPE_SYSCONS 0x0003 /* pty subtypes (magic, used by tty_io.c) */ #define PTY_TYPE_MASTER 0x0001 diff -u --recursive --new-file v2.1.70/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h --- v2.1.70/linux/include/linux/ufs_fs.h Thu Jul 17 10:06:09 1997 +++ linux/include/linux/ufs_fs.h Wed Dec 3 06:18:33 1997 @@ -6,13 +6,17 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_fs.h,v 1.8 1997/07/17 02:17:54 davem Exp $ - * + * Clean swab support by Fare + * just hope no one is using NNUUXXI on __?64 structure elements */ #ifndef __LINUX_UFS_FS_H #define __LINUX_UFS_FS_H +#undef UFS_HEAVY_DEBUG +/*#define UFS_HEAVY_DEBUG 1*/ +/* Uncomment the line above when hacking ufs code */ + #include #include #include @@ -24,6 +28,7 @@ #define UFS_SBSIZE 8192 #define UFS_MAGIC 0x00011954 +#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ #define UFS_FSIZE 1024 #define UFS_BSIZE 8192 @@ -51,6 +56,17 @@ #define UFS_DEBUG_NAMEI 0x00000004 #define UFS_DEBUG_LINKS 0x00000008 +#ifdef UFS_HEAVY_DEBUG +# define UFS_DEBUG_INITIAL UFS_DEBUG +#else +# define UFS_DEBUG_INITIAL 0 +#endif + +/* (!) HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes */ +#define UFS_LITTLE_ENDIAN 0x00000000 /* 0x00010000 */ +#define UFS_BIG_ENDIAN 0x00010000 /* 0x00020000 */ +#define UFS_BYTESEX 0x00010000 /* 0x00030000 */ + #define UFS_ADDR_PER_BLOCK(sb) ((sb)->u.ufs_sb.s_bsize >> 2) #define UFS_ADDR_PER_BLOCK_BITS(sb) ((sb)->u.ufs_sb.s_bshift - 2) @@ -93,10 +109,6 @@ __u32 cs_nffree; /* number of free frags */ }; -typedef struct _ufsquad { - __u32 val[2]; -} ufsquad; - /* * This is the actual superblock, as it is laid out on the disk. */ @@ -109,7 +121,7 @@ __u32 fs_dblkno; /* offset of first data after cg */ __u32 fs_cgoffset; /* cylinder group offset in cylinder */ __u32 fs_cgmask; /* used to calc mod fs_ntrak */ - time_t fs_time; /* last time written */ + __u32 fs_time; /* last time written -- time_t */ __u32 fs_size; /* number of blocks in fs */ __u32 fs_dsize; /* number of data blocks in fs */ __u32 fs_ncg; /* number of cylinder groups */ @@ -177,15 +189,14 @@ __u16 fs_opostbl[16][8]; /* old rotation block list head */ __s32 fs_sparecon[55]; /* reserved for future constants */ __s32 fs_state; /* file system state time stamp */ - ufsquad fs_qbmask; /* ~usb_bmask - for use with __s64 size */ - ufsquad fs_qfmask; /* ~usb_fmask - for use with __s64 size */ + __s64 fs_qbmask; /* ~usb_bmask */ + __s64 fs_qfmask; /* ~usb_fmask */ __s32 fs_postblformat; /* format of positional layout tables */ __s32 fs_nrpos; /* number of rotational positions */ __s32 fs_postbloff; /* (__s16) rotation block list head */ __s32 fs_rotbloff; /* (__u8) blocks for each rotation */ __s32 fs_magic; /* magic number */ __u8 fs_space[1]; /* list of blocks for each rotation */ - }; /* @@ -196,13 +207,13 @@ __u16 ui_nlink; /* 0x2 */ __u16 ui_suid; /* 0x4 */ __u16 ui_sgid; /* 0x6 */ - ufsquad ui_size; /* 0x8 */ /* XXX - should be __u64 */ - struct timeval ui_atime; /* 0x10 */ - struct timeval ui_mtime; /* 0x18 */ - struct timeval ui_ctime; /* 0x20 */ - __u32 ui_db[UFS_NDADDR]; /* 0x28 data blocks */ - __u32 ui_ib[UFS_NINDIR]; /* 0x58 indirect blocks */ - __u32 ui_flags; /* 0x64 unused */ + __u64 ui_size; /* 0x8 */ + struct timeval ui_atime; /* 0x10 access */ + struct timeval ui_mtime; /* 0x18 modification */ + struct timeval ui_ctime; /* 0x20 creation */ + __u32 ui_db[UFS_NDADDR]; /* 0x28 data blocks */ + __u32 ui_ib[UFS_NINDIR]; /* 0x58 indirect blocks */ + __u32 ui_flags; /* 0x64 unused -- "status flags (chflags)" ??? */ __u32 ui_blocks; /* 0x68 blocks in use */ __u32 ui_gen; /* 0x6c generation number XXX - what is this? */ __u32 ui_shadow; /* 0x70 shadow inode XXX - what is this?*/ @@ -225,7 +236,7 @@ extern void ufs_print_inode (struct inode *); /* ufs_namei.c */ -extern int ufs_lookup (struct inode *, struct qstr *, struct inode **); +extern int ufs_lookup (struct inode *, struct dentry *); /* ufs_super.c */ extern void ufs_warning (struct super_block *, const char *, const char *, ...) @@ -247,23 +258,6 @@ /* ufs_symlink.c */ extern struct inode_operations ufs_symlink_inode_operations; extern struct file_operations ufs_symlink_operations; - -/* Byte swapping 32/16-bit quantities into little endian format. */ -extern int ufs_need_swab; - -extern __inline__ __u32 ufs_swab32(__u32 value) -{ - return (ufs_need_swab ? ((value >> 24) | - ((value >> 8) & 0xff00) | - ((value << 8) & 0xff0000) | - (value << 24)) : value); -} - -extern __inline__ __u16 ufs_swab16(__u16 value) -{ - return (ufs_need_swab ? ((value >> 8) | - (value << 8)) : value); -} #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.70/linux/init/main.c linux/init/main.c --- v2.1.70/linux/init/main.c Tue Dec 2 16:45:20 1997 +++ linux/init/main.c Wed Dec 3 15:21:57 1997 @@ -84,6 +84,7 @@ extern void panic_setup(char *str, int *ints); extern void bmouse_setup(char *str, int *ints); extern void msmouse_setup(char *str, int *ints); +extern void console_setup(char *str, int *ints); #ifdef CONFIG_PRINTER extern void lp_setup(char *str, int *ints); #endif @@ -352,6 +353,7 @@ { "swap=", swap_setup }, { "buff=", buff_setup }, { "panic=", panic_setup }, + { "console=", console_setup }, #ifdef CONFIG_VT { "no-scroll", no_scroll }, #endif @@ -1022,7 +1024,7 @@ close(0);close(1);close(2); setsid(); - (void) open("/dev/tty1",O_RDWR,0); + (void) open("/dev/console",O_RDWR,0); (void) dup(0); (void) dup(0); return execve(shell, argv, envp_init); @@ -1106,8 +1108,8 @@ setup(1); - if (open("/dev/console",O_RDWR,0) < 0) - printk("Unable to open an initial console.\n"); + if (open("/dev/console", O_RDWR, 0) < 0) + printk("Warning: unable to open an initial console.\n"); (void) dup(0); (void) dup(0); diff -u --recursive --new-file v2.1.70/linux/kernel/printk.c linux/kernel/printk.c --- v2.1.70/linux/kernel/printk.c Sat Nov 29 11:25:12 1997 +++ linux/kernel/printk.c Wed Dec 3 15:21:57 1997 @@ -53,6 +53,46 @@ static char log_buf[LOG_BUF_LEN]; static unsigned long log_start = 0; static unsigned long logged_chars = 0; +struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; +static int selected_console = 0; + +/* + * Setup a list of consoles. Called from init/main.c + */ +__initfunc(void console_setup(char *str, int *ints)) +{ + char *s; + int i; + struct console_cmdline *c; + + for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) + ; + if (i == MAX_CMDLINECONSOLES) + return; + c = &console_cmdline[i]; + selected_console = 1; + + if (str[0] >= '0' && str[0] <= '9') { + strcpy(c->name, "ttyS"); + strncpy(c->name + 4, str, sizeof(c->name) - 5); + } else + strncpy(c->name, str, sizeof(c->name) - 1); + if ((c->options = strchr(str, ',')) != NULL) + *(c->options++) = 0; +#ifdef __sparc__ + if (strcmp(str, "ttya")) + strcpy(c->name, "ttyS0"); + if (strcmp(str, "ttyb")) + strcpy(c->name, "ttyS1"); +#endif + + for(s = c->name; *s; s++) + if (*s >= '0' && *s <= '9') + break; + c->index = simple_strtoul(s, NULL, 10); + *s = 0; +} + /* * Commands to sys_syslog: @@ -222,8 +262,8 @@ if (msg_level < console_loglevel && console_drivers) { struct console *c = console_drivers; while(c) { - if (c->write) - c->write(msg, p - msg + line_feed); + if ((c->flags & CON_ENABLED) && c->write) + c->write(c, msg, p - msg + line_feed); c = c->next; } } @@ -239,9 +279,10 @@ { struct console *c = console_drivers; int len = strlen(s); + while(c) { - if (c->write) - c->write(s, len); + if ((c->flags & CON_ENABLED) && c->write) + c->write(c, s, len); c = c->next; } } @@ -250,7 +291,7 @@ { struct console *c = console_drivers; while(c) { - if (c->unblank) + if ((c->flags & CON_ENABLED) && c->unblank) c->unblank(); c = c->next; } @@ -262,7 +303,7 @@ * print any messages that were printed by the kernel before the * console driver was initialized. */ -__initfunc(void register_console(struct console * console)) +void register_console(struct console * console) { int i,j,len; int p = log_start; @@ -270,9 +311,52 @@ signed char msg_level = -1; char *q; - console->next = console_drivers; - console_drivers = console; + /* + * See if we want to use this console driver. If we + * didn't select a console we take the first one + * that registers here. + */ + if (selected_console == 0) { + console->flags |= CON_ENABLED | CON_FIRST; + selected_console = 1; + if (console->setup) + console->setup(console, NULL); + } + /* + * See if this console matches one we selected on + * the command line. + */ + for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) { + if (strcmp(console_cmdline[i].name, console->name) != 0) + continue; + if (console->index >= 0 && + console->index != console_cmdline[i].index) + continue; + console->flags |= CON_ENABLED; + console->index = console_cmdline[i].index; + if (i == 0) + console->flags |= CON_FIRST; + if (console->setup) + console->setup(console, console_cmdline[i].options); + break; + } + + /* + * Put this console in the list - keep the + * preferred driver at the head of the list. + */ + if ((console->flags & CON_FIRST) || console_drivers == NULL) { + console->next = console_drivers; + console_drivers = console; + } else { + console->next = console_drivers->next; + console_drivers->next = console; + } + if ((console->flags & CON_PRINTBUFFER) == 0) return; + /* + * Print out buffered log messages. + */ for (i=0,j=0; i < log_size; i++) { buf[j++] = log_buf[p]; p++; p &= LOG_BUF_LEN-1; @@ -287,7 +371,7 @@ len -= 3; } if (msg_level < console_loglevel) - console->write(q, len); + console->write(console, q, len); if (buf[j-1] == '\n') msg_level = -1; j = 0; diff -u --recursive --new-file v2.1.70/linux/kernel/signal.c linux/kernel/signal.c --- v2.1.70/linux/kernel/signal.c Tue Dec 2 16:45:20 1997 +++ linux/kernel/signal.c Wed Dec 3 17:27:43 1997 @@ -651,7 +651,6 @@ { sigset_t these; struct timespec ts; - unsigned long expire; siginfo_t info; int ret, sig; @@ -680,17 +679,19 @@ if (!sig) { /* None ready -- temporarily unblock those we're interested in so that we'll be awakened when they arrive. */ + unsigned long expire; sigset_t oldblocked = current->blocked; sigandsets(¤t->blocked, ¤t->blocked, &these); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); + expire = ~0UL; if (uts) { expire = (timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec)); expire += jiffies; - current->timeout = expire; } + current->timeout = expire; current->state = TASK_INTERRUPTIBLE; schedule(); @@ -709,7 +710,11 @@ ret = -EFAULT; } } else { - ret = !uts || expire > jiffies ? -EINTR : -EAGAIN; + ret = -EAGAIN; + if (current->timeout != 0) { + current->timeout = 0; + ret = -EINTR; + } } return ret; diff -u --recursive --new-file v2.1.70/linux/net/Config.in linux/net/Config.in --- v2.1.70/linux/net/Config.in Mon Dec 1 12:04:15 1997 +++ linux/net/Config.in Wed Dec 3 15:17:30 1997 @@ -23,7 +23,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6 if [ "$CONFIG_IPV6" != "n" ]; then - source net/ipv6/Config.in + source net/ipv6/Config.in fi fi fi @@ -34,13 +34,6 @@ bool 'Full internal IPX network' CONFIG_IPX_INTERN fi tristate 'Appletalk DDP' CONFIG_ATALK -tristate 'Amateur Radio AX.25 Level 2' CONFIG_AX25 -if [ "$CONFIG_AX25" != "n" ]; then - bool 'AX.25 DAMA Slave support' CONFIG_AX25_DAMA_SLAVE -# bool 'AX.25 DAMA Master support' CONFIG_AX25_DAMA_MASTER - dep_tristate 'Amateur Radio NET/ROM' CONFIG_NETROM $CONFIG_AX25 - dep_tristate 'Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25 -fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then # tristate 'DECnet Support (NOT YET FUNCTIONAL)' CONFIG_DECNET # if [ "$CONFIG_DECNET" != "n" ]; then diff -u --recursive --new-file v2.1.70/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.70/linux/net/ax25/af_ax25.c Mon Dec 1 12:04:15 1997 +++ linux/net/ax25/af_ax25.c Wed Dec 3 15:16:39 1997 @@ -954,6 +954,7 @@ #ifdef AX25_CONFIG_DAMA_SLAVE case AX25_PROTO_DAMA_SLAVE: ax25_stop_t3timer(sk->protinfo.ax25); + ax25_stop_idletimer(sk->protinfo.ax25); break; #endif } diff -u --recursive --new-file v2.1.70/linux/net/ax25/ax25_ds_subr.c linux/net/ax25/ax25_ds_subr.c --- v2.1.70/linux/net/ax25/ax25_ds_subr.c Mon Dec 1 12:04:15 1997 +++ linux/net/ax25/ax25_ds_subr.c Wed Dec 3 15:16:39 1997 @@ -115,7 +115,10 @@ if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL) ax25_ds_t1_timeout(ax25o); - ax25_start_t3timer(ax25o); + /* do not start T3 for listening sockets (tnx DD8NE) */ + + if (ax25o->state != AX25_STATE_0) + ax25_start_t3timer(ax25o); } } @@ -210,8 +213,8 @@ void ax25_dama_off(ax25_cb *ax25) { - ax25_dev_dama_off(ax25->ax25_dev); ax25->condition &= ~AX25_COND_DAMA_MODE; + ax25_dev_dama_off(ax25->ax25_dev); } #endif diff -u --recursive --new-file v2.1.70/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v2.1.70/linux/net/ax25/ax25_out.c Mon Dec 1 12:04:15 1997 +++ linux/net/ax25/ax25_out.c Wed Dec 3 15:16:39 1997 @@ -27,6 +27,9 @@ * Joerg(DL1BKE) Fixed a problem with buffer allocation * for fragments. * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Joerg(DL1BKE) Fixed DAMA Slave mode: will work + * on non-DAMA interfaces like AX25L2V2 + * again (this behaviour is _required_). */ #include @@ -196,9 +199,22 @@ skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */ } - if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_SIMPLEX || - ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_DUPLEX) - ax25_kick(ax25); + switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_kick(ax25); + break; + +#ifdef CONFIG_AX25_DAMA_SLAVE + /* + * A DAMA slave is _required_ to work as normal AX.25L2V2 + * if no DAMA master is available. + */ + case AX25_PROTO_DAMA_SLAVE: + if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25); + break; +#endif + } } /* diff -u --recursive --new-file v2.1.70/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.70/linux/net/core/dev.c Mon Dec 1 12:04:15 1997 +++ linux/net/core/dev.c Wed Dec 3 04:28:11 1997 @@ -1291,7 +1291,6 @@ if(dev->set_multicast_list==NULL || ifr->ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; - printk(KERN_DEBUG "SIOCADDMULTI ioctl is deprecated\n"); dev_mc_add(dev,ifr->ifr_hwaddr.sa_data, dev->addr_len, 1); return 0; @@ -1299,7 +1298,6 @@ if(dev->set_multicast_list==NULL || ifr->ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; - printk(KERN_DEBUG "SIOCDELMULTI ioctl is deprecated\n"); dev_mc_delete(dev,ifr->ifr_hwaddr.sa_data,dev->addr_len, 1); return 0; diff -u --recursive --new-file v2.1.70/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.70/linux/net/netsyms.c Tue Dec 2 16:45:21 1997 +++ linux/net/netsyms.c Wed Dec 3 11:41:40 1997 @@ -145,6 +145,7 @@ EXPORT_SYMBOL(max_files); EXPORT_SYMBOL(do_mknod); EXPORT_SYMBOL(memcpy_toiovec); +EXPORT_SYMBOL(csum_partial); #ifdef CONFIG_IPX_MODULE EXPORT_SYMBOL(make_8023_client); @@ -209,7 +210,6 @@ EXPORT_SYMBOL(destroy_sock); EXPORT_SYMBOL(ip_queue_xmit); -EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(memcpy_fromiovecend); EXPORT_SYMBOL(csum_partial_copy_fromiovecend); EXPORT_SYMBOL(__release_sock); diff -u --recursive --new-file v2.1.70/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.1.70/linux/net/unix/af_unix.c Mon Dec 1 12:04:18 1997 +++ linux/net/unix/af_unix.c Wed Dec 3 10:34:16 1997 @@ -1475,8 +1475,10 @@ }; #ifdef MODULE +#ifdef CONFIG_SYSCTL extern void unix_sysctl_register(void); extern void unix_sysctl_unregister(void); +#endif int init_module(void) #else @@ -1503,7 +1505,9 @@ #endif #ifdef MODULE +#ifdef CONFIG_SYSCTL unix_sysctl_register(); +#endif return 0; #endif @@ -1513,7 +1517,9 @@ void cleanup_module(void) { sock_unregister(AF_UNIX); +#ifdef CONFIG_SYSCTL unix_sysctl_unregister(); +#endif } #endif diff -u --recursive --new-file v2.1.70/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c --- v2.1.70/linux/net/wanrouter/wanproc.c Thu Jul 17 10:06:10 1997 +++ linux/net/wanrouter/wanproc.c Wed Dec 3 15:20:04 1997 @@ -57,8 +57,7 @@ /* Proc filesystem interface */ static int router_proc_perms (struct inode*, int); -static long router_proc_read(struct inode* inode, struct file* file, char* buf, - unsigned long count); +static ssize_t router_proc_read(struct file* file, char* buf, size_t count, loff_t *ppos); /* Methods for preparing data for reading proc entries */ @@ -337,9 +336,10 @@ * <0 error */ -static long router_proc_read(struct inode* inode, struct file* file, - char* buf, unsigned long count) +static ssize_t router_proc_read(struct file* file, char* buf, size_t count, + loff_t *ppos) { + struct inode *inode; struct proc_dir_entry* dent; char* page; int pos, offs, len;